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