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 int 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     return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
     61 #else
     62     return 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     Caches& caches = Caches::getInstance();
    186     GLuint fbo = caches.fboCache.get();
    187     if (!fbo) {
    188         ALOGW("Could not obtain an FBO");
    189         return NULL;
    190     }
    191 
    192     caches.activeTexture(0);
    193     Layer* layer = caches.layerCache.get(width, height);
    194     if (!layer) {
    195         ALOGW("Could not obtain a layer");
    196         return NULL;
    197     }
    198 
    199     layer->setFbo(fbo);
    200     layer->layer.set(0.0f, 0.0f, width, height);
    201     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
    202             width / float(layer->getWidth()), 0.0f);
    203     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
    204     layer->setBlend(!isOpaque);
    205     layer->setColorFilter(NULL);
    206     layer->region.clear();
    207 
    208     GLuint previousFbo;
    209     glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
    210 
    211     glBindFramebuffer(GL_FRAMEBUFFER, layer->getFbo());
    212     layer->bindTexture();
    213 
    214     // Initialize the texture if needed
    215     if (layer->isEmpty()) {
    216         layer->setEmpty(false);
    217         layer->allocateTexture(GL_RGBA, GL_UNSIGNED_BYTE);
    218 
    219         if (glGetError() != GL_NO_ERROR) {
    220             ALOGD("Could not allocate texture for layer (fbo=%d %dx%d)",
    221                     fbo, width, height);
    222 
    223             glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    224             caches.fboCache.put(fbo);
    225 
    226             layer->deleteTexture();
    227             delete layer;
    228 
    229             return NULL;
    230         }
    231     }
    232 
    233     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
    234             layer->getTexture(), 0);
    235 
    236     glDisable(GL_SCISSOR_TEST);
    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     Caches::getInstance().activeTexture(0);
    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, false, true);
    298             layer->setWrap(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         GLuint fbo = layer->getFbo();
    309         if (fbo) {
    310             flushLayer(layer);
    311             Caches::getInstance().fboCache.put(fbo);
    312             layer->setFbo(0);
    313         }
    314 
    315         if (!Caches::getInstance().layerCache.put(layer)) {
    316             LAYER_RENDERER_LOGD("  Destroyed!");
    317             layer->deleteTexture();
    318             delete layer;
    319         } else {
    320             LAYER_RENDERER_LOGD("  Cached!");
    321 #if DEBUG_LAYER_RENDERER
    322             Caches::getInstance().layerCache.dump();
    323 #endif
    324             layer->region.clear();
    325         }
    326     }
    327 }
    328 
    329 void LayerRenderer::destroyLayerDeferred(Layer* layer) {
    330     if (layer) {
    331         LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
    332 
    333         Caches::getInstance().deleteLayerDeferred(layer);
    334     }
    335 }
    336 
    337 void LayerRenderer::flushLayer(Layer* layer) {
    338 #ifdef GL_EXT_discard_framebuffer
    339     GLuint fbo = layer->getFbo();
    340     if (layer && fbo) {
    341         // If possible, discard any enqueud operations on deferred
    342         // rendering architectures
    343         if (Caches::getInstance().extensions.hasDiscardFramebuffer()) {
    344             GLuint previousFbo;
    345             glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
    346 
    347             GLenum attachments = GL_COLOR_ATTACHMENT0;
    348             if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    349             glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, &attachments);
    350 
    351             if (fbo != previousFbo) glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    352         }
    353     }
    354 #endif
    355 }
    356 
    357 bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) {
    358     Caches& caches = Caches::getInstance();
    359     if (layer && layer->isTextureLayer() && bitmap->width() <= caches.maxTextureSize &&
    360             bitmap->height() <= caches.maxTextureSize) {
    361 
    362         GLuint fbo = caches.fboCache.get();
    363         if (!fbo) {
    364             ALOGW("Could not obtain an FBO");
    365             return false;
    366         }
    367 
    368         SkAutoLockPixels alp(*bitmap);
    369 
    370         GLuint texture;
    371         GLuint previousFbo;
    372 
    373         GLenum format;
    374         GLenum type;
    375 
    376         GLenum error = GL_NO_ERROR;
    377         bool status = false;
    378 
    379         switch (bitmap->config()) {
    380             case SkBitmap::kA8_Config:
    381                 format = GL_ALPHA;
    382                 type = GL_UNSIGNED_BYTE;
    383                 break;
    384             case SkBitmap::kRGB_565_Config:
    385                 format = GL_RGB;
    386                 type = GL_UNSIGNED_SHORT_5_6_5;
    387                 break;
    388             case SkBitmap::kARGB_4444_Config:
    389                 format = GL_RGBA;
    390                 type = GL_UNSIGNED_SHORT_4_4_4_4;
    391                 break;
    392             case SkBitmap::kARGB_8888_Config:
    393             default:
    394                 format = GL_RGBA;
    395                 type = GL_UNSIGNED_BYTE;
    396                 break;
    397         }
    398 
    399         float alpha = layer->getAlpha();
    400         SkXfermode::Mode mode = layer->getMode();
    401 
    402         layer->setAlpha(255, SkXfermode::kSrc_Mode);
    403         layer->setFbo(fbo);
    404 
    405         glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
    406         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    407 
    408         glGenTextures(1, &texture);
    409         if ((error = glGetError()) != GL_NO_ERROR) goto error;
    410 
    411         caches.activeTexture(0);
    412         glBindTexture(GL_TEXTURE_2D, texture);
    413 
    414         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    415         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    416 
    417         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    418         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    419 
    420         glTexImage2D(GL_TEXTURE_2D, 0, format, bitmap->width(), bitmap->height(),
    421                 0, format, type, NULL);
    422         if ((error = glGetError()) != GL_NO_ERROR) goto error;
    423 
    424         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
    425                 GL_TEXTURE_2D, texture, 0);
    426         if ((error = glGetError()) != GL_NO_ERROR) goto error;
    427 
    428         {
    429             LayerRenderer renderer(layer);
    430             renderer.setViewport(bitmap->width(), bitmap->height());
    431             renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
    432                     bitmap->width(), bitmap->height(), !layer->isBlend());
    433 
    434             glDisable(GL_SCISSOR_TEST);
    435             renderer.translate(0.0f, bitmap->height());
    436             renderer.scale(1.0f, -1.0f);
    437 
    438             mat4 texTransform(layer->getTexTransform());
    439 
    440             mat4 invert;
    441             invert.translate(0.0f, 1.0f, 0.0f);
    442             invert.scale(1.0f, -1.0f, 1.0f);
    443             layer->getTexTransform().multiply(invert);
    444 
    445             if ((error = glGetError()) != GL_NO_ERROR) goto error;
    446 
    447             {
    448                 Rect bounds;
    449                 bounds.set(0.0f, 0.0f, bitmap->width(), bitmap->height());
    450                 renderer.drawTextureLayer(layer, bounds);
    451 
    452                 glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
    453                         type, bitmap->getPixels());
    454 
    455                 if ((error = glGetError()) != GL_NO_ERROR) goto error;
    456             }
    457 
    458             layer->getTexTransform().load(texTransform);
    459             status = true;
    460         }
    461 
    462 error:
    463         glEnable(GL_SCISSOR_TEST);
    464 
    465 #if DEBUG_OPENGL
    466         if (error != GL_NO_ERROR) {
    467             ALOGD("GL error while copying layer into bitmap = 0x%x", error);
    468         }
    469 #endif
    470 
    471         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
    472         layer->setAlpha(alpha, mode);
    473         layer->setFbo(0);
    474         glDeleteTextures(1, &texture);
    475         caches.fboCache.put(fbo);
    476 
    477         return status;
    478     }
    479     return false;
    480 }
    481 
    482 }; // namespace uirenderer
    483 }; // namespace android
    484