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