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