前言:Flutter官方给Texture的内容并不多,再加上for Desktop的,资料就不多了,正好最近比较有时间,研究了下Flutter for Windows底层的渲染逻辑。谷歌在IOS和Android上的Engine处理外部Texture的代码和注释比较实在,Windows上的注释要么是还不支持,要么是很快支持,要么是将来可能有变动,所以至于实现,得自己定制Engine。
这其中需要很多工程知识,比如gn和cmake的使用,我一个读书仔哪懂那么多,不过参考其他平台的外界纹理,总结了大概过程。
前情提要
在上一篇文章中,我们梳理了
FlutterWindowsEngine的创建过程,发现了它创建了一个AngleSurfaceManager,打开文档,发现这是个重量级选手。
src\flutter\shell\platform\windows源码目录
AngleSurfaceManager
ANGLE是什么?
Flutter官方解释:
看得出是GL转DX11或DX12,让我们看看声明文件
angle_surface_manager.h
看得出ANGLE在这里使用EGL进行图形操作。
这些都是不暴露给外面的私有方法,要共享纹理,就得拿到context,Flutter内部自己使用了共享纹理,egl_resource_context_和egl_context_,一个用来异步上传纹理,一个用来渲染。
angle_surface_manager.cc
让我们看看这个东西初始GLcontext的内容
Initialize函数
这个函数内容太多了,我们就截取部分,Flutter内部通过eglCreateContext的第三个参数实现共享Context了。
Flutter Win平台下的纹理注册过程
一切源于这个issue
Issue #78648 · flutter/flutter (github.com)
提issue作者的demo flutter_windows_texture_bug 中,有关于如何在Windows下注册和上传使用纹理的内容,具体过程在gldraw_plugin.cpp的GLDrawPlugin::HandleMethodCall内。
他使用了官方目前实现的PixelBufferTexture和TextureVariant,完成CPU->GPU的纹理上传方法,通过MarkTextureFrameAvailable触发回调函数更新纹理,像素格式为RGBA8。如果你的流仅在Flutter内部使用,那么这种方案可行。
过程可以总结如下
和其他平台并没有区别
更深入一层
还记的我在前面几篇文章讲的flutter_windows.cc吗?
Flutter Engine在Windows上启动详解 - 掘金 (juejin.cn)
不管你上面是PixelBufferTexture还是什么的,他只是个接口,最后的数据还是经过层层处理,会储存在FlutterDesktopTextureInfo。
src\flutter\shell\platform\common\public\flutter_texture_registrar.h包含FlutterDesktopTextureInfo定义,做了数据引用和类型定义
看到了本质,那我们顺着注册流程走一遍看看内部到底在作什么
1. FlutterWindowsTextureRegistrar
Win平台的Registrar是FlutterWindowsTextureRegistrar,实现为src\flutter\shell\platform\windows\flutter_windows_texture_registrar.cc
让我们看看他的RegisterTexture函数:
31行出现了!flutter::ExternalTextureGL,这个才是内部使用的外部纹理对象,构造函数参数包括我们最初设定的供MarkTextureFrameAvailable使用的函数。
2. ExternalTextureGL
实现文件src/flutter/shell/platform/windows/external_texture_gl.cc,一打开,亲切可爱。
ExternalTextureGLState存储的就是使用glGenTextures的第二个纹理标识符参数GLuint。
PopulateTexture会调用CopyPixelBuffer,通过判断ExternalTextureGLState的GLunit是否为0,为0就初始和生成一份纹理,不为0直接glBindTexture。
看到103行的texture_callback了吗,我们最上方写的函数就在这里被调用了,把数据生成并且传递了过来。
那么谁调用PopulateTexture呢?
嘿嘿,是Registrar!每个向他注册的纹理会被它储存,它从自己的textures_库中取出所需纹理,然后调用。
一个疑问:这里也许和MarkTextureFrameAvailable有着某种联系,好奇的可以自己去查查engine的这个函数如何调用。
异想天开
前置条件:你已经在Angle_Surface_Manager获得了egl_context,并且用它创建了属于你自己的egl_context。
-
我们是不是可以向
Registrar注册一个纹理,然后修改他的ExternalTextureGLState为你在其他egl_context自己生成的纹理的GLuint,并且对Populate和Copy这两个函数做一些修改,防止不必要的gl操作,或者定制成glTexSub等等,然后MarkAvaible...... -
你都拿到
flutter的egl_context了,你想把放到其他图形渲染引擎,夺舍它也不是不行.....
END
这可能是这个专栏的倒数第二篇文章了,engine研究那么多,还是没有直接写dart来得快乐。所以接下来停下engine的学习了,希望这篇文章对你有用!!
有错误,留个言,点个赞吧!
下一篇写个用Cmake和Vs2019启动engine的文章就完结吧。