• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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