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