99 return QImage::Format_ARGB4444_Premultiplied; |
100 return QImage::Format_ARGB4444_Premultiplied; |
100 else |
101 else |
101 return argbFormat; // XXX |
102 return argbFormat; // XXX |
102 } |
103 } |
103 |
104 |
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) |
105 #if !defined(QVG_NO_SINGLE_CONTEXT) |
117 |
106 |
118 class QVGSharedContext |
107 class QVGSharedContext |
119 { |
108 { |
120 public: |
109 public: |
121 QVGSharedContext(); |
110 QVGSharedContext(); |
122 ~QVGSharedContext(); |
111 ~QVGSharedContext(); |
123 |
112 |
124 QEglContext *context; |
113 QEglContext *context; |
125 int refCount; |
114 int refCount; |
|
115 int widgetRefCount; |
126 QVGPaintEngine *engine; |
116 QVGPaintEngine *engine; |
127 EGLSurface surface; |
117 EGLSurface surface; |
|
118 QVGPixmapData *firstPixmap; |
128 }; |
119 }; |
129 |
120 |
130 QVGSharedContext::QVGSharedContext() |
121 QVGSharedContext::QVGSharedContext() |
131 : context(0) |
122 : context(0) |
132 , refCount(0) |
123 , refCount(0) |
|
124 , widgetRefCount(0) |
133 , engine(0) |
125 , engine(0) |
134 , surface(EGL_NO_SURFACE) |
126 , surface(EGL_NO_SURFACE) |
|
127 , firstPixmap(0) |
135 { |
128 { |
136 } |
129 } |
137 |
130 |
138 QVGSharedContext::~QVGSharedContext() |
131 QVGSharedContext::~QVGSharedContext() |
139 { |
132 { |
164 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
157 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
165 { |
158 { |
166 Q_UNUSED(engine); |
159 Q_UNUSED(engine); |
167 } |
160 } |
168 |
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 |
169 #else |
186 #else |
170 |
187 |
171 QVGPaintEngine *qt_vg_create_paint_engine(void) |
188 QVGPaintEngine *qt_vg_create_paint_engine(void) |
172 { |
189 { |
173 return new QVGPaintEngine(); |
190 return new QVGPaintEngine(); |
174 } |
191 } |
175 |
192 |
176 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
193 void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) |
177 { |
194 { |
178 delete engine; |
195 delete engine; |
|
196 } |
|
197 |
|
198 void qt_vg_register_pixmap(QVGPixmapData *pd) |
|
199 { |
|
200 Q_UNUSED(pd); |
|
201 } |
|
202 |
|
203 void qt_vg_unregister_pixmap(QVGPixmapData *pd) |
|
204 { |
|
205 Q_UNUSED(pd); |
179 } |
206 } |
180 |
207 |
181 #endif |
208 #endif |
182 |
209 |
183 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
210 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
202 context->setApi(QEgl::OpenVG); |
229 context->setApi(QEgl::OpenVG); |
203 if (!context->openDisplay(device)) { |
230 if (!context->openDisplay(device)) { |
204 delete context; |
231 delete context; |
205 return 0; |
232 return 0; |
206 } |
233 } |
|
234 |
|
235 // Set the swap interval for the display. |
|
236 QByteArray interval = qgetenv("QT_VG_SWAP_INTERVAL"); |
|
237 if (!interval.isEmpty()) |
|
238 eglSwapInterval(context->display(), interval.toInt()); |
|
239 else |
|
240 eglSwapInterval(context->display(), 1); |
|
241 |
|
242 #ifdef EGL_RENDERABLE_TYPE |
|
243 // Has the user specified an explicit EGL configuration to use? |
|
244 QByteArray configId = qgetenv("QT_VG_EGL_CONFIG"); |
|
245 if (!configId.isEmpty()) { |
|
246 EGLint cfgId = configId.toInt(); |
|
247 EGLint properties[] = { |
|
248 EGL_CONFIG_ID, cfgId, |
|
249 EGL_NONE |
|
250 }; |
|
251 EGLint matching = 0; |
|
252 EGLConfig cfg; |
|
253 if (eglChooseConfig |
|
254 (context->display(), properties, &cfg, 1, &matching) && |
|
255 matching > 0) { |
|
256 // Check that the selected configuration actually supports OpenVG |
|
257 // and then create the context with it. |
|
258 EGLint id = 0; |
|
259 EGLint type = 0; |
|
260 eglGetConfigAttrib |
|
261 (context->display(), cfg, EGL_CONFIG_ID, &id); |
|
262 eglGetConfigAttrib |
|
263 (context->display(), cfg, EGL_RENDERABLE_TYPE, &type); |
|
264 if (cfgId == id && (type & EGL_OPENVG_BIT) != 0) { |
|
265 context->setConfig(cfg); |
|
266 if (!context->createContext()) { |
|
267 delete context; |
|
268 return 0; |
|
269 } |
|
270 return context; |
|
271 } else { |
|
272 qWarning("QT_VG_EGL_CONFIG: %d is not a valid OpenVG configuration", int(cfgId)); |
|
273 } |
|
274 } |
|
275 } |
|
276 #endif |
207 |
277 |
208 // Choose an appropriate configuration for rendering into the device. |
278 // Choose an appropriate configuration for rendering into the device. |
209 QEglProperties configProps; |
279 QEglProperties configProps; |
210 configProps.setPaintDeviceFormat(device); |
280 configProps.setPaintDeviceFormat(device); |
211 int redSize = configProps.value(EGL_RED_SIZE); |
281 int redSize = configProps.value(EGL_RED_SIZE); |
214 #ifndef QVG_SCISSOR_CLIP |
284 #ifndef QVG_SCISSOR_CLIP |
215 // If we are using the mask to clip, then explicitly request a mask. |
285 // If we are using the mask to clip, then explicitly request a mask. |
216 configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); |
286 configProps.setValue(EGL_ALPHA_MASK_SIZE, 1); |
217 #endif |
287 #endif |
218 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
288 #ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT |
219 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | |
289 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | |
220 EGL_VG_ALPHA_FORMAT_PRE_BIT); |
290 EGL_VG_ALPHA_FORMAT_PRE_BIT); |
221 configProps.setRenderableType(QEgl::OpenVG); |
291 configProps.setRenderableType(QEgl::OpenVG); |
222 if (!context->chooseConfig(configProps)) { |
292 if (!context->chooseConfig(configProps)) { |
223 // Try again without the "pre" bit. |
293 // Try again without the "pre" bit. |
224 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); |
294 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); |
225 if (!context->chooseConfig(configProps)) { |
295 if (!context->chooseConfig(configProps)) { |
226 delete context; |
296 delete context; |
227 return 0; |
297 return 0; |
228 } |
298 } |
229 } |
299 } |
230 #else |
300 #else |
231 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); |
301 configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); |
232 configProps.setRenderableType(QEgl::OpenVG); |
302 configProps.setRenderableType(QEgl::OpenVG); |
233 if (!context->chooseConfig(configProps)) { |
303 if (!context->chooseConfig(configProps)) { |
234 delete context; |
304 delete context; |
235 return 0; |
305 return 0; |
236 } |
306 } |
245 return context; |
315 return context; |
246 } |
316 } |
247 |
317 |
248 #if !defined(QVG_NO_SINGLE_CONTEXT) |
318 #if !defined(QVG_NO_SINGLE_CONTEXT) |
249 |
319 |
250 QEglContext *qt_vg_create_context(QPaintDevice *device) |
320 QEglContext *qt_vg_create_context(QPaintDevice *device, int devType) |
251 { |
321 { |
252 QVGSharedContext *shared = sharedContext(); |
322 QVGSharedContext *shared = sharedContext(); |
|
323 if (devType == QInternal::Widget) |
|
324 ++(shared->widgetRefCount); |
253 if (shared->context) { |
325 if (shared->context) { |
254 ++(shared->refCount); |
326 ++(shared->refCount); |
255 return shared->context; |
327 return shared->context; |
256 } else { |
328 } else { |
257 shared->context = createContext(device); |
329 shared->context = createContext(device); |
258 shared->refCount = 1; |
330 shared->refCount = 1; |
259 return shared->context; |
331 return shared->context; |
260 } |
332 } |
261 } |
333 } |
262 |
334 |
263 void qt_vg_destroy_context(QEglContext *context) |
335 static void qt_vg_destroy_shared_context(QVGSharedContext *shared) |
|
336 { |
|
337 shared->context->makeCurrent(qt_vg_shared_surface()); |
|
338 delete shared->engine; |
|
339 shared->engine = 0; |
|
340 shared->context->doneCurrent(); |
|
341 if (shared->surface != EGL_NO_SURFACE) { |
|
342 eglDestroySurface(shared->context->display(), shared->surface); |
|
343 shared->surface = EGL_NO_SURFACE; |
|
344 } |
|
345 delete shared->context; |
|
346 shared->context = 0; |
|
347 } |
|
348 |
|
349 void qt_vg_hibernate_pixmaps(QVGSharedContext *shared) |
|
350 { |
|
351 // Artificially increase the reference count to prevent the |
|
352 // context from being destroyed until after we have finished |
|
353 // the hibernation process. |
|
354 ++(shared->refCount); |
|
355 |
|
356 // We need a context current to hibernate the VGImage objects. |
|
357 shared->context->makeCurrent(qt_vg_shared_surface()); |
|
358 |
|
359 // Scan all QVGPixmapData objects in the system and hibernate them. |
|
360 QVGPixmapData *pd = shared->firstPixmap; |
|
361 while (pd != 0) { |
|
362 pd->hibernate(); |
|
363 pd = pd->next; |
|
364 } |
|
365 |
|
366 // Hibernate any remaining VGImage's in the image pool. |
|
367 QVGImagePool::instance()->hibernate(); |
|
368 |
|
369 // Don't need the current context any more. |
|
370 shared->context->lazyDoneCurrent(); |
|
371 |
|
372 // Decrease the reference count and destroy the context if necessary. |
|
373 if (--(shared->refCount) <= 0) |
|
374 qt_vg_destroy_shared_context(shared); |
|
375 } |
|
376 |
|
377 void qt_vg_destroy_context(QEglContext *context, int devType) |
264 { |
378 { |
265 QVGSharedContext *shared = sharedContext(); |
379 QVGSharedContext *shared = sharedContext(); |
266 if (shared->context != context) { |
380 if (shared->context != context) { |
267 // This is not the shared context. Shouldn't happen! |
381 // This is not the shared context. Shouldn't happen! |
268 delete context; |
382 delete context; |
269 } else if (--(shared->refCount) <= 0) { |
383 return; |
270 shared->context->makeCurrent(qt_vg_shared_surface()); |
384 } |
271 delete shared->engine; |
385 if (devType == QInternal::Widget) |
272 shared->engine = 0; |
386 --(shared->widgetRefCount); |
273 shared->context->doneCurrent(); |
387 if (--(shared->refCount) <= 0) { |
274 if (shared->surface != EGL_NO_SURFACE) { |
388 qt_vg_destroy_shared_context(shared); |
275 eglDestroySurface(shared->context->display(), shared->surface); |
389 } else if (shared->widgetRefCount <= 0 && devType == QInternal::Widget) { |
276 shared->surface = EGL_NO_SURFACE; |
390 // All of the widget window surfaces have been destroyed |
277 } |
391 // but we still have VG pixmaps active. Ask them to hibernate |
278 delete shared->context; |
392 // to free up GPU resources until a widget is shown again. |
279 shared->context = 0; |
393 // This may eventually cause the EGLContext to be destroyed |
|
394 // because nothing in the system needs a context, which will |
|
395 // free up even more GPU resources. |
|
396 qt_vg_hibernate_pixmaps(shared); |
280 } |
397 } |
281 } |
398 } |
282 |
399 |
283 EGLSurface qt_vg_shared_surface(void) |
400 EGLSurface qt_vg_shared_surface(void) |
284 { |
401 { |
332 |
451 |
333 QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() |
452 QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() |
334 { |
453 { |
335 // Destroy the paint engine if it hasn't been destroyed already. |
454 // Destroy the paint engine if it hasn't been destroyed already. |
336 destroyPaintEngine(); |
455 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 } |
456 } |
352 |
457 |
353 QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() |
458 QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() |
354 { |
459 { |
355 if (!engine) |
460 if (!engine) |
512 return windowSurface; |
617 return windowSurface; |
513 else |
618 else |
514 return qt_vg_shared_surface(); |
619 return qt_vg_shared_surface(); |
515 } |
620 } |
516 |
621 |
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 |
622 #endif // QVG_VGIMAGE_BACKBUFFERS |
551 |
623 |
552 QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) |
624 QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) |
553 : QVGEGLWindowSurfacePrivate(win) |
625 : QVGEGLWindowSurfacePrivate(win) |
554 , context(0) |
626 , context(0) |
601 // enabled because we cannot reuse the existing paint objects |
673 // enabled because we cannot reuse the existing paint objects |
602 // in the new context. |
674 // in the new context. |
603 qt_vg_destroy_paint_engine(engine); |
675 qt_vg_destroy_paint_engine(engine); |
604 engine = 0; |
676 engine = 0; |
605 context->destroySurface(windowSurface); |
677 context->destroySurface(windowSurface); |
606 qt_vg_destroy_context(context); |
678 qt_vg_destroy_context(context, QInternal::Widget); |
607 context = 0; |
679 context = 0; |
608 windowSurface = EGL_NO_SURFACE; |
680 windowSurface = EGL_NO_SURFACE; |
609 } |
681 } |
610 #endif |
682 #endif |
611 #endif |
683 #endif |
612 if (!context) { |
684 if (!context) { |
613 // Create a new EGL context and bind it to the widget surface. |
685 // Create a new EGL context and bind it to the widget surface. |
614 size = newSize; |
686 size = newSize; |
615 context = qt_vg_create_context(widget); |
687 context = qt_vg_create_context(widget, QInternal::Widget); |
616 if (!context) |
688 if (!context) |
617 return 0; |
689 return 0; |
618 // We want a direct to window rendering surface if possible. |
690 // We want a direct to window rendering surface if possible. |
619 #if defined(QVG_DIRECT_TO_WINDOW) |
691 #if defined(QVG_DIRECT_TO_WINDOW) |
620 surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); |
692 surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); |