OpenGLRenderer.cpp revision b82da65cb1601be504241f36778395cd6cb9f87b
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 <stdlib.h>
20#include <stdint.h>
21#include <sys/types.h>
22
23#include <SkCanvas.h>
24#include <SkTypeface.h>
25
26#include <cutils/properties.h>
27#include <utils/Log.h>
28
29#include "OpenGLRenderer.h"
30#include "Properties.h"
31
32namespace android {
33namespace uirenderer {
34
35///////////////////////////////////////////////////////////////////////////////
36// Defines
37///////////////////////////////////////////////////////////////////////////////
38
39#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
40#define DEFAULT_LAYER_CACHE_SIZE 10.0f
41#define DEFAULT_PATCH_CACHE_SIZE 100
42#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
43
44// Converts a number of mega-bytes into bytes
45#define MB(s) s * 1024 * 1024
46
47// Generates simple and textured vertices
48#define FV(x, y, u, v) { { x, y }, { u, v } }
49
50///////////////////////////////////////////////////////////////////////////////
51// Globals
52///////////////////////////////////////////////////////////////////////////////
53
54// This array is never used directly but used as a memcpy source in the
55// OpenGLRenderer constructor
56static const TextureVertex gMeshVertices[] = {
57        FV(0.0f, 0.0f, 0.0f, 0.0f),
58        FV(1.0f, 0.0f, 1.0f, 0.0f),
59        FV(0.0f, 1.0f, 0.0f, 1.0f),
60        FV(1.0f, 1.0f, 1.0f, 1.0f)
61};
62static const GLsizei gMeshStride = sizeof(TextureVertex);
63static const GLsizei gMeshCount = 4;
64
65/**
66 * Structure mapping Skia xfermodes to OpenGL blending factors.
67 */
68struct Blender {
69    SkXfermode::Mode mode;
70    GLenum src;
71    GLenum dst;
72}; // struct Blender
73
74// In this array, the index of each Blender equals the value of the first
75// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
76static const Blender gBlends[] = {
77        { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO },
78        { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO },
79        { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE },
80        { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
81        { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
82        { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
83        { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
84        { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
85        { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
86        { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
87        { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
88        { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
89};
90
91static const GLint gTileModes[] = {
92        GL_CLAMP_TO_EDGE,   // SkShader::kClamp_TileMode
93        GL_REPEAT,          // SkShader::kRepeat_Mode
94        GL_MIRRORED_REPEAT  // SkShader::kMirror_TileMode
95};
96
97static const GLenum gTextureUnits[] = {
98        GL_TEXTURE0,        // Bitmap or text
99        GL_TEXTURE1,        // Gradient
100        GL_TEXTURE2         // Bitmap shader
101};
102
103///////////////////////////////////////////////////////////////////////////////
104// Constructors/destructor
105///////////////////////////////////////////////////////////////////////////////
106
107OpenGLRenderer::OpenGLRenderer():
108        mBlend(false), mLastSrcMode(GL_ZERO), mLastDstMode(GL_ZERO),
109        mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
110        mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)),
111        mGradientCache(MB(DEFAULT_GRADIENT_CACHE_SIZE)),
112        mPatchCache(DEFAULT_PATCH_CACHE_SIZE) {
113    LOGD("Create OpenGLRenderer");
114
115    char property[PROPERTY_VALUE_MAX];
116    if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
117        LOGD("  Setting texture cache size to %sMB", property);
118        mTextureCache.setMaxSize(MB(atof(property)));
119    } else {
120        LOGD("  Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
121    }
122
123    if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
124        LOGD("  Setting layer cache size to %sMB", property);
125        mLayerCache.setMaxSize(MB(atof(property)));
126    } else {
127        LOGD("  Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
128    }
129
130    if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
131        LOGD("  Setting gradient cache size to %sMB", property);
132        mLayerCache.setMaxSize(MB(atof(property)));
133    } else {
134        LOGD("  Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
135    }
136
137    mCurrentProgram = NULL;
138
139    mShader = kShaderNone;
140    mShaderTileX = GL_CLAMP_TO_EDGE;
141    mShaderTileY = GL_CLAMP_TO_EDGE;
142    mShaderMatrix = NULL;
143    mShaderBitmap = NULL;
144
145    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
146
147    mFirstSnapshot = new Snapshot;
148
149    GLint maxTextureUnits;
150    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
151    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
152        LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
153    }
154}
155
156OpenGLRenderer::~OpenGLRenderer() {
157    LOGD("Destroy OpenGLRenderer");
158
159    mTextureCache.clear();
160    mLayerCache.clear();
161    mGradientCache.clear();
162    mPatchCache.clear();
163}
164
165///////////////////////////////////////////////////////////////////////////////
166// Setup
167///////////////////////////////////////////////////////////////////////////////
168
169void OpenGLRenderer::setViewport(int width, int height) {
170    glViewport(0, 0, width, height);
171
172    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
173
174    mWidth = width;
175    mHeight = height;
176    mFirstSnapshot->height = height;
177}
178
179void OpenGLRenderer::prepare() {
180    mSnapshot = new Snapshot(mFirstSnapshot);
181    mSaveCount = 0;
182
183    glDisable(GL_SCISSOR_TEST);
184
185    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
186    glClear(GL_COLOR_BUFFER_BIT);
187
188    glEnable(GL_SCISSOR_TEST);
189    glScissor(0, 0, mWidth, mHeight);
190
191    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
192}
193
194///////////////////////////////////////////////////////////////////////////////
195// State management
196///////////////////////////////////////////////////////////////////////////////
197
198int OpenGLRenderer::getSaveCount() const {
199    return mSaveCount;
200}
201
202int OpenGLRenderer::save(int flags) {
203    return saveSnapshot();
204}
205
206void OpenGLRenderer::restore() {
207    if (mSaveCount == 0) return;
208
209    if (restoreSnapshot()) {
210        setScissorFromClip();
211    }
212}
213
214void OpenGLRenderer::restoreToCount(int saveCount) {
215    if (saveCount <= 0 || saveCount > mSaveCount) return;
216
217    bool restoreClip = false;
218
219    while (mSaveCount != saveCount - 1) {
220        restoreClip |= restoreSnapshot();
221    }
222
223    if (restoreClip) {
224        setScissorFromClip();
225    }
226}
227
228int OpenGLRenderer::saveSnapshot() {
229    mSnapshot = new Snapshot(mSnapshot);
230    return ++mSaveCount;
231}
232
233bool OpenGLRenderer::restoreSnapshot() {
234    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
235    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
236    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
237
238    sp<Snapshot> current = mSnapshot;
239    sp<Snapshot> previous = mSnapshot->previous;
240
241    if (restoreOrtho) {
242        mOrthoMatrix.load(current->orthoMatrix);
243    }
244
245    if (restoreLayer) {
246        composeLayer(current, previous);
247    }
248
249    mSnapshot = previous;
250    mSaveCount--;
251
252    return restoreClip;
253}
254
255void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
256    if (!current->layer) {
257        LOGE("Attempting to compose a layer that does not exist");
258        return;
259    }
260
261    // Unbind current FBO and restore previous one
262    // Most of the time, previous->fbo will be 0 to bind the default buffer
263    glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
264
265    // Restore the clip from the previous snapshot
266    const Rect& clip = previous->clipRect;
267    glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
268
269    Layer* layer = current->layer;
270    const Rect& rect = layer->layer;
271
272    drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
273            layer->texture, layer->alpha, layer->mode, layer->blend);
274
275    LayerSize size(rect.getWidth(), rect.getHeight());
276    // Failing to add the layer to the cache should happen only if the
277    // layer is too large
278    if (!mLayerCache.put(size, layer)) {
279        LAYER_LOGD("Deleting layer");
280
281        glDeleteFramebuffers(1, &layer->fbo);
282        glDeleteTextures(1, &layer->texture);
283
284        delete layer;
285    }
286}
287
288///////////////////////////////////////////////////////////////////////////////
289// Layers
290///////////////////////////////////////////////////////////////////////////////
291
292int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
293        const SkPaint* p, int flags) {
294    int count = saveSnapshot();
295
296    int alpha = 255;
297    SkXfermode::Mode mode;
298
299    if (p) {
300        alpha = p->getAlpha();
301        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
302        if (!isMode) {
303            // Assume SRC_OVER
304            mode = SkXfermode::kSrcOver_Mode;
305        }
306    } else {
307        mode = SkXfermode::kSrcOver_Mode;
308    }
309
310    createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags);
311
312    return count;
313}
314
315int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
316        int alpha, int flags) {
317    int count = saveSnapshot();
318    createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
319    return count;
320}
321
322bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
323        float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
324    LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
325    LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize());
326
327    GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
328    LayerSize size(right - left, bottom - top);
329
330    Layer* layer = mLayerCache.get(size, previousFbo);
331    if (!layer) {
332        return false;
333    }
334
335    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
336
337    // Clear the FBO
338    glDisable(GL_SCISSOR_TEST);
339    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
340    glClear(GL_COLOR_BUFFER_BIT);
341    glEnable(GL_SCISSOR_TEST);
342
343    // Save the layer in the snapshot
344    snapshot->flags |= Snapshot::kFlagIsLayer;
345    layer->mode = mode;
346    layer->alpha = alpha / 255.0f;
347    layer->layer.set(left, top, right, bottom);
348
349    snapshot->layer = layer;
350    snapshot->fbo = layer->fbo;
351
352    // Creates a new snapshot to draw into the FBO
353    saveSnapshot();
354    // TODO: This doesn't preserve other transformations (check Skia first)
355    mSnapshot->transform.loadTranslate(-left, -top, 0.0f);
356    mSnapshot->setClip(0.0f, 0.0f, right - left, bottom - top);
357    mSnapshot->height = bottom - top;
358    setScissorFromClip();
359
360    mSnapshot->flags = Snapshot::kFlagDirtyOrtho | Snapshot::kFlagClipSet;
361    mSnapshot->orthoMatrix.load(mOrthoMatrix);
362
363    // Change the ortho projection
364    mOrthoMatrix.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f);
365
366    return true;
367}
368
369///////////////////////////////////////////////////////////////////////////////
370// Transforms
371///////////////////////////////////////////////////////////////////////////////
372
373void OpenGLRenderer::translate(float dx, float dy) {
374    mSnapshot->transform.translate(dx, dy, 0.0f);
375}
376
377void OpenGLRenderer::rotate(float degrees) {
378    mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f);
379}
380
381void OpenGLRenderer::scale(float sx, float sy) {
382    mSnapshot->transform.scale(sx, sy, 1.0f);
383}
384
385void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
386    mSnapshot->transform.load(*matrix);
387}
388
389void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
390    mSnapshot->transform.copyTo(*matrix);
391}
392
393void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
394    mat4 m(*matrix);
395    mSnapshot->transform.multiply(m);
396}
397
398///////////////////////////////////////////////////////////////////////////////
399// Clipping
400///////////////////////////////////////////////////////////////////////////////
401
402void OpenGLRenderer::setScissorFromClip() {
403    const Rect& clip = mSnapshot->clipRect;
404    glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
405}
406
407const Rect& OpenGLRenderer::getClipBounds() {
408    return mSnapshot->getLocalClip();
409}
410
411bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
412    Rect r(left, top, right, bottom);
413    mSnapshot->transform.mapRect(r);
414    return !mSnapshot->clipRect.intersects(r);
415}
416
417bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
418    bool clipped = mSnapshot->clip(left, top, right, bottom, op);
419    if (clipped) {
420        setScissorFromClip();
421    }
422    return !mSnapshot->clipRect.isEmpty();
423}
424
425///////////////////////////////////////////////////////////////////////////////
426// Drawing
427///////////////////////////////////////////////////////////////////////////////
428
429void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
430    const float right = left + bitmap->width();
431    const float bottom = top + bitmap->height();
432
433    if (quickReject(left, top, right, bottom)) {
434        return;
435    }
436
437    const Texture* texture = mTextureCache.get(bitmap);
438    drawTextureRect(left, top, right, bottom, texture, paint);
439}
440
441void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
442    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
443    const mat4 transform(*matrix);
444    transform.mapRect(r);
445
446    if (quickReject(r.left, r.top, r.right, r.bottom)) {
447        return;
448    }
449
450    const Texture* texture = mTextureCache.get(bitmap);
451    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
452}
453
454void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
455         float srcLeft, float srcTop, float srcRight, float srcBottom,
456         float dstLeft, float dstTop, float dstRight, float dstBottom,
457         const SkPaint* paint) {
458    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
459        return;
460    }
461
462    const Texture* texture = mTextureCache.get(bitmap);
463
464    const float width = texture->width;
465    const float height = texture->height;
466
467    const float u1 = srcLeft / width;
468    const float v1 = srcTop / height;
469    const float u2 = srcRight / width;
470    const float v2 = srcBottom / height;
471
472    // TODO: Do this in the shader
473    resetDrawTextureTexCoords(u1, v1, u2, v2);
474
475    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
476
477    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
478}
479
480void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
481        float left, float top, float right, float bottom, const SkPaint* paint) {
482    if (quickReject(left, top, right, bottom)) {
483        return;
484    }
485
486    const Texture* texture = mTextureCache.get(bitmap);
487
488    int alpha;
489    SkXfermode::Mode mode;
490    getAlphaAndMode(paint, &alpha, &mode);
491
492    Patch* mesh = mPatchCache.get(patch);
493    mesh->updateVertices(bitmap, left, top, right, bottom,
494            &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
495
496    // Specify right and bottom as +1.0f from left/top to prevent scaling since the
497    // patch mesh already defines the final size
498    drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
499            mode, texture->blend, &mesh->vertices[0].position[0],
500            &mesh->vertices[0].texture[0], mesh->indices, mesh->indicesCount);
501}
502
503void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
504    const Rect& clip = mSnapshot->clipRect;
505    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
506}
507
508void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
509    if (quickReject(left, top, right, bottom)) {
510        return;
511    }
512
513    SkXfermode::Mode mode;
514
515    const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
516    if (!isMode) {
517        // Assume SRC_OVER
518        mode = SkXfermode::kSrcOver_Mode;
519    }
520
521    // Skia draws using the color's alpha channel if < 255
522    // Otherwise, it uses the paint's alpha
523    int color = p->getColor();
524    if (((color >> 24) & 0xff) == 255) {
525        color |= p->getAlpha() << 24;
526    }
527
528    drawColorRect(left, top, right, bottom, color, mode);
529}
530
531void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
532        float x, float y, SkPaint* paint) {
533    if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
534        return;
535    }
536
537    float length;
538    switch (paint->getTextAlign()) {
539        case SkPaint::kCenter_Align:
540            length = paint->measureText(text, bytesCount);
541            x -= length / 2.0f;
542            break;
543        case SkPaint::kRight_Align:
544            length = paint->measureText(text, bytesCount);
545            x -= length;
546            break;
547        default:
548            break;
549    }
550
551    int alpha;
552    SkXfermode::Mode mode;
553    getAlphaAndMode(paint, &alpha, &mode);
554
555    uint32_t color = paint->getColor();
556    const GLfloat a = alpha / 255.0f;
557    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
558    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
559    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
560
561    mModelView.loadIdentity();
562
563    ProgramDescription description;
564    description.hasTexture = true;
565    description.hasAlpha8Texture = true;
566
567    useProgram(mProgramCache.get(description));
568    mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
569
570    chooseBlending(true, mode);
571    bindTexture(mFontRenderer.getTexture(), GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
572    glUniform1i(mCurrentProgram->getUniform("sampler"), 0);
573
574    int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
575    glEnableVertexAttribArray(texCoordsSlot);
576
577    // Always premultiplied
578    glUniform4f(mCurrentProgram->color, r, g, b, a);
579
580    // TODO: Implement scale properly
581    const Rect& clip = mSnapshot->getLocalClip();
582    mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize());
583    mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
584
585    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
586    glDisableVertexAttribArray(texCoordsSlot);
587}
588
589///////////////////////////////////////////////////////////////////////////////
590// Shaders
591///////////////////////////////////////////////////////////////////////////////
592
593void OpenGLRenderer::resetShader() {
594    mShader = OpenGLRenderer::kShaderNone;
595    mShaderKey = NULL;
596    mShaderBlend = false;
597    mShaderTileX = GL_CLAMP_TO_EDGE;
598    mShaderTileY = GL_CLAMP_TO_EDGE;
599}
600
601void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX,
602        SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha) {
603    mShader = OpenGLRenderer::kShaderBitmap;
604    mShaderBlend = hasAlpha;
605    mShaderBitmap = bitmap;
606    mShaderTileX = gTileModes[tileX];
607    mShaderTileY = gTileModes[tileY];
608    mShaderMatrix = matrix;
609}
610
611void OpenGLRenderer::setupLinearGradientShader(SkShader* shader, float* bounds, uint32_t* colors,
612        float* positions, int count, SkShader::TileMode tileMode, SkMatrix* matrix, bool hasAlpha) {
613    // TODO: We should use a struct to describe each shader
614    mShader = OpenGLRenderer::kShaderLinearGradient;
615    mShaderKey = shader;
616    mShaderBlend = hasAlpha;
617    mShaderTileX = gTileModes[tileMode];
618    mShaderTileY = gTileModes[tileMode];
619    mShaderMatrix = matrix;
620    mShaderBounds = bounds;
621    mShaderColors = colors;
622    mShaderPositions = positions;
623    mShaderCount = count;
624}
625
626///////////////////////////////////////////////////////////////////////////////
627// Drawing implementation
628///////////////////////////////////////////////////////////////////////////////
629
630void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
631        int color, SkXfermode::Mode mode, bool ignoreTransform) {
632    // If a shader is set, preserve only the alpha
633    if (mShader != kShaderNone) {
634        color |= 0x00ffffff;
635    }
636
637    // Render using pre-multiplied alpha
638    const int alpha = (color >> 24) & 0xFF;
639    const GLfloat a = alpha / 255.0f;
640
641    switch (mShader) {
642        case OpenGLRenderer::kShaderBitmap:
643            drawBitmapShader(left, top, right, bottom, a, mode);
644            return;
645        case OpenGLRenderer::kShaderLinearGradient:
646            drawLinearGradientShader(left, top, right, bottom, a, mode);
647            return;
648        default:
649            break;
650    }
651
652    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
653    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
654    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
655
656    // Pre-multiplication happens when setting the shader color
657    chooseBlending(alpha < 255 || mShaderBlend, mode);
658
659    mModelView.loadTranslate(left, top, 0.0f);
660    mModelView.scale(right - left, bottom - top, 1.0f);
661
662    ProgramDescription description;
663    Program* program = mProgramCache.get(description);
664    if (!useProgram(program)) {
665        const GLvoid* vertices = &mMeshVertices[0].position[0];
666        const GLvoid* texCoords = &mMeshVertices[0].texture[0];
667
668        glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
669                gMeshStride, vertices);
670    }
671
672    if (!ignoreTransform) {
673        mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
674    } else {
675        mat4 identity;
676        mCurrentProgram->set(mOrthoMatrix, mModelView, identity);
677    }
678
679    glUniform4f(mCurrentProgram->color, r, g, b, a);
680
681    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
682}
683
684void OpenGLRenderer::drawLinearGradientShader(float left, float top, float right, float bottom,
685        float alpha, SkXfermode::Mode mode) {
686    Texture* texture = mGradientCache.get(mShaderKey);
687    if (!texture) {
688        SkShader::TileMode tileMode = SkShader::kClamp_TileMode;
689        switch (mShaderTileX) {
690            case GL_REPEAT:
691                tileMode = SkShader::kRepeat_TileMode;
692                break;
693            case GL_MIRRORED_REPEAT:
694                tileMode = SkShader::kMirror_TileMode;
695                break;
696        }
697
698        texture = mGradientCache.addLinearGradient(mShaderKey, mShaderBounds, mShaderColors,
699                mShaderPositions, mShaderCount, tileMode);
700    }
701
702    ProgramDescription description;
703    description.hasGradient = true;
704
705    mModelView.loadTranslate(left, top, 0.0f);
706    mModelView.scale(right - left, bottom - top, 1.0f);
707
708    useProgram(mProgramCache.get(description));
709    mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
710
711    chooseBlending(mShaderBlend || alpha < 1.0f, mode);
712    bindTexture(texture->id, mShaderTileX, mShaderTileY, 0);
713    glUniform1i(mCurrentProgram->getUniform("gradientSampler"), 0);
714
715    Rect start(mShaderBounds[0], mShaderBounds[1], mShaderBounds[2], mShaderBounds[3]);
716    if (mShaderMatrix) {
717        mat4 shaderMatrix(*mShaderMatrix);
718        shaderMatrix.mapRect(start);
719    }
720    mSnapshot->transform.mapRect(start);
721
722    const float gradientX = start.right - start.left;
723    const float gradientY = start.bottom - start.top;
724
725    mat4 screenSpace(mSnapshot->transform);
726    screenSpace.multiply(mModelView);
727
728    // Always premultiplied
729    glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
730    glUniform2f(mCurrentProgram->getUniform("gradientStart"), start.left, start.top);
731    glUniform2f(mCurrentProgram->getUniform("gradient"), gradientX, gradientY);
732    glUniform1f(mCurrentProgram->getUniform("gradientLength"),
733            1.0f / (gradientX * gradientX + gradientY * gradientY));
734    glUniformMatrix4fv(mCurrentProgram->getUniform("screenSpace"), 1, GL_FALSE,
735            &screenSpace.data[0]);
736
737    glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
738            gMeshStride, &mMeshVertices[0].position[0]);
739
740    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
741}
742
743void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom,
744        float alpha, SkXfermode::Mode mode) {
745    const Texture* texture = mTextureCache.get(mShaderBitmap);
746
747    const float width = texture->width;
748    const float height = texture->height;
749
750    mModelView.loadTranslate(left, top, 0.0f);
751    mModelView.scale(right - left, bottom - top, 1.0f);
752
753    mat4 textureTransform;
754    if (mShaderMatrix) {
755        SkMatrix inverse;
756        mShaderMatrix->invert(&inverse);
757        textureTransform.load(inverse);
758        textureTransform.multiply(mModelView);
759    } else {
760        textureTransform.load(mModelView);
761    }
762
763    ProgramDescription description;
764    description.hasBitmap = true;
765    // The driver does not support non-power of two mirrored/repeated
766    // textures, so do it ourselves
767    if (!mExtensions.hasNPot()) {
768        description.isBitmapNpot = true;
769        description.bitmapWrapS = mShaderTileX;
770        description.bitmapWrapT = mShaderTileY;
771    }
772
773    useProgram(mProgramCache.get(description));
774    mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
775
776    chooseBlending(texture->blend || alpha < 1.0f, mode);
777
778    // Texture
779    bindTexture(texture->id, mShaderTileX, mShaderTileY, 0);
780    glUniform1i(mCurrentProgram->getUniform("bitmapSampler"), 0);
781    glUniformMatrix4fv(mCurrentProgram->getUniform("textureTransform"), 1,
782            GL_FALSE, &textureTransform.data[0]);
783    glUniform2f(mCurrentProgram->getUniform("textureDimension"), 1.0f / width, 1.0f / height);
784
785    // Always premultiplied
786    glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
787
788    // Mesh
789    glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
790            gMeshStride, &mMeshVertices[0].position[0]);
791
792    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
793}
794
795void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
796        const Texture* texture, const SkPaint* paint) {
797    int alpha;
798    SkXfermode::Mode mode;
799    getAlphaAndMode(paint, &alpha, &mode);
800
801    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
802            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
803}
804
805void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
806        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
807    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
808            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
809}
810
811void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
812        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
813        GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
814    ProgramDescription description;
815    description.hasTexture = true;
816
817    mModelView.loadTranslate(left, top, 0.0f);
818    mModelView.scale(right - left, bottom - top, 1.0f);
819
820    useProgram(mProgramCache.get(description));
821    mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
822
823    chooseBlending(blend || alpha < 1.0f, mode);
824
825    // Texture
826    bindTexture(texture, mShaderTileX, mShaderTileY, 0);
827    glUniform1i(mCurrentProgram->getUniform("sampler"), 0);
828
829    // Always premultiplied
830    glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
831
832    // Mesh
833    int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
834    glEnableVertexAttribArray(texCoordsSlot);
835    glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
836            gMeshStride, vertices);
837    glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
838
839    if (!indices) {
840        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
841    } else {
842        glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
843    }
844    glDisableVertexAttribArray(texCoordsSlot);
845}
846
847void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
848    // In theory we should not blend if the mode is Src, but it's rare enough
849    // that it's not worth it
850    blend = blend || mode != SkXfermode::kSrcOver_Mode;
851    if (blend) {
852        if (!mBlend) {
853            glEnable(GL_BLEND);
854        }
855
856        GLenum sourceMode = gBlends[mode].src;
857        GLenum destMode = gBlends[mode].dst;
858        if (!isPremultiplied && sourceMode == GL_ONE) {
859            sourceMode = GL_SRC_ALPHA;
860        }
861
862        if (sourceMode != mLastSrcMode || destMode != mLastDstMode) {
863            glBlendFunc(sourceMode, destMode);
864            mLastSrcMode = sourceMode;
865            mLastDstMode = destMode;
866        }
867    } else if (mBlend) {
868        glDisable(GL_BLEND);
869    }
870    mBlend = blend;
871}
872
873bool OpenGLRenderer::useProgram(Program* program) {
874    if (!program->isInUse()) {
875        if (mCurrentProgram != NULL) mCurrentProgram->remove();
876        program->use();
877        mCurrentProgram = program;
878        return false;
879    }
880    return true;
881}
882
883void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
884    TextureVertex* v = &mMeshVertices[0];
885    TextureVertex::setUV(v++, u1, v1);
886    TextureVertex::setUV(v++, u2, v1);
887    TextureVertex::setUV(v++, u1, v2);
888    TextureVertex::setUV(v++, u2, v2);
889}
890
891void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
892    if (paint) {
893        const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
894        if (!isMode) {
895            // Assume SRC_OVER
896            *mode = SkXfermode::kSrcOver_Mode;
897        }
898
899        // Skia draws using the color's alpha channel if < 255
900        // Otherwise, it uses the paint's alpha
901        int color = paint->getColor();
902        *alpha = (color >> 24) & 0xFF;
903        if (*alpha == 255) {
904            *alpha = paint->getAlpha();
905        }
906    } else {
907        *mode = SkXfermode::kSrcOver_Mode;
908        *alpha = 255;
909    }
910}
911
912void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
913    glActiveTexture(gTextureUnits[textureUnit]);
914    glBindTexture(GL_TEXTURE_2D, texture);
915    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
916    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
917}
918
919}; // namespace uirenderer
920}; // namespace android
921