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.
displayManagers()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
currentSurface()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
registerPlatformSurface(SurfaceOpenVG * platformSurface)63 void EGLDisplayOpenVG::registerPlatformSurface(SurfaceOpenVG* platformSurface)
64 {
65 EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
66 displayManager->m_platformSurfaces.set(platformSurface->eglSurface(), platformSurface);
67 }
68
unregisterPlatformSurface(SurfaceOpenVG * platformSurface)69 void EGLDisplayOpenVG::unregisterPlatformSurface(SurfaceOpenVG* platformSurface)
70 {
71 EGLDisplayOpenVG* displayManager = EGLDisplayOpenVG::forDisplay(platformSurface->eglDisplay());
72 displayManager->m_platformSurfaces.remove(platformSurface->eglSurface());
73 }
74
setCurrentDisplay(const EGLDisplay & display)75 void EGLDisplayOpenVG::setCurrentDisplay(const EGLDisplay& display)
76 {
77 s_current = EGLDisplayOpenVG::forDisplay(display);
78 }
79
current()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
forDisplay(const EGLDisplay & display)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
EGLDisplayOpenVG(const EGLDisplay & display)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
~EGLDisplayOpenVG()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
setDefaultPbufferConfig(const EGLConfig & config)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
defaultPbufferConfig()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
setDefaultWindowConfig(const EGLConfig & config)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
defaultWindowConfig()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
sharedPlatformSurface()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
createPbufferSurface(const IntSize & size,const EGLConfig & config,EGLint * errorCode)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
createPbufferFromClientBuffer(EGLClientBuffer clientBuffer,EGLenum bufferType,const EGLConfig & config,EGLint * errorCode)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
surfaceForWindow(EGLNativeWindowType wId,const EGLConfig & config)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
surfacesCompatible(const EGLSurface & surface,const EGLSurface & otherSurface)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
destroySurface(const EGLSurface & surface)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
contextForSurface(const EGLSurface & surface)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 }
456