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 
     18 #include "renderthread/CanvasContext.h"
     19 #include "renderthread/EglManager.h"
     20 #include "utils/GLUtils.h"
     21 
     22 namespace android {
     23 namespace uirenderer {
     24 
     25 RenderState::RenderState(renderthread::RenderThread& thread)
     26         : mRenderThread(thread)
     27         , mViewportWidth(0)
     28         , mViewportHeight(0)
     29         , mFramebuffer(0) {
     30     mThreadId = pthread_self();
     31 }
     32 
     33 RenderState::~RenderState() {
     34     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
     35             "State object lifecycle not managed correctly");
     36 }
     37 
     38 void RenderState::onGLContextCreated() {
     39     LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
     40             "State object lifecycle not managed correctly");
     41     mBlend = new Blend();
     42     mMeshState = new MeshState();
     43     mScissor = new Scissor();
     44     mStencil = new Stencil();
     45 
     46     // This is delayed because the first access of Caches makes GL calls
     47     if (!mCaches) {
     48         mCaches = &Caches::createInstance(*this);
     49     }
     50     mCaches->init();
     51     mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
     52 }
     53 
     54 static void layerLostGlContext(Layer* layer) {
     55     layer->onGlContextLost();
     56 }
     57 
     58 void RenderState::onGLContextDestroyed() {
     59 /*
     60     size_t size = mActiveLayers.size();
     61     if (CC_UNLIKELY(size != 0)) {
     62         ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d",
     63                 mRegisteredContexts.size(), size, mActiveLayers.empty());
     64         mCaches->dumpMemoryUsage();
     65         for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin();
     66                 cit != mRegisteredContexts.end(); cit++) {
     67             renderthread::CanvasContext* context = *cit;
     68             ALOGE("Context: %p (root = %p)", context, context->mRootRenderNode.get());
     69             ALOGE("  Prefeteched layers: %zu", context->mPrefetechedLayers.size());
     70             for (std::set<RenderNode*>::iterator pit = context->mPrefetechedLayers.begin();
     71                     pit != context->mPrefetechedLayers.end(); pit++) {
     72                 (*pit)->debugDumpLayers("    ");
     73             }
     74             context->mRootRenderNode->debugDumpLayers("  ");
     75         }
     76 
     77 
     78         if (mActiveLayers.begin() == mActiveLayers.end()) {
     79             ALOGE("set has become empty. wat.");
     80         }
     81         for (std::set<const Layer*>::iterator lit = mActiveLayers.begin();
     82              lit != mActiveLayers.end(); lit++) {
     83             const Layer* layer = *(lit);
     84             ALOGE("Layer %p, state %d, texlayer %d, fbo %d, buildlayered %d",
     85                     layer, layer->state, layer->isTextureLayer(), layer->getFbo(), layer->wasBuildLayered);
     86         }
     87         LOG_ALWAYS_FATAL("%d layers have survived gl context destruction", size);
     88     }
     89 */
     90 
     91     // TODO: reset all cached state in state objects
     92     std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
     93     mAssetAtlas.terminate();
     94 
     95     mCaches->terminate();
     96 
     97     delete mBlend;
     98     mBlend = nullptr;
     99     delete mMeshState;
    100     mMeshState = nullptr;
    101     delete mScissor;
    102     mScissor = nullptr;
    103     delete mStencil;
    104     mStencil = nullptr;
    105 }
    106 
    107 void RenderState::setViewport(GLsizei width, GLsizei height) {
    108     mViewportWidth = width;
    109     mViewportHeight = height;
    110     glViewport(0, 0, mViewportWidth, mViewportHeight);
    111 }
    112 
    113 
    114 void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
    115     *outWidth = mViewportWidth;
    116     *outHeight = mViewportHeight;
    117 }
    118 
    119 void RenderState::bindFramebuffer(GLuint fbo) {
    120     if (mFramebuffer != fbo) {
    121         mFramebuffer = fbo;
    122         glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
    123     }
    124 }
    125 
    126 void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
    127     if (mode == DrawGlInfo::kModeProcessNoContext) {
    128         // If there's no context we don't need to interrupt as there's
    129         // no gl state to save/restore
    130         (*functor)(mode, info);
    131     } else {
    132         interruptForFunctorInvoke();
    133         (*functor)(mode, info);
    134         resumeFromFunctorInvoke();
    135     }
    136 }
    137 
    138 void RenderState::interruptForFunctorInvoke() {
    139     mCaches->setProgram(nullptr);
    140     mCaches->textureState().resetActiveTexture();
    141     meshState().unbindMeshBuffer();
    142     meshState().unbindIndicesBuffer();
    143     meshState().resetVertexPointers();
    144     meshState().disableTexCoordsVertexArray();
    145     debugOverdraw(false, false);
    146 }
    147 
    148 void RenderState::resumeFromFunctorInvoke() {
    149     glViewport(0, 0, mViewportWidth, mViewportHeight);
    150     glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
    151     debugOverdraw(false, false);
    152 
    153     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    154 
    155     scissor().invalidate();
    156     blend().invalidate();
    157 
    158     mCaches->textureState().activateTexture(0);
    159     mCaches->textureState().resetBoundTextures();
    160 }
    161 
    162 void RenderState::debugOverdraw(bool enable, bool clear) {
    163     if (Properties::debugOverdraw && mFramebuffer == 0) {
    164         if (clear) {
    165             scissor().setEnabled(false);
    166             stencil().clear();
    167         }
    168         if (enable) {
    169             stencil().enableDebugWrite();
    170         } else {
    171             stencil().disable();
    172         }
    173     }
    174 }
    175 
    176 void RenderState::requireGLContext() {
    177     assertOnGLThread();
    178     LOG_ALWAYS_FATAL_IF(!mRenderThread.eglManager().hasEglContext(),
    179             "No GL context!");
    180 }
    181 
    182 void RenderState::assertOnGLThread() {
    183     pthread_t curr = pthread_self();
    184     LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
    185 }
    186 
    187 class DecStrongTask : public renderthread::RenderTask {
    188 public:
    189     DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
    190 
    191     virtual void run() override {
    192         mObject->decStrong(nullptr);
    193         mObject = nullptr;
    194         delete this;
    195     }
    196 
    197 private:
    198     VirtualLightRefBase* mObject;
    199 };
    200 
    201 void RenderState::postDecStrong(VirtualLightRefBase* object) {
    202     mRenderThread.queue(new DecStrongTask(object));
    203 }
    204 
    205 ///////////////////////////////////////////////////////////////////////////////
    206 // Render
    207 ///////////////////////////////////////////////////////////////////////////////
    208 
    209 void RenderState::render(const Glop& glop) {
    210     const Glop::Mesh& mesh = glop.mesh;
    211     const Glop::Mesh::Vertices& vertices = mesh.vertices;
    212     const Glop::Mesh::Indices& indices = mesh.indices;
    213     const Glop::Fill& fill = glop.fill;
    214 
    215     // ---------------------------------------------
    216     // ---------- Program + uniform setup ----------
    217     // ---------------------------------------------
    218     mCaches->setProgram(fill.program);
    219 
    220     if (fill.colorEnabled) {
    221         fill.program->setColor(fill.color);
    222     }
    223 
    224     fill.program->set(glop.transform.ortho,
    225             glop.transform.modelView,
    226             glop.transform.meshTransform(),
    227             glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
    228 
    229     // Color filter uniforms
    230     if (fill.filterMode == ProgramDescription::kColorBlend) {
    231         const FloatColor& color = fill.filter.color;
    232         glUniform4f(mCaches->program().getUniform("colorBlend"),
    233                 color.r, color.g, color.b, color.a);
    234     } else if (fill.filterMode == ProgramDescription::kColorMatrix) {
    235         glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
    236                 fill.filter.matrix.matrix);
    237         glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
    238                 fill.filter.matrix.vector);
    239     }
    240 
    241     // Round rect clipping uniforms
    242     if (glop.roundRectClipState) {
    243         // TODO: avoid query, and cache values (or RRCS ptr) in program
    244         const RoundRectClipState* state = glop.roundRectClipState;
    245         const Rect& innerRect = state->innerRect;
    246         glUniform4f(fill.program->getUniform("roundRectInnerRectLTRB"),
    247                 innerRect.left, innerRect.top,
    248                 innerRect.right, innerRect.bottom);
    249         glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
    250                 1, GL_FALSE, &state->matrix.data[0]);
    251 
    252         // add half pixel to round out integer rect space to cover pixel centers
    253         float roundedOutRadius = state->radius + 0.5f;
    254         glUniform1f(fill.program->getUniform("roundRectRadius"),
    255                 roundedOutRadius);
    256     }
    257 
    258     // --------------------------------
    259     // ---------- Mesh setup ----------
    260     // --------------------------------
    261     // vertices
    262     const bool force = meshState().bindMeshBufferInternal(vertices.bufferObject)
    263             || (vertices.position != nullptr);
    264     meshState().bindPositionVertexPointer(force, vertices.position, vertices.stride);
    265 
    266     // indices
    267     meshState().bindIndicesBufferInternal(indices.bufferObject);
    268 
    269     if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
    270         const Glop::Fill::TextureData& texture = fill.texture;
    271         // texture always takes slot 0, shader samplers increment from there
    272         mCaches->textureState().activateTexture(0);
    273 
    274         if (texture.clamp != GL_INVALID_ENUM) {
    275             texture.texture->setWrap(texture.clamp, true, false, texture.target);
    276         }
    277         if (texture.filter != GL_INVALID_ENUM) {
    278             texture.texture->setFilter(texture.filter, true, false, texture.target);
    279         }
    280 
    281         mCaches->textureState().bindTexture(texture.target, texture.texture->id);
    282         meshState().enableTexCoordsVertexArray();
    283         meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
    284 
    285         if (texture.textureTransform) {
    286             glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
    287                     GL_FALSE, &texture.textureTransform->data[0]);
    288         }
    289     } else {
    290         meshState().disableTexCoordsVertexArray();
    291     }
    292     int colorLocation = -1;
    293     if (vertices.attribFlags & VertexAttribFlags::Color) {
    294         colorLocation = fill.program->getAttrib("colors");
    295         glEnableVertexAttribArray(colorLocation);
    296         glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
    297     }
    298     int alphaLocation = -1;
    299     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
    300         // NOTE: alpha vertex position is computed assuming no VBO
    301         const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
    302         alphaLocation = fill.program->getAttrib("vtxAlpha");
    303         glEnableVertexAttribArray(alphaLocation);
    304         glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
    305     }
    306     // Shader uniforms
    307     SkiaShader::apply(*mCaches, fill.skiaShaderData);
    308 
    309     // ------------------------------------
    310     // ---------- GL state setup ----------
    311     // ------------------------------------
    312     blend().setFactors(glop.blend.src, glop.blend.dst);
    313 
    314     // ------------------------------------
    315     // ---------- Actual drawing ----------
    316     // ------------------------------------
    317     if (indices.bufferObject == meshState().getQuadListIBO()) {
    318         // Since the indexed quad list is of limited length, we loop over
    319         // the glDrawXXX method while updating the vertex pointer
    320         GLsizei elementsCount = mesh.elementCount;
    321         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
    322         while (elementsCount > 0) {
    323             GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
    324 
    325             // rebind pointers without forcing, since initial bind handled above
    326             meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
    327             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
    328                 meshState().bindTexCoordsVertexPointer(false,
    329                         vertexData + kMeshTextureOffset, vertices.stride);
    330             }
    331 
    332             glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
    333             elementsCount -= drawCount;
    334             vertexData += (drawCount / 6) * 4 * vertices.stride;
    335         }
    336     } else if (indices.bufferObject || indices.indices) {
    337         glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
    338     } else {
    339         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
    340     }
    341 
    342     // -----------------------------------
    343     // ---------- Mesh teardown ----------
    344     // -----------------------------------
    345     if (vertices.attribFlags & VertexAttribFlags::Alpha) {
    346         glDisableVertexAttribArray(alphaLocation);
    347     }
    348     if (vertices.attribFlags & VertexAttribFlags::Color) {
    349         glDisableVertexAttribArray(colorLocation);
    350     }
    351 }
    352 
    353 void RenderState::dump() {
    354     blend().dump();
    355     meshState().dump();
    356     scissor().dump();
    357     stencil().dump();
    358 }
    359 
    360 } /* namespace uirenderer */
    361 } /* namespace android */
    362