diff options
author | Teng-Hui Zhu <ztenghui@google.com> | 2011-12-21 11:45:43 -0800 |
---|---|---|
committer | Teng-Hui Zhu <ztenghui@google.com> | 2011-12-22 15:42:07 -0800 |
commit | 8abedfb0681eb18f62137fffde000a9dbb75c4d2 (patch) | |
tree | f44ba2bf5e7b05b4059a2e501816531b66797162 | |
parent | adf365552d1a6b55782fa3b3c722f5ea914deb40 (diff) | |
download | external_webkit-8abedfb0681eb18f62137fffde000a9dbb75c4d2.zip external_webkit-8abedfb0681eb18f62137fffde000a9dbb75c4d2.tar.gz external_webkit-8abedfb0681eb18f62137fffde000a9dbb75c4d2.tar.bz2 |
Use the shader to draw a tile with single color.
This could save GL texture resources by adding some computation overhead.
But we could improve the overhead by detecting such single color tiles from
skPicture.
Change-Id: Ia8aa76b2622fabf31de1ca921df35a494c4ac116
7 files changed, 251 insertions, 47 deletions
diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index 73b6422..ea546ef 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -124,6 +124,7 @@ void BaseTile::reserveTexture() this, texture, m_backTexture, m_frontTexture); m_state = Unpainted; m_backTexture = texture; + m_backTexture->setPure(false); } if (m_state == UpToDate) { @@ -247,13 +248,28 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) return; if (m_frontTexture->readyFor(this)) { - if (isLayerTile() && m_painter && m_painter->transform()) - TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), - rect, m_frontTexture->m_ownTextureId, - transparency, true); - else - TilesManager::instance()->shader()->drawQuad(rect, m_frontTexture->m_ownTextureId, - transparency); + if (isLayerTile() && m_painter && m_painter->transform()) { + if (m_frontTexture->isPureColor()) { + TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), + rect, 0, + transparency, true, + GL_TEXTURE_2D, + m_frontTexture->pureColor()); + } else { + TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), + rect, m_frontTexture->m_ownTextureId, + transparency, true); + } + } else { + if (m_frontTexture->isPureColor()) { + TilesManager::instance()->shader()->drawQuad(rect, 0, + transparency, + m_frontTexture->pureColor()); + } else { + TilesManager::instance()->shader()->drawQuad(rect, m_frontTexture->m_ownTextureId, + transparency); + } + } } else { XLOG("tile %p at %d, %d not readyfor (at draw),", this, m_x, m_y); } @@ -539,9 +555,13 @@ void BaseTile::validatePaint() { // when both have happened, mark as 'ReadyToSwap' if (m_state == PaintingStarted) m_state = ValidatedUntransferred; - else if (m_state == TransferredUnvalidated) + else if (m_state == TransferredUnvalidated + || (m_backTexture && m_backTexture->isPureColor())) { + // When the backTexture has been marked pureColor, we will skip the + // transfer and marked as ReadyToSwap, in this case, we don't want + // to reset m_dirty bit to true. m_state = ReadyToSwap; - else { + } else { XLOG("Note: validated tile %p at %d %d, state wasn't paintingstarted or transferred %d", this, m_x, m_y, m_state); // failed transferring, in which case mark dirty (since diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp index 6da1b77..ae6f1e8 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.cpp @@ -54,6 +54,7 @@ namespace WebCore { BaseTileTexture::BaseTileTexture(uint32_t w, uint32_t h) : m_owner(0) + , m_isPureColor(false) { m_size.set(w, h); m_ownTextureId = 0; @@ -148,6 +149,11 @@ void BaseTileTexture::setOwnTextureTileInfoFromQueue(const TextureTileInfo* info bool BaseTileTexture::readyFor(BaseTile* baseTile) { + if (isPureColor()) { + XLOG("ReadyFor saw a pureColor tile (%p) at (%d, %d), rgb %x", + this, baseTile->x(), baseTile->y(), pureColor().rgb()); + return true; + } const TextureTileInfo* info = &m_ownTextureTileInfo; if (info && (info->m_x == baseTile->x()) && diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.h b/Source/WebCore/platform/graphics/android/BaseTileTexture.h index 379d587..74f9e5d 100644 --- a/Source/WebCore/platform/graphics/android/BaseTileTexture.h +++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.h @@ -95,6 +95,12 @@ public: TextureInfo* getTextureInfo() { return &m_ownTextureInfo; } + void setPure(bool pure){ m_isPureColor = pure; } + bool isPureColor() {return m_isPureColor; } + + void setPureColor(const Color& color) { m_pureColor = color; } + Color pureColor() { return m_pureColor; } + private: TextureTileInfo m_ownTextureTileInfo; // TODO: Merge this info into the TextureTileInfo. @@ -104,6 +110,11 @@ private: // BaseTile owning the texture, only modified by UI thread TextureOwner* m_owner; + + // When the whole tile is single color, skip the transfer queue and draw + // it directly through shader. + bool m_isPureColor; + Color m_pureColor; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp index afb9bb0..38e1ce9 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp @@ -376,6 +376,84 @@ GLuint GLUtils::createBaseTileGLTexture(int width, int height) return texture; } +bool GLUtils::isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor) +{ + // If the bitmap is the pure color, skip the transfer step, and update the BaseTile Info. + // This check is taking < 1ms if we do full bitmap check per tile. + // TODO: use the SkPicture to determine whether or not a tile is single color. + pureColor = Color(Color::transparent); + bitmap.lockPixels(); + bool sameColor = true; + int bitmapWidth = bitmap.width(); + + // Create a row of pure color using the first pixel. + int* firstPixelPtr = static_cast<int*> (bitmap.getPixels()); + int* pixelsRow = new int[bitmapWidth]; + for (int i = 0; i < bitmapWidth; i++) + pixelsRow[i] = (*firstPixelPtr); + + // Then compare the pure color row with each row of the bitmap. + for (int j = 0; j < bitmap.height(); j++) { + if (memcmp(pixelsRow, &firstPixelPtr[bitmapWidth * j], 4 * bitmapWidth)) { + sameColor = false; + break; + } + } + delete pixelsRow; + pixelsRow = 0; + + if (sameColor) { + char* rgbaPtr = static_cast<char*>(bitmap.getPixels()); + pureColor = Color(rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]); + XLOG("sameColor tile found , %x at (%d, %d, %d, %d)", + *firstPixelPtr, rgbaPtr[0], rgbaPtr[1], rgbaPtr[2], rgbaPtr[3]); + } + bitmap.unlockPixels(); + + return sameColor; +} + +// Return true when the tile is pure color. +bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo, + const SkBitmap& bitmap) +{ + bool skipTransfer = false; + BaseTile* tilePtr = renderInfo->baseTile; + + if (tilePtr) { + BaseTileTexture* tileTexture = tilePtr->backTexture(); + // Check the bitmap, and make everything ready here. + Color pureColor; + bool pure = isPureColorBitmap(bitmap, pureColor); + if (pure) { + // update basetile's info + // Note that we are skipping the whole TransferQueue. + if (tileTexture) { + tileTexture->setPure(true); + tileTexture->setPureColor(pureColor); + + TextureTileInfo info; + // Now fill the tileInfo. + info.m_x = renderInfo->x; + info.m_y = renderInfo->y; + info.m_scale = renderInfo->scale; + info.m_painter = renderInfo->tilePainter; + info.m_picture = renderInfo->textureInfo->m_pictureCount; + info.m_inverted = TilesManager::instance()->invertedScreen(); + + // Make sure the tile is considered ready! + tileTexture->setOwnTextureTileInfoFromQueue(&info); + + renderInfo->textureInfo->m_width = bitmap.width(); + renderInfo->textureInfo->m_height = bitmap.height(); + renderInfo->textureInfo->m_internalFormat = GL_RGBA; + skipTransfer = true; + } + } + } + return skipTransfer; +} + void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) { @@ -386,6 +464,9 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkSize& requiredSize = renderInfo->tileSize; TextureInfo* textureInfo = renderInfo->textureInfo; + if (skipTransferForPureColor(renderInfo, bitmap)) + return; + if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height)) GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, x, y, bitmap); else { diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h index 48235a5..3475760 100644 --- a/Source/WebCore/platform/graphics/android/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/GLUtils.h @@ -28,6 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "Color.h" #include "SkBitmap.h" #include "SkMatrix.h" #include "SkSize.h" @@ -80,6 +81,10 @@ public: static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); + + static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor); + static bool skipTransferForPureColor(const TileRenderInfo* renderInfo, + const SkBitmap& bitmap); }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index 2a6a488..2df97db 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -62,6 +62,26 @@ static const char gFragmentShader[] = " gl_FragColor *= alpha; " "}\n"; +// We could pass the pureColor into either Vertex or Frag Shader. +// The reason we passed the color into the Vertex Shader is that some driver +// might create redundant copy when uniforms in fragment shader changed. +static const char gPureColorVertexShader[] = + "attribute vec4 vPosition;\n" + "uniform mat4 projectionMatrix;\n" + "uniform vec4 inputColor;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_Position = projectionMatrix * vPosition;\n" + " v_color = inputColor;\n" + "}\n"; + +static const char gPureColorFragmentShader[] = + "precision mediump float;\n" + "varying vec4 v_color;\n" + "void main() {\n" + " gl_FragColor = v_color;\n" + "}\n"; + static const char gFragmentShaderInverted[] = "precision mediump float;\n" "varying vec2 v_texCoord; \n" @@ -204,6 +224,7 @@ ShaderProgram::ShaderProgram() void ShaderProgram::init() { m_program = createProgram(gVertexShader, gFragmentShader); + m_pureColorProgram = createProgram(gPureColorVertexShader, gPureColorFragmentShader); m_programInverted = createProgram(gVertexShader, gFragmentShaderInverted); m_videoProgram = createProgram(gVideoVertexShader, gVideoFragmentShader); m_surfTexOESProgram = @@ -212,6 +233,7 @@ void ShaderProgram::init() createProgram(gVertexShader, gSurfaceTextureOESFragmentShaderInverted); if (m_program == -1 + || m_pureColorProgram == -1 || m_programInverted == -1 || m_videoProgram == -1 || m_surfTexOESProgram == -1 @@ -223,6 +245,10 @@ void ShaderProgram::init() m_hTexSampler = glGetUniformLocation(m_program, "s_texture"); m_hPosition = glGetAttribLocation(m_program, "vPosition"); + m_hPureColorProjectionMatrix = glGetUniformLocation(m_pureColorProgram, "projectionMatrix"); + m_hPureColorValue = glGetUniformLocation(m_pureColorProgram, "inputColor"); + m_hPureColorPosition = glGetAttribLocation(m_pureColorProgram, "vPosition"); + m_hProjectionMatrixInverted = glGetUniformLocation(m_programInverted, "projectionMatrix"); m_hAlphaInverted = glGetUniformLocation(m_programInverted, "alpha"); m_hContrastInverted = glGetUniformLocation(m_surfTexOESProgramInverted, "contrast"); @@ -327,7 +353,8 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry, GLint position, GLint alpha, GLint texFilter, - GLint contrast) + GLint contrast, + Color pureColor) { glUseProgram(program); @@ -343,29 +370,61 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry, glUniformMatrix4fv(projectionMatrixHandle, 1, GL_FALSE, projectionMatrix); } - glActiveTexture(GL_TEXTURE0); - glUniform1i(texSampler, 0); - glBindTexture(textureTarget, textureId); - glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, texFilter); - glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, texFilter); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if(textureId) { + glActiveTexture(GL_TEXTURE0); + glUniform1i(texSampler, 0); + glBindTexture(textureTarget, textureId); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, texFilter); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, texFilter); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glUniform1f(alpha, opacity); + if (contrast != -1) + glUniform1f(contrast, m_contrast); + } else { + glUniform4f(m_hPureColorValue, pureColor.red() / 255.0, + pureColor.green() / 255.0, pureColor.blue() / 255.0, + pureColor.alpha() / 255.0 ); + } glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); glEnableVertexAttribArray(position); glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glUniform1f(alpha, opacity); - if (contrast != -1) - glUniform1f(contrast, m_contrast); setBlendingState(opacity < 1.0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } +// Calculate the right color value sent into the shader considering the (0,1) +// clamp and alpha blending. +Color ShaderProgram::shaderColor(Color pureColor, float opacity) +{ + float r = pureColor.red() / 255.0; + float g = pureColor.green() / 255.0; + float b = pureColor.blue() / 255.0; + float a = pureColor.alpha() / 255.0; + + if (TilesManager::instance()->invertedScreen()) { + float intensity = a - (0.2989 * r + 0.5866 * g + 0.1145 * b); + intensity = ((intensity - a / 2.0) * m_contrast) + a / 2.0; + intensity *= opacity; + return Color(intensity, intensity, intensity, a * opacity); + } else + return Color(r * opacity, g * opacity, b * opacity, a * opacity); +} + void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity, - GLenum textureTarget, GLint texFilter) + Color pureColor, GLenum textureTarget, GLint texFilter) { - if (textureTarget == GL_TEXTURE_2D) { + if (!textureId) { + Color finalColor = shaderColor(pureColor, opacity); + if (finalColor.rgb() == Color::transparent && opacity < 1.0) + return; + drawQuadInternal(geometry, 0, opacity, m_pureColorProgram, + m_hPureColorProjectionMatrix, 0, -1, + m_hPureColorPosition, -1, -1, -1, finalColor); + } else if (textureTarget == GL_TEXTURE_2D) { if (!TilesManager::instance()->invertedScreen()) { drawQuadInternal(geometry, textureId, opacity, m_program, m_hProjectionMatrix, @@ -535,33 +594,39 @@ void ShaderProgram::drawLayerQuadInternal(const GLfloat* projectionMatrix, GLenum textureTarget, GLint program, GLint matrix, GLint texSample, GLint position, GLint alpha, - GLint contrast) + GLint contrast, Color color) { glUseProgram(program); glUniformMatrix4fv(matrix, 1, GL_FALSE, projectionMatrix); - glActiveTexture(GL_TEXTURE0); - glUniform1i(texSample, 0); - glBindTexture(textureTarget, textureId); - glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + if (textureId) { + glActiveTexture(GL_TEXTURE0); + glUniform1i(texSample, 0); + glBindTexture(textureTarget, textureId); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glUniform1f(alpha, opacity); + if (contrast != -1) + glUniform1f(contrast, m_contrast); + } else { + glUniform4f(m_hPureColorValue, color.red() / 255.0, + color.green() / 255.0, color.blue() / 255.0, + color.alpha() / 255.0 ); + } glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); glEnableVertexAttribArray(position); glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glUniform1f(alpha, opacity); - if (contrast != -1) - glUniform1f(contrast, m_contrast); } void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, const SkRect& geometry, int textureId, float opacity, bool forceBlending, - GLenum textureTarget) + GLenum textureTarget, + Color pureColor) { TransformationMatrix modifiedDrawMatrix = drawMatrix; @@ -578,7 +643,16 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, GLfloat projectionMatrix[16]; GLUtils::toGLMatrix(projectionMatrix, renderMatrix); - if (textureTarget == GL_TEXTURE_2D) { + bool enableBlending = forceBlending || opacity < 1.0; + if (!textureId) { + Color finalColor = shaderColor(pureColor, opacity); + if (finalColor.rgb() == Color::transparent && enableBlending) + return; + drawLayerQuadInternal(projectionMatrix, 0, opacity, + -1, m_pureColorProgram, + m_hPureColorProjectionMatrix, -1, + m_hPureColorPosition, -1, -1, finalColor); + } else if (textureTarget == GL_TEXTURE_2D) { if (!TilesManager::instance()->invertedScreen()) { drawLayerQuadInternal(projectionMatrix, textureId, opacity, GL_TEXTURE_2D, m_program, @@ -606,7 +680,7 @@ void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, m_hSTOESContrastInverted); } - setBlendingState(forceBlending || opacity < 1.0); + setBlendingState(enableBlending); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); GLUtils::checkGlError("drawLayerQuad"); diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index 9ab7a46..fc37a29 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -19,6 +19,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "Color.h" #include "FloatRect.h" #include "IntRect.h" #include "SkRect.h" @@ -44,19 +45,16 @@ public: // Normal texture in GL_TEXTURE_2D target. // 2) textureTarget == GL_TEXTURE_EXTERNAL_OES // Surface texture in GL_TEXTURE_EXTERNAL_OES target. - // 3) textureTarget == 0 (Will be deprecated soon) - // Surface texture in GL_TEXTURE_2D target. - // - // TODO: Shrink the support modes into 2 (1 and 2) after media framework - // support Surface texture in GL_TEXTURE_EXTERNAL_OES target on all - // platforms. - void drawQuad(SkRect& geometry, int textureId, float opacity, + // 3) textureId == 0 + // No texture needed, just a pureColor quad. + void drawQuad(SkRect& geometry, int textureId, float opacity, Color pureColor = Color(), GLenum textureTarget = GL_TEXTURE_2D, GLint texFilter = GL_LINEAR); void drawLayerQuad(const TransformationMatrix& drawMatrix, const SkRect& geometry, int textureId, float opacity, bool forceBlending = false, - GLenum textureTarget = GL_TEXTURE_2D); + GLenum textureTarget = GL_TEXTURE_2D, + Color pureColor = Color()); void drawVideoLayerQuad(const TransformationMatrix& drawMatrix, float* textureMatrix, SkRect& geometry, int textureId); void setViewRect(const IntRect& viewRect); @@ -112,16 +110,21 @@ private: GLint program, GLint projectionMatrixHandle, GLint texSampler, GLenum textureTarget, GLint position, GLint alpha, - GLint texFilter, GLint contrast = -1); + GLint texFilter, GLint contrast = -1, + Color pureColor = Color()); void drawLayerQuadInternal(const GLfloat* projectionMatrix, int textureId, float opacity, GLenum textureTarget, GLint program, GLint matrix, GLint texSample, - GLint position, GLint alpha, GLint contrast = -1); + GLint position, GLint alpha, GLint contrast = -1, + Color pureColor = Color()); + + Color shaderColor(Color pureColor, float opacity); bool m_blendingEnabled; int m_program; + int m_pureColorProgram; int m_programInverted; int m_videoProgram; int m_surfTexOESProgram; @@ -164,6 +167,10 @@ private: GLint m_hSTOESTexSamplerInverted; GLint m_hSTOESPositionInverted; + GLint m_hPureColorProjectionMatrix; + GLint m_hPureColorValue; + GLint m_hPureColorPosition; + float m_contrast; // attribs |