diff options
Diffstat (limited to 'libs/hwui/SkiaShader.cpp')
-rw-r--r-- | libs/hwui/SkiaShader.cpp | 570 |
1 files changed, 288 insertions, 282 deletions
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 6a4a0c8..c672bc4 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -21,9 +21,10 @@ #include <SkMatrix.h> #include "Caches.h" +#include "Layer.h" +#include "Matrix.h" #include "SkiaShader.h" #include "Texture.h" -#include "Matrix.h" namespace android { namespace uirenderer { @@ -54,89 +55,142 @@ static inline void bindUniformColor(int slot, uint32_t color) { a); } -/////////////////////////////////////////////////////////////////////////////// -// Base shader -/////////////////////////////////////////////////////////////////////////////// - -void SkiaShader::copyFrom(const SkiaShader& shader) { - mType = shader.mType; - mKey = shader.mKey; - mTileX = shader.mTileX; - mTileY = shader.mTileY; - mBlend = shader.mBlend; - mUnitMatrix = shader.mUnitMatrix; - mShaderMatrix = shader.mShaderMatrix; - mGenerationId = shader.mGenerationId; +static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { + caches->bindTexture(texture->id); + texture->setWrapST(wrapS, wrapT); } -SkiaShader::SkiaShader(): mCaches(NULL) { -} +/** + * Compute the matrix to transform to screen space. + * @param screenSpace Output param for the computed matrix. + * @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient, + * or identity. + * @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix(). + * @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer. + */ +static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix, + const SkMatrix& localMatrix, const mat4& modelViewMatrix) { + mat4 shaderMatrix; + // uses implicit construction + shaderMatrix.loadInverse(localMatrix); + // again, uses implicit construction + screenSpace.loadMultiply(unitMatrix, shaderMatrix); + screenSpace.multiply(modelViewMatrix); +} + +// Returns true if one is a bitmap and the other is a gradient +static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) { + return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType) + || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType); +} + +SkiaShaderType SkiaShader::getType(const SkShader& shader) { + // First check for a gradient shader. + switch (shader.asAGradient(NULL)) { + case SkShader::kNone_GradientType: + // Not a gradient shader. Fall through to check for other types. + break; + case SkShader::kLinear_GradientType: + case SkShader::kRadial_GradientType: + case SkShader::kSweep_GradientType: + return kGradient_SkiaShaderType; + default: + // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip. + return kNone_SkiaShaderType; + } -SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, - SkShader::TileMode tileY, const SkMatrix* matrix, bool blend): - mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend), - mCaches(NULL) { - setMatrix(matrix); - mGenerationId = 0; -} + // The shader is not a gradient. Check for a bitmap shader. + if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) { + return kBitmap_SkiaShaderType; + } -SkiaShader::~SkiaShader() { -} + // Check for a ComposeShader. + SkShader::ComposeRec rec; + if (shader.asACompose(&rec)) { + const SkiaShaderType shaderAType = getType(*rec.fShaderA); + const SkiaShaderType shaderBType = getType(*rec.fShaderB); + + // Compose is only supported if one is a bitmap and the other is a + // gradient. Otherwise, return None to skip. + if (!bitmapAndGradient(shaderAType, shaderBType)) { + return kNone_SkiaShaderType; + } + return kCompose_SkiaShaderType; + } -void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) { -} + if (shader.asACustomShader(NULL)) { + return kLayer_SkiaShaderType; + } -void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, - GLuint* textureUnit) { + return kNone_SkiaShaderType; } -void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) { - mCaches->bindTexture(texture->id); - texture->setWrapST(wrapS, wrapT); +typedef void (*describeProc)(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader); + +describeProc gDescribeProc[] = { + InvalidSkiaShader::describe, + SkiaBitmapShader::describe, + SkiaGradientShader::describe, + SkiaComposeShader::describe, + SkiaLayerShader::describe, +}; + +typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); + +setupProgramProc gSetupProgramProc[] = { + InvalidSkiaShader::setupProgram, + SkiaBitmapShader::setupProgram, + SkiaGradientShader::setupProgram, + SkiaComposeShader::setupProgram, + SkiaLayerShader::setupProgram, +}; + +void SkiaShader::describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + gDescribeProc[getType(shader)](caches, description, extensions, shader); } -void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) { - screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix); - screenSpace.multiply(modelView); +void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + + gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader); } /////////////////////////////////////////////////////////////////////////////// // Layer shader /////////////////////////////////////////////////////////////////////////////// -SkiaLayerShader::SkiaLayerShader(Layer* layer, const SkMatrix* matrix): - SkiaShader(kBitmap, NULL, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - matrix, layer->isBlend()), mLayer(layer) { - updateLocalMatrix(matrix); -} - -SkiaShader* SkiaLayerShader::copy() { - SkiaLayerShader* copy = new SkiaLayerShader(); - copy->copyFrom(*this); - copy->mLayer = mLayer; - return copy; -} - -void SkiaLayerShader::describe(ProgramDescription& description, const Extensions& extensions) { +void SkiaLayerShader::describe(Caches*, ProgramDescription& description, + const Extensions&, const SkShader& shader) { description.hasBitmap = true; } -void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { +void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions&, const SkShader& shader) { + Layer* layer; + if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) { + LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!"); + } + GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); + caches->activeTexture(textureSlot); - const float width = mLayer->getWidth(); - const float height = mLayer->getHeight(); + const float width = layer->getWidth(); + const float height = layer->getHeight(); mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, modelView); + computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), + modelViewMatrix); + // Uniforms - mLayer->bindTexture(); - mLayer->setWrap(GL_CLAMP_TO_EDGE); - mLayer->setFilter(GL_LINEAR); + layer->bindTexture(); + layer->setWrap(GL_CLAMP_TO_EDGE); + layer->setFilter(GL_LINEAR); + Program* program = caches->currentProgram; glUniform1i(program->getUniform("bitmapSampler"), textureSlot); glUniformMatrix4fv(program->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); @@ -147,67 +201,99 @@ void SkiaLayerShader::setupProgram(Program* program, const mat4& modelView, // Bitmap shader /////////////////////////////////////////////////////////////////////////////// -SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, - SkShader::TileMode tileY, SkMatrix* matrix, bool blend): - SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) { - updateLocalMatrix(matrix); -} - -SkiaShader* SkiaBitmapShader::copy() { - SkiaBitmapShader* copy = new SkiaBitmapShader(); - copy->copyFrom(*this); - copy->mBitmap = mBitmap; - return copy; -} +struct BitmapShaderInfo { + float width; + float height; + GLenum wrapS; + GLenum wrapT; + Texture* texture; +}; -void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) { - Texture* texture = mCaches->textureCache.get(mBitmap); - if (!texture) return; - mTexture = texture; +static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description, + BitmapShaderInfo* shaderInfo, + const Extensions& extensions, + const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) { + Texture* texture = caches->textureCache.get(&bitmap); + if (!texture) return false; const float width = texture->width; const float height = texture->height; + GLenum wrapS, wrapT; - description.hasBitmap = true; + if (description) { + description->hasBitmap = true; + } // The driver does not support non-power of two mirrored/repeated // textures, so do it ourselves if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && - (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) { - description.isBitmapNpot = true; - description.bitmapWrapS = gTileModes[mTileX]; - description.bitmapWrapT = gTileModes[mTileY]; - mWrapS = GL_CLAMP_TO_EDGE; - mWrapT = GL_CLAMP_TO_EDGE; + (tileModes[0] != SkShader::kClamp_TileMode || + tileModes[1] != SkShader::kClamp_TileMode)) { + if (description) { + description->isBitmapNpot = true; + description->bitmapWrapS = gTileModes[tileModes[0]]; + description->bitmapWrapT = gTileModes[tileModes[1]]; + } + wrapS = GL_CLAMP_TO_EDGE; + wrapT = GL_CLAMP_TO_EDGE; } else { - mWrapS = gTileModes[mTileX]; - mWrapT = gTileModes[mTileY]; + wrapS = gTileModes[tileModes[0]]; + wrapT = gTileModes[tileModes[1]]; + } + + if (shaderInfo) { + shaderInfo->width = width; + shaderInfo->height = height; + shaderInfo->wrapS = wrapS; + shaderInfo->wrapT = wrapT; + shaderInfo->texture = texture; } + return true; } -void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot&, GLuint* textureUnit) { +void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + SkBitmap bitmap; + SkShader::TileMode xy[2]; + if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) { + LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!"); + } + bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy); +} + +void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + SkBitmap bitmap; + SkShader::TileMode xy[2]; + if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) { + LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!"); + } + GLuint textureSlot = (*textureUnit)++; Caches::getInstance().activeTexture(textureSlot); - Texture* texture = mTexture; - mTexture = NULL; - if (!texture) return; - const AutoTexture autoCleanup(texture); + BitmapShaderInfo shaderInfo; + if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) { + return; + } - const float width = texture->width; - const float height = texture->height; + Program* program = caches->currentProgram; + Texture* texture = shaderInfo.texture; + + const AutoTexture autoCleanup(texture); mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, modelView); + computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), + modelViewMatrix); // Uniforms - bindTexture(texture, mWrapS, mWrapT); + bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT); texture->setFilter(GL_LINEAR); glUniform1i(program->getUniform("bitmapSampler"), textureSlot); glUniformMatrix4fv(program->getUniform("textureTransform"), 1, GL_FALSE, &textureTransform.data[0]); - glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); + glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width, + 1.0f / shaderInfo.height); } /////////////////////////////////////////////////////////////////////////////// @@ -225,74 +311,6 @@ static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { matrix->postScale(inv, inv); } -SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors, - float* positions, int count, SkShader* key, SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend): - SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend), - mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) { - SkPoint points[2]; - points[0].set(bounds[0], bounds[1]); - points[1].set(bounds[2], bounds[3]); - - SkMatrix unitMatrix; - toUnitMatrix(points, &unitMatrix); - mUnitMatrix.load(unitMatrix); - - updateLocalMatrix(matrix); - - mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode; -} - -SkiaLinearGradientShader::~SkiaLinearGradientShader() { - delete[] mBounds; - delete[] mColors; - delete[] mPositions; -} - -SkiaShader* SkiaLinearGradientShader::copy() { - SkiaLinearGradientShader* copy = new SkiaLinearGradientShader(); - copy->copyFrom(*this); - copy->mBounds = new float[4]; - memcpy(copy->mBounds, mBounds, sizeof(float) * 4); - copy->mColors = new uint32_t[mCount]; - memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); - copy->mPositions = new float[mCount]; - memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); - copy->mCount = mCount; - copy->mIsSimple = mIsSimple; - return copy; -} - -void SkiaLinearGradientShader::describe(ProgramDescription& description, - const Extensions& extensions) { - description.hasGradient = true; - description.gradientType = ProgramDescription::kGradientLinear; - description.isSimpleGradient = mIsSimple; -} - -void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot&, GLuint* textureUnit) { - if (CC_UNLIKELY(!mIsSimple)) { - GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); - - Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount); - - // Uniforms - bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]); - glUniform1i(program->getUniform("gradientSampler"), textureSlot); - } else { - bindUniformColor(program->getUniform("startColor"), mColors[0]); - bindUniformColor(program->getUniform("endColor"), mColors[1]); - } - - Caches::getInstance().dither.setupProgram(program, textureUnit); - - mat4 screenSpace; - computeScreenSpaceMatrix(screenSpace, modelView); - glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); -} - /////////////////////////////////////////////////////////////////////////////// // Circular gradient shader /////////////////////////////////////////////////////////////////////////////// @@ -304,37 +322,6 @@ static void toCircularUnitMatrix(const float x, const float y, const float radiu matrix->postScale(inv, inv); } -SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, - uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend): - SkiaSweepGradientShader(kCircularGradient, colors, positions, count, key, - tileMode, matrix, blend) { - SkMatrix unitMatrix; - toCircularUnitMatrix(x, y, radius, &unitMatrix); - mUnitMatrix.load(unitMatrix); - - updateLocalMatrix(matrix); -} - -SkiaShader* SkiaCircularGradientShader::copy() { - SkiaCircularGradientShader* copy = new SkiaCircularGradientShader(); - copy->copyFrom(*this); - copy->mColors = new uint32_t[mCount]; - memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); - copy->mPositions = new float[mCount]; - memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); - copy->mCount = mCount; - copy->mIsSimple = mIsSimple; - return copy; -} - -void SkiaCircularGradientShader::describe(ProgramDescription& description, - const Extensions& extensions) { - description.hasGradient = true; - description.gradientType = ProgramDescription::kGradientCircular; - description.isSimpleGradient = mIsSimple; -} - /////////////////////////////////////////////////////////////////////////////// // Sweep gradient shader /////////////////////////////////////////////////////////////////////////////// @@ -343,74 +330,103 @@ static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { matrix->setTranslate(-x, -y); } -SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, - float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): - SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, matrix, blend), - mColors(colors), mPositions(positions), mCount(count) { - SkMatrix unitMatrix; - toSweepUnitMatrix(x, y, &unitMatrix); - mUnitMatrix.load(unitMatrix); - - updateLocalMatrix(matrix); - - mIsSimple = count == 2; -} - -SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, uint32_t* colors, - float* positions, int count, SkShader* key, SkShader::TileMode tileMode, - SkMatrix* matrix, bool blend): - SkiaShader(type, key, tileMode, tileMode, matrix, blend), - mColors(colors), mPositions(positions), mCount(count) { - // protected method, that doesn't setup mUnitMatrix - should be handled by subclass - - mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode; -} - -SkiaSweepGradientShader::~SkiaSweepGradientShader() { - delete[] mColors; - delete[] mPositions; -} - -SkiaShader* SkiaSweepGradientShader::copy() { - SkiaSweepGradientShader* copy = new SkiaSweepGradientShader(); - copy->copyFrom(*this); - copy->mColors = new uint32_t[mCount]; - memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); - copy->mPositions = new float[mCount]; - memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); - copy->mCount = mCount; - copy->mIsSimple = mIsSimple; - return copy; -} +/////////////////////////////////////////////////////////////////////////////// +// Common gradient code +/////////////////////////////////////////////////////////////////////////////// -void SkiaSweepGradientShader::describe(ProgramDescription& description, - const Extensions& extensions) { +static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) { + return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode; +} + +void SkiaGradientShader::describe(Caches*, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + SkShader::GradientInfo gradInfo; + gradInfo.fColorCount = 0; + gradInfo.fColors = NULL; + gradInfo.fColorOffsets = NULL; + + switch (shader.asAGradient(&gradInfo)) { + case SkShader::kLinear_GradientType: + description.gradientType = ProgramDescription::kGradientLinear; + break; + case SkShader::kRadial_GradientType: + description.gradientType = ProgramDescription::kGradientCircular; + break; + case SkShader::kSweep_GradientType: + description.gradientType = ProgramDescription::kGradientSweep; + break; + default: + // Do nothing. This shader is unsupported. + return; + } description.hasGradient = true; - description.gradientType = ProgramDescription::kGradientSweep; - description.isSimpleGradient = mIsSimple; -} - -void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { - if (CC_UNLIKELY(!mIsSimple)) { + description.isSimpleGradient = isSimpleGradient(gradInfo); +} + +void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions&, const SkShader& shader) { + // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient + // how much space has been allocated for fColors and fColorOffsets. 10 was chosen + // arbitrarily, but should be >= 2. + // As output, it tells the number of actual colors/offsets in the gradient. + const int COLOR_COUNT = 10; + SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT); + SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT); + + SkShader::GradientInfo gradInfo; + gradInfo.fColorCount = COLOR_COUNT; + gradInfo.fColors = colorStorage.get(); + gradInfo.fColorOffsets = positionStorage.get(); + + SkShader::GradientType gradType = shader.asAGradient(&gradInfo); + + Program* program = caches->currentProgram; + if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) { + if (gradInfo.fColorCount > COLOR_COUNT) { + // There was not enough room in our arrays for all the colors and offsets. Try again, + // now that we know the true number of colors. + gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount); + gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount); + + shader.asAGradient(&gradInfo); + } GLuint textureSlot = (*textureUnit)++; - Caches::getInstance().activeTexture(textureSlot); + caches->activeTexture(textureSlot); - Texture* texture = mCaches->gradientCache.get(mColors, mPositions, mCount); +#ifndef SK_SCALAR_IS_FLOAT + #error Need to convert gradInfo.fColorOffsets to float! +#endif + Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets, + gradInfo.fColorCount); // Uniforms - bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]); + bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]); glUniform1i(program->getUniform("gradientSampler"), textureSlot); } else { - bindUniformColor(program->getUniform("startColor"), mColors[0]); - bindUniformColor(program->getUniform("endColor"), mColors[1]); + bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]); + bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]); } - mCaches->dither.setupProgram(program, textureUnit); + caches->dither.setupProgram(program, textureUnit); + + SkMatrix unitMatrix; + switch (gradType) { + case SkShader::kLinear_GradientType: + toUnitMatrix(gradInfo.fPoint, &unitMatrix); + break; + case SkShader::kRadial_GradientType: + toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, + gradInfo.fRadius[0], &unitMatrix); + break; + case SkShader::kSweep_GradientType: + toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix); + break; + default: + LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType); + } mat4 screenSpace; - computeScreenSpaceMatrix(screenSpace, modelView); + computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix); glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); } @@ -418,49 +434,39 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi // Compose shader /////////////////////////////////////////////////////////////////////////////// -SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second, - SkXfermode::Mode mode, SkShader* key): - SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - NULL, first->blend() || second->blend()), - mFirst(first), mSecond(second), mMode(mode), mCleanup(false) { -} - -SkiaComposeShader::~SkiaComposeShader() { - if (mCleanup) { - delete mFirst; - delete mSecond; +void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description, + const Extensions& extensions, const SkShader& shader) { + SkShader::ComposeRec rec; + if (!shader.asACompose(&rec)) { + LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!"); } -} - -SkiaShader* SkiaComposeShader::copy() { - SkiaComposeShader* copy = new SkiaComposeShader(); - copy->copyFrom(*this); - copy->mFirst = mFirst->copy(); - copy->mSecond = mSecond->copy(); - copy->mMode = mMode; - copy->cleanup(); - return copy; -} - -void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) { - mFirst->describe(description, extensions); - mSecond->describe(description, extensions); - if (mFirst->type() == kBitmap) { + SkiaShader::describe(caches, description, extensions, *rec.fShaderA); + SkiaShader::describe(caches, description, extensions, *rec.fShaderB); + if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) { description.isBitmapFirst = true; } - description.shadersMode = mMode; + if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) { + // TODO: Support other modes. + description.shadersMode = SkXfermode::kSrcOver_Mode; + } } -void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView, - const Snapshot& snapshot, GLuint* textureUnit) { +void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, + GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { + SkShader::ComposeRec rec; + if (!shader.asACompose(&rec)) { + LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!"); + } + // Apply this compose shader's local transform and pass it down to // the child shaders. They will in turn apply their local transform // to this matrix. mat4 transform; - computeScreenSpaceMatrix(transform, modelView); + computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), + modelViewMatrix); - mFirst->setupProgram(program, transform, snapshot, textureUnit); - mSecond->setupProgram(program, transform, snapshot, textureUnit); + SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA); + SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB); } }; // namespace uirenderer |