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