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