SkiaShader.cpp revision 42e1e0d482d774cf18a55773e434f02edb9e4462
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 mat4 screenSpace; 254 computeScreenSpaceMatrix(screenSpace, modelView); 255 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 256} 257 258void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView, 259 const Snapshot& snapshot) { 260 mat4 screenSpace; 261 computeScreenSpaceMatrix(screenSpace, modelView); 262 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 263} 264 265/////////////////////////////////////////////////////////////////////////////// 266// Circular gradient shader 267/////////////////////////////////////////////////////////////////////////////// 268 269static void toCircularUnitMatrix(const float x, const float y, const float radius, 270 SkMatrix* matrix) { 271 const float inv = 1.0f / radius; 272 matrix->setTranslate(-x, -y); 273 matrix->postScale(inv, inv); 274} 275 276SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, 277 uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, 278 SkMatrix* matrix, bool blend): 279 SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key, 280 tileMode, matrix, blend) { 281 SkMatrix unitMatrix; 282 toCircularUnitMatrix(x, y, radius, &unitMatrix); 283 mUnitMatrix.load(unitMatrix); 284 285 updateLocalMatrix(matrix); 286} 287 288SkiaShader* SkiaCircularGradientShader::copy() { 289 SkiaCircularGradientShader* copy = new SkiaCircularGradientShader(); 290 copy->copyFrom(*this); 291 copy->mColors = new uint32_t[mCount]; 292 memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); 293 copy->mPositions = new float[mCount]; 294 memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); 295 copy->mCount = mCount; 296 copy->mIsSimple = mIsSimple; 297 return copy; 298} 299 300void SkiaCircularGradientShader::describe(ProgramDescription& description, 301 const Extensions& extensions) { 302 description.hasGradient = true; 303 description.gradientType = ProgramDescription::kGradientCircular; 304 description.isSimpleGradient = mIsSimple; 305} 306 307/////////////////////////////////////////////////////////////////////////////// 308// Sweep gradient shader 309/////////////////////////////////////////////////////////////////////////////// 310 311static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { 312 matrix->setTranslate(-x, -y); 313} 314 315SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, 316 float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): 317 SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, 318 SkShader::kClamp_TileMode, matrix, blend), 319 mColors(colors), mPositions(positions), mCount(count) { 320 SkMatrix unitMatrix; 321 toSweepUnitMatrix(x, y, &unitMatrix); 322 mUnitMatrix.load(unitMatrix); 323 324 updateLocalMatrix(matrix); 325 326 mIsSimple = count == 2; 327} 328 329SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, 330 float* positions, int count, SkShader* key, SkShader::TileMode tileMode, 331 SkMatrix* matrix, bool blend): 332 SkiaShader(type, key, tileMode, tileMode, matrix, blend), 333 mColors(colors), mPositions(positions), mCount(count) { 334 335 mIsSimple = count == 2 && tileMode == SkShader::kClamp_TileMode; 336} 337 338SkiaSweepGradientShader::~SkiaSweepGradientShader() { 339 delete[] mColors; 340 delete[] mPositions; 341} 342 343SkiaShader* SkiaSweepGradientShader::copy() { 344 SkiaSweepGradientShader* copy = new SkiaSweepGradientShader(); 345 copy->copyFrom(*this); 346 copy->mColors = new uint32_t[mCount]; 347 memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount); 348 copy->mPositions = new float[mCount]; 349 memcpy(copy->mPositions, mPositions, sizeof(float) * mCount); 350 copy->mCount = mCount; 351 copy->mIsSimple = mIsSimple; 352 return copy; 353} 354 355void SkiaSweepGradientShader::describe(ProgramDescription& description, 356 const Extensions& extensions) { 357 description.hasGradient = true; 358 description.gradientType = ProgramDescription::kGradientSweep; 359 description.isSimpleGradient = mIsSimple; 360} 361 362void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView, 363 const Snapshot& snapshot, GLuint* textureUnit) { 364 if (CC_UNLIKELY(!mIsSimple)) { 365 GLuint textureSlot = (*textureUnit)++; 366 Caches::getInstance().activeTexture(textureSlot); 367 368 Texture* texture = mGradientCache->get(mColors, mPositions, mCount); 369 370 // Uniforms 371 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]); 372 glUniform1i(program->getUniform("gradientSampler"), textureSlot); 373 } else { 374 bindUniformColor(program->getUniform("startColor"), mColors[0]); 375 bindUniformColor(program->getUniform("endColor"), mColors[1]); 376 } 377 378 mat4 screenSpace; 379 computeScreenSpaceMatrix(screenSpace, modelView); 380 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 381} 382 383void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView, 384 const Snapshot& snapshot) { 385 mat4 screenSpace; 386 computeScreenSpaceMatrix(screenSpace, modelView); 387 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); 388} 389 390/////////////////////////////////////////////////////////////////////////////// 391// Compose shader 392/////////////////////////////////////////////////////////////////////////////// 393 394SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second, 395 SkXfermode::Mode mode, SkShader* key): 396 SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 397 NULL, first->blend() || second->blend()), 398 mFirst(first), mSecond(second), mMode(mode), mCleanup(false) { 399} 400 401SkiaComposeShader::~SkiaComposeShader() { 402 if (mCleanup) { 403 delete mFirst; 404 delete mSecond; 405 } 406} 407 408SkiaShader* SkiaComposeShader::copy() { 409 SkiaComposeShader* copy = new SkiaComposeShader(); 410 copy->copyFrom(*this); 411 copy->mFirst = mFirst->copy(); 412 copy->mSecond = mSecond->copy(); 413 copy->mMode = mMode; 414 copy->cleanup(); 415 return copy; 416} 417 418void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) { 419 SkiaShader::set(textureCache, gradientCache); 420 mFirst->set(textureCache, gradientCache); 421 mSecond->set(textureCache, gradientCache); 422} 423 424void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) { 425 mFirst->describe(description, extensions); 426 mSecond->describe(description, extensions); 427 if (mFirst->type() == kBitmap) { 428 description.isBitmapFirst = true; 429 } 430 description.shadersMode = mMode; 431} 432 433void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView, 434 const Snapshot& snapshot, GLuint* textureUnit) { 435 mFirst->setupProgram(program, modelView, snapshot, textureUnit); 436 mSecond->setupProgram(program, modelView, snapshot, textureUnit); 437} 438 439}; // namespace uirenderer 440}; // namespace android 441