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 "SkiaShader.h"
     25 #include "Texture.h"
     26 #include "Matrix.h"
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 
     31 ///////////////////////////////////////////////////////////////////////////////
     32 // Support
     33 ///////////////////////////////////////////////////////////////////////////////
     34 
     35 static const GLint gTileModes[] = {
     36         GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
     37         GL_REPEAT,          // == SkShader::kRepeat_Mode
     38         GL_MIRRORED_REPEAT  // == SkShader::kMirror_TileMode
     39 };
     40 
     41 /**
     42  * This function does not work for n == 0.
     43  */
     44 static inline bool isPowerOfTwo(unsigned int n) {
     45     return !(n & (n - 1));
     46 }
     47 
     48 static inline void bindUniformColor(int slot, uint32_t color) {
     49     const float a = ((color >> 24) & 0xff) / 255.0f;
     50     glUniform4f(slot,
     51             a * ((color >> 16) & 0xff) / 255.0f,
     52             a * ((color >>  8) & 0xff) / 255.0f,
     53             a * ((color      ) & 0xff) / 255.0f,
     54             a);
     55 }
     56 
     57 ///////////////////////////////////////////////////////////////////////////////
     58 // Base shader
     59 ///////////////////////////////////////////////////////////////////////////////
     60 
     61 void SkiaShader::copyFrom(const SkiaShader& shader) {
     62     mType = shader.mType;
     63     mKey = shader.mKey;
     64     mTileX = shader.mTileX;
     65     mTileY = shader.mTileY;
     66     mBlend = shader.mBlend;
     67     mUnitMatrix = shader.mUnitMatrix;
     68     mShaderMatrix = shader.mShaderMatrix;
     69     mGenerationId = shader.mGenerationId;
     70 }
     71 
     72 SkiaShader::SkiaShader(): mCaches(NULL) {
     73 }
     74 
     75 SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
     76         SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
     77         mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend),
     78         mCaches(NULL) {
     79     setMatrix(matrix);
     80     mGenerationId = 0;
     81 }
     82 
     83 SkiaShader::~SkiaShader() {
     84 }
     85 
     86 void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) {
     87 }
     88 
     89 void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
     90         GLuint* textureUnit) {
     91 }
     92 
     93 void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
     94     mCaches->bindTexture(texture->id);
     95     texture->setWrapST(wrapS, wrapT);
     96 }
     97 
     98 void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
     99     screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
    100     screenSpace.multiply(modelView);
    101 }
    102 
    103 ///////////////////////////////////////////////////////////////////////////////
    104 // Bitmap shader
    105 ///////////////////////////////////////////////////////////////////////////////
    106 
    107 SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
    108         SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
    109         SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
    110     updateLocalMatrix(matrix);
    111 }
    112 
    113 SkiaShader* SkiaBitmapShader::copy() {
    114     SkiaBitmapShader* copy = new SkiaBitmapShader();
    115     copy->copyFrom(*this);
    116     copy->mBitmap = mBitmap;
    117     return copy;
    118 }
    119 
    120 void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
    121     Texture* texture = mCaches->textureCache.get(mBitmap);
    122     if (!texture) return;
    123     mTexture = texture;
    124 
    125     const float width = texture->width;
    126     const float height = texture->height;
    127 
    128     description.hasBitmap = true;
    129     // The driver does not support non-power of two mirrored/repeated
    130     // textures, so do it ourselves
    131     if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
    132             (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
    133         description.isBitmapNpot = true;
    134         description.bitmapWrapS = gTileModes[mTileX];
    135         description.bitmapWrapT = gTileModes[mTileY];
    136         mWrapS = GL_CLAMP_TO_EDGE;
    137         mWrapT = GL_CLAMP_TO_EDGE;
    138     } else {
    139         mWrapS = gTileModes[mTileX];
    140         mWrapT = gTileModes[mTileY];
    141     }
    142 }
    143 
    144 void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
    145         const Snapshot& snapshot, GLuint* textureUnit) {
    146     GLuint textureSlot = (*textureUnit)++;
    147     Caches::getInstance().activeTexture(textureSlot);
    148 
    149     Texture* texture = mTexture;
    150     mTexture = NULL;
    151     if (!texture) return;
    152     const AutoTexture autoCleanup(texture);
    153 
    154     const float width = texture->width;
    155     const float height = texture->height;
    156 
    157     mat4 textureTransform;
    158     computeScreenSpaceMatrix(textureTransform, modelView);
    159 
    160     // Uniforms
    161     bindTexture(texture, mWrapS, mWrapT);
    162     texture->setFilter(GL_LINEAR);
    163 
    164     glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
    165     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
    166             GL_FALSE, &textureTransform.data[0]);
    167     glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
    168 }
    169 
    170 ///////////////////////////////////////////////////////////////////////////////
    171 // Linear gradient shader
    172 ///////////////////////////////////////////////////////////////////////////////
    173 
    174 static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
    175     SkVector vec = pts[1] - pts[0];
    176     const float mag = vec.length();
    177     const float inv = mag ? 1.0f / mag : 0;
    178 
    179     vec.scale(inv);
    180     matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
    181     matrix->postTranslate(-pts[0].fX, -pts[0].fY);
    182     matrix->postScale(inv, inv);
    183 }
    184 
    185 SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
    186         float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
    187         SkMatrix* matrix, bool blend):
    188         SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
    189         mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
    190     SkPoint points[2];
    191     points[0].set(bounds[0], bounds[1]);
    192     points[1].set(bounds[2], bounds[3]);
    193 
    194     SkMatrix unitMatrix;
    195     toUnitMatrix(points, &unitMatrix);
    196     mUnitMatrix.load(unitMatrix);
    197 
    198     updateLocalMatrix(matrix);
    199 
    200     mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
    201 }
    202 
    203 SkiaLinearGradientShader::~SkiaLinearGradientShader() {
    204     delete[] mBounds;
    205     delete[] mColors;
    206     delete[] mPositions;
    207 }
    208 
    209 SkiaShader* SkiaLinearGradientShader::copy() {
    210     SkiaLinearGradientShader* copy = new SkiaLinearGradientShader();
    211     copy->copyFrom(*this);
    212     copy->mBounds = new float[4];
    213     memcpy(copy->mBounds, mBounds, sizeof(float) * 4);
    214     copy->mColors = new uint32_t[mCount];
    215     memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
    216     copy->mPositions = new float[mCount];
    217     memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
    218     copy->mCount = mCount;
    219     copy->mIsSimple = mIsSimple;
    220     return copy;
    221 }
    222 
    223 void SkiaLinearGradientShader::describe(ProgramDescription& description,
    224         const Extensions& extensions) {
    225     description.hasGradient = true;
    226     description.gradientType = ProgramDescription::kGradientLinear;
    227     description.isSimpleGradient = mIsSimple;
    228 }
    229 
    230 void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
    231         const Snapshot& snapshot, GLuint* textureUnit) {
    232     if (CC_UNLIKELY(!mIsSimple)) {
    233         GLuint textureSlot = (*textureUnit)++;
    234         Caches::getInstance().activeTexture(textureSlot);
    235 
    236         Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
    237 
    238         // Uniforms
    239         bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
    240         glUniform1i(program->getUniform("gradientSampler"), textureSlot);
    241     } else {
    242         bindUniformColor(program->getUniform("startColor"), mColors[0]);
    243         bindUniformColor(program->getUniform("endColor"), mColors[1]);
    244     }
    245 
    246     Caches::getInstance().dither.setupProgram(program, textureUnit);
    247 
    248     mat4 screenSpace;
    249     computeScreenSpaceMatrix(screenSpace, modelView);
    250     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
    251 }
    252 
    253 ///////////////////////////////////////////////////////////////////////////////
    254 // Circular gradient shader
    255 ///////////////////////////////////////////////////////////////////////////////
    256 
    257 static void toCircularUnitMatrix(const float x, const float y, const float radius,
    258         SkMatrix* matrix) {
    259     const float inv = 1.0f / radius;
    260     matrix->setTranslate(-x, -y);
    261     matrix->postScale(inv, inv);
    262 }
    263 
    264 SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
    265         uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
    266         SkMatrix* matrix, bool blend):
    267         SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
    268                 tileMode, matrix, blend) {
    269     SkMatrix unitMatrix;
    270     toCircularUnitMatrix(x, y, radius, &unitMatrix);
    271     mUnitMatrix.load(unitMatrix);
    272 
    273     updateLocalMatrix(matrix);
    274 }
    275 
    276 SkiaShader* SkiaCircularGradientShader::copy() {
    277     SkiaCircularGradientShader* copy = new SkiaCircularGradientShader();
    278     copy->copyFrom(*this);
    279     copy->mColors = new uint32_t[mCount];
    280     memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
    281     copy->mPositions = new float[mCount];
    282     memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
    283     copy->mCount = mCount;
    284     copy->mIsSimple = mIsSimple;
    285     return copy;
    286 }
    287 
    288 void SkiaCircularGradientShader::describe(ProgramDescription& description,
    289         const Extensions& extensions) {
    290     description.hasGradient = true;
    291     description.gradientType = ProgramDescription::kGradientCircular;
    292     description.isSimpleGradient = mIsSimple;
    293 }
    294 
    295 ///////////////////////////////////////////////////////////////////////////////
    296 // Sweep gradient shader
    297 ///////////////////////////////////////////////////////////////////////////////
    298 
    299 static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
    300     matrix->setTranslate(-x, -y);
    301 }
    302 
    303 SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
    304         float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
    305         SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
    306                 SkShader::kClamp_TileMode, matrix, blend),
    307         mColors(colors), mPositions(positions), mCount(count) {
    308     SkMatrix unitMatrix;
    309     toSweepUnitMatrix(x, y, &unitMatrix);
    310     mUnitMatrix.load(unitMatrix);
    311 
    312     updateLocalMatrix(matrix);
    313 
    314     mIsSimple = count == 2;
    315 }
    316 
    317 SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
    318         float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
    319         SkMatrix* matrix, bool blend):
    320         SkiaShader(type, key, tileMode, tileMode, matrix, blend),
    321         mColors(colors), mPositions(positions), mCount(count) {
    322 
    323     mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode;
    324 }
    325 
    326 SkiaSweepGradientShader::~SkiaSweepGradientShader() {
    327     delete[] mColors;
    328     delete[] mPositions;
    329 }
    330 
    331 SkiaShader* SkiaSweepGradientShader::copy() {
    332     SkiaSweepGradientShader* copy = new SkiaSweepGradientShader();
    333     copy->copyFrom(*this);
    334     copy->mColors = new uint32_t[mCount];
    335     memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
    336     copy->mPositions = new float[mCount];
    337     memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
    338     copy->mCount = mCount;
    339     copy->mIsSimple = mIsSimple;
    340     return copy;
    341 }
    342 
    343 void SkiaSweepGradientShader::describe(ProgramDescription& description,
    344         const Extensions& extensions) {
    345     description.hasGradient = true;
    346     description.gradientType = ProgramDescription::kGradientSweep;
    347     description.isSimpleGradient = mIsSimple;
    348 }
    349 
    350 void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
    351         const Snapshot& snapshot, GLuint* textureUnit) {
    352     if (CC_UNLIKELY(!mIsSimple)) {
    353         GLuint textureSlot = (*textureUnit)++;
    354         Caches::getInstance().activeTexture(textureSlot);
    355 
    356         Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount);
    357 
    358         // Uniforms
    359         bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
    360         glUniform1i(program->getUniform("gradientSampler"), textureSlot);
    361     } else {
    362        bindUniformColor(program->getUniform("startColor"), mColors[0]);
    363        bindUniformColor(program->getUniform("endColor"), mColors[1]);
    364     }
    365 
    366     mCaches->dither.setupProgram(program, textureUnit);
    367 
    368     mat4 screenSpace;
    369     computeScreenSpaceMatrix(screenSpace, modelView);
    370     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
    371 }
    372 
    373 ///////////////////////////////////////////////////////////////////////////////
    374 // Compose shader
    375 ///////////////////////////////////////////////////////////////////////////////
    376 
    377 SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
    378         SkXfermode::Mode mode, SkShader* key):
    379         SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
    380         NULL, first->blend() || second->blend()),
    381         mFirst(first), mSecond(second), mMode(mode), mCleanup(false) {
    382 }
    383 
    384 SkiaComposeShader::~SkiaComposeShader() {
    385     if (mCleanup) {
    386         delete mFirst;
    387         delete mSecond;
    388     }
    389 }
    390 
    391 SkiaShader* SkiaComposeShader::copy() {
    392     SkiaComposeShader* copy = new SkiaComposeShader();
    393     copy->copyFrom(*this);
    394     copy->mFirst = mFirst->copy();
    395     copy->mSecond = mSecond->copy();
    396     copy->mMode = mMode;
    397     copy->cleanup();
    398     return copy;
    399 }
    400 
    401 void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
    402     mFirst->describe(description, extensions);
    403     mSecond->describe(description, extensions);
    404     if (mFirst->type() == kBitmap) {
    405         description.isBitmapFirst = true;
    406     }
    407     description.shadersMode = mMode;
    408 }
    409 
    410 void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
    411         const Snapshot& snapshot, GLuint* textureUnit) {
    412     // Apply this compose shader's local transform and pass it down to
    413     // the child shaders. They will in turn apply their local transform
    414     // to this matrix.
    415     mat4 transform;
    416     computeScreenSpaceMatrix(transform, modelView);
    417 
    418     mFirst->setupProgram(program, transform, snapshot, textureUnit);
    419     mSecond->setupProgram(program, transform, snapshot, textureUnit);
    420 }
    421 
    422 }; // namespace uirenderer
    423 }; // namespace android
    424