diff options
author | Gunnar Sletta <gunnar@trolltech.com> | 2009-10-02 09:40:07 (GMT) |
---|---|---|
committer | Gunnar Sletta <gunnar@trolltech.com> | 2009-10-02 09:40:07 (GMT) |
commit | cfd31c28f2e30ee725d23c36ea8349f984b57047 (patch) | |
tree | 5fcf867475a6fde5b884c9236350460cee0ed95f /src/opengl | |
parent | 46c17756dfa231d5ce7a8907330d97807880a04c (diff) | |
parent | fe85e470d76f6e53759d0fd508e858add5de1eb0 (diff) | |
download | Qt-cfd31c28f2e30ee725d23c36ea8349f984b57047.zip Qt-cfd31c28f2e30ee725d23c36ea8349f984b57047.tar.gz Qt-cfd31c28f2e30ee725d23c36ea8349f984b57047.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into 4.6
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager.cpp | 8 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager_p.h | 2 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 1 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 73 | ||||
-rw-r--r-- | src/opengl/qgl.h | 2 | ||||
-rw-r--r-- | src/opengl/qgl_egl.cpp | 17 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 19 | ||||
-rw-r--r-- | src/opengl/qgl_x11.cpp | 92 | ||||
-rw-r--r-- | src/opengl/qgl_x11egl.cpp | 333 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 58 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject_p.h | 7 | ||||
-rw-r--r-- | src/opengl/qglpixelbuffer_x11.cpp | 33 | ||||
-rw-r--r-- | src/opengl/qglpixmapfilter.cpp | 197 | ||||
-rw-r--r-- | src/opengl/qglshaderprogram.cpp | 8 | ||||
-rw-r--r-- | src/opengl/qpaintengine_opengl.cpp | 26 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 2 |
16 files changed, 440 insertions, 438 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index eceed06..fcb20b4 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -78,7 +78,7 @@ const char* QGLEngineSharedShaders::qglEngineShaderSourceCode[] = { }; QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) - : ctx(QGLContextPrivate::contextGroup(context)) + : ctxGuard(context) , blitShaderProg(0) , simpleShaderProg(0) { @@ -223,7 +223,7 @@ QGLShader *QGLEngineSharedShaders::compileNamedShader(ShaderName name, QGLShader return compiledShaders[name]; QByteArray source = qglEngineShaderSourceCode[name]; - QGLShader *newShader = new QGLShader(type, ctx->context(), this); + QGLShader *newShader = new QGLShader(type, ctxGuard.context(), this); newShader->compile(source); #if defined(QT_DEBUG) @@ -245,7 +245,7 @@ QGLShader *QGLEngineSharedShaders::compileCustomShader(QGLCustomShaderStage *sta if (newShader) return newShader; - newShader = new QGLShader(type, ctx->context(), this); + newShader = new QGLShader(type, ctxGuard.context(), this); newShader->compile(source); customShaderCache.insert(source, newShader); @@ -273,7 +273,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS QGLEngineShaderProg &cached = cachedPrograms.last(); // If the shader program's not found in the cache, create it now. - cached.program = new QGLShaderProgram(ctx->context(), this); + cached.program = new QGLShaderProgram(ctxGuard.context(), this); cached.program->addShader(cached.mainVertexShader); cached.program->addShader(cached.positionVertexShader); cached.program->addShader(cached.mainFragShader); diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 47d9a2a..fbb6d9c 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -361,7 +361,7 @@ private slots: void shaderDestroyed(QObject *shader); private: - QGLContextGroup *ctx; + QGLSharedResourceGuard ctxGuard; QGLShaderProgram *blitShaderProg; QGLShaderProgram *simpleShaderProg; QList<QGLEngineShaderProg> cachedPrograms; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 7e45fd9..f612bc0 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1452,6 +1452,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) #if !defined(QT_OPENGL_ES_2) bool success = qt_resolve_version_2_0_functions(d->ctx); Q_ASSERT(success); + Q_UNUSED(success); #endif d->shaderManager = new QGLEngineShaderManager(d->ctx); diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 77dc9ae..2327d7a 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1626,9 +1626,8 @@ void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap) } #if defined(Q_WS_X11) QPixmapData *pd = pixmap->data_ptr().data(); - // Only need to delete the gl surface if the pixmap is about to be deleted - if (pd->ref == 0) - QGLContextPrivate::destroyGlSurfaceForPixmap(pd); + Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken + QGLContextPrivate::destroyGlSurfaceForPixmap(pd); #endif } @@ -1721,7 +1720,7 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg() the top left corner. Inverting the texture implies a deep copy prior to upload. - \value MipmapBindOption Specifies that bindTexture should try + \value MipmapBindOption Specifies that bindTexture() should try to generate mipmaps. If the GL implementation supports the \c GL_SGIS_generate_mipmap extension, mipmaps will be automatically generated for the texture. Mipmap generation is only supported for @@ -2267,7 +2266,7 @@ QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum targe Q_Q(QGLContext); QGLTexture *texture = QGLTextureCache::instance()->getTexture(key); if (texture && texture->target == target - && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context))) + && (texture->context == q || QGLContext::areSharing(q, texture->context))) { return texture; } @@ -2374,6 +2373,8 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format) } /*! + \since 4.6 + Generates and binds a 2D GL texture to the current context, based on \a image. The generated texture id is returned and can be used in later \c glBindTexture() calls. @@ -2435,6 +2436,7 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma /*! \overload + \since 4.6 Generates and binds a 2D GL texture to the current context, based on \a pixmap. @@ -2768,6 +2770,20 @@ void QGLContext::setDevice(QPaintDevice *pDev) */ /*! + Returns true if \a context1 and \a context2 are sharing their + GL resources such as textures, shader programs, etc; + otherwise returns false. + + \since 4.6 +*/ +bool QGLContext::areSharing(const QGLContext *context1, const QGLContext *context2) +{ + if (!context1 || !context2) + return false; + return context1->d_ptr->group == context2->d_ptr->group; +} + +/*! \fn bool QGLContext::deviceIsPixmap() const Returns true if the paint device of this context is a pixmap; @@ -4502,6 +4518,7 @@ GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format) /*! \overload + \since 4.6 The binding \a options are a set of options used to decide how to bind the texture to the context. @@ -4543,6 +4560,7 @@ GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format /*! \overload + \since 4.6 Generates and binds a 2D GL texture to the current context, based on \a pixmap. The generated texture id is returned and can be used in @@ -4848,55 +4866,46 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name() } #endif -bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) { - bool sharing = (context1 && context2 && context1->d_ptr->group == context2->d_ptr->group); - return sharing; -} - void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) { Q_ASSERT(context && share); if (context->d_ptr->group == share->d_ptr->group) return; // Make sure 'context' is not already shared with another group of contexts. - Q_ASSERT(reg.find(context->d_ptr->group) == reg.end()); Q_ASSERT(context->d_ptr->group->m_refs == 1); // Free 'context' group resources and make it use the same resources as 'share'. + QGLContextGroup *group = share->d_ptr->group; delete context->d_ptr->group; - context->d_ptr->group = share->d_ptr->group; - context->d_ptr->group->m_refs.ref(); + context->d_ptr->group = group; + group->m_refs.ref(); // Maintain a list of all the contexts in each group of sharing contexts. - SharingHash::iterator it = reg.find(share->d_ptr->group); - if (it == reg.end()) - it = reg.insert(share->d_ptr->group, ContextList() << share); - it.value() << context; + // The list is empty if the "share" context wasn't sharing already. + if (group->m_shares.isEmpty()) + group->m_shares.append(share); + group->m_shares.append(context); } QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) { - SharingHash::const_iterator it = reg.find(context->d_ptr->group); - if (it == reg.end()) - return ContextList(); - return it.value(); + return context->d_ptr->group->m_shares; } void QGLShareRegister::removeShare(const QGLContext *context) { - SharingHash::iterator it = reg.find(context->d_ptr->group); - if (it == reg.end()) + // Remove the context from the group. + QGLContextGroup *group = context->d_ptr->group; + if (group->m_shares.isEmpty()) return; - - int count = it.value().removeAll(context); - Q_ASSERT(count == 1); - Q_UNUSED(count); + group->m_shares.removeAll(context); // Update context group representative. - if (context->d_ptr->group->m_context == context) - context->d_ptr->group->m_context = it.value().first(); + Q_ASSERT(group->m_shares.size() != 0); + if (group->m_context == context) + group->m_context = group->m_shares[0]; - Q_ASSERT(it.value().size() != 0); - if (it.value().size() == 1) - reg.erase(it); + // If there is only one context left, then make the list empty. + if (group->m_shares.size() == 1) + group->m_shares.clear(); } QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent) diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 1776004..b1c1317 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -282,6 +282,8 @@ public: bool isSharing() const; void reset(); + static bool areSharing(const QGLContext *context1, const QGLContext *context2); + QGLFormat format() const; QGLFormat requestedFormat() const; void setFormat(const QGLFormat& format); diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index 5ce1a45..fa876c7 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -142,10 +142,23 @@ void QGLContext::reset() d->cleanup(); doneCurrent(); if (d->eglContext) { + if (d->eglSurface != EGL_NO_SURFACE) { +#ifdef Q_WS_X11 + // Make sure we don't call eglDestroySurface on a surface which + // was created for a different winId: + if (d->paintDevice->devType() == QInternal::Widget) { + QGLWidget* w = static_cast<QGLWidget*>(d->paintDevice); + + if (w->d_func()->eglSurfaceWindowId == w->winId()) + eglDestroySurface(d->eglContext->display(), d->eglSurface); + } else +#endif + eglDestroySurface(d->eglContext->display(), d->eglSurface); + } delete d->eglContext; - d->eglContext = 0; } - d->eglSurface = EGL_NO_SURFACE; // XXX - probably need to destroy surface + d->eglContext = 0; + d->eglSurface = EGL_NO_SURFACE; d->crWin = false; d->sharing = false; d->valid = false; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 2e8ac88..1957429 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -233,6 +233,7 @@ private: QGLExtensionFuncs m_extensionFuncs; const QGLContext *m_context; // context group's representative + QList<const QGLContext *> m_shares; QAtomicInt m_refs; friend class QGLShareRegister; @@ -343,13 +344,11 @@ public: #ifdef Q_WS_WIN static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); } - static inline QGLExtensionFuncs& extensionFuncs(QGLContextGroup *ctx) { return ctx->extensionFuncs(); } #endif #if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) static QGLExtensionFuncs qt_extensionFuncs; static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *) { return qt_extensionFuncs; } - static inline QGLExtensionFuncs& extensionFuncs(QGLContextGroup *) { return qt_extensionFuncs; } #endif static void setCurrentContext(QGLContext *context); @@ -399,21 +398,15 @@ public: Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions) -class QGLShareRegister +class Q_AUTOTEST_EXPORT QGLShareRegister { public: QGLShareRegister() {} - ~QGLShareRegister() { reg.clear(); } + ~QGLShareRegister() {} - bool checkSharing(const QGLContext *context1, const QGLContext *context2); void addShare(const QGLContext *context, const QGLContext *share); QList<const QGLContext *> shares(const QGLContext *context); void removeShare(const QGLContext *context); -private: - // Use a context's 'group' pointer to uniquely identify a group. - typedef QList<const QGLContext *> ContextList; - typedef QHash<const QGLContextGroup *, ContextList> SharingHash; - SharingHash reg; }; extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg(); @@ -436,7 +429,7 @@ public: QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext()); QGLContext *ctx = const_cast<QGLContext *>(context); Q_ASSERT(ctx); - bool switch_context = current != ctx && !qgl_share_reg()->checkSharing(current, ctx); + bool switch_context = current != ctx && !QGLContext::areSharing(current, ctx); if (switch_context) ctx->makeCurrent(); #if defined(Q_WS_X11) @@ -491,8 +484,6 @@ private: #ifdef Q_WS_QWS extern QPaintEngine* qt_qgl_paint_engine(); - -extern EGLDisplay qt_qgl_egl_display(); #endif bool qt_gl_preferGL2Engine(); @@ -547,7 +538,7 @@ public: : m_oldContext(0) { QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); - if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) { + if (currentContext != ctx && !QGLContext::areSharing(ctx, currentContext)) { m_oldContext = currentContext; m_ctx = const_cast<QGLContext *>(ctx); m_ctx->makeCurrent(); diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index da7972d..86e593d 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -331,6 +331,62 @@ static void find_trans_colors() QGLFormat UNIX/GLX-specific code *****************************************************************************/ +void* qglx_getProcAddress(const char* procName) +{ + // On systems where the GL driver is pluggable (like Mesa), we have to use + // the glXGetProcAddressARB extension to resolve other function pointers as + // the symbols wont be in the GL library, but rather in a plugin loaded by + // the GL library. + typedef void* (*qt_glXGetProcAddressARB)(const char *); + static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; + static bool triedResolvingGlxGetProcAddress = false; + if (!triedResolvingGlxGetProcAddress) { + triedResolvingGlxGetProcAddress = true; + QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); + if (glxExt.contains(QLatin1String("GLX_ARB_get_proc_address"))) { +#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) + void *handle = dlopen(NULL, RTLD_LAZY); + if (handle) { + glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB"); + dlclose(handle); + } + if (!glXGetProcAddressARB) +#endif + { +#if !defined(QT_NO_LIBRARY) + extern const QString qt_gl_library_name(); + QLibrary lib(qt_gl_library_name()); + glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB"); +#endif + } + } + } + + void *procAddress = 0; + if (glXGetProcAddressARB) + procAddress = glXGetProcAddressARB(procName); + + // If glXGetProcAddress didn't work, try looking the symbol up in the GL library +#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) + if (!procAddress) { + void *handle = dlopen(NULL, RTLD_LAZY); + if (handle) { + procAddress = dlsym(handle, procName); + dlclose(handle); + } + } +#endif +#if !defined(QT_NO_LIBRARY) + if (!procAddress) { + extern const QString qt_gl_library_name(); + QLibrary lib(qt_gl_library_name()); + procAddress = lib.resolve(procName); + } +#endif + + return procAddress; +} + bool QGLFormat::hasOpenGL() { return glXQueryExtension(X11->display, 0, 0) != 0; @@ -819,23 +875,8 @@ void QGLContext::swapBuffers() const if (!resolved) { QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) { -#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) - void *handle = dlopen(NULL, RTLD_LAZY); - if (handle) { - glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) dlsym(handle, "glXGetVideoSyncSGI"); - glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) dlsym(handle, "glXWaitVideoSyncSGI"); - dlclose(handle); - } - if (!glXGetVideoSyncSGI) -#endif - { -#if !defined(QT_NO_LIBRARY) - extern const QString qt_gl_library_name(); - QLibrary lib(qt_gl_library_name()); - glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) lib.resolve("glXGetVideoSyncSGI"); - glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) lib.resolve("glXWaitVideoSyncSGI"); -#endif - } + glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI"); + glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI"); } resolved = true; } @@ -1568,21 +1609,8 @@ bool qt_resolveTextureFromPixmap() QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) { -#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) - void *handle = dlopen(NULL, RTLD_LAZY); - if (handle) { - glXBindTexImageEXT = (qt_glXBindTexImageEXT) dlsym(handle, "glXBindTexImageEXT"); - glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) dlsym(handle, "glXReleaseTexImageEXT"); - dlclose(handle); - } - if (!glXBindTexImageEXT) -#endif - { - extern const QString qt_gl_library_name(); - QLibrary lib(qt_gl_library_name()); - glXBindTexImageEXT = (qt_glXBindTexImageEXT) lib.resolve("glXBindTexImageEXT"); - glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) lib.resolve("glXReleaseTexImageEXT"); - } + glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT"); + glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT"); } } diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 70b2013..971a660 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -150,85 +150,36 @@ void QGLWidget::updateOverlayGL() //handle overlay } -void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) +bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual) { - Q_D(QGLWidget); - if (context == 0) { - qWarning("QGLWidget::setContext: Cannot set null context"); - return; - } - if (!context->deviceIsPixmap() && context->device() != this) { - qWarning("QGLWidget::setContext: Context must refer to this widget"); - return; - } - - if (d->glcx) - d->glcx->doneCurrent(); - QGLContext* oldcx = d->glcx; - d->glcx = context; - - if (parentWidget()) { - // force creation of delay-created widgets - parentWidget()->winId(); - if (parentWidget()->x11Info().screen() != x11Info().screen()) - d_func()->xinfo = parentWidget()->d_func()->xinfo; - } - - // If the application has set WA_TranslucentBackground and not explicitly set - // the alpha buffer size to zero, modify the format so it have an alpha channel - QGLFormat& fmt = d->glcx->d_func()->glFormat; - const bool useArgbVisual = testAttribute(Qt::WA_TranslucentBackground); - if (useArgbVisual && fmt.alphaBufferSize() == -1) - fmt.setAlphaBufferSize(1); - - bool createFailed = false; - if (!d->glcx->isValid()) { - if (!d->glcx->create(shareContext ? shareContext : oldcx)) - createFailed = true; - } - if (createFailed) { - if (deleteOldContext) - delete oldcx; - return; - } + bool foundVisualIsArgb = useArgbVisual; - if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) { - if (deleteOldContext) - delete oldcx; - return; - } - - bool visible = isVisible(); - if (visible) - hide(); - - XVisualInfo vi; memset(&vi, 0, sizeof(XVisualInfo)); // Check to see if EGL is suggesting an appropriate visual id: EGLint nativeVisualId; - QEglContext* qeglCtx = d->glcx->d_func()->eglContext; - qeglCtx->configAttrib(EGL_NATIVE_VISUAL_ID, &nativeVisualId); + eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId); vi.visualid = nativeVisualId; if (vi.visualid) { // EGL has suggested a visual id, so get the rest of the visual info for that id: XVisualInfo *chosenVisualInfo; int matchingCount = 0; - chosenVisualInfo = XGetVisualInfo(x11Info().display(), VisualIDMask, &vi, &matchingCount); + chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount); if (chosenVisualInfo) { #if !defined(QT_NO_XRENDER) if (useArgbVisual) { // Check to make sure the visual provided by EGL is ARGB XRenderPictFormat *format; - format = XRenderFindVisualFormat(x11Info().display(), chosenVisualInfo->visual); + format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual); if (format->type == PictTypeDirect && format->direct.alphaMask) { -// qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid); +// qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid); + foundVisualIsArgb = true; vi = *chosenVisualInfo; } else { qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB", - nativeVisualId, (int)qeglCtx->config()); + nativeVisualId, (int)config); vi.visualid = 0; } } else @@ -241,32 +192,32 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, } else { qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!", - nativeVisualId, (int)qeglCtx->config()); + nativeVisualId, (int)config); vi.visualid = 0; } } // If EGL does not know the visual ID, so try to select an appropriate one ourselves, first // using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo - - bool useArgb = context->format().alpha() && !context->deviceIsPixmap(); + #if !defined(QT_NO_XRENDER) - if (vi.visualid == 0 && useArgb) { + if (vi.visualid == 0 && useArgbVisual) { // Try to use XRender to find an ARGB visual we can use - vi.screen = x11Info().screen(); - vi.depth = 32; + vi.screen = x11Info.screen(); + vi.depth = 32; //### We might at some point (soon) get ARGB4444 vi.c_class = TrueColor; XVisualInfo *matchingVisuals; int matchingCount = 0; - matchingVisuals = XGetVisualInfo(x11Info().display(), + matchingVisuals = XGetVisualInfo(x11Info.display(), VisualScreenMask|VisualDepthMask|VisualClassMask, &vi, &matchingCount); for (int i = 0; i < matchingCount; ++i) { XRenderPictFormat *format; - format = XRenderFindVisualFormat(x11Info().display(), matchingVisuals[i].visual); + format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual); if (format->type == PictTypeDirect && format->direct.alphaMask) { vi = matchingVisuals[i]; + foundVisualIsArgb = true; // qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); break; } @@ -277,17 +228,17 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, if (vi.visualid == 0) { EGLint depth; - qeglCtx->configAttrib(EGL_BUFFER_SIZE, &depth); + eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth); int err; - err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi); + err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi); if (err == 0) { qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!", - (int)qeglCtx->config(), depth); - depth = x11Info().depth(); - err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi); + (int)config, depth); + depth = x11Info.depth(); + err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi); if (err == 0) { qWarning("Error: Couldn't get any matching X visual!"); - return; + return false; } else qWarning(" - Falling back to X11 suggested depth (%d)", depth); } @@ -295,8 +246,8 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, // qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-( - if (useArgb) - useArgb = vi.depth == 32; + if (useArgbVisual) + foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444 } // qDebug("Visual Info:"); @@ -309,6 +260,65 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, // qDebug(" depth=%d", vi.depth); // qDebug(" screen=%d", vi.screen); // qDebug(" visualid=%d", vi.visualid); + return foundVisualIsArgb; +} + +void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext) +{ + Q_D(QGLWidget); + if (context == 0) { + qWarning("QGLWidget::setContext: Cannot set null context"); + return; + } + if (!context->deviceIsPixmap() && context->device() != this) { + qWarning("QGLWidget::setContext: Context must refer to this widget"); + return; + } + + if (d->glcx) + d->glcx->doneCurrent(); + QGLContext* oldcx = d->glcx; + d->glcx = context; + + if (parentWidget()) { + // force creation of delay-created widgets + parentWidget()->winId(); + if (parentWidget()->x11Info().screen() != x11Info().screen()) + d_func()->xinfo = parentWidget()->d_func()->xinfo; + } + + // If the application has set WA_TranslucentBackground and not explicitly set + // the alpha buffer size to zero, modify the format so it have an alpha channel + QGLFormat& fmt = d->glcx->d_func()->glFormat; + const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground); + if (tryArgbVisual && fmt.alphaBufferSize() == -1) + fmt.setAlphaBufferSize(1); + + bool createFailed = false; + if (!d->glcx->isValid()) { + if (!d->glcx->create(shareContext ? shareContext : oldcx)) + createFailed = true; + } + if (createFailed) { + if (deleteOldContext) + delete oldcx; + return; + } + + if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) { + if (deleteOldContext) + delete oldcx; + return; + } + + bool visible = isVisible(); + if (visible) + hide(); + + XVisualInfo vi; + QEglContext *eglContext = d->glcx->d_func()->eglContext; + bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(), + x11Info(), tryArgbVisual); XSetWindowAttributes a; @@ -321,7 +331,7 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, a.border_pixel = colmap.pixel(Qt::black); unsigned int valueMask = CWBackPixel|CWBorderPixel; - if(useArgb) { + if (usingArgbVisual) { a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone); valueMask |= CWColormap; } @@ -418,6 +428,103 @@ void QGLWidgetPrivate::recreateEglSurface(bool force) } } +// Selects which configs should be used +EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly) +{ + // Cache the configs we select as they wont change: + static EGLConfig roPixmapRGBConfig = 0; + static EGLConfig roPixmapRGBAConfig = 0; + static EGLConfig rwPixmapRGBConfig = 0; + static EGLConfig rwPixmapRGBAConfig = 0; + + EGLConfig* targetConfig; + + if (hasAlpha) { + if (readOnly) + targetConfig = &roPixmapRGBAConfig; + else + targetConfig = &rwPixmapRGBAConfig; + } + else { + if (readOnly) + targetConfig = &roPixmapRGBConfig; + else + targetConfig = &rwPixmapRGBConfig; + } + + if (*targetConfig == 0) { + QEglProperties configAttribs; + configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT); + configAttribs.setRenderableType(QEgl::OpenGL); + if (hasAlpha) + configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); + else + configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); + + // If this is going to be a render target, it needs to have a depth, stencil & sample buffer + if (!readOnly) { + configAttribs.setValue(EGL_DEPTH_SIZE, 1); + configAttribs.setValue(EGL_STENCIL_SIZE, 1); + configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1); + } + + EGLint configCount = 0; + do { + eglChooseConfig(QEglContext::defaultDisplay(0), configAttribs.properties(), targetConfig, 1, &configCount); + if (configCount > 0) { + // Got one + qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" ) + << "config (" << int(*targetConfig) << ") to create a pixmap surface:"; + +// QEglProperties configProps(*targetConfig); +// qDebug() << configProps.toString(); + break; + } + qWarning("choosePixmapConfig() - No suitible config found, reducing requirements"); + } while (configAttribs.reduceConfiguration()); + } + + if (*targetConfig == 0) + qWarning("choosePixmapConfig() - Couldn't find a suitable config"); + + return *targetConfig; +} + +bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly) +{ + Q_ASSERT(pmd->classId() == QPixmapData::X11Class); + QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd); + + bool hasAlpha = pixmapData->hasAlphaChannel(); + + EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly); + + QEglProperties pixmapAttribs; + + // If the pixmap can't be bound to a texture, it's pretty useless + pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D); + if (hasAlpha) + pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA); + else + pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB); + + EGLSurface pixmapSurface; + pixmapSurface = eglCreatePixmapSurface(QEglContext::defaultDisplay(0), + pixmapConfig, + (EGLNativePixmapType) pixmapData->handle(), + pixmapAttribs.properties()); + if (pixmapSurface == EGL_NO_SURFACE) { + qWarning("Failed to create a pixmap surface using config %d", (int)pixmapConfig); + return false; + } + + Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure! + pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; + pixmapData->is_cached = true; // Make sure the cleanup hook gets called + + return true; +} + QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, QGLContext::BindOptions options) @@ -459,82 +566,14 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons destroyGlSurfaceForPixmap(pixmapData); } - EGLint pixmapAttribs[] = { - EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, - EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, - EGL_NONE - }; - Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure! - if (pixmapData->gl_surface == 0) - pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE; - EGLSurface pixmapSurface = (EGLSurface)pixmapData->gl_surface; - static EGLConfig pixmapRGBConfig = 0; - static EGLConfig pixmapRGBAConfig = 0; - - // Check to see if we need to find a config - if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) { - const EGLint configAttribs[] = { - EGL_SURFACE_TYPE, EGL_PIXMAP_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_DEPTH_SIZE, 0, - hasAlpha ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE, - EGL_NONE - }; - - EGLint configCount = 0; - eglChooseConfig(eglContext->display(), configAttribs, 0, 256, &configCount); - if (configCount == 0) { - haveTFP = false; - qWarning("bindTextureFromNativePixmap() - Couldn't find a suitable config"); - return 0; - } - - EGLConfig *configList = new EGLConfig[configCount]; - eglChooseConfig(eglContext->display(), configAttribs, configList, configCount, &configCount); - Q_ASSERT(configCount); - - // Try to create a pixmap surface for each config until one works - for (int i = 0; i < configCount; ++i) { - pixmapSurface = eglCreatePixmapSurface(eglContext->display(), configList[i], - (EGLNativePixmapType) pixmapData->handle(), - pixmapAttribs); - if (pixmapSurface != EGL_NO_SURFACE) { - // Got one! - qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") - << "config (" << int(configList[i]) << ") to create a pixmap surface"; - if (hasAlpha) - pixmapRGBAConfig = configList[i]; - else - pixmapRGBConfig = configList[i]; - pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; - break; - } - } - delete configList; - - if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) { - qDebug("Couldn't create a pixmap surface with any of the provided configs"); - haveTFP = false; - return 0; - } - } - - if (pixmapSurface == EGL_NO_SURFACE) { - pixmapSurface = eglCreatePixmapSurface(eglContext->display(), - hasAlpha? pixmapRGBAConfig : pixmapRGBConfig, - (EGLNativePixmapType) pixmapData->handle(), - pixmapAttribs); - if (pixmapSurface == EGL_NO_SURFACE) { - qWarning("Failed to create a pixmap surface using config %d", - (int)(hasAlpha? pixmapRGBAConfig : pixmapRGBConfig)); + if (pixmapData->gl_surface == 0) { + bool success = qt_createEGLSurfaceForPixmap(pixmapData, true); + if (!success) { haveTFP = false; return 0; } - pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; } - // Make sure the cleanup hook gets called so we can delete the glx pixmap - pixmapData->is_cached = true; Q_ASSERT(pixmapData->gl_surface); GLuint textureId; @@ -544,10 +583,10 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons // bind the egl pixmap surface to a texture EGLBoolean success; - success = eglBindTexImage(eglContext->display(), pixmapSurface, EGL_BACK_BUFFER); + success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER); if (success == EGL_FALSE) { qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError()); - eglDestroySurface(eglContext->display(), pixmapSurface); + eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface); pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE; haveTFP = false; return 0; diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index c728902..3e54b35 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -64,7 +64,8 @@ QT_BEGIN_NAMESPACE extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); -#define QGL_FUNC_CONTEXT QGLContextGroup *ctx = d_ptr->ctx; +#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context(); +#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context(); #ifndef QT_NO_DEBUG #define QT_RESET_GLERROR() \ @@ -317,7 +318,7 @@ void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f, QGLFramebufferObject::Attachment attachment) { fbo = f; - m_thisFBO = fbo->d_func()->fbo; // This shouldn't be needed + m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed // The context that the fbo was created in may not have depth // and stencil buffers, but the fbo itself might. @@ -334,7 +335,7 @@ void QGLFBOGLPaintDevice::ensureActiveTarget() { QGLContext* ctx = const_cast<QGLContext*>(QGLContext::currentContext()); Q_ASSERT(ctx); - const GLuint fboId = fbo->d_func()->fbo; + const GLuint fboId = fbo->d_func()->fbo(); if (ctx->d_func()->current_fbo != fboId) { ctx->d_func()->current_fbo = fboId; glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId); @@ -359,6 +360,9 @@ void QGLFBOGLPaintDevice::endPaint() bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const { + QGL_FUNCP_CONTEXT; + if (!ctx) + return false; // Context no longer exists. GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); switch(status) { case GL_NO_ERROR: @@ -405,11 +409,11 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, QGLFramebufferObject::Attachment attachment, GLenum texture_target, GLenum internal_format, GLint samples) { - QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext()); - ctx = QGLContextPrivate::contextGroup(currentContext); + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); + fbo_guard.setContext(ctx); bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); - if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(currentContext))) + if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx))) return; size = sz; @@ -417,8 +421,10 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, // texture dimensions QT_RESET_GLERROR(); // reset error state + GLuint fbo = 0; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); + fbo_guard.setId(fbo); glDevice.setFBO(q, attachment); @@ -535,13 +541,14 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, fbo_attachment = QGLFramebufferObject::NoAttachment; } - glBindFramebuffer(GL_FRAMEBUFFER_EXT, currentContext->d_ptr->current_fbo); + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); if (!valid) { if (color_buffer) glDeleteRenderbuffers(1, &color_buffer); else glDeleteTextures(1, &texture); glDeleteFramebuffers(1, &fbo); + fbo_guard.setId(0); } QT_CHECK_GLERROR(); @@ -810,19 +817,15 @@ QGLFramebufferObject::~QGLFramebufferObject() delete d->engine; - if (isValid()) { - const QGLContext *oldContext = QGLContext::currentContext(); - bool switchContext = !oldContext || QGLContextPrivate::contextGroup(oldContext) != ctx; - if (switchContext) - const_cast<QGLContext *>(ctx->context())->makeCurrent(); + if (isValid() && ctx) { + QGLShareContextScope scope(ctx); glDeleteTextures(1, &d->texture); if (d->color_buffer) glDeleteRenderbuffers(1, &d->color_buffer); if (d->depth_stencil_buffer) glDeleteRenderbuffers(1, &d->depth_stencil_buffer); - glDeleteFramebuffers(1, &d->fbo); - if (oldContext && switchContext) - const_cast<QGLContext *>(oldContext)->makeCurrent(); + GLuint fbo = d->fbo(); + glDeleteFramebuffers(1, &fbo); } } @@ -838,11 +841,16 @@ QGLFramebufferObject::~QGLFramebufferObject() The non-power of two limitation does not apply if the OpenGL version is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension is present. + + The framebuffer can also become invalid if the QGLContext that + the framebuffer was created within is destroyed and there are + no other shared contexts that can take over ownership of the + framebuffer. */ bool QGLFramebufferObject::isValid() const { Q_D(const QGLFramebufferObject); - return d->valid; + return d->valid && d->fbo_guard.context(); } /*! @@ -867,15 +875,17 @@ bool QGLFramebufferObject::bind() return false; Q_D(QGLFramebufferObject); QGL_FUNC_CONTEXT; - glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo); + if (!ctx) + return false; // Context no longer exists. + glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo()); d->valid = d->checkFramebufferStatus(); const QGLContext *context = QGLContext::currentContext(); if (d->valid && context) { - Q_ASSERT(QGLContextPrivate::contextGroup(context) == ctx); + Q_ASSERT(QGLContextPrivate::contextGroup(context) == QGLContextPrivate::contextGroup(ctx)); // Save the previous setting to automatically restore in release(). - if (context->d_ptr->current_fbo != d->fbo) { + if (context->d_ptr->current_fbo != d->fbo()) { d->previous_fbo = context->d_ptr->current_fbo; - context->d_ptr->current_fbo = d->fbo; + context->d_ptr->current_fbo = d->fbo(); } } return d->valid; @@ -900,10 +910,12 @@ bool QGLFramebufferObject::release() return false; Q_D(QGLFramebufferObject); QGL_FUNC_CONTEXT; + if (!ctx) + return false; // Context no longer exists. const QGLContext *context = QGLContext::currentContext(); if (context) { - Q_ASSERT(QGLContextPrivate::contextGroup(context) == ctx); + Q_ASSERT(QGLContextPrivate::contextGroup(context) == QGLContextPrivate::contextGroup(ctx)); // Restore the previous setting for stacked framebuffer objects. if (d->previous_fbo != context->d_ptr->current_fbo) { context->d_ptr->current_fbo = d->previous_fbo; @@ -1144,7 +1156,7 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const GLuint QGLFramebufferObject::handle() const { Q_D(const QGLFramebufferObject); - return d->fbo; + return d->fbo(); } /*! \fn int QGLFramebufferObject::devType() const @@ -1175,7 +1187,7 @@ QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const bool QGLFramebufferObject::isBound() const { Q_D(const QGLFramebufferObject); - return QGLContext::currentContext()->d_ptr->current_fbo == d->fbo; + return QGLContext::currentContext()->d_ptr->current_fbo == d->fbo(); } /*! diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h index f80209d..055a752 100644 --- a/src/opengl/qglframebufferobject_p.h +++ b/src/opengl/qglframebufferobject_p.h @@ -127,15 +127,15 @@ private: class QGLFramebufferObjectPrivate { public: - QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), ctx(0), previous_fbo(0), engine(0) {} + QGLFramebufferObjectPrivate() : fbo_guard(0), depth_stencil_buffer(0), valid(false), previous_fbo(0), engine(0) {} ~QGLFramebufferObjectPrivate() {} void init(QGLFramebufferObject *q, const QSize& sz, QGLFramebufferObject::Attachment attachment, GLenum internal_format, GLenum texture_target, GLint samples = 0); bool checkFramebufferStatus() const; + QGLSharedResourceGuard fbo_guard; GLuint texture; - GLuint fbo; GLuint depth_stencil_buffer; GLuint color_buffer; GLenum target; @@ -143,10 +143,11 @@ public: QGLFramebufferObjectFormat format; uint valid : 1; QGLFramebufferObject::Attachment fbo_attachment; - QGLContextGroup *ctx; // for Windows extension ptrs GLuint previous_fbo; mutable QPaintEngine *engine; QGLFBOGLPaintDevice glDevice; + + inline GLuint fbo() const { return fbo_guard.id(); } }; diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp index 793471d..6971133 100644 --- a/src/opengl/qglpixelbuffer_x11.cpp +++ b/src/opengl/qglpixelbuffer_x11.cpp @@ -93,6 +93,8 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0; #define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib #define glXMakeContextCurrent qt_glXMakeContextCurrent +extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp + static bool qt_resolve_pbuffer_extensions() { static int resolved = false; @@ -101,31 +103,12 @@ static bool qt_resolve_pbuffer_extensions() else if (resolved) return false; -#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) - void *handle = dlopen(NULL, RTLD_LAZY); - if (handle) { - qt_glXChooseFBConfig = (_glXChooseFBConfig) dlsym(handle, "glXChooseFBConfig"); - qt_glXCreateNewContext = (_glXCreateNewContext) dlsym(handle, "glXCreateNewContext"); - qt_glXCreatePbuffer = (_glXCreatePbuffer) dlsym(handle, "glXCreatePbuffer"); - qt_glXDestroyPbuffer = (_glXDestroyPbuffer) dlsym(handle, "glXDestroyPbuffer"); - qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) dlsym(handle, "glXGetFBConfigAttrib"); - qt_glXMakeContextCurrent = (_glXMakeContextCurrent) dlsym(handle, "glXMakeContextCurrent"); - dlclose(handle); - } - if (!qt_glXChooseFBConfig) -#endif - { -#if !defined(QT_NO_LIBRARY) - extern const QString qt_gl_library_name(); - QLibrary gl(qt_gl_library_name()); - qt_glXChooseFBConfig = (_glXChooseFBConfig) gl.resolve("glXChooseFBConfig"); - qt_glXCreateNewContext = (_glXCreateNewContext) gl.resolve("glXCreateNewContext"); - qt_glXCreatePbuffer = (_glXCreatePbuffer) gl.resolve("glXCreatePbuffer"); - qt_glXDestroyPbuffer = (_glXDestroyPbuffer) gl.resolve("glXDestroyPbuffer"); - qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) gl.resolve("glXGetFBConfigAttrib"); - qt_glXMakeContextCurrent = (_glXMakeContextCurrent) gl.resolve("glXMakeContextCurrent"); -#endif - } + qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig"); + qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext"); + qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer"); + qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer"); + qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib"); + qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent"); resolved = qt_glXMakeContextCurrent ? true : false; return resolved; diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index bb3cb5d..1ae3866 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -79,34 +79,28 @@ protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &pixmap, const QRectF &srcRect) const; }; -#ifndef QT_OPENGL_ES_2 - -class QGLPixmapConvolutionFilter: public QGLPixmapFilter<QPixmapConvolutionFilter> +class QGLPixmapConvolutionFilter: public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapConvolutionFilter> { public: QGLPixmapConvolutionFilter(); ~QGLPixmapConvolutionFilter(); + void setUniforms(QGLShaderProgram *program); + protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; private: QByteArray generateConvolutionShader() const; - mutable QGLShaderProgram *m_program; - mutable int m_scaleUniform; - mutable int m_matrixUniform; - - mutable int m_kernelWidth; - mutable int m_kernelHeight; + mutable QSize m_srcSize; + mutable int m_prevKernelSize; }; -#endif - class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter> { public: - QGLPixmapBlurFilter(QPixmapBlurFilter::BlurHint hint); + QGLPixmapBlurFilter(Qt::RenderHint hint); void setUniforms(QGLShaderProgram *program); @@ -121,7 +115,7 @@ private: mutable bool m_haveCached; mutable int m_cachedRadius; - mutable QPixmapBlurFilter::BlurHint m_hint; + mutable Qt::RenderHint m_hint; }; extern QGLWidget *qt_gl_share_widget(); @@ -137,67 +131,26 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr case QPixmapFilter::BlurFilter: { const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype); - if (proto->blurHint() == QPixmapBlurFilter::PerformanceHint || proto->radius() <= 5) { + if (proto->blurHint() == Qt::PerformanceHint || proto->radius() <= 5) { if (!d->fastBlurFilter) - d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QPixmapBlurFilter::PerformanceHint)); + d->fastBlurFilter.reset(new QGLPixmapBlurFilter(Qt::PerformanceHint)); return d->fastBlurFilter.data(); } if (!d->blurFilter) - d->blurFilter.reset(new QGLPixmapBlurFilter(QPixmapBlurFilter::QualityHint)); + d->blurFilter.reset(new QGLPixmapBlurFilter(Qt::QualityHint)); return d->blurFilter.data(); } -#ifndef QT_OPENGL_ES_2 case QPixmapFilter::ConvolutionFilter: if (!d->convolutionFilter) d->convolutionFilter.reset(new QGLPixmapConvolutionFilter); return d->convolutionFilter.data(); -#endif default: break; } return QPaintEngineEx::pixmapFilter(type, prototype); } -#ifndef QT_OPENGL_ES_2 // XXX: needs to be ported - -extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array); -extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array); - -static void qgl_drawTexture(const QRectF &rect, int tx_width, int tx_height, const QRectF & src) -{ -#ifndef QT_OPENGL_ES - glPushAttrib(GL_CURRENT_BIT); -#endif - qreal x1, x2, y1, y2; - - x1 = src.x() / tx_width; - x2 = x1 + src.width() / tx_width; - y1 = 1.0 - ((src.y() / tx_height) + (src.height() / tx_height)); - y2 = 1.0 - (src.y() / tx_height); - - q_vertexType vertexArray[4*2]; - q_vertexType texCoordArray[4*2]; - - qt_add_rect_to_array(rect, vertexArray); - qt_add_texcoords_to_array(x1, y2, x2, y1, texCoordArray); - - glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray); - glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - -#ifndef QT_OPENGL_ES - glPopAttrib(); -#endif -} - -#endif // !QT_OPENGL_ES_2 - static const char *qt_gl_colorize_filter = "uniform lowp vec4 colorizeColor;" "uniform lowp float colorizeStrength;" @@ -231,102 +184,88 @@ void QGLPixmapColorizeFilter::setUniforms(QGLShaderProgram *program) program->setUniformValue("colorizeStrength", float(strength())); } -#ifndef QT_OPENGL_ES_2 +void QGLPixmapConvolutionFilter::setUniforms(QGLShaderProgram *program) +{ + const qreal *kernel = convolutionKernel(); + int kernelWidth = columns(); + int kernelHeight = rows(); + int kernelSize = kernelWidth * kernelHeight; + + QVarLengthArray<GLfloat> matrix(kernelSize); + QVarLengthArray<GLfloat> offset(kernelSize * 2); + + for(int i = 0; i < kernelSize; ++i) + matrix[i] = kernel[i]; + + for(int y = 0; y < kernelHeight; ++y) { + for(int x = 0; x < kernelWidth; ++x) { + offset[(y * kernelWidth + x) * 2] = x - (kernelWidth / 2); + offset[(y * kernelWidth + x) * 2 + 1] = (kernelHeight / 2) - y; + } + } + + const qreal iw = 1.0 / m_srcSize.width(); + const qreal ih = 1.0 / m_srcSize.height(); + program->setUniformValue("inv_texture_size", iw, ih); + program->setUniformValueArray("matrix", matrix.constData(), kernelSize, 1); + program->setUniformValueArray("offset", offset.constData(), kernelSize, 2); +} // generates convolution filter code for arbitrary sized kernel QByteArray QGLPixmapConvolutionFilter::generateConvolutionShader() const { QByteArray code; - code.append("uniform sampler2D texture;\n" - "uniform vec2 inv_texture_size;\n" - "uniform float matrix["); - code.append(QByteArray::number(m_kernelWidth * m_kernelHeight)); - code.append("];\n" - "vec2 offset["); - code.append(QByteArray::number(m_kernelWidth*m_kernelHeight)); + int kernelWidth = columns(); + int kernelHeight = rows(); + int kernelSize = kernelWidth * kernelHeight; + code.append("uniform highp vec2 inv_texture_size;\n" + "uniform mediump float matrix["); + code.append(QByteArray::number(kernelSize)); code.append("];\n" - "void main(void) {\n"); - - for(int y = 0; y < m_kernelHeight; y++) { - for(int x = 0; x < m_kernelWidth; x++) { - code.append(" offset["); - code.append(QByteArray::number(y * m_kernelWidth + x)); - code.append("] = vec2(inv_texture_size.x * "); - code.append(QByteArray::number(x-(int)(m_kernelWidth/2))); - code.append(".0, inv_texture_size.y * "); - code.append(QByteArray::number((int)(m_kernelHeight/2)-y)); - code.append(".0);\n"); - } - } + "uniform highp vec2 offset["); + code.append(QByteArray::number(kernelSize)); + code.append("];\n"); + code.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n"); code.append(" int i = 0;\n" - " vec2 coords = gl_TexCoord[0].st;\n" - " vec4 sum = vec4(0.0);\n" + " lowp vec4 sum = vec4(0.0);\n" " for (i = 0; i < "); - code.append(QByteArray::number(m_kernelWidth * m_kernelHeight)); + code.append(QByteArray::number(kernelSize)); code.append("; i++) {\n" - " vec4 tmp = texture2D(texture,coords+offset[i]);\n" - " sum += matrix[i] * tmp;\n" + " sum += matrix[i] * texture2D(src,srcCoords+inv_texture_size*offset[i]);\n" " }\n" - " gl_FragColor = sum;\n" + " return sum;\n" "}"); return code; } QGLPixmapConvolutionFilter::QGLPixmapConvolutionFilter() - : m_program(0) - , m_scaleUniform(0) - , m_matrixUniform(0) - , m_kernelWidth(0) - , m_kernelHeight(0) + : m_prevKernelSize(-1) { } QGLPixmapConvolutionFilter::~QGLPixmapConvolutionFilter() { - delete m_program; } -bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const +bool QGLPixmapConvolutionFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const { - QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos); - - bindTexture(src); -#ifdef GL_CLAMP - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); -#endif - if (!m_program || m_kernelWidth != columns() || m_kernelHeight != rows()) { - delete m_program; - - m_kernelWidth = columns(); - m_kernelHeight = rows(); - - QByteArray code = generateConvolutionShader(); - m_program = new QGLShaderProgram(); - m_program->addShader(QGLShader::FragmentShader, code); - m_program->link(); - m_scaleUniform = m_program->uniformLocation("inv_texture_size"); - m_matrixUniform = m_program->uniformLocation("matrix"); + QGLPixmapConvolutionFilter *filter = const_cast<QGLPixmapConvolutionFilter *>(this); + + m_srcSize = src.size(); + + int kernelSize = rows() * columns(); + if (m_prevKernelSize == -1 || m_prevKernelSize != kernelSize) { + filter->setSource(generateConvolutionShader()); + m_prevKernelSize = kernelSize; } - const qreal *kernel = convolutionKernel(); - GLfloat *conv = new GLfloat[m_kernelWidth * m_kernelHeight]; - for(int i = 0; i < m_kernelWidth * m_kernelHeight; ++i) - conv[i] = kernel[i]; - - const qreal iw = 1.0 / src.width(); - const qreal ih = 1.0 / src.height(); - m_program->enable(); - m_program->setUniformValue(m_scaleUniform, iw, ih); - m_program->setUniformValueArray(m_matrixUniform, conv, m_kernelWidth * m_kernelHeight, 1); - - qgl_drawTexture(target, src.width(), src.height(), boundingRectFor(srcRect)); - m_program->disable(); + filter->setOnPainter(painter); + painter->drawPixmap(pos, src, srcRect); + filter->removeFromPainter(painter); + return true; } -#endif // !QT_OPENGL_ES_2 - static const char *qt_gl_blur_filter_fast = "const int samples = 9;" "uniform mediump vec2 delta;" @@ -340,12 +279,12 @@ static const char *qt_gl_blur_filter_fast = " return color * (1.0 / float(samples));" "}"; -QGLPixmapBlurFilter::QGLPixmapBlurFilter(QPixmapBlurFilter::BlurHint hint) +QGLPixmapBlurFilter::QGLPixmapBlurFilter(Qt::RenderHint hint) : m_haveCached(false) , m_cachedRadius(5) , m_hint(hint) { - if (hint == PerformanceHint) { + if (hint == Qt::PerformanceHint) { QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this); filter->setSource(qt_gl_blur_filter_fast); m_haveCached = true; @@ -357,7 +296,7 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this); int radius = this->radius(); - if (!m_haveCached || (m_hint == QualityHint && radius != m_cachedRadius)) { + if (!m_haveCached || (m_hint == Qt::QualityHint && radius != m_cachedRadius)) { // Only regenerate the shader from source if parameters have changed. m_haveCached = true; m_cachedRadius = radius; @@ -419,7 +358,7 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program) { - if (m_hint == QualityHint) { + if (m_hint == Qt::QualityHint) { if (m_horizontalBlur) program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); else diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index ebcd723..dfa6c40 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -349,7 +349,7 @@ QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObj context = QGLContext::currentContext(); d = new QGLShaderPrivate(context, type); #ifndef QT_NO_DEBUG - if (context && !qgl_share_reg()->checkSharing(context, QGLContext::currentContext())) { + if (context && !QGLContext::areSharing(context, QGLContext::currentContext())) { qWarning("QGLShader::QGLShader: \'context\' must be the currect context or sharing with it."); return; } @@ -374,7 +374,7 @@ QGLShader::QGLShader context = QGLContext::currentContext(); d = new QGLShaderPrivate(context, type); #ifndef QT_NO_DEBUG - if (context && !qgl_share_reg()->checkSharing(context, QGLContext::currentContext())) { + if (context && !QGLContext::areSharing(context, QGLContext::currentContext())) { qWarning("QGLShader::QGLShader: \'context\' must be currect context or sharing with it."); return; } @@ -806,8 +806,8 @@ bool QGLShaderProgram::addShader(QGLShader *shader) if (d->shaders.contains(shader)) return true; // Already added to this shader program. if (d->programGuard.id() && shader) { - if (!qgl_share_reg()->checkSharing(shader->d->shaderGuard.context(), - d->programGuard.context())) { + if (!QGLContext::areSharing(shader->d->shaderGuard.context(), + d->programGuard.context())) { qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context."); return false; } diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index bd3883a..da490c0 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -338,7 +338,7 @@ void QGLOffscreen::initialize() int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(device->size().width(), device->size().height())))); - bool shared_context = qgl_share_reg()->checkSharing(device->context(), ctx); + bool shared_context = QGLContext::areSharing(device->context(), ctx); bool would_fail = last_failed_size.isValid() && (device->size().width() >= last_failed_size.width() || device->size().height() >= last_failed_size.height()); @@ -555,7 +555,7 @@ public: QList<const QGLContext *> contexts = programs.uniqueKeys(); for (int i=0; i<contexts.size(); ++i) { const QGLContext *cx = contexts.at(i); - if (cx != ctx && qgl_share_reg()->checkSharing(cx, ctx)) { + if (cx != ctx && QGLContext::areSharing(cx, ctx)) { QList<GLProgram> progs = programs.values(cx); for (int k=0; k<progs.size(); ++k) { const GLProgram &prg = progs.at(k); @@ -1015,7 +1015,7 @@ public: } inline GLuint getBuffer(const QGradient &gradient, qreal opacity, QGLContext *ctx) { - if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx)) + if (buffer_ctx && !QGLContext::areSharing(buffer_ctx, ctx)) cleanCache(); buffer_ctx = ctx; @@ -1365,7 +1365,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) #ifdef QT_OPENGL_ES d->max_texture_size = ctx->d_func()->maxTextureSize(); #else - bool shared_ctx = qgl_share_reg()->checkSharing(d->device->context(), d->shader_ctx); + bool shared_ctx = QGLContext::areSharing(d->device->context(), d->shader_ctx); if (shared_ctx) { d->max_texture_size = d->shader_ctx->d_func()->maxTextureSize(); @@ -4683,7 +4683,7 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, QList<const QGLContext *> contexts = qt_context_cache.keys(); for (int i=0; i<contexts.size(); ++i) { const QGLContext *ctx = contexts.at(i); - if (ctx != context && qgl_share_reg()->checkSharing(context, ctx)) { + if (ctx != context && QGLContext::areSharing(context, ctx)) { context_key = ctx; dev_it = qt_context_cache.constFind(context_key); break; @@ -4791,22 +4791,6 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti, } QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i])); - - // The QPF implementation of alphaMapForGlyph() uses the color - // RGBA = (value, value, value, 255) instead of the color - // RGBA = (0, 0, 0, value) that the other font engines use. - // We modify the image colors to rectify this situation. - QFontEngine::Type type = ti.fontEngine->type(); - if (type == QFontEngine::QPF1 || type == QFontEngine::QPF2) { - if (glyph_im.format() == QImage::Format_Indexed8) { - for (int i = 0; i < 256; ++i) - glyph_im.setColor(i, qRgba(0, 0, 0, i)); - } else if (glyph_im.format() == QImage::Format_Mono) { - glyph_im.setColor(0, qRgba(0, 0, 0, 0)); - glyph_im.setColor(1, qRgba(0, 0, 0, 255)); - } - } - glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8); glyph_width = glyph_im.width(); Q_ASSERT(glyph_width >= 0); diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index dc7aa81..ae4bed0 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -251,7 +251,7 @@ bool QGLPixmapData::isValidContext(const QGLContext *ctx) const return true; const QGLContext *share_ctx = qt_gl_share_widget()->context(); - return ctx == share_ctx || qgl_share_reg()->checkSharing(ctx, share_ctx); + return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx); } void QGLPixmapData::resize(int width, int height) |