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