1 /* 2 * Copyright 2011, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 27 #include "config.h" 28 #include "GaneshContext.h" 29 #include "GLUtils.h" 30 31 #include "android/native_window.h" 32 33 #if USE(ACCELERATED_COMPOSITING) 34 35 #ifdef DEBUG 36 37 #include <cutils/log.h> 38 #include <wtf/CurrentTime.h> 39 40 #undef XLOG 41 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GaneshContext", __VA_ARGS__) 42 43 #else 44 45 #undef XLOG 46 #define XLOG(...) 47 48 #endif // DEBUG 49 50 namespace WebCore { 51 52 GaneshContext::GaneshContext() 53 : m_grContext(0) 54 , m_baseTileDeviceFBO(0) 55 , m_baseTileFBO(0) 56 , m_baseTileStencil(0) 57 , m_baseTileDeviceSurface(0) 58 , m_surfaceConfig(0) 59 , m_surfaceContext(EGL_NO_CONTEXT) 60 { 61 } 62 63 GaneshContext* GaneshContext::gInstance = 0; 64 65 GaneshContext* GaneshContext::instance() 66 { 67 if (!gInstance) 68 gInstance = new GaneshContext(); 69 return gInstance; 70 } 71 72 GrContext* GaneshContext::getGrContext() 73 { 74 if (!m_grContext) { 75 m_grContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL); 76 } 77 return m_grContext; 78 } 79 80 void GaneshContext::flush() 81 { 82 if (m_grContext) 83 m_grContext->flush(); 84 } 85 86 SkDevice* GaneshContext::getDeviceForBaseTile(const TileRenderInfo& renderInfo) 87 { 88 // Ganesh should be the only code in the rendering thread that is using GL 89 // and setting the EGLContext. If this is not the case then we need to 90 // reset the Ganesh context to prevent rendering issues. 91 bool contextNeedsReset = false; 92 if (eglGetCurrentContext() != m_surfaceContext) { 93 XLOG("Warning: EGLContext has Changed! %p, %p", m_surfaceContext, 94 eglGetCurrentContext()); 95 contextNeedsReset = true; 96 } 97 98 SkDevice* device = 0; 99 if (renderInfo.textureInfo->getSharedTextureMode() == SurfaceTextureMode) 100 device = getDeviceForBaseTileSurface(renderInfo); 101 else if (renderInfo.textureInfo->getSharedTextureMode() == EglImageMode) 102 device = getDeviceForBaseTileFBO(renderInfo); 103 104 // We must reset the Ganesh context only after we are sure we have 105 // re-established our EGLContext as the current context. 106 if (device && contextNeedsReset) 107 getGrContext()->resetContext(); 108 109 return device; 110 } 111 112 SkDevice* GaneshContext::getDeviceForBaseTileSurface(const TileRenderInfo& renderInfo) 113 { 114 EGLDisplay display; 115 116 if (!m_surfaceContext) { 117 118 if(eglGetCurrentContext() != EGL_NO_CONTEXT) { 119 XLOG("ERROR: should not have a context yet"); 120 } 121 122 display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 123 GLUtils::checkEglError("eglGetDisplay"); 124 125 EGLint majorVersion; 126 EGLint minorVersion; 127 EGLBoolean returnValue = eglInitialize(display, &majorVersion, &minorVersion); 128 GLUtils::checkEglError("eglInitialize", returnValue); 129 130 EGLint numConfigs; 131 static const EGLint configAttribs[] = { 132 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 133 EGL_RED_SIZE, 8, 134 EGL_GREEN_SIZE, 8, 135 EGL_BLUE_SIZE, 8, 136 EGL_ALPHA_SIZE, 8, 137 EGL_STENCIL_SIZE, 8, 138 EGL_NONE 139 }; 140 141 eglChooseConfig(display, configAttribs, &m_surfaceConfig, 1, &numConfigs); 142 GLUtils::checkEglError("eglChooseConfig"); 143 144 static const EGLint contextAttribs[] = { 145 EGL_CONTEXT_CLIENT_VERSION, 2, 146 EGL_NONE 147 }; 148 149 m_surfaceContext = eglCreateContext(display, m_surfaceConfig, NULL, contextAttribs); 150 GLUtils::checkEglError("eglCreateContext"); 151 } else { 152 display = eglGetCurrentDisplay(); 153 GLUtils::checkEglError("eglGetCurrentDisplay"); 154 } 155 156 TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); 157 158 if (tileQueue->m_eglSurface == EGL_NO_SURFACE) { 159 160 const float tileWidth = renderInfo.tileSize.width(); 161 const float tileHeight = renderInfo.tileSize.height(); 162 163 ANativeWindow* anw = tileQueue->m_ANW.get(); 164 165 int result = ANativeWindow_setBuffersGeometry(anw, (int)tileWidth, 166 (int)tileHeight, WINDOW_FORMAT_RGBA_8888); 167 168 renderInfo.textureInfo->m_width = tileWidth; 169 renderInfo.textureInfo->m_height = tileHeight; 170 tileQueue->m_eglSurface = eglCreateWindowSurface(display, m_surfaceConfig, anw, NULL); 171 172 GLUtils::checkEglError("eglCreateWindowSurface"); 173 XLOG("eglCreateWindowSurface"); 174 } 175 176 EGLBoolean returnValue = eglMakeCurrent(display, tileQueue->m_eglSurface, tileQueue->m_eglSurface, m_surfaceContext); 177 GLUtils::checkEglError("eglMakeCurrent", returnValue); 178 XLOG("eglMakeCurrent"); 179 180 if (!m_baseTileDeviceSurface) { 181 182 GrPlatformSurfaceDesc surfaceDesc; 183 surfaceDesc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; 184 surfaceDesc.fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; 185 surfaceDesc.fWidth = TilesManager::tileWidth(); 186 surfaceDesc.fHeight = TilesManager::tileHeight(); 187 surfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; 188 surfaceDesc.fStencilBits = 8; 189 surfaceDesc.fPlatformRenderTarget = 0; 190 191 GrContext* grContext = getGrContext(); 192 GrRenderTarget* renderTarget = (GrRenderTarget*) grContext->createPlatformSurface(surfaceDesc); 193 194 SkBitmap bitmap; 195 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 196 renderInfo.tileSize.width(), 197 renderInfo.tileSize.height()); 198 199 m_baseTileDeviceSurface = new SkGpuDevice(grContext, bitmap, renderTarget); 200 renderTarget->unref(); 201 XLOG("generated device %p", m_baseTileDeviceSurface); 202 } 203 204 GLUtils::checkGlError("getDeviceForBaseTile"); 205 return m_baseTileDeviceSurface; 206 } 207 208 SkDevice* GaneshContext::getDeviceForBaseTileFBO(const TileRenderInfo& renderInfo) 209 { 210 const GLuint textureId = renderInfo.textureInfo->m_textureId; 211 const float tileWidth = renderInfo.tileSize.width(); 212 const float tileHeight = renderInfo.tileSize.height(); 213 214 // bind to the current texture 215 glBindTexture(GL_TEXTURE_2D, textureId); 216 217 // setup the texture if needed 218 if (renderInfo.textureInfo->m_width != tileWidth 219 || renderInfo.textureInfo->m_height != tileHeight) { 220 221 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tileWidth, tileHeight, 222 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 223 renderInfo.textureInfo->m_width = tileWidth; 224 renderInfo.textureInfo->m_height = tileHeight; 225 226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 228 } 229 230 if (!m_baseTileFBO) { 231 glGenFramebuffers(1, &m_baseTileFBO); 232 XLOG("generated FBO"); 233 } 234 235 if (!m_baseTileStencil) { 236 glGenRenderbuffers(1, &m_baseTileStencil); 237 glBindRenderbuffer(GL_RENDERBUFFER, m_baseTileStencil); 238 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, 239 TilesManager::tileWidth(), 240 TilesManager::tileHeight()); 241 glClearStencil(0); 242 glClear(GL_STENCIL_BUFFER_BIT); 243 XLOG("generated stencil"); 244 } 245 246 // bind the FBO and attach the texture and stencil 247 glBindFramebuffer(GL_FRAMEBUFFER, m_baseTileFBO); 248 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); 249 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_baseTileStencil); 250 251 if (!m_baseTileDeviceFBO) { 252 253 GrPlatformSurfaceDesc surfaceDesc; 254 surfaceDesc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; 255 surfaceDesc.fRenderTargetFlags = kNone_GrPlatformRenderTargetFlagBit; 256 surfaceDesc.fWidth = TilesManager::tileWidth(); 257 surfaceDesc.fHeight = TilesManager::tileHeight(); 258 surfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; 259 surfaceDesc.fStencilBits = 8; 260 surfaceDesc.fPlatformRenderTarget = m_baseTileFBO; 261 262 GrContext* grContext = getGrContext(); 263 GrRenderTarget* renderTarget = (GrRenderTarget*) grContext->createPlatformSurface(surfaceDesc); 264 265 SkBitmap bitmap; 266 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 267 TilesManager::tileWidth(), TilesManager::tileWidth()); 268 269 m_baseTileDeviceFBO = new SkGpuDevice(grContext, bitmap, renderTarget); 270 renderTarget->unref(); 271 XLOG("generated device %p", m_baseTileDeviceFBO); 272 } 273 274 GLUtils::checkGlError("getDeviceForBaseTile"); 275 return m_baseTileDeviceFBO; 276 } 277 278 279 } // namespace WebCore 280 281 #endif // USE(ACCELERATED_COMPOSITING) 282