• 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(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