Fix the EGL_NON_CONFORMANT_CONFIG issue
[framework/web/webkit-efl.git] / Source / WebCore / platform / graphics / efl / tizen / SharedPlatformSurfaceTizen.cpp
1 /*
2  * Copyright (C) 2012 Samsung Electronics. 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY 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 #include "config.h"
27
28 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
29 #include "SharedPlatformSurfaceTizen.h"
30 #include "PixmapContextTizen.h"
31
32 #include "NotImplemented.h"
33
34 #include <EGL/egl.h>
35 #include <EGL/eglext.h>
36 #include <wtf/HashMap.h>
37 #include <wtf/OwnPtr.h>
38 #include <wtf/RefCounted.h>
39 #include <wtf/StdLibExtras.h>
40 #include <X11/Xlib.h>
41 #include <X11/Xutil.h>
42
43 #include <stdio.h>
44
45 static PFNEGLLOCKSURFACEKHRPROC eglLockSurfaceKHR = 0;
46 static PFNEGLUNLOCKSURFACEKHRPROC eglUnlockSurfaceKHR = 0;
47
48 namespace WebCore {
49
50 Display* g_nativeDisplay;
51 int g_nativeWindow;
52 class PixmapContextPool {
53 protected:
54     PixmapContextPool(void);
55     virtual ~PixmapContextPool();
56 public:
57     static inline PixmapContextPool& getInstance()
58     {
59         static PixmapContextPool pixmapContextPool;
60         return pixmapContextPool;
61     }
62
63     PixmapContextTizen* getContext(bool isLockable, bool hasAlpha, bool hasDepth, bool hasStencil);
64
65 private:
66     typedef HashMap<int, RefPtr<PixmapContextTizen> > PixmapContextMap;
67     PixmapContextMap m_pixmapContexts;
68 };
69
70 PixmapContextPool::PixmapContextPool()
71 {
72     if (!g_nativeDisplay)
73         g_nativeDisplay = XOpenDisplay(0);
74     if (!g_nativeWindow)
75         g_nativeWindow = XCreateSimpleWindow(g_nativeDisplay, XDefaultRootWindow(g_nativeDisplay),
76                             0, 0, 1, 1, 0,
77                             BlackPixel(g_nativeDisplay, 0), WhitePixel(g_nativeDisplay, 0));
78     XFlush(g_nativeDisplay);
79 }
80
81 PixmapContextPool::~PixmapContextPool()
82 {
83     PixmapContextMap::iterator end = m_pixmapContexts.end();
84     for (PixmapContextMap::iterator iter = m_pixmapContexts.begin(); iter != end; ++iter) {
85         RefPtr<PixmapContextTizen> context = iter->second;
86         context.release();
87     }
88     m_pixmapContexts.clear();
89
90     if (g_nativeWindow) {
91         XDestroyWindow(g_nativeDisplay, g_nativeWindow);
92         g_nativeWindow = 0;
93     }
94 }
95
96 PixmapContextTizen* PixmapContextPool::getContext(bool isLockable, bool hasAlpha, bool hasDepth, bool hasStencil)
97 {
98     int contextId = ((isLockable) | (hasAlpha << 1) | (hasDepth << 2) | (hasStencil << 3));
99     RefPtr<PixmapContextTizen> pixmapContext = m_pixmapContexts.get(contextId);
100     if (!pixmapContext) {
101         pixmapContext = PixmapContextTizen::create(isLockable, hasAlpha, hasDepth, hasStencil);
102         if (pixmapContext)
103             m_pixmapContexts.add(contextId, pixmapContext);
104         else
105             return 0;
106     }
107     return pixmapContext.get();
108 }
109
110 PassRefPtr<PixmapContextTizen> PixmapContextTizen::create(bool isLockable, bool hasAlpha, bool hasDepth, bool hasStencil)
111 {
112     RefPtr<PixmapContextTizen> context = adoptRef(new PixmapContextTizen(isLockable, hasAlpha, hasDepth, hasStencil));
113     if (!context->initialize())
114         return 0;
115     return context.release();
116 }
117
118 void PixmapContextTizen::HandleEGLError(const char* name)
119 {
120     static const char* const egErrorStrings[] =
121     {
122         "EGL_SUCCESS",
123         "EGL_NOT_INITIALIZED",
124         "EGL_BAD_ACCESS",
125         "EGL_BAD_ALLOC",
126         "EGL_BAD_ATTRIBUTE",
127         "EGL_BAD_CONFIG",
128         "EGL_BAD_CONTEXT",
129         "EGL_BAD_CURRENT_SURFACE",
130         "EGL_BAD_DISPLAY",
131         "EGL_BAD_MATCH",
132         "EGL_BAD_NATIVE_PIXMAP",
133         "EGL_BAD_NATIVE_WINDOW",
134         "EGL_BAD_PARAMETER",
135         "EGL_BAD_SURFACE"
136     };
137
138     EGLint errorCode = eglGetError();
139
140     if (errorCode != EGL_SUCCESS)
141         TIZEN_LOGE("'%s' returned egl error '%s' (0x%x)", name, egErrorStrings[errorCode - EGL_SUCCESS], errorCode);
142 }
143
144 PixmapContextTizen::PixmapContextTizen(bool isLockable, bool hasAlpha, bool hasDepth, bool hasStencil)
145     : m_initialized(false)
146     , m_display(EGL_NO_DISPLAY)
147     , m_context(EGL_NO_CONTEXT)
148     , m_isLockable(isLockable)
149     , m_hasAlpha(hasAlpha)
150     , m_hasDepth(hasDepth)
151     , m_hasStencil(hasStencil)
152 {
153 }
154
155 PixmapContextTizen::~PixmapContextTizen()
156 {
157     if (m_context) {
158         eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
159         eglDestroyContext(m_display, m_context);
160         m_context = EGL_NO_CONTEXT;
161     }
162     m_display = 0;
163 }
164
165 bool PixmapContextTizen::initialize()
166 {
167     EGLint major, minor;
168     EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
169
170     m_display = eglGetDisplay(g_nativeDisplay);
171     if (m_display == EGL_NO_DISPLAY)
172         HandleEGLError("eglGetDisplay");
173
174     if (eglInitialize(m_display, &major, &minor) != EGL_TRUE)
175         HandleEGLError("eglInitialize");
176
177     EGLint configCount = 0;
178     int i = 0;
179     EGLint configAttribs[32];
180     configAttribs[i++] = EGL_LEVEL;
181     configAttribs[i++] = 0;
182     // FIXME : Create pixmap surface with RGB_565 when alpha is off. Graphics driver needs to be fixed first.
183     configAttribs[i++] = EGL_RED_SIZE;
184     configAttribs[i++] = 8;
185     configAttribs[i++] = EGL_GREEN_SIZE;
186     configAttribs[i++] = 8;
187     configAttribs[i++] = EGL_BLUE_SIZE;
188     configAttribs[i++] = 8;
189     configAttribs[i++] = EGL_ALPHA_SIZE;
190     if (m_hasAlpha)
191         configAttribs[i++] = 8;
192     else {
193         configAttribs[i++] = 0;
194         configAttribs[i++] = EGL_CONFIG_CAVEAT;
195         if (!strcmp(eglQueryString (m_display, EGL_VENDOR), "Imagination Technologies"))
196             configAttribs[i++] = EGL_NONE;
197         else
198             configAttribs[i++] = EGL_NON_CONFORMANT_CONFIG;
199     }
200
201     if (m_isLockable) {
202         configAttribs[i++] = EGL_MATCH_FORMAT_KHR;
203         // FIXME : This strcmp will be replaced.to the feature macro.
204         if (!strcmp(eglQueryString (m_display, EGL_VENDOR), "ARM"))
205             configAttribs[i++] = EGL_FORMAT_RGBA_8888_EXACT_KHR;
206         else if (!strcmp(eglQueryString (m_display, EGL_VENDOR), "Imagination Technologies"))
207             configAttribs[i++] = EGL_FORMAT_RGBA_8888_EXACT_KHR;
208         else
209             configAttribs[i++] = EGL_FORMAT_RGBA_8888_KHR;
210         configAttribs[i++] = EGL_SURFACE_TYPE;
211         configAttribs[i++] = EGL_PIXMAP_BIT | EGL_LOCK_SURFACE_BIT_KHR;
212         configAttribs[i++] = EGL_DEPTH_SIZE;
213         configAttribs[i++] = 0;
214         configAttribs[i++] = EGL_STENCIL_SIZE;
215         configAttribs[i++] = 0;
216     } else {
217         configAttribs[i++] = EGL_SURFACE_TYPE;
218         configAttribs[i++] = EGL_PIXMAP_BIT;
219         configAttribs[i++] = EGL_DEPTH_SIZE;
220         if (m_hasDepth)
221             configAttribs[i++] = 16;
222         else
223             configAttribs[i++] = 0;
224         configAttribs[i++] = EGL_STENCIL_SIZE;
225         if (m_hasStencil)
226             configAttribs[i++] = 8;
227         else
228             configAttribs[i++] = 0;
229     }
230     configAttribs[i++] = EGL_RENDERABLE_TYPE;
231     configAttribs[i++] = EGL_OPENGL_ES2_BIT;
232     configAttribs[i++] = EGL_NONE;
233
234     if (eglChooseConfig(m_display, configAttribs, &m_surfaceConfig, 1, &configCount) != EGL_TRUE) {
235         HandleEGLError("eglChooseConfig");
236         return false;
237     }
238     m_context = eglCreateContext(m_display, m_surfaceConfig, EGL_NO_CONTEXT, contextAttribs);
239     if( m_context == EGL_NO_CONTEXT) {
240         HandleEGLError("eglCreateContext");
241         return false;
242     }
243     return true;
244 }
245
246 bool PixmapContextTizen::makeCurrent(EGLSurface surface)
247 {
248     if (eglGetCurrentSurface(EGL_READ) == surface && eglGetCurrentSurface(EGL_DRAW) == surface && eglGetCurrentContext() == m_context)
249         return true;
250
251     if (eglMakeCurrent(m_display, surface, surface, m_context) != EGL_TRUE) {
252         HandleEGLError("eglMakeCurrent");
253         return false;
254     }
255     return true;
256 }
257
258 void* PixmapContextTizen::createSurface(int pixmapID)
259 {
260     EGLSurface surface = eglCreatePixmapSurface(m_display, m_surfaceConfig, pixmapID, NULL);
261     if (surface == EGL_NO_SURFACE)
262         HandleEGLError("eglCreatePixmapSurface");
263
264     return surface;
265 }
266
267 void PixmapContextTizen::destroySurface(EGLSurface surface)
268 {
269     if (surface) {
270         if (eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE)
271             HandleEGLError("eglMakeCurrent");
272         eglDestroySurface(m_display, surface);
273     }
274 }
275
276 bool PixmapContextTizen::lockSurface(EGLSurface surface)
277 {
278     EGLint lockAttrib[] = { EGL_LOCK_USAGE_HINT_KHR, EGL_WRITE_SURFACE_BIT_KHR, EGL_NONE };
279     if (!eglLockSurfaceKHR)
280         eglLockSurfaceKHR = (PFNEGLLOCKSURFACEKHRPROC)eglGetProcAddress("eglLockSurfaceKHR");
281
282     static bool needsMakeCurrent = strcmp(eglQueryString(m_display, EGL_VENDOR), "ARM") != 0;
283     if (needsMakeCurrent)
284         eglMakeCurrent(m_display, surface, surface, m_context);
285
286     if (eglLockSurfaceKHR(m_display, surface, lockAttrib) != EGL_TRUE) {
287         HandleEGLError("eglLockSurfaceKHR");
288         return false;
289     }
290     return true;
291 }
292
293 bool PixmapContextTizen::unlockSurface(EGLSurface surface)
294 {
295     if (!eglUnlockSurfaceKHR)
296         eglUnlockSurfaceKHR = (PFNEGLUNLOCKSURFACEKHRPROC)eglGetProcAddress("eglUnlockSurfaceKHR");
297     if (eglUnlockSurfaceKHR(m_display, surface) != EGL_TRUE) {
298         HandleEGLError("eglUnlockSurfaceKHR");
299         return false;
300     }
301     return true;
302 }
303
304 bool PixmapContextTizen::querySurface(EGLSurface surface, EGLint* value)
305 {
306     if (eglQuerySurface(m_display, surface, EGL_BITMAP_POINTER_KHR, value) != EGL_TRUE) {
307         HandleEGLError("eglQuerySurface");
308         return false;
309     }
310     return true;
311 }
312
313 int PixmapContextTizen::createPixmap(int width, int height)
314 {
315     // FIXME : Create 16 bit pixmap when alpha is off. Graphics driver needs to be fixed first.
316     int pix = XCreatePixmap(g_nativeDisplay, g_nativeWindow, width, height, 32);
317     XFlush(g_nativeDisplay);
318
319     return pix;
320 }
321
322 void PixmapContextTizen::freePixmap(int pixmap)
323 {
324     if (pixmap)
325         XFreePixmap(g_nativeDisplay, pixmap);
326 }
327
328 PassOwnPtr<SharedPlatformSurfaceTizen> SharedPlatformSurfaceTizen::create(const IntSize& size, bool lockable, bool hasAlpha, bool hasDepth, bool hasStencil, PixmapContextTizen* pixmapContext)
329 {
330     OwnPtr<SharedPlatformSurfaceTizen> pixmap = adoptPtr(new SharedPlatformSurfaceTizen(size, lockable, hasAlpha, hasDepth, hasStencil, pixmapContext));
331     if (!pixmap->initialize())
332         return nullptr;
333     return pixmap.release();
334 }
335
336 SharedPlatformSurfaceTizen::SharedPlatformSurfaceTizen(const IntSize& size, bool lockable, bool hasAlpha, bool hasDepth, bool hasStencil, PixmapContextTizen* pixmapContext)
337     : m_pixmap(0)
338     , m_size(size)
339     , m_surface(0)
340     , m_isLockable(lockable)
341     , m_hasAlpha(hasAlpha)
342     , m_hasDepth(hasDepth)
343     , m_hasStencil(hasStencil)
344     , m_isUsed(false)
345 {
346     m_pixmapContext = pixmapContext;
347 }
348
349 SharedPlatformSurfaceTizen::~SharedPlatformSurfaceTizen()
350 {
351     if (m_surface != EGL_NO_SURFACE) {
352         m_pixmapContext->destroySurface(m_surface);
353         m_surface = EGL_NO_SURFACE;
354     }
355     if (m_pixmap) {
356         m_pixmapContext->freePixmap(m_pixmap);
357         m_pixmap = 0;
358     }
359 }
360
361 bool SharedPlatformSurfaceTizen::initialize()
362 {
363     if (m_size.isEmpty())
364         return false;
365
366     if(!m_pixmapContext) {
367         PixmapContextPool& pixmapContextPool = PixmapContextPool::getInstance();
368         m_pixmapContext = pixmapContextPool.getContext(m_isLockable, m_hasAlpha, m_hasDepth, m_hasStencil);
369     }
370
371     if(!m_pixmapContext)
372         return false;
373
374     m_pixmap = m_pixmapContext->createPixmap(m_size.width(), m_size.height());
375     if (!m_pixmap)
376         return false;
377     m_surface = (void*)(m_pixmapContext->createSurface(m_pixmap));
378     if (m_surface == EGL_NO_SURFACE)
379         return false;
380     return true;
381 }
382
383 void* SharedPlatformSurfaceTizen::context()
384 {
385     return m_pixmapContext->context();
386 }
387
388 bool SharedPlatformSurfaceTizen::makeContextCurrent()
389 {
390     return m_pixmapContext->makeCurrent(m_surface);
391 }
392
393 bool SharedPlatformSurfaceTizen::lockSurface()
394 {
395     return m_pixmapContext->lockSurface(m_surface);
396 }
397
398 bool SharedPlatformSurfaceTizen::unlockSurface()
399 {
400     return m_pixmapContext->unlockSurface(m_surface);
401 }
402
403 bool SharedPlatformSurfaceTizen::querySurface(int* value)
404 {
405     int* value_local;
406     bool ret;
407
408     ret = m_pixmapContext->querySurface(m_surface, (EGLint*)&value_local);
409     *value = (int)value_local;
410
411     return ret;
412 }
413 }
414 #endif // ENABLE(TIZEN_ACCELERATED_COMPOSITING)