blob: 590a9d7c41b80d5cee3091a69ad3433879ea298c [file] [log] [blame]
Romain Guy06f96e22010-07-30 19:18:16 -07001/*
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
27namespace android {
28namespace uirenderer {
29
30///////////////////////////////////////////////////////////////////////////////
31// Support
32///////////////////////////////////////////////////////////////////////////////
33
34static const GLenum gTextureUnitsMap[] = {
35 GL_TEXTURE0,
36 GL_TEXTURE1,
37 GL_TEXTURE2
38};
39
40static 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
50SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
51 SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
Romain Guy14830942010-10-07 15:07:45 -070052 mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) {
53 setMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -070054}
55
56SkiaShader::~SkiaShader() {
57}
58
59void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) {
60}
61
62void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
63 GLuint* textureUnit) {
64}
65
Romain Guy01d06572010-11-11 12:06:27 -080066void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
Romain Guy8164c2d2010-10-25 18:03:28 -070067 glBindTexture(GL_TEXTURE_2D, texture->id);
68 if (wrapS != texture->wrapS) {
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
70 texture->wrapS = wrapS;
71 }
72 if (wrapT != texture->wrapT) {
73 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
74 texture->wrapT = wrapT;
75 }
Romain Guy06f96e22010-07-30 19:18:16 -070076}
77
Romain Guy14830942010-10-07 15:07:45 -070078void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
79 screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
80 screenSpace.multiply(modelView);
81}
82
Romain Guy06f96e22010-07-30 19:18:16 -070083///////////////////////////////////////////////////////////////////////////////
84// Bitmap shader
85///////////////////////////////////////////////////////////////////////////////
86
87SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
88 SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
Romain Guy9cccc2b92010-08-07 23:46:15 -070089 SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
Romain Guy14830942010-10-07 15:07:45 -070090 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -070091}
92
Romain Guy06f96e22010-07-30 19:18:16 -070093void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
Romain Guy8164c2d2010-10-25 18:03:28 -070094 Texture* texture = mTextureCache->get(mBitmap);
Romain Guy9cccc2b92010-08-07 23:46:15 -070095 if (!texture) return;
96 mTexture = texture;
Romain Guy06f96e22010-07-30 19:18:16 -070097
98 const float width = texture->width;
99 const float height = texture->height;
100
101 description.hasBitmap = true;
102 // The driver does not support non-power of two mirrored/repeated
103 // textures, so do it ourselves
Romain Guy61c8c9c2010-08-09 20:48:09 -0700104 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
105 (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
Romain Guy06f96e22010-07-30 19:18:16 -0700106 description.isBitmapNpot = true;
107 description.bitmapWrapS = gTileModes[mTileX];
108 description.bitmapWrapT = gTileModes[mTileY];
Romain Guy29d89972010-09-22 16:10:57 -0700109 mWrapS = GL_CLAMP_TO_EDGE;
110 mWrapT = GL_CLAMP_TO_EDGE;
111 } else {
112 mWrapS = gTileModes[mTileX];
113 mWrapT = gTileModes[mTileY];
Romain Guy06f96e22010-07-30 19:18:16 -0700114 }
115}
116
117void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
118 const Snapshot& snapshot, GLuint* textureUnit) {
119 GLuint textureSlot = (*textureUnit)++;
120 glActiveTexture(gTextureUnitsMap[textureSlot]);
Romain Guy9cccc2b92010-08-07 23:46:15 -0700121
Romain Guy8164c2d2010-10-25 18:03:28 -0700122 Texture* texture = mTexture;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700123 mTexture = NULL;
124 if (!texture) return;
125 const AutoTexture autoCleanup(texture);
Romain Guy06f96e22010-07-30 19:18:16 -0700126
127 const float width = texture->width;
128 const float height = texture->height;
129
130 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700131 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700132
133 // Uniforms
Romain Guy01d06572010-11-11 12:06:27 -0800134 bindTexture(texture, mWrapS, mWrapT);
Romain Guy06f96e22010-07-30 19:18:16 -0700135 glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
136 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
137 GL_FALSE, &textureTransform.data[0]);
138 glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
139}
140
Romain Guy759ea802010-09-16 20:49:46 -0700141void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
142 const Snapshot& snapshot) {
143 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700144 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700145 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
146 GL_FALSE, &textureTransform.data[0]);
147}
148
Romain Guy06f96e22010-07-30 19:18:16 -0700149///////////////////////////////////////////////////////////////////////////////
150// Linear gradient shader
151///////////////////////////////////////////////////////////////////////////////
152
Romain Guye3095e02010-10-06 16:57:29 -0700153static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
154 SkVector vec = pts[1] - pts[0];
155 const float mag = vec.length();
156 const float inv = mag ? 1.0f / mag : 0;
157
158 vec.scale(inv);
159 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
160 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
161 matrix->postScale(inv, inv);
162}
163
Romain Guy06f96e22010-07-30 19:18:16 -0700164SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
165 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
166 SkMatrix* matrix, bool blend):
167 SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
168 mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
Romain Guye3095e02010-10-06 16:57:29 -0700169 SkPoint points[2];
170 points[0].set(bounds[0], bounds[1]);
171 points[1].set(bounds[2], bounds[3]);
172
173 SkMatrix unitMatrix;
174 toUnitMatrix(points, &unitMatrix);
175 mUnitMatrix.load(unitMatrix);
176
177 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -0700178}
179
180SkiaLinearGradientShader::~SkiaLinearGradientShader() {
Romain Guy25ee0372010-08-06 10:57:58 -0700181 delete[] mBounds;
182 delete[] mColors;
183 delete[] mPositions;
Romain Guy06f96e22010-07-30 19:18:16 -0700184}
185
186void SkiaLinearGradientShader::describe(ProgramDescription& description,
187 const Extensions& extensions) {
188 description.hasGradient = true;
Romain Guyee916f12010-09-20 17:53:08 -0700189 description.gradientType = ProgramDescription::kGradientLinear;
Romain Guy06f96e22010-07-30 19:18:16 -0700190}
191
192void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
193 const Snapshot& snapshot, GLuint* textureUnit) {
194 GLuint textureSlot = (*textureUnit)++;
195 glActiveTexture(gTextureUnitsMap[textureSlot]);
196
197 Texture* texture = mGradientCache->get(mKey);
198 if (!texture) {
Romain Guyee916f12010-09-20 17:53:08 -0700199 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX);
Romain Guy06f96e22010-07-30 19:18:16 -0700200 }
201
Romain Guye3095e02010-10-06 16:57:29 -0700202 mat4 screenSpace;
203 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700204
205 // Uniforms
Romain Guy01d06572010-11-11 12:06:27 -0800206 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
Romain Guy06f96e22010-07-30 19:18:16 -0700207 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700208 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
209}
210
Romain Guy759ea802010-09-16 20:49:46 -0700211void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
212 const Snapshot& snapshot) {
Romain Guye3095e02010-10-06 16:57:29 -0700213 mat4 screenSpace;
214 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700215 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
216}
217
Romain Guy06f96e22010-07-30 19:18:16 -0700218///////////////////////////////////////////////////////////////////////////////
Romain Guyddb80be2010-09-20 19:04:33 -0700219// Circular gradient shader
220///////////////////////////////////////////////////////////////////////////////
221
Romain Guy14830942010-10-07 15:07:45 -0700222static void toCircularUnitMatrix(const float x, const float y, const float radius,
223 SkMatrix* matrix) {
224 const float inv = 1.0f / radius;
225 matrix->setTranslate(-x, -y);
226 matrix->postScale(inv, inv);
227}
228
Romain Guyddb80be2010-09-20 19:04:33 -0700229SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
230 uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
231 SkMatrix* matrix, bool blend):
232 SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
Romain Guy14830942010-10-07 15:07:45 -0700233 tileMode, matrix, blend) {
234 SkMatrix unitMatrix;
235 toCircularUnitMatrix(x, y, radius, &unitMatrix);
236 mUnitMatrix.load(unitMatrix);
237
238 updateLocalMatrix(matrix);
Romain Guyddb80be2010-09-20 19:04:33 -0700239}
240
241void SkiaCircularGradientShader::describe(ProgramDescription& description,
242 const Extensions& extensions) {
243 description.hasGradient = true;
244 description.gradientType = ProgramDescription::kGradientCircular;
245}
246
Romain Guyddb80be2010-09-20 19:04:33 -0700247///////////////////////////////////////////////////////////////////////////////
Romain Guyee916f12010-09-20 17:53:08 -0700248// Sweep gradient shader
249///////////////////////////////////////////////////////////////////////////////
250
Romain Guy14830942010-10-07 15:07:45 -0700251static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
252 matrix->setTranslate(-x, -y);
253}
254
Romain Guyee916f12010-09-20 17:53:08 -0700255SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
256 float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
257 SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
258 SkShader::kClamp_TileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700259 mColors(colors), mPositions(positions), mCount(count) {
260 SkMatrix unitMatrix;
261 toSweepUnitMatrix(x, y, &unitMatrix);
262 mUnitMatrix.load(unitMatrix);
263
264 updateLocalMatrix(matrix);
Romain Guyee916f12010-09-20 17:53:08 -0700265}
266
Romain Guyddb80be2010-09-20 19:04:33 -0700267SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
268 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
269 SkMatrix* matrix, bool blend):
270 SkiaShader(type, key, tileMode, tileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700271 mColors(colors), mPositions(positions), mCount(count) {
Romain Guyddb80be2010-09-20 19:04:33 -0700272}
273
Romain Guyee916f12010-09-20 17:53:08 -0700274SkiaSweepGradientShader::~SkiaSweepGradientShader() {
275 delete[] mColors;
276 delete[] mPositions;
277}
278
279void SkiaSweepGradientShader::describe(ProgramDescription& description,
280 const Extensions& extensions) {
281 description.hasGradient = true;
282 description.gradientType = ProgramDescription::kGradientSweep;
283}
284
285void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
286 const Snapshot& snapshot, GLuint* textureUnit) {
287 GLuint textureSlot = (*textureUnit)++;
288 glActiveTexture(gTextureUnitsMap[textureSlot]);
289
290 Texture* texture = mGradientCache->get(mKey);
291 if (!texture) {
292 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
293 }
294
Romain Guy14830942010-10-07 15:07:45 -0700295 mat4 screenSpace;
296 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700297
298 // Uniforms
Romain Guy01d06572010-11-11 12:06:27 -0800299 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
Romain Guyee916f12010-09-20 17:53:08 -0700300 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guyee916f12010-09-20 17:53:08 -0700301 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
302}
303
304void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
305 const Snapshot& snapshot) {
Romain Guy14830942010-10-07 15:07:45 -0700306 mat4 screenSpace;
307 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700308 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
309}
310
311///////////////////////////////////////////////////////////////////////////////
Romain Guy06f96e22010-07-30 19:18:16 -0700312// Compose shader
313///////////////////////////////////////////////////////////////////////////////
314
315SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
316 SkXfermode::Mode mode, SkShader* key):
317 SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
318 NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) {
319}
320
Romain Guy06f96e22010-07-30 19:18:16 -0700321void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
322 SkiaShader::set(textureCache, gradientCache);
323 mFirst->set(textureCache, gradientCache);
324 mSecond->set(textureCache, gradientCache);
325}
326
327void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
328 mFirst->describe(description, extensions);
329 mSecond->describe(description, extensions);
330 if (mFirst->type() == kBitmap) {
331 description.isBitmapFirst = true;
332 }
333 description.shadersMode = mMode;
334}
335
336void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
337 const Snapshot& snapshot, GLuint* textureUnit) {
338 mFirst->setupProgram(program, modelView, snapshot, textureUnit);
339 mSecond->setupProgram(program, modelView, snapshot, textureUnit);
340}
341
342}; // namespace uirenderer
343}; // namespace android