OpenGLRenderer.cpp revision a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5
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 <utils/Log.h>
27
28#include "OpenGLRenderer.h"
29
30namespace android {
31namespace uirenderer {
32
33///////////////////////////////////////////////////////////////////////////////
34// Defines
35///////////////////////////////////////////////////////////////////////////////
36
37#define REQUIRED_TEXTURE_UNITS_COUNT 3
38
39// Generates simple and textured vertices
40#define FV(x, y, u, v) { { x, y }, { u, v } }
41
42///////////////////////////////////////////////////////////////////////////////
43// Globals
44///////////////////////////////////////////////////////////////////////////////
45
46// This array is never used directly but used as a memcpy source in the
47// OpenGLRenderer constructor
48static const TextureVertex gMeshVertices[] = {
49        FV(0.0f, 0.0f, 0.0f, 0.0f),
50        FV(1.0f, 0.0f, 1.0f, 0.0f),
51        FV(0.0f, 1.0f, 0.0f, 1.0f),
52        FV(1.0f, 1.0f, 1.0f, 1.0f)
53};
54static const GLsizei gMeshStride = sizeof(TextureVertex);
55static const GLsizei gMeshCount = 4;
56
57/**
58 * Structure mapping Skia xfermodes to OpenGL blending factors.
59 */
60struct Blender {
61    SkXfermode::Mode mode;
62    GLenum src;
63    GLenum dst;
64}; // struct Blender
65
66// In this array, the index of each Blender equals the value of the first
67// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
68static const Blender gBlends[] = {
69        { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO },
70        { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO },
71        { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE },
72        { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA },
73        { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE },
74        { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO },
75        { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA },
76        { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO },
77        { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA },
78        { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA },
79        { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA },
80        { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA }
81};
82
83static const GLenum gTextureUnits[] = {
84        GL_TEXTURE0,
85        GL_TEXTURE1,
86        GL_TEXTURE2
87};
88
89///////////////////////////////////////////////////////////////////////////////
90// Constructors/destructor
91///////////////////////////////////////////////////////////////////////////////
92
93OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
94    LOGD("Create OpenGLRenderer");
95
96    mShader = NULL;
97    mColorFilter = NULL;
98    mHasShadow = false;
99
100    memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
101
102    mFirstSnapshot = new Snapshot;
103
104    GLint maxTextureUnits;
105    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
106    if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
107        LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
108    }
109}
110
111OpenGLRenderer::~OpenGLRenderer() {
112    LOGD("Destroy OpenGLRenderer");
113}
114
115///////////////////////////////////////////////////////////////////////////////
116// Setup
117///////////////////////////////////////////////////////////////////////////////
118
119void OpenGLRenderer::setViewport(int width, int height) {
120    glViewport(0, 0, width, height);
121    mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
122
123    mWidth = width;
124    mHeight = height;
125    mFirstSnapshot->height = height;
126    mFirstSnapshot->viewport.set(0, 0, width, height);
127}
128
129void OpenGLRenderer::prepare() {
130    mSnapshot = new Snapshot(mFirstSnapshot,
131            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
132    mSaveCount = 1;
133
134    glViewport(0, 0, mWidth, mHeight);
135
136    glDisable(GL_DITHER);
137    glDisable(GL_SCISSOR_TEST);
138
139    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
140    glClear(GL_COLOR_BUFFER_BIT);
141
142    glEnable(GL_SCISSOR_TEST);
143    glScissor(0, 0, mWidth, mHeight);
144
145    mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
146}
147
148void OpenGLRenderer::acquireContext() {
149    if (mCaches.currentProgram) {
150        if (mCaches.currentProgram->isInUse()) {
151            mCaches.currentProgram->remove();
152            mCaches.currentProgram = NULL;
153        }
154    }
155}
156
157void OpenGLRenderer::releaseContext() {
158    glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight());
159
160    glEnable(GL_SCISSOR_TEST);
161    setScissorFromClip();
162
163    if (mCaches.blend) {
164        glEnable(GL_BLEND);
165        glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
166    } else {
167        glDisable(GL_BLEND);
168    }
169}
170
171///////////////////////////////////////////////////////////////////////////////
172// State management
173///////////////////////////////////////////////////////////////////////////////
174
175int OpenGLRenderer::getSaveCount() const {
176    return mSaveCount;
177}
178
179int OpenGLRenderer::save(int flags) {
180    return saveSnapshot(flags);
181}
182
183void OpenGLRenderer::restore() {
184    if (mSaveCount > 1) {
185        restoreSnapshot();
186    }
187}
188
189void OpenGLRenderer::restoreToCount(int saveCount) {
190    if (saveCount < 1) saveCount = 1;
191
192    while (mSaveCount > saveCount) {
193        restoreSnapshot();
194    }
195}
196
197int OpenGLRenderer::saveSnapshot(int flags) {
198    mSnapshot = new Snapshot(mSnapshot, flags);
199    return mSaveCount++;
200}
201
202bool OpenGLRenderer::restoreSnapshot() {
203    bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet;
204    bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer;
205    bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho;
206
207    sp<Snapshot> current = mSnapshot;
208    sp<Snapshot> previous = mSnapshot->previous;
209
210    if (restoreOrtho) {
211        Rect& r = previous->viewport;
212        glViewport(r.left, r.top, r.right, r.bottom);
213        mOrthoMatrix.load(current->orthoMatrix);
214    }
215
216    mSaveCount--;
217    mSnapshot = previous;
218
219    if (restoreLayer) {
220        composeLayer(current, previous);
221    }
222
223    if (restoreClip) {
224        setScissorFromClip();
225    }
226
227    return restoreClip;
228}
229
230///////////////////////////////////////////////////////////////////////////////
231// Layers
232///////////////////////////////////////////////////////////////////////////////
233
234int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
235        const SkPaint* p, int flags) {
236    int count = saveSnapshot(flags);
237
238    int alpha = 255;
239    SkXfermode::Mode mode;
240
241    if (p) {
242        alpha = p->getAlpha();
243        if (!mExtensions.hasFramebufferFetch()) {
244            const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
245            if (!isMode) {
246                // Assume SRC_OVER
247                mode = SkXfermode::kSrcOver_Mode;
248            }
249        } else {
250            mode = getXfermode(p->getXfermode());
251        }
252    } else {
253        mode = SkXfermode::kSrcOver_Mode;
254    }
255
256    if (alpha > 0 && !mSnapshot->invisible) {
257        createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags);
258    } else {
259        mSnapshot->invisible = true;
260    }
261
262    return count;
263}
264
265int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
266        int alpha, int flags) {
267    if (alpha == 0xff) {
268        return saveLayer(left, top, right, bottom, NULL, flags);
269    } else {
270        SkPaint paint;
271        paint.setAlpha(alpha);
272        return saveLayer(left, top, right, bottom, &paint, flags);
273    }
274}
275
276bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
277        float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
278    LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
279    LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
280
281    Rect bounds(left, top, right, bottom);
282    // TODO: Apply transformations and treat layers in screen coordinates
283    // mSnapshot->transform->mapRect(bounds);
284
285    GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
286    LayerSize size(bounds.getWidth(), bounds.getHeight());
287
288    Layer* layer = mCaches.layerCache.get(size, previousFbo);
289    if (!layer) {
290        return false;
291    }
292
293    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
294
295    // Clear the FBO
296    glDisable(GL_SCISSOR_TEST);
297    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
298    glClear(GL_COLOR_BUFFER_BIT);
299    glEnable(GL_SCISSOR_TEST);
300
301    layer->mode = mode;
302    layer->alpha = alpha / 255.0f;
303    layer->layer.set(bounds);
304
305    // Save the layer in the snapshot
306    snapshot->flags |= Snapshot::kFlagIsLayer;
307    snapshot->layer = layer;
308    snapshot->fbo = layer->fbo;
309    // TODO: Temporary until real layer support is implemented
310    snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
311    // TODO: Temporary until real layer support is implemented
312    snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
313    snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
314    snapshot->height = bounds.getHeight();
315    snapshot->flags |= Snapshot::kFlagDirtyOrtho;
316    snapshot->orthoMatrix.load(mOrthoMatrix);
317
318    setScissorFromClip();
319
320    // Change the ortho projection
321    glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
322    mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
323
324    return true;
325}
326
327void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
328    if (!current->layer) {
329        LOGE("Attempting to compose a layer that does not exist");
330        return;
331    }
332
333    // Unbind current FBO and restore previous one
334    // Most of the time, previous->fbo will be 0 to bind the default buffer
335    glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
336
337    // Restore the clip from the previous snapshot
338    const Rect& clip = *previous->clipRect;
339    glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight());
340
341    Layer* layer = current->layer;
342    const Rect& rect = layer->layer;
343
344    // FBOs are already drawn with a top-left origin, don't flip the texture
345    resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
346
347    drawTextureRect(rect.left, rect.top, rect.right, rect.bottom,
348            layer->texture, layer->alpha, layer->mode, layer->blend);
349
350    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
351
352    LayerSize size(rect.getWidth(), rect.getHeight());
353    // Failing to add the layer to the cache should happen only if the
354    // layer is too large
355    if (!mCaches.layerCache.put(size, layer)) {
356        LAYER_LOGD("Deleting layer");
357
358        glDeleteFramebuffers(1, &layer->fbo);
359        glDeleteTextures(1, &layer->texture);
360
361        delete layer;
362    }
363}
364
365///////////////////////////////////////////////////////////////////////////////
366// Transforms
367///////////////////////////////////////////////////////////////////////////////
368
369void OpenGLRenderer::translate(float dx, float dy) {
370    mSnapshot->transform->translate(dx, dy, 0.0f);
371}
372
373void OpenGLRenderer::rotate(float degrees) {
374    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
375}
376
377void OpenGLRenderer::scale(float sx, float sy) {
378    mSnapshot->transform->scale(sx, sy, 1.0f);
379}
380
381void OpenGLRenderer::setMatrix(SkMatrix* matrix) {
382    mSnapshot->transform->load(*matrix);
383}
384
385void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
386    mSnapshot->transform->copyTo(*matrix);
387}
388
389void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
390    mat4 m(*matrix);
391    mSnapshot->transform->multiply(m);
392}
393
394///////////////////////////////////////////////////////////////////////////////
395// Clipping
396///////////////////////////////////////////////////////////////////////////////
397
398void OpenGLRenderer::setScissorFromClip() {
399    const Rect& clip = *mSnapshot->clipRect;
400    glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight());
401}
402
403const Rect& OpenGLRenderer::getClipBounds() {
404    return mSnapshot->getLocalClip();
405}
406
407bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
408    if (mSnapshot->invisible) return true;
409
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    glActiveTexture(GL_TEXTURE0);
436    const Texture* texture = mCaches.textureCache.get(bitmap);
437    if (!texture) return;
438    const AutoTexture autoCleanup(texture);
439
440    drawTextureRect(left, top, right, bottom, texture, paint);
441}
442
443void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
444    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
445    const mat4 transform(*matrix);
446    transform.mapRect(r);
447
448    if (quickReject(r.left, r.top, r.right, r.bottom)) {
449        return;
450    }
451
452    glActiveTexture(GL_TEXTURE0);
453    const Texture* texture = mCaches.textureCache.get(bitmap);
454    if (!texture) return;
455    const AutoTexture autoCleanup(texture);
456
457    drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint);
458}
459
460void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
461         float srcLeft, float srcTop, float srcRight, float srcBottom,
462         float dstLeft, float dstTop, float dstRight, float dstBottom,
463         const SkPaint* paint) {
464    if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
465        return;
466    }
467
468    glActiveTexture(GL_TEXTURE0);
469    const Texture* texture = mCaches.textureCache.get(bitmap);
470    if (!texture) return;
471    const AutoTexture autoCleanup(texture);
472
473    const float width = texture->width;
474    const float height = texture->height;
475
476    const float u1 = srcLeft / width;
477    const float v1 = srcTop / height;
478    const float u2 = srcRight / width;
479    const float v2 = srcBottom / height;
480
481    resetDrawTextureTexCoords(u1, v1, u2, v2);
482
483    drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture, paint);
484
485    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
486}
487
488void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
489        float left, float top, float right, float bottom, const SkPaint* paint) {
490    if (quickReject(left, top, right, bottom)) {
491        return;
492    }
493
494    glActiveTexture(GL_TEXTURE0);
495    const Texture* texture = mCaches.textureCache.get(bitmap);
496    if (!texture) return;
497    const AutoTexture autoCleanup(texture);
498
499    int alpha;
500    SkXfermode::Mode mode;
501    getAlphaAndMode(paint, &alpha, &mode);
502
503    Patch* mesh = mCaches.patchCache.get(patch);
504    mesh->updateVertices(bitmap, left, top, right, bottom,
505            &patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
506
507    // Specify right and bottom as +1.0f from left/top to prevent scaling since the
508    // patch mesh already defines the final size
509    drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f,
510            mode, texture->blend, &mesh->vertices[0].position[0],
511            &mesh->vertices[0].texture[0], mesh->indices, mesh->indicesCount);
512}
513
514void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
515    if (mSnapshot->invisible) return;
516    const Rect& clip = *mSnapshot->clipRect;
517    drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
518}
519
520void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
521    if (quickReject(left, top, right, bottom)) {
522        return;
523    }
524
525    SkXfermode::Mode mode;
526    if (!mExtensions.hasFramebufferFetch()) {
527        const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
528        if (!isMode) {
529            // Assume SRC_OVER
530            mode = SkXfermode::kSrcOver_Mode;
531        }
532    } else {
533        mode = getXfermode(p->getXfermode());
534    }
535
536    // Skia draws using the color's alpha channel if < 255
537    // Otherwise, it uses the paint's alpha
538    int color = p->getColor();
539    if (((color >> 24) & 0xff) == 255) {
540        color |= p->getAlpha() << 24;
541    }
542
543    drawColorRect(left, top, right, bottom, color, mode);
544}
545
546void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
547        float x, float y, SkPaint* paint) {
548    if (mSnapshot->invisible || text == NULL || count == 0 ||
549            (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
550        return;
551    }
552
553    float scaleX = paint->getTextScaleX();
554    bool applyScaleX = scaleX < 0.9999f || scaleX > 1.0001f;
555    if (applyScaleX) {
556        save(SkCanvas::kMatrix_SaveFlag);
557        translate(x - (x * scaleX), 0.0f);
558        scale(scaleX, 1.0f);
559    }
560
561    float length = -1.0f;
562    switch (paint->getTextAlign()) {
563        case SkPaint::kCenter_Align:
564            length = paint->measureText(text, bytesCount);
565            x -= length / 2.0f;
566            break;
567        case SkPaint::kRight_Align:
568            length = paint->measureText(text, bytesCount);
569            x -= length;
570            break;
571        default:
572            break;
573    }
574
575    int alpha;
576    SkXfermode::Mode mode;
577    getAlphaAndMode(paint, &alpha, &mode);
578
579    uint32_t color = paint->getColor();
580    const GLfloat a = alpha / 255.0f;
581    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
582    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
583    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
584
585    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
586    fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
587            paint->getTextSize());
588    if (mHasShadow) {
589        glActiveTexture(gTextureUnits[0]);
590        mCaches.dropShadowCache.setFontRenderer(fontRenderer);
591        const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount,
592                count, mShadowRadius);
593        const AutoTexture autoCleanup(shadow);
594
595        setupShadow(shadow, x, y, mode, a);
596
597        // Draw the mesh
598        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
599        glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
600    }
601
602    GLuint textureUnit = 0;
603    glActiveTexture(gTextureUnits[textureUnit]);
604
605    setupTextureAlpha8(fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a,
606            mode, false, true);
607
608    const Rect& clip = mSnapshot->getLocalClip();
609    fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
610
611    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
612    glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
613
614    drawTextDecorations(text, bytesCount, length, x, y, paint);
615
616    if (applyScaleX) {
617        restore();
618    }
619}
620
621void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
622    if (mSnapshot->invisible) return;
623
624    GLuint textureUnit = 0;
625    glActiveTexture(gTextureUnits[textureUnit]);
626
627    const PathTexture* texture = mCaches.pathCache.get(path, paint);
628    if (!texture) return;
629    const AutoTexture autoCleanup(texture);
630
631    const float x = texture->left - texture->offset;
632    const float y = texture->top - texture->offset;
633
634    if (quickReject(x, y, x + texture->width, y + texture->height)) {
635        return;
636    }
637
638    int alpha;
639    SkXfermode::Mode mode;
640    getAlphaAndMode(paint, &alpha, &mode);
641
642    uint32_t color = paint->getColor();
643    const GLfloat a = alpha / 255.0f;
644    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
645    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
646    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
647
648    setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true);
649
650    // Draw the mesh
651    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
652    glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
653}
654
655///////////////////////////////////////////////////////////////////////////////
656// Shaders
657///////////////////////////////////////////////////////////////////////////////
658
659void OpenGLRenderer::resetShader() {
660    mShader = NULL;
661}
662
663void OpenGLRenderer::setupShader(SkiaShader* shader) {
664    mShader = shader;
665    if (mShader) {
666        mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
667    }
668}
669
670///////////////////////////////////////////////////////////////////////////////
671// Color filters
672///////////////////////////////////////////////////////////////////////////////
673
674void OpenGLRenderer::resetColorFilter() {
675    mColorFilter = NULL;
676}
677
678void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) {
679    mColorFilter = filter;
680}
681
682///////////////////////////////////////////////////////////////////////////////
683// Drop shadow
684///////////////////////////////////////////////////////////////////////////////
685
686void OpenGLRenderer::resetShadow() {
687    mHasShadow = false;
688}
689
690void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
691    mHasShadow = true;
692    mShadowRadius = radius;
693    mShadowDx = dx;
694    mShadowDy = dy;
695    mShadowColor = color;
696}
697
698///////////////////////////////////////////////////////////////////////////////
699// Drawing implementation
700///////////////////////////////////////////////////////////////////////////////
701
702void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y,
703        SkXfermode::Mode mode, float alpha) {
704    const float sx = x - texture->left + mShadowDx;
705    const float sy = y - texture->top + mShadowDy;
706
707    const int shadowAlpha = ((mShadowColor >> 24) & 0xFF);
708    const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha;
709    const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f;
710    const GLfloat g = a * ((mShadowColor >>  8) & 0xFF) / 255.0f;
711    const GLfloat b = a * ((mShadowColor      ) & 0xFF) / 255.0f;
712
713    GLuint textureUnit = 0;
714    setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false);
715}
716
717void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit,
718        float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode,
719        bool transforms, bool applyFilters) {
720    setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit,
721            x, y, r, g, b, a, mode, transforms, applyFilters);
722}
723
724void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height,
725        GLuint& textureUnit, float x, float y, float r, float g, float b, float a,
726        SkXfermode::Mode mode, bool transforms, bool applyFilters) {
727     // Describe the required shaders
728     ProgramDescription description;
729     description.hasTexture = true;
730     description.hasAlpha8Texture = true;
731
732     if (applyFilters) {
733         if (mShader) {
734             mShader->describe(description, mExtensions);
735         }
736         if (mColorFilter) {
737             mColorFilter->describe(description, mExtensions);
738         }
739     }
740
741     // Setup the blending mode
742     chooseBlending(true, mode, description);
743
744     // Build and use the appropriate shader
745     useProgram(mCaches.programCache.get(description));
746
747     bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
748     glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit);
749
750     int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
751     glEnableVertexAttribArray(texCoordsSlot);
752
753     // Setup attributes
754     glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
755             gMeshStride, &mMeshVertices[0].position[0]);
756     glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
757             gMeshStride, &mMeshVertices[0].texture[0]);
758
759     // Setup uniforms
760     if (transforms) {
761         mModelView.loadTranslate(x, y, 0.0f);
762         mModelView.scale(width, height, 1.0f);
763     } else {
764         mModelView.loadIdentity();
765     }
766     mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
767     glUniform4f(mCaches.currentProgram->color, r, g, b, a);
768
769     textureUnit++;
770     if (applyFilters) {
771         // Setup attributes and uniforms required by the shaders
772         if (mShader) {
773             mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
774         }
775         if (mColorFilter) {
776             mColorFilter->setupProgram(mCaches.currentProgram);
777         }
778     }
779}
780
781#define kStdStrikeThru_Offset   (-6.0f / 21.0f)
782#define kStdUnderline_Offset    (1.0f / 9.0f)
783#define kStdUnderline_Thickness (1.0f / 18.0f)
784
785void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length,
786        float x, float y, SkPaint* paint) {
787    // Handle underline and strike-through
788    uint32_t flags = paint->getFlags();
789    if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) {
790        float underlineWidth = length;
791        // If length is > 0.0f, we already measured the text for the text alignment
792        if (length <= 0.0f) {
793            underlineWidth = paint->measureText(text, bytesCount);
794        }
795
796        float offsetX = 0;
797        switch (paint->getTextAlign()) {
798            case SkPaint::kCenter_Align:
799                offsetX = underlineWidth * 0.5f;
800                break;
801            case SkPaint::kRight_Align:
802                offsetX = underlineWidth;
803                break;
804            default:
805                break;
806        }
807
808        if (underlineWidth > 0.0f) {
809            float textSize = paint->getTextSize();
810            float height = textSize * kStdUnderline_Thickness;
811
812            float left = x - offsetX;
813            float top = 0.0f;
814            float right = left + underlineWidth;
815            float bottom = 0.0f;
816
817            if (flags & SkPaint::kUnderlineText_Flag) {
818                top = y + textSize * kStdUnderline_Offset;
819                bottom = top + height;
820                drawRect(left, top, right, bottom, paint);
821            }
822
823            if (flags & SkPaint::kStrikeThruText_Flag) {
824                top = y + textSize * kStdStrikeThru_Offset;
825                bottom = top + height;
826                drawRect(left, top, right, bottom, paint);
827            }
828        }
829    }
830}
831
832void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
833        int color, SkXfermode::Mode mode, bool ignoreTransform) {
834    // If a shader is set, preserve only the alpha
835    if (mShader) {
836        color |= 0x00ffffff;
837    }
838
839    // Render using pre-multiplied alpha
840    const int alpha = (color >> 24) & 0xFF;
841    const GLfloat a = alpha / 255.0f;
842    const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
843    const GLfloat g = a * ((color >>  8) & 0xFF) / 255.0f;
844    const GLfloat b = a * ((color      ) & 0xFF) / 255.0f;
845
846    GLuint textureUnit = 0;
847
848    // Describe the required shaders
849    ProgramDescription description;
850    if (mShader) {
851        mShader->describe(description, mExtensions);
852    }
853    if (mColorFilter) {
854        mColorFilter->describe(description, mExtensions);
855    }
856
857    // Setup the blending mode
858    chooseBlending(alpha < 255 || (mShader && mShader->blend()), mode, description);
859
860    // Build and use the appropriate shader
861    useProgram(mCaches.programCache.get(description));
862
863    // Setup attributes
864    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
865            gMeshStride, &mMeshVertices[0].position[0]);
866
867    // Setup uniforms
868    mModelView.loadTranslate(left, top, 0.0f);
869    mModelView.scale(right - left, bottom - top, 1.0f);
870    if (!ignoreTransform) {
871        mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
872    } else {
873        mat4 identity;
874        mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
875    }
876    glUniform4f(mCaches.currentProgram->color, r, g, b, a);
877
878    // Setup attributes and uniforms required by the shaders
879    if (mShader) {
880        mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
881    }
882    if (mColorFilter) {
883        mColorFilter->setupProgram(mCaches.currentProgram);
884    }
885
886    // Draw the mesh
887    glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
888}
889
890void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
891        const Texture* texture, const SkPaint* paint) {
892    int alpha;
893    SkXfermode::Mode mode;
894    getAlphaAndMode(paint, &alpha, &mode);
895
896    drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, texture->blend,
897            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
898}
899
900void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
901        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) {
902    drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend,
903            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], NULL);
904}
905
906void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
907        GLuint texture, float alpha, SkXfermode::Mode mode, bool blend,
908        GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) {
909    ProgramDescription description;
910    description.hasTexture = true;
911    if (mColorFilter) {
912        mColorFilter->describe(description, mExtensions);
913    }
914
915    mModelView.loadTranslate(left, top, 0.0f);
916    mModelView.scale(right - left, bottom - top, 1.0f);
917
918    chooseBlending(blend || alpha < 1.0f, mode, description);
919
920    useProgram(mCaches.programCache.get(description));
921    mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
922
923    // Texture
924    bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
925    glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
926
927    // Always premultiplied
928    glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha);
929
930    // Mesh
931    int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
932    glEnableVertexAttribArray(texCoordsSlot);
933    glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
934            gMeshStride, vertices);
935    glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
936
937    // Color filter
938    if (mColorFilter) {
939        mColorFilter->setupProgram(mCaches.currentProgram);
940    }
941
942    if (!indices) {
943        glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
944    } else {
945        glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices);
946    }
947    glDisableVertexAttribArray(texCoordsSlot);
948}
949
950void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
951        ProgramDescription& description) {
952    blend = blend || mode != SkXfermode::kSrcOver_Mode;
953    if (blend) {
954        if (mode < SkXfermode::kPlus_Mode) {
955            if (!mCaches.blend) {
956                glEnable(GL_BLEND);
957            }
958
959            GLenum sourceMode = gBlends[mode].src;
960            GLenum destMode = gBlends[mode].dst;
961
962            if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
963                glBlendFunc(sourceMode, destMode);
964                mCaches.lastSrcMode = sourceMode;
965                mCaches.lastDstMode = destMode;
966            }
967        } else {
968            // These blend modes are not supported by OpenGL directly and have
969            // to be implemented using shaders. Since the shader will perform
970            // the blending, turn blending off here
971            if (mExtensions.hasFramebufferFetch()) {
972                description.framebufferMode = mode;
973            }
974
975            if (mCaches.blend) {
976                glDisable(GL_BLEND);
977            }
978            blend = false;
979        }
980    } else if (mCaches.blend) {
981        glDisable(GL_BLEND);
982    }
983    mCaches.blend = blend;
984}
985
986bool OpenGLRenderer::useProgram(Program* program) {
987    if (!program->isInUse()) {
988        if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
989        program->use();
990        mCaches.currentProgram = program;
991        return false;
992    }
993    return true;
994}
995
996void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
997    TextureVertex* v = &mMeshVertices[0];
998    TextureVertex::setUV(v++, u1, v1);
999    TextureVertex::setUV(v++, u2, v1);
1000    TextureVertex::setUV(v++, u1, v2);
1001    TextureVertex::setUV(v++, u2, v2);
1002}
1003
1004void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
1005    if (paint) {
1006        if (!mExtensions.hasFramebufferFetch()) {
1007            const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
1008            if (!isMode) {
1009                // Assume SRC_OVER
1010                *mode = SkXfermode::kSrcOver_Mode;
1011            }
1012        } else {
1013            *mode = getXfermode(paint->getXfermode());
1014        }
1015
1016        // Skia draws using the color's alpha channel if < 255
1017        // Otherwise, it uses the paint's alpha
1018        int color = paint->getColor();
1019        *alpha = (color >> 24) & 0xFF;
1020        if (*alpha == 255) {
1021            *alpha = paint->getAlpha();
1022        }
1023    } else {
1024        *mode = SkXfermode::kSrcOver_Mode;
1025        *alpha = 255;
1026    }
1027}
1028
1029SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
1030    if (mode == NULL) {
1031        return SkXfermode::kSrcOver_Mode;
1032    }
1033    return mode->fMode;
1034}
1035
1036void OpenGLRenderer::bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit) {
1037    glActiveTexture(gTextureUnits[textureUnit]);
1038    glBindTexture(GL_TEXTURE_2D, texture);
1039    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
1040    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
1041}
1042
1043}; // namespace uirenderer
1044}; // namespace android
1045