OpenGLRenderer.cpp revision 746b7401ceb86b5f2805f8c0d3b39ac739152015
189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/* 289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project 389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * you may not use this file except in compliance with the License. 689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * You may obtain a copy of the License at 789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 1089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * See the License for the specific language governing permissions and 1489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * limitations under the License. 1589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project */ 1689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 1789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#define LOG_TAG "OpenGLRenderer" 1889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 1989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <stdlib.h> 2089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <stdint.h> 21273d098cc72a88c797d01c7dff0c1350f315f05fMathias Agopian#include <sys/types.h> 22273d098cc72a88c797d01c7dff0c1350f315f05fMathias Agopian 23273d098cc72a88c797d01c7dff0c1350f315f05fMathias Agopian#include <SkCanvas.h> 24273d098cc72a88c797d01c7dff0c1350f315f05fMathias Agopian#include <SkTypeface.h> 2589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 262db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber#include <utils/Log.h> 27a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania#include <utils/StopWatch.h> 2889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 2989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "OpenGLRenderer.h" 3089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 3189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectnamespace android { 32a64c8c79af1a15911c55306d83a797fa50969f77nikonamespace uirenderer { 3389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 3489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 3589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// Defines 3689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 3789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 3820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#define RAD_TO_DEG (180.0f / 3.14159265f) 39dac6a31a33ba53fb93850670cdddd1e6515dadceGloria Wang#define MIN_ANGLE 0.001f 4089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 4189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// TODO: This should be set in properties 4289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH) 4389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 4489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 4589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// Globals 4689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 4789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 4889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/** 4989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Structure mapping Skia xfermodes to OpenGL blending factors. 5089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project */ 5189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstruct Blender { 5289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project SkXfermode::Mode mode; 5389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project GLenum src; 5489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project GLenum dst; 5589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}; // struct Blender 5689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 5789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// In this array, the index of each Blender equals the value of the first 5889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] 5989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatic const Blender gBlends[] = { 6089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, 6189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO }, 6289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kDst_Mode, GL_ZERO, GL_ONE }, 6389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 6489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 6589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO }, 6689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 6789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 6889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 6989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 7089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 7189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } 7289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}; 7389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 7489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// This array contains the swapped version of each SkXfermode. For instance 7589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// this array's SrcOver blending mode is actually DstOver. You can refer to 7689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// createLayer() for more information on the purpose of this array. 7789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatic const Blender gBlendsSwap[] = { 7889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO }, 7989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrc_Mode, GL_ZERO, GL_ONE }, 80342e9cf388cceb807def720e40e8b0a217f4bcaaEric Laurent { SkXfermode::kDst_Mode, GL_ONE, GL_ZERO }, 8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber { SkXfermode::kSrcOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE }, 8220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber { SkXfermode::kDstOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, 8320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber { SkXfermode::kSrcIn_Mode, GL_ZERO, GL_SRC_ALPHA }, 8420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber { SkXfermode::kDstIn_Mode, GL_DST_ALPHA, GL_ZERO }, 8520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber { SkXfermode::kSrcOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, 8620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber { SkXfermode::kDstOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, 8789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kSrcATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, 8889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kDstATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, 8989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project { SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA } 9089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}; 9189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 9289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatic const GLenum gTextureUnits[] = { 9389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project GL_TEXTURE0, 9489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project GL_TEXTURE1, 9589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project GL_TEXTURE2 9689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}; 9789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 9889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 9989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// Constructors/destructor 10089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 10120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 10220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberOpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) { 10389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mShader = NULL; 10489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mColorFilter = NULL; 10520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mHasShadow = false; 10620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 10789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices)); 10889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 10989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mFirstSnapshot = new Snapshot; 11089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 11189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 11289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source ProjectOpenGLRenderer::~OpenGLRenderer() { 11389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project // The context has already been destroyed at this point, do not call 11489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project // GL APIs. All GL state should be kept in Caches.h 11589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 11610dbb8e97e7a81ca4867663b5517f048820b3094Marco Nelissen 11710dbb8e97e7a81ca4867663b5517f048820b3094Marco Nelissen/////////////////////////////////////////////////////////////////////////////// 1187ee8ac94bb1a724a481a7cddf10ce63d35df6296Marco Nelissen// Setup 11989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 12089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 12189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::setViewport(int width, int height) { 12289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glViewport(0, 0, width, height); 12389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1); 12489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 12589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mWidth = width; 12689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mHeight = height; 12789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 12889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mFirstSnapshot->height = height; 12989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mFirstSnapshot->viewport.set(0, 0, width, height); 13089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 13189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mDirtyClip = false; 13289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 13389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 13489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::prepare(bool opaque) { 135342e9cf388cceb807def720e40e8b0a217f4bcaaEric Laurent mSnapshot = new Snapshot(mFirstSnapshot, 13620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); 13720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber mSaveCount = 1; 13820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 13920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber glViewport(0, 0, mWidth, mHeight); 14020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber 14120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber glDisable(GL_DITHER); 1427d5b8a70c28c0d5746a600467b2887822dbff88eAndreas Huber 14389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (!opaque) { 1447d5b8a70c28c0d5746a600467b2887822dbff88eAndreas Huber glDisable(GL_SCISSOR_TEST); 14589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 14689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glClear(GL_COLOR_BUFFER_BIT); 14789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glEnable(GL_SCISSOR_TEST); 14889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } else { 14989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glEnable(GL_SCISSOR_TEST); 15089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glScissor(0, 0, mWidth, mHeight); 15189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project dirtyClip(); 15289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 15389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 15489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight); 15589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 15689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 15789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::finish() { 15889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#if DEBUG_OPENGL 15989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project GLenum status = GL_NO_ERROR; 16089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project while ((status = glGetError()) != GL_NO_ERROR) { 16189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project LOGD("GL error from OpenGLRenderer: 0x%x", status); 16289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 16389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#endif 16489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 16589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 16689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::acquireContext() { 16789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (mCaches.currentProgram) { 168a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania if (mCaches.currentProgram->isInUse()) { 16989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mCaches.currentProgram->remove(); 17089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mCaches.currentProgram = NULL; 17189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 17289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 17389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mCaches.unbindMeshBuffer(); 1747d5b8a70c28c0d5746a600467b2887822dbff88eAndreas Huber} 1757d5b8a70c28c0d5746a600467b2887822dbff88eAndreas Huber 17689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::releaseContext() { 17789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glViewport(0, 0, mSnapshot->viewport.getWidth(), mSnapshot->viewport.getHeight()); 17889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 17989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glEnable(GL_SCISSOR_TEST); 18089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project dirtyClip(); 18189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 18289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glDisable(GL_DITHER); 183dac6a31a33ba53fb93850670cdddd1e6515dadceGloria Wang 18489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glBindFramebuffer(GL_FRAMEBUFFER, 0); 18589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 18689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 1872db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber mCaches.blend = true; 1882db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber glEnable(GL_BLEND); 1892db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode); 1902db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber glBlendEquation(GL_FUNC_ADD); 19189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 19289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 19389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 19410dbb8e97e7a81ca4867663b5517f048820b3094Marco Nelissen// State management 195318ad9c1d9d6515026dfc2c021359d27decaa7a1Andreas Huber/////////////////////////////////////////////////////////////////////////////// 19689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 19789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectint OpenGLRenderer::getSaveCount() const { 19889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return mSaveCount; 19989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 20089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 201a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Cataniaint OpenGLRenderer::save(int flags) { 20289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return saveSnapshot(flags); 20389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 20489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 20589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::restore() { 20689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (mSaveCount > 1) { 20789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project restoreSnapshot(); 20889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 20989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 21089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 21189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid OpenGLRenderer::restoreToCount(int saveCount) { 21289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (saveCount < 1) saveCount = 1; 21389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 21489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project while (mSaveCount > saveCount) { 21589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project restoreSnapshot(); 21689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 21789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 21889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 21989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectint OpenGLRenderer::saveSnapshot(int flags) { 22089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mSnapshot = new Snapshot(mSnapshot, flags); 2211d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania return mSaveCount++; 222a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania} 2234829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania 2244829038419910aa6e75ce8992d45a223452d5c67Nicolas Cataniabool OpenGLRenderer::restoreSnapshot() { 2254829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 22689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 22789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; 2282db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber 2292db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber sp<Snapshot> current = mSnapshot; 2302db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber sp<Snapshot> previous = mSnapshot->previous; 2312db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber 2322db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber if (restoreOrtho) { 23389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project Rect& r = previous->viewport; 23489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project glViewport(r.left, r.top, r.right, r.bottom); 23589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mOrthoMatrix.load(current->orthoMatrix); 23689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 23789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 23889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mSaveCount--; 23989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mSnapshot = previous; 24089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 24189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (restoreLayer) { 24289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project composeLayer(current, previous); 24389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 24489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 24589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (restoreClip) { 24689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project dirtyClip(); 24789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 24889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 24989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return restoreClip; 25089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 25189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 252a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania/////////////////////////////////////////////////////////////////////////////// 2534829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania// Layers 2544829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania/////////////////////////////////////////////////////////////////////////////// 2554829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania 2564829038419910aa6e75ce8992d45a223452d5c67Nicolas Cataniaint OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 257a64c8c79af1a15911c55306d83a797fa50969f77niko SkPaint* p, int flags) { 2584829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania const GLuint previousFbo = mSnapshot->fbo; 2594829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania const int count = saveSnapshot(flags); 2604829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania 2614829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania int alpha = 255; 262a64c8c79af1a15911c55306d83a797fa50969f77niko SkXfermode::Mode mode; 263a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania 26489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (p) { 26589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project alpha = p->getAlpha(); 26689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (!mCaches.extensions.hasFramebufferFetch()) { 26789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 26889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (!isMode) { 26989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project // Assume SRC_OVER 27089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mode = SkXfermode::kSrcOver_Mode; 27189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 27289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } else { 2734829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania mode = getXfermode(p->getXfermode()); 274a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania } 275a64c8c79af1a15911c55306d83a797fa50969f77niko } else { 276a64c8c79af1a15911c55306d83a797fa50969f77niko mode = SkXfermode::kSrcOver_Mode; 2774829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania } 2784829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania 2794829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania if (!mSnapshot->previous->invisible) { 2804829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo); 2814829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania } 282a64c8c79af1a15911c55306d83a797fa50969f77niko 2834829038419910aa6e75ce8992d45a223452d5c67Nicolas Catania return count; 28489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 28589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 28689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectint OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 28789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project int alpha, int flags) { 28889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (alpha == 0xff) { 28989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return saveLayer(left, top, right, bottom, NULL, flags); 29089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } else { 29189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project SkPaint paint; 29289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project paint.setAlpha(alpha); 29389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return saveLayer(left, top, right, bottom, &paint, flags); 29489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 29589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 296dac6a31a33ba53fb93850670cdddd1e6515dadceGloria Wang 29789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project/** 298318ad9c1d9d6515026dfc2c021359d27decaa7a1Andreas Huber * Layers are viewed by Skia are slightly different than layers in image editing 29989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * programs (for instance.) When a layer is created, previously created layers 30089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * and the frame buffer still receive every drawing command. For instance, if a 30189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * layer is created and a shape intersecting the bounds of the layers and the 30289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * framebuffer is draw, the shape will be drawn on both (unless the layer was 30389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * created with the SkCanvas::kClipToLayer_SaveFlag flag.) 30489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 30589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * A way to implement layers is to create an FBO for each layer, backed by an RGBA 306 * texture. Unfortunately, this is inefficient as it requires every primitive to 307 * be drawn n + 1 times, where n is the number of active layers. In practice this 308 * means, for every primitive: 309 * - Switch active frame buffer 310 * - Change viewport, clip and projection matrix 311 * - Issue the drawing 312 * 313 * Switching rendering target n + 1 times per drawn primitive is extremely costly. 314 * To avoid this, layers are implemented in a different way here, at least in the 315 * general case. FBOs are used, as an optimization, when the "clip to layer" flag 316 * is set. When this flag is set we can redirect all drawing operations into a 317 * single FBO. 318 * 319 * This implementation relies on the frame buffer being at least RGBA 8888. When 320 * a layer is created, only a texture is created, not an FBO. The content of the 321 * frame buffer contained within the layer's bounds is copied into this texture 322 * using glCopyTexImage2D(). The layer's region is then cleared(1) in the frame 323 * buffer and drawing continues as normal. This technique therefore treats the 324 * frame buffer as a scratch buffer for the layers. 325 * 326 * To compose the layers back onto the frame buffer, each layer texture 327 * (containing the original frame buffer data) is drawn as a simple quad over 328 * the frame buffer. The trick is that the quad is set as the composition 329 * destination in the blending equation, and the frame buffer becomes the source 330 * of the composition. 331 * 332 * Drawing layers with an alpha value requires an extra step before composition. 333 * An empty quad is drawn over the layer's region in the frame buffer. This quad 334 * is drawn with the rgba color (0,0,0,alpha). The alpha value offered by the 335 * quad is used to multiply the colors in the frame buffer. This is achieved by 336 * changing the GL blend functions for the GL_FUNC_ADD blend equation to 337 * GL_ZERO, GL_SRC_ALPHA. 338 * 339 * Because glCopyTexImage2D() can be slow, an alternative implementation might 340 * be use to draw a single clipped layer. The implementation described above 341 * is correct in every case. 342 * 343 * (1) The frame buffer is actually not cleared right away. To allow the GPU 344 * to potentially optimize series of calls to glCopyTexImage2D, the frame 345 * buffer is left untouched until the first drawing operation. Only when 346 * something actually gets drawn are the layers regions cleared. 347 */ 348bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, 349 float right, float bottom, int alpha, SkXfermode::Mode mode, 350 int flags, GLuint previousFbo) { 351 LAYER_LOGD("Requesting layer %.2fx%.2f", right - left, bottom - top); 352 LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize()); 353 354 const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag; 355 356 // Window coordinates of the layer 357 Rect bounds(left, top, right, bottom); 358 if (fboLayer) { 359 // Clear the previous layer regions before we change the viewport 360 clearLayerRegions(); 361 } else { 362 mSnapshot->transform->mapRect(bounds); 363 364 // Layers only make sense if they are in the framebuffer's bounds 365 bounds.intersect(*snapshot->clipRect); 366 367 // We cannot work with sub-pixels in this case 368 bounds.snapToPixelBoundaries(); 369 370 // When the layer is not an FBO, we may use glCopyTexImage so we 371 // need to make sure the layer does not extend outside the bounds 372 // of the framebuffer 373 bounds.intersect(snapshot->previous->viewport); 374 } 375 376 if (bounds.isEmpty() || bounds.getWidth() > mCaches.maxTextureSize || 377 bounds.getHeight() > mCaches.maxTextureSize) { 378 snapshot->invisible = true; 379 } else { 380 // TODO: Should take the mode into account 381 snapshot->invisible = snapshot->previous->invisible || 382 (alpha <= ALPHA_THRESHOLD && fboLayer); 383 } 384 385 // Bail out if we won't draw in this snapshot 386 if (snapshot->invisible) { 387 return false; 388 } 389 390 glActiveTexture(GL_TEXTURE0); 391 392 Layer* layer = mCaches.layerCache.get(bounds.getWidth(), bounds.getHeight()); 393 if (!layer) { 394 return false; 395 } 396 397 layer->mode = mode; 398 layer->alpha = alpha; 399 layer->layer.set(bounds); 400 layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height), 401 bounds.getWidth() / float(layer->width), 0.0f); 402 403 // Save the layer in the snapshot 404 snapshot->flags |= Snapshot::kFlagIsLayer; 405 snapshot->layer = layer; 406 407 if (fboLayer) { 408 layer->fbo = mCaches.fboCache.get(); 409 410 snapshot->flags |= Snapshot::kFlagIsFboLayer; 411 snapshot->fbo = layer->fbo; 412 snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f); 413 snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); 414 snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight()); 415 snapshot->height = bounds.getHeight(); 416 snapshot->flags |= Snapshot::kFlagDirtyOrtho; 417 snapshot->orthoMatrix.load(mOrthoMatrix); 418 419 // Bind texture to FBO 420 glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); 421 glBindTexture(GL_TEXTURE_2D, layer->texture); 422 423 // Initialize the texture if needed 424 if (layer->empty) { 425 layer->empty = false; 426 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layer->width, layer->height, 0, 427 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 428 } 429 430 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 431 layer->texture, 0); 432 433#if DEBUG_LAYERS 434 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 435 if (status != GL_FRAMEBUFFER_COMPLETE) { 436 LOGE("Framebuffer incomplete (GL error code 0x%x)", status); 437 438 glBindFramebuffer(GL_FRAMEBUFFER, previousFbo); 439 glDeleteTextures(1, &layer->texture); 440 mCaches.fboCache.put(layer->fbo); 441 442 delete layer; 443 444 return false; 445 } 446#endif 447 448 // Clear the FBO 449 glScissor(0.0f, 0.0f, bounds.getWidth() + 1.0f, bounds.getHeight() + 1.0f); 450 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 451 glClear(GL_COLOR_BUFFER_BIT); 452 453 dirtyClip(); 454 455 // Change the ortho projection 456 glViewport(0, 0, bounds.getWidth(), bounds.getHeight()); 457 mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f); 458 } else { 459 // Copy the framebuffer into the layer 460 glBindTexture(GL_TEXTURE_2D, layer->texture); 461 462 if (layer->empty) { 463 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bounds.left, 464 snapshot->height - bounds.bottom, layer->width, layer->height, 0); 465 layer->empty = false; 466 } else { 467 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bounds.left, 468 snapshot->height - bounds.bottom, bounds.getWidth(), bounds.getHeight()); 469 } 470 471 // Enqueue the buffer coordinates to clear the corresponding region later 472 mLayers.push(new Rect(bounds)); 473 } 474 475 return true; 476} 477 478/** 479 * Read the documentation of createLayer() before doing anything in this method. 480 */ 481void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { 482 if (!current->layer) { 483 LOGE("Attempting to compose a layer that does not exist"); 484 return; 485 } 486 487 const bool fboLayer = current->flags & SkCanvas::kClipToLayer_SaveFlag; 488 489 if (fboLayer) { 490 // Unbind current FBO and restore previous one 491 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 492 } 493 494 // Restore the clip from the previous snapshot 495 Rect& clip(*previous->clipRect); 496 clip.snapToPixelBoundaries(); 497 glScissor(clip.left, previous->height - clip.bottom, clip.getWidth(), clip.getHeight()); 498 499 Layer* layer = current->layer; 500 const Rect& rect = layer->layer; 501 502 if (!fboLayer && layer->alpha < 255) { 503 drawColorRect(rect.left, rect.top, rect.right, rect.bottom, 504 layer->alpha << 24, SkXfermode::kDstIn_Mode, true); 505 } 506 507 const Rect& texCoords = layer->texCoords; 508 mCaches.unbindMeshBuffer(); 509 resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom); 510 511 glActiveTexture(gTextureUnits[0]); 512 if (fboLayer) { 513 drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, 514 layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], 515 &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount); 516 } else { 517 drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture, 518 1.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0], 519 &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, true, true); 520 } 521 522 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 523 524 if (fboLayer) { 525 // Detach the texture from the FBO 526 glBindFramebuffer(GL_FRAMEBUFFER, current->fbo); 527 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); 528 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 529 530 // Put the FBO name back in the cache, if it doesn't fit, it will be destroyed 531 mCaches.fboCache.put(current->fbo); 532 } 533 534 dirtyClip(); 535 536 // Failing to add the layer to the cache should happen only if the layer is too large 537 if (!mCaches.layerCache.put(layer)) { 538 LAYER_LOGD("Deleting layer"); 539 glDeleteTextures(1, &layer->texture); 540 delete layer; 541 } 542} 543 544void OpenGLRenderer::setupDraw() { 545 clearLayerRegions(); 546 if (mDirtyClip) { 547 setScissorFromClip(); 548 } 549} 550 551void OpenGLRenderer::clearLayerRegions() { 552 if (mLayers.size() == 0 || mSnapshot->invisible) return; 553 554 for (uint32_t i = 0; i < mLayers.size(); i++) { 555 Rect* bounds = mLayers.itemAt(i); 556 557 // Clear the framebuffer where the layer will draw 558 glScissor(bounds->left, mSnapshot->height - bounds->bottom, 559 bounds->getWidth(), bounds->getHeight()); 560 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 561 glClear(GL_COLOR_BUFFER_BIT); 562 563 delete bounds; 564 } 565 mLayers.clear(); 566 567 // Restore the clip 568 dirtyClip(); 569} 570 571/////////////////////////////////////////////////////////////////////////////// 572// Transforms 573/////////////////////////////////////////////////////////////////////////////// 574 575void OpenGLRenderer::translate(float dx, float dy) { 576 mSnapshot->transform->translate(dx, dy, 0.0f); 577} 578 579void OpenGLRenderer::rotate(float degrees) { 580 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f); 581} 582 583void OpenGLRenderer::scale(float sx, float sy) { 584 mSnapshot->transform->scale(sx, sy, 1.0f); 585} 586 587void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 588 mSnapshot->transform->load(*matrix); 589} 590 591const float* OpenGLRenderer::getMatrix() const { 592 if (mSnapshot->fbo != 0) { 593 return &mSnapshot->transform->data[0]; 594 } 595 return &mIdentity.data[0]; 596} 597 598void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 599 mSnapshot->transform->copyTo(*matrix); 600} 601 602void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 603 SkMatrix transform; 604 mSnapshot->transform->copyTo(transform); 605 transform.preConcat(*matrix); 606 mSnapshot->transform->load(transform); 607} 608 609/////////////////////////////////////////////////////////////////////////////// 610// Clipping 611/////////////////////////////////////////////////////////////////////////////// 612 613void OpenGLRenderer::setScissorFromClip() { 614 Rect clip(*mSnapshot->clipRect); 615 clip.snapToPixelBoundaries(); 616 glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); 617 mDirtyClip = false; 618} 619 620const Rect& OpenGLRenderer::getClipBounds() { 621 return mSnapshot->getLocalClip(); 622} 623 624bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 625 if (mSnapshot->invisible) { 626 return true; 627 } 628 629 Rect r(left, top, right, bottom); 630 mSnapshot->transform->mapRect(r); 631 r.snapToPixelBoundaries(); 632 633 Rect clipRect(*mSnapshot->clipRect); 634 clipRect.snapToPixelBoundaries(); 635 636 return !clipRect.intersects(r); 637} 638 639bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) { 640 bool clipped = mSnapshot->clip(left, top, right, bottom, op); 641 if (clipped) { 642 dirtyClip(); 643 } 644 return !mSnapshot->clipRect->isEmpty(); 645} 646 647/////////////////////////////////////////////////////////////////////////////// 648// Drawing 649/////////////////////////////////////////////////////////////////////////////// 650 651void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { 652 const float right = left + bitmap->width(); 653 const float bottom = top + bitmap->height(); 654 655 if (quickReject(left, top, right, bottom)) { 656 return; 657 } 658 659 glActiveTexture(GL_TEXTURE0); 660 Texture* texture = mCaches.textureCache.get(bitmap); 661 if (!texture) return; 662 const AutoTexture autoCleanup(texture); 663 664 drawTextureRect(left, top, right, bottom, texture, paint); 665} 666 667void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { 668 Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); 669 const mat4 transform(*matrix); 670 transform.mapRect(r); 671 672 if (quickReject(r.left, r.top, r.right, r.bottom)) { 673 return; 674 } 675 676 glActiveTexture(GL_TEXTURE0); 677 Texture* texture = mCaches.textureCache.get(bitmap); 678 if (!texture) return; 679 const AutoTexture autoCleanup(texture); 680 681 drawTextureRect(r.left, r.top, r.right, r.bottom, texture, paint); 682} 683 684void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, 685 float srcLeft, float srcTop, float srcRight, float srcBottom, 686 float dstLeft, float dstTop, float dstRight, float dstBottom, 687 SkPaint* paint) { 688 if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) { 689 return; 690 } 691 692 glActiveTexture(gTextureUnits[0]); 693 Texture* texture = mCaches.textureCache.get(bitmap); 694 if (!texture) return; 695 const AutoTexture autoCleanup(texture); 696 setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 697 698 const float width = texture->width; 699 const float height = texture->height; 700 701 const float u1 = srcLeft / width; 702 const float v1 = srcTop / height; 703 const float u2 = srcRight / width; 704 const float v2 = srcBottom / height; 705 706 mCaches.unbindMeshBuffer(); 707 resetDrawTextureTexCoords(u1, v1, u2, v2); 708 709 int alpha; 710 SkXfermode::Mode mode; 711 getAlphaAndMode(paint, &alpha, &mode); 712 713 drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom, texture->id, alpha / 255.0f, 714 mode, texture->blend, &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0], 715 GL_TRIANGLE_STRIP, gMeshCount); 716 717 resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); 718} 719 720void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, 721 const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, 722 float left, float top, float right, float bottom, SkPaint* paint) { 723 if (quickReject(left, top, right, bottom)) { 724 return; 725 } 726 727 glActiveTexture(gTextureUnits[0]); 728 Texture* texture = mCaches.textureCache.get(bitmap); 729 if (!texture) return; 730 const AutoTexture autoCleanup(texture); 731 setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 732 733 int alpha; 734 SkXfermode::Mode mode; 735 getAlphaAndMode(paint, &alpha, &mode); 736 737 const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(), 738 right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors); 739 740 if (mesh) { 741 // Specify right and bottom as +1.0f from left/top to prevent scaling since the 742 // patch mesh already defines the final size 743 drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha / 255.0f, 744 mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 745 GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer); 746 } 747} 748 749void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) { 750 if (mSnapshot->invisible) return; 751 752 int alpha; 753 SkXfermode::Mode mode; 754 getAlphaAndMode(paint, &alpha, &mode); 755 756 uint32_t color = paint->getColor(); 757 const GLfloat a = alpha / 255.0f; 758 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 759 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 760 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 761 762 const bool isAA = paint->isAntiAlias(); 763 if (isAA) { 764 GLuint textureUnit = 0; 765 glActiveTexture(gTextureUnits[textureUnit]); 766 setupTextureAlpha8(mCaches.line.getTexture(), 0, 0, textureUnit, 0.0f, 0.0f, r, g, b, a, 767 mode, false, true, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset, 768 mCaches.line.getMeshBuffer()); 769 } else { 770 setupColorRect(0.0f, 0.0f, 1.0f, 1.0f, r, g, b, a, mode, false); 771 } 772 773 const float strokeWidth = paint->getStrokeWidth(); 774 const GLsizei elementsCount = isAA ? mCaches.line.getElementsCount() : gMeshCount; 775 const GLenum drawMode = isAA ? GL_TRIANGLES : GL_TRIANGLE_STRIP; 776 777 for (int i = 0; i < count; i += 4) { 778 float tx = 0.0f; 779 float ty = 0.0f; 780 781 if (isAA) { 782 mCaches.line.update(points[i], points[i + 1], points[i + 2], points[i + 3], 783 strokeWidth, tx, ty); 784 } else { 785 ty = strokeWidth <= 1.0f ? 0.0f : -strokeWidth * 0.5f; 786 } 787 788 const float dx = points[i + 2] - points[i]; 789 const float dy = points[i + 3] - points[i + 1]; 790 const float mag = sqrtf(dx * dx + dy * dy); 791 const float angle = acos(dx / mag); 792 793 mModelView.loadTranslate(points[i], points[i + 1], 0.0f); 794 if (angle > MIN_ANGLE || angle < -MIN_ANGLE) { 795 mModelView.rotate(angle * RAD_TO_DEG, 0.0f, 0.0f, 1.0f); 796 } 797 mModelView.translate(tx, ty, 0.0f); 798 if (!isAA) { 799 float length = mCaches.line.getLength(points[i], points[i + 1], 800 points[i + 2], points[i + 3]); 801 mModelView.scale(length, strokeWidth, 1.0f); 802 } 803 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 804 805 if (mShader) { 806 mShader->updateTransforms(mCaches.currentProgram, mModelView, *mSnapshot); 807 } 808 809 glDrawArrays(drawMode, 0, elementsCount); 810 } 811 812 if (isAA) { 813 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 814 } 815} 816 817void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 818 Rect& clip(*mSnapshot->clipRect); 819 clip.snapToPixelBoundaries(); 820 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true); 821} 822 823void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) { 824 if (quickReject(left, top, right, bottom)) { 825 return; 826 } 827 828 SkXfermode::Mode mode; 829 if (!mCaches.extensions.hasFramebufferFetch()) { 830 const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); 831 if (!isMode) { 832 // Assume SRC_OVER 833 mode = SkXfermode::kSrcOver_Mode; 834 } 835 } else { 836 mode = getXfermode(p->getXfermode()); 837 } 838 839 // Skia draws using the color's alpha channel if < 255 840 // Otherwise, it uses the paint's alpha 841 int color = p->getColor(); 842 if (((color >> 24) & 0xff) == 255) { 843 color |= p->getAlpha() << 24; 844 } 845 846 drawColorRect(left, top, right, bottom, color, mode); 847} 848 849void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, 850 float x, float y, SkPaint* paint) { 851 if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) { 852 return; 853 } 854 if (mSnapshot->invisible) return; 855 856 paint->setAntiAlias(true); 857 858 float length = -1.0f; 859 switch (paint->getTextAlign()) { 860 case SkPaint::kCenter_Align: 861 length = paint->measureText(text, bytesCount); 862 x -= length / 2.0f; 863 break; 864 case SkPaint::kRight_Align: 865 length = paint->measureText(text, bytesCount); 866 x -= length; 867 break; 868 default: 869 break; 870 } 871 872 int alpha; 873 SkXfermode::Mode mode; 874 getAlphaAndMode(paint, &alpha, &mode); 875 876 uint32_t color = paint->getColor(); 877 const GLfloat a = alpha / 255.0f; 878 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 879 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 880 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 881 882 FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint); 883 fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), 884 paint->getTextSize()); 885 886 setupDraw(); 887 888 if (mHasShadow) { 889 glActiveTexture(gTextureUnits[0]); 890 mCaches.dropShadowCache.setFontRenderer(fontRenderer); 891 const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount, 892 count, mShadowRadius); 893 const AutoTexture autoCleanup(shadow); 894 895 setupShadow(shadow, x, y, mode, a); 896 897 // Draw the mesh 898 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 899 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 900 } 901 902 GLuint textureUnit = 0; 903 glActiveTexture(gTextureUnits[textureUnit]); 904 905 // Assume that the modelView matrix does not force scales, rotates, etc. 906 const bool linearFilter = mSnapshot->transform->changesBounds(); 907 setupTextureAlpha8(fontRenderer.getTexture(linearFilter), 0, 0, textureUnit, 908 x, y, r, g, b, a, mode, false, true, NULL, NULL); 909 910 const Rect& clip = mSnapshot->getLocalClip(); 911 912 mCaches.unbindMeshBuffer(); 913 fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y); 914 915 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 916 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 917 918 drawTextDecorations(text, bytesCount, length, x, y, paint); 919} 920 921void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { 922 if (mSnapshot->invisible) return; 923 924 GLuint textureUnit = 0; 925 glActiveTexture(gTextureUnits[textureUnit]); 926 927 const PathTexture* texture = mCaches.pathCache.get(path, paint); 928 if (!texture) return; 929 const AutoTexture autoCleanup(texture); 930 931 const float x = texture->left - texture->offset; 932 const float y = texture->top - texture->offset; 933 934 if (quickReject(x, y, x + texture->width, y + texture->height)) { 935 return; 936 } 937 938 int alpha; 939 SkXfermode::Mode mode; 940 getAlphaAndMode(paint, &alpha, &mode); 941 942 uint32_t color = paint->getColor(); 943 const GLfloat a = alpha / 255.0f; 944 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 945 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 946 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 947 948 setupTextureAlpha8(texture, textureUnit, x, y, r, g, b, a, mode, true, true); 949 950 setupDraw(); 951 952 // Draw the mesh 953 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 954 glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords")); 955} 956 957/////////////////////////////////////////////////////////////////////////////// 958// Shaders 959/////////////////////////////////////////////////////////////////////////////// 960 961void OpenGLRenderer::resetShader() { 962 mShader = NULL; 963} 964 965void OpenGLRenderer::setupShader(SkiaShader* shader) { 966 mShader = shader; 967 if (mShader) { 968 mShader->set(&mCaches.textureCache, &mCaches.gradientCache); 969 } 970} 971 972/////////////////////////////////////////////////////////////////////////////// 973// Color filters 974/////////////////////////////////////////////////////////////////////////////// 975 976void OpenGLRenderer::resetColorFilter() { 977 mColorFilter = NULL; 978} 979 980void OpenGLRenderer::setupColorFilter(SkiaColorFilter* filter) { 981 mColorFilter = filter; 982} 983 984/////////////////////////////////////////////////////////////////////////////// 985// Drop shadow 986/////////////////////////////////////////////////////////////////////////////// 987 988void OpenGLRenderer::resetShadow() { 989 mHasShadow = false; 990} 991 992void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) { 993 mHasShadow = true; 994 mShadowRadius = radius; 995 mShadowDx = dx; 996 mShadowDy = dy; 997 mShadowColor = color; 998} 999 1000/////////////////////////////////////////////////////////////////////////////// 1001// Drawing implementation 1002/////////////////////////////////////////////////////////////////////////////// 1003 1004void OpenGLRenderer::setupShadow(const ShadowTexture* texture, float x, float y, 1005 SkXfermode::Mode mode, float alpha) { 1006 const float sx = x - texture->left + mShadowDx; 1007 const float sy = y - texture->top + mShadowDy; 1008 1009 const int shadowAlpha = ((mShadowColor >> 24) & 0xFF); 1010 const GLfloat a = shadowAlpha < 255 ? shadowAlpha / 255.0f : alpha; 1011 const GLfloat r = a * ((mShadowColor >> 16) & 0xFF) / 255.0f; 1012 const GLfloat g = a * ((mShadowColor >> 8) & 0xFF) / 255.0f; 1013 const GLfloat b = a * ((mShadowColor ) & 0xFF) / 255.0f; 1014 1015 GLuint textureUnit = 0; 1016 setupTextureAlpha8(texture, textureUnit, sx, sy, r, g, b, a, mode, true, false); 1017} 1018 1019void OpenGLRenderer::setupTextureAlpha8(const Texture* texture, GLuint& textureUnit, 1020 float x, float y, float r, float g, float b, float a, SkXfermode::Mode mode, 1021 bool transforms, bool applyFilters) { 1022 setupTextureAlpha8(texture->id, texture->width, texture->height, textureUnit, 1023 x, y, r, g, b, a, mode, transforms, applyFilters, 1024 (GLvoid*) 0, (GLvoid*) gMeshTextureOffset); 1025} 1026 1027void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, 1028 GLuint& textureUnit, float x, float y, float r, float g, float b, float a, 1029 SkXfermode::Mode mode, bool transforms, bool applyFilters) { 1030 setupTextureAlpha8(texture, width, height, textureUnit, x, y, r, g, b, a, mode, 1031 transforms, applyFilters, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset); 1032} 1033 1034void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t height, 1035 GLuint& textureUnit, float x, float y, float r, float g, float b, float a, 1036 SkXfermode::Mode mode, bool transforms, bool applyFilters, 1037 GLvoid* vertices, GLvoid* texCoords, GLuint vbo) { 1038 // Describe the required shaders 1039 ProgramDescription description; 1040 description.hasTexture = true; 1041 description.hasAlpha8Texture = true; 1042 const bool setColor = description.setAlpha8Color(r, g, b, a); 1043 1044 if (applyFilters) { 1045 if (mShader) { 1046 mShader->describe(description, mCaches.extensions); 1047 } 1048 if (mColorFilter) { 1049 mColorFilter->describe(description, mCaches.extensions); 1050 } 1051 } 1052 1053 // Setup the blending mode 1054 chooseBlending(true, mode, description); 1055 1056 // Build and use the appropriate shader 1057 useProgram(mCaches.programCache.get(description)); 1058 1059 bindTexture(texture); 1060 glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit); 1061 1062 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 1063 glEnableVertexAttribArray(texCoordsSlot); 1064 1065 if (texCoords) { 1066 // Setup attributes 1067 if (!vertices) { 1068 mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); 1069 } else { 1070 mCaches.unbindMeshBuffer(); 1071 } 1072 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1073 gMeshStride, vertices); 1074 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); 1075 } 1076 1077 // Setup uniforms 1078 if (transforms) { 1079 mModelView.loadTranslate(x, y, 0.0f); 1080 mModelView.scale(width, height, 1.0f); 1081 } else { 1082 mModelView.loadIdentity(); 1083 } 1084 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1085 if (setColor) { 1086 mCaches.currentProgram->setColor(r, g, b, a); 1087 } 1088 1089 textureUnit++; 1090 if (applyFilters) { 1091 // Setup attributes and uniforms required by the shaders 1092 if (mShader) { 1093 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 1094 } 1095 if (mColorFilter) { 1096 mColorFilter->setupProgram(mCaches.currentProgram); 1097 } 1098 } 1099} 1100 1101// Same values used by Skia 1102#define kStdStrikeThru_Offset (-6.0f / 21.0f) 1103#define kStdUnderline_Offset (1.0f / 9.0f) 1104#define kStdUnderline_Thickness (1.0f / 18.0f) 1105 1106void OpenGLRenderer::drawTextDecorations(const char* text, int bytesCount, float length, 1107 float x, float y, SkPaint* paint) { 1108 // Handle underline and strike-through 1109 uint32_t flags = paint->getFlags(); 1110 if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 1111 float underlineWidth = length; 1112 // If length is > 0.0f, we already measured the text for the text alignment 1113 if (length <= 0.0f) { 1114 underlineWidth = paint->measureText(text, bytesCount); 1115 } 1116 1117 float offsetX = 0; 1118 switch (paint->getTextAlign()) { 1119 case SkPaint::kCenter_Align: 1120 offsetX = underlineWidth * 0.5f; 1121 break; 1122 case SkPaint::kRight_Align: 1123 offsetX = underlineWidth; 1124 break; 1125 default: 1126 break; 1127 } 1128 1129 if (underlineWidth > 0.0f) { 1130 const float textSize = paint->getTextSize(); 1131 const float strokeWidth = textSize * kStdUnderline_Thickness; 1132 1133 const float left = x - offsetX; 1134 float top = 0.0f; 1135 1136 const int pointsCount = 4 * (flags & SkPaint::kStrikeThruText_Flag ? 2 : 1); 1137 float points[pointsCount]; 1138 int currentPoint = 0; 1139 1140 if (flags & SkPaint::kUnderlineText_Flag) { 1141 top = y + textSize * kStdUnderline_Offset; 1142 points[currentPoint++] = left; 1143 points[currentPoint++] = top; 1144 points[currentPoint++] = left + underlineWidth; 1145 points[currentPoint++] = top; 1146 } 1147 1148 if (flags & SkPaint::kStrikeThruText_Flag) { 1149 top = y + textSize * kStdStrikeThru_Offset; 1150 points[currentPoint++] = left; 1151 points[currentPoint++] = top; 1152 points[currentPoint++] = left + underlineWidth; 1153 points[currentPoint++] = top; 1154 } 1155 1156 SkPaint linesPaint(*paint); 1157 linesPaint.setStrokeWidth(strokeWidth); 1158 1159 drawLines(&points[0], pointsCount, &linesPaint); 1160 } 1161 } 1162} 1163 1164void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, 1165 int color, SkXfermode::Mode mode, bool ignoreTransform) { 1166 setupDraw(); 1167 1168 // If a shader is set, preserve only the alpha 1169 if (mShader) { 1170 color |= 0x00ffffff; 1171 } 1172 1173 // Render using pre-multiplied alpha 1174 const int alpha = (color >> 24) & 0xFF; 1175 const GLfloat a = alpha / 255.0f; 1176 const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f; 1177 const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f; 1178 const GLfloat b = a * ((color ) & 0xFF) / 255.0f; 1179 1180 setupColorRect(left, top, right, bottom, r, g, b, a, mode, ignoreTransform); 1181 1182 // Draw the mesh 1183 glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); 1184} 1185 1186void OpenGLRenderer::setupColorRect(float left, float top, float right, float bottom, 1187 float r, float g, float b, float a, SkXfermode::Mode mode, bool ignoreTransform) { 1188 GLuint textureUnit = 0; 1189 1190 // Describe the required shaders 1191 ProgramDescription description; 1192 const bool setColor = description.setColor(r, g, b, a); 1193 1194 if (mShader) { 1195 mShader->describe(description, mCaches.extensions); 1196 } 1197 if (mColorFilter) { 1198 mColorFilter->describe(description, mCaches.extensions); 1199 } 1200 1201 // Setup the blending mode 1202 chooseBlending(a < 1.0f || (mShader && mShader->blend()), mode, description); 1203 1204 // Build and use the appropriate shader 1205 useProgram(mCaches.programCache.get(description)); 1206 1207 // Setup attributes 1208 mCaches.bindMeshBuffer(); 1209 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1210 gMeshStride, 0); 1211 1212 // Setup uniforms 1213 mModelView.loadTranslate(left, top, 0.0f); 1214 mModelView.scale(right - left, bottom - top, 1.0f); 1215 if (!ignoreTransform) { 1216 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1217 } else { 1218 mat4 identity; 1219 mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity); 1220 } 1221 mCaches.currentProgram->setColor(r, g, b, a); 1222 1223 // Setup attributes and uniforms required by the shaders 1224 if (mShader) { 1225 mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit); 1226 } 1227 if (mColorFilter) { 1228 mColorFilter->setupProgram(mCaches.currentProgram); 1229 } 1230} 1231 1232void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 1233 Texture* texture, SkPaint* paint) { 1234 int alpha; 1235 SkXfermode::Mode mode; 1236 getAlphaAndMode(paint, &alpha, &mode); 1237 1238 setTextureWrapModes(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); 1239 1240 drawTextureMesh(left, top, right, bottom, texture->id, alpha / 255.0f, mode, 1241 texture->blend, (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, 1242 GL_TRIANGLE_STRIP, gMeshCount); 1243} 1244 1245void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 1246 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend) { 1247 drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, 1248 (GLvoid*) NULL, (GLvoid*) gMeshTextureOffset, GL_TRIANGLE_STRIP, gMeshCount); 1249} 1250 1251void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, 1252 GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, 1253 GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount, 1254 bool swapSrcDst, bool ignoreTransform, GLuint vbo) { 1255 setupDraw(); 1256 1257 ProgramDescription description; 1258 description.hasTexture = true; 1259 const bool setColor = description.setColor(alpha, alpha, alpha, alpha); 1260 if (mColorFilter) { 1261 mColorFilter->describe(description, mCaches.extensions); 1262 } 1263 1264 mModelView.loadTranslate(left, top, 0.0f); 1265 mModelView.scale(right - left, bottom - top, 1.0f); 1266 1267 chooseBlending(blend || alpha < 1.0f, mode, description, swapSrcDst); 1268 1269 useProgram(mCaches.programCache.get(description)); 1270 if (!ignoreTransform) { 1271 mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform); 1272 } else { 1273 mat4 m; 1274 mCaches.currentProgram->set(mOrthoMatrix, mModelView, m); 1275 } 1276 1277 // Texture 1278 bindTexture(texture); 1279 glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0); 1280 1281 // Always premultiplied 1282 if (setColor) { 1283 mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha); 1284 } 1285 1286 // Mesh 1287 int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords"); 1288 glEnableVertexAttribArray(texCoordsSlot); 1289 1290 if (!vertices) { 1291 mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo); 1292 } else { 1293 mCaches.unbindMeshBuffer(); 1294 } 1295 glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE, 1296 gMeshStride, vertices); 1297 glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords); 1298 1299 // Color filter 1300 if (mColorFilter) { 1301 mColorFilter->setupProgram(mCaches.currentProgram); 1302 } 1303 1304 glDrawArrays(drawMode, 0, elementsCount); 1305 glDisableVertexAttribArray(texCoordsSlot); 1306} 1307 1308void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, 1309 ProgramDescription& description, bool swapSrcDst) { 1310 blend = blend || mode != SkXfermode::kSrcOver_Mode; 1311 if (blend) { 1312 if (mode < SkXfermode::kPlus_Mode) { 1313 if (!mCaches.blend) { 1314 glEnable(GL_BLEND); 1315 } 1316 1317 GLenum sourceMode = swapSrcDst ? gBlendsSwap[mode].src : gBlends[mode].src; 1318 GLenum destMode = swapSrcDst ? gBlendsSwap[mode].dst : gBlends[mode].dst; 1319 1320 if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) { 1321 glBlendFunc(sourceMode, destMode); 1322 mCaches.lastSrcMode = sourceMode; 1323 mCaches.lastDstMode = destMode; 1324 } 1325 } else { 1326 // These blend modes are not supported by OpenGL directly and have 1327 // to be implemented using shaders. Since the shader will perform 1328 // the blending, turn blending off here 1329 if (mCaches.extensions.hasFramebufferFetch()) { 1330 description.framebufferMode = mode; 1331 description.swapSrcDst = swapSrcDst; 1332 } 1333 1334 if (mCaches.blend) { 1335 glDisable(GL_BLEND); 1336 } 1337 blend = false; 1338 } 1339 } else if (mCaches.blend) { 1340 glDisable(GL_BLEND); 1341 } 1342 mCaches.blend = blend; 1343} 1344 1345bool OpenGLRenderer::useProgram(Program* program) { 1346 if (!program->isInUse()) { 1347 if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove(); 1348 program->use(); 1349 mCaches.currentProgram = program; 1350 return false; 1351 } 1352 return true; 1353} 1354 1355void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 1356 TextureVertex* v = &mMeshVertices[0]; 1357 TextureVertex::setUV(v++, u1, v1); 1358 TextureVertex::setUV(v++, u2, v1); 1359 TextureVertex::setUV(v++, u1, v2); 1360 TextureVertex::setUV(v++, u2, v2); 1361} 1362 1363void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { 1364 if (paint) { 1365 if (!mCaches.extensions.hasFramebufferFetch()) { 1366 const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode); 1367 if (!isMode) { 1368 // Assume SRC_OVER 1369 *mode = SkXfermode::kSrcOver_Mode; 1370 } 1371 } else { 1372 *mode = getXfermode(paint->getXfermode()); 1373 } 1374 1375 // Skia draws using the color's alpha channel if < 255 1376 // Otherwise, it uses the paint's alpha 1377 int color = paint->getColor(); 1378 *alpha = (color >> 24) & 0xFF; 1379 if (*alpha == 255) { 1380 *alpha = paint->getAlpha(); 1381 } 1382 } else { 1383 *mode = SkXfermode::kSrcOver_Mode; 1384 *alpha = 255; 1385 } 1386} 1387 1388SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) { 1389 if (mode == NULL) { 1390 return SkXfermode::kSrcOver_Mode; 1391 } 1392 return mode->fMode; 1393} 1394 1395void OpenGLRenderer::setTextureWrapModes(Texture* texture, GLenum wrapS, GLenum wrapT) { 1396 bool bound = false; 1397 if (wrapS != texture->wrapS) { 1398 glBindTexture(GL_TEXTURE_2D, texture->id); 1399 bound = true; 1400 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); 1401 texture->wrapS = wrapS; 1402 } 1403 if (wrapT != texture->wrapT) { 1404 if (!bound) { 1405 glBindTexture(GL_TEXTURE_2D, texture->id); 1406 } 1407 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); 1408 texture->wrapT = wrapT; 1409 } 1410} 1411 1412}; // namespace uirenderer 1413}; // namespace android 1414