Home | History | Annotate | Download | only in renderstate
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #include "renderstate/RenderState.h"
     17 #include <GpuMemoryTracker.h>
     18 #include "DeferredLayerUpdater.h"
     19 #include "GlLayer.h"
     20 #include "VkLayer.h"
     21 
     22 #include "renderthread/CanvasContext.h"
     23 #include "renderthread/EglManager.h"
     24 #include "utils/GLUtils.h"
     25 
     26 #include <algorithm>
     27 
     28 #include <ui/ColorSpace.h>
     29 
     30 namespace android {
     31 namespace uirenderer {
     32 
     33 RenderState::RenderState(renderthread::RenderThread& thread)
     34         : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) {
     35     mThreadId = pthread_self();
     36 }
     37 
     38 RenderState::~RenderState() {
     39     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
     40                         "State object lifecycle not managed correctly");
     41 }
     42 
     43 void RenderState::onGLContextCreated() {
     44     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
     45                         "State object lifecycle not managed correctly");
     46     GpuMemoryTracker::onGpuContextCreated();
     47 
     48     mBlend = new Blend();
     49     mMeshState = new MeshState();
     50     mScissor = new Scissor();
     51     mStencil = new Stencil();
     52 
     53     // Deferred because creation needs GL context for texture limits
     54     if (!mLayerPool) {
     55         mLayerPool = new OffscreenBufferPool();
     56     }
     57 
     58     // This is delayed because the first access of Caches makes GL calls
     59     if (!mCaches) {
     60         mCaches = &Caches::createInstance(*this);
     61     }
     62     mCaches->init();
     63 }
     64 
     65 static void layerLostGlContext(Layer* layer) {
     66     LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL,
     67                         "layerLostGlContext on non GL layer");
     68     static_cast<GlLayer*>(layer)->onGlContextLost();
     69 }
     70 
     71 void RenderState::onGLContextDestroyed() {
     72     mLayerPool->clear();
     73 
     74     // TODO: reset all cached state in state objects
     75     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
     76 
     77     mCaches->terminate();
     78 
     79     delete mBlend;
     80     mBlend = nullptr;
     81     delete mMeshState;
     82     mMeshState = nullptr;
     83     delete mScissor;
     84     mScissor = nullptr;
     85     delete mStencil;
     86     mStencil = nullptr;
     87 
     88     destroyLayersInUpdater();
     89     GpuMemoryTracker::onGpuContextDestroyed();
     90 }
     91 
     92 void RenderState::onVkContextCreated() {
     93     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
     94                         "State object lifecycle not managed correctly");
     95     GpuMemoryTracker::onGpuContextCreated();
     96 }
     97 
     98 static void layerDestroyedVkContext(Layer* layer) {
     99     LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::Vulkan,
    100                         "layerLostVkContext on non Vulkan layer");
    101     static_cast<VkLayer*>(layer)->onVkContextDestroyed();
    102 }
    103 
    104 void RenderState::onVkContextDestroyed() {
    105     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext);
    106     destroyLayersInUpdater();
    107     GpuMemoryTracker::onGpuContextDestroyed();
    108 }
    109 
    110 GrContext* RenderState::getGrContext() const {
    111     return mRenderThread.getGrContext();
    112 }
    113 
    114 void RenderState::flush(Caches::FlushMode mode) {
    115     switch (mode) {
    116         case Caches::FlushMode::Full:
    117         // fall through
    118         case Caches::FlushMode::Moderate:
    119         // fall through
    120         case Caches::FlushMode::Layers:
    121             if (mLayerPool) mLayerPool->clear();
    122             break;
    123     }
    124     if (mCaches) mCaches->flush(mode);
    125 }
    126 
    127 void RenderState::onBitmapDestroyed(uint32_t pixelRefId) {
    128     if (mCaches && mCaches->textureCache.destroyTexture(pixelRefId)) {
    129         glFlush();
    130         GL_CHECKPOINT(MODERATE);
    131     }
    132 }
    133 
    134 void RenderState::setViewport(GLsizei width, GLsizei height) {
    135     mViewportWidth = width;
    136     mViewportHeight = height;
    137     glViewport(0, 0, mViewportWidth, mViewportHeight);
    138 }
    139 
    140 void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
    141     *outWidth = mViewportWidth;
    142     *outHeight = mViewportHeight;
    143 }
    144 
    145 void RenderState::bindFramebuffer(GLuint fbo) {
    146     if (mFramebuffer != fbo) {
    147         mFramebuffer = fbo;
    148         glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
    149     }
    150 }
    151 
    152 GLuint RenderState::createFramebuffer() {
    153     GLuint ret;
    154     glGenFramebuffers(1, &ret);
    155     return ret;
    156 }
    157 
    158 void RenderState::deleteFramebuffer(GLuint fbo) {
    159     if (mFramebuffer == fbo) {
    160         // GL defines that deleting the currently bound FBO rebinds FBO 0.
    161         // Reflect this in our cached value.
    162         mFramebuffer = 0;
    163     }
    164     glDeleteFramebuffers(1, &fbo);
    165 }
    166 
    167 void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
    168     if (mode == DrawGlInfo::kModeProcessNoContext) {
    169         // If there's no context we don't need to interrupt as there's
    170         // no gl state to save/restore
    171         (*functor)(mode, info);
    172     } else {
    173         interruptForFunctorInvoke();
    174         (*functor)(mode, info);
    175         resumeFromFunctorInvoke();
    176     }
    177 }
    178 
    179 void RenderState::interruptForFunctorInvoke() {
    180     mCaches->setProgram(nullptr);
    181     mCaches->textureState().resetActiveTexture();
    182     meshState().unbindMeshBuffer();
    183     meshState().unbindIndicesBuffer();
    184     meshState().resetVertexPointers();
    185     meshState().disableTexCoordsVertexArray();
    186     debugOverdraw(false, false);
    187     // TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
    188     if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
    189         glDisable(GL_FRAMEBUFFER_SRGB_EXT);
    190     }
    191 }
    192 
    193 void RenderState::resumeFromFunctorInvoke() {
    194     if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
    195         glEnable(GL_FRAMEBUFFER_SRGB_EXT);
    196     }
    197 
    198     glViewport(0, 0, mViewportWidth, mViewportHeight);
    199     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
    200     debugOverdraw(false, false);
    201 
    202     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    203 
    204     scissor().invalidate();
    205     blend().invalidate();
    206 
    207     mCaches->textureState().activateTexture(0);
    208     mCaches->textureState().resetBoundTextures();
    209 }
    210 
    211 void RenderState::debugOverdraw(bool enable, bool clear) {
    212     if (Properties::debugOverdraw && mFramebuffer == 0) {
    213         if (clear) {
    214             scissor().setEnabled(false);
    215             stencil().clear();
    216         }
    217         if (enable) {
    218             stencil().enableDebugWrite();
    219         } else {
    220             stencil().disable();
    221         }
    222     }
    223 }
    224 
    225 static void destroyLayerInUpdater(DeferredLayerUpdater* layerUpdater) {
    226     layerUpdater->destroyLayer();
    227 }
    228 
    229 void RenderState::destroyLayersInUpdater() {
    230     std::for_each(mActiveLayerUpdaters.begin(), mActiveLayerUpdaters.end(), destroyLayerInUpdater);
    231 }
    232 
    233 void RenderState::postDecStrong(VirtualLightRefBase* object) {
    234     if (pthread_equal(mThreadId, pthread_self())) {
    235         object->decStrong(nullptr);
    236     } else {
    237         mRenderThread.queue().post([object]() { object->decStrong(nullptr); });
    238     }
    239 }
    240 
    241 ///////////////////////////////////////////////////////////////////////////////
    242 // Render
    243 ///////////////////////////////////////////////////////////////////////////////
    244 
    245 void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
    246                          bool overrideDisableBlending) {
    247     const Glop::Mesh& mesh = glop.mesh;
    248     const Glop::Mesh::Vertices& vertices = mesh.vertices;
    249     const Glop::Mesh::Indices& indices = mesh.indices;
    250     const Glop::Fill& fill = glop.fill;
    251 
    252     GL_CHECKPOINT(MODERATE);
    253 
    254     // ---------------------------------------------
    255     // ---------- Program + uniform setup ----------
    256     // ---------------------------------------------
    257     mCaches->setProgram(fill.program);
    258 
    259     if (fill.colorEnabled) {
    260         fill.program->setColor(fill.color);
    261     }
    262 
    263     fill.program->set(orthoMatrix, glop.transform.modelView, glop.transform.meshTransform(),
    264                       glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
    265 
    266     // Color filter uniforms
    267     if (fill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
    268         const FloatColor& color = fill.filter.color;
    269         glUniform4f(mCaches->program().getUniform("colorBlend"), color.r, color.g, color.b,
    270                     color.a);
    271     } else if (fill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
    272         glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
    273                            fill.filter.matrix.matrix);
    274         glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
    275                      fill.filter.matrix.vector);
    276     }
    277 
    278     // Round rect clipping uniforms
    279     if (glop.roundRectClipState) {
    280         // TODO: avoid query, and cache values (or RRCS ptr) in program
    281         const RoundRectClipState* state = glop.roundRectClipState;
    282         const Rect& innerRect = state->innerRect;
    283 
    284         // add half pixel to round out integer rect space to cover pixel centers
    285         float roundedOutRadius = state->radius + 0.5f;
    286 
    287         // Divide by the radius to simplify the calculations in the fragment shader
    288         // roundRectPos is also passed from vertex shader relative to top/left & radius
    289         glUniform4f(fill.program->getUniform("roundRectInnerRectLTWH"),
    290                     innerRect.left / roundedOutRadius, innerRect.top / roundedOutRadius,
    291                     (innerRect.right - innerRect.left) / roundedOutRadius,
    292                     (innerRect.bottom - innerRect.top) / roundedOutRadius);
    293 
    294         glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"), 1, GL_FALSE,
    295                            &state->matrix.data[0]);
    296 
    297         glUniform1f(fill.program->getUniform("roundRectRadius"), roundedOutRadius);
    298     }
    299 
    300     GL_CHECKPOINT(MODERATE);
    301 
    302     // --------------------------------
    303     // ---------- Mesh setup ----------
    304     // --------------------------------
    305     // vertices
    306     meshState().bindMeshBuffer(vertices.bufferObject);
    307     meshState().bindPositionVertexPointer(vertices.position, vertices.stride);
    308 
    309     // indices
    310     meshState().bindIndicesBuffer(indices.bufferObject);
    311 
    312     // texture
    313     if (fill.texture.texture != nullptr) {
    314         const Glop::Fill::TextureData& texture = fill.texture;
    315         // texture always takes slot 0, shader samplers increment from there
    316         mCaches->textureState().activateTexture(0);
    317 
    318         mCaches->textureState().bindTexture(texture.texture->target(), texture.texture->id());
    319         if (texture.clamp != GL_INVALID_ENUM) {
    320             texture.texture->setWrap(texture.clamp, false, false);
    321         }
    322         if (texture.filter != GL_INVALID_ENUM) {
    323             texture.texture->setFilter(texture.filter, false, false);
    324         }
    325 
    326         if (texture.textureTransform) {
    327             glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1, GL_FALSE,
    328                                &texture.textureTransform->data[0]);
    329         }
    330     }
    331 
    332     // vertex attributes (tex coord, color, alpha)
    333     if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
    334         meshState().enableTexCoordsVertexArray();
    335         meshState().bindTexCoordsVertexPointer(vertices.texCoord, vertices.stride);
    336     } else {
    337         meshState().disableTexCoordsVertexArray();
    338     }
    339     int colorLocation = -1;
    340     if (vertices.attribFlags & VertexAttribFlags::Color) {
    341         colorLocation = fill.program->getAttrib("colors");
    342         glEnableVertexAttribArray(colorLocation);
    343         glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride,
    344                               vertices.color);
    345     }
    346     int alphaLocation = -1;
    347     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
    348         // NOTE: alpha vertex position is computed assuming no VBO
    349         const void* alphaCoords = ((const GLbyte*)vertices.position) + kVertexAlphaOffset;
    350         alphaLocation = fill.program->getAttrib("vtxAlpha");
    351         glEnableVertexAttribArray(alphaLocation);
    352         glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
    353     }
    354     // Shader uniforms
    355     SkiaShader::apply(*mCaches, fill.skiaShaderData, mViewportWidth, mViewportHeight);
    356 
    357     GL_CHECKPOINT(MODERATE);
    358     Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType)
    359                                ? fill.skiaShaderData.bitmapData.bitmapTexture
    360                                : nullptr;
    361     const AutoTexture autoCleanup(texture);
    362 
    363     // If we have a shader and a base texture, the base texture is assumed to be an alpha mask
    364     // which means the color space conversion applies to the shader's bitmap
    365     Texture* colorSpaceTexture = texture != nullptr ? texture : fill.texture.texture;
    366     if (colorSpaceTexture != nullptr) {
    367         if (colorSpaceTexture->hasColorSpaceConversion()) {
    368             const ColorSpaceConnector* connector = colorSpaceTexture->getColorSpaceConnector();
    369             glUniformMatrix3fv(fill.program->getUniform("colorSpaceMatrix"), 1, GL_FALSE,
    370                                connector->getTransform().asArray());
    371         }
    372 
    373         TransferFunctionType transferFunction = colorSpaceTexture->getTransferFunctionType();
    374         if (transferFunction != TransferFunctionType::None) {
    375             const ColorSpaceConnector* connector = colorSpaceTexture->getColorSpaceConnector();
    376             const ColorSpace& source = connector->getSource();
    377 
    378             switch (transferFunction) {
    379                 case TransferFunctionType::None:
    380                     break;
    381                 case TransferFunctionType::Full:
    382                     glUniform1fv(fill.program->getUniform("transferFunction"), 7,
    383                                  reinterpret_cast<const float*>(&source.getTransferParameters().g));
    384                     break;
    385                 case TransferFunctionType::Limited:
    386                     glUniform1fv(fill.program->getUniform("transferFunction"), 5,
    387                                  reinterpret_cast<const float*>(&source.getTransferParameters().g));
    388                     break;
    389                 case TransferFunctionType::Gamma:
    390                     glUniform1f(fill.program->getUniform("transferFunctionGamma"),
    391                                 source.getTransferParameters().g);
    392                     break;
    393             }
    394         }
    395     }
    396 
    397     // ------------------------------------
    398     // ---------- GL state setup ----------
    399     // ------------------------------------
    400     if (CC_UNLIKELY(overrideDisableBlending)) {
    401         blend().setFactors(GL_ZERO, GL_ZERO);
    402     } else {
    403         blend().setFactors(glop.blend.src, glop.blend.dst);
    404     }
    405 
    406     GL_CHECKPOINT(MODERATE);
    407 
    408     // ------------------------------------
    409     // ---------- Actual drawing ----------
    410     // ------------------------------------
    411     if (indices.bufferObject == meshState().getQuadListIBO()) {
    412         // Since the indexed quad list is of limited length, we loop over
    413         // the glDrawXXX method while updating the vertex pointer
    414         GLsizei elementsCount = mesh.elementCount;
    415         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
    416         while (elementsCount > 0) {
    417             GLsizei drawCount = std::min(elementsCount, (GLsizei)kMaxNumberOfQuads * 6);
    418             GLsizei vertexCount = (drawCount / 6) * 4;
    419             meshState().bindPositionVertexPointer(vertexData, vertices.stride);
    420             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
    421                 meshState().bindTexCoordsVertexPointer(vertexData + kMeshTextureOffset,
    422                                                        vertices.stride);
    423             }
    424 
    425             if (mCaches->extensions().getMajorGlVersion() >= 3) {
    426                 glDrawRangeElements(mesh.primitiveMode, 0, vertexCount - 1, drawCount,
    427                                     GL_UNSIGNED_SHORT, nullptr);
    428             } else {
    429                 glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
    430             }
    431             elementsCount -= drawCount;
    432             vertexData += vertexCount * vertices.stride;
    433         }
    434     } else if (indices.bufferObject || indices.indices) {
    435         if (mCaches->extensions().getMajorGlVersion() >= 3) {
    436             // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine
    437             // the min/max index values)
    438             glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount - 1, mesh.elementCount,
    439                                 GL_UNSIGNED_SHORT, indices.indices);
    440         } else {
    441             glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT,
    442                            indices.indices);
    443         }
    444     } else {
    445         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
    446     }
    447 
    448     GL_CHECKPOINT(MODERATE);
    449 
    450     // -----------------------------------
    451     // ---------- Mesh teardown ----------
    452     // -----------------------------------
    453     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
    454         glDisableVertexAttribArray(alphaLocation);
    455     }
    456     if (vertices.attribFlags & VertexAttribFlags::Color) {
    457         glDisableVertexAttribArray(colorLocation);
    458     }
    459 
    460     GL_CHECKPOINT(MODERATE);
    461 }
    462 
    463 void RenderState::dump() {
    464     blend().dump();
    465     meshState().dump();
    466     scissor().dump();
    467     stencil().dump();
    468 }
    469 
    470 } /* namespace uirenderer */
    471 } /* namespace android */
    472