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