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#define LOG_TAG "GaneshContext"
27#define LOG_NDEBUG 1
28
29#include "config.h"
30#include "GaneshContext.h"
31
32#include "AndroidLog.h"
33#include "GLUtils.h"
34#include "TextureInfo.h"
35#include "TilesManager.h"
36#include "TransferQueue.h"
37
38#include "android/native_window.h"
39
40#if USE(ACCELERATED_COMPOSITING)
41
42namespace WebCore {
43
44GaneshContext::GaneshContext()
45    : m_grContext(0)
46    , m_tileDeviceSurface(0)
47    , m_surfaceConfig(0)
48    , m_surfaceContext(EGL_NO_CONTEXT)
49{
50}
51
52GaneshContext* GaneshContext::gInstance = 0;
53
54GaneshContext* GaneshContext::instance()
55{
56    if (!gInstance)
57        gInstance = new GaneshContext();
58    return gInstance;
59}
60
61GrContext* GaneshContext::getGrContext()
62{
63    if (!m_grContext)
64        m_grContext = GrContext::Create(kOpenGL_Shaders_GrEngine, 0);
65    return m_grContext;
66}
67
68void GaneshContext::flush()
69{
70    if (m_grContext)
71        m_grContext->flush();
72}
73
74SkDevice* GaneshContext::getDeviceForTile(const TileRenderInfo& renderInfo)
75{
76    // Ganesh should be the only code in the rendering thread that is using GL
77    // and setting the EGLContext.  If this is not the case then we need to
78    // reset the Ganesh context to prevent rendering issues.
79    bool contextNeedsReset = false;
80    if (eglGetCurrentContext() != m_surfaceContext) {
81        ALOGV("Warning: EGLContext has Changed! %p, %p",
82              m_surfaceContext, eglGetCurrentContext());
83        contextNeedsReset = true;
84    }
85
86    EGLDisplay display;
87
88    if (!m_surfaceContext) {
89
90        if(eglGetCurrentContext() != EGL_NO_CONTEXT)
91            ALOGV("ERROR: should not have a context yet");
92
93        display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
94        GLUtils::checkEglError("eglGetDisplay");
95
96        EGLint majorVersion;
97        EGLint minorVersion;
98        EGLBoolean returnValue = eglInitialize(display, &majorVersion, &minorVersion);
99        GLUtils::checkEglError("eglInitialize", returnValue);
100
101        EGLint numConfigs;
102        static const EGLint configAttribs[] = {
103            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
104            EGL_RED_SIZE, 8,
105            EGL_GREEN_SIZE, 8,
106            EGL_BLUE_SIZE, 8,
107            EGL_ALPHA_SIZE, 8,
108            EGL_STENCIL_SIZE, 8,
109            EGL_NONE
110        };
111
112        eglChooseConfig(display, configAttribs, &m_surfaceConfig, 1, &numConfigs);
113        GLUtils::checkEglError("eglChooseConfig");
114
115        static const EGLint contextAttribs[] = {
116            EGL_CONTEXT_CLIENT_VERSION, 2,
117            EGL_NONE
118        };
119
120        m_surfaceContext = eglCreateContext(display, m_surfaceConfig, NULL, contextAttribs);
121        GLUtils::checkEglError("eglCreateContext");
122    } else {
123        display = eglGetCurrentDisplay();
124        GLUtils::checkEglError("eglGetCurrentDisplay");
125    }
126
127    TransferQueue* tileQueue = TilesManager::instance()->transferQueue();
128    if (tileQueue->m_eglSurface == EGL_NO_SURFACE) {
129
130        const float tileWidth = renderInfo.tileSize.width();
131        const float tileHeight = renderInfo.tileSize.height();
132
133        ANativeWindow* anw = tileQueue->m_ANW.get();
134
135        int result = ANativeWindow_setBuffersGeometry(anw, (int)tileWidth,
136                (int)tileHeight, WINDOW_FORMAT_RGBA_8888);
137
138        renderInfo.textureInfo->m_width = tileWidth;
139        renderInfo.textureInfo->m_height = tileHeight;
140        tileQueue->m_eglSurface = eglCreateWindowSurface(display, m_surfaceConfig, anw, NULL);
141
142        GLUtils::checkEglError("eglCreateWindowSurface");
143        ALOGV("eglCreateWindowSurface");
144    }
145
146    EGLBoolean returnValue = eglMakeCurrent(display, tileQueue->m_eglSurface, tileQueue->m_eglSurface, m_surfaceContext);
147    GLUtils::checkEglError("eglMakeCurrent", returnValue);
148    ALOGV("eglMakeCurrent");
149
150    if (!m_tileDeviceSurface) {
151
152        GrPlatformRenderTargetDesc renderTargetDesc;
153        renderTargetDesc.fWidth = TilesManager::tileWidth();
154        renderTargetDesc.fHeight = TilesManager::tileHeight();
155        renderTargetDesc.fConfig = kRGBA_8888_PM_GrPixelConfig;
156        renderTargetDesc.fSampleCnt = 0;
157        renderTargetDesc.fStencilBits = 8;
158        renderTargetDesc.fRenderTargetHandle = 0;
159
160        GrContext* grContext = getGrContext();
161        GrRenderTarget* renderTarget = grContext->createPlatformRenderTarget(renderTargetDesc);
162
163        m_tileDeviceSurface = new SkGpuDevice(grContext, renderTarget);
164        renderTarget->unref();
165        ALOGV("generated device %p", m_tileDeviceSurface);
166    }
167
168    GLUtils::checkGlError("getDeviceForTile");
169
170    // We must reset the Ganesh context only after we are sure we have
171    // re-established our EGLContext as the current context.
172    if (m_tileDeviceSurface && contextNeedsReset)
173        getGrContext()->resetContext();
174
175    return m_tileDeviceSurface;
176}
177
178
179
180} // namespace WebCore
181
182#endif // USE(ACCELERATED_COMPOSITING)
183