SkiaShader.cpp revision 43ccf4663c822ddd435b7683cc05221f6169c6c3
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 = 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);
214    copy->mCount = mCount;
215    return copy;
216}
217
218void SkiaLinearGradientShader::describe(ProgramDescription& description,
219        const Extensions& extensions) {
220    description.hasGradient = true;
221    description.gradientType = ProgramDescription::kGradientLinear;
222}
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) {
231        texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX);
232    }
233
234    mat4 screenSpace;
235    computeScreenSpaceMatrix(screenSpace, modelView);
236
237    // Uniforms
238    bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
239    glUniform1i(program->getUniform("gradientSampler"), textureSlot);
240    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
241}
242
243void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& modelView,
244        const Snapshot& snapshot) {
245    mat4 screenSpace;
246    computeScreenSpaceMatrix(screenSpace, modelView);
247    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
248}
249
250///////////////////////////////////////////////////////////////////////////////
251// Circular gradient shader
252///////////////////////////////////////////////////////////////////////////////
253
254static 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
261SkiaCircularGradientShader::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,
265                tileMode, matrix, blend) {
266    SkMatrix unitMatrix;
267    toCircularUnitMatrix(x, y, radius, &unitMatrix);
268    mUnitMatrix.load(unitMatrix);
269
270    updateLocalMatrix(matrix);
271}
272
273SkiaShader* SkiaCircularGradientShader::copy() {
274    SkiaCircularGradientShader* copy = new SkiaCircularGradientShader();
275    copy->copyFrom(*this);
276    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);
280    copy->mCount = mCount;
281    return copy;
282}
283
284void SkiaCircularGradientShader::describe(ProgramDescription& description,
285        const Extensions& extensions) {
286    description.hasGradient = true;
287    description.gradientType = ProgramDescription::kGradientCircular;
288}
289
290///////////////////////////////////////////////////////////////////////////////
291// Sweep gradient shader
292///////////////////////////////////////////////////////////////////////////////
293
294static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
295    matrix->setTranslate(-x, -y);
296}
297
298SkiaSweepGradientShader::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),
302        mColors(colors), mPositions(positions), mCount(count) {
303    SkMatrix unitMatrix;
304    toSweepUnitMatrix(x, y, &unitMatrix);
305    mUnitMatrix.load(unitMatrix);
306
307    updateLocalMatrix(matrix);
308}
309
310SkiaSweepGradientShader::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),
314        mColors(colors), mPositions(positions), mCount(count) {
315}
316
317SkiaSweepGradientShader::~SkiaSweepGradientShader() {
318    delete[] mColors;
319    delete[] mPositions;
320}
321
322SkiaShader* SkiaSweepGradientShader::copy() {
323    SkiaSweepGradientShader* copy = new SkiaSweepGradientShader();
324    copy->copyFrom(*this);
325    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);
329    copy->mCount = mCount;
330    return copy;
331}
332
333void 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
349    mat4 screenSpace;
350    computeScreenSpaceMatrix(screenSpace, modelView);
351
352    // Uniforms
353    bindTexture(texture, gTileModes[mTileX], gTileModes[mTileY]);
354    glUniform1i(program->getUniform("gradientSampler"), textureSlot);
355    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
356}
357
358void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
359        const Snapshot& snapshot) {
360    mat4 screenSpace;
361    computeScreenSpaceMatrix(screenSpace, modelView);
362    glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
363}
364
365///////////////////////////////////////////////////////////////////////////////
366// 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,
372        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    }
381}
382
383SkiaShader* SkiaComposeShader::copy() {
384    SkiaComposeShader* copy = new SkiaComposeShader();
385    copy->copyFrom(*this);
386    copy->mFirst = mFirst->copy();
387    copy->mSecond = mSecond->copy();
388    copy->mMode = mMode;
389    copy->cleanup();
390    return copy;
391}
392
393void 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
416