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