OpenGLRenderer.cpp revision 5cbbce535744b89df5ecea95de21ee3733298260
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "OpenGLRenderer" 18 19#include <stdlib.h> 20#include <stdint.h> 21#include <sys/types.h> 22 23#include <SkCanvas.h> 24 25#include <utils/Log.h> 26 27#include "OpenGLRenderer.h" 28 29namespace android { 30namespace uirenderer { 31 32/////////////////////////////////////////////////////////////////////////////// 33// Defines 34/////////////////////////////////////////////////////////////////////////////// 35 36#define SV(x, y) { { x, y } } 37#define FV(x, y, u, v) { { x, y }, { u, v } } 38 39/////////////////////////////////////////////////////////////////////////////// 40// Globals 41/////////////////////////////////////////////////////////////////////////////// 42 43const SimpleVertex gDrawColorVertices[] = { 44 SV(0.0f, 0.0f), 45 SV(1.0f, 0.0f), 46 SV(0.0f, 1.0f), 47 SV(1.0f, 1.0f) 48}; 49const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex); 50const GLsizei gDrawColorVertexCount = 4; 51 52TextureVertex gDrawTextureVertices[] = { 53 FV(0.0f, 0.0f, 0.0f, 1.0f), 54 FV(1.0f, 0.0f, 1.0f, 1.0f), 55 FV(0.0f, 1.0f, 0.0f, 0.0f), 56 FV(1.0f, 1.0f, 1.0f, 0.0f) 57}; 58const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex); 59const GLsizei gDrawTextureVertexCount = 4; 60 61static inline void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) { 62 gDrawTextureVertices[0].texture[0] = u1; 63 gDrawTextureVertices[0].texture[1] = v2; 64 gDrawTextureVertices[1].texture[0] = u2; 65 gDrawTextureVertices[1].texture[1] = v2; 66 gDrawTextureVertices[2].texture[0] = u1; 67 gDrawTextureVertices[2].texture[1] = v1; 68 gDrawTextureVertices[3].texture[0] = u2; 69 gDrawTextureVertices[3].texture[1] = v1; 70} 71 72/////////////////////////////////////////////////////////////////////////////// 73// Constructors/destructor 74/////////////////////////////////////////////////////////////////////////////// 75 76OpenGLRenderer::OpenGLRenderer() { 77 LOGD("Create OpenGLRenderer"); 78 79 mDrawColorShader = new DrawColorProgram; 80 mDrawTextureShader = new DrawTextureProgram; 81} 82 83OpenGLRenderer::~OpenGLRenderer() { 84 LOGD("Destroy OpenGLRenderer"); 85} 86 87/////////////////////////////////////////////////////////////////////////////// 88// Setup 89/////////////////////////////////////////////////////////////////////////////// 90 91void OpenGLRenderer::setViewport(int width, int height) { 92 glViewport(0, 0, width, height); 93 94 mat4 ortho; 95 ortho.loadOrtho(0, width, height, 0, -1, 1); 96 ortho.copyTo(mOrthoMatrix); 97 98 mWidth = width; 99 mHeight = height; 100} 101 102void OpenGLRenderer::prepare() { 103 mSnapshot = &mFirstSnapshot; 104 mSaveCount = 0; 105 106 glDisable(GL_SCISSOR_TEST); 107 108 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 109 glClear(GL_COLOR_BUFFER_BIT); 110 111 glEnable(GL_SCISSOR_TEST); 112 glScissor(0, 0, mWidth, mHeight); 113 114 mSnapshot->clipRect.set(0.0f, 0.0f, mWidth, mHeight); 115} 116 117/////////////////////////////////////////////////////////////////////////////// 118// State management 119/////////////////////////////////////////////////////////////////////////////// 120 121int OpenGLRenderer::getSaveCount() const { 122 return mSaveCount; 123} 124 125int OpenGLRenderer::save(int flags) { 126 return saveSnapshot(); 127} 128 129void OpenGLRenderer::restore() { 130 if (mSaveCount == 0) return; 131 132 if (restoreSnapshot()) { 133 setScissorFromClip(); 134 } 135} 136 137void OpenGLRenderer::restoreToCount(int saveCount) { 138 if (saveCount <= 0 || saveCount > mSaveCount) return; 139 140 bool restoreClip = false; 141 142 while (mSaveCount != saveCount - 1) { 143 restoreClip |= restoreSnapshot(); 144 } 145 146 if (restoreClip) { 147 setScissorFromClip(); 148 } 149} 150 151int OpenGLRenderer::saveSnapshot() { 152 mSnapshot = new Snapshot(mSnapshot); 153 return ++mSaveCount; 154} 155 156bool OpenGLRenderer::restoreSnapshot() { 157 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 158 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 159 160 sp<Snapshot> current = mSnapshot; 161 sp<Snapshot> previous = mSnapshot->previous; 162 163 if (restoreLayer) { 164 // Unbind current FBO and restore previous one 165 // Most of the time, previous->fbo will be 0 to bind the default buffer 166 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 167 168 // Restore the clip from the previous snapshot 169 const Rect& clip = previous->getMappedClip(); 170 glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); 171 172 // Compute the correct texture coordinates for the FBO texture 173 // The texture is currently as big as the window but drawn with 174 // a quad of the appropriate size 175 const Rect& layer = current->layer; 176 Rect texCoords(current->layer); 177 mSnapshot->transform.mapRect(texCoords); 178 179 const float u1 = texCoords.left / float(mWidth); 180 const float v1 = (mHeight - texCoords.top) / float(mHeight); 181 const float u2 = texCoords.right / float(mWidth); 182 const float v2 = (mHeight - texCoords.bottom) / float(mHeight); 183 184 resetDrawTextureTexCoords(u1, v1, u2, v1); 185 186 drawTextureRect(layer.left, layer.top, layer.right, layer.bottom, 187 current->texture, current->alpha); 188 189 resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f); 190 191 glDeleteFramebuffers(1, ¤t->fbo); 192 glDeleteTextures(1, ¤t->texture); 193 } 194 195 mSnapshot = previous; 196 mSaveCount--; 197 198 return restoreClip; 199} 200 201/////////////////////////////////////////////////////////////////////////////// 202// Layers 203/////////////////////////////////////////////////////////////////////////////// 204 205int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 206 const SkPaint* p, int flags) { 207 // TODO Implement 208 return saveSnapshot(); 209} 210 211int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 212 int alpha, int flags) { 213 int count = saveSnapshot(); 214 215 mSnapshot->flags |= Snapshot::kFlagIsLayer; 216 mSnapshot->alpha = alpha / 255.0f; 217 mSnapshot->layer.set(left, top, right, bottom); 218 219 // Generate the FBO and attach the texture 220 glGenFramebuffers(1, &mSnapshot->fbo); 221 glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo); 222 223 // Generate the texture in which the FBO will draw 224 glGenTextures(1, &mSnapshot->texture); 225 glBindTexture(GL_TEXTURE_2D, mSnapshot->texture); 226 227 // The FBO will not be scaled, so we can use lower quality filtering 228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 231 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 232 233 // TODO ***** IMPORTANT ***** 234 // Creating a texture-backed FBO works only if the texture is the same size 235 // as the original rendering buffer (in this case, mWidth and mHeight.) 236 // This is expensive and wasteful and must be fixed. 237 // TODO Additionally we should use an FBO cache 238 239 const GLsizei width = mWidth; //right - left; 240 const GLsizei height = mHeight; //bottom - right; 241 242 const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB; 243 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); 244 glBindTexture(GL_TEXTURE_2D, 0); 245 246 // Bind texture to FBO 247 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 248 mSnapshot->texture, 0); 249 250 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 251 if (status != GL_FRAMEBUFFER_COMPLETE) { 252 LOGD("Framebuffer incomplete %d", status); 253 254 glDeleteFramebuffers(1, &mSnapshot->fbo); 255 glDeleteTextures(1, &mSnapshot->texture); 256 } 257 258 return count; 259} 260 261/////////////////////////////////////////////////////////////////////////////// 262// Transforms 263/////////////////////////////////////////////////////////////////////////////// 264 265void OpenGLRenderer::translate(float dx, float dy) { 266 mSnapshot->transform.translate(dx, dy, 0.0f); 267 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 268} 269 270void OpenGLRenderer::rotate(float degrees) { 271 mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f); 272 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 273} 274 275void OpenGLRenderer::scale(float sx, float sy) { 276 mSnapshot->transform.scale(sx, sy, 1.0f); 277 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 278} 279 280void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 281 mSnapshot->transform.load(*matrix); 282 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 283} 284 285void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 286 mSnapshot->transform.copyTo(*matrix); 287} 288 289void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 290 mat4 m(*matrix); 291 mSnapshot->transform.multiply(m); 292 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 293} 294 295/////////////////////////////////////////////////////////////////////////////// 296// Clipping 297/////////////////////////////////////////////////////////////////////////////// 298 299void OpenGLRenderer::setScissorFromClip() { 300 const Rect& clip = mSnapshot->getMappedClip(); 301 glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); 302} 303 304const Rect& OpenGLRenderer::getClipBounds() { 305 return mSnapshot->clipRect; 306} 307 308bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 309 /* 310 * The documentation of quickReject() indicates that the specified rect 311 * is transformed before being compared to the clip rect. However, the 312 * clip rect is not stored transformed in the snapshot and can thus be 313 * compared directly 314 * 315 * The following code can be used instead to performed a mapped comparison: 316 * 317 * mSnapshot->transform.mapRect(r); 318 * const Rect& clip = mSnapshot->getMappedClip(); 319 * return !clip.intersects(r); 320 */ 321 Rect r(left, top, right, bottom); 322 return !mSnapshot->clipRect.intersects(r); 323} 324 325bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) { 326 bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom); 327 if (clipped) { 328 mSnapshot->flags |= Snapshot::kFlagClipSet; 329 setScissorFromClip(); 330 } 331 return clipped; 332} 333 334/////////////////////////////////////////////////////////////////////////////// 335// Drawing 336/////////////////////////////////////////////////////////////////////////////// 337 338void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 339 // TODO: Set the transfer mode 340 const Rect& clip = mSnapshot->clipRect; 341 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color); 342} 343 344void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { 345 // TODO Support more than just color 346 // TODO: Set the transfer mode 347 drawColorRect(left, top, right, bottom, p->getColor()); 348} 349 350void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) { 351 GLfloat a = ((color >> 24) & 0xFF) / 255.0f; 352 GLfloat r = ((color >> 16) & 0xFF) / 255.0f; 353 GLfloat g = ((color >> 8) & 0xFF) / 255.0f; 354 GLfloat b = ((color ) & 0xFF) / 255.0f; 355 356 mModelView.loadTranslate(left, top, 0.0f); 357 mModelView.scale(right - left, bottom - top, 1.0f); 358 359 mDrawColorShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); 360 361 const GLvoid* p = &gDrawColorVertices[0].position[0]; 362 363 glEnableVertexAttribArray(mDrawColorShader->position); 364 glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, 365 gDrawColorVertexStride, p); 366 glVertexAttrib4f(mDrawColorShader->color, r, g, b, a); 367 368 glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount); 369 370 glDisableVertexAttribArray(mDrawColorShader->position); 371} 372 373void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 374 GLuint texture, float alpha) { 375 mModelView.loadTranslate(left, top, 0.0f); 376 mModelView.scale(right - left, bottom - top, 1.0f); 377 378 mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); 379 380 // TODO Correctly set the blend function, based on texture format and xfermode 381 glEnable(GL_BLEND); 382 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); 383 384 glBindTexture(GL_TEXTURE_2D, texture); 385 386 glActiveTexture(GL_TEXTURE0); 387 glUniform1i(mDrawTextureShader->sampler, 0); 388 389 const GLvoid* p = &gDrawTextureVertices[0].position[0]; 390 const GLvoid* t = &gDrawTextureVertices[0].texture[0]; 391 392 glEnableVertexAttribArray(mDrawTextureShader->position); 393 glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE, 394 gDrawTextureVertexStride, p); 395 396 glEnableVertexAttribArray(mDrawTextureShader->texCoords); 397 glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE, 398 gDrawTextureVertexStride, t); 399 400 glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha); 401 402 glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount); 403 404 glDisableVertexAttribArray(mDrawTextureShader->position); 405 glDisableVertexAttribArray(mDrawTextureShader->texCoords); 406 407 glBindTexture(GL_TEXTURE_2D, 0); 408 glDisable(GL_BLEND); 409} 410 411}; // namespace uirenderer 412}; // namespace android 413