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