From c7e578330aece3c556ef205365c24676687223e2 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Fri, 1 Jul 2011 09:30:26 -0400 Subject: Add features to support Ganesh in the Android browser 1) Added a runtime switch between Raster and Ganesh 2) Added support for using SurfaceTextures with Ganesh bug: 5013645 Change-Id: I2efebf1bc9befb0c7f6f66109d80818f9d0775b3 --- .../platform/graphics/android/BaseRenderer.cpp | 22 +++ .../platform/graphics/android/BaseRenderer.h | 6 + .../WebCore/platform/graphics/android/BaseTile.cpp | 5 + .../platform/graphics/android/GaneshContext.cpp | 151 +++++++++++++++++++-- .../platform/graphics/android/GaneshContext.h | 23 +++- .../platform/graphics/android/GaneshRenderer.cpp | 48 +++---- .../platform/graphics/android/SharedTexture.cpp | 4 +- .../platform/graphics/android/TextureInfo.cpp | 1 + .../platform/graphics/android/TextureInfo.h | 4 + 9 files changed, 214 insertions(+), 50 deletions(-) (limited to 'Source/WebCore/platform/graphics/android') diff --git a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp index 4fde188..ea6c8ec 100644 --- a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp @@ -29,7 +29,9 @@ #if USE(ACCELERATED_COMPOSITING) +#include "GaneshRenderer.h" #include "GLUtils.h" +#include "RasterRenderer.h" #include "SkBitmap.h" #include "SkBitmapRef.h" #include "SkCanvas.h" @@ -56,6 +58,26 @@ namespace WebCore { +BaseRenderer::RendererType BaseRenderer::g_currentType = BaseRenderer::Raster; + +BaseRenderer* BaseRenderer::createRenderer() +{ + if (g_currentType == Raster) + return new RasterRenderer(); + else if (g_currentType == Ganesh) + return new GaneshRenderer(); + return NULL; +} + +void BaseRenderer::swapRendererIfNeeded(BaseRenderer*& renderer) +{ + if (renderer->getType() == g_currentType) + return; + + delete renderer; + renderer = createRenderer(); +} + void BaseRenderer::drawTileInfo(SkCanvas* canvas, const TileRenderInfo& renderInfo, int pictureCount) { diff --git a/Source/WebCore/platform/graphics/android/BaseRenderer.h b/Source/WebCore/platform/graphics/android/BaseRenderer.h index 0ee9ebd..7780db1 100644 --- a/Source/WebCore/platform/graphics/android/BaseRenderer.h +++ b/Source/WebCore/platform/graphics/android/BaseRenderer.h @@ -80,6 +80,11 @@ public: RendererType getType() { return m_type; } + static BaseRenderer* createRenderer(); + static void swapRendererIfNeeded(BaseRenderer*& renderer); + static RendererType getCurrentRendererType() { return g_currentType; } + static void setCurrentRendererType(RendererType type) { g_currentType = type; } + protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; @@ -96,6 +101,7 @@ protected: private: RendererType m_type; + static RendererType g_currentType; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index 4cbcf7c..6ab2cd2 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -86,6 +86,8 @@ BaseTile::BaseTile(bool isLayerTile) m_fullRepaint = new bool[m_maxBufferNumber]; for (int i = 0; i < m_maxBufferNumber; i++) m_fullRepaint[i] = true; + + m_renderer = BaseRenderer::createRenderer(); } BaseTile::~BaseTile() @@ -306,6 +308,9 @@ void BaseTile::paintBitmap() unsigned int pictureCount = 0; + // swap out the renderer if necessary + BaseRenderer::swapRendererIfNeeded(m_renderer); + // setup the common renderInfo fields; TileRenderInfo renderInfo; renderInfo.x = x; diff --git a/Source/WebCore/platform/graphics/android/GaneshContext.cpp b/Source/WebCore/platform/graphics/android/GaneshContext.cpp index b316e5a..6118aef 100644 --- a/Source/WebCore/platform/graphics/android/GaneshContext.cpp +++ b/Source/WebCore/platform/graphics/android/GaneshContext.cpp @@ -28,6 +28,8 @@ #include "GaneshContext.h" #include "GLUtils.h" +#include "android/native_window.h" + #if USE(ACCELERATED_COMPOSITING) #ifdef DEBUG @@ -49,9 +51,12 @@ namespace WebCore { GaneshContext::GaneshContext() : m_grContext(0) - , m_baseTileDevice(0) - , m_baseTileFbo(0) + , m_baseTileDeviceFBO(0) + , m_baseTileFBO(0) , m_baseTileStencil(0) + , m_baseTileDeviceSurface(0) + , m_surfaceConfig(0) + , m_surfaceContext(EGL_NO_CONTEXT) { } @@ -72,10 +77,130 @@ GrContext* GaneshContext::getGrContext() return m_grContext; } -SkDevice* GaneshContext::getDeviceForBaseTile(GLuint textureId) +void GaneshContext::flush() +{ + if (m_grContext) + m_grContext->flush(); +} + +SkDevice* GaneshContext::getDeviceForBaseTile(const TileRenderInfo& renderInfo) +{ + SkDevice* device = 0; + if (renderInfo.textureInfo->getSharedTextureMode() == SurfaceTextureMode) + device = getDeviceForBaseTileSurface(renderInfo); + else if (renderInfo.textureInfo->getSharedTextureMode() == EglImageMode) + device = getDeviceForBaseTileFBO(renderInfo); + + // TODO only need to reset if others are sharing our context + if (device) + getGrContext()->resetContext(); + + return device; +} + +SkDevice* GaneshContext::getDeviceForBaseTileSurface(const TileRenderInfo& renderInfo) +{ + EGLDisplay display = eglGetCurrentDisplay(); + GLUtils::checkEglError("eglGetCurrentDisplay"); + + if (!m_surfaceContext) { + + EGLint numConfigs; + static const EGLint configAttribs[] = { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + + eglChooseConfig(display, configAttribs, &m_surfaceConfig, 1, &numConfigs); + GLUtils::checkEglError("eglChooseConfig"); + + static const EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + m_surfaceContext = eglCreateContext(display, m_surfaceConfig, NULL, contextAttribs); + GLUtils::checkEglError("eglCreateContext"); + } + + if (renderInfo.textureInfo->m_eglSurface == EGL_NO_SURFACE) { + + const float tileWidth = renderInfo.tileSize.width(); + const float tileHeight = renderInfo.tileSize.height(); + ANativeWindow* anw = renderInfo.textureInfo->m_ANW.get(); + + int result = ANativeWindow_setBuffersGeometry(anw, (int)tileWidth, + (int)tileHeight, WINDOW_FORMAT_RGBA_8888); + + renderInfo.textureInfo->m_width = tileWidth; + renderInfo.textureInfo->m_height = tileHeight; + renderInfo.textureInfo->m_eglSurface = eglCreateWindowSurface(display, m_surfaceConfig, anw, NULL); + + GLUtils::checkEglError("eglCreateWindowSurface"); + XLOG("eglCreateWindowSurface"); + } + + EGLBoolean returnValue = eglMakeCurrent(display, renderInfo.textureInfo->m_eglSurface, renderInfo.textureInfo->m_eglSurface, m_surfaceContext); + GLUtils::checkEglError("eglMakeCurrent", returnValue); + XLOG("eglMakeCurrent"); + + if (!m_baseTileDeviceSurface) { + + GrPlatformSurfaceDesc surfaceDesc; + surfaceDesc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; + surfaceDesc.fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; + surfaceDesc.fWidth = TilesManager::tileWidth(); + surfaceDesc.fHeight = TilesManager::tileHeight(); + surfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; + surfaceDesc.fStencilBits = 8; + surfaceDesc.fPlatformRenderTarget = 0; + + GrContext* grContext = getGrContext(); + GrRenderTarget* renderTarget = (GrRenderTarget*) grContext->createPlatformSurface(surfaceDesc); + + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, + renderInfo.tileSize.width(), + renderInfo.tileSize.height()); + + m_baseTileDeviceSurface = new SkGpuDevice(grContext, bitmap, renderTarget); + renderTarget->unref(); + XLOG("generated device %p", m_baseTileDeviceSurface); + } + + GLUtils::checkGlError("getDeviceForBaseTile"); + return m_baseTileDeviceSurface; +} + +SkDevice* GaneshContext::getDeviceForBaseTileFBO(const TileRenderInfo& renderInfo) { - if (!m_baseTileFbo) { - glGenFramebuffers(1, &m_baseTileFbo); + const GLuint textureId = renderInfo.textureInfo->m_textureId; + const float tileWidth = renderInfo.tileSize.width(); + const float tileHeight = renderInfo.tileSize.height(); + + // bind to the current texture + glBindTexture(GL_TEXTURE_2D, textureId); + + // setup the texture if needed + if (renderInfo.textureInfo->m_width != tileWidth + || renderInfo.textureInfo->m_height != tileHeight) { + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tileWidth, tileHeight, + 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + renderInfo.textureInfo->m_width = tileWidth; + renderInfo.textureInfo->m_height = tileHeight; + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (!m_baseTileFBO) { + glGenFramebuffers(1, &m_baseTileFBO); XLOG("generated FBO"); } @@ -90,20 +215,21 @@ SkDevice* GaneshContext::getDeviceForBaseTile(GLuint textureId) XLOG("generated stencil"); } - glBindFramebuffer(GL_FRAMEBUFFER, m_baseTileFbo); + // bind the FBO and attach the texture and stencil + glBindFramebuffer(GL_FRAMEBUFFER, m_baseTileFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_baseTileStencil); - if (!m_baseTileDevice) { + if (!m_baseTileDeviceFBO) { GrPlatformSurfaceDesc surfaceDesc; surfaceDesc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; surfaceDesc.fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; surfaceDesc.fWidth = TilesManager::tileWidth(); - surfaceDesc.fHeight = TilesManager::tileWidth(); + surfaceDesc.fHeight = TilesManager::tileHeight(); surfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; surfaceDesc.fStencilBits = 8; - surfaceDesc.fPlatformRenderTarget = m_baseTileFbo; + surfaceDesc.fPlatformRenderTarget = m_baseTileFBO; GrContext* grContext = getGrContext(); GrRenderTarget* renderTarget = (GrRenderTarget*) grContext->createPlatformSurface(surfaceDesc); @@ -112,17 +238,16 @@ SkDevice* GaneshContext::getDeviceForBaseTile(GLuint textureId) bitmap.setConfig(SkBitmap::kARGB_8888_Config, TilesManager::tileWidth(), TilesManager::tileWidth()); - m_baseTileDevice = new SkGpuDevice(grContext, bitmap, renderTarget); + m_baseTileDeviceFBO = new SkGpuDevice(grContext, bitmap, renderTarget); renderTarget->unref(); - XLOG("generated device %p", m_baseTileDevice); + XLOG("generated device %p", m_baseTileDeviceFBO); } GLUtils::checkGlError("getDeviceForBaseTile"); - return m_baseTileDevice; + return m_baseTileDeviceFBO; } - } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/GaneshContext.h b/Source/WebCore/platform/graphics/android/GaneshContext.h index 9d90b96..12ea92d 100644 --- a/Source/WebCore/platform/graphics/android/GaneshContext.h +++ b/Source/WebCore/platform/graphics/android/GaneshContext.h @@ -28,6 +28,7 @@ #if USE(ACCELERATED_COMPOSITING) +#include "BaseRenderer.h" #include "GrContext.h" #include "SkGpuDevice.h" #include "TilesManager.h" @@ -38,19 +39,33 @@ class GaneshContext { public: static GaneshContext* instance(); - GrContext* getGrContext(); + SkDevice* getDeviceForBaseTile(const TileRenderInfo& renderInfo); - SkDevice* getDeviceForBaseTile(GLuint textureId); + void flush(); private: GaneshContext(); + GrContext* getGrContext(); + + // Creates a device for rendering into a SurfaceTexture via an EGLSurface + SkDevice* getDeviceForBaseTileSurface(const TileRenderInfo& renderInfo); + // Creates a device for rendering into a EGLImage via an FBO + SkDevice* getDeviceForBaseTileFBO(const TileRenderInfo& renderInfo); + GrContext* m_grContext; - SkGpuDevice* m_baseTileDevice; - GLuint m_baseTileFbo; + + // FBO specific variables + SkGpuDevice* m_baseTileDeviceFBO; + GLuint m_baseTileFBO; GLuint m_baseTileStencil; + // Surface specific variables + SkGpuDevice* m_baseTileDeviceSurface; + EGLConfig m_surfaceConfig; + EGLContext m_surfaceContext; + static GaneshContext* gInstance; }; diff --git a/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp index fcb0675..8f4d0b3 100644 --- a/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/GaneshRenderer.cpp @@ -34,12 +34,12 @@ #include "SkGpuDevice.h" #include "TilesManager.h" -#include #ifdef DEBUG #include #include +#include #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GaneshRenderer", __VA_ARGS__) @@ -63,7 +63,7 @@ static const String TAGS[] = { TAG_UPDATE_TEXTURE, }; -GaneshRenderer::GaneshRenderer() : BaseRenderer(BaseRenderer::Raster) +GaneshRenderer::GaneshRenderer() : BaseRenderer(BaseRenderer::Ganesh) { #ifdef DEBUG_COUNT ClassTracker::instance()->increment("GaneshRenderer"); @@ -82,37 +82,17 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can if (renderInfo.measurePerf) m_perfMon.start(TAG_CREATE_FBO); - const float tileWidth = renderInfo.tileSize.width(); - const float tileHeight = renderInfo.tileSize.height(); - - glBindTexture(GL_TEXTURE_2D, renderInfo.textureInfo->m_textureId); - - // setup the texture if needed - if (renderInfo.textureInfo->m_width != tileWidth - || renderInfo.textureInfo->m_height != tileHeight) { - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tileWidth, tileHeight, - 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - renderInfo.textureInfo->m_width = tileWidth; - renderInfo.textureInfo->m_height = tileHeight; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - GaneshContext* ganesh = GaneshContext::instance(); - // TODO only need to reset if others are sharing our context - ganesh->getGrContext()->resetContext(); - SkDevice* device = NULL; - if (tileWidth == TilesManager::tileWidth() && tileHeight == TilesManager::tileHeight()) { - device = ganesh->getDeviceForBaseTile(renderInfo.textureInfo->m_textureId); + if (renderInfo.tileSize.width() == TilesManager::tileWidth() + && renderInfo.tileSize.height() == TilesManager::tileHeight()) { + device = ganesh->getDeviceForBaseTile(renderInfo); } else { // TODO support arbitrary sizes for layers XLOG("ERROR: expected (%d,%d) actual (%d,%d)", TilesManager::tileWidth(), TilesManager::tileHeight(), - tileWidth, tileHeight); + renderInfo.tileSize.width(), renderInfo.tileSize.height()); } if (renderInfo.measurePerf) { @@ -124,8 +104,10 @@ void GaneshRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can canvas->setDevice(device); // invert canvas contents - canvas->scale(SK_Scalar1, -SK_Scalar1); - canvas->translate(0, -SkIntToScalar(renderInfo.tileSize.height())); + if (renderInfo.textureInfo->getSharedTextureMode() == EglImageMode) { + canvas->scale(SK_Scalar1, -SK_Scalar1); + canvas->translate(0, -renderInfo.tileSize.height()); + } } void GaneshRenderer::setupPartialInval(const TileRenderInfo& renderInfo, SkCanvas* canvas) @@ -145,9 +127,15 @@ void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva m_perfMon.start(TAG_UPDATE_TEXTURE); } - GaneshContext::instance()->getGrContext()->flush(); + XLOG("rendered to tile (%d,%d)", renderInfo.x, renderInfo.y); + + GaneshContext::instance()->flush(); - //TODO if texture is surfaceTexture then... + // In SurfaceTextureMode we must call swapBuffers to unlock and post the + // tile's ANativeWindow (i.e. SurfaceTexture) buffer + if (renderInfo.textureInfo->getSharedTextureMode() == SurfaceTextureMode) { + eglSwapBuffers(eglGetCurrentDisplay(), renderInfo.textureInfo->m_eglSurface); + } if (renderInfo.measurePerf) m_perfMon.stop(TAG_UPDATE_TEXTURE); diff --git a/Source/WebCore/platform/graphics/android/SharedTexture.cpp b/Source/WebCore/platform/graphics/android/SharedTexture.cpp index 4f52107..a7d43b5 100644 --- a/Source/WebCore/platform/graphics/android/SharedTexture.cpp +++ b/Source/WebCore/platform/graphics/android/SharedTexture.cpp @@ -60,11 +60,9 @@ SharedTexture::SharedTexture(SharedTextureMode mode) glGenTextures(1, &m_sourceTexture->m_textureId); m_sourceTexture->m_surfaceTexture = - new android::SurfaceTexture(m_sourceTexture->m_textureId); + new android::SurfaceTexture(m_sourceTexture->m_textureId, false); m_sourceTexture->m_ANW = new android::SurfaceTextureClient(m_sourceTexture->m_surfaceTexture); - - m_sourceTexture->m_surfaceTexture->setSynchronousMode(false); } } diff --git a/Source/WebCore/platform/graphics/android/TextureInfo.cpp b/Source/WebCore/platform/graphics/android/TextureInfo.cpp index 849e6fc..5db1711 100644 --- a/Source/WebCore/platform/graphics/android/TextureInfo.cpp +++ b/Source/WebCore/platform/graphics/android/TextureInfo.cpp @@ -42,6 +42,7 @@ TextureInfo::TextureInfo(SharedTextureMode mode) m_height = 0; m_internalFormat = 0; m_sharedTextureMode = mode; + m_eglSurface = EGL_NO_SURFACE; } bool TextureInfo::equalsAttributes(const TextureInfo* otherTexture) diff --git a/Source/WebCore/platform/graphics/android/TextureInfo.h b/Source/WebCore/platform/graphics/android/TextureInfo.h index 252d288..c1cb1cd 100644 --- a/Source/WebCore/platform/graphics/android/TextureInfo.h +++ b/Source/WebCore/platform/graphics/android/TextureInfo.h @@ -26,6 +26,7 @@ #ifndef TextureInfo_h #define TextureInfo_h +#include #include #include #include @@ -70,6 +71,9 @@ public: sp m_surfaceTexture; sp m_ANW; + // The EGLSurface wraps the m_ANW to enable direct OpenGL rendering (e.g. Ganesh) + EGLSurface m_eglSurface; + private: SharedTextureMode m_sharedTextureMode; }; -- cgit v1.1