|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtOpenVG module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qwindowsurface_vgegl_p.h" |
|
43 #include "qpaintengine_vg_p.h" |
|
44 #include "qpixmapdata_vg_p.h" |
|
45 #include "qvgimagepool_p.h" |
|
46 #include "qvg_p.h" |
|
47 |
|
48 #if !defined(QT_NO_EGL) |
|
49 |
|
50 QT_BEGIN_NAMESPACE |
|
51 |
|
52 // Turn off "direct to window" rendering if EGL cannot support it. |
|
53 #if !defined(EGL_RENDER_BUFFER) || !defined(EGL_SINGLE_BUFFER) |
|
54 #if defined(QVG_DIRECT_TO_WINDOW) |
|
55 #undef QVG_DIRECT_TO_WINDOW |
|
56 #endif |
|
57 #endif |
|
58 |
|
59 // Determine if preserved window contents should be used. |
|
60 #if !defined(EGL_SWAP_BEHAVIOR) || !defined(EGL_BUFFER_PRESERVED) |
|
61 #if !defined(QVG_NO_PRESERVED_SWAP) |
|
62 #define QVG_NO_PRESERVED_SWAP 1 |
|
63 #endif |
|
64 #endif |
|
65 |
|
66 VGImageFormat qt_vg_config_to_vg_format(QEglContext *context) |
|
67 { |
|
68 return qt_vg_image_to_vg_format |
|
69 (qt_vg_config_to_image_format(context)); |
|
70 } |
|
71 |
|
72 QImage::Format qt_vg_config_to_image_format(QEglContext *context) |
|
73 { |
|
74 EGLint red = 0; |
|
75 EGLint green = 0; |
|
76 EGLint blue = 0; |
|
77 EGLint alpha = 0; |
|
78 context->configAttrib(EGL_RED_SIZE, &red); |
|
79 context->configAttrib(EGL_GREEN_SIZE, &green); |
|
80 context->configAttrib(EGL_BLUE_SIZE, &blue); |
|
81 context->configAttrib(EGL_ALPHA_SIZE, &alpha); |
|
82 QImage::Format argbFormat; |
|
83 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
84 EGLint type = 0; |
|
85 context->configAttrib(EGL_SURFACE_TYPE, &type); |
|
86 if ((type & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) |
|
87 argbFormat = QImage::Format_ARGB32_Premultiplied; |
|
88 else |
|
89 argbFormat = QImage::Format_ARGB32; |
|
90 #else |
|
91 argbFormat = QImage::Format_ARGB32; |
|
92 #endif |
|
93 if (red == 8 && green == 8 && blue == 8 && alpha == 8) |
|
94 return argbFormat; |
|
95 else if (red == 8 && green == 8 && blue == 8 && alpha == 0) |
|
96 return QImage::Format_RGB32; |
|
97 else if (red == 5 && green == 6 && blue == 5 && alpha == 0) |
|
98 return QImage::Format_RGB16; |
|
99 else if (red == 4 && green == 4 && blue == 4 && alpha == 4) |
|
100 return QImage::Format_ARGB4444_Premultiplied; |
|
101 else |
|
102 return argbFormat; // XXX |
|
103 } |
|
104 |
|
105 #if !defined(QVG_NO_SINGLE_CONTEXT) |
|
106 |
|
107 class QVGSharedContext |
|
108 { |
|
109 public: |
|
110 QVGSharedContext(); |
|
111 ~QVGSharedContext(); |
|
112 |
|
113 QEglContext *context; |
|
114 int refCount; |
|
115 int widgetRefCount; |
|
116 QVGPaintEngine *engine; |
|
117 EGLSurface surface; |
|
118 QVGPixmapData *firstPixmap; |
|
119 }; |
|
120 |
|
121 QVGSharedContext::QVGSharedContext() |
|
122 : context(0) |
|
123 , refCount(0) |
|
124 , widgetRefCount(0) |
|
125 , engine(0) |
|
126 , surface(EGL_NO_SURFACE) |
|
127 , firstPixmap(0) |
|
128 { |
|
129 } |
|
130 |
|
131 QVGSharedContext::~QVGSharedContext() |
|
132 { |
|
133 // Don't accidentally destroy the QEglContext if the reference |
|
134 // count falls to zero while deleting the paint engine. |
|
135 ++refCount; |
|
136 |
|
137 if (context) |
|
138 context->makeCurrent(qt_vg_shared_surface()); |
|
139 delete engine; |
|
140 if (context) |
|
141 context->doneCurrent(); |
|
142 if (context && surface != EGL_NO_SURFACE) |
|
143 context->destroySurface(surface); |
|
144 delete context; |
|
145 } |
|
146 |
|
147 Q_GLOBAL_STATIC(QVGSharedContext, sharedContext); |
|
148 |
|
149 QVGPaintEngine *qt_vg_create_paint_engine(void) |
|
150 { |
|
151 QVGSharedContext *shared = sharedContext(); |
|
152 if (!shared->engine) |
|
153 shared->engine = new QVGPaintEngine(); |
|
154 return shared->engine; |
|
155 } |
|
156 |
|
157 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
|
158 { |
|
159 Q_UNUSED(engine); |
|
160 } |
|
161 |
|
162 void qt_vg_register_pixmap(QVGPixmapData *pd) |
|
163 { |
|
164 QVGSharedContext *shared = sharedContext(); |
|
165 pd->next = shared->firstPixmap; |
|
166 pd->prev = 0; |
|
167 if (shared->firstPixmap) |
|
168 shared->firstPixmap->prev = pd; |
|
169 shared->firstPixmap = pd; |
|
170 } |
|
171 |
|
172 void qt_vg_unregister_pixmap(QVGPixmapData *pd) |
|
173 { |
|
174 if (pd->next) |
|
175 pd->next->prev = pd->prev; |
|
176 if (pd->prev) { |
|
177 pd->prev->next = pd->next; |
|
178 } else { |
|
179 QVGSharedContext *shared = sharedContext(); |
|
180 if (shared) |
|
181 shared->firstPixmap = pd->next; |
|
182 } |
|
183 } |
|
184 |
|
185 #else |
|
186 |
|
187 QVGPaintEngine *qt_vg_create_paint_engine(void) |
|
188 { |
|
189 return new QVGPaintEngine(); |
|
190 } |
|
191 |
|
192 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
|
193 { |
|
194 delete engine; |
|
195 } |
|
196 |
|
197 void qt_vg_register_pixmap(QVGPixmapData *pd) |
|
198 { |
|
199 Q_UNUSED(pd); |
|
200 } |
|
201 |
|
202 void qt_vg_unregister_pixmap(QVGPixmapData *pd) |
|
203 { |
|
204 Q_UNUSED(pd); |
|
205 } |
|
206 |
|
207 #endif |
|
208 |
|
209 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
210 |
|
211 static bool isPremultipliedContext(const QEglContext *context) |
|
212 { |
|
213 EGLint value = 0; |
|
214 if (context->configAttrib(EGL_SURFACE_TYPE, &value)) |
|
215 return (value & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0; |
|
216 else |
|
217 return false; |
|
218 } |
|
219 |
|
220 #endif |
|
221 |
|
222 static QEglContext *createContext(QPaintDevice *device) |
|
223 { |
|
224 QEglContext *context; |
|
225 |
|
226 // Create the context object and open the display. |
|
227 context = new QEglContext(); |
|
228 context->setApi(QEgl::OpenVG); |
|
229 |
|
230 // Set the swap interval for the display. |
|
231 QByteArray interval = qgetenv("QT_VG_SWAP_INTERVAL"); |
|
232 if (!interval.isEmpty()) |
|
233 eglSwapInterval(QEglContext::display(), interval.toInt()); |
|
234 else |
|
235 eglSwapInterval(QEglContext::display(), 1); |
|
236 |
|
237 #ifdef EGL_RENDERABLE_TYPE |
|
238 // Has the user specified an explicit EGL configuration to use? |
|
239 QByteArray configId = qgetenv("QT_VG_EGL_CONFIG"); |
|
240 if (!configId.isEmpty()) { |
|
241 EGLint cfgId = configId.toInt(); |
|
242 EGLint properties[] = { |
|
243 EGL_CONFIG_ID, cfgId, |
|
244 EGL_NONE |
|
245 }; |
|
246 EGLint matching = 0; |
|
247 EGLConfig cfg; |
|
248 if (eglChooseConfig |
|
249 (QEglContext::display(), properties, &cfg, 1, &matching) && |
|
250 matching > 0) { |
|
251 // Check that the selected configuration actually supports OpenVG |
|
252 // and then create the context with it. |
|
253 EGLint id = 0; |
|
254 EGLint type = 0; |
|
255 eglGetConfigAttrib |
|
256 (QEglContext::display(), cfg, EGL_CONFIG_ID, &id); |
|
257 eglGetConfigAttrib |
|
258 (QEglContext::display(), cfg, EGL_RENDERABLE_TYPE, &type); |
|
259 if (cfgId == id && (type & EGL_OPENVG_BIT) != 0) { |
|
260 context->setConfig(cfg); |
|
261 if (!context->createContext()) { |
|
262 delete context; |
|
263 return 0; |
|
264 } |
|
265 return context; |
|
266 } else { |
|
267 qWarning("QT_VG_EGL_CONFIG: %d is not a valid OpenVG configuration", int(cfgId)); |
|
268 } |
|
269 } |
|
270 } |
|
271 #endif |
|
272 |
|
273 // Choose an appropriate configuration for rendering into the device. |
|
274 QEglProperties configProps; |
|
275 configProps.setPaintDeviceFormat(device); |
|
276 int redSize = configProps.value(EGL_RED_SIZE); |
|
277 if (redSize == EGL_DONT_CARE || redSize == 0) |
|
278 configProps.setPixelFormat(QImage::Format_ARGB32); // XXX |
|
279 #ifndef QVG_SCISSOR_CLIP |
|
280 // If we are using the mask to clip, then explicitly request a mask. |
|
281 configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); |
|
282 #endif |
|
283 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
284 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | |
|
285 EGL_VG_ALPHA_FORMAT_PRE_BIT); |
|
286 configProps.setRenderableType(QEgl::OpenVG); |
|
287 if (!context->chooseConfig(configProps)) { |
|
288 // Try again without the "pre" bit. |
|
289 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); |
|
290 if (!context->chooseConfig(configProps)) { |
|
291 delete context; |
|
292 return 0; |
|
293 } |
|
294 } |
|
295 #else |
|
296 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); |
|
297 configProps.setRenderableType(QEgl::OpenVG); |
|
298 if (!context->chooseConfig(configProps)) { |
|
299 delete context; |
|
300 return 0; |
|
301 } |
|
302 #endif |
|
303 |
|
304 // Construct a new EGL context for the selected configuration. |
|
305 if (!context->createContext()) { |
|
306 delete context; |
|
307 return 0; |
|
308 } |
|
309 |
|
310 return context; |
|
311 } |
|
312 |
|
313 #if !defined(QVG_NO_SINGLE_CONTEXT) |
|
314 |
|
315 QEglContext *qt_vg_create_context(QPaintDevice *device, int devType) |
|
316 { |
|
317 QVGSharedContext *shared = sharedContext(); |
|
318 if (devType == QInternal::Widget) |
|
319 ++(shared->widgetRefCount); |
|
320 if (shared->context) { |
|
321 ++(shared->refCount); |
|
322 return shared->context; |
|
323 } else { |
|
324 shared->context = createContext(device); |
|
325 shared->refCount = 1; |
|
326 return shared->context; |
|
327 } |
|
328 } |
|
329 |
|
330 static void qt_vg_destroy_shared_context(QVGSharedContext *shared) |
|
331 { |
|
332 shared->context->makeCurrent(qt_vg_shared_surface()); |
|
333 delete shared->engine; |
|
334 shared->engine = 0; |
|
335 shared->context->doneCurrent(); |
|
336 if (shared->surface != EGL_NO_SURFACE) { |
|
337 eglDestroySurface(QEglContext::display(), shared->surface); |
|
338 shared->surface = EGL_NO_SURFACE; |
|
339 } |
|
340 delete shared->context; |
|
341 shared->context = 0; |
|
342 } |
|
343 |
|
344 void qt_vg_hibernate_pixmaps(QVGSharedContext *shared) |
|
345 { |
|
346 // Artificially increase the reference count to prevent the |
|
347 // context from being destroyed until after we have finished |
|
348 // the hibernation process. |
|
349 ++(shared->refCount); |
|
350 |
|
351 // We need a context current to hibernate the VGImage objects. |
|
352 shared->context->makeCurrent(qt_vg_shared_surface()); |
|
353 |
|
354 // Scan all QVGPixmapData objects in the system and hibernate them. |
|
355 QVGPixmapData *pd = shared->firstPixmap; |
|
356 while (pd != 0) { |
|
357 pd->hibernate(); |
|
358 pd = pd->next; |
|
359 } |
|
360 |
|
361 // Hibernate any remaining VGImage's in the image pool. |
|
362 QVGImagePool::instance()->hibernate(); |
|
363 |
|
364 // Don't need the current context any more. |
|
365 shared->context->lazyDoneCurrent(); |
|
366 |
|
367 // Decrease the reference count and destroy the context if necessary. |
|
368 if (--(shared->refCount) <= 0) |
|
369 qt_vg_destroy_shared_context(shared); |
|
370 } |
|
371 |
|
372 void qt_vg_destroy_context(QEglContext *context, int devType) |
|
373 { |
|
374 QVGSharedContext *shared = sharedContext(); |
|
375 if (shared->context != context) { |
|
376 // This is not the shared context. Shouldn't happen! |
|
377 delete context; |
|
378 return; |
|
379 } |
|
380 if (devType == QInternal::Widget) |
|
381 --(shared->widgetRefCount); |
|
382 if (--(shared->refCount) <= 0) { |
|
383 qt_vg_destroy_shared_context(shared); |
|
384 } else if (shared->widgetRefCount <= 0 && devType == QInternal::Widget) { |
|
385 // All of the widget window surfaces have been destroyed |
|
386 // but we still have VG pixmaps active. Ask them to hibernate |
|
387 // to free up GPU resources until a widget is shown again. |
|
388 // This may eventually cause the EGLContext to be destroyed |
|
389 // because nothing in the system needs a context, which will |
|
390 // free up even more GPU resources. |
|
391 qt_vg_hibernate_pixmaps(shared); |
|
392 } |
|
393 } |
|
394 |
|
395 EGLSurface qt_vg_shared_surface(void) |
|
396 { |
|
397 QVGSharedContext *shared = sharedContext(); |
|
398 if (shared->surface == EGL_NO_SURFACE) { |
|
399 EGLint attribs[7]; |
|
400 attribs[0] = EGL_WIDTH; |
|
401 attribs[1] = 16; |
|
402 attribs[2] = EGL_HEIGHT; |
|
403 attribs[3] = 16; |
|
404 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
405 if (isPremultipliedContext(shared->context)) { |
|
406 attribs[4] = EGL_VG_ALPHA_FORMAT; |
|
407 attribs[5] = EGL_VG_ALPHA_FORMAT_PRE; |
|
408 attribs[6] = EGL_NONE; |
|
409 } else |
|
410 #endif |
|
411 { |
|
412 attribs[4] = EGL_NONE; |
|
413 } |
|
414 shared->surface = eglCreatePbufferSurface |
|
415 (QEglContext::display(), shared->context->config(), attribs); |
|
416 } |
|
417 return shared->surface; |
|
418 } |
|
419 |
|
420 #else |
|
421 |
|
422 QEglContext *qt_vg_create_context(QPaintDevice *device, int devType) |
|
423 { |
|
424 Q_UNUSED(devType); |
|
425 return createContext(device); |
|
426 } |
|
427 |
|
428 void qt_vg_destroy_context(QEglContext *context, int devType) |
|
429 { |
|
430 Q_UNUSED(devType); |
|
431 delete context; |
|
432 } |
|
433 |
|
434 EGLSurface qt_vg_shared_surface(void) |
|
435 { |
|
436 return EGL_NO_SURFACE; |
|
437 } |
|
438 |
|
439 #endif |
|
440 |
|
441 QVGEGLWindowSurfacePrivate::QVGEGLWindowSurfacePrivate(QWindowSurface *win) |
|
442 { |
|
443 winSurface = win; |
|
444 engine = 0; |
|
445 } |
|
446 |
|
447 QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() |
|
448 { |
|
449 // Destroy the paint engine if it hasn't been destroyed already. |
|
450 destroyPaintEngine(); |
|
451 } |
|
452 |
|
453 QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() |
|
454 { |
|
455 if (!engine) |
|
456 engine = qt_vg_create_paint_engine(); |
|
457 return engine; |
|
458 } |
|
459 |
|
460 VGImage QVGEGLWindowSurfacePrivate::surfaceImage() const |
|
461 { |
|
462 return VG_INVALID_HANDLE; |
|
463 } |
|
464 |
|
465 void QVGEGLWindowSurfacePrivate::destroyPaintEngine() |
|
466 { |
|
467 if (engine) { |
|
468 qt_vg_destroy_paint_engine(engine); |
|
469 engine = 0; |
|
470 } |
|
471 } |
|
472 |
|
473 QSize QVGEGLWindowSurfacePrivate::windowSurfaceSize(QWidget *widget) const |
|
474 { |
|
475 Q_UNUSED(widget); |
|
476 |
|
477 QRect rect = winSurface->geometry(); |
|
478 QSize newSize = rect.size(); |
|
479 |
|
480 #if defined(Q_WS_QWS) |
|
481 // Account for the widget mask, if any. |
|
482 if (widget && !widget->mask().isEmpty()) { |
|
483 const QRegion region = widget->mask() |
|
484 & rect.translated(-widget->geometry().topLeft()); |
|
485 newSize = region.boundingRect().size(); |
|
486 } |
|
487 #endif |
|
488 |
|
489 return newSize; |
|
490 } |
|
491 |
|
492 #if defined(QVG_VGIMAGE_BACKBUFFERS) |
|
493 |
|
494 QVGEGLWindowSurfaceVGImage::QVGEGLWindowSurfaceVGImage(QWindowSurface *win) |
|
495 : QVGEGLWindowSurfacePrivate(win) |
|
496 , context(0) |
|
497 , backBuffer(VG_INVALID_HANDLE) |
|
498 , backBufferSurface(EGL_NO_SURFACE) |
|
499 , recreateBackBuffer(false) |
|
500 , isPaintingActive(false) |
|
501 , windowSurface(EGL_NO_SURFACE) |
|
502 { |
|
503 } |
|
504 |
|
505 QVGEGLWindowSurfaceVGImage::~QVGEGLWindowSurfaceVGImage() |
|
506 { |
|
507 destroyPaintEngine(); |
|
508 if (context) { |
|
509 if (backBufferSurface != EGL_NO_SURFACE) { |
|
510 // We need a current context to be able to destroy the image. |
|
511 // We use the shared surface because the native window handle |
|
512 // associated with "windowSurface" may have been destroyed already. |
|
513 context->makeCurrent(qt_vg_shared_surface()); |
|
514 context->destroySurface(backBufferSurface); |
|
515 vgDestroyImage(backBuffer); |
|
516 context->doneCurrent(); |
|
517 } |
|
518 if (windowSurface != EGL_NO_SURFACE) |
|
519 context->destroySurface(windowSurface); |
|
520 qt_vg_destroy_context(context, QInternal::Widget); |
|
521 } |
|
522 } |
|
523 |
|
524 QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget) |
|
525 { |
|
526 QSize newSize = windowSurfaceSize(widget); |
|
527 if (context && size != newSize) { |
|
528 // The surface size has changed, so we need to recreate |
|
529 // the back buffer. Keep the same context and paint engine. |
|
530 size = newSize; |
|
531 if (isPaintingActive) |
|
532 context->doneCurrent(); |
|
533 isPaintingActive = false; |
|
534 recreateBackBuffer = true; |
|
535 } |
|
536 if (!context) { |
|
537 // Create a new EGL context. We create the surface in beginPaint(). |
|
538 size = newSize; |
|
539 context = qt_vg_create_context(widget, QInternal::Widget); |
|
540 if (!context) |
|
541 return 0; |
|
542 isPaintingActive = false; |
|
543 } |
|
544 return context; |
|
545 } |
|
546 |
|
547 void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget) |
|
548 { |
|
549 QEglContext *context = ensureContext(widget); |
|
550 if (context) { |
|
551 if (recreateBackBuffer || backBufferSurface == EGL_NO_SURFACE) { |
|
552 // Create a VGImage object to act as the back buffer |
|
553 // for this window. We have to create the VGImage with a |
|
554 // current context, so activate the main surface for the window. |
|
555 context->makeCurrent(mainSurface()); |
|
556 recreateBackBuffer = false; |
|
557 if (backBufferSurface != EGL_NO_SURFACE) { |
|
558 eglDestroySurface(QEglContext::display(), backBufferSurface); |
|
559 backBufferSurface = EGL_NO_SURFACE; |
|
560 } |
|
561 if (backBuffer != VG_INVALID_HANDLE) { |
|
562 vgDestroyImage(backBuffer); |
|
563 } |
|
564 VGImageFormat format = qt_vg_config_to_vg_format(context); |
|
565 backBuffer = vgCreateImage |
|
566 (format, size.width(), size.height(), |
|
567 VG_IMAGE_QUALITY_FASTER); |
|
568 if (backBuffer != VG_INVALID_HANDLE) { |
|
569 // Create an EGL surface for rendering into the VGImage. |
|
570 backBufferSurface = eglCreatePbufferFromClientBuffer |
|
571 (QEglContext::display(), EGL_OPENVG_IMAGE, |
|
572 (EGLClientBuffer)(backBuffer), |
|
573 context->config(), NULL); |
|
574 if (backBufferSurface == EGL_NO_SURFACE) { |
|
575 vgDestroyImage(backBuffer); |
|
576 backBuffer = VG_INVALID_HANDLE; |
|
577 } |
|
578 } |
|
579 } |
|
580 if (backBufferSurface != EGL_NO_SURFACE) |
|
581 context->makeCurrent(backBufferSurface); |
|
582 else |
|
583 context->makeCurrent(mainSurface()); |
|
584 isPaintingActive = true; |
|
585 } |
|
586 } |
|
587 |
|
588 void QVGEGLWindowSurfaceVGImage::endPaint |
|
589 (QWidget *widget, const QRegion& region, QImage *image) |
|
590 { |
|
591 Q_UNUSED(region); |
|
592 Q_UNUSED(image); |
|
593 QEglContext *context = ensureContext(widget); |
|
594 if (context) { |
|
595 if (backBufferSurface != EGL_NO_SURFACE) { |
|
596 if (isPaintingActive) |
|
597 vgFlush(); |
|
598 context->lazyDoneCurrent(); |
|
599 } |
|
600 isPaintingActive = false; |
|
601 } |
|
602 } |
|
603 |
|
604 VGImage QVGEGLWindowSurfaceVGImage::surfaceImage() const |
|
605 { |
|
606 return backBuffer; |
|
607 } |
|
608 |
|
609 EGLSurface QVGEGLWindowSurfaceVGImage::mainSurface() const |
|
610 { |
|
611 if (windowSurface != EGL_NO_SURFACE) |
|
612 return windowSurface; |
|
613 else |
|
614 return qt_vg_shared_surface(); |
|
615 } |
|
616 |
|
617 #endif // QVG_VGIMAGE_BACKBUFFERS |
|
618 |
|
619 QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) |
|
620 : QVGEGLWindowSurfacePrivate(win) |
|
621 , context(0) |
|
622 , isPaintingActive(false) |
|
623 , needToSwap(false) |
|
624 , windowSurface(EGL_NO_SURFACE) |
|
625 { |
|
626 } |
|
627 |
|
628 QVGEGLWindowSurfaceDirect::~QVGEGLWindowSurfaceDirect() |
|
629 { |
|
630 destroyPaintEngine(); |
|
631 if (context) { |
|
632 if (windowSurface != EGL_NO_SURFACE) |
|
633 context->destroySurface(windowSurface); |
|
634 qt_vg_destroy_context(context, QInternal::Widget); |
|
635 } |
|
636 } |
|
637 |
|
638 QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) |
|
639 { |
|
640 QSize newSize = windowSurfaceSize(widget); |
|
641 QEglProperties surfaceProps; |
|
642 |
|
643 #if defined(QVG_RECREATE_ON_SIZE_CHANGE) |
|
644 #if !defined(QVG_NO_SINGLE_CONTEXT) |
|
645 if (context && size != newSize) { |
|
646 // The surface size has changed, so we need to recreate it. |
|
647 // We can keep the same context and paint engine. |
|
648 size = newSize; |
|
649 if (isPaintingActive) |
|
650 context->doneCurrent(); |
|
651 context->destroySurface(windowSurface); |
|
652 #if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) |
|
653 if (isPremultipliedContext(context)) { |
|
654 surfaceProps.setValue |
|
655 (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); |
|
656 } else { |
|
657 surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); |
|
658 } |
|
659 #endif |
|
660 windowSurface = context->createSurface(widget, &surfaceProps); |
|
661 isPaintingActive = false; |
|
662 } |
|
663 #else |
|
664 if (context && size != newSize) { |
|
665 // The surface size has changed, so we need to recreate |
|
666 // the EGL context for the widget. We also need to recreate |
|
667 // the surface's paint engine if context sharing is not |
|
668 // enabled because we cannot reuse the existing paint objects |
|
669 // in the new context. |
|
670 qt_vg_destroy_paint_engine(engine); |
|
671 engine = 0; |
|
672 context->destroySurface(windowSurface); |
|
673 qt_vg_destroy_context(context, QInternal::Widget); |
|
674 context = 0; |
|
675 windowSurface = EGL_NO_SURFACE; |
|
676 } |
|
677 #endif |
|
678 #endif |
|
679 if (!context) { |
|
680 // Create a new EGL context and bind it to the widget surface. |
|
681 size = newSize; |
|
682 context = qt_vg_create_context(widget, QInternal::Widget); |
|
683 if (!context) |
|
684 return 0; |
|
685 // We want a direct to window rendering surface if possible. |
|
686 #if defined(QVG_DIRECT_TO_WINDOW) |
|
687 surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); |
|
688 #endif |
|
689 #if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) |
|
690 if (isPremultipliedContext(context)) { |
|
691 surfaceProps.setValue |
|
692 (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); |
|
693 } else { |
|
694 surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); |
|
695 } |
|
696 #endif |
|
697 EGLSurface surface = context->createSurface(widget, &surfaceProps); |
|
698 if (surface == EGL_NO_SURFACE) { |
|
699 qt_vg_destroy_context(context, QInternal::Widget); |
|
700 context = 0; |
|
701 return 0; |
|
702 } |
|
703 needToSwap = true; |
|
704 #if defined(QVG_DIRECT_TO_WINDOW) |
|
705 // Did we get a direct to window rendering surface? |
|
706 EGLint buffer = 0; |
|
707 if (eglQueryContext(QEglContext::display(), context->context(), |
|
708 EGL_RENDER_BUFFER, &buffer) && |
|
709 buffer == EGL_SINGLE_BUFFER) { |
|
710 needToSwap = false; |
|
711 } |
|
712 #endif |
|
713 #if !defined(QVG_NO_PRESERVED_SWAP) |
|
714 // Try to force the surface back buffer to preserve its contents. |
|
715 if (needToSwap) { |
|
716 eglGetError(); // Clear error state first. |
|
717 eglSurfaceAttrib(QEglContext::display(), surface, |
|
718 EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); |
|
719 if (eglGetError() != EGL_SUCCESS) { |
|
720 qWarning("QVG: could not enable preserved swap"); |
|
721 } |
|
722 } |
|
723 #endif |
|
724 windowSurface = surface; |
|
725 isPaintingActive = false; |
|
726 } |
|
727 return context; |
|
728 } |
|
729 |
|
730 void QVGEGLWindowSurfaceDirect::beginPaint(QWidget *widget) |
|
731 { |
|
732 QEglContext *context = ensureContext(widget); |
|
733 if (context) { |
|
734 context->makeCurrent(windowSurface); |
|
735 isPaintingActive = true; |
|
736 } |
|
737 } |
|
738 |
|
739 void QVGEGLWindowSurfaceDirect::endPaint |
|
740 (QWidget *widget, const QRegion& region, QImage *image) |
|
741 { |
|
742 Q_UNUSED(region); |
|
743 Q_UNUSED(image); |
|
744 QEglContext *context = ensureContext(widget); |
|
745 if (context) { |
|
746 if (needToSwap) { |
|
747 if (!isPaintingActive) |
|
748 context->makeCurrent(windowSurface); |
|
749 context->swapBuffers(windowSurface); |
|
750 context->lazyDoneCurrent(); |
|
751 } else if (isPaintingActive) { |
|
752 vgFlush(); |
|
753 context->lazyDoneCurrent(); |
|
754 } |
|
755 isPaintingActive = false; |
|
756 } |
|
757 } |
|
758 |
|
759 QT_END_NAMESPACE |
|
760 |
|
761 #endif |