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