Home | History | Annotate | Download | only in android
      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