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