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 "Layer.h" 25 #include "Matrix.h" 26 #include "SkiaShader.h" 27 #include "Texture.h" 28 29 namespace android { 30 namespace uirenderer { 31 32 /////////////////////////////////////////////////////////////////////////////// 33 // Support 34 /////////////////////////////////////////////////////////////////////////////// 35 36 static const GLint gTileModes[] = { 37 GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode 38 GL_REPEAT, // == SkShader::kRepeat_Mode 39 GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode 40 }; 41 42 /** 43 * This function does not work for n == 0. 44 */ 45 static inline bool isPowerOfTwo(unsigned int n) { 46 return !(n & (n - 1)); 47 } 48 49 static inline void bindUniformColor(int slot, uint32_t color) { 50 const float a = ((color >> 24) & 0xff) / 255.0f; 51 glUniform4f(slot, 52 a * ((color >> 16) & 0xff) / 255.0f, 53 a * ((color >> 8) & 0xff) / 255.0f, 54 a * ((color ) & 0xff) / 255.0f, 55 a); 56 } 57 58 static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { 59 caches->bindTexture(texture->id); 60 texture->setWrapST(wrapS, wrapT); 61 } 62 63 /** 64 * Compute the matrix to transform to screen space. 65 * @param screenSpace Output param for the computed matrix. 66 * @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient, 67 * or identity. 68 * @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix(). 69 * @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer. 70 */ 71 static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix, 72 const SkMatrix& localMatrix, const mat4& modelViewMatrix) { 73 mat4 shaderMatrix; 74 // uses implicit construction 75 shaderMatrix.loadInverse(localMatrix); 76 // again, uses implicit construction 77 screenSpace.loadMultiply(unitMatrix, shaderMatrix); 78 screenSpace.multiply(modelViewMatrix); 79 } 80 81 // Returns true if one is a bitmap and the other is a gradient 82 static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) { 83 return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType) 84 || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType); 85 } 86 87 SkiaShaderType SkiaShader::getType(const SkShader& shader) { 88 // First check for a gradient shader. 89 switch (shader.asAGradient(NULL)) { 90 case SkShader::kNone_GradientType: 91 // Not a gradient shader. Fall through to check for other types. 92 break; 93 case SkShader::kLinear_GradientType: 94 case SkShader::kRadial_GradientType: 95 case SkShader::kSweep_GradientType: 96 return kGradient_SkiaShaderType; 97 default: 98 // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip. 99 return kNone_SkiaShaderType; 100 } 101 102 // The shader is not a gradient. Check for a bitmap shader. 103 if (shader.asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) { 104 return kBitmap_SkiaShaderType; 105 } 106 107 // Check for a ComposeShader. 108 SkShader::ComposeRec rec; 109 if (shader.asACompose(&rec)) { 110 const SkiaShaderType shaderAType = getType(*rec.fShaderA); 111 const SkiaShaderType shaderBType = getType(*rec.fShaderB); 112 113 // Compose is only supported if one is a bitmap and the other is a 114 // gradient. Otherwise, return None to skip. 115 if (!bitmapAndGradient(shaderAType, shaderBType)) { 116 return kNone_SkiaShaderType; 117 } 118 return kCompose_SkiaShaderType; 119 } 120 121 if (shader.asACustomShader(NULL)) { 122 return kLayer_SkiaShaderType; 123 } 124 125 return kNone_SkiaShaderType; 126 } 127 128 typedef void (*describeProc)(Caches* caches, ProgramDescription& description, 129 const Extensions& extensions, const SkShader& shader); 130 131 describeProc gDescribeProc[] = { 132 InvalidSkiaShader::describe, 133 SkiaBitmapShader::describe, 134 SkiaGradientShader::describe, 135 SkiaComposeShader::describe, 136 SkiaLayerShader::describe, 137 }; 138 139 typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix, 140 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); 141 142 setupProgramProc gSetupProgramProc[] = { 143 InvalidSkiaShader::setupProgram, 144 SkiaBitmapShader::setupProgram, 145 SkiaGradientShader::setupProgram, 146 SkiaComposeShader::setupProgram, 147 SkiaLayerShader::setupProgram, 148 }; 149 150 void SkiaShader::describe(Caches* caches, ProgramDescription& description, 151 const Extensions& extensions, const SkShader& shader) { 152 gDescribeProc[getType(shader)](caches, description, extensions, shader); 153 } 154 155 void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 156 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { 157 158 gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader); 159 } 160 161 /////////////////////////////////////////////////////////////////////////////// 162 // Layer shader 163 /////////////////////////////////////////////////////////////////////////////// 164 165 void SkiaLayerShader::describe(Caches*, ProgramDescription& description, 166 const Extensions&, const SkShader& shader) { 167 description.hasBitmap = true; 168 } 169 170 void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 171 GLuint* textureUnit, const Extensions&, const SkShader& shader) { 172 Layer* layer; 173 if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) { 174 LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!"); 175 } 176 177 GLuint textureSlot = (*textureUnit)++; 178 caches->activeTexture(textureSlot); 179 180 const float width = layer->getWidth(); 181 const float height = layer->getHeight(); 182 183 mat4 textureTransform; 184 computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), 185 modelViewMatrix); 186 187 188 // Uniforms 189 layer->bindTexture(); 190 layer->setWrap(GL_CLAMP_TO_EDGE); 191 layer->setFilter(GL_LINEAR); 192 193 Program* program = caches->currentProgram; 194 glUniform1i(program->getUniform("bitmapSampler"), textureSlot); 195 glUniformMatrix4fv(program->getUniform("textureTransform"), 1, 196 GL_FALSE, &textureTransform.data[0]); 197 glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height); 198 } 199 200 /////////////////////////////////////////////////////////////////////////////// 201 // Bitmap shader 202 /////////////////////////////////////////////////////////////////////////////// 203 204 struct BitmapShaderInfo { 205 float width; 206 float height; 207 GLenum wrapS; 208 GLenum wrapT; 209 Texture* texture; 210 }; 211 212 static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description, 213 BitmapShaderInfo* shaderInfo, 214 const Extensions& extensions, 215 const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) { 216 Texture* texture = caches->textureCache.get(&bitmap); 217 if (!texture) return false; 218 219 const float width = texture->width; 220 const float height = texture->height; 221 GLenum wrapS, wrapT; 222 223 if (description) { 224 description->hasBitmap = true; 225 } 226 // The driver does not support non-power of two mirrored/repeated 227 // textures, so do it ourselves 228 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && 229 (tileModes[0] != SkShader::kClamp_TileMode || 230 tileModes[1] != SkShader::kClamp_TileMode)) { 231 if (description) { 232 description->isBitmapNpot = true; 233 description->bitmapWrapS = gTileModes[tileModes[0]]; 234 description->bitmapWrapT = gTileModes[tileModes[1]]; 235 } 236 wrapS = GL_CLAMP_TO_EDGE; 237 wrapT = GL_CLAMP_TO_EDGE; 238 } else { 239 wrapS = gTileModes[tileModes[0]]; 240 wrapT = gTileModes[tileModes[1]]; 241 } 242 243 if (shaderInfo) { 244 shaderInfo->width = width; 245 shaderInfo->height = height; 246 shaderInfo->wrapS = wrapS; 247 shaderInfo->wrapT = wrapT; 248 shaderInfo->texture = texture; 249 } 250 return true; 251 } 252 253 void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description, 254 const Extensions& extensions, const SkShader& shader) { 255 SkBitmap bitmap; 256 SkShader::TileMode xy[2]; 257 if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) { 258 LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!"); 259 } 260 bitmapShaderHelper(caches, &description, NULL, extensions, bitmap, xy); 261 } 262 263 void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 264 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { 265 SkBitmap bitmap; 266 SkShader::TileMode xy[2]; 267 if (shader.asABitmap(&bitmap, NULL, xy) != SkShader::kDefault_BitmapType) { 268 LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!"); 269 } 270 271 GLuint textureSlot = (*textureUnit)++; 272 Caches::getInstance().activeTexture(textureSlot); 273 274 BitmapShaderInfo shaderInfo; 275 if (!bitmapShaderHelper(caches, NULL, &shaderInfo, extensions, bitmap, xy)) { 276 return; 277 } 278 279 Program* program = caches->currentProgram; 280 Texture* texture = shaderInfo.texture; 281 282 const AutoTexture autoCleanup(texture); 283 284 mat4 textureTransform; 285 computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), 286 modelViewMatrix); 287 288 // Uniforms 289 bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT); 290 texture->setFilter(GL_LINEAR); 291 292 glUniform1i(program->getUniform("bitmapSampler"), textureSlot); 293 glUniformMatrix4fv(program->getUniform("textureTransform"), 1, 294 GL_FALSE, &textureTransform.data[0]); 295 glUniform2f(program->getUniform("textureDimension"), 1.0f / shaderInfo.width, 296 1.0f / shaderInfo.height); 297 } 298 299 /////////////////////////////////////////////////////////////////////////////// 300 // Linear gradient shader 301 /////////////////////////////////////////////////////////////////////////////// 302 303 static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { 304 SkVector vec = pts[1] - pts[0]; 305 const float mag = vec.length(); 306 const float inv = mag ? 1.0f / mag : 0; 307 308 vec.scale(inv); 309 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 310 matrix->postTranslate(-pts[0].fX, -pts[0].fY); 311 matrix->postScale(inv, inv); 312 } 313 314 /////////////////////////////////////////////////////////////////////////////// 315 // Circular gradient shader 316 /////////////////////////////////////////////////////////////////////////////// 317 318 static void toCircularUnitMatrix(const float x, const float y, const float radius, 319 SkMatrix* matrix) { 320 const float inv = 1.0f / radius; 321 matrix->setTranslate(-x, -y); 322 matrix->postScale(inv, inv); 323 } 324 325 /////////////////////////////////////////////////////////////////////////////// 326 // Sweep gradient shader 327 /////////////////////////////////////////////////////////////////////////////// 328 329 static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { 330 matrix->setTranslate(-x, -y); 331 } 332 333 /////////////////////////////////////////////////////////////////////////////// 334 // Common gradient code 335 /////////////////////////////////////////////////////////////////////////////// 336 337 static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) { 338 return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode; 339 } 340 341 void SkiaGradientShader::describe(Caches*, ProgramDescription& description, 342 const Extensions& extensions, const SkShader& shader) { 343 SkShader::GradientInfo gradInfo; 344 gradInfo.fColorCount = 0; 345 gradInfo.fColors = NULL; 346 gradInfo.fColorOffsets = NULL; 347 348 switch (shader.asAGradient(&gradInfo)) { 349 case SkShader::kLinear_GradientType: 350 description.gradientType = ProgramDescription::kGradientLinear; 351 break; 352 case SkShader::kRadial_GradientType: 353 description.gradientType = ProgramDescription::kGradientCircular; 354 break; 355 case SkShader::kSweep_GradientType: 356 description.gradientType = ProgramDescription::kGradientSweep; 357 break; 358 default: 359 // Do nothing. This shader is unsupported. 360 return; 361 } 362 description.hasGradient = true; 363 description.isSimpleGradient = isSimpleGradient(gradInfo); 364 } 365 366 void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 367 GLuint* textureUnit, const Extensions&, const SkShader& shader) { 368 // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient 369 // how much space has been allocated for fColors and fColorOffsets. 10 was chosen 370 // arbitrarily, but should be >= 2. 371 // As output, it tells the number of actual colors/offsets in the gradient. 372 const int COLOR_COUNT = 10; 373 SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT); 374 SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT); 375 376 SkShader::GradientInfo gradInfo; 377 gradInfo.fColorCount = COLOR_COUNT; 378 gradInfo.fColors = colorStorage.get(); 379 gradInfo.fColorOffsets = positionStorage.get(); 380 381 SkShader::GradientType gradType = shader.asAGradient(&gradInfo); 382 383 Program* program = caches->currentProgram; 384 if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) { 385 if (gradInfo.fColorCount > COLOR_COUNT) { 386 // There was not enough room in our arrays for all the colors and offsets. Try again, 387 // now that we know the true number of colors. 388 gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount); 389 gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount); 390 391 shader.asAGradient(&gradInfo); 392 } 393 GLuint textureSlot = (*textureUnit)++; 394 caches->activeTexture(textureSlot); 395 396 #ifndef SK_SCALAR_IS_FLOAT 397 #error Need to convert gradInfo.fColorOffsets to float! 398 #endif 399 Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets, 400 gradInfo.fColorCount); 401 402 // Uniforms 403 bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]); 404 glUniform1i(program->getUniform("gradientSampler"), textureSlot); 405 } else { 406 bindUniformColor(program->getUniform("startColor"), gradInfo.fColors[0]); 407 bindUniformColor(program->getUniform("endColor"), gradInfo.fColors[1]); 408 } 409 410 caches->dither.setupProgram(program, textureUnit); 411 412 SkMatrix unitMatrix; 413 switch (gradType) { 414 case SkShader::kLinear_GradientType: 415 toUnitMatrix(gradInfo.fPoint, &unitMatrix); 416 break; 417 case SkShader::kRadial_GradientType: 418 toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, 419 gradInfo.fRadius[0], &unitMatrix); 420 break; 421 case SkShader::kSweep_GradientType: 422 toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix); 423 break; 424 default: 425 LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType); 426 } 427 428 mat4 screenSpace; 429 computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix); 430 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 431 } 432 433 /////////////////////////////////////////////////////////////////////////////// 434 // Compose shader 435 /////////////////////////////////////////////////////////////////////////////// 436 437 void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description, 438 const Extensions& extensions, const SkShader& shader) { 439 SkShader::ComposeRec rec; 440 if (!shader.asACompose(&rec)) { 441 LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!"); 442 } 443 SkiaShader::describe(caches, description, extensions, *rec.fShaderA); 444 SkiaShader::describe(caches, description, extensions, *rec.fShaderB); 445 if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) { 446 description.isBitmapFirst = true; 447 } 448 if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) { 449 // TODO: Support other modes. 450 description.shadersMode = SkXfermode::kSrcOver_Mode; 451 } 452 } 453 454 void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 455 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { 456 SkShader::ComposeRec rec; 457 if (!shader.asACompose(&rec)) { 458 LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!"); 459 } 460 461 // Apply this compose shader's local transform and pass it down to 462 // the child shaders. They will in turn apply their local transform 463 // to this matrix. 464 mat4 transform; 465 computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), 466 modelViewMatrix); 467 468 SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA); 469 SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB); 470 } 471 472 }; // namespace uirenderer 473 }; // namespace android 474