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