SkiaShader.cpp revision d4289922ce772ed8e170a27d1c9521672b315698
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(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 79SkiaShader::~SkiaShader() { 80} 81 82void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) { 83} 84 85void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, 86 GLuint* textureUnit) { 87} 88 89void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) { 90 glBindTexture(GL_TEXTURE_2D, texture->id); 91 texture->setWrapST(wrapS, wrapT); 92} 93 94void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) { 95 screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix); 96 screenSpace.multiply(modelView); 97} 98 99/////////////////////////////////////////////////////////////////////////////// 100// Bitmap shader 101/////////////////////////////////////////////////////////////////////////////// 102 103SkiaBitmapShader::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 109SkiaShader* SkiaBitmapShader::copy() { 110 SkiaBitmapShader* copy = new SkiaBitmapShader(); 111 copy->copyFrom(*this); 112 copy->mBitmap = mBitmap; 113 return copy; 114} 115 116void 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 140void 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 170static 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 181SkiaLinearGradientShader::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 199SkiaLinearGradientShader::~SkiaLinearGradientShader() { 200 delete[] mBounds; 201 delete[] mColors; 202 delete[] mPositions; 203} 204 205SkiaShader* 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 219void SkiaLinearGradientShader::describe(ProgramDescription& description, 220 const Extensions& extensions) { 221 description.hasGradient = true; 222 description.gradientType = ProgramDescription::kGradientLinear; 223 description.isSimpleGradient = mIsSimple; 224} 225 226void 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 253static 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 260SkiaCircularGradientShader::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 272SkiaShader* 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 284void 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 295static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) { 296 matrix->setTranslate(-x, -y); 297} 298 299SkiaSweepGradientShader::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 313SkiaSweepGradientShader::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 322SkiaSweepGradientShader::~SkiaSweepGradientShader() { 323 delete[] mColors; 324 delete[] mPositions; 325} 326 327SkiaShader* 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 339void SkiaSweepGradientShader::describe(ProgramDescription& description, 340 const Extensions& extensions) { 341 description.hasGradient = true; 342 description.gradientType = ProgramDescription::kGradientSweep; 343 description.isSimpleGradient = mIsSimple; 344} 345 346void 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 373SkiaComposeShader::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 380SkiaComposeShader::~SkiaComposeShader() { 381 if (mCleanup) { 382 delete mFirst; 383 delete mSecond; 384 } 385} 386 387SkiaShader* 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 397void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) { 398 SkiaShader::set(textureCache, gradientCache); 399 mFirst->set(textureCache, gradientCache); 400 mSecond->set(textureCache, gradientCache); 401} 402 403void 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 412void 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