Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2012 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 
     17 #define LOG_TAG "OpenGLRenderer"
     18 
     19 #include <utils/Log.h>
     20 
     21 #include "Caches.h"
     22 #include "DeferredDisplayList.h"
     23 #include "Layer.h"
     24 #include "LayerRenderer.h"
     25 #include "OpenGLRenderer.h"
     26 #include "RenderNode.h"
     27 #include "RenderState.h"
     28 #include "utils/TraceUtils.h"
     29 
     30 #define ATRACE_LAYER_WORK(label) \
     31     ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
     32             label, \
     33             (renderNode.get() != NULL) ? renderNode->getName() : "", \
     34             getWidth(), getHeight())
     35 
     36 namespace android {
     37 namespace uirenderer {
     38 
     39 Layer::Layer(Type layerType, RenderState& renderState, const uint32_t layerWidth, const uint32_t layerHeight)
     40         : state(kState_Uncached)
     41         , caches(Caches::getInstance())
     42         , renderState(renderState)
     43         , texture(caches)
     44         , type(layerType) {
     45     // TODO: This is a violation of Android's typical ref counting, but it
     46     // preserves the old inc/dec ref locations. This should be changed...
     47     incStrong(0);
     48     mesh = NULL;
     49     meshElementCount = 0;
     50     cacheable = true;
     51     dirty = false;
     52     renderTarget = GL_TEXTURE_2D;
     53     texture.width = layerWidth;
     54     texture.height = layerHeight;
     55     colorFilter = NULL;
     56     deferredUpdateScheduled = false;
     57     renderer = NULL;
     58     renderNode = NULL;
     59     fbo = 0;
     60     stencil = NULL;
     61     debugDrawUpdate = false;
     62     hasDrawnSinceUpdate = false;
     63     forceFilter = false;
     64     deferredList = NULL;
     65     convexMask = NULL;
     66     rendererLightPosDirty = true;
     67     wasBuildLayered = false;
     68     renderState.registerLayer(this);
     69 }
     70 
     71 Layer::~Layer() {
     72     renderState.unregisterLayer(this);
     73     SkSafeUnref(colorFilter);
     74 
     75     if (stencil || fbo || texture.id) {
     76         renderState.requireGLContext();
     77         removeFbo();
     78         deleteTexture();
     79     }
     80 
     81     delete[] mesh;
     82     delete deferredList;
     83     delete renderer;
     84 }
     85 
     86 void Layer::onGlContextLost() {
     87     removeFbo();
     88     deleteTexture();
     89 }
     90 
     91 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
     92     return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
     93 }
     94 
     95 uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
     96     return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
     97 }
     98 
     99 void Layer::requireRenderer() {
    100     if (!renderer) {
    101         renderer = new LayerRenderer(renderState, this);
    102         renderer->initProperties();
    103     }
    104 }
    105 
    106 void Layer::updateLightPosFromRenderer(const OpenGLRenderer& rootRenderer) {
    107     if (renderer && rendererLightPosDirty) {
    108         // re-init renderer's light position, based upon last cached location in window
    109         Vector3 lightPos = rootRenderer.getLightCenter();
    110         cachedInvTransformInWindow.mapPoint3d(lightPos);
    111         renderer->initLight(lightPos, rootRenderer.getLightRadius(),
    112                 rootRenderer.getAmbientShadowAlpha(), rootRenderer.getSpotShadowAlpha());
    113         rendererLightPosDirty = false;
    114     }
    115 }
    116 
    117 bool Layer::resize(const uint32_t width, const uint32_t height) {
    118     uint32_t desiredWidth = computeIdealWidth(width);
    119     uint32_t desiredHeight = computeIdealWidth(height);
    120 
    121     if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
    122         return true;
    123     }
    124 
    125     ATRACE_NAME("resizeLayer");
    126 
    127     const uint32_t maxTextureSize = caches.maxTextureSize;
    128     if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
    129         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
    130                 desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
    131         return false;
    132     }
    133 
    134     uint32_t oldWidth = getWidth();
    135     uint32_t oldHeight = getHeight();
    136 
    137     setSize(desiredWidth, desiredHeight);
    138 
    139     if (fbo) {
    140         caches.activeTexture(0);
    141         bindTexture();
    142         allocateTexture();
    143 
    144         if (glGetError() != GL_NO_ERROR) {
    145             setSize(oldWidth, oldHeight);
    146             return false;
    147         }
    148     }
    149 
    150     if (stencil) {
    151         stencil->bind();
    152         stencil->resize(desiredWidth, desiredHeight);
    153 
    154         if (glGetError() != GL_NO_ERROR) {
    155             setSize(oldWidth, oldHeight);
    156             return false;
    157         }
    158     }
    159 
    160     return true;
    161 }
    162 
    163 void Layer::removeFbo(bool flush) {
    164     if (stencil) {
    165         GLuint previousFbo = renderState.getFramebuffer();
    166         renderState.bindFramebuffer(fbo);
    167         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
    168         renderState.bindFramebuffer(previousFbo);
    169 
    170         caches.renderBufferCache.put(stencil);
    171         stencil = NULL;
    172     }
    173 
    174     if (fbo) {
    175         if (flush) LayerRenderer::flushLayer(renderState, this);
    176         // If put fails the cache will delete the FBO
    177         caches.fboCache.put(fbo);
    178         fbo = 0;
    179     }
    180 }
    181 
    182 void Layer::updateDeferred(RenderNode* renderNode, int left, int top, int right, int bottom) {
    183     requireRenderer();
    184     this->renderNode = renderNode;
    185     const Rect r(left, top, right, bottom);
    186     dirtyRect.unionWith(r);
    187     deferredUpdateScheduled = true;
    188 }
    189 
    190 void Layer::setPaint(const SkPaint* paint) {
    191     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
    192     setColorFilter((paint) ? paint->getColorFilter() : NULL);
    193 }
    194 
    195 void Layer::setColorFilter(SkColorFilter* filter) {
    196     SkRefCnt_SafeAssign(colorFilter, filter);
    197 }
    198 
    199 void Layer::bindTexture() const {
    200     if (texture.id) {
    201         caches.bindTexture(renderTarget, texture.id);
    202     }
    203 }
    204 
    205 void Layer::bindStencilRenderBuffer() const {
    206     if (stencil) {
    207         stencil->bind();
    208     }
    209 }
    210 
    211 void Layer::generateTexture() {
    212     if (!texture.id) {
    213         glGenTextures(1, &texture.id);
    214     }
    215 }
    216 
    217 void Layer::deleteTexture() {
    218     if (texture.id) {
    219         texture.deleteTexture();
    220         texture.id = 0;
    221     }
    222 }
    223 
    224 void Layer::clearTexture() {
    225     caches.unbindTexture(texture.id);
    226     texture.id = 0;
    227 }
    228 
    229 void Layer::allocateTexture() {
    230 #if DEBUG_LAYERS
    231     ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
    232 #endif
    233     if (texture.id) {
    234         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    235         glTexImage2D(renderTarget, 0, GL_RGBA, getWidth(), getHeight(), 0,
    236                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    237     }
    238 }
    239 
    240 void Layer::defer(const OpenGLRenderer& rootRenderer) {
    241     ATRACE_LAYER_WORK("Optimize");
    242 
    243     updateLightPosFromRenderer(rootRenderer);
    244     const float width = layer.getWidth();
    245     const float height = layer.getHeight();
    246 
    247     if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
    248             dirtyRect.right >= width && dirtyRect.bottom >= height)) {
    249         dirtyRect.set(0, 0, width, height);
    250     }
    251 
    252     delete deferredList;
    253     deferredList = new DeferredDisplayList(dirtyRect);
    254 
    255     DeferStateStruct deferredState(*deferredList, *renderer,
    256             RenderNode::kReplayFlag_ClipChildren);
    257 
    258     renderer->setViewport(width, height);
    259     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
    260             dirtyRect.right, dirtyRect.bottom, !isBlend());
    261 
    262     renderNode->computeOrdering();
    263     renderNode->defer(deferredState, 0);
    264 
    265     deferredUpdateScheduled = false;
    266 }
    267 
    268 void Layer::cancelDefer() {
    269     renderNode = NULL;
    270     deferredUpdateScheduled = false;
    271     if (deferredList) {
    272         delete deferredList;
    273         deferredList = NULL;
    274     }
    275 }
    276 
    277 void Layer::flush() {
    278     // renderer is checked as layer may be destroyed/put in layer cache with flush scheduled
    279     if (deferredList && renderer) {
    280         ATRACE_LAYER_WORK("Issue");
    281         renderer->startMark((renderNode.get() != NULL) ? renderNode->getName() : "Layer");
    282 
    283         renderer->setViewport(layer.getWidth(), layer.getHeight());
    284         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
    285                 !isBlend());
    286 
    287         deferredList->flush(*renderer, dirtyRect);
    288 
    289         renderer->finish();
    290 
    291         dirtyRect.setEmpty();
    292         renderNode = NULL;
    293 
    294         renderer->endMark();
    295     }
    296 }
    297 
    298 void Layer::render(const OpenGLRenderer& rootRenderer) {
    299     ATRACE_LAYER_WORK("Direct-Issue");
    300 
    301     updateLightPosFromRenderer(rootRenderer);
    302     renderer->setViewport(layer.getWidth(), layer.getHeight());
    303     renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
    304             !isBlend());
    305 
    306     renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
    307 
    308     renderer->finish();
    309 
    310     dirtyRect.setEmpty();
    311 
    312     deferredUpdateScheduled = false;
    313     renderNode = NULL;
    314 }
    315 
    316 void Layer::postDecStrong() {
    317     renderState.postDecStrong(this);
    318 }
    319 
    320 }; // namespace uirenderer
    321 }; // namespace android
    322