diff options
Diffstat (limited to 'src/opengl/qwindowsurface_gl.cpp')
-rw-r--r-- | src/opengl/qwindowsurface_gl.cpp | 155 |
1 files changed, 135 insertions, 20 deletions
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index aad12d7..ed541ce 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -181,16 +181,14 @@ QGLGraphicsSystem::QGLGraphicsSystem(bool useX11GL) // // QGLWindowSurface // - class QGLGlobalShareWidget { public: - QGLGlobalShareWidget() : widget(0), initializing(false) {} + QGLGlobalShareWidget() : firstPixmap(0), widgetRefCount(0), widget(0), initializing(false) {} QGLWidget *shareWidget() { if (!initializing && !widget && !cleanedUp) { initializing = true; - widget = new QGLWidget(QGLFormat(QGL::SingleBuffer | QGL::NoDepthBuffer | QGL::NoStencilBuffer)); widget->resize(1, 1); @@ -226,6 +224,9 @@ public: static bool cleanedUp; + QGLPixmapData *firstPixmap; + int widgetRefCount; + private: QGLWidget *widget; bool initializing; @@ -256,6 +257,43 @@ void qt_destroy_gl_share_widget() _qt_gl_share_widget()->destroy(); } +#ifdef QGL_USE_TEXTURE_POOL +void qt_gl_register_pixmap(QGLPixmapData *pd) +{ + QGLGlobalShareWidget *shared = _qt_gl_share_widget(); + pd->next = shared->firstPixmap; + pd->prev = 0; + if (shared->firstPixmap) + shared->firstPixmap->prev = pd; + shared->firstPixmap = pd; +} + +void qt_gl_unregister_pixmap(QGLPixmapData *pd) +{ + if (pd->next) + pd->next->prev = pd->prev; + if (pd->prev) { + pd->prev->next = pd->next; + } else { + QGLGlobalShareWidget *shared = _qt_gl_share_widget(); + if (shared) + shared->firstPixmap = pd->next; + } +} + +void qt_gl_hibernate_pixmaps() +{ + QGLGlobalShareWidget *shared = _qt_gl_share_widget(); + + // Scan all QGLPixmapData objects in the system and hibernate them. + QGLPixmapData *pd = shared->firstPixmap; + while (pd != 0) { + pd->hibernate(); + pd = pd->next; + } +} +#endif + struct QGLWindowSurfacePrivate { QGLFramebufferObject *fbo; @@ -333,6 +371,10 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window) d_ptr->q_ptr = this; d_ptr->geometry_updated = false; d_ptr->did_paint = false; + +#ifdef QGL_NO_PRESERVED_SWAP + setPartialUpdateSupport(false); +#endif } QGLWindowSurface::~QGLWindowSurface() @@ -347,6 +389,27 @@ QGLWindowSurface::~QGLWindowSurface() delete d_ptr->pb; delete d_ptr->fbo; delete d_ptr; + + if (QGLGlobalShareWidget::cleanedUp) + return; + + --(_qt_gl_share_widget()->widgetRefCount); + +#ifdef QGL_USE_TEXTURE_POOL + if (_qt_gl_share_widget()->widgetRefCount <= 0) { + // All of the widget window surfaces have been destroyed + // but we still have GL pixmaps active. Ask them to hibernate + // to free up GPU resources until a widget is shown again. + // This may eventually cause the EGLContext to be destroyed + // because nothing in the system needs a context, which will + // free up even more GPU resources. + qt_gl_hibernate_pixmaps(); + + // Destroy the context if necessary. + if (!qt_gl_share_widget()->context()->isSharing()) + qt_destroy_gl_share_widget(); + } +#endif } void QGLWindowSurface::deleted(QObject *object) @@ -394,6 +457,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) ctx->create(qt_gl_share_widget()->context()); + if (widget != qt_gl_share_widget()) + ++(_qt_gl_share_widget()->widgetRefCount); + #ifndef QT_NO_EGL static bool checkedForNOKSwapRegion = false; static bool haveNOKSwapRegion = false; @@ -406,8 +472,16 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) qDebug() << "Found EGL_NOK_swap_region2 extension. Using partial updates."; } - if (ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR) != EGL_BUFFER_PRESERVED && - ! haveNOKSwapRegion) + bool swapBehaviourPreserved = ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR); + if (ctx->d_func()->eglContext->configAttrib(EGL_SURFACE_TYPE)&EGL_SWAP_BEHAVIOR_PRESERVED_BIT) { + EGLint swapBehavior; + if (eglQuerySurface(ctx->d_func()->eglContext->display(), ctx->d_func()->eglSurface + , EGL_SWAP_BEHAVIOR, &swapBehavior)) { + swapBehaviourPreserved = (swapBehavior == EGL_BUFFER_PRESERVED); + } + } + + if (!swapBehaviourPreserved && !haveNOKSwapRegion) setPartialUpdateSupport(false); // Force full-screen updates else setPartialUpdateSupport(true); @@ -421,7 +495,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) voidPtr = &widgetPrivate->extraData()->glContext; d_ptr->contexts << ctxPtr; +#ifndef Q_OS_SYMBIAN qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size(); +#endif } QGLContext *QGLWindowSurface::context() const @@ -450,6 +526,8 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, void QGLWindowSurface::beginPaint(const QRegion &) { + updateGeometry(); + if (!context()) return; @@ -776,32 +854,68 @@ void QGLWindowSurface::updateGeometry() { return; d_ptr->geometry_updated = false; - QRect rect = geometry(); - hijackWindow(window()); - QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext); + bool hijack(true); + QWidgetPrivate *wd = window()->d_func(); + if (wd->extraData() && wd->extraData()->glContext) + hijack = false; // we already have gl context for widget + + if (hijack) + hijackWindow(window()); + + QGLContext *ctx = reinterpret_cast<QGLContext *>(wd->extraData()->glContext); #ifdef Q_WS_MAC ctx->updatePaintDevice(); #endif - const GLenum target = GL_TEXTURE_2D; + QSize surfSize = geometry().size(); - if (rect.width() <= 0 || rect.height() <= 0) + if (surfSize.width() <= 0 || surfSize.height() <= 0) return; - if (d_ptr->size == rect.size()) + if (d_ptr->size == surfSize) return; - d_ptr->size = rect.size(); + d_ptr->size = surfSize; + +#ifdef Q_OS_SYMBIAN + if (!hijack) { // Symbian needs to recreate EGL surface when native window size changes + if (ctx->d_func()->eglSurface != EGL_NO_SURFACE) { + eglDestroySurface(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface); + } + + ctx->d_func()->eglSurface = QEgl::createSurface(ctx->device(), + ctx->d_func()->eglContext->config()); + + eglGetError(); // Clear error state. + if (hasPartialUpdateSupport()) { + eglSurfaceAttrib(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface: could not enable preserved swap behaviour"); + } else { + eglSurfaceAttrib(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface: could not enable destroyed swap behaviour"); + } + } +#endif if (d_ptr->ctx) { #ifndef QT_OPENGL_ES_2 if (d_ptr->destructive_swap_buffers) - initializeOffscreenTexture(rect.size()); + initializeOffscreenTexture(surfSize); #endif return; } + const GLenum target = GL_TEXTURE_2D; if (d_ptr->destructive_swap_buffers && (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject) && (d_ptr->fbo || !d_ptr->tried_fbo) @@ -820,10 +934,10 @@ void QGLWindowSurface::updateGeometry() { if (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit) format.setSamples(8); - d_ptr->fbo = new QGLFramebufferObject(rect.size(), format); + d_ptr->fbo = new QGLFramebufferObject(surfSize, format); if (d_ptr->fbo->isValid()) { - qDebug() << "Created Window Surface FBO" << rect.size() + qDebug() << "Created Window Surface FBO" << surfSize << "with samples" << d_ptr->fbo->format().samples(); return; } else { @@ -844,7 +958,7 @@ void QGLWindowSurface::updateGeometry() { delete d_ptr->pb; - d_ptr->pb = new QGLPixelBuffer(rect.width(), rect.height(), + d_ptr->pb = new QGLPixelBuffer(surfSize.width(), surfSize.height(), QGLFormat(QGL::SampleBuffers | QGL::StencilBuffer | QGL::DepthBuffer), qt_gl_share_widget()); @@ -854,7 +968,7 @@ void QGLWindowSurface::updateGeometry() { glGenTextures(1, &d_ptr->pb_tex_id); glBindTexture(target, d_ptr->pb_tex_id); - glTexImage2D(target, 0, GL_RGBA, rect.width(), rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(target, 0, GL_RGBA, surfSize.width(), surfSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -878,10 +992,11 @@ void QGLWindowSurface::updateGeometry() { #ifndef QT_OPENGL_ES_2 if (d_ptr->destructive_swap_buffers) - initializeOffscreenTexture(rect.size()); + initializeOffscreenTexture(surfSize); +#endif +#ifndef Q_OS_SYMBIAN + qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this; #endif - - qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;; d_ptr->ctx = ctx; d_ptr->ctx->d_ptr->internal_context = true; } |