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