| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 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 |  | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 17 | #define LOG_TAG "OpenGLRenderer" | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 18 |  | 
 | 19 | #include <stdlib.h> | 
 | 20 | #include <stdint.h> | 
 | 21 | #include <sys/types.h> | 
 | 22 |  | 
| Romain Guy | 5cbbce5 | 2010-06-27 22:59:20 -0700 | [diff] [blame] | 23 | #include <SkCanvas.h> | 
 | 24 |  | 
| Romain Guy | 121e2242 | 2010-07-01 18:26:52 -0700 | [diff] [blame] | 25 | #include <cutils/properties.h> | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 26 | #include <utils/Log.h> | 
 | 27 |  | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 28 | #include "OpenGLRenderer.h" | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 29 |  | 
 | 30 | namespace android { | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 31 | namespace uirenderer { | 
 | 32 |  | 
 | 33 | /////////////////////////////////////////////////////////////////////////////// | 
 | 34 | // Defines | 
 | 35 | /////////////////////////////////////////////////////////////////////////////// | 
 | 36 |  | 
| Romain Guy | 121e2242 | 2010-07-01 18:26:52 -0700 | [diff] [blame] | 37 | // These properties are defined in mega-bytes | 
 | 38 | #define PROPERTY_TEXTURE_CACHE_SIZE "ro.hwui.texture_cache_size" | 
 | 39 | #define PROPERTY_LAYER_CACHE_SIZE "ro.hwui.layer_cache_size" | 
 | 40 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 41 | #define DEFAULT_TEXTURE_CACHE_SIZE 20 | 
 | 42 | #define DEFAULT_LAYER_CACHE_SIZE 10 | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 43 | #define DEFAULT_PATCH_CACHE_SIZE 100 | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 44 |  | 
| Romain Guy | 121e2242 | 2010-07-01 18:26:52 -0700 | [diff] [blame] | 45 | // Converts a number of mega-bytes into bytes | 
 | 46 | #define MB(s) s * 1024 * 1024 | 
 | 47 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 48 | // Generates simple and textured vertices | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 49 | #define SV(x, y) { { x, y } } | 
 | 50 | #define FV(x, y, u, v) { { x, y }, { u, v } } | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 51 |  | 
 | 52 | /////////////////////////////////////////////////////////////////////////////// | 
 | 53 | // Globals | 
 | 54 | /////////////////////////////////////////////////////////////////////////////// | 
 | 55 |  | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 56 | static const SimpleVertex gDrawColorVertices[] = { | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 57 |         SV(0.0f, 0.0f), | 
 | 58 |         SV(1.0f, 0.0f), | 
 | 59 |         SV(0.0f, 1.0f), | 
 | 60 |         SV(1.0f, 1.0f) | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 61 | }; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 62 | static const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex); | 
 | 63 | static const GLsizei gDrawColorVertexCount = 4; | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 64 |  | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 65 | // This array is never used directly but used as a memcpy source in the | 
 | 66 | // OpenGLRenderer constructor | 
 | 67 | static const TextureVertex gDrawTextureVertices[] = { | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 68 |         FV(0.0f, 0.0f, 0.0f, 0.0f), | 
 | 69 |         FV(1.0f, 0.0f, 1.0f, 0.0f), | 
 | 70 |         FV(0.0f, 1.0f, 0.0f, 1.0f), | 
 | 71 |         FV(1.0f, 1.0f, 1.0f, 1.0f) | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 72 | }; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 73 | static const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex); | 
 | 74 | static const GLsizei gDrawTextureVertexCount = 4; | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 75 |  | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 76 | // In this array, the index of each Blender equals the value of the first | 
 | 77 | // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode] | 
 | 78 | static const Blender gBlends[] = { | 
 | 79 |         { SkXfermode::kClear_Mode,   GL_ZERO,                 GL_ZERO }, | 
 | 80 |         { SkXfermode::kSrc_Mode,     GL_ONE,                  GL_ZERO }, | 
 | 81 |         { SkXfermode::kDst_Mode,     GL_ZERO,                 GL_ONE }, | 
 | 82 |         { SkXfermode::kSrcOver_Mode, GL_ONE,                  GL_ONE_MINUS_SRC_ALPHA }, | 
 | 83 |         { SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_ONE }, | 
 | 84 |         { SkXfermode::kSrcIn_Mode,   GL_DST_ALPHA,            GL_ZERO }, | 
 | 85 |         { SkXfermode::kDstIn_Mode,   GL_ZERO,                 GL_SRC_ALPHA }, | 
 | 86 |         { SkXfermode::kSrcOut_Mode,  GL_ONE_MINUS_DST_ALPHA,  GL_ZERO }, | 
 | 87 |         { SkXfermode::kDstOut_Mode,  GL_ZERO,                 GL_ONE_MINUS_SRC_ALPHA }, | 
 | 88 |         { SkXfermode::kSrcATop_Mode, GL_DST_ALPHA,            GL_ONE_MINUS_SRC_ALPHA }, | 
 | 89 |         { SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA,  GL_SRC_ALPHA }, | 
 | 90 |         { SkXfermode::kXor_Mode,     GL_ONE_MINUS_DST_ALPHA,  GL_ONE_MINUS_SRC_ALPHA } | 
 | 91 | }; | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 92 |  | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 93 | /////////////////////////////////////////////////////////////////////////////// | 
 | 94 | // Constructors/destructor | 
 | 95 | /////////////////////////////////////////////////////////////////////////////// | 
 | 96 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 97 | OpenGLRenderer::OpenGLRenderer(): | 
 | 98 |         mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)), | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 99 |         mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)), | 
 | 100 |         mPatchCache(DEFAULT_PATCH_CACHE_SIZE) { | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 101 |     LOGD("Create OpenGLRenderer"); | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 102 |  | 
| Romain Guy | 121e2242 | 2010-07-01 18:26:52 -0700 | [diff] [blame] | 103 |     char property[PROPERTY_VALUE_MAX]; | 
 | 104 |     if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) { | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 105 |         LOGD("  Setting texture cache size to %sMB", property); | 
| Romain Guy | 121e2242 | 2010-07-01 18:26:52 -0700 | [diff] [blame] | 106 |         mTextureCache.setMaxSize(MB(atoi(property))); | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 107 |     } else { | 
 | 108 |         LOGD("  Using default texture cache size of %dMB", DEFAULT_TEXTURE_CACHE_SIZE); | 
 | 109 |     } | 
 | 110 |  | 
 | 111 |     if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) { | 
 | 112 |         LOGD("  Setting layer cache size to %sMB", property); | 
 | 113 |         mLayerCache.setMaxSize(MB(atoi(property))); | 
 | 114 |     } else { | 
 | 115 |         LOGD("  Using default layer cache size of %dMB", DEFAULT_LAYER_CACHE_SIZE); | 
| Romain Guy | 121e2242 | 2010-07-01 18:26:52 -0700 | [diff] [blame] | 116 |     } | 
 | 117 |  | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 118 |     mDrawColorShader = new DrawColorProgram; | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 119 |     mDrawTextureShader = new DrawTextureProgram; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 120 |  | 
 | 121 |     memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices)); | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 122 | } | 
 | 123 |  | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 124 | OpenGLRenderer::~OpenGLRenderer() { | 
 | 125 |     LOGD("Destroy OpenGLRenderer"); | 
| Romain Guy | ce0537b | 2010-06-29 21:05:21 -0700 | [diff] [blame] | 126 |  | 
 | 127 |     mTextureCache.clear(); | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 128 |     mLayerCache.clear(); | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 129 | } | 
 | 130 |  | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 131 | /////////////////////////////////////////////////////////////////////////////// | 
 | 132 | // Setup | 
 | 133 | /////////////////////////////////////////////////////////////////////////////// | 
 | 134 |  | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 135 | void OpenGLRenderer::setViewport(int width, int height) { | 
| Romain Guy | 08ae317 | 2010-06-21 19:35:50 -0700 | [diff] [blame] | 136 |     glViewport(0, 0, width, height); | 
 | 137 |  | 
 | 138 |     mat4 ortho; | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 139 |     ortho.loadOrtho(0, width, height, 0, -1, 1); | 
| Romain Guy | 08ae317 | 2010-06-21 19:35:50 -0700 | [diff] [blame] | 140 |     ortho.copyTo(mOrthoMatrix); | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 141 |  | 
 | 142 |     mWidth = width; | 
 | 143 |     mHeight = height; | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 144 |     mFirstSnapshot.height = height; | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 145 | } | 
 | 146 |  | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 147 | void OpenGLRenderer::prepare() { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 148 |     mSnapshot = &mFirstSnapshot; | 
 | 149 |     mSaveCount = 0; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 150 |  | 
| Romain Guy | 08ae317 | 2010-06-21 19:35:50 -0700 | [diff] [blame] | 151 |     glDisable(GL_SCISSOR_TEST); | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 152 |  | 
| Romain Guy | 08ae317 | 2010-06-21 19:35:50 -0700 | [diff] [blame] | 153 |     glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | 
 | 154 |     glClear(GL_COLOR_BUFFER_BIT); | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 155 |  | 
| Romain Guy | 08ae317 | 2010-06-21 19:35:50 -0700 | [diff] [blame] | 156 |     glEnable(GL_SCISSOR_TEST); | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 157 |     glScissor(0, 0, mWidth, mHeight); | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 158 |  | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 159 |     mSnapshot->clipRect.set(0.0f, 0.0f, mWidth, mHeight); | 
 | 160 | } | 
 | 161 |  | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 162 | /////////////////////////////////////////////////////////////////////////////// | 
 | 163 | // State management | 
 | 164 | /////////////////////////////////////////////////////////////////////////////// | 
 | 165 |  | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 166 | int OpenGLRenderer::getSaveCount() const { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 167 |     return mSaveCount; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 168 | } | 
 | 169 |  | 
 | 170 | int OpenGLRenderer::save(int flags) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 171 |     return saveSnapshot(); | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 172 | } | 
 | 173 |  | 
 | 174 | void OpenGLRenderer::restore() { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 175 |     if (mSaveCount == 0) return; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 176 |  | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 177 |     if (restoreSnapshot()) { | 
 | 178 |         setScissorFromClip(); | 
 | 179 |     } | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 180 | } | 
 | 181 |  | 
 | 182 | void OpenGLRenderer::restoreToCount(int saveCount) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 183 |     if (saveCount <= 0 || saveCount > mSaveCount) return; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 184 |  | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 185 |     bool restoreClip = false; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 186 |  | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 187 |     while (mSaveCount != saveCount - 1) { | 
 | 188 |         restoreClip |= restoreSnapshot(); | 
 | 189 |     } | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 190 |  | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 191 |     if (restoreClip) { | 
 | 192 |         setScissorFromClip(); | 
 | 193 |     } | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 194 | } | 
 | 195 |  | 
 | 196 | int OpenGLRenderer::saveSnapshot() { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 197 |     mSnapshot = new Snapshot(mSnapshot); | 
 | 198 |     return ++mSaveCount; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 199 | } | 
 | 200 |  | 
 | 201 | bool OpenGLRenderer::restoreSnapshot() { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 202 |     bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 203 |     bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 204 |     bool restoreOrtho = mSnapshot->flags & Snapshot::kFlagDirtyOrtho; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 205 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 206 |     sp<Snapshot> current = mSnapshot; | 
 | 207 |     sp<Snapshot> previous = mSnapshot->previous; | 
 | 208 |  | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 209 |     if (restoreOrtho) { | 
 | 210 |         memcpy(mOrthoMatrix, current->orthoMatrix, sizeof(mOrthoMatrix)); | 
 | 211 |     } | 
 | 212 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 213 |     if (restoreLayer) { | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 214 |         composeLayer(current, previous); | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 215 |     } | 
 | 216 |  | 
 | 217 |     mSnapshot = previous; | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 218 |     mSaveCount--; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 219 |  | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 220 |     return restoreClip; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 221 | } | 
 | 222 |  | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 223 | void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 224 |     if (!current->layer) { | 
 | 225 |         LOGE("Attempting to compose a layer that does not exist"); | 
 | 226 |         return; | 
 | 227 |     } | 
 | 228 |  | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 229 |     // Unbind current FBO and restore previous one | 
 | 230 |     // Most of the time, previous->fbo will be 0 to bind the default buffer | 
 | 231 |     glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); | 
 | 232 |  | 
 | 233 |     // Restore the clip from the previous snapshot | 
 | 234 |     const Rect& clip = previous->getMappedClip(); | 
 | 235 |     glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); | 
 | 236 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 237 |     Layer* layer = current->layer; | 
 | 238 |  | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 239 |     // Compute the correct texture coordinates for the FBO texture | 
 | 240 |     // The texture is currently as big as the window but drawn with | 
 | 241 |     // a quad of the appropriate size | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 242 |     const Rect& rect = layer->layer; | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 243 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 244 |     drawTextureRect(rect.left, rect.top, rect.right, rect.bottom, | 
 | 245 |             layer->texture, layer->alpha, layer->mode, layer->blend, true); | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 246 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 247 |     LayerSize size(rect.getWidth(), rect.getHeight()); | 
| Romain Guy | f18fd99 | 2010-07-08 11:45:51 -0700 | [diff] [blame] | 248 |     // Failing to add the layer to the cache should happen only if the | 
 | 249 |     // layer is too large | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 250 |     if (!mLayerCache.put(size, layer)) { | 
 | 251 |         LAYER_LOGD("Deleting layer"); | 
 | 252 |  | 
 | 253 |         glDeleteFramebuffers(1, &layer->fbo); | 
 | 254 |         glDeleteTextures(1, &layer->texture); | 
 | 255 |  | 
 | 256 |         delete layer; | 
 | 257 |     } | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 258 | } | 
 | 259 |  | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 260 | /////////////////////////////////////////////////////////////////////////////// | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 261 | // Layers | 
 | 262 | /////////////////////////////////////////////////////////////////////////////// | 
 | 263 |  | 
 | 264 | int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, | 
 | 265 |         const SkPaint* p, int flags) { | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 266 |     int count = saveSnapshot(); | 
 | 267 |  | 
 | 268 |     int alpha = 255; | 
 | 269 |     SkXfermode::Mode mode; | 
 | 270 |  | 
 | 271 |     if (p) { | 
 | 272 |         alpha = p->getAlpha(); | 
 | 273 |         const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); | 
 | 274 |         if (!isMode) { | 
 | 275 |             // Assume SRC_OVER | 
 | 276 |             mode = SkXfermode::kSrcOver_Mode; | 
 | 277 |         } | 
 | 278 |     } else { | 
 | 279 |         mode = SkXfermode::kSrcOver_Mode; | 
 | 280 |     } | 
 | 281 |  | 
 | 282 |     createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags); | 
 | 283 |  | 
 | 284 |     return count; | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 285 | } | 
 | 286 |  | 
 | 287 | int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, | 
 | 288 |         int alpha, int flags) { | 
 | 289 |     int count = saveSnapshot(); | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 290 |     createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags); | 
 | 291 |     return count; | 
 | 292 | } | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 293 |  | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 294 | bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top, | 
 | 295 |         float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) { | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 296 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 297 |     LAYER_LOGD("Requesting layer %dx%d", size.width, size.height); | 
 | 298 |     LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize()); | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 299 |  | 
| Romain Guy | f18fd99 | 2010-07-08 11:45:51 -0700 | [diff] [blame] | 300 |     GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0; | 
 | 301 |     LayerSize size(right - left, bottom - top); | 
 | 302 |  | 
| Romain Guy | f18fd99 | 2010-07-08 11:45:51 -0700 | [diff] [blame] | 303 |     Layer* layer = mLayerCache.get(size, previousFbo); | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 304 |     if (!layer) { | 
| Romain Guy | f18fd99 | 2010-07-08 11:45:51 -0700 | [diff] [blame] | 305 |         return false; | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 306 |     } | 
 | 307 |  | 
| Romain Guy | f18fd99 | 2010-07-08 11:45:51 -0700 | [diff] [blame] | 308 |     glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo); | 
 | 309 |  | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 310 |     // Clear the FBO | 
 | 311 |     glDisable(GL_SCISSOR_TEST); | 
 | 312 |     glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | 
 | 313 |     glClear(GL_COLOR_BUFFER_BIT); | 
 | 314 |     glEnable(GL_SCISSOR_TEST); | 
 | 315 |  | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 316 |     // Save the layer in the snapshot | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 317 |     snapshot->flags |= Snapshot::kFlagIsLayer; | 
| Romain Guy | dda57020 | 2010-07-06 11:39:32 -0700 | [diff] [blame] | 318 |     layer->mode = mode; | 
 | 319 |     layer->alpha = alpha / 255.0f; | 
 | 320 |     layer->layer.set(left, top, right, bottom); | 
 | 321 |  | 
 | 322 |     snapshot->layer = layer; | 
 | 323 |     snapshot->fbo = layer->fbo; | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 324 |  | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 325 |     // Creates a new snapshot to draw into the FBO | 
 | 326 |     saveSnapshot(); | 
 | 327 |     // TODO: This doesn't preserve other transformations (check Skia first) | 
 | 328 |     mSnapshot->transform.loadTranslate(-left, -top, 0.0f); | 
 | 329 |     mSnapshot->clipRect.set(left, top, right, bottom); | 
 | 330 |     mSnapshot->height = bottom - top; | 
 | 331 |     setScissorFromClip(); | 
 | 332 |  | 
 | 333 |     mSnapshot->flags = Snapshot::kFlagDirtyTransform | Snapshot::kFlagDirtyOrtho | | 
 | 334 |             Snapshot::kFlagClipSet; | 
 | 335 |     memcpy(mSnapshot->orthoMatrix, mOrthoMatrix, sizeof(mOrthoMatrix)); | 
 | 336 |  | 
 | 337 |     // Change the ortho projection | 
 | 338 |     mat4 ortho; | 
 | 339 |     ortho.loadOrtho(0.0f, right - left, bottom - top, 0.0f, 0.0f, 1.0f); | 
 | 340 |     ortho.copyTo(mOrthoMatrix); | 
 | 341 |  | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 342 |     return true; | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 343 | } | 
 | 344 |  | 
 | 345 | /////////////////////////////////////////////////////////////////////////////// | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 346 | // Transforms | 
 | 347 | /////////////////////////////////////////////////////////////////////////////// | 
 | 348 |  | 
 | 349 | void OpenGLRenderer::translate(float dx, float dy) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 350 |     mSnapshot->transform.translate(dx, dy, 0.0f); | 
 | 351 |     mSnapshot->flags |= Snapshot::kFlagDirtyTransform; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 352 | } | 
 | 353 |  | 
 | 354 | void OpenGLRenderer::rotate(float degrees) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 355 |     mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f); | 
 | 356 |     mSnapshot->flags |= Snapshot::kFlagDirtyTransform; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 357 | } | 
 | 358 |  | 
 | 359 | void OpenGLRenderer::scale(float sx, float sy) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 360 |     mSnapshot->transform.scale(sx, sy, 1.0f); | 
 | 361 |     mSnapshot->flags |= Snapshot::kFlagDirtyTransform; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 362 | } | 
 | 363 |  | 
 | 364 | void OpenGLRenderer::setMatrix(SkMatrix* matrix) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 365 |     mSnapshot->transform.load(*matrix); | 
 | 366 |     mSnapshot->flags |= Snapshot::kFlagDirtyTransform; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 367 | } | 
 | 368 |  | 
 | 369 | void OpenGLRenderer::getMatrix(SkMatrix* matrix) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 370 |     mSnapshot->transform.copyTo(*matrix); | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 371 | } | 
 | 372 |  | 
 | 373 | void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 374 |     mat4 m(*matrix); | 
 | 375 |     mSnapshot->transform.multiply(m); | 
 | 376 |     mSnapshot->flags |= Snapshot::kFlagDirtyTransform; | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 377 | } | 
 | 378 |  | 
 | 379 | /////////////////////////////////////////////////////////////////////////////// | 
 | 380 | // Clipping | 
 | 381 | /////////////////////////////////////////////////////////////////////////////// | 
 | 382 |  | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 383 | void OpenGLRenderer::setScissorFromClip() { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 384 |     const Rect& clip = mSnapshot->getMappedClip(); | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 385 |     glScissor(clip.left, mSnapshot->height - clip.bottom, clip.getWidth(), clip.getHeight()); | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 386 | } | 
 | 387 |  | 
 | 388 | const Rect& OpenGLRenderer::getClipBounds() { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 389 |     return mSnapshot->clipRect; | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 390 | } | 
 | 391 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 392 | bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { | 
 | 393 |     /* | 
 | 394 |      * The documentation of quickReject() indicates that the specified rect | 
 | 395 |      * is transformed before being compared to the clip rect. However, the | 
 | 396 |      * clip rect is not stored transformed in the snapshot and can thus be | 
 | 397 |      * compared directly | 
 | 398 |      * | 
 | 399 |      * The following code can be used instead to performed a mapped comparison: | 
 | 400 |      * | 
 | 401 |      *     mSnapshot->transform.mapRect(r); | 
 | 402 |      *     const Rect& clip = mSnapshot->getMappedClip(); | 
 | 403 |      *     return !clip.intersects(r); | 
 | 404 |      */ | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 405 |     Rect r(left, top, right, bottom); | 
 | 406 |     return !mSnapshot->clipRect.intersects(r); | 
 | 407 | } | 
 | 408 |  | 
| Romain Guy | bb9524b | 2010-06-22 18:56:38 -0700 | [diff] [blame] | 409 | bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) { | 
| Romain Guy | 7ae7ac4 | 2010-06-25 13:46:18 -0700 | [diff] [blame] | 410 |     bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom); | 
 | 411 |     if (clipped) { | 
 | 412 |         mSnapshot->flags |= Snapshot::kFlagClipSet; | 
 | 413 |         setScissorFromClip(); | 
 | 414 |     } | 
 | 415 |     return clipped; | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 416 | } | 
 | 417 |  | 
| Romain Guy | f6a11b8 | 2010-06-23 17:47:49 -0700 | [diff] [blame] | 418 | /////////////////////////////////////////////////////////////////////////////// | 
 | 419 | // Drawing | 
 | 420 | /////////////////////////////////////////////////////////////////////////////// | 
 | 421 |  | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 422 | void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) { | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 423 |     const Texture* texture = mTextureCache.get(bitmap); | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 424 |  | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 425 |     int alpha; | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 426 |     SkXfermode::Mode mode; | 
 | 427 |     getAlphaAndMode(paint, &alpha, &mode); | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 428 |  | 
 | 429 |     drawTextureRect(left, top, left + texture->width, top + texture->height, texture->id, | 
 | 430 |             alpha / 255.0f, mode, texture->blend, true); | 
| Romain Guy | ce0537b | 2010-06-29 21:05:21 -0700 | [diff] [blame] | 431 | } | 
 | 432 |  | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 433 | void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) { | 
 | 434 |     Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); | 
 | 435 |     const mat4 transform(*matrix); | 
 | 436 |     transform.mapRect(r); | 
 | 437 |  | 
 | 438 |     const Texture* texture = mTextureCache.get(bitmap); | 
 | 439 |  | 
 | 440 |     int alpha; | 
 | 441 |     SkXfermode::Mode mode; | 
 | 442 |     getAlphaAndMode(paint, &alpha, &mode); | 
 | 443 |  | 
 | 444 |     drawTextureRect(r.left, r.top, r.right, r.bottom, texture->id, | 
 | 445 |             alpha / 255.0f, mode, texture->blend, true); | 
 | 446 | } | 
 | 447 |  | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 448 | void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, | 
 | 449 |          float srcLeft, float srcTop, float srcRight, float srcBottom, | 
 | 450 |          float dstLeft, float dstTop, float dstRight, float dstBottom, | 
| Romain Guy | f86ef57 | 2010-07-01 11:05:42 -0700 | [diff] [blame] | 451 |          const SkPaint* paint) { | 
 | 452 |     const Texture* texture = mTextureCache.get(bitmap); | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 453 |  | 
 | 454 |     int alpha; | 
 | 455 |     SkXfermode::Mode mode; | 
 | 456 |     getAlphaAndMode(paint, &alpha, &mode); | 
 | 457 |  | 
 | 458 |     const float width = texture->width; | 
 | 459 |     const float height = texture->height; | 
 | 460 |  | 
 | 461 |     const float u1 = srcLeft / width; | 
 | 462 |     const float v1 = srcTop / height; | 
 | 463 |     const float u2 = srcRight / width; | 
 | 464 |     const float v2 = srcBottom / height; | 
 | 465 |  | 
 | 466 |     resetDrawTextureTexCoords(u1, v1, u2, v2); | 
 | 467 |  | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 468 |     drawTextureRect(dstLeft, dstTop, dstRight, dstBottom, texture->id, | 
 | 469 |             alpha / 255.0f, mode, texture->blend, true); | 
 | 470 |  | 
 | 471 |     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f); | 
 | 472 | } | 
 | 473 |  | 
| Romain Guy | deba785 | 2010-07-07 17:54:48 -0700 | [diff] [blame] | 474 | void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, | 
 | 475 |         float left, float top, float right, float bottom, const SkPaint* paint) { | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 476 |     const Texture* texture = mTextureCache.get(bitmap); | 
 | 477 |  | 
 | 478 |     int alpha; | 
 | 479 |     SkXfermode::Mode mode; | 
 | 480 |     getAlphaAndMode(paint, &alpha, &mode); | 
 | 481 |  | 
 | 482 |     const uint32_t width = patch->numXDivs; | 
 | 483 |     const uint32_t height = patch->numYDivs; | 
 | 484 |  | 
 | 485 |     Patch* mesh = mPatchCache.get(patch); | 
 | 486 |  | 
 | 487 |     const uint32_t xStretchCount = (width + 1) >> 1; | 
 | 488 |     const uint32_t yStretchCount = (height + 1) >> 1; | 
 | 489 |  | 
 | 490 |     const int32_t* xDivs = &patch->xDivs[0]; | 
 | 491 |     const int32_t* yDivs = &patch->yDivs[0]; | 
 | 492 |  | 
 | 493 |     float xStretch = 0; | 
 | 494 |     float yStretch = 0; | 
 | 495 |     float xStretchTex = 0; | 
 | 496 |     float yStretchTex = 0; | 
 | 497 |  | 
 | 498 |     const float meshWidth = right - left; | 
 | 499 |  | 
 | 500 |     const float bitmapWidth = float(bitmap->width()); | 
 | 501 |     const float bitmapHeight = float(bitmap->height()); | 
 | 502 |  | 
 | 503 |     if (xStretchCount > 0) { | 
 | 504 |         uint32_t stretchSize = 0; | 
 | 505 |         for (uint32_t i = 1; i < width; i += 2) { | 
 | 506 |             stretchSize += xDivs[i] - xDivs[i - 1]; | 
 | 507 |         } | 
 | 508 |         xStretchTex = (stretchSize / bitmapWidth) / xStretchCount; | 
 | 509 |         const float fixed = bitmapWidth - stretchSize; | 
 | 510 |         xStretch = (right - left - fixed) / xStretchCount; | 
 | 511 |     } | 
 | 512 |  | 
 | 513 |     if (yStretchCount > 0) { | 
 | 514 |         uint32_t stretchSize = 0; | 
 | 515 |         for (uint32_t i = 1; i < height; i += 2) { | 
 | 516 |             stretchSize += yDivs[i] - yDivs[i - 1]; | 
 | 517 |         } | 
 | 518 |         yStretchTex = (stretchSize / bitmapHeight) / yStretchCount; | 
 | 519 |         const float fixed = bitmapHeight - stretchSize; | 
 | 520 |         yStretch = (bottom - top - fixed) / yStretchCount; | 
 | 521 |     } | 
 | 522 |  | 
 | 523 |     float vy = 0.0f; | 
 | 524 |     float ty = 0.0f; | 
 | 525 |     TextureVertex* vertex = mesh->vertices; | 
 | 526 |  | 
 | 527 |     generateVertices(vertex, 0.0f, 0.0f, xDivs, width, xStretch, xStretchTex, | 
 | 528 |             meshWidth, bitmapWidth); | 
 | 529 |     vertex += width + 2; | 
 | 530 |  | 
 | 531 |     for (uint32_t y = 0; y < height; y++) { | 
 | 532 |         if (y & 1) { | 
 | 533 |             vy += yStretch; | 
 | 534 |             ty += yStretchTex; | 
 | 535 |         } else { | 
 | 536 |             const float step = float(yDivs[y]); | 
 | 537 |             vy += step; | 
 | 538 |             ty += step / bitmapHeight; | 
 | 539 |         } | 
 | 540 |         generateVertices(vertex, vy, ty, xDivs, width, xStretch, xStretchTex, | 
 | 541 |                 meshWidth, bitmapWidth); | 
 | 542 |         vertex += width + 2; | 
 | 543 |     } | 
 | 544 |  | 
 | 545 |     generateVertices(vertex, bottom - top, 1.0f, xDivs, width, xStretch, xStretchTex, | 
 | 546 |             meshWidth, bitmapWidth); | 
 | 547 |  | 
 | 548 |     // Specify right and bottom as +1.0f from left/top to prevent scaling since the | 
 | 549 |     // patch mesh already defines the final size | 
 | 550 |     drawTextureMesh(left, top, left + 1.0f, top + 1.0f, texture->id, alpha, mode, texture->blend, | 
 | 551 |             true, &mesh->vertices[0].position[0], &mesh->vertices[0].texture[0], mesh->indices, | 
 | 552 |             mesh->indicesCount); | 
 | 553 | } | 
 | 554 |  | 
 | 555 | void OpenGLRenderer::generateVertices(TextureVertex* vertex, float y, float v, | 
 | 556 |         const int32_t xDivs[], uint32_t xCount, float xStretch, float xStretchTex, | 
 | 557 |         float width, float widthTex) { | 
 | 558 |     float vx = 0.0f; | 
 | 559 |     float tx = 0.0f; | 
 | 560 |  | 
 | 561 |     TextureVertex::set(vertex, vx, y, tx, v); | 
 | 562 |     vertex++; | 
 | 563 |  | 
 | 564 |     for (uint32_t x = 0; x < xCount; x++) { | 
 | 565 |         if (x & 1) { | 
 | 566 |             vx += xStretch; | 
 | 567 |             tx += xStretchTex; | 
 | 568 |         } else { | 
 | 569 |             const float step = float(xDivs[x]); | 
 | 570 |             vx += step; | 
 | 571 |             tx += step / widthTex; | 
 | 572 |         } | 
 | 573 |  | 
 | 574 |         TextureVertex::set(vertex, vx, y, tx, v); | 
 | 575 |         vertex++; | 
 | 576 |     } | 
 | 577 |  | 
 | 578 |     TextureVertex::set(vertex, width, y, 1.0f, v); | 
 | 579 |     vertex++; | 
| Romain Guy | deba785 | 2010-07-07 17:54:48 -0700 | [diff] [blame] | 580 | } | 
 | 581 |  | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 582 | void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 583 |     const Rect& clip = mSnapshot->clipRect; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 584 |     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode); | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 585 | } | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 586 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 587 | void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 588 |     SkXfermode::Mode mode; | 
 | 589 |  | 
 | 590 |     const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode); | 
 | 591 |     if (!isMode) { | 
 | 592 |         // Assume SRC_OVER | 
 | 593 |         mode = SkXfermode::kSrcOver_Mode; | 
 | 594 |     } | 
 | 595 |  | 
 | 596 |     // Skia draws using the color's alpha channel if < 255 | 
 | 597 |     // Otherwise, it uses the paint's alpha | 
 | 598 |     int color = p->getColor(); | 
 | 599 |     if (((color >> 24) & 0xFF) == 255) { | 
 | 600 |         color |= p->getAlpha() << 24; | 
 | 601 |     } | 
 | 602 |  | 
 | 603 |     drawColorRect(left, top, right, bottom, color, mode); | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 604 | } | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 605 |  | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 606 | void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, | 
 | 607 |         int color, SkXfermode::Mode mode) { | 
 | 608 |     const int alpha = (color >> 24) & 0xFF; | 
 | 609 |     const bool blend = alpha < 255 || mode != SkXfermode::kSrcOver_Mode; | 
 | 610 |  | 
 | 611 |     const GLfloat a = alpha                  / 255.0f; | 
 | 612 |     const GLfloat r = ((color >> 16) & 0xFF) / 255.0f; | 
 | 613 |     const GLfloat g = ((color >>  8) & 0xFF) / 255.0f; | 
 | 614 |     const GLfloat b = ((color      ) & 0xFF) / 255.0f; | 
 | 615 |  | 
 | 616 |     if (blend) { | 
 | 617 |         glEnable(GL_BLEND); | 
 | 618 |         glBlendFunc(gBlends[mode].src, gBlends[mode].dst); | 
 | 619 |     } | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 620 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 621 |     mModelView.loadTranslate(left, top, 0.0f); | 
 | 622 |     mModelView.scale(right - left, bottom - top, 1.0f); | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 623 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 624 |     mDrawColorShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 625 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 626 |     const GLvoid* p = &gDrawColorVertices[0].position[0]; | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 627 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 628 |     glEnableVertexAttribArray(mDrawColorShader->position); | 
 | 629 |     glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, | 
 | 630 |             gDrawColorVertexStride, p); | 
 | 631 |     glVertexAttrib4f(mDrawColorShader->color, r, g, b, a); | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 632 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 633 |     glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount); | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 634 |  | 
| Romain Guy | c7d5349 | 2010-06-25 13:41:57 -0700 | [diff] [blame] | 635 |     glDisableVertexAttribArray(mDrawColorShader->position); | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 636 |  | 
 | 637 |     if (blend) { | 
 | 638 |         glDisable(GL_BLEND); | 
 | 639 |     } | 
| Romain Guy | 85bf02f | 2010-06-22 13:11:24 -0700 | [diff] [blame] | 640 | } | 
 | 641 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 642 | void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 643 |         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied) { | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 644 |     drawTextureMesh(left, top, right, bottom, texture, alpha, mode, blend, isPremultiplied, | 
 | 645 |             &mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL); | 
 | 646 | } | 
 | 647 |  | 
 | 648 | void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom, | 
 | 649 |         GLuint texture, float alpha, SkXfermode::Mode mode, bool blend, bool isPremultiplied, | 
 | 650 |         GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount) { | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 651 |     mModelView.loadTranslate(left, top, 0.0f); | 
 | 652 |     mModelView.scale(right - left, bottom - top, 1.0f); | 
 | 653 |  | 
 | 654 |     mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); | 
 | 655 |  | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 656 |     if (blend || alpha < 1.0f || mode != SkXfermode::kSrcOver_Mode) { | 
 | 657 |         GLenum sourceMode = gBlends[mode].src; | 
 | 658 |         if (!isPremultiplied && sourceMode == GL_ONE) { | 
 | 659 |             sourceMode = GL_SRC_ALPHA; | 
 | 660 |         } | 
 | 661 |  | 
 | 662 |         glEnable(GL_BLEND); | 
 | 663 |         glBlendFunc(sourceMode, gBlends[mode].dst); | 
| Romain Guy | d55a861 | 2010-06-28 17:42:46 -0700 | [diff] [blame] | 664 |     } | 
 | 665 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 666 |     glBindTexture(GL_TEXTURE_2D, texture); | 
 | 667 |  | 
| Romain Guy | c1396e9 | 2010-06-30 17:56:19 -0700 | [diff] [blame] | 668 |     // TODO handle tiling and filtering here | 
 | 669 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 670 |     glActiveTexture(GL_TEXTURE0); | 
 | 671 |     glUniform1i(mDrawTextureShader->sampler, 0); | 
 | 672 |  | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 673 |     glEnableVertexAttribArray(mDrawTextureShader->position); | 
 | 674 |     glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE, | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 675 |             gDrawTextureVertexStride, vertices); | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 676 |  | 
 | 677 |     glEnableVertexAttribArray(mDrawTextureShader->texCoords); | 
 | 678 |     glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE, | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 679 |             gDrawTextureVertexStride, texCoords); | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 680 |  | 
 | 681 |     glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha); | 
 | 682 |  | 
| Romain Guy | f7f9355 | 2010-07-08 19:17:03 -0700 | [diff] [blame^] | 683 |     if (!indices) { | 
 | 684 |         glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount); | 
 | 685 |     } else { | 
 | 686 |         glDrawElements(GL_TRIANGLES, elementsCount, GL_UNSIGNED_SHORT, indices); | 
 | 687 |     } | 
| Romain Guy | bd6b79b | 2010-06-26 00:13:53 -0700 | [diff] [blame] | 688 |  | 
 | 689 |     glDisableVertexAttribArray(mDrawTextureShader->position); | 
 | 690 |     glDisableVertexAttribArray(mDrawTextureShader->texCoords); | 
 | 691 |  | 
 | 692 |     glBindTexture(GL_TEXTURE_2D, 0); | 
 | 693 |     glDisable(GL_BLEND); | 
 | 694 | } | 
 | 695 |  | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 696 | void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { | 
 | 697 |     mDrawTextureVertices[0].texture[0] = u1; | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 698 |     mDrawTextureVertices[0].texture[1] = v1; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 699 |     mDrawTextureVertices[1].texture[0] = u2; | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 700 |     mDrawTextureVertices[1].texture[1] = v1; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 701 |     mDrawTextureVertices[2].texture[0] = u1; | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 702 |     mDrawTextureVertices[2].texture[1] = v2; | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 703 |     mDrawTextureVertices[3].texture[0] = u2; | 
| Romain Guy | 8ba548f | 2010-06-30 19:21:21 -0700 | [diff] [blame] | 704 |     mDrawTextureVertices[3].texture[1] = v2; | 
 | 705 | } | 
 | 706 |  | 
 | 707 | void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) { | 
 | 708 |     if (paint) { | 
 | 709 |         const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode); | 
 | 710 |         if (!isMode) { | 
 | 711 |             // Assume SRC_OVER | 
 | 712 |             *mode = SkXfermode::kSrcOver_Mode; | 
 | 713 |         } | 
 | 714 |  | 
 | 715 |         // Skia draws using the color's alpha channel if < 255 | 
 | 716 |         // Otherwise, it uses the paint's alpha | 
 | 717 |         int color = paint->getColor(); | 
 | 718 |         *alpha = (color >> 24) & 0xFF; | 
 | 719 |         if (*alpha == 255) { | 
 | 720 |             *alpha = paint->getAlpha(); | 
 | 721 |         } | 
 | 722 |     } else { | 
 | 723 |         *mode = SkXfermode::kSrcOver_Mode; | 
 | 724 |         *alpha = 255; | 
 | 725 |     } | 
| Romain Guy | 026c5e16 | 2010-06-28 17:12:22 -0700 | [diff] [blame] | 726 | } | 
 | 727 |  | 
| Romain Guy | 9d5316e | 2010-06-24 19:30:36 -0700 | [diff] [blame] | 728 | }; // namespace uirenderer | 
| Romain Guy | e4d0112 | 2010-06-16 18:44:05 -0700 | [diff] [blame] | 729 | }; // namespace android |