2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
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.
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.
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.
21 #include "EGLDisplayOpenVG.h"
25 #include "SurfaceOpenVG.h"
27 #include <wtf/Assertions.h>
28 #include <wtf/StdLibExtras.h>
32 // Need to typedef this, otherwise DEFINE_STATIC_LOCAL() doesn't swallow it.
33 typedef HashMap<EGLDisplay, EGLDisplayOpenVG*> EGLDisplayManagerMap;
35 // File-static variables.
36 static EGLDisplayManagerMap& displayManagers()
38 DEFINE_STATIC_LOCAL(EGLDisplayManagerMap, managers, ());
42 static EGLDisplayOpenVG* s_current = 0;
44 // Static class members.
46 SurfaceOpenVG* EGLDisplayOpenVG::currentSurface()
48 EGLDisplayManagerMap& managers = displayManagers();
49 EGLDisplay currentDisplay = eglGetCurrentDisplay();
51 if (currentDisplay == EGL_NO_DISPLAY || !managers.contains(currentDisplay))
54 EGLDisplayOpenVG* displayManager = managers.get(currentDisplay);
55 EGLSurface currentSurface = eglGetCurrentSurface(EGL_DRAW);
57 if (currentSurface == EGL_NO_SURFACE || !displayManager->m_platformSurfaces.contains(currentSurface))
60 return displayManager->m_platformSurfaces.get(currentSurface);
63 void EGLDisplayOpenVG::registerPlatformSurface(SurfaceOpenVG* platformSurface)
65 EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
66 displayManager->m_platformSurfaces.set(platformSurface->eglSurface(), platformSurface);
69 void EGLDisplayOpenVG::unregisterPlatformSurface(SurfaceOpenVG* platformSurface)
71 EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
72 displayManager->m_platformSurfaces.remove(platformSurface->eglSurface());
75 void EGLDisplayOpenVG::setCurrentDisplay(const EGLDisplay& display)
77 s_current = EGLDisplayOpenVG::forDisplay(display);
80 EGLDisplayOpenVG* EGLDisplayOpenVG::current()
83 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
84 eglInitialize(display, 0, 0);
85 ASSERT_EGL_NO_ERROR();
87 s_current = EGLDisplayOpenVG::forDisplay(display);
92 EGLDisplayOpenVG* EGLDisplayOpenVG::forDisplay(const EGLDisplay& display)
94 EGLDisplayManagerMap& managers = displayManagers();
96 if (!managers.contains(display))
97 managers.set(display, new EGLDisplayOpenVG(display));
99 return managers.get(display);
103 // Object/instance members.
105 EGLDisplayOpenVG::EGLDisplayOpenVG(const EGLDisplay& display)
107 , m_sharedPlatformSurface(0)
108 , m_pbufferConfigId(0)
109 , m_windowConfigId(0)
111 eglBindAPI(EGL_OPENVG_API);
112 ASSERT_EGL_NO_ERROR();
115 EGLDisplayOpenVG::~EGLDisplayOpenVG()
117 eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
118 ASSERT_EGL_NO_ERROR();
120 delete m_sharedPlatformSurface;
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);
126 eglTerminate(m_display);
127 ASSERT_EGL_NO_ERROR();
130 void EGLDisplayOpenVG::setDefaultPbufferConfig(const EGLConfig& config)
133 EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
134 ASSERT(success == EGL_TRUE);
135 ASSERT(configId != EGL_BAD_ATTRIBUTE);
137 m_pbufferConfigId = configId;
140 EGLConfig EGLDisplayOpenVG::defaultPbufferConfig()
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[] = {
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,
159 eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
161 const EGLint configAttribs[] = {
162 EGL_CONFIG_ID, m_pbufferConfigId,
165 eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
168 ASSERT_EGL_NO_ERROR();
169 ASSERT(numConfigs == 1);
173 void EGLDisplayOpenVG::setDefaultWindowConfig(const EGLConfig& config)
176 EGLBoolean success = eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &configId);
177 ASSERT(success == EGL_TRUE);
178 ASSERT(configId != EGL_BAD_ATTRIBUTE);
180 m_windowConfigId = configId;
183 EGLConfig EGLDisplayOpenVG::defaultWindowConfig()
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[] = {
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,
202 eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
204 const EGLint configAttribs[] = {
205 EGL_CONFIG_ID, m_windowConfigId,
208 eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
211 ASSERT_EGL_NO_ERROR();
212 ASSERT(numConfigs == 1);
216 SurfaceOpenVG* EGLDisplayOpenVG::sharedPlatformSurface()
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);
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);
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()
236 return m_sharedPlatformSurface;
239 EGLSurface EGLDisplayOpenVG::createPbufferSurface(const IntSize& size, const EGLConfig& config, EGLint* errorCode)
241 const EGLint attribList[] = {
242 EGL_WIDTH, size.width(),
243 EGL_HEIGHT, size.height(),
246 EGLSurface surface = eglCreatePbufferSurface(m_display, config, attribList);
249 *errorCode = eglGetError();
251 ASSERT_EGL_NO_ERROR();
253 if (surface == EGL_NO_SURFACE)
254 return EGL_NO_SURFACE;
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);
261 ASSERT(!m_surfaceConfigIds.contains(surface));
262 m_surfaceConfigIds.set(surface, surfaceConfigId);
266 EGLSurface EGLDisplayOpenVG::createPbufferFromClientBuffer(
267 EGLClientBuffer clientBuffer, EGLenum bufferType, const EGLConfig& config, EGLint* errorCode)
269 EGLSurface surface = eglCreatePbufferFromClientBuffer(m_display,
270 bufferType, clientBuffer, config, 0 /* attribList */);
273 *errorCode = eglGetError();
275 ASSERT_EGL_NO_ERROR();
277 if (surface == EGL_NO_SURFACE)
278 return EGL_NO_SURFACE;
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);
285 ASSERT(!m_surfaceConfigIds.contains(surface));
286 m_surfaceConfigIds.set(surface, surfaceConfigId);
290 EGLSurface EGLDisplayOpenVG::surfaceForWindow(EGLNativeWindowType wId, const EGLConfig& config)
292 if (m_windowSurfaces.contains(wId))
293 return m_windowSurfaces.get(wId);
295 EGLSurface surface = eglCreateWindowSurface(m_display, config, wId, 0);
296 ASSERT_EGL_NO_ERROR();
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);
303 ASSERT(!m_surfaceConfigIds.contains(surface));
304 m_surfaceConfigIds.set(surface, surfaceConfigId);
308 bool EGLDisplayOpenVG::surfacesCompatible(const EGLSurface& surface, const EGLSurface& otherSurface)
310 if (surface == EGL_NO_SURFACE || otherSurface == EGL_NO_SURFACE)
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);
320 void EGLDisplayOpenVG::destroySurface(const EGLSurface& surface)
322 ASSERT(surface != EGL_NO_SURFACE);
324 if (eglGetCurrentSurface(EGL_DRAW) == surface) {
325 eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
326 ASSERT_EGL_NO_ERROR();
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;
334 if (m_compatibleConfigIds.contains(surfaceConfigId))
335 surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
337 HashMap<EGLSurface, EGLint>::iterator end = m_surfaceConfigIds.end();
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;
346 if (!isContextReferenced && m_contexts.contains(surfaceConfigId)) {
347 EGLContext context = m_contexts.take(surfaceConfigId);
348 eglDestroyContext(m_display, context);
349 ASSERT_EGL_NO_ERROR();
353 m_platformSurfaces.remove(surface);
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);
363 eglDestroySurface(m_display, surface);
364 ASSERT_EGL_NO_ERROR();
367 EGLContext EGLDisplayOpenVG::contextForSurface(const EGLSurface& surface)
369 ASSERT(surface != EGL_NO_SURFACE);
371 if (m_platformSurfaces.contains(surface))
372 return m_platformSurfaces.get(surface)->eglContext();
374 eglBindAPI(EGL_OPENVG_API);
375 ASSERT_EGL_NO_ERROR();
377 EGLint surfaceConfigId;
379 if (m_surfaceConfigIds.contains(surface))
380 surfaceConfigId = m_surfaceConfigIds.get(surface);
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);
388 m_surfaceConfigIds.set(surface, surfaceConfigId);
391 if (m_compatibleConfigIds.contains(surfaceConfigId))
392 surfaceConfigId = m_compatibleConfigIds.get(surfaceConfigId);
394 if (m_contexts.contains(surfaceConfigId))
395 return m_contexts.get(surfaceConfigId);
397 if (!m_sharedPlatformSurface) // shared context has not been created yet
398 sharedPlatformSurface(); // creates the shared surface & context
400 EGLDisplay currentDisplay = eglGetCurrentDisplay();
401 EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
402 EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
403 EGLContext currentContext = eglGetCurrentContext();
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
409 HashMap<EGLint, EGLContext>::iterator end = m_contexts.end();
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();
419 // Cool, surface is compatible to one of our existing contexts.
420 m_compatibleConfigIds.set(surfaceConfigId, (*it).first);
424 // Restore previous surface/context.
425 if (currentContext != EGL_NO_CONTEXT) {
426 eglMakeCurrent(currentDisplay, currentReadSurface, currentDrawSurface, currentContext);
427 ASSERT_EGL_NO_ERROR();
433 const EGLint configAttribs[] = {
434 EGL_CONFIG_ID, surfaceConfigId,
438 eglChooseConfig(m_display, configAttribs, &config, 1, &numConfigs);
439 ASSERT_EGL_NO_ERROR();
440 ASSERT(numConfigs == 1);
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();
450 ASSERT(!m_contexts.contains(surfaceConfigId));
451 m_contexts.set(surfaceConfigId, context);