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 "DisplayList.h"
     22 #include "DeferredDisplayList.h"
     23 #include "Layer.h"
     24 #include "LayerRenderer.h"
     25 #include "OpenGLRenderer.h"
     26 #include "Caches.h"
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 
     31 Layer::Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
     32     mesh = NULL;
     33     meshIndices = NULL;
     34     meshElementCount = 0;
     35     cacheable = true;
     36     dirty = false;
     37     textureLayer = false;
     38     renderTarget = GL_TEXTURE_2D;
     39     texture.width = layerWidth;
     40     texture.height = layerHeight;
     41     colorFilter = NULL;
     42     deferredUpdateScheduled = false;
     43     renderer = NULL;
     44     displayList = NULL;
     45     fbo = 0;
     46     stencil = NULL;
     47     debugDrawUpdate = false;
     48     hasDrawnSinceUpdate = false;
     49     deferredList = NULL;
     50     Caches::getInstance().resourceCache.incrementRefcount(this);
     51 }
     52 
     53 Layer::~Layer() {
     54     if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
     55     removeFbo();
     56     deleteTexture();
     57 
     58     delete[] mesh;
     59     delete[] meshIndices;
     60     delete deferredList;
     61 }
     62 
     63 uint32_t Layer::computeIdealWidth(uint32_t layerWidth) {
     64     return uint32_t(ceilf(layerWidth / float(LAYER_SIZE)) * LAYER_SIZE);
     65 }
     66 
     67 uint32_t Layer::computeIdealHeight(uint32_t layerHeight) {
     68     return uint32_t(ceilf(layerHeight / float(LAYER_SIZE)) * LAYER_SIZE);
     69 }
     70 
     71 bool Layer::resize(const uint32_t width, const uint32_t height) {
     72     uint32_t desiredWidth = computeIdealWidth(width);
     73     uint32_t desiredHeight = computeIdealWidth(height);
     74 
     75     if (desiredWidth <= getWidth() && desiredHeight <= getHeight()) {
     76         return true;
     77     }
     78 
     79     const uint32_t maxTextureSize = Caches::getInstance().maxTextureSize;
     80     if (desiredWidth > maxTextureSize || desiredHeight > maxTextureSize) {
     81         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
     82                 desiredWidth, desiredHeight, maxTextureSize, maxTextureSize);
     83         return false;
     84     }
     85 
     86     uint32_t oldWidth = getWidth();
     87     uint32_t oldHeight = getHeight();
     88 
     89     setSize(desiredWidth, desiredHeight);
     90 
     91     if (fbo) {
     92         Caches::getInstance().activeTexture(0);
     93         bindTexture();
     94         allocateTexture();
     95 
     96         if (glGetError() != GL_NO_ERROR) {
     97             setSize(oldWidth, oldHeight);
     98             return false;
     99         }
    100     }
    101 
    102     if (stencil) {
    103         stencil->bind();
    104         stencil->resize(desiredWidth, desiredHeight);
    105 
    106         if (glGetError() != GL_NO_ERROR) {
    107             setSize(oldWidth, oldHeight);
    108             return false;
    109         }
    110     }
    111 
    112     return true;
    113 }
    114 
    115 void Layer::removeFbo(bool flush) {
    116     if (stencil) {
    117         GLuint previousFbo;
    118         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
    119         if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    120         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
    121         if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    122 
    123         Caches::getInstance().renderBufferCache.put(stencil);
    124         stencil = NULL;
    125     }
    126 
    127     if (fbo) {
    128         if (flush) LayerRenderer::flushLayer(this);
    129         // If put fails the cache will delete the FBO
    130         Caches::getInstance().fboCache.put(fbo);
    131         fbo = 0;
    132     }
    133 }
    134 
    135 void Layer::setPaint(SkPaint* paint) {
    136     OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
    137 }
    138 
    139 void Layer::setColorFilter(SkiaColorFilter* filter) {
    140     if (colorFilter) {
    141         Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
    142     }
    143     colorFilter = filter;
    144     if (colorFilter) {
    145         Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
    146     }
    147 }
    148 
    149 void Layer::defer() {
    150     if (!deferredList) {
    151         deferredList = new DeferredDisplayList;
    152     }
    153     DeferStateStruct deferredState(*deferredList, *renderer,
    154             DisplayList::kReplayFlag_ClipChildren);
    155 
    156     const float width = layer.getWidth();
    157     const float height = layer.getHeight();
    158 
    159     if (dirtyRect.isEmpty() || (dirtyRect.left <= 0 && dirtyRect.top <= 0 &&
    160             dirtyRect.right >= width && dirtyRect.bottom >= height)) {
    161         dirtyRect.set(0, 0, width, height);
    162     }
    163 
    164     renderer->initViewport(width, height);
    165     renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
    166             dirtyRect.right, dirtyRect.bottom, !isBlend());
    167 
    168     displayList->defer(deferredState, 0);
    169 
    170     deferredUpdateScheduled = false;
    171 }
    172 
    173 void Layer::flush() {
    174     if (deferredList) {
    175         renderer->setViewport(layer.getWidth(), layer.getHeight());
    176         renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
    177                 !isBlend());
    178 
    179         deferredList->flush(*renderer, dirtyRect);
    180 
    181         renderer->finish();
    182         renderer = NULL;
    183 
    184         dirtyRect.setEmpty();
    185         displayList = NULL;
    186     }
    187 }
    188 
    189 void Layer::render() {
    190     renderer->setViewport(layer.getWidth(), layer.getHeight());
    191     renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
    192             !isBlend());
    193 
    194     renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren);
    195 
    196     renderer->finish();
    197     renderer = NULL;
    198 
    199     dirtyRect.setEmpty();
    200 
    201     deferredUpdateScheduled = false;
    202     displayList = NULL;
    203 }
    204 
    205 }; // namespace uirenderer
    206 }; // namespace android
    207