diff options
Diffstat (limited to 'libs/hwui/SkiaShader.cpp')
| -rw-r--r-- | libs/hwui/SkiaShader.cpp | 372 |
1 files changed, 3 insertions, 369 deletions
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 2fcf7f3..ecf8b6b 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -47,15 +47,6 @@ static inline bool isPowerOfTwo(unsigned int n) { return !(n & (n - 1)); } -static inline void bindUniformColor(int slot, uint32_t color) { - const float a = ((color >> 24) & 0xff) / 255.0f; - glUniform4f(slot, - a * ((color >> 16) & 0xff) / 255.0f, - a * ((color >> 8) & 0xff) / 255.0f, - a * ((color ) & 0xff) / 255.0f, - a); -} - static inline void bindUniformColor(int slot, FloatColor color) { glUniform4fv(slot, 1, reinterpret_cast<const float*>(&color)); } @@ -83,229 +74,11 @@ static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatr 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(nullptr)) { - 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; - } - - // The shader is not a gradient. Check for a bitmap shader. - if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) { - return kBitmap_SkiaShaderType; - } - - // 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; - } - - if (shader.asACustomShader(nullptr)) { - return kLayer_SkiaShaderType; - } - - return kNone_SkiaShaderType; -} - -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::setupProgram(Caches* caches, const mat4& modelViewMatrix, - GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { - - gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader); -} - -/////////////////////////////////////////////////////////////////////////////// -// Layer shader -/////////////////////////////////////////////////////////////////////////////// - -void SkiaLayerShader::describe(Caches*, ProgramDescription& description, - const Extensions&, const SkShader& shader) { - description.hasBitmap = true; -} - -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->textureState().activateTexture(textureSlot); - - const float width = layer->getWidth(); - const float height = layer->getHeight(); - - mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), - modelViewMatrix); - - - // Uniforms - layer->bindTexture(); - layer->setWrap(GL_CLAMP_TO_EDGE); - layer->setFilter(GL_LINEAR); - - Program& program = caches->program(); - 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); -} - /////////////////////////////////////////////////////////////////////////////// -// Bitmap shader +// gradient shader matrix helpers /////////////////////////////////////////////////////////////////////////////// -struct BitmapShaderInfo { - float width; - float height; - GLenum wrapS; - GLenum wrapT; - Texture* 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; - - 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)) && - (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 { - 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::describe(Caches* caches, ProgramDescription& description, - const Extensions& extensions, const SkShader& shader) { - SkBitmap bitmap; - SkShader::TileMode xy[2]; - if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) { - LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!"); - } - bitmapShaderHelper(caches, &description, nullptr, 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, nullptr, xy) != SkShader::kDefault_BitmapType) { - LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!"); - } - - GLuint textureSlot = (*textureUnit)++; - caches->textureState().activateTexture(textureSlot); - - BitmapShaderInfo shaderInfo; - if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) { - return; - } - - Program& program = caches->program(); - Texture* texture = shaderInfo.texture; - - const AutoTexture autoCleanup(texture); - - mat4 textureTransform; - computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), - modelViewMatrix); - - // Uniforms - 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 / shaderInfo.width, - 1.0f / shaderInfo.height); -} - -/////////////////////////////////////////////////////////////////////////////// -// Linear gradient shader -/////////////////////////////////////////////////////////////////////////////// - -static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { +static void toLinearUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { SkVector vec = pts[1] - pts[0]; const float mag = vec.length(); const float inv = mag ? 1.0f / mag : 0; @@ -316,10 +89,6 @@ static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { matrix->postScale(inv, inv); } -/////////////////////////////////////////////////////////////////////////////// -// Circular gradient shader -/////////////////////////////////////////////////////////////////////////////// - static void toCircularUnitMatrix(const float x, const float y, const float radius, SkMatrix* matrix) { const float inv = 1.0f / radius; @@ -327,10 +96,6 @@ static void toCircularUnitMatrix(const float x, const float y, const float radiu matrix->postScale(inv, inv); } -/////////////////////////////////////////////////////////////////////////////// -// Sweep gradient shader -/////////////////////////////////////////////////////////////////////////////// - static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { matrix->setTranslate(-x, -y); } @@ -343,137 +108,6 @@ 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 = nullptr; - gradInfo.fColorOffsets = nullptr; - - 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.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->program(); - 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->textureState().activateTexture(textureSlot); - -#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(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]); - glUniform1i(program.getUniform("gradientSampler"), textureSlot); - } else { - bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]); - bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]); - } - - 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, unitMatrix, shader.getLocalMatrix(), modelViewMatrix); - glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); -} - -/////////////////////////////////////////////////////////////////////////////// -// Compose shader -/////////////////////////////////////////////////////////////////////////////// - -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::describe(caches, description, extensions, *rec.fShaderA); - SkiaShader::describe(caches, description, extensions, *rec.fShaderB); - if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) { - description.isBitmapFirst = true; - } - if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) { - // TODO: Support other modes. - description.shadersMode = SkXfermode::kSrcOver_Mode; - } -} - -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, SkMatrix::I(), shader.getLocalMatrix(), - modelViewMatrix); - - SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA); - SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB); -} - /////////////////////////////////////////////////////////////////////////////// // Store / apply /////////////////////////////////////////////////////////////////////////////// @@ -491,7 +125,7 @@ bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 mode case SkShader::kLinear_GradientType: description->gradientType = ProgramDescription::kGradientLinear; - toUnitMatrix(gradInfo.fPoint, &unitMatrix); + toLinearUnitMatrix(gradInfo.fPoint, &unitMatrix); break; case SkShader::kRadial_GradientType: description->gradientType = ProgramDescription::kGradientCircular; |
