OpenGL ES 应用: SurfaceFlinger

一.几个重要的类

1. Description

Description.cpp中主要是接收一些来自GLES20RenderEngine设置参数保存在其成员变量中,主要用到GLES 2.0的。并将数据设置到Program中。

frameworks/native/services/surfaceflinger/RenderEngine/Description.cpp
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
//这个后期可以研究一下
57    enum class TransferFunction : int {
58        LINEAR,
59        SRGB,
60        ST2084,
61        HLG,  // Hybrid Log-Gamma for HDR.
62    };
//下面这两个类是允许直接访问私有成员变量的
67private:
68    friend class Program;
69    friend class ProgramCache;

2. Program

Program类中主要完成一些glsl的初始化工作,提供一些接口函数,也提供调试用的函数(dumpShader),接收Description中值设置到glsl中uniform参数。

frameworks/native/services/surfaceflinger/RenderEngine/Program.cpp
29Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
30      : mInitialized(false) {
//1. 针对glsl的编译----固定方式
31    GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
32    GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
33    GLuint programId = glCreateProgram();
34    glAttachShader(programId, vertexId);
35    glAttachShader(programId, fragmentId);
//attach in 的index,见:enum { position = 0, texCoords = 1 };
36    glBindAttribLocation(programId, position, "position");
37    glBindAttribLocation(programId, texCoords, "texCoords");
38    glLinkProgram(programId);
...
56    } else {
//2.保存变量
57        mProgram = programId;
58        mVertexShader = vertexId;
59        mFragmentShader = fragmentId;
60        mInitialized = true;
//3.获取glsl中的uniform变量index
61        mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
62        mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
63        mSamplerLoc = glGetUniformLocation(programId, "sampler");
64        mColorLoc = glGetUniformLocation(programId, "color");
65        mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
66        mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix");
67        mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix");
68
69        // set-up the default values for our uniforms
70        glUseProgram(programId);
//4.设置projection
71        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray());
//5.开启顶点position属性
72        glEnableVertexAttribArray(0);
73    }

//提供一些接口函数
82void Program::use() {
83    glUseProgram(mProgram);
84}
86GLuint Program::getAttrib(const char* name) const {
87    // TODO: maybe use a local cache
88    return glGetAttribLocation(mProgram, name);
89}
91GLint Program::getUniform(const char* name) const {
92    // TODO: maybe use a local cache
93    return glGetUniformLocation(mProgram, name);
94}

//最关键的设置uniform变量的值,从Description中接收来的数据
125void Program::setUniforms(const Description& desc) {
126    // TODO: we should have a mechanism here to not always reset uniforms that
127    // didn't change for this program.
128
129    if (mSamplerLoc >= 0) {
130        glUniform1i(mSamplerLoc, 0);
131        glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray());
132    }
133    if (mColorLoc >= 0) {
134        const float color[4] = {desc.mColor.r, desc.mColor.g, desc.mColor.b, desc.mColor.a};
135        glUniform4fv(mColorLoc, 1, color);
136    }
137    if (mInputTransformMatrixLoc >= 0) {
138        // If the input transform matrix is not identity matrix, we want to merge
139        // the saturation matrix with input transform matrix so that the saturation
140        // matrix is applied at the correct stage.
141        mat4 inputTransformMatrix = mat4(desc.mInputTransformMatrix) * desc.mSaturationMatrix;
142        glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
143    }
144    if (mOutputTransformMatrixLoc >= 0) {
145        // The output transform matrix and color matrix can be combined as one matrix
146        // that is applied right before applying OETF.
147        mat4 outputTransformMatrix = desc.mColorMatrix * desc.mOutputTransformMatrix;
148        // If there is no input transform matrix, we want to merge the saturation
149        // matrix with output transform matrix to avoid extra matrix multiplication
150        // in shader.
151        if (mInputTransformMatrixLoc < 0) {
152            outputTransformMatrix *= desc.mSaturationMatrix;
153        }
154        glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE,
155                           outputTransformMatrix.asArray());
156    }
157    if (mDisplayMaxLuminanceLoc >= 0) {
158        glUniform1f(mDisplayMaxLuminanceLoc, desc.mDisplayMaxLuminance);
159    }
160    // these uniforms are always present
161    glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
162}

3.ProgramCache

ProgramCache 接收Description的信息,完成glsl的初始化工作入口:编译shader、set Uniform值。

frameworks/native/services/surfaceflinger/RenderEngine/ProgramCache.cpp
//有trace哦,可以抓取看看哦
17#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19#include <GLES2/gl2.h>
20#include <GLES2/gl2ext.h>
23#include <utils/Trace.h>

666void ProgramCache::useProgram(const Description& description) {
667    // generate the key for the shader based on the description
      //1.根据Descrption生成对应的needs
668    Key needs(computeKey(description));
669
670    // look-up the program in the cache
       //2.根据needs找到之前加入的program,如果第一次的话等于nullptr
671    Program* program = mCache.valueFor(needs);
672    if (program == nullptr) {
673        // we didn't find our program, so generate one...
674        nsecs_t time = -systemTime();
           //3.编译shader
675        program = generateProgram(needs);
676        mCache.add(needs, program);
677        time += systemTime();
678        //打印出的needs很有意思,可以根据位去判断哪些东西打开了
679        ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
680              uint32_t(ns2ms(time)), mCache.size());
681    }
682
683    // here we have a suitable program for this description
684    if (program->isValid()) {
           //4.set Uniform值
685        program->use();
686        program->setUniforms(description);
687    }
688}

Key::TEXTURE_MASK
Key::ALPHA_MASK -> description.mColor.a
Key::BLEND_MASK -> description.mPremultipliedAlpha
Key::OPACITY_MASK -> description.mOpaque
Key::INPUT_TRANSFORM_MATRIX_MASK -> description.hasInputTransformMatrix
Key::OUTPUT_TRANSFORM_MATRIX_MASK,
Key::Y410_BT2020_MASK -> description.mY410BT2020
Key::INPUT_TF_MASK -> description.mInputTransferFunction
Key::OUTPUT_TF_MASK -> description.mOutputTransferFunction

下面这个函数主要是生成对应的glsl:

653Program* ProgramCache::generateProgram(const Key& needs) {
654    ATRACE_CALL();
655
656    // vertex shader
657    String8 vs = generateVertexShader(needs);
658
659    // fragment shader
660    String8 fs = generateFragmentShader(needs);
661
662    Program* program = new Program(needs, vs.string(), fs.string());
663    return program;
664}

最后我们看下vs和fs的结果呢!
vs如下:

//1.只有开启纹理才会有(TEXTURE_2D、TEXTURE_EXT )
"attribute vec4 texCoords;"
//1.只有开启纹理才会有(TEXTURE_2D、TEXTURE_EXT )
"varying vec2 outTexCoords;"

//通用部分
"attribute vec4 position;"
"uniform mat4 projection;"
"uniform mat4 texture;"
"void main(void) {" 
    "gl_Position = projection * position;"
    //2.只有开启纹理才会有(TEXTURE_2D、TEXTURE_EXT )
    "outTexCoords = (texture * texCoords).st;"
"}"

上面1、2两处会首先根据Description中mTextureEnabled判断是否开启纹理,如果开启的话开启的是TEXTURE_2D还是TEXTURE_EXT,会根据mTexture.getTextureTarget来决定

fs如下:

//1.如果是TEXTURE_EXT的话需要加上,后面我会讨论这种方式的纹理优势
"#extension GL_OES_EGL_image_external : require"
"precision mediump float;"
//2.以下两句为开启TEXTURE_EXT的:
"uniform samplerExternalOES sampler;"
"varying vec2 outTexCoords;"
//3.以下两句为开启2D:
"uniform sampler2D sampler;"
"varying vec2 outTexCoords;"
//4.当没有开启纹理(2D、OES)或者color拥有a通道(a<1)的话:
"uniform vec4 color;"
//5.以下的为开启Y410BT2020,之后研究:
R"__SHADER__(
            vec3 convertY410BT2020(const vec3 color) {
                const vec3 offset = vec3(0.0625, 0.5, 0.5);
                const mat3 transform = mat3(
                    vec3(1.1678,  1.1678, 1.1678),
                    vec3(   0.0, -0.1878, 2.1481),
                    vec3(1.6836, -0.6523,   0.0));
                // Y is in G, U is in R, and V is in B
                return clamp(transform * (color.grb - offset), 0.0, 1.0);
            }
            )__SHADER__"
//6.以下为开启transformMatrix或者inputTransformMatrix和outputTransformMatrix不一
致时开启
//1)根据inputTransformMatrix和outputTransformMatrix决定
"uniform float displayMaxLuminance;
//2)以下为拥有inputTransformMatrix:
"uniform mat4 inputTransformMatrix;"
R"__SHADER__(
                highp vec3 InputTransform(const highp vec3 color) {
                    return vec3(inputTransformMatrix * vec4(color, 1.0));
                }
//3)拥有outputTransformMatrix:
R"__SHADER__(
                highp vec3 InputTransform(const highp vec3 color) {
                    return color;
                }
            )__SHADER__";

"void main(void) {"
//7.开启纹理:
    "gl_FragColor = texture2D(sampler, outTexCoords);"
   //1)开启Y410BT2020:
    "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);"
//8.没有开启纹理:
"gl_FragColor.rgb = color.rgb;";
"gl_FragColor.a = 1.0;"
//9.根据mOpaque判断
"gl_FragColor.a = 1.0;
//10.alpha通道<1
  //1)Premultiplied:每个通道乘以alpha
  "gl_FragColor *= color.a;"
  //2) 否则的话:
  "gl_FragColor.a *= color.a;"
//11.存在inputTransform:
  "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);"
  "gl_FragColor.rgb = OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))));"
  "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);"
"}"

ProgramCache::primeCache函数在sf::init阶段调用,初始化mCache,向其中设置多种组合的Key,还用于处理Wide Color。

二.研究下上面特殊的key

1.Texture

Description::disableTexture
1.GLES20RenderEngine::setupLayerBlending,根据第三个参数判断
1)ColorLayer::onDraw ->disable
2)BufferLayer::drawWithOpenGL ->enable Texture
2.GLES20RenderEngine::disableTexturing
1)SurfaceFlinger::renderScreenImplLocked
2)BufferLayer::onDraw ->draw完成后的关闭texture
3.GLES20RenderEngine::setupFillWithColor
1)RenderEngine::fillRegionWithColor
a.SurfaceFlinger::doDebugFlashRegions
b.SurfaceFlinger::drawWormhole
2)Layer::clearWithOpenGL
a.BufferLayer::onDraw
b.SurfaceFlinger::doComposeSurfaces

Description::setTexture
以下1和2,2选1,互斥:

  1. GLES20RenderEngine::setupLayerTexturing
    1) BufferLayer::onDraw
  2. GLES20RenderEngine::setupLayerBlackedOut ->Texture::TEXTURE_2D
    1) BufferLayer::onDraw :仅在buffer的Usage包含GRALLOC_USAGE_PROTECTED或者layer flags包含layer_state_t::eLayerSecure同时renderArea不为secure(LayerRenderArea为false,DisplayDeviceArea为true,因为为主屏)

那么我们看下texture时怎么绑定的呢?

BufferLayer::BufferLayer() {
    ...
    mFlinger->getRenderEngine().genTextures(1, &mTextureName);
    mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
    ...
}

161void BufferLayer::onDraw(){
       ...
205    if (!blackOutLayer) {
206        // TODO: we could be more subtle with isFixedSize()
207        const bool useFiltering = getFiltering() || needsFiltering(renderArea) || isFixedSize();
208
209        // Query the texture matrix given our current filtering mode.
210        float textureMatrix[16];
211        mConsumer->setFilteringEnabled(useFiltering);
212        mConsumer->getTransformMatrix(textureMatrix);
           ...
242        // Set things up for texturing.
243        mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
244                               getBE().compositionInfo.mBuffer->getHeight());
245        mTexture.setFiltering(useFiltering);
246        mTexture.setMatrix(textureMatrix);
247
248        engine.setupLayerTexturing(mTexture);
249    } else {
250        engine.setupLayerBlackedOut();
251    }
252    drawWithOpenGL(renderArea, useIdentityTransform);
253    engine.disableTexturing();
254}

2.mY410BT2020

在BufferLayer的drawWithOpenGL时通过isHdrY410函数判断是否将mY410BT2020置true。

818bool BufferLayer::isHdrY410() const {
819    // pixel format is HDR Y410 masquerading as RGBA_1010102
820    return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
821            mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
822            getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
823}

3.mPremultipliedAlpha、mOpaque

1) GLES20RenderEngine::setupLayerBlending

210void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
211                                            bool disableTexture, const half4& color) {
212    mState.setPremultipliedAlpha(premultipliedAlpha);
213    mState.setOpaque(opaque);
214    mState.setColor(color);
215
216    if (disableTexture) {
217        mState.disableTexture();
218    }
219
220    if (color.a < 1.0f || !opaque) {
221        glEnable(GL_BLEND);
222        glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
223    } else {
224        glDisable(GL_BLEND);
225    }
226}

在new一个layer的时候构造函数中就会将mPremultipliedAlpha初始化为true;而在BufferLayer构造中会根据flag重新更改:

if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;

那么mOpaque获取通过下面的函数:

691bool BufferLayer::isOpaque(const Layer::State& s) const {
692    // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
693    // layer's opaque flag.
694    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {  
695        return false;
696    }
697
698    // if the layer has the opaque flag, then we're always opaque,
699    // otherwise we use the current buffer's format.
700    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
701}

相反ColorLayer中mPremultipliedAlpha值取决于父类Layer,即true,mOpaque为false。
2) GLES20RenderEngine::setupFillWithColor

306void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
307    mState.setPremultipliedAlpha(true);
308    mState.setOpaque(false);
309    mState.setColor(half4(r, g, b, a));
310    mState.disableTexture();
311    glDisable(GL_BLEND);
312}

mPremultipliedAlpha = true 直接为true
mOpaque = false直接为false

4.mColor

和mPremultipliedAlpha、mOpaque一样,在setupLayerBlending 和setupFillWithColor中设置。
BufferLayer & ColorLayer:

1883half4 Layer::getColor() const {
1884    const half4 color(getDrawingState().color);
1885    return half4(color.r, color.g, color.b, getAlpha());
1886}

那么在setupFillWithColor时会直接指定颜色主动设置,无需再get。
1)Layer::clearWithOpenGL
BufferLayer在draw的时候如果存在hole,那么会将color置为黑色(0,0,0,1)
Layer::clearWithOpenGL
在doComposerSurface时也会将颜色调整:

3003                    if (layer->getClearClientTarget(hwcId) && !firstLayer &&
3004                            layer->isOpaque(state) && (state.color.a == 1.0f)
3005                            && hasClientComposition) {
3006                        // never clear the very first layer since we're
3007                        // guaranteed the FB is already cleared
3008                        layer->clearWithOpenGL(renderArea);
3009                    }

2)RenderEngine::fillRegionWithColor
doDebugFlashRegions:
engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);

3048void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const {
3049    const int32_t height = displayDevice->getHeight();
3050    auto& engine(getRenderEngine());
3051    engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
3052}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容