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