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