From bd6b79b40247aea7bfe13d0831c6c0472df6c636 Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Sat, 26 Jun 2010 00:13:53 -0700 Subject: Add implementations for saveLayerAlpha() and textured rects. Even though there's an implementation for textured rects, drawBitmap() is not hooked up yet as it will require a good texture cache. This method is implemented using FBOs. There's currently an issue either in the driver or in the Canvas renderer that forces the FBO to be fullscreen, which is extremely expensive and yields terrible performance. Change-Id: I148419195e12d45653c60186938aa78c23a68e2c --- libs/hwui/OpenGLRenderer.cpp | 161 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 151 insertions(+), 10 deletions(-) (limited to 'libs/hwui/OpenGLRenderer.cpp') diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 830e0c36ff83..786b927d35eb 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -40,21 +41,31 @@ namespace uirenderer { // Defines /////////////////////////////////////////////////////////////////////////////// -#define V(x, y) { { x, y } } +#define SV(x, y) { { x, y } } +#define FV(x, y, u, v) { { x, y }, { u, v } } /////////////////////////////////////////////////////////////////////////////// // Globals /////////////////////////////////////////////////////////////////////////////// const SimpleVertex gDrawColorVertices[] = { - V(0.0f, 0.0f), - V(1.0f, 0.0f), - V(0.0f, 1.0f), - V(1.0f, 1.0f) + SV(0.0f, 0.0f), + SV(1.0f, 0.0f), + SV(0.0f, 1.0f), + SV(1.0f, 1.0f) }; const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex); const GLsizei gDrawColorVertexCount = 4; +const TextureVertex gDrawTextureVertices[] = { + FV(0.0f, 0.0f, 0.0f, 1.0f), + FV(1.0f, 0.0f, 1.0f, 1.0f), + FV(0.0f, 1.0f, 0.0f, 0.0f), + FV(1.0f, 1.0f, 1.0f, 0.0f) +}; +const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex); +const GLsizei gDrawTextureVertexCount = 4; + /////////////////////////////////////////////////////////////////////////////// // Shaders /////////////////////////////////////////////////////////////////////////////// @@ -64,6 +75,9 @@ const GLsizei gDrawColorVertexCount = 4; #include "shaders/drawColor.vert" #include "shaders/drawColor.frag" +#include "shaders/drawTexture.vert" +#include "shaders/drawTexture.frag" + Program::Program(const char* vertex, const char* fragment) { vertexShader = buildShader(vertex, GL_VERTEX_SHADER); fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); @@ -139,6 +153,15 @@ GLuint Program::buildShader(const char* source, GLenum type) { DrawColorProgram::DrawColorProgram(): Program(gDrawColorVertexShader, gDrawColorFragmentShader) { + getAttribsAndUniforms(); +} + +DrawColorProgram::DrawColorProgram(const char* vertex, const char* fragment): + Program(vertex, fragment) { + getAttribsAndUniforms(); +} + +void DrawColorProgram::getAttribsAndUniforms() { position = addAttrib("position"); color = addAttrib("color"); projection = addUniform("projection"); @@ -154,6 +177,12 @@ void DrawColorProgram::use(const GLfloat* projectionMatrix, const GLfloat* model glUniformMatrix4fv(transform, 1, GL_FALSE, transformMatrix); } +DrawTextureProgram::DrawTextureProgram(): + DrawColorProgram(gDrawTextureVertexShader, gDrawTextureFragmentShader) { + texCoords = addAttrib("texCoords"); + sampler = addUniform("sampler"); +} + /////////////////////////////////////////////////////////////////////////////// // Support /////////////////////////////////////////////////////////////////////////////// @@ -175,6 +204,7 @@ OpenGLRenderer::OpenGLRenderer() { LOGD("Create OpenGLRenderer"); mDrawColorShader = new DrawColorProgram; + mDrawTextureShader = new DrawTextureProgram; } OpenGLRenderer::~OpenGLRenderer() { @@ -252,16 +282,89 @@ int OpenGLRenderer::saveSnapshot() { bool OpenGLRenderer::restoreSnapshot() { bool restoreClip = mSnapshot->flags & Snapshot::kFlagClipSet; + bool restoreLayer = mSnapshot->flags & Snapshot::kFlagIsLayer; - mSaveCount--; - - // Do not merge these two lines! + sp current = mSnapshot; sp previous = mSnapshot->previous; + + if (restoreLayer) { + // Unbind current FBO and restore previous one + // Most of the time, previous->fbo will be 0 to bind the default buffer + glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo); + + const Rect& layer = current->layer; + clipRect(layer.left, layer.top, layer.right, layer.bottom); + mSnapshot->transform.loadIdentity(); + + drawTextureRect(0.0f, 0.0f, mWidth, mHeight, current->texture, current->alpha); + + glDeleteFramebuffers(1, ¤t->fbo); + glDeleteTextures(1, ¤t->texture); + } + mSnapshot = previous; + mSaveCount--; return restoreClip; } +/////////////////////////////////////////////////////////////////////////////// +// Layers +/////////////////////////////////////////////////////////////////////////////// + +int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom, + const SkPaint* p, int flags) { + // TODO Implement + return saveSnapshot(); +} + +int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom, + int alpha, int flags) { + int count = saveSnapshot(); + + mSnapshot->flags |= Snapshot::kFlagIsLayer; + mSnapshot->alpha = alpha / 255.0f; + mSnapshot->layer.set(left, top, right, bottom); + + // Generate the FBO and attach the texture + glGenFramebuffers(1, &mSnapshot->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo); + + // Generate the texture in which the FBO will draw + glGenTextures(1, &mSnapshot->texture); + glBindTexture(GL_TEXTURE_2D, mSnapshot->texture); + + // The FBO will not be scaled, so we can use lower quality filtering + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // TODO ***** IMPORTANT ***** + // Creating a texture-backed FBO works only if the texture is the same size + // as the original rendering buffer (in this case, mWidth and mHeight.) + // This is expensive and wasteful and must be fixed. + + const GLsizei width = mWidth; //right - left; + const GLsizei height = mHeight; //bottom - right; + + const GLint format = (flags & SkCanvas::kHasAlphaLayer_SaveFlag) ? GL_RGBA : GL_RGB; + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + + // Bind texture to FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + mSnapshot->texture, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LOGD("Framebuffer incomplete %d", status); + + glDeleteFramebuffers(1, &mSnapshot->fbo); + glDeleteTextures(1, &mSnapshot->texture); + } + + return count; +} + /////////////////////////////////////////////////////////////////////////////// // Transforms /////////////////////////////////////////////////////////////////////////////// @@ -346,10 +449,10 @@ void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) { drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color); } -void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* paint) { +void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) { // TODO Support more than just color // TODO: Set the transfer mode - drawColorRect(left, top, right, bottom, paint->getColor()); + drawColorRect(left, top, right, bottom, p->getColor()); } void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) { @@ -375,5 +478,43 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot glDisableVertexAttribArray(mDrawColorShader->position); } +void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom, + GLuint texture, float alpha) { + mModelView.loadTranslate(left, top, 0.0f); + mModelView.scale(right - left, bottom - top, 1.0f); + + mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]); + + // TODO Correctly set the blend function + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, texture); + + glActiveTexture(GL_TEXTURE0); + glUniform1i(mDrawTextureShader->sampler, 0); + + const GLvoid* p = &gDrawTextureVertices[0].position[0]; + const GLvoid* t = &gDrawTextureVertices[0].texture[0]; + + glEnableVertexAttribArray(mDrawTextureShader->position); + glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE, + gDrawTextureVertexStride, p); + + glEnableVertexAttribArray(mDrawTextureShader->texCoords); + glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE, + gDrawTextureVertexStride, t); + + glVertexAttrib4f(mDrawTextureShader->color, 1.0f, 1.0f, 1.0f, alpha); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawTextureVertexCount); + + glDisableVertexAttribArray(mDrawTextureShader->position); + glDisableVertexAttribArray(mDrawTextureShader->texCoords); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_BLEND); +} + }; // namespace uirenderer }; // namespace android -- cgit v1.2.3-59-g8ed1b