SkiaShader.cpp revision 8164c2d338781c3a3c4a443941070dca5d88f2a7
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 27namespace android { 28namespace uirenderer { 29 30/////////////////////////////////////////////////////////////////////////////// 31// Support 32/////////////////////////////////////////////////////////////////////////////// 33 34static const GLenum gTextureUnitsMap[] = { 35 GL_TEXTURE0, 36 GL_TEXTURE1, 37 GL_TEXTURE2 38}; 39 40static 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 50SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, 51 SkShader::TileMode tileY, SkMatrix* matrix, bool blend): 52 mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) { 53 setMatrix(matrix); 54} 55 56SkiaShader::~SkiaShader() { 57} 58 59void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) { 60} 61 62void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, 63 GLuint* textureUnit) { 64} 65 66void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) { 67 glActiveTexture(gTextureUnitsMap[textureUnit]); 68 glBindTexture(GL_TEXTURE_2D, texture->id); 69 if (wrapS != texture->wrapS) { 70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); 71 texture->wrapS = wrapS; 72 } 73 if (wrapT != texture->wrapT) { 74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); 75 texture->wrapT = wrapT; 76 } 77} 78 79void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) { 80 screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix); 81 screenSpace.multiply(modelView); 82} 83 84/////////////////////////////////////////////////////////////////////////////// 85// Bitmap shader 86/////////////////////////////////////////////////////////////////////////////// 87 88SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX, 89 SkShader::TileMode tileY, SkMatrix* matrix, bool blend): 90 SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) { 91 updateLocalMatrix(matrix); 92} 93 94void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) { 95 Texture* texture = mTextureCache->get(mBitmap); 96 if (!texture) return; 97 mTexture = texture; 98 99 const float width = texture->width; 100 const float height = texture->height; 101 102 description.hasBitmap = true; 103 // The driver does not support non-power of two mirrored/repeated 104 // textures, so do it ourselves 105 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && 106 (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) { 107 description.isBitmapNpot = true; 108 description.bitmapWrapS = gTileModes[mTileX]; 109 description.bitmapWrapT = gTileModes[mTileY]; 110 mWrapS = GL_CLAMP_TO_EDGE; 111 mWrapT = GL_CLAMP_TO_EDGE; 112 } else { 113 mWrapS = gTileModes[mTileX]; 114 mWrapT = gTileModes[mTileY]; 115 } 116} 117 118void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView, 119 const Snapshot& snapshot, GLuint* textureUnit) { 120 GLuint textureSlot = (*textureUnit)++; 121 glActiveTexture(gTextureUnitsMap[textureSlot]); 122 123 Texture* texture = mTexture; 124 mTexture = NULL; 125 if (!texture) return; 126 const AutoTexture autoCleanup(texture); 127 128 const float width = texture->width; 129 const float height = texture->height; 130 131 mat4 textureTransform; 132 computeScreenSpaceMatrix(textureTransform, modelView); 133 134 // Uniforms 135 bindTexture(texture, mWrapS, mWrapT, textureSlot); 136 glUniform1i(program->getUniform("bitmapSampler"), textureSlot); 137 glUniformMatrix4fv(program->getUniform("textureTransform"), 1, 138 GL_FALSE, &textureTransform.data[0]); 139 glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); 140} 141 142void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView, 143 const Snapshot& snapshot) { 144 mat4 textureTransform; 145 computeScreenSpaceMatrix(textureTransform, modelView); 146 glUniformMatrix4fv(program->getUniform("textureTransform"), 1, 147 GL_FALSE, &textureTransform.data[0]); 148} 149 150/////////////////////////////////////////////////////////////////////////////// 151// Linear gradient shader 152/////////////////////////////////////////////////////////////////////////////// 153 154static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { 155 SkVector vec = pts[1] - pts[0]; 156 const float mag = vec.length(); 157 const float inv = mag ? 1.0f / mag : 0; 158 159 vec.scale(inv); 160 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 161 matrix->postTranslate(-pts[0].fX, -pts[0].fY); 162 matrix->postScale(inv, inv); 163} 164 165SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors, 166 float* positions, int count, SkShader* key, SkShader::TileMode tileMode, 167 SkMatrix* matrix, bool blend): 168 SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend), 169 mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) { 170 SkPoint points[2]; 171 points[0].set(bounds[0], bounds[1]); 172 points[1].set(bounds[2], bounds[3]); 173 174 SkMatrix unitMatrix; 175 toUnitMatrix(points, &unitMatrix); 176 mUnitMatrix.load(unitMatrix); 177 178 updateLocalMatrix(matrix); 179} 180 181SkiaLinearGradientShader::~SkiaLinearGradientShader() { 182 delete[] mBounds; 183 delete[] mColors; 184 delete[] mPositions; 185} 186 187void SkiaLinearGradientShader::describe(ProgramDescription& description, 188 const Extensions& extensions) { 189 description.hasGradient = true; 190 description.gradientType = ProgramDescription::kGradientLinear; 191} 192 193void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView, 194 const Snapshot& snapshot, GLuint* textureUnit) { 195 GLuint textureSlot = (*textureUnit)++; 196 glActiveTexture(gTextureUnitsMap[textureSlot]); 197 198 Texture* texture = mGradientCache->get(mKey); 199 if (!texture) { 200 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX); 201 } 202 203 mat4 screenSpace; 204 computeScreenSpaceMatrix(screenSpace, modelView); 205 206 // Uniforms 207 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot); 208 glUniform1i(program->getUniform("gradientSampler"), textureSlot); 209 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 210} 211 212void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView, 213 const Snapshot& snapshot) { 214 mat4 screenSpace; 215 computeScreenSpaceMatrix(screenSpace, modelView); 216 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 217} 218 219/////////////////////////////////////////////////////////////////////////////// 220// Circular gradient shader 221/////////////////////////////////////////////////////////////////////////////// 222 223static void toCircularUnitMatrix(const float x, const float y, const float radius, 224 SkMatrix* matrix) { 225 const float inv = 1.0f / radius; 226 matrix->setTranslate(-x, -y); 227 matrix->postScale(inv, inv); 228} 229 230SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, 231 uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, 232 SkMatrix* matrix, bool blend): 233 SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key, 234 tileMode, matrix, blend) { 235 SkMatrix unitMatrix; 236 toCircularUnitMatrix(x, y, radius, &unitMatrix); 237 mUnitMatrix.load(unitMatrix); 238 239 updateLocalMatrix(matrix); 240} 241 242void SkiaCircularGradientShader::describe(ProgramDescription& description, 243 const Extensions& extensions) { 244 description.hasGradient = true; 245 description.gradientType = ProgramDescription::kGradientCircular; 246} 247 248/////////////////////////////////////////////////////////////////////////////// 249// Sweep gradient shader 250/////////////////////////////////////////////////////////////////////////////// 251 252static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { 253 matrix->setTranslate(-x, -y); 254} 255 256SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, 257 float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): 258 SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, 259 SkShader::kClamp_TileMode, matrix, blend), 260 mColors(colors), mPositions(positions), mCount(count) { 261 SkMatrix unitMatrix; 262 toSweepUnitMatrix(x, y, &unitMatrix); 263 mUnitMatrix.load(unitMatrix); 264 265 updateLocalMatrix(matrix); 266} 267 268SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, 269 float* positions, int count, SkShader* key, SkShader::TileMode tileMode, 270 SkMatrix* matrix, bool blend): 271 SkiaShader(type, key, tileMode, tileMode, matrix, blend), 272 mColors(colors), mPositions(positions), mCount(count) { 273} 274 275SkiaSweepGradientShader::~SkiaSweepGradientShader() { 276 delete[] mColors; 277 delete[] mPositions; 278} 279 280void SkiaSweepGradientShader::describe(ProgramDescription& description, 281 const Extensions& extensions) { 282 description.hasGradient = true; 283 description.gradientType = ProgramDescription::kGradientSweep; 284} 285 286void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView, 287 const Snapshot& snapshot, GLuint* textureUnit) { 288 GLuint textureSlot = (*textureUnit)++; 289 glActiveTexture(gTextureUnitsMap[textureSlot]); 290 291 Texture* texture = mGradientCache->get(mKey); 292 if (!texture) { 293 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount); 294 } 295 296 mat4 screenSpace; 297 computeScreenSpaceMatrix(screenSpace, modelView); 298 299 // Uniforms 300 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot); 301 glUniform1i(program->getUniform("gradientSampler"), textureSlot); 302 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 303} 304 305void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView, 306 const Snapshot& snapshot) { 307 mat4 screenSpace; 308 computeScreenSpaceMatrix(screenSpace, modelView); 309 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 310} 311 312/////////////////////////////////////////////////////////////////////////////// 313// Compose shader 314/////////////////////////////////////////////////////////////////////////////// 315 316SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second, 317 SkXfermode::Mode mode, SkShader* key): 318 SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 319 NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) { 320} 321 322void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) { 323 SkiaShader::set(textureCache, gradientCache); 324 mFirst->set(textureCache, gradientCache); 325 mSecond->set(textureCache, gradientCache); 326} 327 328void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) { 329 mFirst->describe(description, extensions); 330 mSecond->describe(description, extensions); 331 if (mFirst->type() == kBitmap) { 332 description.isBitmapFirst = true; 333 } 334 description.shadersMode = mMode; 335} 336 337void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView, 338 const Snapshot& snapshot, GLuint* textureUnit) { 339 mFirst->setupProgram(program, modelView, snapshot, textureUnit); 340 mSecond->setupProgram(program, modelView, snapshot, textureUnit); 341} 342 343}; // namespace uirenderer 344}; // namespace android 345