SkiaShader.cpp revision 36a35e366a65980843b96759f863643f17ca1ee7
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 "SkiaShader.h" 20 21#include "Caches.h" 22#include "Extensions.h" 23#include "Layer.h" 24#include "Matrix.h" 25#include "Texture.h" 26 27#include <SkMatrix.h> 28#include <utils/Log.h> 29 30namespace android { 31namespace uirenderer { 32 33/////////////////////////////////////////////////////////////////////////////// 34// Support 35/////////////////////////////////////////////////////////////////////////////// 36 37static const GLenum gTileModes[] = { 38 GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode 39 GL_REPEAT, // == SkShader::kRepeat_Mode 40 GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode 41}; 42 43/** 44 * This function does not work for n == 0. 45 */ 46static inline bool isPowerOfTwo(unsigned int n) { 47 return !(n & (n - 1)); 48} 49 50static inline void bindUniformColor(int slot, uint32_t color) { 51 const float a = ((color >> 24) & 0xff) / 255.0f; 52 glUniform4f(slot, 53 a * ((color >> 16) & 0xff) / 255.0f, 54 a * ((color >> 8) & 0xff) / 255.0f, 55 a * ((color ) & 0xff) / 255.0f, 56 a); 57} 58 59static inline void bindUniformColor(int slot, FloatColor color) { 60 glUniform4fv(slot, 1, reinterpret_cast<const float*>(&color)); 61} 62 63static inline void bindTexture(Caches* caches, Texture* texture, GLenum wrapS, GLenum wrapT) { 64 caches->textureState().bindTexture(texture->id); 65 texture->setWrapST(wrapS, wrapT); 66} 67 68/** 69 * Compute the matrix to transform to screen space. 70 * @param screenSpace Output param for the computed matrix. 71 * @param unitMatrix The unit matrix for gradient shaders, as returned by SkShader::asAGradient, 72 * or identity. 73 * @param localMatrix Local matrix, as returned by SkShader::getLocalMatrix(). 74 * @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer. 75 */ 76static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix, 77 const SkMatrix& localMatrix, const mat4& modelViewMatrix) { 78 mat4 shaderMatrix; 79 // uses implicit construction 80 shaderMatrix.loadInverse(localMatrix); 81 // again, uses implicit construction 82 screenSpace.loadMultiply(unitMatrix, shaderMatrix); 83 screenSpace.multiply(modelViewMatrix); 84} 85 86// Returns true if one is a bitmap and the other is a gradient 87static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) { 88 return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType) 89 || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType); 90} 91 92SkiaShaderType SkiaShader::getType(const SkShader& shader) { 93 // First check for a gradient shader. 94 switch (shader.asAGradient(nullptr)) { 95 case SkShader::kNone_GradientType: 96 // Not a gradient shader. Fall through to check for other types. 97 break; 98 case SkShader::kLinear_GradientType: 99 case SkShader::kRadial_GradientType: 100 case SkShader::kSweep_GradientType: 101 return kGradient_SkiaShaderType; 102 default: 103 // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip. 104 return kNone_SkiaShaderType; 105 } 106 107 // The shader is not a gradient. Check for a bitmap shader. 108 if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) { 109 return kBitmap_SkiaShaderType; 110 } 111 112 // Check for a ComposeShader. 113 SkShader::ComposeRec rec; 114 if (shader.asACompose(&rec)) { 115 const SkiaShaderType shaderAType = getType(*rec.fShaderA); 116 const SkiaShaderType shaderBType = getType(*rec.fShaderB); 117 118 // Compose is only supported if one is a bitmap and the other is a 119 // gradient. Otherwise, return None to skip. 120 if (!bitmapAndGradient(shaderAType, shaderBType)) { 121 return kNone_SkiaShaderType; 122 } 123 return kCompose_SkiaShaderType; 124 } 125 126 if (shader.asACustomShader(nullptr)) { 127 return kLayer_SkiaShaderType; 128 } 129 130 return kNone_SkiaShaderType; 131} 132 133typedef void (*describeProc)(Caches* caches, ProgramDescription& description, 134 const Extensions& extensions, const SkShader& shader); 135 136describeProc gDescribeProc[] = { 137 InvalidSkiaShader::describe, 138 SkiaBitmapShader::describe, 139 SkiaGradientShader::describe, 140 SkiaComposeShader::describe, 141 SkiaLayerShader::describe, 142}; 143 144typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix, 145 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader); 146 147setupProgramProc gSetupProgramProc[] = { 148 InvalidSkiaShader::setupProgram, 149 SkiaBitmapShader::setupProgram, 150 SkiaGradientShader::setupProgram, 151 SkiaComposeShader::setupProgram, 152 SkiaLayerShader::setupProgram, 153}; 154 155void SkiaShader::describe(Caches* caches, ProgramDescription& description, 156 const Extensions& extensions, const SkShader& shader) { 157 gDescribeProc[getType(shader)](caches, description, extensions, shader); 158} 159 160void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 161 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { 162 163 gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader); 164} 165 166/////////////////////////////////////////////////////////////////////////////// 167// Layer shader 168/////////////////////////////////////////////////////////////////////////////// 169 170void SkiaLayerShader::describe(Caches*, ProgramDescription& description, 171 const Extensions&, const SkShader& shader) { 172 description.hasBitmap = true; 173} 174 175void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 176 GLuint* textureUnit, const Extensions&, const SkShader& shader) { 177 Layer* layer; 178 if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) { 179 LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!"); 180 } 181 182 GLuint textureSlot = (*textureUnit)++; 183 caches->textureState().activateTexture(textureSlot); 184 185 const float width = layer->getWidth(); 186 const float height = layer->getHeight(); 187 188 mat4 textureTransform; 189 computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), 190 modelViewMatrix); 191 192 193 // Uniforms 194 layer->bindTexture(); 195 layer->setWrap(GL_CLAMP_TO_EDGE); 196 layer->setFilter(GL_LINEAR); 197 198 Program& program = caches->program(); 199 glUniform1i(program.getUniform("bitmapSampler"), textureSlot); 200 glUniformMatrix4fv(program.getUniform("textureTransform"), 1, 201 GL_FALSE, &textureTransform.data[0]); 202 glUniform2f(program.getUniform("textureDimension"), 1.0f / width, 1.0f / height); 203} 204 205/////////////////////////////////////////////////////////////////////////////// 206// Bitmap shader 207/////////////////////////////////////////////////////////////////////////////// 208 209struct BitmapShaderInfo { 210 float width; 211 float height; 212 GLenum wrapS; 213 GLenum wrapT; 214 Texture* texture; 215}; 216 217static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description, 218 BitmapShaderInfo* shaderInfo, 219 const Extensions& extensions, 220 const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) { 221 Texture* texture = caches->textureCache.get(&bitmap); 222 if (!texture) return false; 223 224 const float width = texture->width; 225 const float height = texture->height; 226 GLenum wrapS, wrapT; 227 228 if (description) { 229 description->hasBitmap = true; 230 } 231 // The driver does not support non-power of two mirrored/repeated 232 // textures, so do it ourselves 233 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) && 234 (tileModes[0] != SkShader::kClamp_TileMode || 235 tileModes[1] != SkShader::kClamp_TileMode)) { 236 if (description) { 237 description->isBitmapNpot = true; 238 description->bitmapWrapS = gTileModes[tileModes[0]]; 239 description->bitmapWrapT = gTileModes[tileModes[1]]; 240 } 241 wrapS = GL_CLAMP_TO_EDGE; 242 wrapT = GL_CLAMP_TO_EDGE; 243 } else { 244 wrapS = gTileModes[tileModes[0]]; 245 wrapT = gTileModes[tileModes[1]]; 246 } 247 248 if (shaderInfo) { 249 shaderInfo->width = width; 250 shaderInfo->height = height; 251 shaderInfo->wrapS = wrapS; 252 shaderInfo->wrapT = wrapT; 253 shaderInfo->texture = texture; 254 } 255 return true; 256} 257 258void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description, 259 const Extensions& extensions, const SkShader& shader) { 260 SkBitmap bitmap; 261 SkShader::TileMode xy[2]; 262 if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) { 263 LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!"); 264 } 265 bitmapShaderHelper(caches, &description, nullptr, extensions, bitmap, xy); 266} 267 268void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 269 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { 270 SkBitmap bitmap; 271 SkShader::TileMode xy[2]; 272 if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) { 273 LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!"); 274 } 275 276 GLuint textureSlot = (*textureUnit)++; 277 caches->textureState().activateTexture(textureSlot); 278 279 BitmapShaderInfo shaderInfo; 280 if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) { 281 return; 282 } 283 284 Program& program = caches->program(); 285 Texture* texture = shaderInfo.texture; 286 287 const AutoTexture autoCleanup(texture); 288 289 mat4 textureTransform; 290 computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(), 291 modelViewMatrix); 292 293 // Uniforms 294 bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT); 295 texture->setFilter(GL_LINEAR); 296 297 glUniform1i(program.getUniform("bitmapSampler"), textureSlot); 298 glUniformMatrix4fv(program.getUniform("textureTransform"), 1, 299 GL_FALSE, &textureTransform.data[0]); 300 glUniform2f(program.getUniform("textureDimension"), 1.0f / shaderInfo.width, 301 1.0f / shaderInfo.height); 302} 303 304/////////////////////////////////////////////////////////////////////////////// 305// Linear gradient shader 306/////////////////////////////////////////////////////////////////////////////// 307 308static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) { 309 SkVector vec = pts[1] - pts[0]; 310 const float mag = vec.length(); 311 const float inv = mag ? 1.0f / mag : 0; 312 313 vec.scale(inv); 314 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 315 matrix->postTranslate(-pts[0].fX, -pts[0].fY); 316 matrix->postScale(inv, inv); 317} 318 319/////////////////////////////////////////////////////////////////////////////// 320// Circular gradient shader 321/////////////////////////////////////////////////////////////////////////////// 322 323static void toCircularUnitMatrix(const float x, const float y, const float radius, 324 SkMatrix* matrix) { 325 const float inv = 1.0f / radius; 326 matrix->setTranslate(-x, -y); 327 matrix->postScale(inv, inv); 328} 329 330/////////////////////////////////////////////////////////////////////////////// 331// Sweep gradient shader 332/////////////////////////////////////////////////////////////////////////////// 333 334static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { 335 matrix->setTranslate(-x, -y); 336} 337 338/////////////////////////////////////////////////////////////////////////////// 339// Common gradient code 340/////////////////////////////////////////////////////////////////////////////// 341 342static bool isSimpleGradient(const SkShader::GradientInfo& gradInfo) { 343 return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode; 344} 345 346void SkiaGradientShader::describe(Caches*, ProgramDescription& description, 347 const Extensions& extensions, const SkShader& shader) { 348 SkShader::GradientInfo gradInfo; 349 gradInfo.fColorCount = 0; 350 gradInfo.fColors = nullptr; 351 gradInfo.fColorOffsets = nullptr; 352 353 switch (shader.asAGradient(&gradInfo)) { 354 case SkShader::kLinear_GradientType: 355 description.gradientType = ProgramDescription::kGradientLinear; 356 break; 357 case SkShader::kRadial_GradientType: 358 description.gradientType = ProgramDescription::kGradientCircular; 359 break; 360 case SkShader::kSweep_GradientType: 361 description.gradientType = ProgramDescription::kGradientSweep; 362 break; 363 default: 364 // Do nothing. This shader is unsupported. 365 return; 366 } 367 description.hasGradient = true; 368 description.isSimpleGradient = isSimpleGradient(gradInfo); 369} 370 371void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 372 GLuint* textureUnit, const Extensions&, const SkShader& shader) { 373 // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient 374 // how much space has been allocated for fColors and fColorOffsets. 10 was chosen 375 // arbitrarily, but should be >= 2. 376 // As output, it tells the number of actual colors/offsets in the gradient. 377 const int COLOR_COUNT = 10; 378 SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT); 379 SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT); 380 381 SkShader::GradientInfo gradInfo; 382 gradInfo.fColorCount = COLOR_COUNT; 383 gradInfo.fColors = colorStorage.get(); 384 gradInfo.fColorOffsets = positionStorage.get(); 385 386 SkShader::GradientType gradType = shader.asAGradient(&gradInfo); 387 388 Program& program = caches->program(); 389 if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) { 390 if (gradInfo.fColorCount > COLOR_COUNT) { 391 // There was not enough room in our arrays for all the colors and offsets. Try again, 392 // now that we know the true number of colors. 393 gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount); 394 gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount); 395 396 shader.asAGradient(&gradInfo); 397 } 398 GLuint textureSlot = (*textureUnit)++; 399 caches->textureState().activateTexture(textureSlot); 400 401#ifndef SK_SCALAR_IS_FLOAT 402 #error Need to convert gradInfo.fColorOffsets to float! 403#endif 404 Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets, 405 gradInfo.fColorCount); 406 407 // Uniforms 408 bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]); 409 glUniform1i(program.getUniform("gradientSampler"), textureSlot); 410 } else { 411 bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]); 412 bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]); 413 } 414 415 caches->dither.setupProgram(program, textureUnit); 416 417 SkMatrix unitMatrix; 418 switch (gradType) { 419 case SkShader::kLinear_GradientType: 420 toUnitMatrix(gradInfo.fPoint, &unitMatrix); 421 break; 422 case SkShader::kRadial_GradientType: 423 toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, 424 gradInfo.fRadius[0], &unitMatrix); 425 break; 426 case SkShader::kSweep_GradientType: 427 toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix); 428 break; 429 default: 430 LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType); 431 } 432 433 mat4 screenSpace; 434 computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix); 435 glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 436} 437 438/////////////////////////////////////////////////////////////////////////////// 439// Compose shader 440/////////////////////////////////////////////////////////////////////////////// 441 442void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description, 443 const Extensions& extensions, const SkShader& shader) { 444 SkShader::ComposeRec rec; 445 if (!shader.asACompose(&rec)) { 446 LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!"); 447 } 448 SkiaShader::describe(caches, description, extensions, *rec.fShaderA); 449 SkiaShader::describe(caches, description, extensions, *rec.fShaderB); 450 if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) { 451 description.isBitmapFirst = true; 452 } 453 if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) { 454 // TODO: Support other modes. 455 description.shadersMode = SkXfermode::kSrcOver_Mode; 456 } 457} 458 459void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix, 460 GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) { 461 SkShader::ComposeRec rec; 462 if (!shader.asACompose(&rec)) { 463 LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!"); 464 } 465 466 // Apply this compose shader's local transform and pass it down to 467 // the child shaders. They will in turn apply their local transform 468 // to this matrix. 469 mat4 transform; 470 computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), 471 modelViewMatrix); 472 473 SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA); 474 SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB); 475} 476 477/////////////////////////////////////////////////////////////////////////////// 478// Store / apply 479/////////////////////////////////////////////////////////////////////////////// 480 481bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 modelViewMatrix, 482 GLuint* textureUnit, ProgramDescription* description, 483 SkiaShaderData::GradientShaderData* outData) { 484 SkShader::GradientInfo gradInfo; 485 gradInfo.fColorCount = 0; 486 gradInfo.fColors = nullptr; 487 gradInfo.fColorOffsets = nullptr; 488 489 SkMatrix unitMatrix; 490 switch (shader.asAGradient(&gradInfo)) { 491 case SkShader::kLinear_GradientType: 492 description->gradientType = ProgramDescription::kGradientLinear; 493 494 toUnitMatrix(gradInfo.fPoint, &unitMatrix); 495 break; 496 case SkShader::kRadial_GradientType: 497 description->gradientType = ProgramDescription::kGradientCircular; 498 499 toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, 500 gradInfo.fRadius[0], &unitMatrix); 501 break; 502 case SkShader::kSweep_GradientType: 503 description->gradientType = ProgramDescription::kGradientSweep; 504 505 toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix); 506 break; 507 default: 508 // Do nothing. This shader is unsupported. 509 return false; 510 } 511 description->hasGradient = true; 512 description->isSimpleGradient = isSimpleGradient(gradInfo); 513 514 computeScreenSpaceMatrix(outData->screenSpace, unitMatrix, 515 shader.getLocalMatrix(), modelViewMatrix); 516 517 // re-query shader to get full color / offset data 518 std::unique_ptr<SkColor[]> colorStorage(new SkColor[gradInfo.fColorCount]); 519 std::unique_ptr<SkScalar[]> colorOffsets(new SkScalar[gradInfo.fColorCount]); 520 gradInfo.fColors = &colorStorage[0]; 521 gradInfo.fColorOffsets = &colorOffsets[0]; 522 shader.asAGradient(&gradInfo); 523 524 if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) { 525 outData->gradientSampler = (*textureUnit)++; 526 527#ifndef SK_SCALAR_IS_FLOAT 528 #error Need to convert gradInfo.fColorOffsets to float! 529#endif 530 outData->gradientTexture = caches.gradientCache.get( 531 gradInfo.fColors, gradInfo.fColorOffsets, gradInfo.fColorCount); 532 outData->wrapST = gTileModes[gradInfo.fTileMode]; 533 } else { 534 outData->gradientSampler = 0; 535 outData->gradientTexture = nullptr; 536 537 outData->startColor.set(gradInfo.fColors[0]); 538 outData->endColor.set(gradInfo.fColors[1]); 539 } 540 541 outData->ditherSampler = (*textureUnit)++; 542 return true; 543} 544 545void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data) { 546 if (CC_UNLIKELY(data.gradientTexture)) { 547 caches.textureState().activateTexture(data.gradientSampler); 548 bindTexture(&caches, data.gradientTexture, data.wrapST, data.wrapST); 549 glUniform1i(caches.program().getUniform("gradientSampler"), data.gradientSampler); 550 } else { 551 bindUniformColor(caches.program().getUniform("startColor"), data.startColor); 552 bindUniformColor(caches.program().getUniform("endColor"), data.endColor); 553 } 554 555 // TODO: remove sampler slot incrementing from dither.setupProgram, 556 // since this assignment of slots is done at store, not apply time 557 GLuint ditherSampler = data.ditherSampler; 558 caches.dither.setupProgram(caches.program(), &ditherSampler); 559 glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1, 560 GL_FALSE, &data.screenSpace.data[0]); 561} 562 563bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix, 564 GLuint* textureUnit, ProgramDescription* description, 565 SkiaShaderData::BitmapShaderData* outData) { 566 SkBitmap bitmap; 567 SkShader::TileMode xy[2]; 568 if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) { 569 return false; 570 } 571 572 outData->bitmapTexture = caches.textureCache.get(&bitmap); 573 if (!outData->bitmapTexture) return false; 574 575 outData->bitmapSampler = (*textureUnit)++; 576 577 const float width = outData->bitmapTexture->width; 578 const float height = outData->bitmapTexture->height; 579 580 description->hasBitmap = true; 581 if (!caches.extensions().hasNPot() 582 && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) 583 && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode)) { 584 description->isBitmapNpot = true; 585 description->bitmapWrapS = gTileModes[xy[0]]; 586 description->bitmapWrapT = gTileModes[xy[1]]; 587 588 outData->wrapS = GL_CLAMP_TO_EDGE; 589 outData->wrapT = GL_CLAMP_TO_EDGE; 590 } else { 591 outData->wrapS = gTileModes[xy[0]]; 592 outData->wrapT = gTileModes[xy[1]]; 593 } 594 595 computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(), 596 modelViewMatrix); 597 outData->textureDimension[0] = 1.0f / width; 598 outData->textureDimension[1] = 1.0f / height; 599 600 return true; 601} 602 603void applyBitmap(Caches& caches, const SkiaShaderData::BitmapShaderData& data) { 604 caches.textureState().activateTexture(data.bitmapSampler); 605 bindTexture(&caches, data.bitmapTexture, data.wrapS, data.wrapT); 606 data.bitmapTexture->setFilter(GL_LINEAR); 607 608 glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler); 609 glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1, GL_FALSE, 610 &data.textureTransform.data[0]); 611 glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]); 612} 613 614SkiaShaderType getComposeSubType(const SkShader& shader) { 615 // First check for a gradient shader. 616 switch (shader.asAGradient(nullptr)) { 617 case SkShader::kNone_GradientType: 618 // Not a gradient shader. Fall through to check for other types. 619 break; 620 case SkShader::kLinear_GradientType: 621 case SkShader::kRadial_GradientType: 622 case SkShader::kSweep_GradientType: 623 return kGradient_SkiaShaderType; 624 default: 625 // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip. 626 return kNone_SkiaShaderType; 627 } 628 629 // The shader is not a gradient. Check for a bitmap shader. 630 if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) { 631 return kBitmap_SkiaShaderType; 632 } 633 return kNone_SkiaShaderType; 634} 635 636void storeCompose(Caches& caches, const SkShader& bitmapShader, const SkShader& gradientShader, 637 const Matrix4& modelViewMatrix, GLuint* textureUnit, 638 ProgramDescription* description, SkiaShaderData* outData) { 639 LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix, 640 textureUnit, description, &outData->bitmapData), 641 "failed storing bitmap shader data"); 642 LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix, 643 textureUnit, description, &outData->gradientData), 644 "failing storing gradient shader data"); 645} 646 647bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix, 648 GLuint* textureUnit, ProgramDescription* description, 649 SkiaShaderData* outData) { 650 651 SkShader::ComposeRec rec; 652 if (!shader.asACompose(&rec)) return false; 653 654 const SkiaShaderType shaderAType = getComposeSubType(*rec.fShaderA); 655 const SkiaShaderType shaderBType = getComposeSubType(*rec.fShaderB); 656 657 // check that type enum values are the 2 flags that compose the kCompose value 658 if ((shaderAType & shaderBType) != 0) return false; 659 if ((shaderAType | shaderBType) != kCompose_SkiaShaderType) return false; 660 661 mat4 transform; 662 computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), modelViewMatrix); 663 if (shaderAType == kBitmap_SkiaShaderType) { 664 description->isBitmapFirst = true; 665 storeCompose(caches, *rec.fShaderA, *rec.fShaderB, 666 transform, textureUnit, description, outData); 667 } else { 668 description->isBitmapFirst = false; 669 storeCompose(caches, *rec.fShaderB, *rec.fShaderA, 670 transform, textureUnit, description, outData); 671 } 672 if (!SkXfermode::AsMode(rec.fMode, &description->shadersMode)) { 673 // TODO: Support other modes. 674 description->shadersMode = SkXfermode::kSrcOver_Mode; 675 } 676 return true; 677} 678 679bool tryStoreLayer(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix, 680 GLuint* textureUnit, ProgramDescription* description, 681 SkiaShaderData::LayerShaderData* outData) { 682 Layer* layer; 683 if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) { 684 return false; 685 } 686 687 description->hasBitmap = true; 688 outData->layer = layer; 689 outData->bitmapSampler = (*textureUnit)++; 690 691 const float width = layer->getWidth(); 692 const float height = layer->getHeight(); 693 694 computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(), 695 modelViewMatrix); 696 697 outData->textureDimension[0] = 1.0f / width; 698 outData->textureDimension[1] = 1.0f / height; 699 return true; 700} 701 702void applyLayer(Caches& caches, const SkiaShaderData::LayerShaderData& data) { 703 caches.textureState().activateTexture(data.bitmapSampler); 704 705 data.layer->bindTexture(); 706 data.layer->setWrap(GL_CLAMP_TO_EDGE); 707 data.layer->setFilter(GL_LINEAR); 708 709 glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler); 710 glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1, 711 GL_FALSE, &data.textureTransform.data[0]); 712 glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]); 713} 714 715void SkiaShader::store(Caches& caches, const SkShader* shader, const Matrix4& modelViewMatrix, 716 GLuint* textureUnit, ProgramDescription* description, 717 SkiaShaderData* outData) { 718 if (!shader) { 719 outData->skiaShaderType = kNone_SkiaShaderType; 720 return; 721 } 722 723 if (tryStoreGradient(caches, *shader, modelViewMatrix, 724 textureUnit, description, &outData->gradientData)) { 725 outData->skiaShaderType = kGradient_SkiaShaderType; 726 return; 727 } 728 729 if (tryStoreBitmap(caches, *shader, modelViewMatrix, 730 textureUnit, description, &outData->bitmapData)) { 731 outData->skiaShaderType = kBitmap_SkiaShaderType; 732 return; 733 } 734 735 if (tryStoreCompose(caches, *shader, modelViewMatrix, 736 textureUnit, description, outData)) { 737 outData->skiaShaderType = kCompose_SkiaShaderType; 738 return; 739 } 740 741 if (tryStoreLayer(caches, *shader, modelViewMatrix, 742 textureUnit, description, &outData->layerData)) { 743 outData->skiaShaderType = kLayer_SkiaShaderType; 744 } 745} 746 747void SkiaShader::apply(Caches& caches, const SkiaShaderData& data) { 748 if (!data.skiaShaderType) return; 749 750 if (data.skiaShaderType & kGradient_SkiaShaderType) { 751 applyGradient(caches, data.gradientData); 752 } 753 if (data.skiaShaderType & kBitmap_SkiaShaderType) { 754 applyBitmap(caches, data.bitmapData); 755 } 756 757 if (data.skiaShaderType == kLayer_SkiaShaderType) { 758 applyLayer(caches, data.layerData); 759 } 760} 761 762}; // namespace uirenderer 763}; // namespace android 764