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