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