1/*
2 * Copyright (C) 2012 Intel Corporation. All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. 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 APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if USE(3D_GRAPHICS)
29#include "GLPlatformContext.h"
30
31#if USE(GLX)
32#include "GLXContext.h"
33#elif USE(EGL)
34#include "EGLContext.h"
35#endif
36
37#include "NotImplemented.h"
38
39namespace WebCore {
40
41#if USE(OPENGL_ES_2)
42static PFNGLGETGRAPHICSRESETSTATUSEXTPROC glGetGraphicsResetStatus = 0;
43#else
44static PFNGLGETGRAPHICSRESETSTATUSARBPROC glGetGraphicsResetStatus = 0;
45#endif
46static GLPlatformContext* m_currentContext = 0;
47
48class GLCurrentContextWrapper : public GLPlatformContext {
49
50public:
51    GLCurrentContextWrapper()
52        : GLPlatformContext()
53    {
54#if USE(GLX)
55        m_contextHandle = glXGetCurrentContext();
56#elif USE(EGL)
57        m_contextHandle = eglGetCurrentContext();
58#endif
59        if (m_contextHandle)
60            m_currentContext = this;
61    }
62
63    virtual ~GLCurrentContextWrapper() { }
64};
65
66static std::unique_ptr<GLPlatformContext> createOffScreenContext()
67{
68#if USE(GLX)
69    return std::make_unique<GLXOffScreenContext>();
70#elif USE(EGL)
71    return std::make_unique<EGLOffScreenContext>();
72#else
73    return nullptr;
74#endif
75}
76
77static HashSet<String> parseExtensions(const String& extensionsString)
78{
79    Vector<String> extNames;
80    extensionsString.split(" ", extNames);
81    HashSet<String> splitExtNames;
82    unsigned size = extNames.size();
83    for (unsigned i = 0; i < size; ++i)
84        splitExtNames.add(extNames[i]);
85    extNames.clear();
86
87    return splitExtNames;
88}
89
90static void resolveResetStatusExtension()
91{
92    static bool resolvedRobustnessExtension = false;
93    if (!resolvedRobustnessExtension) {
94        resolvedRobustnessExtension = true;
95#if USE(OPENGL_ES_2)
96        glGetGraphicsResetStatus = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSEXTPROC>(eglGetProcAddress("glGetGraphicsResetStatusEXT"));
97#elif USE(EGL)
98        glGetGraphicsResetStatus = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSARBPROC>(eglGetProcAddress("glGetGraphicsResetStatusARB"));
99#elif USE(GLX)
100        glGetGraphicsResetStatus = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSARBPROC>(glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("glGetGraphicsResetStatusARB")));
101#endif
102    }
103}
104
105std::unique_ptr<GLPlatformContext> GLPlatformContext::createContext(GraphicsContext3D::RenderStyle renderStyle)
106{
107#if !USE(OPENGL_ES_2)
108    if (!initializeOpenGLShims())
109        return nullptr;
110#endif
111
112    switch (renderStyle) {
113    case GraphicsContext3D::RenderOffscreen:
114        return createOffScreenContext();
115    case GraphicsContext3D::RenderToCurrentGLContext:
116        return std::make_unique<GLCurrentContextWrapper>();
117    case GraphicsContext3D::RenderDirectlyToHostWindow:
118        ASSERT_NOT_REACHED();
119        break;
120    }
121
122    return nullptr;
123}
124
125bool GLPlatformContext::supportsGLExtension(const String& name)
126{
127    static HashSet<String> supportedExtensions;
128
129    if (!supportedExtensions.size()) {
130        String rawExtensions = reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS));
131        supportedExtensions = parseExtensions(rawExtensions);
132    }
133
134    if (supportedExtensions.contains(name))
135        return true;
136
137    return false;
138}
139
140#if USE(EGL)
141bool GLPlatformContext::supportsEGLExtension(EGLDisplay display, const String& name)
142{
143    static HashSet<String> supportedExtensions;
144
145    if (!supportedExtensions.size()) {
146        if (display == EGL_NO_DISPLAY)
147            return false;
148
149        String rawExtensions = reinterpret_cast<const char*>(eglQueryString(display, EGL_EXTENSIONS));
150        supportedExtensions = parseExtensions(rawExtensions);
151    }
152
153    if (supportedExtensions.contains(name))
154        return true;
155
156    return false;
157}
158#endif
159
160#if USE(GLX)
161bool GLPlatformContext::supportsGLXExtension(Display* display, const String& name)
162{
163    static HashSet<String> supportedExtensions;
164
165    if (!supportedExtensions.size()) {
166        if (!display)
167            return false;
168
169        String rawExtensions = glXQueryExtensionsString(display, DefaultScreen(display));
170        supportedExtensions = parseExtensions(rawExtensions);
171    }
172
173    if (supportedExtensions.contains(name))
174        return true;
175
176    return false;
177}
178#endif
179
180GLPlatformContext::GLPlatformContext()
181    : m_contextHandle(0)
182    , m_resetLostContext(false)
183{
184}
185
186GLPlatformContext::~GLPlatformContext()
187{
188    if (this == m_currentContext)
189        m_currentContext = 0;
190}
191
192bool GLPlatformContext::makeCurrent(GLPlatformSurface* surface)
193{
194    m_contextLost = false;
195
196    if (m_currentContext == this && (!surface || surface->isCurrentDrawable()))
197        return true;
198
199    m_currentContext = 0;
200
201    if (!surface || (surface && !surface->drawable()))
202        platformReleaseCurrent();
203    else if (platformMakeCurrent(surface)) {
204        m_currentContext = this;
205        surface->onMakeCurrent();
206    }
207
208    if (m_resetLostContext) {
209        resolveResetStatusExtension();
210
211        if (glGetGraphicsResetStatus) {
212            GLenum status = glGetGraphicsResetStatus();
213
214            switch (status) {
215            case PLATFORMCONTEXT_NO_ERROR:
216                break;
217            case PLATFORMCONTEXT_GUILTY_CONTEXT_RESET:
218                m_contextLost = true;
219                break;
220            case PLATFORMCONTEXT_INNOCENT_CONTEXT_RESET:
221                break;
222            case PLATFORMCONTEXT_UNKNOWN_CONTEXT_RESET:
223                m_contextLost = true;
224                break;
225            default:
226                break;
227            }
228        }
229    }
230
231    return m_currentContext;
232}
233
234bool GLPlatformContext::isValid() const
235{
236    return !m_contextLost;
237}
238
239void GLPlatformContext::releaseCurrent()
240{
241    if (this == m_currentContext) {
242        m_currentContext = 0;
243        platformReleaseCurrent();
244    }
245}
246
247PlatformContext GLPlatformContext::handle() const
248{
249    return m_contextHandle;
250}
251
252bool GLPlatformContext::isCurrentContext() const
253{
254    return true;
255}
256
257bool GLPlatformContext::initialize(GLPlatformSurface*, PlatformContext)
258{
259    return true;
260}
261
262GLPlatformContext* GLPlatformContext::getCurrent()
263{
264    return m_currentContext;
265}
266
267bool GLPlatformContext::platformMakeCurrent(GLPlatformSurface*)
268{
269    return true;
270}
271
272void GLPlatformContext::platformReleaseCurrent()
273{
274    notImplemented();
275}
276
277void GLPlatformContext::destroy()
278{
279    m_contextHandle = 0;
280    m_resetLostContext = false;
281}
282
283} // namespace WebCore
284
285#endif
286