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