|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 "qvg_p.h" |
|
46 |
|
47 #if !defined(QT_NO_EGL) |
|
48 |
|
49 QT_BEGIN_NAMESPACE |
|
50 |
|
51 // Turn off "direct to window" rendering if EGL cannot support it. |
|
52 #if !defined(EGL_RENDER_BUFFER) || !defined(EGL_SINGLE_BUFFER) |
|
53 #if defined(QVG_DIRECT_TO_WINDOW) |
|
54 #undef QVG_DIRECT_TO_WINDOW |
|
55 #endif |
|
56 #endif |
|
57 |
|
58 // Determine if preserved window contents should be used. |
|
59 #if !defined(EGL_SWAP_BEHAVIOR) || !defined(EGL_BUFFER_PRESERVED) |
|
60 #if !defined(QVG_NO_PRESERVED_SWAP) |
|
61 #define QVG_NO_PRESERVED_SWAP 1 |
|
62 #endif |
|
63 #endif |
|
64 |
|
65 VGImageFormat qt_vg_config_to_vg_format(QEglContext *context) |
|
66 { |
|
67 return qt_vg_image_to_vg_format |
|
68 (qt_vg_config_to_image_format(context)); |
|
69 } |
|
70 |
|
71 QImage::Format qt_vg_config_to_image_format(QEglContext *context) |
|
72 { |
|
73 EGLint red = 0; |
|
74 EGLint green = 0; |
|
75 EGLint blue = 0; |
|
76 EGLint alpha = 0; |
|
77 context->configAttrib(EGL_RED_SIZE, &red); |
|
78 context->configAttrib(EGL_GREEN_SIZE, &green); |
|
79 context->configAttrib(EGL_BLUE_SIZE, &blue); |
|
80 context->configAttrib(EGL_ALPHA_SIZE, &alpha); |
|
81 QImage::Format argbFormat; |
|
82 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
83 EGLint type = 0; |
|
84 context->configAttrib(EGL_SURFACE_TYPE, &type); |
|
85 if ((type & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) |
|
86 argbFormat = QImage::Format_ARGB32_Premultiplied; |
|
87 else |
|
88 argbFormat = QImage::Format_ARGB32; |
|
89 #else |
|
90 argbFormat = QImage::Format_ARGB32; |
|
91 #endif |
|
92 if (red == 8 && green == 8 && blue == 8 && alpha == 8) |
|
93 return argbFormat; |
|
94 else if (red == 8 && green == 8 && blue == 8 && alpha == 0) |
|
95 return QImage::Format_RGB32; |
|
96 else if (red == 5 && green == 6 && blue == 5 && alpha == 0) |
|
97 return QImage::Format_RGB16; |
|
98 else if (red == 4 && green == 4 && blue == 4 && alpha == 4) |
|
99 return QImage::Format_ARGB4444_Premultiplied; |
|
100 else |
|
101 return argbFormat; // XXX |
|
102 } |
|
103 |
|
104 static void copySubImage(QImage *image, VGImage vgImage, const QRect& rect) |
|
105 { |
|
106 vgGetImageSubData |
|
107 (vgImage, |
|
108 image->bits() + rect.bottom() * image->bytesPerLine() + |
|
109 rect.x() * (image->depth() / 8), |
|
110 -(image->bytesPerLine()), |
|
111 qt_vg_image_to_vg_format(image->format()), |
|
112 rect.x(), (image->height() - 1) - rect.bottom(), |
|
113 rect.width(), rect.height()); |
|
114 } |
|
115 |
|
116 #if !defined(QVG_NO_SINGLE_CONTEXT) |
|
117 |
|
118 class QVGSharedContext |
|
119 { |
|
120 public: |
|
121 QVGSharedContext(); |
|
122 ~QVGSharedContext(); |
|
123 |
|
124 QEglContext *context; |
|
125 int refCount; |
|
126 QVGPaintEngine *engine; |
|
127 EGLSurface surface; |
|
128 }; |
|
129 |
|
130 QVGSharedContext::QVGSharedContext() |
|
131 : context(0) |
|
132 , refCount(0) |
|
133 , engine(0) |
|
134 , surface(EGL_NO_SURFACE) |
|
135 { |
|
136 } |
|
137 |
|
138 QVGSharedContext::~QVGSharedContext() |
|
139 { |
|
140 // Don't accidentally destroy the QEglContext if the reference |
|
141 // count falls to zero while deleting the paint engine. |
|
142 ++refCount; |
|
143 |
|
144 if (context) |
|
145 context->makeCurrent(qt_vg_shared_surface()); |
|
146 delete engine; |
|
147 if (context) |
|
148 context->doneCurrent(); |
|
149 if (context && surface != EGL_NO_SURFACE) |
|
150 context->destroySurface(surface); |
|
151 delete context; |
|
152 } |
|
153 |
|
154 Q_GLOBAL_STATIC(QVGSharedContext, sharedContext); |
|
155 |
|
156 QVGPaintEngine *qt_vg_create_paint_engine(void) |
|
157 { |
|
158 QVGSharedContext *shared = sharedContext(); |
|
159 if (!shared->engine) |
|
160 shared->engine = new QVGPaintEngine(); |
|
161 return shared->engine; |
|
162 } |
|
163 |
|
164 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
|
165 { |
|
166 Q_UNUSED(engine); |
|
167 } |
|
168 |
|
169 #else |
|
170 |
|
171 QVGPaintEngine *qt_vg_create_paint_engine(void) |
|
172 { |
|
173 return new QVGPaintEngine(); |
|
174 } |
|
175 |
|
176 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
|
177 { |
|
178 delete engine; |
|
179 } |
|
180 |
|
181 #endif |
|
182 |
|
183 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
184 |
|
185 static bool isPremultipliedContext(const QEglContext *context) |
|
186 { |
|
187 EGLint value = 0; |
|
188 if (context->configAttrib(EGL_SURFACE_TYPE, &value)) |
|
189 return (value & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0; |
|
190 else |
|
191 return false; |
|
192 } |
|
193 |
|
194 #endif |
|
195 |
|
196 static QEglContext *createContext(QPaintDevice *device) |
|
197 { |
|
198 QEglContext *context; |
|
199 |
|
200 // Create the context object and open the display. |
|
201 context = new QEglContext(); |
|
202 context->setApi(QEgl::OpenVG); |
|
203 if (!context->openDisplay(device)) { |
|
204 delete context; |
|
205 return 0; |
|
206 } |
|
207 |
|
208 // Choose an appropriate configuration for rendering into the device. |
|
209 QEglProperties configProps; |
|
210 configProps.setPaintDeviceFormat(device); |
|
211 int redSize = configProps.value(EGL_RED_SIZE); |
|
212 if (redSize == EGL_DONT_CARE || redSize == 0) |
|
213 configProps.setPixelFormat(QImage::Format_ARGB32); // XXX |
|
214 #ifndef QVG_SCISSOR_CLIP |
|
215 // If we are using the mask to clip, then explicitly request a mask. |
|
216 configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); |
|
217 #endif |
|
218 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
219 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | |
|
220 EGL_VG_ALPHA_FORMAT_PRE_BIT); |
|
221 configProps.setRenderableType(QEgl::OpenVG); |
|
222 if (!context->chooseConfig(configProps)) { |
|
223 // Try again without the "pre" bit. |
|
224 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); |
|
225 if (!context->chooseConfig(configProps)) { |
|
226 delete context; |
|
227 return 0; |
|
228 } |
|
229 } |
|
230 #else |
|
231 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); |
|
232 configProps.setRenderableType(QEgl::OpenVG); |
|
233 if (!context->chooseConfig(configProps)) { |
|
234 delete context; |
|
235 return 0; |
|
236 } |
|
237 #endif |
|
238 |
|
239 // Construct a new EGL context for the selected configuration. |
|
240 if (!context->createContext()) { |
|
241 delete context; |
|
242 return 0; |
|
243 } |
|
244 |
|
245 return context; |
|
246 } |
|
247 |
|
248 #if !defined(QVG_NO_SINGLE_CONTEXT) |
|
249 |
|
250 QEglContext *qt_vg_create_context(QPaintDevice *device) |
|
251 { |
|
252 QVGSharedContext *shared = sharedContext(); |
|
253 if (shared->context) { |
|
254 ++(shared->refCount); |
|
255 return shared->context; |
|
256 } else { |
|
257 shared->context = createContext(device); |
|
258 shared->refCount = 1; |
|
259 return shared->context; |
|
260 } |
|
261 } |
|
262 |
|
263 void qt_vg_destroy_context(QEglContext *context) |
|
264 { |
|
265 QVGSharedContext *shared = sharedContext(); |
|
266 if (shared->context != context) { |
|
267 // This is not the shared context. Shouldn't happen! |
|
268 delete context; |
|
269 } else if (--(shared->refCount) <= 0) { |
|
270 shared->context->makeCurrent(qt_vg_shared_surface()); |
|
271 delete shared->engine; |
|
272 shared->engine = 0; |
|
273 shared->context->doneCurrent(); |
|
274 if (shared->surface != EGL_NO_SURFACE) { |
|
275 eglDestroySurface(shared->context->display(), shared->surface); |
|
276 shared->surface = EGL_NO_SURFACE; |
|
277 } |
|
278 delete shared->context; |
|
279 shared->context = 0; |
|
280 } |
|
281 } |
|
282 |
|
283 EGLSurface qt_vg_shared_surface(void) |
|
284 { |
|
285 QVGSharedContext *shared = sharedContext(); |
|
286 if (shared->surface == EGL_NO_SURFACE) { |
|
287 EGLint attribs[7]; |
|
288 attribs[0] = EGL_WIDTH; |
|
289 attribs[1] = 16; |
|
290 attribs[2] = EGL_HEIGHT; |
|
291 attribs[3] = 16; |
|
292 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
|
293 if (isPremultipliedContext(shared->context)) { |
|
294 attribs[4] = EGL_VG_ALPHA_FORMAT; |
|
295 attribs[5] = EGL_VG_ALPHA_FORMAT_PRE; |
|
296 attribs[6] = EGL_NONE; |
|
297 } else |
|
298 #endif |
|
299 { |
|
300 attribs[4] = EGL_NONE; |
|
301 } |
|
302 shared->surface = eglCreatePbufferSurface |
|
303 (shared->context->display(), shared->context->config(), attribs); |
|
304 } |
|
305 return shared->surface; |
|
306 } |
|
307 |
|
308 #else |
|
309 |
|
310 QEglContext *qt_vg_create_context(QPaintDevice *device) |
|
311 { |
|
312 return createContext(device); |
|
313 } |
|
314 |
|
315 void qt_vg_destroy_context(QEglContext *context) |
|
316 { |
|
317 delete context; |
|
318 } |
|
319 |
|
320 EGLSurface qt_vg_shared_surface(void) |
|
321 { |
|
322 return EGL_NO_SURFACE; |
|
323 } |
|
324 |
|
325 #endif |
|
326 |
|
327 QVGEGLWindowSurfacePrivate::QVGEGLWindowSurfacePrivate(QWindowSurface *win) |
|
328 { |
|
329 winSurface = win; |
|
330 engine = 0; |
|
331 } |
|
332 |
|
333 QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() |
|
334 { |
|
335 // Destroy the paint engine if it hasn't been destroyed already. |
|
336 destroyPaintEngine(); |
|
337 } |
|
338 |
|
339 QVGEGLWindowSurfacePrivate *QVGEGLWindowSurfacePrivate::create |
|
340 (SurfaceType type, QWindowSurface *win) |
|
341 { |
|
342 #if defined(QVG_VGIMAGE_BACKBUFFERS) |
|
343 if (type == VGImageSurface) |
|
344 return new QVGEGLWindowSurfaceVGImage(win); |
|
345 else if (type == QImageSurface) |
|
346 return new QVGEGLWindowSurfaceQImage(win); |
|
347 #endif |
|
348 if (type == WindowSurface) |
|
349 return new QVGEGLWindowSurfaceDirect(win); |
|
350 return 0; |
|
351 } |
|
352 |
|
353 QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() |
|
354 { |
|
355 if (!engine) |
|
356 engine = qt_vg_create_paint_engine(); |
|
357 return engine; |
|
358 } |
|
359 |
|
360 VGImage QVGEGLWindowSurfacePrivate::surfaceImage() const |
|
361 { |
|
362 return VG_INVALID_HANDLE; |
|
363 } |
|
364 |
|
365 void QVGEGLWindowSurfacePrivate::destroyPaintEngine() |
|
366 { |
|
367 if (engine) { |
|
368 qt_vg_destroy_paint_engine(engine); |
|
369 engine = 0; |
|
370 } |
|
371 } |
|
372 |
|
373 QSize QVGEGLWindowSurfacePrivate::windowSurfaceSize(QWidget *widget) const |
|
374 { |
|
375 Q_UNUSED(widget); |
|
376 |
|
377 QRect rect = winSurface->geometry(); |
|
378 QSize newSize = rect.size(); |
|
379 |
|
380 #if defined(Q_WS_QWS) |
|
381 // Account for the widget mask, if any. |
|
382 if (widget && !widget->mask().isEmpty()) { |
|
383 const QRegion region = widget->mask() |
|
384 & rect.translated(-widget->geometry().topLeft()); |
|
385 newSize = region.boundingRect().size(); |
|
386 } |
|
387 #endif |
|
388 |
|
389 return newSize; |
|
390 } |
|
391 |
|
392 #if defined(QVG_VGIMAGE_BACKBUFFERS) |
|
393 |
|
394 QVGEGLWindowSurfaceVGImage::QVGEGLWindowSurfaceVGImage(QWindowSurface *win) |
|
395 : QVGEGLWindowSurfacePrivate(win) |
|
396 , context(0) |
|
397 , backBuffer(VG_INVALID_HANDLE) |
|
398 , backBufferSurface(EGL_NO_SURFACE) |
|
399 , recreateBackBuffer(false) |
|
400 , isPaintingActive(false) |
|
401 , windowSurface(EGL_NO_SURFACE) |
|
402 { |
|
403 } |
|
404 |
|
405 QVGEGLWindowSurfaceVGImage::~QVGEGLWindowSurfaceVGImage() |
|
406 { |
|
407 destroyPaintEngine(); |
|
408 if (context) { |
|
409 if (backBufferSurface != EGL_NO_SURFACE) { |
|
410 // We need a current context to be able to destroy the image. |
|
411 // We use the shared surface because the native window handle |
|
412 // associated with "windowSurface" may have been destroyed already. |
|
413 context->makeCurrent(qt_vg_shared_surface()); |
|
414 context->destroySurface(backBufferSurface); |
|
415 vgDestroyImage(backBuffer); |
|
416 context->doneCurrent(); |
|
417 } |
|
418 if (windowSurface != EGL_NO_SURFACE) |
|
419 context->destroySurface(windowSurface); |
|
420 qt_vg_destroy_context(context); |
|
421 } |
|
422 } |
|
423 |
|
424 QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget) |
|
425 { |
|
426 QSize newSize = windowSurfaceSize(widget); |
|
427 if (context && size != newSize) { |
|
428 // The surface size has changed, so we need to recreate |
|
429 // the back buffer. Keep the same context and paint engine. |
|
430 size = newSize; |
|
431 if (isPaintingActive) |
|
432 context->doneCurrent(); |
|
433 isPaintingActive = false; |
|
434 recreateBackBuffer = true; |
|
435 } |
|
436 if (!context) { |
|
437 // Create a new EGL context. We create the surface in beginPaint(). |
|
438 size = newSize; |
|
439 context = qt_vg_create_context(widget); |
|
440 if (!context) |
|
441 return 0; |
|
442 isPaintingActive = false; |
|
443 } |
|
444 return context; |
|
445 } |
|
446 |
|
447 void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget) |
|
448 { |
|
449 QEglContext *context = ensureContext(widget); |
|
450 if (context) { |
|
451 if (recreateBackBuffer || backBufferSurface == EGL_NO_SURFACE) { |
|
452 // Create a VGImage object to act as the back buffer |
|
453 // for this window. We have to create the VGImage with a |
|
454 // current context, so activate the main surface for the window. |
|
455 context->makeCurrent(mainSurface()); |
|
456 recreateBackBuffer = false; |
|
457 if (backBufferSurface != EGL_NO_SURFACE) { |
|
458 eglDestroySurface(context->display(), backBufferSurface); |
|
459 backBufferSurface = EGL_NO_SURFACE; |
|
460 } |
|
461 if (backBuffer != VG_INVALID_HANDLE) { |
|
462 vgDestroyImage(backBuffer); |
|
463 } |
|
464 VGImageFormat format = qt_vg_config_to_vg_format(context); |
|
465 backBuffer = vgCreateImage |
|
466 (format, size.width(), size.height(), |
|
467 VG_IMAGE_QUALITY_FASTER); |
|
468 if (backBuffer != VG_INVALID_HANDLE) { |
|
469 // Create an EGL surface for rendering into the VGImage. |
|
470 backBufferSurface = eglCreatePbufferFromClientBuffer |
|
471 (context->display(), EGL_OPENVG_IMAGE, |
|
472 (EGLClientBuffer)(backBuffer), |
|
473 context->config(), NULL); |
|
474 if (backBufferSurface == EGL_NO_SURFACE) { |
|
475 vgDestroyImage(backBuffer); |
|
476 backBuffer = VG_INVALID_HANDLE; |
|
477 } |
|
478 } |
|
479 } |
|
480 if (backBufferSurface != EGL_NO_SURFACE) |
|
481 context->makeCurrent(backBufferSurface); |
|
482 else |
|
483 context->makeCurrent(mainSurface()); |
|
484 isPaintingActive = true; |
|
485 } |
|
486 } |
|
487 |
|
488 void QVGEGLWindowSurfaceVGImage::endPaint |
|
489 (QWidget *widget, const QRegion& region, QImage *image) |
|
490 { |
|
491 Q_UNUSED(region); |
|
492 Q_UNUSED(image); |
|
493 QEglContext *context = ensureContext(widget); |
|
494 if (context) { |
|
495 if (backBufferSurface != EGL_NO_SURFACE) { |
|
496 if (isPaintingActive) |
|
497 vgFlush(); |
|
498 context->lazyDoneCurrent(); |
|
499 } |
|
500 isPaintingActive = false; |
|
501 } |
|
502 } |
|
503 |
|
504 VGImage QVGEGLWindowSurfaceVGImage::surfaceImage() const |
|
505 { |
|
506 return backBuffer; |
|
507 } |
|
508 |
|
509 EGLSurface QVGEGLWindowSurfaceVGImage::mainSurface() const |
|
510 { |
|
511 if (windowSurface != EGL_NO_SURFACE) |
|
512 return windowSurface; |
|
513 else |
|
514 return qt_vg_shared_surface(); |
|
515 } |
|
516 |
|
517 QVGEGLWindowSurfaceQImage::QVGEGLWindowSurfaceQImage(QWindowSurface *win) |
|
518 : QVGEGLWindowSurfaceVGImage(win) |
|
519 { |
|
520 } |
|
521 |
|
522 QVGEGLWindowSurfaceQImage::~QVGEGLWindowSurfaceQImage() |
|
523 { |
|
524 } |
|
525 |
|
526 void QVGEGLWindowSurfaceQImage::endPaint |
|
527 (QWidget *widget, const QRegion& region, QImage *image) |
|
528 { |
|
529 QEglContext *context = ensureContext(widget); |
|
530 if (context) { |
|
531 if (backBufferSurface != EGL_NO_SURFACE) { |
|
532 if (isPaintingActive) |
|
533 vgFlush(); |
|
534 context->makeCurrent(mainSurface()); |
|
535 QRegion rgn = region.intersected |
|
536 (QRect(0, 0, image->width(), image->height())); |
|
537 if (rgn.numRects() == 1) { |
|
538 copySubImage(image, backBuffer, rgn.boundingRect()); |
|
539 } else { |
|
540 QVector<QRect> rects = rgn.rects(); |
|
541 for (int index = 0; index < rects.size(); ++index) |
|
542 copySubImage(image, backBuffer, rects[index]); |
|
543 } |
|
544 context->lazyDoneCurrent(); |
|
545 } |
|
546 isPaintingActive = false; |
|
547 } |
|
548 } |
|
549 |
|
550 #endif // QVG_VGIMAGE_BACKBUFFERS |
|
551 |
|
552 QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) |
|
553 : QVGEGLWindowSurfacePrivate(win) |
|
554 , context(0) |
|
555 , isPaintingActive(false) |
|
556 , needToSwap(false) |
|
557 , windowSurface(EGL_NO_SURFACE) |
|
558 { |
|
559 } |
|
560 |
|
561 QVGEGLWindowSurfaceDirect::~QVGEGLWindowSurfaceDirect() |
|
562 { |
|
563 destroyPaintEngine(); |
|
564 if (context) { |
|
565 if (windowSurface != EGL_NO_SURFACE) |
|
566 context->destroySurface(windowSurface); |
|
567 qt_vg_destroy_context(context); |
|
568 } |
|
569 } |
|
570 |
|
571 QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) |
|
572 { |
|
573 QSize newSize = windowSurfaceSize(widget); |
|
574 QEglProperties surfaceProps; |
|
575 |
|
576 #if defined(QVG_RECREATE_ON_SIZE_CHANGE) |
|
577 #if !defined(QVG_NO_SINGLE_CONTEXT) |
|
578 if (context && size != newSize) { |
|
579 // The surface size has changed, so we need to recreate it. |
|
580 // We can keep the same context and paint engine. |
|
581 size = newSize; |
|
582 if (isPaintingActive) |
|
583 context->doneCurrent(); |
|
584 context->destroySurface(windowSurface); |
|
585 #if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) |
|
586 if (isPremultipliedContext(context)) { |
|
587 surfaceProps.setValue |
|
588 (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); |
|
589 } else { |
|
590 surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); |
|
591 } |
|
592 #endif |
|
593 windowSurface = context->createSurface(widget, &surfaceProps); |
|
594 isPaintingActive = false; |
|
595 } |
|
596 #else |
|
597 if (context && size != newSize) { |
|
598 // The surface size has changed, so we need to recreate |
|
599 // the EGL context for the widget. We also need to recreate |
|
600 // the surface's paint engine if context sharing is not |
|
601 // enabled because we cannot reuse the existing paint objects |
|
602 // in the new context. |
|
603 qt_vg_destroy_paint_engine(engine); |
|
604 engine = 0; |
|
605 context->destroySurface(windowSurface); |
|
606 qt_vg_destroy_context(context); |
|
607 context = 0; |
|
608 windowSurface = EGL_NO_SURFACE; |
|
609 } |
|
610 #endif |
|
611 #endif |
|
612 if (!context) { |
|
613 // Create a new EGL context and bind it to the widget surface. |
|
614 size = newSize; |
|
615 context = qt_vg_create_context(widget); |
|
616 if (!context) |
|
617 return 0; |
|
618 // We want a direct to window rendering surface if possible. |
|
619 #if defined(QVG_DIRECT_TO_WINDOW) |
|
620 surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); |
|
621 #endif |
|
622 #if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) |
|
623 if (isPremultipliedContext(context)) { |
|
624 surfaceProps.setValue |
|
625 (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); |
|
626 } else { |
|
627 surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); |
|
628 } |
|
629 #endif |
|
630 EGLSurface surface = context->createSurface(widget, &surfaceProps); |
|
631 if (surface == EGL_NO_SURFACE) { |
|
632 qt_vg_destroy_context(context); |
|
633 context = 0; |
|
634 return 0; |
|
635 } |
|
636 needToSwap = true; |
|
637 #if defined(QVG_DIRECT_TO_WINDOW) |
|
638 // Did we get a direct to window rendering surface? |
|
639 EGLint buffer = 0; |
|
640 if (eglQueryContext(context->display(), context->context(), |
|
641 EGL_RENDER_BUFFER, &buffer) && |
|
642 buffer == EGL_SINGLE_BUFFER) { |
|
643 needToSwap = false; |
|
644 } |
|
645 #endif |
|
646 #if !defined(QVG_NO_PRESERVED_SWAP) |
|
647 // Try to force the surface back buffer to preserve its contents. |
|
648 if (needToSwap) { |
|
649 eglGetError(); // Clear error state first. |
|
650 eglSurfaceAttrib(context->display(), surface, |
|
651 EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); |
|
652 if (eglGetError() != EGL_SUCCESS) { |
|
653 qWarning("QVG: could not enable preserved swap"); |
|
654 } |
|
655 } |
|
656 #endif |
|
657 windowSurface = surface; |
|
658 isPaintingActive = false; |
|
659 } |
|
660 return context; |
|
661 } |
|
662 |
|
663 void QVGEGLWindowSurfaceDirect::beginPaint(QWidget *widget) |
|
664 { |
|
665 QEglContext *context = ensureContext(widget); |
|
666 if (context) { |
|
667 context->makeCurrent(windowSurface); |
|
668 isPaintingActive = true; |
|
669 } |
|
670 } |
|
671 |
|
672 void QVGEGLWindowSurfaceDirect::endPaint |
|
673 (QWidget *widget, const QRegion& region, QImage *image) |
|
674 { |
|
675 Q_UNUSED(region); |
|
676 Q_UNUSED(image); |
|
677 QEglContext *context = ensureContext(widget); |
|
678 if (context) { |
|
679 if (needToSwap) { |
|
680 if (!isPaintingActive) |
|
681 context->makeCurrent(windowSurface); |
|
682 context->swapBuffers(windowSurface); |
|
683 context->lazyDoneCurrent(); |
|
684 } else if (isPaintingActive) { |
|
685 vgFlush(); |
|
686 context->lazyDoneCurrent(); |
|
687 } |
|
688 isPaintingActive = false; |
|
689 } |
|
690 } |
|
691 |
|
692 QT_END_NAMESPACE |
|
693 |
|
694 #endif |