OpenGLRenderer.cpp revision bd6b79b40247aea7bfe13d0831c6c0472df6c636
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 <utils/Errors.h> 24#include <utils/KeyedVector.h> 25#include <utils/Log.h> 26 27#include <GLES2/gl2.h> 28#include <GLES2/gl2ext.h> 29 30#include <SkCanvas.h> 31#include <SkPaint.h> 32#include <SkXfermode.h> 33 34#include "OpenGLRenderer.h" 35#include "Matrix.h" 36 37namespace android { 38namespace uirenderer { 39 40/////////////////////////////////////////////////////////////////////////////// 41// Defines 42/////////////////////////////////////////////////////////////////////////////// 43 44#define SV(x, y) { { x, y } } 45#define FV(x, y, u, v) { { x, y }, { u, v } } 46 47/////////////////////////////////////////////////////////////////////////////// 48// Globals 49/////////////////////////////////////////////////////////////////////////////// 50 51const SimpleVertex gDrawColorVertices[] = { 52 SV(0.0f, 0.0f), 53 SV(1.0f, 0.0f), 54 SV(0.0f, 1.0f), 55 SV(1.0f, 1.0f) 56}; 57const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex); 58const GLsizei gDrawColorVertexCount = 4; 59 60const TextureVertex gDrawTextureVertices[] = { 61 FV(0.0f, 0.0f, 0.0f, 1.0f), 62 FV(1.0f, 0.0f, 1.0f, 1.0f), 63 FV(0.0f, 1.0f, 0.0f, 0.0f), 64 FV(1.0f, 1.0f, 1.0f, 0.0f) 65}; 66const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex); 67const GLsizei gDrawTextureVertexCount = 4; 68 69/////////////////////////////////////////////////////////////////////////////// 70// Shaders 71/////////////////////////////////////////////////////////////////////////////// 72 73#define SHADER_SOURCE(name, source) const char* name = #source 74 75#include "shaders/drawColor.vert" 76#include "shaders/drawColor.frag" 77 78#include "shaders/drawTexture.vert" 79#include "shaders/drawTexture.frag" 80 81Program::Program(const char* vertex, const char* fragment) { 82 vertexShader = buildShader(vertex, GL_VERTEX_SHADER); 83 fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 84 85 id = glCreateProgram(); 86 glAttachShader(id, vertexShader); 87 glAttachShader(id, fragmentShader); 88 glLinkProgram(id); 89 90 GLint status; 91 glGetProgramiv(id, GL_LINK_STATUS, &status); 92 if (status != GL_TRUE) { 93 GLint infoLen = 0; 94 glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen); 95 if (infoLen > 1) { 96 char* log = (char*) malloc(sizeof(char) * infoLen); 97 glGetProgramInfoLog(id, infoLen, 0, log); 98 LOGE("Error while linking shaders: %s", log); 99 delete log; 100 } 101 glDeleteProgram(id); 102 } 103} 104 105Program::~Program() { 106 glDeleteShader(vertexShader); 107 glDeleteShader(fragmentShader); 108 glDeleteProgram(id); 109} 110 111void Program::use() { 112 glUseProgram(id); 113} 114 115int Program::addAttrib(const char* name) { 116 int slot = glGetAttribLocation(id, name); 117 attributes.add(name, slot); 118 return slot; 119} 120 121int Program::getAttrib(const char* name) { 122 return attributes.valueFor(name); 123} 124 125int Program::addUniform(const char* name) { 126 int slot = glGetUniformLocation(id, name); 127 uniforms.add(name, slot); 128 return slot; 129} 130 131int Program::getUniform(const char* name) { 132 return uniforms.valueFor(name); 133} 134 135GLuint Program::buildShader(const char* source, GLenum type) { 136 GLuint shader = glCreateShader(type); 137 glShaderSource(shader, 1, &source, 0); 138 glCompileShader(shader); 139 140 GLint status; 141 glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 142 if (status != GL_TRUE) { 143 // Some drivers return wrong values for GL_INFO_LOG_LENGTH 144 // use a fixed size instead 145 GLchar log[512]; 146 glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); 147 LOGE("Error while compiling shader: %s", log); 148 glDeleteShader(shader); 149 } 150 151 return shader; 152} 153 154DrawColorProgram::DrawColorProgram(): 155 Program(gDrawColorVertexShader, gDrawColorFragmentShader) { 156 getAttribsAndUniforms(); 157} 158 159DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment): 160 Program(vertex, fragment) { 161 getAttribsAndUniforms(); 162} 163 164void DrawColorProgram::getAttribsAndUniforms() { 165 position = addAttrib("position"); 166 color = addAttrib("color"); 167 projection = addUniform("projection"); 168 modelView = addUniform("modelView"); 169 transform = addUniform("transform"); 170} 171 172void DrawColorProgram::use(const GLfloat* projectionMatrix, const GLfloat* modelViewMatrix, 173 const GLfloat* transformMatrix) { 174 Program::use(); 175 glUniformMatrix4fv(projection, 1, GL_FALSE, projectionMatrix); 176 glUniformMatrix4fv(modelView, 1, GL_FALSE, modelViewMatrix); 177 glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix); 178} 179 180DrawTextureProgram::DrawTextureProgram(): 181 DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) { 182 texCoords = addAttrib("texCoords"); 183 sampler = addUniform("sampler"); 184} 185 186/////////////////////////////////////////////////////////////////////////////// 187// Support 188/////////////////////////////////////////////////////////////////////////////// 189 190const Rect& Snapshot::getMappedClip() { 191 if (flags & kFlagDirtyTransform) { 192 flags &= ~kFlagDirtyTransform; 193 mappedClip.set(clipRect); 194 transform.mapRect(mappedClip); 195 } 196 return mappedClip; 197} 198 199/////////////////////////////////////////////////////////////////////////////// 200// Constructors/destructor 201/////////////////////////////////////////////////////////////////////////////// 202 203OpenGLRenderer::OpenGLRenderer() { 204 LOGD("Create OpenGLRenderer"); 205 206 mDrawColorShader = new DrawColorProgram; 207 mDrawTextureShader = new DrawTextureProgram; 208} 209 210OpenGLRenderer::~OpenGLRenderer() { 211 LOGD("Destroy OpenGLRenderer"); 212} 213 214/////////////////////////////////////////////////////////////////////////////// 215// Setup 216/////////////////////////////////////////////////////////////////////////////// 217 218void OpenGLRenderer::setViewport(int width, int height) { 219 glViewport(0, 0, width, height); 220 221 mat4 ortho; 222 ortho.loadOrtho(0, width, height, 0, -1, 1); 223 ortho.copyTo(mOrthoMatrix); 224 225 mWidth = width; 226 mHeight = height; 227} 228 229void OpenGLRenderer::prepare() { 230 mSnapshot = &mFirstSnapshot; 231 mSaveCount = 0; 232 233 glDisable(GL_SCISSOR_TEST); 234 235 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 236 glClear(GL_COLOR_BUFFER_BIT); 237 238 glEnable(GL_SCISSOR_TEST); 239 glScissor(0, 0, mWidth, mHeight); 240 241 mSnapshot->clipRect.set(0.0f, 0.0f, mWidth, mHeight); 242} 243 244/////////////////////////////////////////////////////////////////////////////// 245// State management 246/////////////////////////////////////////////////////////////////////////////// 247 248int OpenGLRenderer::getSaveCount() const { 249 return mSaveCount; 250} 251 252int OpenGLRenderer::save(int flags) { 253 return saveSnapshot(); 254} 255 256void OpenGLRenderer::restore() { 257 if (mSaveCount == 0) return; 258 259 if (restoreSnapshot()) { 260 setScissorFromClip(); 261 } 262} 263 264void OpenGLRenderer::restoreToCount(int saveCount) { 265 if (saveCount <= 0 || saveCount > mSaveCount) return; 266 267 bool restoreClip = false; 268 269 while (mSaveCount != saveCount - 1) { 270 restoreClip |= restoreSnapshot(); 271 } 272 273 if (restoreClip) { 274 setScissorFromClip(); 275 } 276} 277 278int OpenGLRenderer::saveSnapshot() { 279 mSnapshot = new Snapshot(mSnapshot); 280 return ++mSaveCount; 281} 282 283bool OpenGLRenderer::restoreSnapshot() { 284 bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; 285 bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; 286 287 sp<Snapshot> current = mSnapshot; 288 sp<Snapshot> previous = mSnapshot->previous; 289 290 if (restoreLayer) { 291 // Unbind current FBO and restore previous one 292 // Most of the time, previous->fbo will be 0 to bind the default buffer 293 glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); 294 295 const Rect& layer = current->layer; 296 clipRect(layer.left, layer.top, layer.right, layer.bottom); 297 mSnapshot->transform.loadIdentity(); 298 299 drawTextureRect(0.0f, 0.0f, mWidth, mHeight, current->texture, current->alpha); 300 301 glDeleteFramebuffers(1, ¤t->fbo); 302 glDeleteTextures(1, ¤t->texture); 303 } 304 305 mSnapshot = previous; 306 mSaveCount--; 307 308 return restoreClip; 309} 310 311/////////////////////////////////////////////////////////////////////////////// 312// Layers 313/////////////////////////////////////////////////////////////////////////////// 314 315int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, 316 const SkPaint* p, int flags) { 317 // TODO Implement 318 return saveSnapshot(); 319} 320 321int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, 322 int alpha, int flags) { 323 int count = saveSnapshot(); 324 325 mSnapshot->flags |= Snapshot::kFlagIsLayer; 326 mSnapshot->alpha = alpha / 255.0f; 327 mSnapshot->layer.set(left, top, right, bottom); 328 329 // Generate the FBO and attach the texture 330 glGenFramebuffers(1, &mSnapshot->fbo); 331 glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo); 332 333 // Generate the texture in which the FBO will draw 334 glGenTextures(1, &mSnapshot->texture); 335 glBindTexture(GL_TEXTURE_2D, mSnapshot->texture); 336 337 // The FBO will not be scaled, so we can use lower quality filtering 338 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 339 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 340 341 // TODO ***** IMPORTANT ***** 342 // Creating a texture-backed FBO works only if the texture is the same size 343 // as the original rendering buffer (in this case, mWidth and mHeight.) 344 // This is expensive and wasteful and must be fixed. 345 346 const GLsizei width = mWidth; //right - left; 347 const GLsizei height = mHeight; //bottom - right; 348 349 const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB; 350 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); 351 glBindTexture(GL_TEXTURE_2D, 0); 352 353 // Bind texture to FBO 354 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 355 mSnapshot->texture, 0); 356 357 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 358 if (status != GL_FRAMEBUFFER_COMPLETE) { 359 LOGD("Framebuffer incomplete %d", status); 360 361 glDeleteFramebuffers(1, &mSnapshot->fbo); 362 glDeleteTextures(1, &mSnapshot->texture); 363 } 364 365 return count; 366} 367 368/////////////////////////////////////////////////////////////////////////////// 369// Transforms 370/////////////////////////////////////////////////////////////////////////////// 371 372void OpenGLRenderer::translate(float dx, float dy) { 373 mSnapshot->transform.translate(dx, dy, 0.0f); 374 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 375} 376 377void OpenGLRenderer::rotate(float degrees) { 378 mSnapshot->transform.rotate(degrees, 0.0f, 0.0f, 1.0f); 379 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 380} 381 382void OpenGLRenderer::scale(float sx, float sy) { 383 mSnapshot->transform.scale(sx, sy, 1.0f); 384 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 385} 386 387void OpenGLRenderer::setMatrix(SkMatrix* matrix) { 388 mSnapshot->transform.load(*matrix); 389 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 390} 391 392void OpenGLRenderer::getMatrix(SkMatrix* matrix) { 393 mSnapshot->transform.copyTo(*matrix); 394} 395 396void OpenGLRenderer::concatMatrix(SkMatrix* matrix) { 397 mat4 m(*matrix); 398 mSnapshot->transform.multiply(m); 399 mSnapshot->flags |= Snapshot::kFlagDirtyTransform; 400} 401 402/////////////////////////////////////////////////////////////////////////////// 403// Clipping 404/////////////////////////////////////////////////////////////////////////////// 405 406void OpenGLRenderer::setScissorFromClip() { 407 const Rect& clip = mSnapshot->getMappedClip(); 408 glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight()); 409} 410 411const Rect& OpenGLRenderer::getClipBounds() { 412 return mSnapshot->clipRect; 413} 414 415bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { 416 /* 417 * The documentation of quickReject() indicates that the specified rect 418 * is transformed before being compared to the clip rect. However, the 419 * clip rect is not stored transformed in the snapshot and can thus be 420 * compared directly 421 * 422 * The following code can be used instead to performed a mapped comparison: 423 * 424 * mSnapshot->transform.mapRect(r); 425 * const Rect& clip = mSnapshot->getMappedClip(); 426 * return !clip.intersects(r); 427 */ 428 429 Rect r(left, top, right, bottom); 430 return !mSnapshot->clipRect.intersects(r); 431} 432 433bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom) { 434 bool clipped = mSnapshot->clipRect.intersect(left, top, right, bottom); 435 if (clipped) { 436 mSnapshot->flags |= Snapshot::kFlagClipSet; 437 setScissorFromClip(); 438 } 439 return clipped; 440} 441 442/////////////////////////////////////////////////////////////////////////////// 443// Drawing 444/////////////////////////////////////////////////////////////////////////////// 445 446void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { 447 // TODO: Set the transfer mode 448 const Rect& clip = mSnapshot->clipRect; 449 drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color); 450} 451 452void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { 453 // TODO Support more than just color 454 // TODO: Set the transfer mode 455 drawColorRect(left, top, right, bottom, p->getColor()); 456} 457 458void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) { 459 GLfloat a = ((color >> 24) & 0xFF) / 255.0f; 460 GLfloat r = ((color >> 16) & 0xFF) / 255.0f; 461 GLfloat g = ((color >> 8) & 0xFF) / 255.0f; 462 GLfloat b = ((color ) & 0xFF) / 255.0f; 463 464 mModelView.loadTranslate(left, top, 0.0f); 465 mModelView.scale(right - left, bottom - top, 1.0f); 466 467 mDrawColorShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); 468 469 const GLvoid* p = &gDrawColorVertices[0].position[0]; 470 471 glEnableVertexAttribArray(mDrawColorShader->position); 472 glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE, 473 gDrawColorVertexStride, p); 474 glVertexAttrib4f(mDrawColorShader->color, r, g, b, a); 475 476 glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount); 477 478 glDisableVertexAttribArray(mDrawColorShader->position); 479} 480 481void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, 482 GLuint texture, float alpha) { 483 mModelView.loadTranslate(left, top, 0.0f); 484 mModelView.scale(right - left, bottom - top, 1.0f); 485 486 mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); 487 488 // TODO Correctly set the blend function 489 glEnable(GL_BLEND); 490 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); 491 492 glBindTexture(GL_TEXTURE_2D, texture); 493 494 glActiveTexture(GL_TEXTURE0); 495 glUniform1i(mDrawTextureShader->sampler, 0); 496 497 const GLvoid* p = &gDrawTextureVertices[0].position[0]; 498 const GLvoid* t = &gDrawTextureVertices[0].texture[0]; 499 500 glEnableVertexAttribArray(mDrawTextureShader->position); 501 glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE, 502 gDrawTextureVertexStride, p); 503 504 glEnableVertexAttribArray(mDrawTextureShader->texCoords); 505 glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE, 506 gDrawTextureVertexStride, t); 507 508 glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha); 509 510 glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount); 511 512 glDisableVertexAttribArray(mDrawTextureShader->position); 513 glDisableVertexAttribArray(mDrawTextureShader->texCoords); 514 515 glBindTexture(GL_TEXTURE_2D, 0); 516 glDisable(GL_BLEND); 517} 518 519}; // namespace uirenderer 520}; // namespace android 521