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