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 <utils/Log.h>
     20 
     21 #include <SkMatrix.h>
     22 
     23 #include "Caches.h"
     24 #include "Layer.h"
     25 #include "Matrix.h"
     26 #include "SkiaShader.h"
     27 #include "Texture.h"
     28 
     29 namespace android {
     30 namespace uirenderer {
     31 
     32 ///////////////////////////////////////////////////////////////////////////////
     33 // Support
     34 ///////////////////////////////////////////////////////////////////////////////
     35 
     36 static const GLint gTileModes[] = {
     37         GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
     38         GL_REPEAT,          // == SkShader::kRepeat_Mode
     39         GL_MIRRORED_REPEAT  // == SkShader::kMirror_TileMode
     40 };
     41 
     42 /**
     43  * This function does not work for n == 0.
     44  */
     45 static inline bool isPowerOfTwo(unsigned int n) {
     46     return !(n & (n - 1));
     47 }
     48 
     49 static inline void bindUniformColor(int slot, uint32_t color) {
     50     const float a = ((color >> 24) & 0xff) / 255.0f;
     51     glUniform4f(slot,
     52             a * ((color >> 16) & 0xff) / 255.0f,
     53             a * ((color >>  8) & 0xff) / 255.0f,
     54             a * ((color      ) & 0xff) / 255.0f,
     55             a);
     56 }
     57 
     58 static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) {
     59     caches->bindTexture(texture->id);
     60     texture->setWrapST(wrapS, wrapT);
     61 }
     62 
     63 /**
     64  * Compute the matrix to transform to screen space.
     65  * @param screenSpace Output param for the computed matrix.
     66  * @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient,
     67  *      or identity.
     68  * @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix().
     69  * @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer.
     70  */
     71 static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix,
     72         const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
     73     mat4 shaderMatrix;
     74     // uses implicit construction
     75     shaderMatrix.loadInverse(localMatrix);
     76     // again, uses implicit construction
     77     screenSpace.loadMultiply(unitMatrix, shaderMatrix);
     78     screenSpace.multiply(modelViewMatrix);
     79 }
     80 
     81 // Returns true if one is a bitmap and the other is a gradient
     82 static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) {
     83     return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType)
     84             || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType);
     85 }
     86 
     87 SkiaShaderType SkiaShader::getType(const SkShader& shader) {
     88     // First check for a gradient shader.
     89     switch (shader.asAGradient(NULL)) {
     90         case SkShader::kNone_GradientType:
     91             // Not a gradient shader. Fall through to check for other types.
     92             break;
     93         case SkShader::kLinear_GradientType:
     94         case SkShader::kRadial_GradientType:
     95         case SkShader::kSweep_GradientType:
     96             return kGradient_SkiaShaderType;
     97         default:
     98             // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip.
     99             return kNone_SkiaShaderType;
    100     }
    101 
    102     // The shader is not a gradient. Check for a bitmap shader.
    103     if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
    104         return kBitmap_SkiaShaderType;
    105     }
    106 
    107     // Check for a ComposeShader.
    108     SkShader::ComposeRec rec;
    109     if (shader.asACompose(&rec)) {
    110         const SkiaShaderType shaderAType = getType(*rec.fShaderA);
    111         const SkiaShaderType shaderBType = getType(*rec.fShaderB);
    112 
    113         // Compose is only supported if one is a bitmap and the other is a
    114         // gradient. Otherwise, return None to skip.
    115         if (!bitmapAndGradient(shaderAType, shaderBType)) {
    116             return kNone_SkiaShaderType;
    117         }
    118         return kCompose_SkiaShaderType;
    119     }
    120 
    121     if (shader.asACustomShader(NULL)) {
    122         return kLayer_SkiaShaderType;
    123     }
    124 
    125     return kNone_SkiaShaderType;
    126 }
    127 
    128 typedef void (*describeProc)(Caches* caches, ProgramDescription& description,
    129         const Extensions& extensions, const SkShader& shader);
    130 
    131 describeProc gDescribeProc[] = {
    132     InvalidSkiaShader::describe,
    133     SkiaBitmapShader::describe,
    134     SkiaGradientShader::describe,
    135     SkiaComposeShader::describe,
    136     SkiaLayerShader::describe,
    137 };
    138 
    139 typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix,
    140         GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
    141 
    142 setupProgramProc gSetupProgramProc[] = {
    143     InvalidSkiaShader::setupProgram,
    144     SkiaBitmapShader::setupProgram,
    145     SkiaGradientShader::setupProgram,
    146     SkiaComposeShader::setupProgram,
    147     SkiaLayerShader::setupProgram,
    148 };
    149 
    150 void SkiaShader::describe(Caches* caches, ProgramDescription& description,
    151         const Extensions& extensions, const SkShader& shader) {
    152     gDescribeProc[getType(shader)](caches, description, extensions, shader);
    153 }
    154 
    155 void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
    156         GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
    157 
    158     gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader);
    159 }
    160 
    161 ///////////////////////////////////////////////////////////////////////////////
    162 // Layer shader
    163 ///////////////////////////////////////////////////////////////////////////////
    164 
    165 void SkiaLayerShader::describe(Caches*, ProgramDescription& description,
    166         const Extensions&, const SkShader& shader) {
    167     description.hasBitmap = true;
    168 }
    169 
    170 void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
    171         GLuint* textureUnit, const Extensions&, const SkShader& shader) {
    172     Layer* layer;
    173     if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) {
    174         LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!");
    175     }
    176 
    177     GLuint textureSlot = (*textureUnit)++;
    178     caches->activeTexture(textureSlot);
    179 
    180     const float width = layer->getWidth();
    181     const float height = layer->getHeight();
    182 
    183     mat4 textureTransform;
    184     computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
    185             modelViewMatrix);
    186 
    187 
    188     // Uniforms
    189     layer->bindTexture();
    190     layer->setWrap(GL_CLAMP_TO_EDGE);
    191     layer->setFilter(GL_LINEAR);
    192 
    193     Program* program = caches->currentProgram;
    194     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
    195     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
    196             GL_FALSE, &textureTransform.data[0]);
    197     glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
    198 }
    199 
    200 ///////////////////////////////////////////////////////////////////////////////
    201 // Bitmap shader
    202 ///////////////////////////////////////////////////////////////////////////////
    203 
    204 struct BitmapShaderInfo {
    205     float width;
    206     float height;
    207     GLenum wrapS;
    208     GLenum wrapT;
    209     Texture* texture;
    210 };
    211 
    212 static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description,
    213         BitmapShaderInfo* shaderInfo,
    214         const Extensions& extensions,
    215         const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) {
    216     Texture* texture = caches->textureCache.get(&bitmap);
    217     if (!texture) return false;
    218 
    219     const float width = texture->width;
    220     const float height = texture->height;
    221     GLenum wrapS, wrapT;
    222 
    223     if (description) {
    224         description->hasBitmap = true;
    225     }
    226     // The driver does not support non-power of two mirrored/repeated
    227     // textures, so do it ourselves
    228     if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
    229             (tileModes[0] != SkShader::kClamp_TileMode ||
    230              tileModes[1] != SkShader::kClamp_TileMode)) {
    231         if (description) {
    232             description->isBitmapNpot = true;
    233             description->bitmapWrapS = gTileModes[tileModes[0]];
    234             description->bitmapWrapT = gTileModes[tileModes[1]];
    235         }
    236         wrapS = GL_CLAMP_TO_EDGE;
    237         wrapT = GL_CLAMP_TO_EDGE;
    238     } else {
    239         wrapS = gTileModes[tileModes[0]];
    240         wrapT = gTileModes[tileModes[1]];
    241     }
    242 
    243     if (shaderInfo) {
    244         shaderInfo->width = width;
    245         shaderInfo->height = height;
    246         shaderInfo->wrapS = wrapS;
    247         shaderInfo->wrapT = wrapT;
    248         shaderInfo->texture = texture;
    249     }
    250     return true;
    251 }
    252 
    253 void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description,
    254         const Extensions& extensions, const SkShader& shader) {
    255     SkBitmap bitmap;
    256     SkShader::TileMode xy[2];
    257     if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
    258         LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!");
    259     }
    260     bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy);
    261 }
    262 
    263 void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
    264         GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
    265     SkBitmap bitmap;
    266     SkShader::TileMode xy[2];
    267     if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) {
    268         LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!");
    269     }
    270 
    271     GLuint textureSlot = (*textureUnit)++;
    272     Caches::getInstance().activeTexture(textureSlot);
    273 
    274     BitmapShaderInfo shaderInfo;
    275     if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) {
    276         return;
    277     }
    278 
    279     Program* program = caches->currentProgram;
    280     Texture* texture = shaderInfo.texture;
    281 
    282     const AutoTexture autoCleanup(texture);
    283 
    284     mat4 textureTransform;
    285     computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
    286             modelViewMatrix);
    287 
    288     // Uniforms
    289     bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
    290     texture->setFilter(GL_LINEAR);
    291 
    292     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
    293     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
    294             GL_FALSE, &textureTransform.data[0]);
    295     glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width,
    296             1.0f / shaderInfo.height);
    297 }
    298 
    299 ///////////////////////////////////////////////////////////////////////////////
    300 // Linear gradient shader
    301 ///////////////////////////////////////////////////////////////////////////////
    302 
    303 static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
    304     SkVector vec = pts[1] - pts[0];
    305     const float mag = vec.length();
    306     const float inv = mag ? 1.0f / mag : 0;
    307 
    308     vec.scale(inv);
    309     matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
    310     matrix->postTranslate(-pts[0].fX, -pts[0].fY);
    311     matrix->postScale(inv, inv);
    312 }
    313 
    314 ///////////////////////////////////////////////////////////////////////////////
    315 // Circular gradient shader
    316 ///////////////////////////////////////////////////////////////////////////////
    317 
    318 static void toCircularUnitMatrix(const float x, const float y, const float radius,
    319         SkMatrix* matrix) {
    320     const float inv = 1.0f / radius;
    321     matrix->setTranslate(-x, -y);
    322     matrix->postScale(inv, inv);
    323 }
    324 
    325 ///////////////////////////////////////////////////////////////////////////////
    326 // Sweep gradient shader
    327 ///////////////////////////////////////////////////////////////////////////////
    328 
    329 static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
    330     matrix->setTranslate(-x, -y);
    331 }
    332 
    333 ///////////////////////////////////////////////////////////////////////////////
    334 // Common gradient code
    335 ///////////////////////////////////////////////////////////////////////////////
    336 
    337 static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) {
    338     return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode;
    339 }
    340 
    341 void SkiaGradientShader::describe(Caches*, ProgramDescription& description,
    342         const Extensions& extensions, const SkShader& shader) {
    343     SkShader::GradientInfo gradInfo;
    344     gradInfo.fColorCount = 0;
    345     gradInfo.fColors = NULL;
    346     gradInfo.fColorOffsets = NULL;
    347 
    348     switch (shader.asAGradient(&gradInfo)) {
    349         case SkShader::kLinear_GradientType:
    350             description.gradientType = ProgramDescription::kGradientLinear;
    351             break;
    352         case SkShader::kRadial_GradientType:
    353             description.gradientType = ProgramDescription::kGradientCircular;
    354             break;
    355         case SkShader::kSweep_GradientType:
    356             description.gradientType = ProgramDescription::kGradientSweep;
    357             break;
    358         default:
    359             // Do nothing. This shader is unsupported.
    360             return;
    361     }
    362     description.hasGradient = true;
    363     description.isSimpleGradient = isSimpleGradient(gradInfo);
    364 }
    365 
    366 void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
    367         GLuint* textureUnit, const Extensions&, const SkShader& shader) {
    368     // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient
    369     // how much space has been allocated for fColors and fColorOffsets.  10 was chosen
    370     // arbitrarily, but should be >= 2.
    371     // As output, it tells the number of actual colors/offsets in the gradient.
    372     const int COLOR_COUNT = 10;
    373     SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT);
    374     SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT);
    375 
    376     SkShader::GradientInfo gradInfo;
    377     gradInfo.fColorCount = COLOR_COUNT;
    378     gradInfo.fColors = colorStorage.get();
    379     gradInfo.fColorOffsets = positionStorage.get();
    380 
    381     SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
    382 
    383     Program* program = caches->currentProgram;
    384     if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
    385         if (gradInfo.fColorCount > COLOR_COUNT) {
    386             // There was not enough room in our arrays for all the colors and offsets. Try again,
    387             // now that we know the true number of colors.
    388             gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount);
    389             gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount);
    390 
    391             shader.asAGradient(&gradInfo);
    392         }
    393         GLuint textureSlot = (*textureUnit)++;
    394         caches->activeTexture(textureSlot);
    395 
    396 #ifndef SK_SCALAR_IS_FLOAT
    397     #error Need to convert gradInfo.fColorOffsets to float!
    398 #endif
    399         Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets,
    400                 gradInfo.fColorCount);
    401 
    402         // Uniforms
    403         bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
    404         glUniform1i(program->getUniform("gradientSampler"), textureSlot);
    405     } else {
    406         bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]);
    407         bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]);
    408     }
    409 
    410     caches->dither.setupProgram(program, textureUnit);
    411 
    412     SkMatrix unitMatrix;
    413     switch (gradType) {
    414         case SkShader::kLinear_GradientType:
    415             toUnitMatrix(gradInfo.fPoint, &unitMatrix);
    416             break;
    417         case SkShader::kRadial_GradientType:
    418             toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
    419                     gradInfo.fRadius[0], &unitMatrix);
    420             break;
    421         case SkShader::kSweep_GradientType:
    422             toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix);
    423             break;
    424         default:
    425             LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType);
    426     }
    427 
    428     mat4 screenSpace;
    429     computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
    430     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
    431 }
    432 
    433 ///////////////////////////////////////////////////////////////////////////////
    434 // Compose shader
    435 ///////////////////////////////////////////////////////////////////////////////
    436 
    437 void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description,
    438         const Extensions& extensions, const SkShader& shader) {
    439     SkShader::ComposeRec rec;
    440     if (!shader.asACompose(&rec)) {
    441         LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!");
    442     }
    443     SkiaShader::describe(caches, description, extensions, *rec.fShaderA);
    444     SkiaShader::describe(caches, description, extensions, *rec.fShaderB);
    445     if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) {
    446         description.isBitmapFirst = true;
    447     }
    448     if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) {
    449         // TODO: Support other modes.
    450         description.shadersMode = SkXfermode::kSrcOver_Mode;
    451     }
    452 }
    453 
    454 void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
    455         GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
    456     SkShader::ComposeRec rec;
    457     if (!shader.asACompose(&rec)) {
    458         LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!");
    459     }
    460 
    461     // Apply this compose shader's local transform and pass it down to
    462     // the child shaders. They will in turn apply their local transform
    463     // to this matrix.
    464     mat4 transform;
    465     computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(),
    466             modelViewMatrix);
    467 
    468     SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA);
    469     SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB);
    470 }
    471 
    472 }; // namespace uirenderer
    473 }; // namespace android
    474