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