mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Refactored cvf::OpenGLContext and cvf::OpenGLContextGroup, and added first cut impl of cvfqt::GLWidget and cvfqt::OpenGLWidget
This commit is contained in:
parent
4bd1be3763
commit
9b553d6963
@ -65,15 +65,18 @@ OpenGLWidget::OpenGLWidget( cvf::OpenGLContextGroup* contextGroup,
|
||||
cvf::ref<cvf::OpenGLContext> myContext = cvfOpenGLContext();
|
||||
if ( myContext.notNull() )
|
||||
{
|
||||
cvf::OpenGLContextGroup* myOwnerContextGroup = myContext->group();
|
||||
|
||||
if ( shareWidget )
|
||||
{
|
||||
// We need to check if we actually got a context that shares resources with shareWidget.
|
||||
cvf::ref<cvf::OpenGLContext> shareContext = shareWidget->cvfOpenGLContext();
|
||||
CVF_ASSERT(myOwnerContextGroup == shareContext->group());
|
||||
|
||||
if ( isSharing() )
|
||||
{
|
||||
CVF_ASSERT( myContext->group() == shareContext->group() );
|
||||
myContext->initializeContext();
|
||||
makeCurrent();
|
||||
myOwnerContextGroup->initializeContextGroup(myContext.p());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -81,13 +84,14 @@ OpenGLWidget::OpenGLWidget( cvf::OpenGLContextGroup* contextGroup,
|
||||
// since the construction process above has already optimistically added the new context to the
|
||||
// existing group. In this case, the newly context is basically defunct so we just shut it down
|
||||
// (which will also remove it from the group)
|
||||
myContext->shutdownContext();
|
||||
myOwnerContextGroup->contextAboutToBeShutdown(myContext.p());
|
||||
CVF_ASSERT( myContext->group() == nullptr );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myContext->initializeContext();
|
||||
makeCurrent();
|
||||
contextGroup->initializeContextGroup(myContext.p());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,13 +122,16 @@ OpenGLWidget::OpenGLWidget( OpenGLWidget* shareWidget, QWidget* parent, Qt::Wind
|
||||
cvf::ref<cvf::OpenGLContext> myContext = cvfOpenGLContext();
|
||||
if ( myContext.notNull() )
|
||||
{
|
||||
cvf::OpenGLContextGroup* myOwnerContextGroup = myContext->group();
|
||||
|
||||
// We need to check if we actually got a context that shares resources with shareWidget.
|
||||
if ( isSharing() )
|
||||
{
|
||||
if ( isValid() )
|
||||
{
|
||||
CVF_ASSERT( myContext->group() == shareContext->group() );
|
||||
myContext->initializeContext();
|
||||
makeCurrent();
|
||||
myOwnerContextGroup->initializeContextGroup(myContext.p());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -133,7 +140,7 @@ OpenGLWidget::OpenGLWidget( OpenGLWidget* shareWidget, QWidget* parent, Qt::Wind
|
||||
// the construction process above has already optimistically added the new context to the existing group.
|
||||
// In this case, the newly context is basically defunct so we just shut it down (which will also remove it
|
||||
// from the group)
|
||||
myContext->shutdownContext();
|
||||
myOwnerContextGroup->contextAboutToBeShutdown(myContext.p());
|
||||
CVF_ASSERT( myContext->group() == nullptr );
|
||||
}
|
||||
}
|
||||
@ -161,7 +168,14 @@ void OpenGLWidget::cvfShutdownOpenGLContext()
|
||||
cvf::ref<cvf::OpenGLContext> myContext = cvfOpenGLContext();
|
||||
if ( myContext.notNull() )
|
||||
{
|
||||
myContext->shutdownContext();
|
||||
cvf::OpenGLContextGroup* myOwnerContextGroup = myContext->group();
|
||||
|
||||
// If shutdown has already been called, the context is no longer member of any group
|
||||
if (myOwnerContextGroup)
|
||||
{
|
||||
makeCurrent();
|
||||
myOwnerContextGroup->contextAboutToBeShutdown(myContext.p());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,9 @@ set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets Qt5::OpenGL)
|
||||
|
||||
set(CEE_HEADER_FILES
|
||||
cvfqtBasicAboutDialog.h
|
||||
cvfqtGLWidget.h
|
||||
cvfqtMouseState.h
|
||||
cvfqtOpenGLWidget.h
|
||||
cvfqtPerformanceInfoHud.h
|
||||
cvfqtUtils.h
|
||||
cvfqtCvfBoundQGLContext_deprecated.h
|
||||
@ -29,13 +31,16 @@ cvfqtGLWidget_deprecated.h
|
||||
|
||||
set(CEE_SOURCE_FILES
|
||||
cvfqtBasicAboutDialog.cpp
|
||||
cvfqtGLWidget.cpp
|
||||
cvfqtMouseState.cpp
|
||||
cvfqtOpenGLWidget.cpp
|
||||
cvfqtPerformanceInfoHud.cpp
|
||||
cvfqtUtils.cpp
|
||||
cvfqtCvfBoundQGLContext_deprecated.cpp
|
||||
cvfqtGLWidget_deprecated.cpp
|
||||
)
|
||||
|
||||
|
||||
add_library(${PROJECT_NAME} ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
@ -57,5 +62,4 @@ source_group("" FILES ${PROJECT_FILES})
|
||||
# Unity Build
|
||||
if (CMAKE_UNITY_BUILD)
|
||||
set_source_files_properties (cvfqtGLWidget_deprecated.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE)
|
||||
set_source_files_properties (cvfqtOpenGLContext.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION TRUE)
|
||||
endif()
|
||||
|
@ -56,18 +56,9 @@ namespace cvfqt {
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
OpenGLContext_QGLContextAdapter_deprecated::OpenGLContext_QGLContextAdapter_deprecated(cvf::OpenGLContextGroup* contextGroup, QGLContext* backingQGLContext)
|
||||
: cvf::OpenGLContext(contextGroup),
|
||||
m_isCoreOpenGLProfile(false),
|
||||
m_majorVersion(0),
|
||||
m_minorVersion(0)
|
||||
: cvf::OpenGLContext(contextGroup)
|
||||
{
|
||||
m_qtGLContext = backingQGLContext;
|
||||
|
||||
CVF_ASSERT(m_qtGLContext);
|
||||
QGLFormat glFormat = m_qtGLContext->format();
|
||||
m_majorVersion = glFormat.majorVersion();
|
||||
m_minorVersion = glFormat.minorVersion();
|
||||
m_isCoreOpenGLProfile = (glFormat.profile() == QGLFormat::CoreProfile) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
@ -80,26 +71,6 @@ OpenGLContext_QGLContextAdapter_deprecated::~OpenGLContext_QGLContextAdapter_dep
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool OpenGLContext_QGLContextAdapter_deprecated::initializeContext()
|
||||
{
|
||||
if (!cvf::OpenGLContext::initializeContext())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Possibly override setting for fixed function support
|
||||
if (m_isCoreOpenGLProfile)
|
||||
{
|
||||
group()->capabilities()->setSupportsFixedFunction(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -55,16 +55,11 @@ public:
|
||||
OpenGLContext_QGLContextAdapter_deprecated(cvf::OpenGLContextGroup* contextGroup, QGLContext* backingQGLContext);
|
||||
virtual ~OpenGLContext_QGLContextAdapter_deprecated();
|
||||
|
||||
virtual bool initializeContext();
|
||||
|
||||
virtual void makeCurrent();
|
||||
virtual bool isCurrent() const;
|
||||
|
||||
private:
|
||||
QGLContext* m_qtGLContext;
|
||||
bool m_isCoreOpenGLProfile; // This is a Core OpenGL profile. Implies OpenGL version of 3.2 or more
|
||||
int m_majorVersion; // OpenGL version as reported by Qt
|
||||
int m_minorVersion;
|
||||
};
|
||||
|
||||
|
||||
|
519
Fwk/VizFwk/LibGuiQt/cvfqtGLWidget.cpp
Normal file
519
Fwk/VizFwk/LibGuiQt/cvfqtGLWidget.cpp
Normal file
@ -0,0 +1,519 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2011-2013 Ceetron AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
//
|
||||
// GNU General Public License Usage
|
||||
// This library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
// GNU Lesser General Public License Usage
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
|
||||
#include "cvfqtGLWidget.h"
|
||||
|
||||
#include "cvfOpenGLContextGroup.h"
|
||||
#include "cvfOpenGLContext.h"
|
||||
#include "cvfLogManager.h"
|
||||
#include "cvfTrace.h"
|
||||
|
||||
#include <QPointer>
|
||||
#include <QEvent>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QPlatformSurfaceEvent>
|
||||
|
||||
namespace cvfqt {
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class ForwardingOpenGLContext_GLWidget : public cvf::OpenGLContext
|
||||
{
|
||||
public:
|
||||
ForwardingOpenGLContext_GLWidget(cvf::OpenGLContextGroup* contextGroup, QGLWidget* ownerQtGLWidget)
|
||||
: cvf::OpenGLContext(contextGroup),
|
||||
m_ownerQtGLWidget(ownerQtGLWidget)
|
||||
{
|
||||
CVF_ASSERT(contextGroup);
|
||||
|
||||
// In our current usage pattern the owner widget (and its contained Qt OpenGL context) must already be initialized/created
|
||||
CVF_ASSERT(m_ownerQtGLWidget);
|
||||
CVF_ASSERT(m_ownerQtGLWidget->isValid());
|
||||
CVF_ASSERT(m_ownerQtGLWidget->context());
|
||||
CVF_ASSERT(m_ownerQtGLWidget->context()->isValid());
|
||||
}
|
||||
|
||||
virtual void makeCurrent()
|
||||
{
|
||||
if (m_ownerQtGLWidget)
|
||||
{
|
||||
m_ownerQtGLWidget->makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool isCurrent() const
|
||||
{
|
||||
const QGLContext* ownersQGLContext = m_ownerQtGLWidget ? m_ownerQtGLWidget->context() : NULL;
|
||||
if (ownersQGLContext && QGLContext::currentContext() == ownersQGLContext)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual cvf::OglId defaultFramebufferObject() const
|
||||
{
|
||||
if (m_ownerQtGLWidget)
|
||||
{
|
||||
const QGLContext* ownersQGLContext = m_ownerQtGLWidget->context();
|
||||
const QOpenGLContext* ownersQOpenGLContext = ownersQGLContext ? ownersQGLContext->contextHandle() : NULL;
|
||||
return ownersQOpenGLContext ? ownersQOpenGLContext->defaultFramebufferObject() : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
QPointer<QGLWidget> m_ownerQtGLWidget;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
/// \class cvfqt::GLWidget
|
||||
/// \ingroup GuiQt
|
||||
///
|
||||
///
|
||||
///
|
||||
//==================================================================================================
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Constructor, use this for the first or only widget in your application.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
GLWidget::GLWidget(cvf::OpenGLContextGroup* contextGroup, const QGLFormat& format, QWidget* parent, Qt::WindowFlags f)
|
||||
: QGLWidget(format, parent, NULL, f),
|
||||
m_cvfOpenGLContextGroup(contextGroup),
|
||||
m_logger(CVF_GET_LOGGER("cee.cvf.qt"))
|
||||
{
|
||||
// Must pass a context group
|
||||
CVF_ASSERT(m_cvfOpenGLContextGroup.notNull());
|
||||
|
||||
// Only the first widget in a context group can be created using this constructor
|
||||
// All following widgets must be created using the constructor overload that takes a shareWidget
|
||||
CVF_ASSERT(m_cvfOpenGLContextGroup->contextCount() == 0);
|
||||
|
||||
// The isValid() call will return true if the widget has a valid GL rendering context; otherwise returns false.
|
||||
// The widget will be invalid if the system has no OpenGL support.
|
||||
if (!isValid())
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Widget creation failed, the system has no OpenGL support");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// The Qt docs for QGLWidget and all previous experience indicates that it is OK to do OpenGL related
|
||||
// initialization in QGLWidget's constructor (contrary to QOpenGLWidget).
|
||||
// Note that the Qt docs still hint that initialization should be deferred to initializeGL(). If we ever
|
||||
// experience problems related to doing initialization here, we should probably move the initialization.
|
||||
|
||||
// Since we're in the constructor we must ensure this widget's context is current before initialization
|
||||
makeCurrent();
|
||||
|
||||
const QGLContext* myQtGLContext = context();
|
||||
CVF_ASSERT(myQtGLContext);
|
||||
CVF_ASSERT(myQtGLContext->isValid());
|
||||
CVF_ASSERT(QGLContext::currentContext() == myQtGLContext);
|
||||
|
||||
m_cvfForwardingOpenGLContext = new ForwardingOpenGLContext_GLWidget(m_cvfOpenGLContextGroup.p(), this);
|
||||
|
||||
if (!m_cvfOpenGLContextGroup->initializeContextGroup(m_cvfForwardingOpenGLContext.p()))
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Error initializing context group");
|
||||
}
|
||||
|
||||
|
||||
// Install our event filter
|
||||
installEventFilter(this);
|
||||
|
||||
// If we're using Qt5 or above, we can get hold of a QOpenGLContext from our QGLContext
|
||||
// Connect to QOpenGLContext's aboutToBeDestroyed signal so we get notified when Qt's OpenGL context is about to be destroyed
|
||||
connect(myQtGLContext->contextHandle(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::qtOpenGLContextAboutToBeDestroyed);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Constructor, creates a widget sharing the OpenGL resources with the specified widget.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
GLWidget::GLWidget(GLWidget* shareWidget, QWidget* parent , Qt::WindowFlags f)
|
||||
: QGLWidget(shareWidget->context()->requestedFormat(), parent, shareWidget, f),
|
||||
m_logger(CVF_GET_LOGGER("cee.cvf.qt"))
|
||||
{
|
||||
// Note that when calling QGLWidget's constructor in the initializer list above, we *must* use the
|
||||
// constructor overload that takes a format as its first parameter. If we do not do this, the default QGLFormat
|
||||
// will be used, and it may not be compatible with the format of the shareWidget.
|
||||
// We grab hold of the format from the shareWidget, but note that we do that by calling requestedFormat()
|
||||
// instead of just format() to ensure that the format being requested here is the same as the one that was actually used
|
||||
// in the "first widget constructor" and not whatever format the first widget ended up with after construction.
|
||||
|
||||
// Requires that a share widget is passed in as parameter
|
||||
CVF_ASSERT(shareWidget);
|
||||
|
||||
// If the share widget doesn't have a CVF OpenGL context something went wrong when it was created and we cannot continue
|
||||
cvf::ref<cvf::OpenGLContext> shareContext = shareWidget->cvfOpenGLContext();
|
||||
CVF_ASSERT(shareContext.notNull());
|
||||
|
||||
if (!isValid())
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Widget creation failed, the system has no OpenGL support");
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to check if we actually got a context that shares resources with the passed shareWidget.
|
||||
if (!isSharing())
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Widget creation failed, unable to create a shared OpenGL context");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Since we're in the constructor we must ensure this widget's context is current before initialization
|
||||
makeCurrent();
|
||||
|
||||
const QGLContext* myQtGLContext = context();
|
||||
CVF_ASSERT(myQtGLContext);
|
||||
CVF_ASSERT(myQtGLContext->isValid());
|
||||
CVF_ASSERT(QGLContext::currentContext() == myQtGLContext);
|
||||
|
||||
m_cvfOpenGLContextGroup = shareContext->group();
|
||||
CVF_ASSERT(m_cvfOpenGLContextGroup.notNull());
|
||||
|
||||
m_cvfForwardingOpenGLContext = new ForwardingOpenGLContext_GLWidget(m_cvfOpenGLContextGroup.p(), this);
|
||||
|
||||
// Normally, the context group should already be initialized when the first widget in the group was created.
|
||||
// Still, for good measure do an initialization here. It will amount to a no-op if context group is already initialized
|
||||
if (!m_cvfOpenGLContextGroup->initializeContextGroup(m_cvfForwardingOpenGLContext.p()))
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Error initializing context group using sharing widget");
|
||||
}
|
||||
|
||||
|
||||
// Install our event filter
|
||||
installEventFilter(this);
|
||||
|
||||
// If we're using Qt5 or above, we can get hold of a QOpenGLContext from our QGLContext
|
||||
// Connect to QOpenGLContext's aboutToBeDestroyed signal so we get notified when Qt's OpenGL context is about to be destroyed
|
||||
connect(myQtGLContext->contextHandle(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::qtOpenGLContextAboutToBeDestroyed);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
GLWidget::~GLWidget()
|
||||
{
|
||||
cvf::Trace::show("GLWidget::~GLWidget()");
|
||||
|
||||
// Make sure we disconnect from the aboutToBeDestroyed signal since after this destructor has been
|
||||
// called, out object is dangling and the call to the slot will cause a crash
|
||||
const QGLContext* myQtGLContext = context();
|
||||
const QOpenGLContext* myQtOpenGLContext = myQtGLContext ? myQtGLContext->contextHandle() : NULL;
|
||||
if (myQtOpenGLContext)
|
||||
{
|
||||
disconnect(myQtOpenGLContext, &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::qtOpenGLContextAboutToBeDestroyed);
|
||||
}
|
||||
|
||||
// For Qt5, our testing indicates that once we hit the widget's destructor it may be too late
|
||||
// to try and do any cleanup of OpenGL resources. Most of the time it works, but typically it will fail when
|
||||
// we're shutting down the application by closing the main window. In such cases it seems that the OpenGL
|
||||
// context cannot be made current anymore.
|
||||
//
|
||||
// One solution to this is to do an explicit shutdown of the context while before the system
|
||||
// start shutting down. One traditional way of doing this is to iterate over all GLWidgets and call
|
||||
// the cvfShutdownOpenGLContext() explicitly, eg from QMainWindow::closeEvent()
|
||||
//
|
||||
// In our quest to get a notification just before the QGLContext dies we have also tried to go via
|
||||
// QGLContext's QOpenGLContext and connect to the aboutToBeDestroyed signal. This signal does indeed trigger
|
||||
// before the QGLContext dies, but it seems that at this point we are no longer able to make the context
|
||||
// current which is a requirement before we can do our OpenGL related cleanup.
|
||||
//
|
||||
// Another promising solution that seems to work reliably is to install an event filter and respond to
|
||||
// the QEvent::PlatformSurface event. See our eventFilter() override
|
||||
|
||||
// For Qt4 it seems that doing OpenGL related cleanup in the destructor is OK
|
||||
// We're able to make the context current and delete any OpenGL resources necessary through the cvfShutdownOpenGLContext();
|
||||
|
||||
|
||||
// Note that calling this function is safe even if the context has already been shut down.
|
||||
// It may however fail/assert if the context hasn't already been shut down and if we're unable to make the OpenGL context current
|
||||
cvfShutdownOpenGLContext();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::OpenGLContext* GLWidget::cvfOpenGLContext()
|
||||
{
|
||||
return m_cvfForwardingOpenGLContext.p();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void GLWidget::cvfShutdownOpenGLContext()
|
||||
{
|
||||
if (m_cvfForwardingOpenGLContext.notNull())
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
// If we're not able to make the context current, the eventual un-initialize that will happen
|
||||
// in the context group when we remove the last context will fail.
|
||||
const QGLContext* myContext = context();
|
||||
const QGLContext* currContext = QGLContext::currentContext();
|
||||
if (myContext != currContext)
|
||||
{
|
||||
CVF_LOG_WARNING(m_logger, "Could not make the widget's OpenGL context current for context shutdown");
|
||||
}
|
||||
|
||||
m_cvfOpenGLContextGroup->contextAboutToBeShutdown(m_cvfForwardingOpenGLContext.p());
|
||||
m_cvfForwardingOpenGLContext = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void GLWidget::initializeGL()
|
||||
{
|
||||
//cvf::Trace::show("GLWidget::initializeGL()");
|
||||
|
||||
// According to Qt doc this function is called once before the first call to paintGL() or resizeGL(),
|
||||
// and then once whenever the widget has been assigned a new QGLContext. There is no need to call makeCurrent() because
|
||||
// this has already been done when this function is called.
|
||||
|
||||
if (m_cvfForwardingOpenGLContext.isNull())
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Unexpected error in GLWidget::initializeGL(), no forwarding OpenGL context present");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialization of context group should already be done, but for good measure
|
||||
CVF_ASSERT(m_cvfOpenGLContextGroup.notNull());
|
||||
if (!m_cvfOpenGLContextGroup->isContextGroupInitialized())
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, "Doing late initialization of context group in GLWidget::initializeGL()");
|
||||
if (!m_cvfOpenGLContextGroup->initializeContextGroup(m_cvfForwardingOpenGLContext.p()))
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Initialization of context group in GLWidget::initializeGL() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void GLWidget::resizeGL(int /*width*/, int /*height*/)
|
||||
{
|
||||
// Intentionally empty, and no implementation in QGLWidget::resizeGL() either.
|
||||
// Should normally be implemented in derived class
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void GLWidget::paintGL()
|
||||
{
|
||||
// No implementation here and no significant implementation in QGLWidget either.
|
||||
// In Qt4 QGLWidget::paintGL() does nothing. In Qt5 QGLWidget::paintGL() merely clears the depth and color buffer.
|
||||
// Derived classes must reimplement this function in order to do painting.
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void GLWidget::qtOpenGLContextAboutToBeDestroyed()
|
||||
{
|
||||
//cvf::Trace::show("GLWidget::qtOpenGLContextAboutToBeDestroyed()");
|
||||
|
||||
cvfShutdownOpenGLContext();
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool GLWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
// The most reliable way we have found of detecting when an OpenGL context is about to be destroyed is
|
||||
// hooking into the QEvent::PlatformSurface event and checking for the SurfaceAboutToBeDestroyed event type.
|
||||
// From the Qt doc:
|
||||
// The underlying native surface will be destroyed immediately after this event.
|
||||
// The SurfaceAboutToBeDestroyed event type is useful as a means of stopping rendering to a platform window before it is destroyed.
|
||||
if (event->type() == QEvent::PlatformSurface)
|
||||
{
|
||||
QPlatformSurfaceEvent* platformSurfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
|
||||
if (platformSurfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, "Shutting down OpenGL context in response to platform surface about to be destroyed");
|
||||
cvfShutdownOpenGLContext();
|
||||
}
|
||||
}
|
||||
|
||||
// Reading the Qt docs it can seem like reparenting of the QGLWidget might pose a problem for us.
|
||||
// According to the doc, a change of parent will cause the widget's QGLContext to be deleted and a new one
|
||||
// to be created. In Qt4, this does indeed seem to happen, whereas for Qt5 it does not. Still, it appears that Qt4 makes
|
||||
// an effort to make the new QGLContext compatible with the old one, and does some tricks to set up temporary OpenGL
|
||||
// resource sharing so that we may not actually be affected by this since we're actually not storing any references to
|
||||
// the QGLContext, but accessing it indirectly through the widget in our ForwardingOpenGLContext.
|
||||
// May also want to look out for
|
||||
if (event->type() == QEvent::ParentChange)
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, "cvfqt::GLWidget has been reparented. This may cause OpenGL issues");
|
||||
}
|
||||
else if (event->type() == QEvent::ParentAboutToChange)
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, "cvfqt::GLWidget is about to change parent. This may cause OpenGL issues");
|
||||
}
|
||||
|
||||
return QGLWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void GLWidget::logOpenGLInfo()
|
||||
{
|
||||
CVF_LOG_INFO(m_logger, "Starting logging of OpenGL info (cvfqt::GLWidget)...");
|
||||
|
||||
cvf::String sQtVerInfo = cvf::String("Qt version: %1 (run-time=%2)").arg(QT_VERSION_STR).arg(qVersion());
|
||||
CVF_LOG_INFO(m_logger, sQtVerInfo);
|
||||
|
||||
if (!context() || !isValid())
|
||||
{
|
||||
CVF_LOG_WARNING(m_logger, "QGLWidget does not have a valid GL rendering context, reported info will not be correct!");
|
||||
}
|
||||
|
||||
// Log output from querying Qt
|
||||
CVF_LOG_INFO(m_logger, "Qt OpenGL format info:");
|
||||
|
||||
const QGLFormat qglFormat = format();
|
||||
const QGLFormat::OpenGLContextProfile profile = qglFormat.profile();
|
||||
const QGLFormat::OpenGLVersionFlags qglVersionFlags = QGLFormat::openGLVersionFlags();
|
||||
|
||||
cvf::String sInfo = cvf::String(" info: version %1.%2, depthSize: %3, software: %4, doubleBuffer: %5, sampleBuffers: %6 (size: %7)")
|
||||
.arg(qglFormat.majorVersion()).arg(qglFormat.minorVersion())
|
||||
.arg(qglFormat.depthBufferSize())
|
||||
.arg(qglFormat.directRendering() ? "no" : "yes")
|
||||
.arg(qglFormat.doubleBuffer() ? "yes" : "no")
|
||||
.arg(qglFormat.sampleBuffers() ? "yes" : "no")
|
||||
.arg(qglFormat.samples());
|
||||
CVF_LOG_INFO(m_logger, sInfo);
|
||||
|
||||
cvf::String sProfile = "UNKNOWN";
|
||||
if (profile == QGLFormat::NoProfile) sProfile = "NoProfile";
|
||||
else if (profile == QGLFormat::CoreProfile) sProfile = "CoreProfile";
|
||||
else if (profile == QGLFormat::CompatibilityProfile) sProfile = "CompatibilityProfile";
|
||||
CVF_LOG_INFO(m_logger, " context profile: " + sProfile);
|
||||
|
||||
cvf::String sVersionsPresent = cvf::String(" versions present: 1.1: %1, 2.0: %2, 2.1: %3, 3.0: %4, 3.3: %5, 4.0: %6, ES2: %7")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_Version_1_1 ? "yes" : "no")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_Version_2_0 ? "yes" : "no")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_Version_2_1 ? "yes" : "no")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_Version_3_0 ? "yes" : "no")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_Version_3_3 ? "yes" : "no")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_Version_4_0 ? "yes" : "no")
|
||||
.arg(qglVersionFlags & QGLFormat::OpenGL_ES_Version_2_0 ? "yes" : "no");
|
||||
CVF_LOG_INFO(m_logger, sVersionsPresent);
|
||||
|
||||
CVF_LOG_INFO(m_logger, " is sharing: " + cvf::String(isSharing() ? "yes" : "no"));
|
||||
|
||||
|
||||
// Log the information we have gathered when initializing the context group
|
||||
const cvf::OpenGLInfo oglInfo = m_cvfOpenGLContextGroup->info();
|
||||
CVF_LOG_INFO(m_logger, "OpenGL info:");
|
||||
CVF_LOG_INFO(m_logger, " version: " + oglInfo.version());
|
||||
CVF_LOG_INFO(m_logger, " vendor: " + oglInfo.vendor());
|
||||
CVF_LOG_INFO(m_logger, " renderer: " + oglInfo.renderer());
|
||||
|
||||
|
||||
// Lastly, query OpenGL implementation directly if this context is current
|
||||
GLint smoothLineWidthRange[2] = { -1, -1 };
|
||||
GLint smoothPointSizeRange[2] = { -1, -1 };
|
||||
GLint aliasedLineWidthRange[2] = { -1, -1 };
|
||||
GLint aliasedPointSizeRange[2] = { -1, -1 };
|
||||
|
||||
// Note that GL_LINE_WIDTH_RANGE and GL_SMOOTH_LINE_WIDTH_RANGE are synonyms (0x0B22)
|
||||
// Likewise for GL_POINT_SIZE_RANGE and GL_SMOOTH_POINT_SIZE_RANGE are synonyms (0x0B12)
|
||||
#ifndef GL_ALIASED_LINE_WIDTH_RANGE
|
||||
#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
|
||||
#endif
|
||||
#ifndef GL_ALIASED_POINT_SIZE_RANGE
|
||||
#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
|
||||
#endif
|
||||
|
||||
const bool thisContextIsCurrent = context() == QGLContext::currentContext();
|
||||
if (thisContextIsCurrent)
|
||||
{
|
||||
glGetIntegerv(GL_LINE_WIDTH_RANGE, smoothLineWidthRange);
|
||||
glGetIntegerv(GL_POINT_SIZE_RANGE, smoothPointSizeRange);
|
||||
if (qglVersionFlags & QGLFormat::OpenGL_Version_1_2)
|
||||
{
|
||||
glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, aliasedLineWidthRange);
|
||||
glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, aliasedPointSizeRange);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CVF_LOG_WARNING(m_logger, "Cannot query OpenGL directly, QGLWidget's context is not current");
|
||||
}
|
||||
|
||||
cvf::String sLineInfo = cvf::String("OpenGL line width range: aliased lines: %1 to %2, smooth lines: %3 to %4").arg(aliasedLineWidthRange[0]).arg(aliasedLineWidthRange[1]).arg(smoothLineWidthRange[0]).arg(smoothLineWidthRange[1]);
|
||||
cvf::String sPointInfo = cvf::String("OpenGL point size range: aliased points: %1 to %2, smooth points: %3 to %4").arg(aliasedPointSizeRange[0]).arg(aliasedPointSizeRange[1]).arg(smoothPointSizeRange[0]).arg(smoothPointSizeRange[1]);
|
||||
CVF_LOG_INFO(m_logger, sLineInfo);
|
||||
CVF_LOG_INFO(m_logger, sPointInfo);
|
||||
|
||||
CVF_LOG_INFO(m_logger, "Finished logging of OpenGL info");
|
||||
}
|
||||
|
||||
|
||||
} // namespace cvfqt
|
||||
|
||||
|
86
Fwk/VizFwk/LibGuiQt/cvfqtGLWidget.h
Normal file
86
Fwk/VizFwk/LibGuiQt/cvfqtGLWidget.h
Normal file
@ -0,0 +1,86 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2011-2013 Ceetron AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
//
|
||||
// GNU General Public License Usage
|
||||
// This library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
// GNU Lesser General Public License Usage
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cvfBase.h"
|
||||
#include "cvfObject.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
|
||||
namespace cvf {
|
||||
class OpenGLContext;
|
||||
class OpenGLContextGroup;
|
||||
class Logger;
|
||||
}
|
||||
|
||||
namespace cvfqt {
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class GLWidget : public QGLWidget
|
||||
{
|
||||
public:
|
||||
GLWidget(cvf::OpenGLContextGroup* contextGroup, const QGLFormat& format, QWidget* parent, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
GLWidget(GLWidget* shareWidget, QWidget* parent , Qt::WindowFlags f = Qt::WindowFlags());
|
||||
~GLWidget();
|
||||
|
||||
cvf::OpenGLContext* cvfOpenGLContext();
|
||||
void cvfShutdownOpenGLContext();
|
||||
|
||||
void logOpenGLInfo();
|
||||
|
||||
protected:
|
||||
virtual void initializeGL();
|
||||
virtual void resizeGL(int width, int height);
|
||||
virtual void paintGL();
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
private:
|
||||
void qtOpenGLContextAboutToBeDestroyed();
|
||||
|
||||
private:
|
||||
cvf::ref<cvf::OpenGLContextGroup> m_cvfOpenGLContextGroup;
|
||||
cvf::ref<cvf::OpenGLContext> m_cvfForwardingOpenGLContext;
|
||||
cvf::ref<cvf::Logger> m_logger;
|
||||
};
|
||||
|
||||
}
|
@ -68,7 +68,9 @@ GLWidget_deprecated::GLWidget_deprecated(cvf::OpenGLContextGroup* contextGroup,
|
||||
cvf::ref<cvf::OpenGLContext> myContext = cvfOpenGLContext();
|
||||
if (myContext.notNull())
|
||||
{
|
||||
myContext->initializeContext();
|
||||
// We must ensure the context is current before initialization
|
||||
makeCurrent();
|
||||
contextGroup->initializeContextGroup(myContext.p());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,13 +98,16 @@ GLWidget_deprecated::GLWidget_deprecated(GLWidget_deprecated* shareWidget, QWidg
|
||||
cvf::ref<cvf::OpenGLContext> myContext = cvfOpenGLContext();
|
||||
if (myContext.notNull())
|
||||
{
|
||||
cvf::OpenGLContextGroup* myOwnerContextGroup = myContext->group();
|
||||
CVF_ASSERT(myOwnerContextGroup == shareContext->group());
|
||||
|
||||
// We need to check if we actually got a context that shares resources with shareWidget.
|
||||
if (isSharing())
|
||||
{
|
||||
if (isValid())
|
||||
{
|
||||
CVF_ASSERT(myContext->group() == shareContext->group());
|
||||
myContext->initializeContext();
|
||||
makeCurrent();
|
||||
myOwnerContextGroup->initializeContextGroup(myContext.p());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -110,7 +115,9 @@ GLWidget_deprecated::GLWidget_deprecated(GLWidget_deprecated* shareWidget, QWidg
|
||||
// If we didn't, we need to remove the newly created context from the group it has been added to since
|
||||
// the construction process above has already optimistically added the new context to the existing group.
|
||||
// In this case, the newly context is basically defunct so we just shut it down (which will also remove it from the group)
|
||||
myContext->shutdownContext();
|
||||
// Normally, we would need to ensure the context is current before calling shutdown, but in this case we are not the last
|
||||
// context in the group so there should be no need for cleaning up resources.
|
||||
myOwnerContextGroup->contextAboutToBeShutdown(myContext.p());
|
||||
CVF_ASSERT(myContext->group() == NULL);
|
||||
}
|
||||
}
|
||||
@ -140,7 +147,14 @@ void GLWidget_deprecated::cvfShutdownOpenGLContext()
|
||||
cvf::ref<cvf::OpenGLContext> myContext = cvfOpenGLContext();
|
||||
if (myContext.notNull())
|
||||
{
|
||||
myContext->shutdownContext();
|
||||
cvf::OpenGLContextGroup* myOwnerContextGroup = myContext->group();
|
||||
|
||||
// If shutdown has already been called, the context is no longer member of any group
|
||||
if (myOwnerContextGroup)
|
||||
{
|
||||
makeCurrent();
|
||||
myOwnerContextGroup->contextAboutToBeShutdown(myContext.p());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
334
Fwk/VizFwk/LibGuiQt/cvfqtOpenGLWidget.cpp
Normal file
334
Fwk/VizFwk/LibGuiQt/cvfqtOpenGLWidget.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2011-2013 Ceetron AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
//
|
||||
// GNU General Public License Usage
|
||||
// This library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
// GNU Lesser General Public License Usage
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
|
||||
#include "cvfqtOpenGLWidget.h"
|
||||
|
||||
#include "cvfTrace.h"
|
||||
#include "cvfString.h"
|
||||
#include "cvfOpenGLContext.h"
|
||||
#include "cvfLogManager.h"
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QPointer>
|
||||
#include <QEvent>
|
||||
#include <QPlatformSurfaceEvent>
|
||||
|
||||
namespace cvfqt {
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class ForwardingOpenGLContext_OpenGLWidget : public cvf::OpenGLContext
|
||||
{
|
||||
public:
|
||||
ForwardingOpenGLContext_OpenGLWidget(cvf::OpenGLContextGroup* contextGroup, QOpenGLWidget* ownerQtOpenGLWidget)
|
||||
: cvf::OpenGLContext(contextGroup),
|
||||
m_ownerQtOpenGLWidget(ownerQtOpenGLWidget)
|
||||
{
|
||||
CVF_ASSERT(contextGroup);
|
||||
|
||||
// In our current usage pattern the owner widget (and its contained Qt OpenGL context)
|
||||
// must already be initialized/created
|
||||
CVF_ASSERT(m_ownerQtOpenGLWidget);
|
||||
CVF_ASSERT(m_ownerQtOpenGLWidget->isValid());
|
||||
CVF_ASSERT(m_ownerQtOpenGLWidget->context());
|
||||
CVF_ASSERT(m_ownerQtOpenGLWidget->context()->isValid());
|
||||
}
|
||||
|
||||
virtual void makeCurrent()
|
||||
{
|
||||
if (m_ownerQtOpenGLWidget)
|
||||
{
|
||||
m_ownerQtOpenGLWidget->makeCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool isCurrent() const
|
||||
{
|
||||
QOpenGLContext* ownersContext = m_ownerQtOpenGLWidget ? m_ownerQtOpenGLWidget->context() : NULL;
|
||||
if (ownersContext && QOpenGLContext::currentContext() == ownersContext)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual cvf::OglId defaultFramebufferObject() const
|
||||
{
|
||||
if (m_ownerQtOpenGLWidget)
|
||||
{
|
||||
return m_ownerQtOpenGLWidget->defaultFramebufferObject();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QOpenGLWidget* ownerQtOpenGLWidget()
|
||||
{
|
||||
return m_ownerQtOpenGLWidget;
|
||||
}
|
||||
|
||||
private:
|
||||
QPointer<QOpenGLWidget> m_ownerQtOpenGLWidget;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
OpenGLWidget::OpenGLWidget(cvf::OpenGLContextGroup* contextGroup, QWidget* parent, Qt::WindowFlags f)
|
||||
: QOpenGLWidget(parent, f),
|
||||
m_instanceNumber(-1),
|
||||
m_initializationState(UNINITIALIZED),
|
||||
m_cvfOpenGlContextGroup(contextGroup),
|
||||
m_logger(CVF_GET_LOGGER("cee.cvf.qt"))
|
||||
{
|
||||
static int sl_nextInstanceNumber = 0;
|
||||
m_instanceNumber = sl_nextInstanceNumber++;
|
||||
|
||||
CVF_LOG_DEBUG(m_logger, cvf::String("OpenGLWidget[%1]::OpenGLWidget()").arg(m_instanceNumber));
|
||||
|
||||
CVF_ASSERT(m_cvfOpenGlContextGroup.notNull());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
OpenGLWidget::~OpenGLWidget()
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, cvf::String("OpenGLWidget[%1]::~OpenGLWidget()").arg(m_instanceNumber));
|
||||
|
||||
if (m_initializationState == IS_INITIALIZED)
|
||||
{
|
||||
// Make sure we disconnect from the aboutToBeDestroyed signal since after this destructor has been
|
||||
// called, our object is dangling and the call to the slot will cause a crash
|
||||
QOpenGLContext* myQtOpenGLContext = context();
|
||||
if (myQtOpenGLContext)
|
||||
{
|
||||
disconnect(myQtOpenGLContext, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLWidget::qtOpenGLContextAboutToBeDestroyed);
|
||||
}
|
||||
}
|
||||
|
||||
shutdownCvfOpenGLContext();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// This is where we do the custom initialization needed for the Qt binding to work
|
||||
///
|
||||
/// Note that if you re-implement this function in your subclass, you must make
|
||||
/// sure to call the base class.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLWidget::initializeGL()
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, cvf::String("OpenGLWidget[%1]::initializeGL()").arg(m_instanceNumber));
|
||||
|
||||
if (!isValid())
|
||||
{
|
||||
CVF_LOG_WARNING(m_logger, cvf::String("OpenGLWidget[%1]: Widget is not valid for initialization").arg(m_instanceNumber));
|
||||
}
|
||||
|
||||
// According to Qt doc this function is called once before the first call to paintGL() or resizeGL().
|
||||
// Further it is stated that this widget's QOpenGLContext is already current.
|
||||
// We should be able to assume that we will only be called with a create, valid and current QOpenGLContext
|
||||
//
|
||||
// Note that in some scenarios, such as when a widget get reparented, initializeGL() ends up being called
|
||||
// multiple times in the lifetime of the widget. In those cases, the widget's associated context is first destroyed
|
||||
// and then a new one is created. This is then followed by a new call to initializeGL() where all OpenGL resources must get reinitialized.
|
||||
|
||||
QOpenGLContext* myQtOpenGLContext = context();
|
||||
CVF_ASSERT(myQtOpenGLContext);
|
||||
CVF_ASSERT(myQtOpenGLContext->isValid());
|
||||
CVF_ASSERT(QOpenGLContext::currentContext() == myQtOpenGLContext);
|
||||
|
||||
if (m_initializationState != IS_INITIALIZED)
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, cvf::String("OpenGLWidget[%1]: Starting internal initialization").arg(m_instanceNumber));
|
||||
|
||||
// This should either be the first call or the result of a destroy/recreate cycle
|
||||
CVF_ASSERT(m_cvfForwardingOpenGlContext.isNull());
|
||||
|
||||
// Try and detect the situation where the user is trying to associate incompatible widgets/contexts in the same cvf OpenGLContextGroup
|
||||
// The assert below will fail if two incompatible OpenGL contexts end up in the same context group
|
||||
if (m_cvfOpenGlContextGroup->contextCount() > 0)
|
||||
{
|
||||
for (size_t i = 0; i < m_cvfOpenGlContextGroup->contextCount(); i++)
|
||||
{
|
||||
ForwardingOpenGLContext_OpenGLWidget* existingFwdContext = dynamic_cast<ForwardingOpenGLContext_OpenGLWidget*>(m_cvfOpenGlContextGroup->context(i));
|
||||
QOpenGLWidget* existingWidget = existingFwdContext ? existingFwdContext->ownerQtOpenGLWidget() : NULL;
|
||||
QOpenGLContext* existingQtContext = existingWidget ? existingWidget->context() : NULL;
|
||||
if (existingQtContext)
|
||||
{
|
||||
// Assert that these two contexts are actually sharing OpenGL resources
|
||||
CVF_ASSERT(QOpenGLContext::areSharing(existingQtContext, myQtOpenGLContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the actual wrapper/forwarding OpenGL context that implements the cvf::OpenGLContext that we need
|
||||
cvf::ref<ForwardingOpenGLContext_OpenGLWidget> myCvfContext = new ForwardingOpenGLContext_OpenGLWidget(m_cvfOpenGlContextGroup.p(), this);
|
||||
|
||||
// Possibly initialize the context group
|
||||
if (!m_cvfOpenGlContextGroup->isContextGroupInitialized())
|
||||
{
|
||||
if (!m_cvfOpenGlContextGroup->initializeContextGroup(myCvfContext.p()))
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, cvf::String("OpenGLWidget[%1]: OpenGL context creation failed, could not initialize context group").arg(m_instanceNumber));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// All is well, so store pointer to the cvf OpenGL context
|
||||
m_cvfForwardingOpenGlContext = myCvfContext;
|
||||
|
||||
const InitializationState prevInitState = m_initializationState;
|
||||
m_initializationState = IS_INITIALIZED;
|
||||
|
||||
// Connect to signal so we get notified when Qt's OpenGL context is about to be destroyed
|
||||
connect(myQtOpenGLContext, &QOpenGLContext::aboutToBeDestroyed, this, &OpenGLWidget::qtOpenGLContextAboutToBeDestroyed);
|
||||
|
||||
if (prevInitState == UNINITIALIZED)
|
||||
{
|
||||
// Call overridable notification function to indicate that OpenGL has been initialized
|
||||
// Don't do this if we're being re-initialized
|
||||
onWidgetOpenGLReady();
|
||||
}
|
||||
|
||||
// Trigger a repaint if we're being re-initialized
|
||||
if (prevInitState == PENDING_REINITIALIZATION)
|
||||
{
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLWidget::resizeGL(int /*w*/, int /*h*/)
|
||||
{
|
||||
// Empty, should normally be implemented in derived class
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLWidget::paintGL()
|
||||
{
|
||||
// No implementation here (nor in QOpenGLWidget::paintGL())
|
||||
// Derived classes must re-implement this function in order to do painting.
|
||||
//
|
||||
// Typical code would go something like this:
|
||||
// cvf::OpenGLContext* currentOglContext = cvfOpenGLContext();
|
||||
// myRenderSequence->render(currentOglContext);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::OpenGLContext* OpenGLWidget::cvfOpenGLContext()
|
||||
{
|
||||
return m_cvfForwardingOpenGlContext.p();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
int OpenGLWidget::instanceNumber() const
|
||||
{
|
||||
return m_instanceNumber;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Notification function that will be called after internal CVF OpenGL initialization has
|
||||
/// successfully completed. This includes both the creation of the CVF OpenGLContext and
|
||||
/// successful initialization of the OpenGL context group
|
||||
///
|
||||
/// Can be re-implemented in derived classes to take any needed actions.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLWidget::onWidgetOpenGLReady()
|
||||
{
|
||||
// Base implementation does nothing
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLWidget::qtOpenGLContextAboutToBeDestroyed()
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, cvf::String("OpenGLWidget[%1]::qtOpenGLContextAboutToBeDestroyed()").arg(m_instanceNumber));
|
||||
|
||||
if (m_cvfForwardingOpenGlContext.notNull())
|
||||
{
|
||||
CVF_LOG_DEBUG(m_logger, cvf::String("OpenGLWidget[%1]: Shutting down CVF OpenGL context since Qt context is about to be destroyed").arg(m_instanceNumber));
|
||||
shutdownCvfOpenGLContext();
|
||||
}
|
||||
|
||||
if (m_initializationState == IS_INITIALIZED)
|
||||
{
|
||||
m_initializationState = PENDING_REINITIALIZATION;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLWidget::shutdownCvfOpenGLContext()
|
||||
{
|
||||
if (m_cvfForwardingOpenGlContext.notNull())
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
m_cvfOpenGlContextGroup->contextAboutToBeShutdown(m_cvfForwardingOpenGlContext.p());
|
||||
m_cvfForwardingOpenGlContext = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace cvfqt
|
||||
|
96
Fwk/VizFwk/LibGuiQt/cvfqtOpenGLWidget.h
Normal file
96
Fwk/VizFwk/LibGuiQt/cvfqtOpenGLWidget.h
Normal file
@ -0,0 +1,96 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2011-2013 Ceetron AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
//
|
||||
// GNU General Public License Usage
|
||||
// This library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
// GNU Lesser General Public License Usage
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cvfBase.h"
|
||||
#include "cvfObject.h"
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
|
||||
namespace cvf {
|
||||
class OpenGLContext;
|
||||
class OpenGLContextGroup;
|
||||
class Logger;
|
||||
}
|
||||
|
||||
namespace cvfqt {
|
||||
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==================================================================================================
|
||||
class OpenGLWidget : public QOpenGLWidget
|
||||
{
|
||||
public:
|
||||
OpenGLWidget(cvf::OpenGLContextGroup* contextGroup, QWidget* parent, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
~OpenGLWidget();
|
||||
|
||||
cvf::OpenGLContext* cvfOpenGLContext();
|
||||
|
||||
protected:
|
||||
virtual void initializeGL();
|
||||
virtual void resizeGL(int w, int h);
|
||||
virtual void paintGL();
|
||||
|
||||
int instanceNumber() const;
|
||||
|
||||
virtual void onWidgetOpenGLReady();
|
||||
|
||||
private:
|
||||
void qtOpenGLContextAboutToBeDestroyed();
|
||||
void shutdownCvfOpenGLContext();
|
||||
|
||||
private:
|
||||
enum InitializationState
|
||||
{
|
||||
UNINITIALIZED,
|
||||
PENDING_REINITIALIZATION,
|
||||
IS_INITIALIZED
|
||||
};
|
||||
|
||||
int m_instanceNumber;
|
||||
InitializationState m_initializationState;
|
||||
cvf::ref<cvf::OpenGLContextGroup> m_cvfOpenGlContextGroup;
|
||||
cvf::ref<cvf::OpenGLContext> m_cvfForwardingOpenGlContext;
|
||||
cvf::ref<cvf::Logger> m_logger;
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -485,8 +485,13 @@ void FramebufferObject::useDefaultWindowFramebuffer(OpenGLContext* oglContext)
|
||||
{
|
||||
CVF_CALLSITE_OPENGL(oglContext);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDrawBuffer(GL_BACK);
|
||||
const OglId defaultFBO = oglContext->defaultFramebufferObject();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
|
||||
if (defaultFBO == 0)
|
||||
{
|
||||
glDrawBuffer(GL_BACK);
|
||||
}
|
||||
|
||||
CVF_CHECK_OGL(oglContext);
|
||||
}
|
||||
|
@ -59,8 +59,7 @@ namespace cvf {
|
||||
/// The context will be added unconditionally to the \a contextGroup group
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
OpenGLContext::OpenGLContext(OpenGLContextGroup* contextGroup)
|
||||
: m_contextGroup(contextGroup),
|
||||
m_isValid(false)
|
||||
: m_contextGroup(contextGroup)
|
||||
{
|
||||
CVF_ASSERT(m_contextGroup);
|
||||
m_contextGroup->addContext(this);
|
||||
@ -74,8 +73,6 @@ OpenGLContext::~OpenGLContext()
|
||||
{
|
||||
//Trace::show("OpenGLContext destructor");
|
||||
|
||||
m_isValid = false;
|
||||
|
||||
// Context group is holding references to contexts, so by the time we get to this
|
||||
// destructor the link to the context group must already be broken
|
||||
CVF_ASSERT(m_contextGroup == NULL);
|
||||
@ -87,8 +84,7 @@ OpenGLContext::~OpenGLContext()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool OpenGLContext::isContextValid() const
|
||||
{
|
||||
// Also check on context group, since it may have been set to NULL after valid flag was set
|
||||
if (m_contextGroup && m_isValid)
|
||||
if (m_contextGroup && m_contextGroup->isContextGroupInitialized())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -102,59 +98,9 @@ bool OpenGLContext::isContextValid() const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool OpenGLContext::initializeContext()
|
||||
OglId OpenGLContext::defaultFramebufferObject() const
|
||||
{
|
||||
makeCurrent();
|
||||
|
||||
if (!m_contextGroup)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_contextGroup->isContextGroupInitialized())
|
||||
{
|
||||
if (!m_contextGroup->initializeContextGroup(this))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Prepare the context for deletion
|
||||
///
|
||||
/// Prepares the context for deletion by removing the context from its context group. If this is the
|
||||
/// last context in the context group, this function will also try and delete the context group's
|
||||
/// OpenGL resources.
|
||||
///
|
||||
/// \warning After calling this function the context is no longer usable and should be deleted.
|
||||
/// \warning May try and make the context current in order to free resources if this context
|
||||
/// is the last context in the context group.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLContext::shutdownContext()
|
||||
{
|
||||
if (m_contextGroup)
|
||||
{
|
||||
CVF_ASSERT(m_contextGroup->containsContext(this));
|
||||
|
||||
// If our ref count is down to 1, there is probably something strange going on.
|
||||
// Since one reference to us is being held by the context group, this means that the
|
||||
// caller ISN'T holding a reference which may give him a nast surprise when this function returns!
|
||||
CVF_ASSERT(refCount() > 1);
|
||||
|
||||
// This call will remove the context from the group AND clean up resources in the
|
||||
// group if we are the last context in the group
|
||||
m_contextGroup->contextAboutToBeShutdown(this);
|
||||
}
|
||||
|
||||
CVF_ASSERT(m_contextGroup == NULL);
|
||||
|
||||
m_isValid = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include "cvfObject.h"
|
||||
#include "cvfOpenGLContextGroup.h"
|
||||
#include "cvfOpenGLTypes.h"
|
||||
|
||||
namespace cvf {
|
||||
|
||||
@ -58,11 +59,10 @@ public:
|
||||
virtual ~OpenGLContext();
|
||||
|
||||
bool isContextValid() const;
|
||||
virtual bool initializeContext();
|
||||
virtual void shutdownContext();
|
||||
|
||||
virtual void makeCurrent() = 0;
|
||||
virtual bool isCurrent() const = 0;
|
||||
virtual OglId defaultFramebufferObject() const;
|
||||
|
||||
OpenGLContextGroup* group();
|
||||
const OpenGLContextGroup* group() const;
|
||||
@ -71,7 +71,6 @@ public:
|
||||
|
||||
private:
|
||||
OpenGLContextGroup* m_contextGroup; // Raw pointer (to avoid circular reference) to the context group that this context belongs to.
|
||||
bool m_isValid; // Will be set to true after successful initialization
|
||||
|
||||
friend class OpenGLContextGroup;
|
||||
};
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "cvfOpenGLResourceManager.h"
|
||||
#include "cvfOpenGLCapabilities.h"
|
||||
#include "cvfLogManager.h"
|
||||
#include "cvfTrace.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
@ -75,6 +76,8 @@ OpenGLContextGroup::OpenGLContextGroup()
|
||||
m_glewContextStruct(NULL),
|
||||
m_wglewContextStruct(NULL)
|
||||
{
|
||||
Trace::show("OpenGLContextGroup constructor");
|
||||
|
||||
m_resourceManager = new OpenGLResourceManager;
|
||||
m_logger = CVF_GET_LOGGER("cee.cvf.OpenGL");
|
||||
m_capabilities = new OpenGLCapabilities;
|
||||
@ -86,7 +89,7 @@ OpenGLContextGroup::OpenGLContextGroup()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
OpenGLContextGroup::~OpenGLContextGroup()
|
||||
{
|
||||
//Trace::show("OpenGLContextGroup destructor");
|
||||
Trace::show("OpenGLContextGroup destructor");
|
||||
|
||||
// Our resource manager must already be clean
|
||||
// There is no way of safely deleting the resources after all the contexts have been removed
|
||||
@ -129,6 +132,8 @@ bool OpenGLContextGroup::isContextGroupInitialized() const
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool OpenGLContextGroup::initializeContextGroup(OpenGLContext* currentContext)
|
||||
{
|
||||
Trace::show("OpenGLContextGroup::initializeContextGroup()");
|
||||
|
||||
CVF_ASSERT(currentContext);
|
||||
CVF_ASSERT(currentContext->isCurrent());
|
||||
CVF_ASSERT(containsContext(currentContext));
|
||||
@ -139,20 +144,27 @@ bool OpenGLContextGroup::initializeContextGroup(OpenGLContext* currentContext)
|
||||
|
||||
if (!initializeGLEW(currentContext))
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger.p(), "Failed to intitialize GLEW in context group");
|
||||
return false;
|
||||
}
|
||||
|
||||
configureCapablititesFromGLEW(currentContext);
|
||||
configureCapabilitiesFromGLEW(currentContext);
|
||||
|
||||
#ifdef WIN32
|
||||
if (!initializeWGLEW(currentContext))
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger.p(), "Failed to intitialize WGLEW in context group");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
CVF_LOG_DEBUG(m_logger.p(), "OpenGL initialized in context group");
|
||||
CVF_LOG_DEBUG(m_logger.p(), " version: " + m_info.version());
|
||||
CVF_LOG_DEBUG(m_logger.p(), " vendor: " + m_info.vendor());
|
||||
CVF_LOG_DEBUG(m_logger.p(), " renderer: " + m_info.renderer());
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
@ -165,10 +177,12 @@ bool OpenGLContextGroup::initializeContextGroup(OpenGLContext* currentContext)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLContextGroup::uninitializeContextGroup()
|
||||
{
|
||||
Trace::show("OpenGLContextGroup::uninitializeContextGroup()");
|
||||
|
||||
CVF_ASSERT(m_contexts.empty());
|
||||
CVF_ASSERT(!m_resourceManager->hasAnyOpenGLResources());
|
||||
|
||||
// Just replace capablities with a new object
|
||||
// Just replace capabilities with a new object
|
||||
m_capabilities = new OpenGLCapabilities;
|
||||
|
||||
#ifdef CVF_USE_GLEW
|
||||
@ -188,26 +202,28 @@ void OpenGLContextGroup::uninitializeContextGroup()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Called by OpenGLContext objects when they are being shut down
|
||||
///
|
||||
/// This function will remove the context \a contextToShutdown from the context group.
|
||||
/// If \a contextToShutdown is the last context in the group, all resources in the group's
|
||||
/// This function will remove the context \a currentContextToShutdown from the context group.
|
||||
/// If \a currentContextToShutdown is the last context in the group, all resources in the group's
|
||||
/// resource manager will be deleted and the context group will be reset to uninitialized.
|
||||
///
|
||||
/// \warning This function may try and make the context passed in \a contextToShutdown curreent!
|
||||
/// \warning The passed context must be the current OpenGL context!
|
||||
/// \warning After calling this function the context is no longer usable and should be deleted.
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLContextGroup::contextAboutToBeShutdown(OpenGLContext* contextToShutdown)
|
||||
void OpenGLContextGroup::contextAboutToBeShutdown(OpenGLContext* currentContextToShutdown)
|
||||
{
|
||||
CVF_ASSERT(contextToShutdown);
|
||||
CVF_ASSERT(containsContext(contextToShutdown));
|
||||
Trace::show("OpenGLContextGroup::contextAboutToBeShutdown()");
|
||||
|
||||
CVF_ASSERT(currentContextToShutdown);
|
||||
CVF_ASSERT(containsContext(currentContextToShutdown));
|
||||
|
||||
// If this is the last context in the group, we'll delete all the OpenGL resources in the s resource manager before we go
|
||||
bool shouldUninitializeGroup = false;
|
||||
if (contextCount() == 1)
|
||||
{
|
||||
CVF_ASSERT(m_resourceManager.notNull());
|
||||
if (m_resourceManager->hasAnyOpenGLResources() && contextToShutdown->isContextValid())
|
||||
if (m_resourceManager->hasAnyOpenGLResources() && currentContextToShutdown->isContextValid())
|
||||
{
|
||||
contextToShutdown->makeCurrent();
|
||||
m_resourceManager->deleteAllOpenGLResources(contextToShutdown);
|
||||
m_resourceManager->deleteAllOpenGLResources(currentContextToShutdown);
|
||||
}
|
||||
|
||||
shouldUninitializeGroup = true;
|
||||
@ -217,12 +233,12 @@ void OpenGLContextGroup::contextAboutToBeShutdown(OpenGLContext* contextToShutdo
|
||||
// Since one reference to the context is being held by this context group, this means that the
|
||||
// caller isn't holding a reference to the context. In this case the context object will evaporate
|
||||
// during the call below, and the caller will most likely get a nasty surprise
|
||||
CVF_ASSERT(contextToShutdown->refCount() > 1);
|
||||
CVF_ASSERT(currentContextToShutdown->refCount() > 1);
|
||||
|
||||
// Make sure we set the back pointer before removing it from our collection
|
||||
// since the removal from the list may actually trigger destruction of the context (see comment above)
|
||||
contextToShutdown->m_contextGroup = NULL;
|
||||
m_contexts.erase(contextToShutdown);
|
||||
currentContextToShutdown->m_contextGroup = NULL;
|
||||
m_contexts.erase(currentContextToShutdown);
|
||||
|
||||
if (shouldUninitializeGroup)
|
||||
{
|
||||
@ -239,11 +255,23 @@ void OpenGLContextGroup::contextAboutToBeShutdown(OpenGLContext* contextToShutdo
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool OpenGLContextGroup::initializeGLEW(OpenGLContext* currentContext)
|
||||
{
|
||||
Trace::show("OpenGLContextGroup::initializeGLEW()");
|
||||
|
||||
CVF_ASSERT(currentContext);
|
||||
CVF_ASSERT(m_glewContextStruct == NULL);
|
||||
|
||||
#ifdef CVF_USE_GLEW
|
||||
|
||||
// Usage of GLEW requires that we have a standard OpenGL implementation available (not any Qt wrapper etc)
|
||||
// Supposedly the version string should always contain at least one '.'
|
||||
// Try and test this by querying the OpenGL version number and assume that there is no OpenGL available if it fails
|
||||
const String sVersion(reinterpret_cast<const char*>(glGetString(GL_VERSION)));
|
||||
if (sVersion.find(".") == String::npos)
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, "Error initializing OpenGL functions, probe for OpenGL version failed. No valid OpenGL context is current");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Since we're sometimes (when using Core OpenGL) seeing some OGL errors from GLEW, check before and after call to help find them
|
||||
CVF_CHECK_OGL(currentContext);
|
||||
|
||||
@ -253,6 +281,7 @@ bool OpenGLContextGroup::initializeGLEW(OpenGLContext* currentContext)
|
||||
GLenum err = glewContextInit(theContextStruct);
|
||||
if (err != GLEW_OK)
|
||||
{
|
||||
CVF_LOG_ERROR(m_logger, String("Error initializing GLEW, glewContextInit() returned %1").arg(err));
|
||||
delete theContextStruct;
|
||||
return false;
|
||||
}
|
||||
@ -261,6 +290,10 @@ bool OpenGLContextGroup::initializeGLEW(OpenGLContext* currentContext)
|
||||
|
||||
CVF_CHECK_OGL(currentContext);
|
||||
|
||||
String sVendor(reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
|
||||
String sRenderer(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
|
||||
m_info.setOpenGLStrings(sVersion, sVendor, sRenderer);
|
||||
|
||||
#else
|
||||
|
||||
CVF_FAIL_MSG("Not implemented");
|
||||
@ -315,7 +348,7 @@ bool OpenGLContextGroup::initializeWGLEW(OpenGLContext* currentContext)
|
||||
///
|
||||
/// \warning The passed context must be current and GLEW must already be initialized!
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void OpenGLContextGroup::configureCapablititesFromGLEW(OpenGLContext* currentContext)
|
||||
void OpenGLContextGroup::configureCapabilitiesFromGLEW(OpenGLContext* currentContext)
|
||||
{
|
||||
#ifdef CVF_USE_GLEW
|
||||
CVF_CALLSITE_GLEW(currentContext);
|
||||
@ -362,6 +395,15 @@ size_t OpenGLContextGroup::contextCount() const
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
cvf::OpenGLContext* OpenGLContextGroup::context(size_t index)
|
||||
{
|
||||
return m_contexts.at(index);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -432,6 +474,15 @@ OpenGLCapabilities* OpenGLContextGroup::capabilities()
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
OpenGLInfo OpenGLContextGroup::info() const
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
@ -40,6 +40,8 @@
|
||||
#include "cvfObject.h"
|
||||
#include "cvfCollection.h"
|
||||
#include "cvfLogger.h"
|
||||
#include "cvfOpenGLCapabilities.h"
|
||||
#include "cvfOpenGLInfo.h"
|
||||
|
||||
struct GLEWContextStruct;
|
||||
struct WGLEWContextStruct;
|
||||
@ -48,7 +50,6 @@ namespace cvf {
|
||||
|
||||
class OpenGLContext;
|
||||
class OpenGLResourceManager;
|
||||
class OpenGLCapabilities;
|
||||
|
||||
|
||||
//==================================================================================================
|
||||
@ -63,24 +64,27 @@ public:
|
||||
virtual ~OpenGLContextGroup();
|
||||
|
||||
bool isContextGroupInitialized() const;
|
||||
bool initializeContextGroup(OpenGLContext* currentContext);
|
||||
void contextAboutToBeShutdown(OpenGLContext* currentContextToShutdown);
|
||||
|
||||
size_t contextCount() const;
|
||||
OpenGLContext* context(size_t index);
|
||||
bool containsContext(const OpenGLContext* context) const;
|
||||
|
||||
OpenGLResourceManager* resourceManager();
|
||||
Logger* logger();
|
||||
|
||||
OpenGLCapabilities* capabilities();
|
||||
OpenGLInfo info() const;
|
||||
|
||||
GLEWContextStruct* glewContextStruct();
|
||||
WGLEWContextStruct* wglewContextStruct();
|
||||
|
||||
private:
|
||||
bool initializeContextGroup(OpenGLContext* currentContext);
|
||||
void uninitializeContextGroup();
|
||||
void contextAboutToBeShutdown(OpenGLContext* contextToShutdown);
|
||||
bool initializeGLEW(OpenGLContext* currentContext);
|
||||
bool initializeWGLEW(OpenGLContext* currentContext);
|
||||
void configureCapablititesFromGLEW(OpenGLContext* currentContext);
|
||||
void configureCapabilitiesFromGLEW(OpenGLContext* currentContext);
|
||||
void addContext(OpenGLContext* contextToAdd);
|
||||
|
||||
private:
|
||||
@ -89,6 +93,7 @@ private:
|
||||
ref<OpenGLResourceManager> m_resourceManager; // Resource manager that is shared between all contexts in this group
|
||||
ref<Logger> m_logger;
|
||||
ref<OpenGLCapabilities> m_capabilities; // Capabilities of the contexts in this group context
|
||||
OpenGLInfo m_info;
|
||||
GLEWContextStruct* m_glewContextStruct; // Pointer to the GLEW context struct
|
||||
WGLEWContextStruct* m_wglewContextStruct; // Pointer to the GLEW context struct
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2018 Ceetron AS
|
||||
// Copyright (C) 2011-2013 Ceetron AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
|
@ -1,7 +1,7 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2018 Ceetron AS
|
||||
// Copyright (C) 2011-2013 Ceetron AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
|
@ -119,7 +119,9 @@ bool Win32OpenGLContext::createHardwareContext(HWND hWnd)
|
||||
m_hDC = hDC;
|
||||
m_hRC = hRC;
|
||||
|
||||
if (initializeContext())
|
||||
cvf::OpenGLContextGroup* ownerContextGroup = group();
|
||||
CVF_ASSERT(ownerContextGroup);
|
||||
if (ownerContextGroup->initializeContextGroup(this))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -136,7 +138,11 @@ bool Win32OpenGLContext::createHardwareContext(HWND hWnd)
|
||||
void Win32OpenGLContext::shutdownContext()
|
||||
{
|
||||
// Clears up resources and removes us from our group
|
||||
cvf::OpenGLContext::shutdownContext();
|
||||
cvf::OpenGLContextGroup* ownerContextGroup = group();
|
||||
CVF_ASSERT(ownerContextGroup);
|
||||
|
||||
makeCurrent();
|
||||
ownerContextGroup->contextAboutToBeShutdown(this);
|
||||
|
||||
if (m_hRC)
|
||||
{
|
||||
@ -165,7 +171,14 @@ void Win32OpenGLContext::makeCurrent()
|
||||
{
|
||||
if (m_hDC && m_hRC)
|
||||
{
|
||||
wglMakeCurrent(m_hDC, m_hRC);
|
||||
HGLRC currRCBefore = wglGetCurrentContext();
|
||||
if (currRCBefore != m_hRC)
|
||||
{
|
||||
wglMakeCurrent(m_hDC, m_hRC);
|
||||
HGLRC currRCAfter = wglGetCurrentContext();
|
||||
CVF_ASSERT(currRCAfter = m_hRC);
|
||||
CVF_UNUSED(currRCAfter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +190,8 @@ bool Win32OpenGLContext::isCurrent() const
|
||||
{
|
||||
if (m_hDC && m_hRC)
|
||||
{
|
||||
if (wglGetCurrentContext() == m_hRC)
|
||||
HGLRC currRC = wglGetCurrentContext();
|
||||
if (currRC == m_hRC)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
~Win32OpenGLContext();
|
||||
|
||||
bool createHardwareContext(HWND hWnd);
|
||||
virtual void shutdownContext();
|
||||
void shutdownContext();
|
||||
|
||||
virtual void makeCurrent();
|
||||
virtual bool isCurrent() const;
|
||||
|
@ -91,7 +91,7 @@ TEST(OpenGLContextGroupTest, LifeCycle)
|
||||
EXPECT_EQ(2, ctx2->refCount());
|
||||
EXPECT_EQ(2, ctx3->refCount());
|
||||
|
||||
ctx1->shutdownContext();
|
||||
grp->contextAboutToBeShutdown(ctx1.p());
|
||||
EXPECT_EQ(1, ctx1->refCount());
|
||||
EXPECT_TRUE(ctx1->group() == NULL);
|
||||
EXPECT_FALSE(grp->containsContext(ctx1.p()));
|
||||
|
Loading…
Reference in New Issue
Block a user