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