blob: e7e118755c49593681317240026843fe65e1dcd1 [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 Guy8164c2d2010-10-25 18:03:28 -070066void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
Romain Guy06f96e22010-07-30 19:18:16 -070067 glActiveTexture(gTextureUnitsMap[textureUnit]);
Romain Guy8164c2d2010-10-25 18:03:28 -070068 glBindTexture(GL_TEXTURE_2D, texture->id);
69 if (wrapS != texture->wrapS) {
70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
71 texture->wrapS = wrapS;
72 }
73 if (wrapT != texture->wrapT) {
74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
75 texture->wrapT = wrapT;
76 }
Romain Guy06f96e22010-07-30 19:18:16 -070077}
78
Romain Guy14830942010-10-07 15:07:45 -070079void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
80 screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
81 screenSpace.multiply(modelView);
82}
83
Romain Guy06f96e22010-07-30 19:18:16 -070084///////////////////////////////////////////////////////////////////////////////
85// Bitmap shader
86///////////////////////////////////////////////////////////////////////////////
87
88SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
89 SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
Romain Guy9cccc2b92010-08-07 23:46:15 -070090 SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
Romain Guy14830942010-10-07 15:07:45 -070091 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -070092}
93
Romain Guy06f96e22010-07-30 19:18:16 -070094void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
Romain Guy8164c2d2010-10-25 18:03:28 -070095 Texture* texture = mTextureCache->get(mBitmap);
Romain Guy9cccc2b92010-08-07 23:46:15 -070096 if (!texture) return;
97 mTexture = texture;
Romain Guy06f96e22010-07-30 19:18:16 -070098
99 const float width = texture->width;
100 const float height = texture->height;
101
102 description.hasBitmap = true;
103 // The driver does not support non-power of two mirrored/repeated
104 // textures, so do it ourselves
Romain Guy61c8c9c2010-08-09 20:48:09 -0700105 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
106 (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
Romain Guy06f96e22010-07-30 19:18:16 -0700107 description.isBitmapNpot = true;
108 description.bitmapWrapS = gTileModes[mTileX];
109 description.bitmapWrapT = gTileModes[mTileY];
Romain Guy29d89972010-09-22 16:10:57 -0700110 mWrapS = GL_CLAMP_TO_EDGE;
111 mWrapT = GL_CLAMP_TO_EDGE;
112 } else {
113 mWrapS = gTileModes[mTileX];
114 mWrapT = gTileModes[mTileY];
Romain Guy06f96e22010-07-30 19:18:16 -0700115 }
116}
117
118void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
119 const Snapshot& snapshot, GLuint* textureUnit) {
120 GLuint textureSlot = (*textureUnit)++;
121 glActiveTexture(gTextureUnitsMap[textureSlot]);
Romain Guy9cccc2b92010-08-07 23:46:15 -0700122
Romain Guy8164c2d2010-10-25 18:03:28 -0700123 Texture* texture = mTexture;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700124 mTexture = NULL;
125 if (!texture) return;
126 const AutoTexture autoCleanup(texture);
Romain Guy06f96e22010-07-30 19:18:16 -0700127
128 const float width = texture->width;
129 const float height = texture->height;
130
131 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700132 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700133
134 // Uniforms
Romain Guy8164c2d2010-10-25 18:03:28 -0700135 bindTexture(texture, mWrapS, mWrapT, textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700136 glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
137 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
138 GL_FALSE, &textureTransform.data[0]);
139 glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
140}
141
Romain Guy759ea802010-09-16 20:49:46 -0700142void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
143 const Snapshot& snapshot) {
144 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700145 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700146 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
147 GL_FALSE, &textureTransform.data[0]);
148}
149
Romain Guy06f96e22010-07-30 19:18:16 -0700150///////////////////////////////////////////////////////////////////////////////
151// Linear gradient shader
152///////////////////////////////////////////////////////////////////////////////
153
Romain Guye3095e02010-10-06 16:57:29 -0700154static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
155 SkVector vec = pts[1] - pts[0];
156 const float mag = vec.length();
157 const float inv = mag ? 1.0f / mag : 0;
158
159 vec.scale(inv);
160 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
161 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
162 matrix->postScale(inv, inv);
163}
164
Romain Guy06f96e22010-07-30 19:18:16 -0700165SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
166 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
167 SkMatrix* matrix, bool blend):
168 SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
169 mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
Romain Guye3095e02010-10-06 16:57:29 -0700170 SkPoint points[2];
171 points[0].set(bounds[0], bounds[1]);
172 points[1].set(bounds[2], bounds[3]);
173
174 SkMatrix unitMatrix;
175 toUnitMatrix(points, &unitMatrix);
176 mUnitMatrix.load(unitMatrix);
177
178 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -0700179}
180
181SkiaLinearGradientShader::~SkiaLinearGradientShader() {
Romain Guy25ee0372010-08-06 10:57:58 -0700182 delete[] mBounds;
183 delete[] mColors;
184 delete[] mPositions;
Romain Guy06f96e22010-07-30 19:18:16 -0700185}
186
187void SkiaLinearGradientShader::describe(ProgramDescription& description,
188 const Extensions& extensions) {
189 description.hasGradient = true;
Romain Guyee916f12010-09-20 17:53:08 -0700190 description.gradientType = ProgramDescription::kGradientLinear;
Romain Guy06f96e22010-07-30 19:18:16 -0700191}
192
193void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
194 const Snapshot& snapshot, GLuint* textureUnit) {
195 GLuint textureSlot = (*textureUnit)++;
196 glActiveTexture(gTextureUnitsMap[textureSlot]);
197
198 Texture* texture = mGradientCache->get(mKey);
199 if (!texture) {
Romain Guyee916f12010-09-20 17:53:08 -0700200 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX);
Romain Guy06f96e22010-07-30 19:18:16 -0700201 }
202
Romain Guye3095e02010-10-06 16:57:29 -0700203 mat4 screenSpace;
204 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700205
206 // Uniforms
Romain Guy8164c2d2010-10-25 18:03:28 -0700207 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700208 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700209 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
210}
211
Romain Guy759ea802010-09-16 20:49:46 -0700212void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
213 const Snapshot& snapshot) {
Romain Guye3095e02010-10-06 16:57:29 -0700214 mat4 screenSpace;
215 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700216 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
217}
218
Romain Guy06f96e22010-07-30 19:18:16 -0700219///////////////////////////////////////////////////////////////////////////////
Romain Guyddb80be2010-09-20 19:04:33 -0700220// Circular gradient shader
221///////////////////////////////////////////////////////////////////////////////
222
Romain Guy14830942010-10-07 15:07:45 -0700223static void toCircularUnitMatrix(const float x, const float y, const float radius,
224 SkMatrix* matrix) {
225 const float inv = 1.0f / radius;
226 matrix->setTranslate(-x, -y);
227 matrix->postScale(inv, inv);
228}
229
Romain Guyddb80be2010-09-20 19:04:33 -0700230SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
231 uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
232 SkMatrix* matrix, bool blend):
233 SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
Romain Guy14830942010-10-07 15:07:45 -0700234 tileMode, matrix, blend) {
235 SkMatrix unitMatrix;
236 toCircularUnitMatrix(x, y, radius, &unitMatrix);
237 mUnitMatrix.load(unitMatrix);
238
239 updateLocalMatrix(matrix);
Romain Guyddb80be2010-09-20 19:04:33 -0700240}
241
242void SkiaCircularGradientShader::describe(ProgramDescription& description,
243 const Extensions& extensions) {
244 description.hasGradient = true;
245 description.gradientType = ProgramDescription::kGradientCircular;
246}
247
Romain Guyddb80be2010-09-20 19:04:33 -0700248///////////////////////////////////////////////////////////////////////////////
Romain Guyee916f12010-09-20 17:53:08 -0700249// Sweep gradient shader
250///////////////////////////////////////////////////////////////////////////////
251
Romain Guy14830942010-10-07 15:07:45 -0700252static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
253 matrix->setTranslate(-x, -y);
254}
255
Romain Guyee916f12010-09-20 17:53:08 -0700256SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
257 float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
258 SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
259 SkShader::kClamp_TileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700260 mColors(colors), mPositions(positions), mCount(count) {
261 SkMatrix unitMatrix;
262 toSweepUnitMatrix(x, y, &unitMatrix);
263 mUnitMatrix.load(unitMatrix);
264
265 updateLocalMatrix(matrix);
Romain Guyee916f12010-09-20 17:53:08 -0700266}
267
Romain Guyddb80be2010-09-20 19:04:33 -0700268SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
269 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
270 SkMatrix* matrix, bool blend):
271 SkiaShader(type, key, tileMode, tileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700272 mColors(colors), mPositions(positions), mCount(count) {
Romain Guyddb80be2010-09-20 19:04:33 -0700273}
274
Romain Guyee916f12010-09-20 17:53:08 -0700275SkiaSweepGradientShader::~SkiaSweepGradientShader() {
276 delete[] mColors;
277 delete[] mPositions;
278}
279
280void SkiaSweepGradientShader::describe(ProgramDescription& description,
281 const Extensions& extensions) {
282 description.hasGradient = true;
283 description.gradientType = ProgramDescription::kGradientSweep;
284}
285
286void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
287 const Snapshot& snapshot, GLuint* textureUnit) {
288 GLuint textureSlot = (*textureUnit)++;
289 glActiveTexture(gTextureUnitsMap[textureSlot]);
290
291 Texture* texture = mGradientCache->get(mKey);
292 if (!texture) {
293 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
294 }
295
Romain Guy14830942010-10-07 15:07:45 -0700296 mat4 screenSpace;
297 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700298
299 // Uniforms
Romain Guy8164c2d2010-10-25 18:03:28 -0700300 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
Romain Guyee916f12010-09-20 17:53:08 -0700301 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guyee916f12010-09-20 17:53:08 -0700302 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
303}
304
305void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
306 const Snapshot& snapshot) {
Romain Guy14830942010-10-07 15:07:45 -0700307 mat4 screenSpace;
308 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700309 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
310}
311
312///////////////////////////////////////////////////////////////////////////////
Romain Guy06f96e22010-07-30 19:18:16 -0700313// Compose shader
314///////////////////////////////////////////////////////////////////////////////
315
316SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
317 SkXfermode::Mode mode, SkShader* key):
318 SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
319 NULL, first->blend() || second->blend()), mFirst(first), mSecond(second), mMode(mode) {
320}
321
Romain Guy06f96e22010-07-30 19:18:16 -0700322void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
323 SkiaShader::set(textureCache, gradientCache);
324 mFirst->set(textureCache, gradientCache);
325 mSecond->set(textureCache, gradientCache);
326}
327
328void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
329 mFirst->describe(description, extensions);
330 mSecond->describe(description, extensions);
331 if (mFirst->type() == kBitmap) {
332 description.isBitmapFirst = true;
333 }
334 description.shadersMode = mMode;
335}
336
337void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
338 const Snapshot& snapshot, GLuint* textureUnit) {
339 mFirst->setupProgram(program, modelView, snapshot, textureUnit);
340 mSecond->setupProgram(program, modelView, snapshot, textureUnit);
341}
342
343}; // namespace uirenderer
344}; // namespace android