blob: fa85d20ed3a43c5c7211e3360e507e70cc4df372 [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
66void SkiaShader::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
67 glActiveTexture(gTextureUnitsMap[textureUnit]);
68 glBindTexture(GL_TEXTURE_2D, texture);
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
71}
72
Romain Guy14830942010-10-07 15:07:45 -070073void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
74 screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
75 screenSpace.multiply(modelView);
76}
77
Romain Guy06f96e22010-07-30 19:18:16 -070078///////////////////////////////////////////////////////////////////////////////
79// Bitmap shader
80///////////////////////////////////////////////////////////////////////////////
81
82SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
83 SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
Romain Guy9cccc2b2010-08-07 23:46:15 -070084 SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
Romain Guy14830942010-10-07 15:07:45 -070085 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -070086}
87
Romain Guy06f96e22010-07-30 19:18:16 -070088void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
89 const Texture* texture = mTextureCache->get(mBitmap);
Romain Guy9cccc2b2010-08-07 23:46:15 -070090 if (!texture) return;
91 mTexture = texture;
Romain Guy06f96e22010-07-30 19:18:16 -070092
93 const float width = texture->width;
94 const float height = texture->height;
95
96 description.hasBitmap = true;
97 // The driver does not support non-power of two mirrored/repeated
98 // textures, so do it ourselves
Romain Guy61c8c9c2010-08-09 20:48:09 -070099 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
100 (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
Romain Guy06f96e22010-07-30 19:18:16 -0700101 description.isBitmapNpot = true;
102 description.bitmapWrapS = gTileModes[mTileX];
103 description.bitmapWrapT = gTileModes[mTileY];
Romain Guy29d89972010-09-22 16:10:57 -0700104 mWrapS = GL_CLAMP_TO_EDGE;
105 mWrapT = GL_CLAMP_TO_EDGE;
106 } else {
107 mWrapS = gTileModes[mTileX];
108 mWrapT = gTileModes[mTileY];
Romain Guy06f96e22010-07-30 19:18:16 -0700109 }
110}
111
112void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
113 const Snapshot& snapshot, GLuint* textureUnit) {
114 GLuint textureSlot = (*textureUnit)++;
115 glActiveTexture(gTextureUnitsMap[textureSlot]);
Romain Guy9cccc2b2010-08-07 23:46:15 -0700116
117 const Texture* texture = mTexture;
118 mTexture = NULL;
119 if (!texture) return;
120 const AutoTexture autoCleanup(texture);
Romain Guy06f96e22010-07-30 19:18:16 -0700121
122 const float width = texture->width;
123 const float height = texture->height;
124
125 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700126 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700127
128 // Uniforms
Romain Guy29d89972010-09-22 16:10:57 -0700129 bindTexture(texture->id, mWrapS, mWrapT, textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700130 glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
131 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
132 GL_FALSE, &textureTransform.data[0]);
133 glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
134}
135
Romain Guy759ea802010-09-16 20:49:46 -0700136void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
137 const Snapshot& snapshot) {
138 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700139 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700140 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
141 GL_FALSE, &textureTransform.data[0]);
142}
143
Romain Guy06f96e22010-07-30 19:18:16 -0700144///////////////////////////////////////////////////////////////////////////////
145// Linear gradient shader
146///////////////////////////////////////////////////////////////////////////////
147
Romain Guye3095e02010-10-06 16:57:29 -0700148static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
149 SkVector vec = pts[1] - pts[0];
150 const float mag = vec.length();
151 const float inv = mag ? 1.0f / mag : 0;
152
153 vec.scale(inv);
154 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
155 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
156 matrix->postScale(inv, inv);
157}
158
Romain Guy06f96e22010-07-30 19:18:16 -0700159SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
160 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
161 SkMatrix* matrix, bool blend):
162 SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
163 mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
Romain Guye3095e02010-10-06 16:57:29 -0700164 SkPoint points[2];
165 points[0].set(bounds[0], bounds[1]);
166 points[1].set(bounds[2], bounds[3]);
167
168 SkMatrix unitMatrix;
169 toUnitMatrix(points, &unitMatrix);
170 mUnitMatrix.load(unitMatrix);
171
172 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -0700173}
174
175SkiaLinearGradientShader::~SkiaLinearGradientShader() {
Romain Guy25ee0372010-08-06 10:57:58 -0700176 delete[] mBounds;
177 delete[] mColors;
178 delete[] mPositions;
Romain Guy06f96e22010-07-30 19:18:16 -0700179}
180
181void SkiaLinearGradientShader::describe(ProgramDescription& description,
182 const Extensions& extensions) {
183 description.hasGradient = true;
Romain Guyee916f12010-09-20 17:53:08 -0700184 description.gradientType = ProgramDescription::kGradientLinear;
Romain Guy06f96e22010-07-30 19:18:16 -0700185}
186
187void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
188 const Snapshot& snapshot, GLuint* textureUnit) {
189 GLuint textureSlot = (*textureUnit)++;
190 glActiveTexture(gTextureUnitsMap[textureSlot]);
191
192 Texture* texture = mGradientCache->get(mKey);
193 if (!texture) {
Romain Guyee916f12010-09-20 17:53:08 -0700194 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX);
Romain Guy06f96e22010-07-30 19:18:16 -0700195 }
196
Romain Guye3095e02010-10-06 16:57:29 -0700197 mat4 screenSpace;
198 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700199
200 // Uniforms
201 bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
202 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700203 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
204}
205
Romain Guy759ea802010-09-16 20:49:46 -0700206void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
207 const Snapshot& snapshot) {
Romain Guye3095e02010-10-06 16:57:29 -0700208 mat4 screenSpace;
209 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700210 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
211}
212
Romain Guy06f96e22010-07-30 19:18:16 -0700213///////////////////////////////////////////////////////////////////////////////
Romain Guyddb80be2010-09-20 19:04:33 -0700214// Circular gradient shader
215///////////////////////////////////////////////////////////////////////////////
216
Romain Guy14830942010-10-07 15:07:45 -0700217static void toCircularUnitMatrix(const float x, const float y, const float radius,
218 SkMatrix* matrix) {
219 const float inv = 1.0f / radius;
220 matrix->setTranslate(-x, -y);
221 matrix->postScale(inv, inv);
222}
223
Romain Guyddb80be2010-09-20 19:04:33 -0700224SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
225 uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
226 SkMatrix* matrix, bool blend):
227 SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
Romain Guy14830942010-10-07 15:07:45 -0700228 tileMode, matrix, blend) {
229 SkMatrix unitMatrix;
230 toCircularUnitMatrix(x, y, radius, &unitMatrix);
231 mUnitMatrix.load(unitMatrix);
232
233 updateLocalMatrix(matrix);
Romain Guyddb80be2010-09-20 19:04:33 -0700234}
235
236void SkiaCircularGradientShader::describe(ProgramDescription& description,
237 const Extensions& extensions) {
238 description.hasGradient = true;
239 description.gradientType = ProgramDescription::kGradientCircular;
240}
241
Romain Guyddb80be2010-09-20 19:04:33 -0700242///////////////////////////////////////////////////////////////////////////////
Romain Guyee916f12010-09-20 17:53:08 -0700243// Sweep gradient shader
244///////////////////////////////////////////////////////////////////////////////
245
Romain Guy14830942010-10-07 15:07:45 -0700246static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
247 matrix->setTranslate(-x, -y);
248}
249
Romain Guyee916f12010-09-20 17:53:08 -0700250SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
251 float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
252 SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
253 SkShader::kClamp_TileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700254 mColors(colors), mPositions(positions), mCount(count) {
255 SkMatrix unitMatrix;
256 toSweepUnitMatrix(x, y, &unitMatrix);
257 mUnitMatrix.load(unitMatrix);
258
259 updateLocalMatrix(matrix);
Romain Guyee916f12010-09-20 17:53:08 -0700260}
261
Romain Guyddb80be2010-09-20 19:04:33 -0700262SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
263 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
264 SkMatrix* matrix, bool blend):
265 SkiaShader(type, key, tileMode, tileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700266 mColors(colors), mPositions(positions), mCount(count) {
Romain Guyddb80be2010-09-20 19:04:33 -0700267}
268
Romain Guyee916f12010-09-20 17:53:08 -0700269SkiaSweepGradientShader::~SkiaSweepGradientShader() {
270 delete[] mColors;
271 delete[] mPositions;
272}
273
274void SkiaSweepGradientShader::describe(ProgramDescription& description,
275 const Extensions& extensions) {
276 description.hasGradient = true;
277 description.gradientType = ProgramDescription::kGradientSweep;
278}
279
280void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
281 const Snapshot& snapshot, GLuint* textureUnit) {
282 GLuint textureSlot = (*textureUnit)++;
283 glActiveTexture(gTextureUnitsMap[textureSlot]);
284
285 Texture* texture = mGradientCache->get(mKey);
286 if (!texture) {
287 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
288 }
289
Romain Guy14830942010-10-07 15:07:45 -0700290 mat4 screenSpace;
291 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700292
293 // Uniforms
294 bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
295 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guyee916f12010-09-20 17:53:08 -0700296 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
297}
298
299void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
300 const Snapshot& snapshot) {
Romain Guy14830942010-10-07 15:07:45 -0700301 mat4 screenSpace;
302 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700303 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
304}
305
306///////////////////////////////////////////////////////////////////////////////
Romain Guy06f96e22010-07-30 19:18:16 -0700307// Compose shader
308///////////////////////////////////////////////////////////////////////////////
309
310SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
311 SkXfermode::Mode mode, SkShader* key):
312 SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
313 NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) {
314}
315
Romain Guy06f96e22010-07-30 19:18:16 -0700316void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
317 SkiaShader::set(textureCache, gradientCache);
318 mFirst->set(textureCache, gradientCache);
319 mSecond->set(textureCache, gradientCache);
320}
321
322void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
323 mFirst->describe(description, extensions);
324 mSecond->describe(description, extensions);
325 if (mFirst->type() == kBitmap) {
326 description.isBitmapFirst = true;
327 }
328 description.shadersMode = mMode;
329}
330
331void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
332 const Snapshot& snapshot, GLuint* textureUnit) {
333 mFirst->setupProgram(program, modelView, snapshot, textureUnit);
334 mSecond->setupProgram(program, modelView, snapshot, textureUnit);
335}
336
337}; // namespace uirenderer
338}; // namespace android