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