SkiaShader.cpp revision 24c00216687ac87fe531dc4d4168ac0c0ca04ea6
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
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
50void 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
61SkiaShader::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
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
78void SkiaShader::bindTexture(Texture* texture, GLenum wrapS, GLenum wrapT) {
79    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    }
88}
89
90void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
91    screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
92    screenSpace.multiply(modelView);
93}
94
95///////////////////////////////////////////////////////////////////////////////
96// Bitmap shader
97///////////////////////////////////////////////////////////////////////////////
98
99SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
100        SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
101        SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
102    updateLocalMatrix(matrix);
103}
104
105SkiaShader* SkiaBitmapShader::copy() {
106    SkiaBitmapShader* copy = new SkiaBitmapShader();
107    copy->copyFrom(*this);
108    copy->mBitmap = mBitmap;
109    return copy;
110}
111
112void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
113    Texture* texture = mTextureCache->get(mBitmap);
114    if (!texture) return;
115    mTexture = texture;
116
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
123    if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
124            (mTileX != SkShader::kClamp_TileMode || mTileY != SkShader::kClamp_TileMode)) {
125        description.isBitmapNpot = true;
126        description.bitmapWrapS = gTileModes[mTileX];
127        description.bitmapWrapT = gTileModes[mTileY];
128        mWrapS = GL_CLAMP_TO_EDGE;
129        mWrapT = GL_CLAMP_TO_EDGE;
130    } else {
131        mWrapS = gTileModes[mTileX];
132        mWrapT = gTileModes[mTileY];
133    }
134}
135
136void SkiaBitmapShader::setupProgram(Program* program, const mat4& modelView,
137        const Snapshot& snapshot, GLuint* textureUnit) {
138    GLuint textureSlot = (*textureUnit)++;
139    glActiveTexture(gTextureUnitsMap[textureSlot]);
140
141    Texture* texture = mTexture;
142    mTexture = NULL;
143    if (!texture) return;
144    const AutoTexture autoCleanup(texture);
145
146    const float width = texture->width;
147    const float height = texture->height;
148
149    mat4 textureTransform;
150    computeScreenSpaceMatrix(textureTransform, modelView);
151
152    // Uniforms
153    bindTexture(texture, mWrapS, mWrapT);
154    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
160void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
161        const Snapshot& snapshot) {
162    mat4 textureTransform;
163    computeScreenSpaceMatrix(textureTransform, modelView);
164    glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
165            GL_FALSE, &textureTransform.data[0]);
166}
167
168///////////////////////////////////////////////////////////////////////////////
169// Linear gradient shader
170///////////////////////////////////////////////////////////////////////////////
171
172static 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
183SkiaLinearGradientShader::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) {
188    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);
197}
198
199SkiaLinearGradientShader::~SkiaLinearGradientShader() {
200    delete[] mBounds;
201    delete[] mColors;
202    delete[] mPositions;
203}
204
205SkiaShader* SkiaLinearGradientShader::copy() {
206    SkiaLinearGradientShader* copy = new SkiaLinearGradientShader();
207    copy->copyFrom(*this);
208    copy->mBounds = mBounds;
209    copy->mColors = mColors;
210    copy->mPositions = mPositions;
211    copy->mCount = mCount;
212    return copy;
213}
214
215void SkiaLinearGradientShader::describe(ProgramDescription& description,
216        const Extensions& extensions) {
217    description.hasGradient = true;
218    description.gradientType = ProgramDescription::kGradientLinear;
219}
220
221void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
222        const Snapshot& snapshot, GLuint* textureUnit) {
223    GLuint textureSlot = (*textureUnit)++;
224    glActiveTexture(gTextureUnitsMap[textureSlot]);
225
226    Texture* texture = mGradientCache->get(mKey);
227    if (!texture) {
228        texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX);
229    }
230
231    mat4 screenSpace;
232    computeScreenSpaceMatrix(screenSpace, modelView);
233
234    // Uniforms
235    bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
236    glUniform1i(program->getUniform("gradientSampler"), textureSlot);
237    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
238}
239
240void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
241        const Snapshot& snapshot) {
242    mat4 screenSpace;
243    computeScreenSpaceMatrix(screenSpace, modelView);
244    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
245}
246
247///////////////////////////////////////////////////////////////////////////////
248// Circular gradient shader
249///////////////////////////////////////////////////////////////////////////////
250
251static void toCircularUnitMatrix(const float x, const float y, const float radius,
252        SkMatrix* matrix) {
253    const float inv = 1.0f / radius;
254    matrix->setTranslate(-x, -y);
255    matrix->postScale(inv, inv);
256}
257
258SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
259        uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
260        SkMatrix* matrix, bool blend):
261        SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
262                tileMode, matrix, blend) {
263    SkMatrix unitMatrix;
264    toCircularUnitMatrix(x, y, radius, &unitMatrix);
265    mUnitMatrix.load(unitMatrix);
266
267    updateLocalMatrix(matrix);
268}
269
270SkiaShader* SkiaCircularGradientShader::copy() {
271    SkiaCircularGradientShader* copy = new SkiaCircularGradientShader();
272    copy->copyFrom(*this);
273    copy->mColors = mColors;
274    copy->mPositions = mPositions;
275    copy->mCount = mCount;
276    return copy;
277}
278
279void SkiaCircularGradientShader::describe(ProgramDescription& description,
280        const Extensions& extensions) {
281    description.hasGradient = true;
282    description.gradientType = ProgramDescription::kGradientCircular;
283}
284
285///////////////////////////////////////////////////////////////////////////////
286// Sweep gradient shader
287///////////////////////////////////////////////////////////////////////////////
288
289static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
290    matrix->setTranslate(-x, -y);
291}
292
293SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
294        float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
295        SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
296                SkShader::kClamp_TileMode, matrix, blend),
297        mColors(colors), mPositions(positions), mCount(count) {
298    SkMatrix unitMatrix;
299    toSweepUnitMatrix(x, y, &unitMatrix);
300    mUnitMatrix.load(unitMatrix);
301
302    updateLocalMatrix(matrix);
303}
304
305SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
306        float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
307        SkMatrix* matrix, bool blend):
308        SkiaShader(type, key, tileMode, tileMode, matrix, blend),
309        mColors(colors), mPositions(positions), mCount(count) {
310}
311
312SkiaSweepGradientShader::~SkiaSweepGradientShader() {
313    delete[] mColors;
314    delete[] mPositions;
315}
316
317SkiaShader* SkiaSweepGradientShader::copy() {
318    SkiaSweepGradientShader* copy = new SkiaSweepGradientShader();
319    copy->copyFrom(*this);
320    copy->mColors = mColors;
321    copy->mPositions = mPositions;
322    copy->mCount = mCount;
323    return copy;
324}
325
326void SkiaSweepGradientShader::describe(ProgramDescription& description,
327        const Extensions& extensions) {
328    description.hasGradient = true;
329    description.gradientType = ProgramDescription::kGradientSweep;
330}
331
332void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView,
333        const Snapshot& snapshot, GLuint* textureUnit) {
334    GLuint textureSlot = (*textureUnit)++;
335    glActiveTexture(gTextureUnitsMap[textureSlot]);
336
337    Texture* texture = mGradientCache->get(mKey);
338    if (!texture) {
339        texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
340    }
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
351void 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
362SkiaComposeShader::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()), mFirst(first), mSecond(second), mMode(mode) {
366}
367
368SkiaShader* SkiaComposeShader::copy() {
369    SkiaComposeShader* copy = new SkiaComposeShader();
370    copy->copyFrom(*this);
371    copy->mFirst = mFirst;
372    copy->mSecond = mSecond;
373    copy->mMode = mMode;
374    return copy;
375}
376
377void SkiaComposeShader::set(TextureCache* textureCache, GradientCache* gradientCache) {
378    SkiaShader::set(textureCache, gradientCache);
379    mFirst->set(textureCache, gradientCache);
380    mSecond->set(textureCache, gradientCache);
381}
382
383void SkiaComposeShader::describe(ProgramDescription& description, const Extensions& extensions) {
384    mFirst->describe(description, extensions);
385    mSecond->describe(description, extensions);
386    if (mFirst->type() == kBitmap) {
387        description.isBitmapFirst = true;
388    }
389    description.shadersMode = mMode;
390}
391
392void SkiaComposeShader::setupProgram(Program* program, const mat4& modelView,
393        const Snapshot& snapshot, GLuint* textureUnit) {
394    mFirst->setupProgram(program, modelView, snapshot, textureUnit);
395    mSecond->setupProgram(program, modelView, snapshot, textureUnit);
396}
397
398}; // namespace uirenderer
399}; // namespace android
400