Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2010 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 <cmath>
     20 
     21 #include <utils/Log.h>
     22 
     23 #include "Patch.h"
     24 #include "Caches.h"
     25 #include "Properties.h"
     26 
     27 namespace android {
     28 namespace uirenderer {
     29 
     30 ///////////////////////////////////////////////////////////////////////////////
     31 // Constructors/destructor
     32 ///////////////////////////////////////////////////////////////////////////////
     33 
     34 Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads):
     35         mXCount(xCount), mYCount(yCount), mEmptyQuads(emptyQuads) {
     36     // Initialized with the maximum number of vertices we will need
     37     // 2 triangles per patch, 3 vertices per triangle
     38     uint32_t maxVertices = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
     39     mVertices = new TextureVertex[maxVertices];
     40     mUploaded = false;
     41 
     42     verticesCount = 0;
     43     hasEmptyQuads = emptyQuads > 0;
     44 
     45     mColorKey = 0;
     46     mXDivs = new int32_t[mXCount];
     47     mYDivs = new int32_t[mYCount];
     48 
     49     PATCH_LOGD("    patch: xCount = %d, yCount = %d, emptyQuads = %d, max vertices = %d",
     50             xCount, yCount, emptyQuads, maxVertices);
     51 
     52     glGenBuffers(1, &meshBuffer);
     53 }
     54 
     55 Patch::~Patch() {
     56     delete[] mVertices;
     57     delete[] mXDivs;
     58     delete[] mYDivs;
     59     glDeleteBuffers(1, &meshBuffer);
     60 }
     61 
     62 ///////////////////////////////////////////////////////////////////////////////
     63 // Patch management
     64 ///////////////////////////////////////////////////////////////////////////////
     65 
     66 void Patch::copy(const int32_t* xDivs, const int32_t* yDivs) {
     67     memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t));
     68     memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
     69 }
     70 
     71 void Patch::copy(const int32_t* yDivs) {
     72     memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
     73 }
     74 
     75 void Patch::updateColorKey(const uint32_t colorKey) {
     76     mColorKey = colorKey;
     77 }
     78 
     79 bool Patch::matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey) {
     80     if (mColorKey != colorKey) {
     81         updateColorKey(colorKey);
     82         copy(xDivs, yDivs);
     83         return false;
     84     }
     85 
     86     for (uint32_t i = 0; i < mXCount; i++) {
     87         if (mXDivs[i] != xDivs[i]) {
     88             // The Y divs may or may not match, copy everything
     89             copy(xDivs, yDivs);
     90             return false;
     91         }
     92     }
     93 
     94     for (uint32_t i = 0; i < mYCount; i++) {
     95         if (mYDivs[i] != yDivs[i]) {
     96             // We know all the X divs match, copy only Y divs
     97             copy(yDivs);
     98             return false;
     99         }
    100     }
    101 
    102     return true;
    103 }
    104 
    105 ///////////////////////////////////////////////////////////////////////////////
    106 // Vertices management
    107 ///////////////////////////////////////////////////////////////////////////////
    108 
    109 void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
    110         float left, float top, float right, float bottom) {
    111 #if RENDER_LAYERS_AS_REGIONS
    112     if (hasEmptyQuads) quads.clear();
    113 #endif
    114 
    115     // Reset the vertices count here, we will count exactly how many
    116     // vertices we actually need when generating the quads
    117     verticesCount = 0;
    118 
    119     const uint32_t xStretchCount = (mXCount + 1) >> 1;
    120     const uint32_t yStretchCount = (mYCount + 1) >> 1;
    121 
    122     float stretchX = 0.0f;
    123     float stretchY = 0.0;
    124 
    125     const float meshWidth = right - left;
    126 
    127     if (xStretchCount > 0) {
    128         uint32_t stretchSize = 0;
    129         for (uint32_t i = 1; i < mXCount; i += 2) {
    130             stretchSize += mXDivs[i] - mXDivs[i - 1];
    131         }
    132         const float xStretchTex = stretchSize;
    133         const float fixed = bitmapWidth - stretchSize;
    134         const float xStretch = right - left - fixed;
    135         stretchX = xStretch / xStretchTex;
    136     }
    137 
    138     if (yStretchCount > 0) {
    139         uint32_t stretchSize = 0;
    140         for (uint32_t i = 1; i < mYCount; i += 2) {
    141             stretchSize += mYDivs[i] - mYDivs[i - 1];
    142         }
    143         const float yStretchTex = stretchSize;
    144         const float fixed = bitmapHeight - stretchSize;
    145         const float yStretch = bottom - top - fixed;
    146         stretchY = yStretch / yStretchTex;
    147     }
    148 
    149     TextureVertex* vertex = mVertices;
    150     uint32_t quadCount = 0;
    151 
    152     float previousStepY = 0.0f;
    153 
    154     float y1 = 0.0f;
    155     float y2 = 0.0f;
    156     float v1 = 0.0f;
    157 
    158     for (uint32_t i = 0; i < mYCount; i++) {
    159         float stepY = mYDivs[i];
    160         const float segment = stepY - previousStepY;
    161 
    162         if (i & 1) {
    163             y2 = y1 + floorf(segment * stretchY + 0.5f);
    164         } else {
    165             y2 = y1 + segment;
    166         }
    167 
    168         float vOffset = y1 == y2 ? 0.0f : 0.5 - (0.5 * segment / (y2 - y1));
    169         float v2 = fmax(0.0f, stepY - vOffset) / bitmapHeight;
    170         v1 += vOffset / bitmapHeight;
    171 
    172         if (stepY > 0.0f) {
    173 #if DEBUG_EXPLODE_PATCHES
    174             y1 += i * EXPLODE_GAP;
    175             y2 += i * EXPLODE_GAP;
    176 #endif
    177             generateRow(vertex, y1, y2, v1, v2, stretchX, right - left,
    178                     bitmapWidth, quadCount);
    179 #if DEBUG_EXPLODE_PATCHES
    180             y2 -= i * EXPLODE_GAP;
    181 #endif
    182         }
    183 
    184         y1 = y2;
    185         v1 = stepY / bitmapHeight;
    186 
    187         previousStepY = stepY;
    188     }
    189 
    190     if (previousStepY != bitmapHeight) {
    191         y2 = bottom - top;
    192 #if DEBUG_EXPLODE_PATCHES
    193         y1 += mYCount * EXPLODE_GAP;
    194         y2 += mYCount * EXPLODE_GAP;
    195 #endif
    196         generateRow(vertex, y1, y2, v1, 1.0f, stretchX, right - left, bitmapWidth, quadCount);
    197     }
    198 
    199     if (verticesCount > 0) {
    200         Caches::getInstance().bindMeshBuffer(meshBuffer);
    201         if (!mUploaded) {
    202             glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
    203                     mVertices, GL_DYNAMIC_DRAW);
    204             mUploaded = true;
    205         } else {
    206             glBufferSubData(GL_ARRAY_BUFFER, 0,
    207                     sizeof(TextureVertex) * verticesCount, mVertices);
    208         }
    209     }
    210 
    211     PATCH_LOGD("    patch: new vertices count = %d", verticesCount);
    212 }
    213 
    214 void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
    215         float stretchX, float width, float bitmapWidth, uint32_t& quadCount) {
    216     float previousStepX = 0.0f;
    217 
    218     float x1 = 0.0f;
    219     float x2 = 0.0f;
    220     float u1 = 0.0f;
    221 
    222     // Generate the row quad by quad
    223     for (uint32_t i = 0; i < mXCount; i++) {
    224         float stepX = mXDivs[i];
    225         const float segment = stepX - previousStepX;
    226 
    227         if (i & 1) {
    228             x2 = x1 + floorf(segment * stretchX + 0.5f);
    229         } else {
    230             x2 = x1 + segment;
    231         }
    232 
    233         float uOffset = x1 == x2 ? 0.0f : 0.5 - (0.5 * segment / (x2 - x1));
    234         float u2 = fmax(0.0f, stepX - uOffset) / bitmapWidth;
    235         u1 += uOffset / bitmapWidth;
    236 
    237         if (stepX > 0.0f) {
    238 #if DEBUG_EXPLODE_PATCHES
    239             x1 += i * EXPLODE_GAP;
    240             x2 += i * EXPLODE_GAP;
    241 #endif
    242             generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
    243 #if DEBUG_EXPLODE_PATCHES
    244             x2 -= i * EXPLODE_GAP;
    245 #endif
    246         }
    247 
    248         x1 = x2;
    249         u1 = stepX / bitmapWidth;
    250 
    251         previousStepX = stepX;
    252     }
    253 
    254     if (previousStepX != bitmapWidth) {
    255         x2 = width;
    256 #if DEBUG_EXPLODE_PATCHES
    257         x1 += mXCount * EXPLODE_GAP;
    258         x2 += mXCount * EXPLODE_GAP;
    259 #endif
    260         generateQuad(vertex, x1, y1, x2, y2, u1, v1, 1.0f, v2, quadCount);
    261     }
    262 }
    263 
    264 void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
    265             float u1, float v1, float u2, float v2, uint32_t& quadCount) {
    266     const uint32_t oldQuadCount = quadCount;
    267     quadCount++;
    268 
    269     // Skip degenerate and transparent (empty) quads
    270     if ((mColorKey >> oldQuadCount) & 0x1) {
    271 #if DEBUG_PATCHES_EMPTY_VERTICES
    272         PATCH_LOGD("    quad %d (empty)", oldQuadCount);
    273         PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.4f, %.4f", x1, y1, u1, v1);
    274         PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.4f, %.4f", x2, y2, u2, v2);
    275 #endif
    276         return;
    277     }
    278 
    279 #if RENDER_LAYERS_AS_REGIONS
    280     // Record all non empty quads
    281     if (hasEmptyQuads) {
    282         Rect bounds(x1, y1, x2, y2);
    283         quads.add(bounds);
    284     }
    285 #endif
    286 
    287     // Left triangle
    288     TextureVertex::set(vertex++, x1, y1, u1, v1);
    289     TextureVertex::set(vertex++, x2, y1, u2, v1);
    290     TextureVertex::set(vertex++, x1, y2, u1, v2);
    291 
    292     // Right triangle
    293     TextureVertex::set(vertex++, x1, y2, u1, v2);
    294     TextureVertex::set(vertex++, x2, y1, u2, v1);
    295     TextureVertex::set(vertex++, x2, y2, u2, v2);
    296 
    297     // A quad is made of 2 triangles, 6 vertices
    298     verticesCount += 6;
    299 
    300 #if DEBUG_PATCHES_VERTICES
    301     PATCH_LOGD("    quad %d", oldQuadCount);
    302     PATCH_LOGD("        left,  top    = %.2f, %.2f\t\tu1, v1 = %.4f, %.4f", x1, y1, u1, v1);
    303     PATCH_LOGD("        right, bottom = %.2f, %.2f\t\tu2, v2 = %.4f, %.4f", x2, y2, u2, v2);
    304 #endif
    305 }
    306 
    307 }; // namespace uirenderer
    308 }; // namespace android
    309