initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / openvg / EGLDisplayOpenVG.cpp
1 /*
2  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "EGLDisplayOpenVG.h"
22
23 #include "EGLUtils.h"
24 #include "IntSize.h"
25 #include "SurfaceOpenVG.h"
26
27 #include <wtf/Assertions.h>
28 #include <wtf/StdLibExtras.h>
29
30 namespace WebCore {
31
32 // Need to typedef this, otherwise DEFINE_STATIC_LOCAL() doesn't swallow it.
33 typedef HashMap<EGLDisplay, EGLDisplayOpenVG*> EGLDisplayManagerMap;
34
35 // File-static variables.
36 static EGLDisplayManagerMap& displayManagers()
37 {
38     DEFINE_STATIC_LOCAL(EGLDisplayManagerMap, managers, ());
39     return managers;
40 }
41
42 static EGLDisplayOpenVG* s_current = 0;
43
44 // Static class members.
45
46 SurfaceOpenVG* EGLDisplayOpenVG::currentSurface()
47 {
48     EGLDisplayManagerMap& managers = displayManagers();
49     EGLDisplay currentDisplay = eglGetCurrentDisplay();
50
51     if (currentDisplay == EGL_NO_DISPLAY || !managers.contains(currentDisplay))
52         return 0;
53
54     EGLDisplayOpenVG* displayManager = managers.get(currentDisplay);
55     EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
56
57     if (currentSurface == EGL_NO_SURFACE || !displayManager->m_platformSurfaces.contains(currentSurface))
58         return 0;
59
60     return displayManager->m_platformSurfaces.get(currentSurface);
61 }
62
63 void EGLDisplayOpenVG::registerPlatformSurface(SurfaceOpenVG* platformSurface)
64 {
65     EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
66     displayManager->m_platformSurfaces.set(platformSurface->eglSurface(), platformSurface);
67 }
68
69 void EGLDisplayOpenVG::unregisterPlatformSurface(SurfaceOpenVG* platformSurface)
70 {
71     EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
72     displayManager->m_platformSurfaces.remove(platformSurface->eglSurface());
73 }
74
75 void EGLDisplayOpenVG::setCurrentDisplay(const EGLDisplay& display)
76 {
77     s_current = EGLDisplayOpenVG::forDisplay(display);
78 }
79
80 EGLDisplayOpenVG* EGLDisplayOpenVG::current()
81 {
82     if (!s_current) {
83         EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
84         eglInitialize(display, 0, 0);
85         ASSERT_EGL_NO_ERROR();
86
87         s_current = EGLDisplayOpenVG::forDisplay(display);
88     }
89     return s_current;
90 }
91
92 EGLDisplayOpenVG* EGLDisplayOpenVG::forDisplay(const EGLDisplay& display)
93 {
94     EGLDisplayManagerMap& managers = displayManagers();
95
96     if (!managers.contains(display))
97         managers.set(display, new EGLDisplayOpenVG(display));
98
99     return managers.get(display);
100 }
101
102
103 // Object/instance members.
104
105 EGLDisplayOpenVG::EGLDisplayOpenVG(const EGLDisplay& display)
106     : m_display(display)
107     , m_sharedPlatformSurface(0)
108     , m_pbufferConfigId(0)
109     , m_windowConfigId(0)
110 {
111     eglBindAPI(EGL_OPENVG_API);
112     ASSERT_EGL_NO_ERROR();
113 }
114
115 EGLDisplayOpenVG::~EGLDisplayOpenVG()
116 {
117     eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
118     ASSERT_EGL_NO_ERROR();
119
120     delete m_sharedPlatformSurface;
121
122     HashMap<EGLSurface, EGLint>::const_iterator end = m_surfaceConfigIds.end();
123     for (HashMap<EGLSurface, EGLint>::const_iterator it = m_surfaceConfigIds.begin(); it != end; ++it)
124         destroySurface((*it).first);
125
126     eglTerminate(m_display);
127     ASSERT_EGL_NO_ERROR();
128 }
129
130 void EGLDisplayOpenVG::setDefaultPbufferConfig(const EGLConfig& config)
131 {
132     EGLint configId;
133     EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
134     ASSERT(success == EGL_TRUE);
135     ASSERT(configId != EGL_BAD_ATTRIBUTE);
136
137     m_pbufferConfigId = configId;
138 }
139
140 EGLConfig EGLDisplayOpenVG::defaultPbufferConfig()
141 {
142     EGLConfig config;
143     EGLint numConfigs;
144
145     // Hopefully the client will have set the pbuffer config of its choice
146     // by now - if not, use a 32-bit generic one as default.
147     if (!m_pbufferConfigId) {
148         static const EGLint configAttribs[] = {
149             EGL_RED_SIZE, 8,
150             EGL_GREEN_SIZE, 8,
151             EGL_BLUE_SIZE, 8,
152             EGL_ALPHA_SIZE, 8,
153             EGL_ALPHA_MASK_SIZE, 1,
154             EGL_LUMINANCE_SIZE, EGL_DONT_CARE,
155             EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
156             EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
157             EGL_NONE
158         };
159         eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
160     } else {
161         const EGLint configAttribs[] = {
162             EGL_CONFIG_ID, m_pbufferConfigId,
163             EGL_NONE
164         };
165         eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
166     }
167
168     ASSERT_EGL_NO_ERROR();
169     ASSERT(numConfigs == 1);
170     return config;
171 }
172
173 void EGLDisplayOpenVG::setDefaultWindowConfig(const EGLConfig& config)
174 {
175     EGLint configId;
176     EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
177     ASSERT(success == EGL_TRUE);
178     ASSERT(configId != EGL_BAD_ATTRIBUTE);
179
180     m_windowConfigId = configId;
181 }
182
183 EGLConfig EGLDisplayOpenVG::defaultWindowConfig()
184 {
185     EGLConfig config;
186     EGLint numConfigs;
187
188     // Hopefully the client will have set the window config of its choice
189     // by now - if not, use a 32-bit generic one as default.
190     if (!m_windowConfigId) {
191         static const EGLint configAttribs[] = {
192             EGL_RED_SIZE, 8,
193             EGL_GREEN_SIZE, 8,
194             EGL_BLUE_SIZE, 8,
195             EGL_ALPHA_SIZE, 8,
196             EGL_ALPHA_MASK_SIZE, 1,
197             EGL_LUMINANCE_SIZE, EGL_DONT_CARE,
198             EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
199             EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
200             EGL_NONE
201         };
202         eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
203     } else {
204         const EGLint configAttribs[] = {
205             EGL_CONFIG_ID, m_windowConfigId,
206             EGL_NONE
207         };
208         eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
209     }
210
211     ASSERT_EGL_NO_ERROR();
212     ASSERT(numConfigs == 1);
213     return config;
214 }
215
216 SurfaceOpenVG* EGLDisplayOpenVG::sharedPlatformSurface()
217 {
218     if (!m_sharedPlatformSurface) {
219         // The shared surface doesn't need to be drawn on, it just exists so
220         // that we can always make the shared context current (which in turn is
221         // the owner of long-living resources such as images, paths and fonts).
222         // We'll just make the shared surface as small as possible: 1x1 pixel.
223         EGLConfig config = defaultPbufferConfig();
224         EGLSurface surface = createPbufferSurface(IntSize(1, 1), config);
225
226         EGLContext context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, 0);
227         ASSERT_EGL_NO_ERROR();
228         m_contexts.set(m_surfaceConfigIds.get(surface), context);
229
230         m_sharedPlatformSurface = new SurfaceOpenVG;
231         m_sharedPlatformSurface->m_eglDisplay = m_display;
232         m_sharedPlatformSurface->m_eglSurface = surface;
233         m_sharedPlatformSurface->m_eglContext = context;
234         m_platformSurfaces.set(surface, m_sharedPlatformSurface); // a.k.a. registerPlatformSurface()
235     }
236     return m_sharedPlatformSurface;
237 }
238
239 EGLSurface EGLDisplayOpenVG::createPbufferSurface(const IntSize& size, const EGLConfig& config, EGLint* errorCode)
240 {
241     const EGLint attribList[] = {
242         EGL_WIDTH, size.width(),
243         EGL_HEIGHT, size.height(),
244         EGL_NONE
245     };
246     EGLSurface surface = eglCreatePbufferSurface(m_display, config, attribList);
247
248     if (errorCode)
249         *errorCode = eglGetError();
250     else
251         ASSERT_EGL_NO_ERROR();
252
253     if (surface == EGL_NO_SURFACE)
254         return EGL_NO_SURFACE;
255
256     EGLint surfaceConfigId;
257     EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
258     ASSERT(success == EGL_TRUE);
259     ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
260
261     ASSERT(!m_surfaceConfigIds.contains(surface));
262     m_surfaceConfigIds.set(surface, surfaceConfigId);
263     return surface;
264 }
265
266 EGLSurface EGLDisplayOpenVG::createPbufferFromClientBuffer(
267     EGLClientBuffer clientBuffer, EGLenum bufferType, const EGLConfig& config, EGLint* errorCode)
268 {
269     EGLSurface surface = eglCreatePbufferFromClientBuffer(m_display,
270         bufferType, clientBuffer, config, 0 /* attribList */);
271
272     if (errorCode)
273         *errorCode = eglGetError();
274     else
275         ASSERT_EGL_NO_ERROR();
276
277     if (surface == EGL_NO_SURFACE)
278         return EGL_NO_SURFACE;
279
280     EGLint surfaceConfigId;
281     EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
282     ASSERT(success == EGL_TRUE);
283     ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
284
285     ASSERT(!m_surfaceConfigIds.contains(surface));
286     m_surfaceConfigIds.set(surface, surfaceConfigId);
287     return surface;
288 }
289
290 EGLSurface EGLDisplayOpenVG::surfaceForWindow(EGLNativeWindowType wId, const EGLConfig& config)
291 {
292     if (m_windowSurfaces.contains(wId))
293         return m_windowSurfaces.get(wId);
294
295     EGLSurface surface = eglCreateWindowSurface(m_display, config, wId, 0);
296     ASSERT_EGL_NO_ERROR();
297
298     EGLint surfaceConfigId;
299     EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &surfaceConfigId);
300     ASSERT(success == EGL_TRUE);
301     ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
302
303     ASSERT(!m_surfaceConfigIds.contains(surface));
304     m_surfaceConfigIds.set(surface, surfaceConfigId);
305     return surface;
306 }
307
308 bool EGLDisplayOpenVG::surfacesCompatible(const EGLSurface& surface, const EGLSurface& otherSurface)
309 {
310     if (surface == EGL_NO_SURFACE || otherSurface == EGL_NO_SURFACE)
311         return false;
312
313     // Currently, we assume that all surfaces known to this object are
314     // context-compatible to each other (which is reasonable to assume,
315     // otherwise eglCreateContext() would fail with EGL_BAD_MATCH for shared
316     // context compatibility anyways.
317     return m_surfaceConfigIds.contains(surface) && m_surfaceConfigIds.contains(otherSurface);
318 }
319
320 void EGLDisplayOpenVG::destroySurface(const EGLSurface& surface)
321 {
322     ASSERT(surface != EGL_NO_SURFACE);
323
324     if (eglGetCurrentSurface(EGL_DRAW) == surface) {
325         eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
326         ASSERT_EGL_NO_ERROR();
327     }
328
329     // Destroy the context associated to the surface, if we already created one.
330     if (m_surfaceConfigIds.contains(surface)) {
331         EGLint surfaceConfigId = m_surfaceConfigIds.take(surface); // take = get and remove
332         bool isContextReferenced = false;
333
334         if (m_compatibleConfigIds.contains(surfaceConfigId))
335             surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
336
337         HashMap<EGLSurface, EGLint>::iterator end = m_surfaceConfigIds.end();
338
339         // ...but only if there's no other surfaces associated to that context.
340         for (HashMap<EGLSurface, EGLint>::iterator it = m_surfaceConfigIds.begin(); it != end; ++it) {
341             if ((*it).second == surfaceConfigId) {
342                 isContextReferenced = true;
343                 break;
344             }
345         }
346         if (!isContextReferenced && m_contexts.contains(surfaceConfigId)) {
347             EGLContext context = m_contexts.take(surfaceConfigId);
348             eglDestroyContext(m_display, context);
349             ASSERT_EGL_NO_ERROR();
350         }
351     }
352
353     m_platformSurfaces.remove(surface);
354
355     HashMap<EGLNativeWindowType, EGLSurface>::iterator end = m_windowSurfaces.end();
356     for (HashMap<EGLNativeWindowType, EGLSurface>::iterator it = m_windowSurfaces.begin(); it != end; ++it) {
357         if ((*it).second == surface) {
358             m_windowSurfaces.remove(it);
359             break;
360         }
361     }
362
363     eglDestroySurface(m_display, surface);
364     ASSERT_EGL_NO_ERROR();
365 }
366
367 EGLContext EGLDisplayOpenVG::contextForSurface(const EGLSurface& surface)
368 {
369     ASSERT(surface != EGL_NO_SURFACE);
370
371     if (m_platformSurfaces.contains(surface))
372         return m_platformSurfaces.get(surface)->eglContext();
373
374     eglBindAPI(EGL_OPENVG_API);
375     ASSERT_EGL_NO_ERROR();
376
377     EGLint surfaceConfigId;
378
379     if (m_surfaceConfigIds.contains(surface))
380         surfaceConfigId = m_surfaceConfigIds.get(surface);
381     else {
382         // Retrieve the same EGL config for context creation that was used to
383         // create the the EGL surface.
384         EGLBoolean success = eglQuerySurface(m_display, surface, EGL_CONFIG_ID, &surfaceConfigId);
385         ASSERT(success == EGL_TRUE);
386         ASSERT(surfaceConfigId != EGL_BAD_ATTRIBUTE);
387
388         m_surfaceConfigIds.set(surface, surfaceConfigId);
389     }
390
391     if (m_compatibleConfigIds.contains(surfaceConfigId))
392         surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
393
394     if (m_contexts.contains(surfaceConfigId))
395         return m_contexts.get(surfaceConfigId);
396
397     if (!m_sharedPlatformSurface) // shared context has not been created yet
398         sharedPlatformSurface(); // creates the shared surface & context
399
400     EGLDisplay currentDisplay = eglGetCurrentDisplay();
401     EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
402     EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
403     EGLContext currentContext = eglGetCurrentContext();
404
405     // Before creating a new context, let's try whether an existing one
406     // is compatible with the surface. EGL doesn't give us a different way
407     // to check context/surface compatibility than trying it out, so let's
408     // do just that.
409     HashMap<EGLint, EGLContext>::iterator end = m_contexts.end();
410
411     for (HashMap<EGLint, EGLContext>::iterator it = m_contexts.begin(); it != end; ++it) {
412         eglMakeCurrent(m_display, surface, surface, (*it).second);
413         if (eglGetError() == EGL_SUCCESS) {
414             // Restore previous surface/context.
415             if (currentContext != EGL_NO_CONTEXT) {
416                 eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
417                 ASSERT_EGL_NO_ERROR();
418             }
419             // Cool, surface is compatible to one of our existing contexts.
420             m_compatibleConfigIds.set(surfaceConfigId, (*it).first);
421             return (*it).second;
422         }
423     }
424     // Restore previous surface/context.
425     if (currentContext != EGL_NO_CONTEXT) {
426         eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
427         ASSERT_EGL_NO_ERROR();
428     }
429
430     EGLConfig config;
431     EGLint numConfigs;
432
433     const EGLint configAttribs[] = {
434         EGL_CONFIG_ID, surfaceConfigId,
435         EGL_NONE
436     };
437
438     eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
439     ASSERT_EGL_NO_ERROR();
440     ASSERT(numConfigs == 1);
441
442     // We share all of the images and paths amongst the different contexts,
443     // so that they can be used in all of them. Resources that are created
444     // while m_sharedPlatformSurface->context() is current will be
445     // accessible from all other contexts, but are not restricted to the
446     // lifetime of those contexts.
447     EGLContext context = eglCreateContext(m_display, config, m_sharedPlatformSurface->eglContext(), 0);
448     ASSERT_EGL_NO_ERROR();
449
450     ASSERT(!m_contexts.contains(surfaceConfigId));
451     m_contexts.set(surfaceConfigId, context);
452     return context;
453 }
454
455 }