blob: 8878c709809e24f4dd6205419f1be6637e8fc960 [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
Romain Guy24c00212011-01-14 15:31:00 -080050void 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
Romain Guy06f96e22010-07-30 19:18:16 -070061SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
62 SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
Romain Guy14830942010-10-07 15:07:45 -070063 mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) {
64 setMatrix(matrix);
Romain Guy24c00212011-01-14 15:31:00 -080065 mGenerationId = 0;
Romain Guy06f96e22010-07-30 19:18:16 -070066}
67
68SkiaShader::~SkiaShader() {
69}
70
71void SkiaShader::describe(ProgramDescription& description, const Extensions& extensions) {
72}
73
74void SkiaShader::setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
75 GLuint* textureUnit) {
76}
77
Romain Guy01d06572010-11-11 12:06:27 -080078void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
Romain Guy8164c2d2010-10-25 18:03:28 -070079 glBindTexture(GL_TEXTURE_2D, texture->id);
80 if (wrapS != texture->wrapS) {
81 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
82 texture->wrapS = wrapS;
83 }
84 if (wrapT != texture->wrapT) {
85 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
86 texture->wrapT = wrapT;
87 }
Romain Guy06f96e22010-07-30 19:18:16 -070088}
89
Romain Guy14830942010-10-07 15:07:45 -070090void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
91 screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
92 screenSpace.multiply(modelView);
93}
94
Romain Guy06f96e22010-07-30 19:18:16 -070095///////////////////////////////////////////////////////////////////////////////
96// Bitmap shader
97///////////////////////////////////////////////////////////////////////////////
98
99SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
100 SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
Romain Guy9cccc2b92010-08-07 23:46:15 -0700101 SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
Romain Guy14830942010-10-07 15:07:45 -0700102 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -0700103}
104
Romain Guy24c00212011-01-14 15:31:00 -0800105SkiaShader* SkiaBitmapShader::copy() {
106 SkiaBitmapShader* copy = new SkiaBitmapShader();
107 copy->copyFrom(*this);
108 copy->mBitmap = mBitmap;
109 return copy;
110}
111
Romain Guy06f96e22010-07-30 19:18:16 -0700112void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
Romain Guy8164c2d2010-10-25 18:03:28 -0700113 Texture* texture = mTextureCache->get(mBitmap);
Romain Guy9cccc2b92010-08-07 23:46:15 -0700114 if (!texture) return;
115 mTexture = texture;
Romain Guy06f96e22010-07-30 19:18:16 -0700116
117 const float width = texture->width;
118 const float height = texture->height;
119
120 description.hasBitmap = true;
121 // The driver does not support non-power of two mirrored/repeated
122 // textures, so do it ourselves
Romain Guy61c8c9c2010-08-09 20:48:09 -0700123 if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
124 (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
Romain Guy06f96e22010-07-30 19:18:16 -0700125 description.isBitmapNpot = true;
126 description.bitmapWrapS = gTileModes[mTileX];
127 description.bitmapWrapT = gTileModes[mTileY];
Romain Guy29d89972010-09-22 16:10:57 -0700128 mWrapS = GL_CLAMP_TO_EDGE;
129 mWrapT = GL_CLAMP_TO_EDGE;
130 } else {
131 mWrapS = gTileModes[mTileX];
132 mWrapT = gTileModes[mTileY];
Romain Guy06f96e22010-07-30 19:18:16 -0700133 }
134}
135
136void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
137 const Snapshot& snapshot, GLuint* textureUnit) {
138 GLuint textureSlot = (*textureUnit)++;
139 glActiveTexture(gTextureUnitsMap[textureSlot]);
Romain Guy9cccc2b92010-08-07 23:46:15 -0700140
Romain Guy8164c2d2010-10-25 18:03:28 -0700141 Texture* texture = mTexture;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700142 mTexture = NULL;
143 if (!texture) return;
144 const AutoTexture autoCleanup(texture);
Romain Guy06f96e22010-07-30 19:18:16 -0700145
146 const float width = texture->width;
147 const float height = texture->height;
148
149 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700150 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700151
152 // Uniforms
Romain Guy01d06572010-11-11 12:06:27 -0800153 bindTexture(texture, mWrapS, mWrapT);
Romain Guy06f96e22010-07-30 19:18:16 -0700154 glUniform1i(program->getUniform("bitmapSampler"), textureSlot);
155 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
156 GL_FALSE, &textureTransform.data[0]);
157 glUniform2f(program->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
158}
159
Romain Guy759ea802010-09-16 20:49:46 -0700160void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
161 const Snapshot& snapshot) {
162 mat4 textureTransform;
Romain Guy14830942010-10-07 15:07:45 -0700163 computeScreenSpaceMatrix(textureTransform, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700164 glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
165 GL_FALSE, &textureTransform.data[0]);
166}
167
Romain Guy06f96e22010-07-30 19:18:16 -0700168///////////////////////////////////////////////////////////////////////////////
169// Linear gradient shader
170///////////////////////////////////////////////////////////////////////////////
171
Romain Guye3095e02010-10-06 16:57:29 -0700172static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
173 SkVector vec = pts[1] - pts[0];
174 const float mag = vec.length();
175 const float inv = mag ? 1.0f / mag : 0;
176
177 vec.scale(inv);
178 matrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
179 matrix->postTranslate(-pts[0].fX, -pts[0].fY);
180 matrix->postScale(inv, inv);
181}
182
Romain Guy06f96e22010-07-30 19:18:16 -0700183SkiaLinearGradientShader::SkiaLinearGradientShader(float* bounds, uint32_t* colors,
184 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
185 SkMatrix* matrix, bool blend):
186 SkiaShader(kLinearGradient, key, tileMode, tileMode, matrix, blend),
187 mBounds(bounds), mColors(colors), mPositions(positions), mCount(count) {
Romain Guye3095e02010-10-06 16:57:29 -0700188 SkPoint points[2];
189 points[0].set(bounds[0], bounds[1]);
190 points[1].set(bounds[2], bounds[3]);
191
192 SkMatrix unitMatrix;
193 toUnitMatrix(points, &unitMatrix);
194 mUnitMatrix.load(unitMatrix);
195
196 updateLocalMatrix(matrix);
Romain Guy06f96e22010-07-30 19:18:16 -0700197}
198
199SkiaLinearGradientShader::~SkiaLinearGradientShader() {
Romain Guy25ee0372010-08-06 10:57:58 -0700200 delete[] mBounds;
201 delete[] mColors;
202 delete[] mPositions;
Romain Guy06f96e22010-07-30 19:18:16 -0700203}
204
Romain Guy24c00212011-01-14 15:31:00 -0800205SkiaShader* SkiaLinearGradientShader::copy() {
206 SkiaLinearGradientShader* copy = new SkiaLinearGradientShader();
207 copy->copyFrom(*this);
Romain Guy43ccf462011-01-14 18:51:01 -0800208 copy->mBounds = new float[4];
209 memcpy(copy->mBounds, mBounds, sizeof(float) * 4);
210 copy->mColors = new uint32_t[mCount];
211 memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
212 copy->mPositions = new float[mCount];
213 memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
Romain Guy24c00212011-01-14 15:31:00 -0800214 copy->mCount = mCount;
215 return copy;
216}
217
Romain Guy06f96e22010-07-30 19:18:16 -0700218void SkiaLinearGradientShader::describe(ProgramDescription& description,
219 const Extensions& extensions) {
220 description.hasGradient = true;
Romain Guyee916f12010-09-20 17:53:08 -0700221 description.gradientType = ProgramDescription::kGradientLinear;
Romain Guy06f96e22010-07-30 19:18:16 -0700222}
223
224void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
225 const Snapshot& snapshot, GLuint* textureUnit) {
226 GLuint textureSlot = (*textureUnit)++;
227 glActiveTexture(gTextureUnitsMap[textureSlot]);
228
229 Texture* texture = mGradientCache->get(mKey);
230 if (!texture) {
Romain Guyee916f12010-09-20 17:53:08 -0700231 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX);
Romain Guy06f96e22010-07-30 19:18:16 -0700232 }
233
Romain Guye3095e02010-10-06 16:57:29 -0700234 mat4 screenSpace;
235 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy06f96e22010-07-30 19:18:16 -0700236
237 // Uniforms
Romain Guy01d06572010-11-11 12:06:27 -0800238 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
Romain Guy06f96e22010-07-30 19:18:16 -0700239 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guy06f96e22010-07-30 19:18:16 -0700240 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
241}
242
Romain Guy759ea802010-09-16 20:49:46 -0700243void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
244 const Snapshot& snapshot) {
Romain Guye3095e02010-10-06 16:57:29 -0700245 mat4 screenSpace;
246 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guy759ea802010-09-16 20:49:46 -0700247 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
248}
249
Romain Guy06f96e22010-07-30 19:18:16 -0700250///////////////////////////////////////////////////////////////////////////////
Romain Guyddb80be2010-09-20 19:04:33 -0700251// Circular gradient shader
252///////////////////////////////////////////////////////////////////////////////
253
Romain Guy14830942010-10-07 15:07:45 -0700254static void toCircularUnitMatrix(const float x, const float y, const float radius,
255 SkMatrix* matrix) {
256 const float inv = 1.0f / radius;
257 matrix->setTranslate(-x, -y);
258 matrix->postScale(inv, inv);
259}
260
Romain Guyddb80be2010-09-20 19:04:33 -0700261SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
262 uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
263 SkMatrix* matrix, bool blend):
264 SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
Romain Guy14830942010-10-07 15:07:45 -0700265 tileMode, matrix, blend) {
266 SkMatrix unitMatrix;
267 toCircularUnitMatrix(x, y, radius, &unitMatrix);
268 mUnitMatrix.load(unitMatrix);
269
270 updateLocalMatrix(matrix);
Romain Guyddb80be2010-09-20 19:04:33 -0700271}
272
Romain Guy24c00212011-01-14 15:31:00 -0800273SkiaShader* SkiaCircularGradientShader::copy() {
274 SkiaCircularGradientShader* copy = new SkiaCircularGradientShader();
275 copy->copyFrom(*this);
Romain Guy43ccf462011-01-14 18:51:01 -0800276 copy->mColors = new uint32_t[mCount];
277 memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
278 copy->mPositions = new float[mCount];
279 memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
Romain Guy24c00212011-01-14 15:31:00 -0800280 copy->mCount = mCount;
281 return copy;
282}
283
Romain Guyddb80be2010-09-20 19:04:33 -0700284void SkiaCircularGradientShader::describe(ProgramDescription& description,
285 const Extensions& extensions) {
286 description.hasGradient = true;
287 description.gradientType = ProgramDescription::kGradientCircular;
288}
289
Romain Guyddb80be2010-09-20 19:04:33 -0700290///////////////////////////////////////////////////////////////////////////////
Romain Guyee916f12010-09-20 17:53:08 -0700291// Sweep gradient shader
292///////////////////////////////////////////////////////////////////////////////
293
Romain Guy14830942010-10-07 15:07:45 -0700294static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
295 matrix->setTranslate(-x, -y);
296}
297
Romain Guyee916f12010-09-20 17:53:08 -0700298SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
299 float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
300 SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
301 SkShader::kClamp_TileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700302 mColors(colors), mPositions(positions), mCount(count) {
303 SkMatrix unitMatrix;
304 toSweepUnitMatrix(x, y, &unitMatrix);
305 mUnitMatrix.load(unitMatrix);
306
307 updateLocalMatrix(matrix);
Romain Guyee916f12010-09-20 17:53:08 -0700308}
309
Romain Guyddb80be2010-09-20 19:04:33 -0700310SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
311 float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
312 SkMatrix* matrix, bool blend):
313 SkiaShader(type, key, tileMode, tileMode, matrix, blend),
Romain Guy14830942010-10-07 15:07:45 -0700314 mColors(colors), mPositions(positions), mCount(count) {
Romain Guyddb80be2010-09-20 19:04:33 -0700315}
316
Romain Guyee916f12010-09-20 17:53:08 -0700317SkiaSweepGradientShader::~SkiaSweepGradientShader() {
318 delete[] mColors;
319 delete[] mPositions;
320}
321
Romain Guy24c00212011-01-14 15:31:00 -0800322SkiaShader* SkiaSweepGradientShader::copy() {
323 SkiaSweepGradientShader* copy = new SkiaSweepGradientShader();
324 copy->copyFrom(*this);
Romain Guy43ccf462011-01-14 18:51:01 -0800325 copy->mColors = new uint32_t[mCount];
326 memcpy(copy->mColors, mColors, sizeof(uint32_t) * mCount);
327 copy->mPositions = new float[mCount];
328 memcpy(copy->mPositions, mPositions, sizeof(float) * mCount);
Romain Guy24c00212011-01-14 15:31:00 -0800329 copy->mCount = mCount;
330 return copy;
331}
332
Romain Guyee916f12010-09-20 17:53:08 -0700333void SkiaSweepGradientShader::describe(ProgramDescription& description,
334 const Extensions& extensions) {
335 description.hasGradient = true;
336 description.gradientType = ProgramDescription::kGradientSweep;
337}
338
339void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
340 const Snapshot& snapshot, GLuint* textureUnit) {
341 GLuint textureSlot = (*textureUnit)++;
342 glActiveTexture(gTextureUnitsMap[textureSlot]);
343
344 Texture* texture = mGradientCache->get(mKey);
345 if (!texture) {
346 texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
347 }
348
Romain Guy14830942010-10-07 15:07:45 -0700349 mat4 screenSpace;
350 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700351
352 // Uniforms
Romain Guy01d06572010-11-11 12:06:27 -0800353 bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
Romain Guyee916f12010-09-20 17:53:08 -0700354 glUniform1i(program->getUniform("gradientSampler"), textureSlot);
Romain Guyee916f12010-09-20 17:53:08 -0700355 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
356}
357
358void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
359 const Snapshot& snapshot) {
Romain Guy14830942010-10-07 15:07:45 -0700360 mat4 screenSpace;
361 computeScreenSpaceMatrix(screenSpace, modelView);
Romain Guyee916f12010-09-20 17:53:08 -0700362 glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
363}
364
365///////////////////////////////////////////////////////////////////////////////
Romain Guy06f96e22010-07-30 19:18:16 -0700366// Compose shader
367///////////////////////////////////////////////////////////////////////////////
368
369SkiaComposeShader::SkiaComposeShader(SkiaShader* first, SkiaShader* second,
370 SkXfermode::Mode mode, SkShader* key):
371 SkiaShader(kCompose, key, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
Romain Guy43ccf462011-01-14 18:51:01 -0800372 NULL, first->blend() || second->blend()),
373 mFirst(first), mSecond(second), mMode(mode), mCleanup(false) {
374}
375
376SkiaComposeShader::~SkiaComposeShader() {
377 if (mCleanup) {
378 delete mFirst;
379 delete mSecond;
380 }
Romain Guy06f96e22010-07-30 19:18:16 -0700381}
382
Romain Guy24c00212011-01-14 15:31:00 -0800383SkiaShader* SkiaComposeShader::copy() {
384 SkiaComposeShader* copy = new SkiaComposeShader();
385 copy->copyFrom(*this);
Romain Guy43ccf462011-01-14 18:51:01 -0800386 copy->mFirst = mFirst->copy();
387 copy->mSecond = mSecond->copy();
Romain Guy24c00212011-01-14 15:31:00 -0800388 copy->mMode = mMode;
Romain Guy43ccf462011-01-14 18:51:01 -0800389 copy->cleanup();
Romain Guy24c00212011-01-14 15:31:00 -0800390 return copy;
391}
392
Romain Guy06f96e22010-07-30 19:18:16 -0700393void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
394 SkiaShader::set(textureCache, gradientCache);
395 mFirst->set(textureCache, gradientCache);
396 mSecond->set(textureCache, gradientCache);
397}
398
399void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
400 mFirst->describe(description, extensions);
401 mSecond->describe(description, extensions);
402 if (mFirst->type() == kBitmap) {
403 description.isBitmapFirst = true;
404 }
405 description.shadersMode = mMode;
406}
407
408void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
409 const Snapshot& snapshot, GLuint* textureUnit) {
410 mFirst->setupProgram(program, modelView, snapshot, textureUnit);
411 mSecond->setupProgram(program, modelView, snapshot, textureUnit);
412}
413
414}; // namespace uirenderer
415}; // namespace android