Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2011 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 <ui/Rect.h>
     20 
     21 #include "LayerCache.h"
     22 #include "LayerRenderer.h"
     23 #include "Matrix.h"
     24 #include "Properties.h"
     25 #include "Rect.h"
     26 
     27 namespace android {
     28 namespace uirenderer {
     29 
     30 ///////////////////////////////////////////////////////////////////////////////
     31 // Rendering
     32 ///////////////////////////////////////////////////////////////////////////////
     33 
     34 LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
     35 }
     36 
     37 LayerRenderer::~LayerRenderer() {
     38 }
     39 
     40 void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     41     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
     42 
     43     glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
     44 
     45     const float width = mLayer->layer.getWidth();
     46     const float height = mLayer->layer.getHeight();
     47 
     48 #if RENDER_LAYERS_AS_REGIONS
     49     Rect dirty(left, top, right, bottom);
     50     if (dirty.isEmpty() || (dirty.left <= 0 && dirty.top <= 0 &&
     51             dirty.right >= width && dirty.bottom >= height)) {
     52         mLayer->region.clear();
     53         dirty.set(0.0f, 0.0f, width, height);
     54     } else {
     55         dirty.intersect(0.0f, 0.0f, width, height);
     56         android::Rect r(dirty.left, dirty.top, dirty.right, dirty.bottom);
     57         mLayer->region.subtractSelf(r);
     58     }
     59 
     60     OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
     61 #else
     62     OpenGLRenderer::prepareDirty(0.0f, 0.0f, width, height, opaque);
     63 #endif
     64 }
     65 
     66 void LayerRenderer::finish() {
     67     OpenGLRenderer::finish();
     68 
     69     generateMesh();
     70 
     71     LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->getFbo());
     72 
     73     // No need to unbind our FBO, this will be taken care of by the caller
     74     // who will invoke OpenGLRenderer::resume()
     75 }
     76 
     77 GLint LayerRenderer::getTargetFbo() {
     78     return mLayer->getFbo();
     79 }
     80 
     81 ///////////////////////////////////////////////////////////////////////////////
     82 // Dirty region tracking
     83 ///////////////////////////////////////////////////////////////////////////////
     84 
     85 bool LayerRenderer::hasLayer() {
     86     return true;
     87 }
     88 
     89 Region* LayerRenderer::getRegion() {
     90 #if RENDER_LAYERS_AS_REGIONS
     91     if (getSnapshot()->flags & Snapshot::kFlagFboTarget) {
     92         return OpenGLRenderer::getRegion();
     93     }
     94     return &mLayer->region;
     95 #else
     96     return OpenGLRenderer::getRegion();
     97 #endif
     98 }
     99 
    100 // TODO: This implementation is flawed and can generate T-junctions
    101 //       in the mesh, which will in turn produce cracks when the
    102 //       mesh is rotated/skewed. The easiest way to fix this would
    103 //       be, for each row, to add new vertices shared with the previous
    104 //       row when the two rows share an edge.
    105 //       In practice, T-junctions do not appear often so this has yet
    106 //       to be fixed.
    107 void LayerRenderer::generateMesh() {
    108 #if RENDER_LAYERS_AS_REGIONS
    109     if (mLayer->region.isRect() || mLayer->region.isEmpty()) {
    110         if (mLayer->mesh) {
    111             delete mLayer->mesh;
    112             delete mLayer->meshIndices;
    113 
    114             mLayer->mesh = NULL;
    115             mLayer->meshIndices = NULL;
    116             mLayer->meshElementCount = 0;
    117         }
    118 
    119         mLayer->setRegionAsRect();
    120         return;
    121     }
    122 
    123     size_t count;
    124     const android::Rect* rects = mLayer->region.getArray(&count);
    125 
    126     GLsizei elementCount = count * 6;
    127 
    128     if (mLayer->mesh && mLayer->meshElementCount < elementCount) {
    129         delete mLayer->mesh;
    130         delete mLayer->meshIndices;
    131 
    132         mLayer->mesh = NULL;
    133         mLayer->meshIndices = NULL;
    134     }
    135 
    136     bool rebuildIndices = false;
    137     if (!mLayer->mesh) {
    138         mLayer->mesh = new TextureVertex[count * 4];
    139         mLayer->meshIndices = new uint16_t[elementCount];
    140         rebuildIndices = true;
    141     }
    142     mLayer->meshElementCount = elementCount;
    143 
    144     const float texX = 1.0f / float(mLayer->getWidth());
    145     const float texY = 1.0f / float(mLayer->getHeight());
    146     const float height = mLayer->layer.getHeight();
    147 
    148     TextureVertex* mesh = mLayer->mesh;
    149     uint16_t* indices = mLayer->meshIndices;
    150 
    151     for (size_t i = 0; i < count; i++) {
    152         const android::Rect* r = &rects[i];
    153 
    154         const float u1 = r->left * texX;
    155         const float v1 = (height - r->top) * texY;
    156         const float u2 = r->right * texX;
    157         const float v2 = (height - r->bottom) * texY;
    158 
    159         TextureVertex::set(mesh++, r->left, r->top, u1, v1);
    160         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
    161         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
    162         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
    163 
    164         if (rebuildIndices) {
    165             uint16_t quad = i * 4;
    166             int index = i * 6;
    167             indices[index    ] = quad;       // top-left
    168             indices[index + 1] = quad + 1;   // top-right
    169             indices[index + 2] = quad + 2;   // bottom-left
    170             indices[index + 3] = quad + 2;   // bottom-left
    171             indices[index + 4] = quad + 1;   // top-right
    172             indices[index + 5] = quad + 3;   // bottom-right
    173         }
    174     }
    175 #endif
    176 }
    177 
    178 ///////////////////////////////////////////////////////////////////////////////
    179 // Layers management
    180 ///////////////////////////////////////////////////////////////////////////////
    181 
    182 Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
    183     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
    184 
    185     GLuint fbo = Caches::getInstance().fboCache.get();
    186     if (!fbo) {
    187         LOGW("Could not obtain an FBO");
    188         return NULL;
    189     }
    190 
    191     glActiveTexture(GL_TEXTURE0);
    192     Layer* layer = Caches::getInstance().layerCache.get(width, height);
    193     if (!layer) {
    194         LOGW("Could not obtain a layer");
    195         return NULL;
    196     }
    197 
    198     layer->setFbo(fbo);
    199     layer->layer.set(0.0f, 0.0f, width, height);
    200     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
    201             width / float(layer->getWidth()), 0.0f);
    202     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
    203     layer->setBlend(!isOpaque);
    204     layer->setColorFilter(NULL);
    205     layer->region.clear();
    206 
    207     GLuint previousFbo;
    208     glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
    209 
    210     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
    211     layer->bindTexture();
    212 
    213     // Initialize the texture if needed
    214     if (layer->isEmpty()) {
    215         layer->setEmpty(false);
    216         layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
    217 
    218         if (glGetError() != GL_NO_ERROR) {
    219             LOGD("Could not allocate texture for layer (fbo=%d %dx%d)",
    220                     fbo, width, height);
    221 
    222             glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    223             Caches::getInstance().fboCache.put(fbo);
    224 
    225             layer->deleteTexture();
    226             delete layer;
    227 
    228             return NULL;
    229         }
    230     }
    231 
    232     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
    233             layer->getTexture(), 0);
    234 
    235     glDisable(GL_SCISSOR_TEST);
    236     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    237     glClear(GL_COLOR_BUFFER_BIT);
    238     glEnable(GL_SCISSOR_TEST);
    239 
    240     glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    241 
    242     return layer;
    243 }
    244 
    245 bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
    246     if (layer) {
    247         LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->getFbo(), width, height);
    248 
    249         if (Caches::getInstance().layerCache.resize(layer, width, height)) {
    250             layer->layer.set(0.0f, 0.0f, width, height);
    251             layer->texCoords.set(0.0f, height / float(layer->getHeight()),
    252                     width / float(layer->getWidth()), 0.0f);
    253         } else {
    254             layer->deleteTexture();
    255             delete layer;
    256             return false;
    257         }
    258     }
    259 
    260     return true;
    261 }
    262 
    263 Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
    264     LAYER_RENDERER_LOGD("Creating new texture layer");
    265 
    266     Layer* layer = new Layer(0, 0);
    267     layer->setCacheable(false);
    268     layer->setTextureLayer(true);
    269     layer->setBlend(!isOpaque);
    270     layer->setEmpty(true);
    271     layer->setFbo(0);
    272     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
    273     layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
    274     layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
    275     layer->region.clear();
    276     layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
    277 
    278     glActiveTexture(GL_TEXTURE0);
    279     layer->generateTexture();
    280 
    281     return layer;
    282 }
    283 
    284 void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
    285         bool isOpaque, GLenum renderTarget, float* transform) {
    286     if (layer) {
    287         layer->setBlend(!isOpaque);
    288         layer->setSize(width, height);
    289         layer->layer.set(0.0f, 0.0f, width, height);
    290         layer->region.set(width, height);
    291         layer->regionRect.set(0.0f, 0.0f, width, height);
    292         layer->getTexTransform().load(transform);
    293 
    294         if (renderTarget != layer->getRenderTarget()) {
    295             layer->setRenderTarget(renderTarget);
    296             layer->bindTexture();
    297             layer->setFilter(GL_NEAREST, GL_NEAREST, false, true);
    298             layer->setWrap(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, false, true);
    299         }
    300     }
    301 }
    302 
    303 void LayerRenderer::destroyLayer(Layer* layer) {
    304     if (layer) {
    305         LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
    306                 layer->getWidth(), layer->getHeight(), layer->getFbo());
    307 
    308         if (layer->getFbo()) {
    309             Caches::getInstance().fboCache.put(layer->getFbo());
    310         }
    311 
    312         if (!Caches::getInstance().layerCache.put(layer)) {
    313             LAYER_RENDERER_LOGD("  Destroyed!");
    314             layer->deleteTexture();
    315             delete layer;
    316         } else {
    317             LAYER_RENDERER_LOGD("  Cached!");
    318 #if DEBUG_LAYER_RENDERER
    319             Caches::getInstance().layerCache.dump();
    320 #endif
    321             layer->region.clear();
    322         }
    323     }
    324 }
    325 
    326 void LayerRenderer::destroyLayerDeferred(Layer* layer) {
    327     if (layer) {
    328         LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
    329 
    330         Caches::getInstance().deleteLayerDeferred(layer);
    331     }
    332 }
    333 
    334 bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
    335     Caches& caches = Caches::getInstance();
    336     if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
    337             bitmap->height() <= caches.maxTextureSize) {
    338 
    339         GLuint fbo = caches.fboCache.get();
    340         if (!fbo) {
    341             LOGW("Could not obtain an FBO");
    342             return false;
    343         }
    344 
    345         SkAutoLockPixels alp(*bitmap);
    346 
    347         GLuint texture;
    348         GLuint previousFbo;
    349 
    350         GLenum format;
    351         GLenum type;
    352 
    353         GLenum error = GL_NO_ERROR;
    354         bool status = false;
    355 
    356         switch (bitmap->config()) {
    357             case SkBitmap::kA8_Config:
    358                 format = GL_ALPHA;
    359                 type = GL_UNSIGNED_BYTE;
    360                 break;
    361             case SkBitmap::kRGB_565_Config:
    362                 format = GL_RGB;
    363                 type = GL_UNSIGNED_SHORT_5_6_5;
    364                 break;
    365             case SkBitmap::kARGB_4444_Config:
    366                 format = GL_RGBA;
    367                 type = GL_UNSIGNED_SHORT_4_4_4_4;
    368                 break;
    369             case SkBitmap::kARGB_8888_Config:
    370             default:
    371                 format = GL_RGBA;
    372                 type = GL_UNSIGNED_BYTE;
    373                 break;
    374         }
    375 
    376         float alpha = layer->getAlpha();
    377         SkXfermode::Mode mode = layer->getMode();
    378 
    379         layer->setAlpha(255, SkXfermode::kSrc_Mode);
    380         layer->setFbo(fbo);
    381 
    382         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
    383         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    384 
    385         glGenTextures(1, &texture);
    386         if ((error = glGetError()) != GL_NO_ERROR) goto error;
    387 
    388         glActiveTexture(GL_TEXTURE0);
    389         glBindTexture(GL_TEXTURE_2D, texture);
    390 
    391         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    392         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    393 
    394         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    395         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    396 
    397         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
    398                 0, format, type, NULL);
    399         if ((error = glGetError()) != GL_NO_ERROR) goto error;
    400 
    401         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    402                 GL_TEXTURE_2D, texture, 0);
    403         if ((error = glGetError()) != GL_NO_ERROR) goto error;
    404 
    405         {
    406             LayerRenderer renderer(layer);
    407             renderer.setViewport(bitmap->width(), bitmap->height());
    408             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
    409                     bitmap->width(), bitmap->height(), !layer->isBlend());
    410 
    411             glDisable(GL_SCISSOR_TEST);
    412             renderer.translate(0.0f, bitmap->height());
    413             renderer.scale(1.0f, -1.0f);
    414 
    415             mat4 texTransform(layer->getTexTransform());
    416 
    417             mat4 invert;
    418             invert.translate(0.0f, 1.0f, 0.0f);
    419             invert.scale(1.0f, -1.0f, 1.0f);
    420             layer->getTexTransform().multiply(invert);
    421 
    422             if ((error = glGetError()) != GL_NO_ERROR) goto error;
    423 
    424             {
    425                 Rect bounds;
    426                 bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
    427                 renderer.drawTextureLayer(layer, bounds);
    428 
    429                 glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
    430                         type, bitmap->getPixels());
    431 
    432                 if ((error = glGetError()) != GL_NO_ERROR) goto error;
    433             }
    434 
    435             layer->getTexTransform().load(texTransform);
    436             status = true;
    437         }
    438 
    439 error:
    440 #if DEBUG_OPENGL
    441         if (error != GL_NO_ERROR) {
    442             LOGD("GL error while copying layer into bitmap = 0x%x", error);
    443         }
    444 #endif
    445 
    446         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    447         layer->setAlpha(alpha, mode);
    448         layer->setFbo(0);
    449         glDeleteTextures(1, &texture);
    450         caches.fboCache.put(fbo);
    451 
    452         return status;
    453     }
    454     return false;
    455 }
    456 
    457 }; // namespace uirenderer
    458 }; // namespace android
    459