Moved Qt dependency to Qt5:

* Updated all CMake scripts to use Qt5
* CampvisApplication takes care of moving the QGLContext thread affinity to the threads that do the rendering.
* QtCanvas:resize() is called through Qt signalling to ensure being in GUI thread.
* Added init and deinit functions to the Runnable interface.
* minimum required CMake version is now 3.0

refs #249
parent 151a2cf3
...@@ -105,15 +105,9 @@ EXPORT(PACKAGE CAMPVis) ...@@ -105,15 +105,9 @@ EXPORT(PACKAGE CAMPVis)
# = Copy Windows DLLs to binary dir for improved development experience ======= # = Copy Windows DLLs to binary dir for improved development experience =======
IF(WIN32) IF(WIN32)
# gather Qt4 DLLs - TODO: remove redundant naming of required components
FIND_PACKAGE(Qt4DLLs COMPONENTS QtCore QtGui QtOpenGL QtNetwork QtXmlPatterns)
LIST(APPEND CampvisExternalDllsDebug ${QT_DEBUG_DLLS})
LIST(APPEND CampvisExternalDllsRelease ${QT_RELEASE_DLLS})
LIST(REMOVE_DUPLICATES CampvisExternalDllsDebug)
LIST(REMOVE_DUPLICATES CampvisExternalDllsRelease)
IF(CAMPVIS_COPY_EXTERNAL_DLLS) IF(CAMPVIS_COPY_EXTERNAL_DLLS)
LIST(REMOVE_DUPLICATES CampvisExternalDllsDebug)
LIST(REMOVE_DUPLICATES CampvisExternalDllsRelease)
COPY_EXTERNAL_DLLS(CampvisExternalDllsDebug CampvisExternalDllsRelease false) COPY_EXTERNAL_DLLS(CampvisExternalDllsDebug CampvisExternalDllsRelease false)
ENDIF() ENDIF()
ENDIF() ENDIF()
......
...@@ -106,13 +106,7 @@ FOREACH(ModFile ${CampvisModulesApplicationToBeMocced}) ...@@ -106,13 +106,7 @@ FOREACH(ModFile ${CampvisModulesApplicationToBeMocced})
LIST(APPEND CampvisApplicationToBeMocced ${ModFileRelative}) LIST(APPEND CampvisApplicationToBeMocced ${ModFileRelative})
ENDFOREACH() ENDFOREACH()
# QT5_WRAP_UI(CampvisApplicationFormsHeaders ${CampvisApplicationForms})
# Qt related stuff:
#
QT4_WRAP_CPP(CampvisApplicationMoc ${CampvisApplicationToBeMocced})
LIST(APPEND CampvisApplicationSources ${CampvisApplicationMoc})
QT4_WRAP_UI(CampvisApplicationFormsHeaders ${CampvisApplicationForms})
LIST(APPEND CampvisApplicationSources ${CampvisApplicationFormsHeaders}) LIST(APPEND CampvisApplicationSources ${CampvisApplicationFormsHeaders})
LINK_DIRECTORIES(${CampvisGlobalLinkDirectories} ${CampvisModulesLinkDirectories}) LINK_DIRECTORIES(${CampvisGlobalLinkDirectories} ${CampvisModulesLinkDirectories})
...@@ -127,14 +121,16 @@ ADD_LIBRARY(campvis-application-lib ...@@ -127,14 +121,16 @@ ADD_LIBRARY(campvis-application-lib
${CampvisApplicationSources} ${CampvisApplicationHeaders} ${CampvisApplicationSources} ${CampvisApplicationHeaders}
${CampvisApplicationMoc} ${CampvisApplicationMoc}
) )
ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${CampvisApplicationDefinitions} ${QT_DEFINITIONS}) ADD_DEFINITIONS(${CampvisGlobalDefinitions} ${CampvisModulesDefinitions} ${CampvisApplicationDefinitions})
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs}) INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs} ${CampvisModulesIncludeDirs})
TARGET_LINK_LIBRARIES(campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES}) TARGET_LINK_LIBRARIES(campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs})
qt5_use_modules(campvis-application-lib Widgets OpenGL)
# if campvis-core is built as a shared library, CMake will define the following flag to instruct # if campvis-core is built as a shared library, CMake will define the following flag to instruct
# the code to export DLL symbols # the code to export DLL symbols
SET_TARGET_PROPERTIES(campvis-application-lib PROPERTIES DEFINE_SYMBOL "CAMPVIS_APPLICATION_BUILD_DLL") SET_TARGET_PROPERTIES(campvis-application-lib PROPERTIES DEFINE_SYMBOL "CAMPVIS_APPLICATION_BUILD_DLL")
IF(CAMPVIS_GROUP_SOURCE_FILES) IF(CAMPVIS_GROUP_SOURCE_FILES)
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationSources ${CampvisHome} "") DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationSources ${CampvisHome} "")
DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationHeaders ${CampvisHome} "") DEFINE_SOURCE_GROUPS_FROM_SUBDIR(CampvisApplicationHeaders ${CampvisHome} "")
...@@ -144,8 +140,8 @@ INSTALL(TARGETS campvis-application-lib DESTINATION exports EXPORT campvis-targe ...@@ -144,8 +140,8 @@ INSTALL(TARGETS campvis-application-lib DESTINATION exports EXPORT campvis-targe
ADD_EXECUTABLE(campvis-application "campvis.cpp") ADD_EXECUTABLE(campvis-application "campvis.cpp")
TARGET_LINK_LIBRARIES(campvis-application campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs} ${QT_LIBRARIES}) TARGET_LINK_LIBRARIES(campvis-application campvis-application-lib ${CampvisMainLibs} ${CampvisGlobalExternalLibs} ${CampvisModulesExternalLibs})
qt5_use_modules(campvis-application Widgets OpenGL)
IF(CAMPVIS_DEPLOY_SHADERS) IF(CAMPVIS_DEPLOY_SHADERS)
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "tools/qtjobprocessor.h" #include "tools/qtjobprocessor.h"
#include <QApplication> #include <QApplication>
#include <QThread>
#ifdef CAMPVIS_HAS_SCRIPTING #ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/glue/luavmstate.h" #include "scripting/glue/luavmstate.h"
...@@ -93,12 +94,11 @@ namespace campvis { ...@@ -93,12 +94,11 @@ namespace campvis {
#endif #endif
} }
_localContext = new QtThreadedCanvas("", cgt::ivec2(16, 16)); _localContext = new cgt::QtThreadedCanvas("", cgt::ivec2(16, 16));
campvis::init(_localContext, searchPaths); campvis::init(_localContext, searchPaths);
_mainWindow = new MainWindow(this); _mainWindow = new MainWindow(this);
cgt::GLContextScopedLock lock(_localContext); GLJobProc.enqueueJobBlocking([&]() {
{
_mainWindow->init(); _mainWindow->init();
// load textureData from file // load textureData from file
...@@ -133,7 +133,7 @@ namespace campvis { ...@@ -133,7 +133,7 @@ namespace campvis {
if (! _luaVmState->injectGlobalObjectPointer(this, "campvis::CampVisApplication *", "application")) if (! _luaVmState->injectGlobalObjectPointer(this, "campvis::CampVisApplication *", "application"))
LERROR("Could not inject the pipeline into the Lua VM."); LERROR("Could not inject the pipeline into the Lua VM.");
#endif #endif
} });
// parse argument list and create pipelines // parse argument list and create pipelines
QStringList pipelinesToAdd = this->arguments(); QStringList pipelinesToAdd = this->arguments();
...@@ -185,6 +185,12 @@ namespace campvis { ...@@ -185,6 +185,12 @@ namespace campvis {
for (auto it = _workflows.begin(); it != _workflows.end(); ++it) for (auto it = _workflows.begin(); it != _workflows.end(); ++it)
(*it)->deinit(); (*it)->deinit();
// Stop the OpenGLJobProcessor and pass Qt thread affinity back to this thread.
QThread* mainThread = QThread::currentThread();
GLJobProc.stop([&] () {
this->_localContext->context()->moveToThread(mainThread);
});
{ {
// Deinit everything OpenGL related using the local context. // Deinit everything OpenGL related using the local context.
cgt::GLContextScopedLock lock(_localContext); cgt::GLContextScopedLock lock(_localContext);
...@@ -255,7 +261,8 @@ namespace campvis { ...@@ -255,7 +261,8 @@ namespace campvis {
GLCtxtMgr.releaseContext(canvas, false); GLCtxtMgr.releaseContext(canvas, false);
s_PipelinesChanged.emitSignal(); s_PipelinesChanged.emitSignal();
pipeline->start();
startOpenGlThreadAndMoveQtThreadAffinity(pipeline, canvas);
} }
void CampVisApplication::initGlContextAndPipeline(cgt::GLCanvas* canvas, AbstractPipeline* pipeline) { void CampVisApplication::initGlContextAndPipeline(cgt::GLCanvas* canvas, AbstractPipeline* pipeline) {
...@@ -286,7 +293,7 @@ namespace campvis { ...@@ -286,7 +293,7 @@ namespace campvis {
void CampVisApplication::rebuildAllShadersFromFiles() { void CampVisApplication::rebuildAllShadersFromFiles() {
// rebuilding all shaders has to be done from OpenGL context, use the local one. // rebuilding all shaders has to be done from OpenGL context, use the local one.
GLJobProc.enqueueJob(makeJobOnHeap(this, &CampVisApplication::triggerShaderRebuild)); GLJobProc.enqueueJob(cgt::makeJobOnHeap(this, &CampVisApplication::triggerShaderRebuild));
} }
void CampVisApplication::triggerShaderRebuild() { void CampVisApplication::triggerShaderRebuild() {
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
namespace cgt { namespace cgt {
class GLCanvas; class GLCanvas;
class QtCanvas;
class QtThreadedCanvas; class QtThreadedCanvas;
class Texture; class Texture;
} }
...@@ -170,7 +171,7 @@ namespace campvis { ...@@ -170,7 +171,7 @@ namespace campvis {
void triggerShaderRebuild(); void triggerShaderRebuild();
/// A local OpenGL context used for initialization /// A local OpenGL context used for initialization
cgt::GLCanvas* _localContext; cgt::QtCanvas* _localContext;
/// Main window hosting GUI stuff /// Main window hosting GUI stuff
MainWindow* _mainWindow; MainWindow* _mainWindow;
......
...@@ -70,7 +70,6 @@ namespace campvis { ...@@ -70,7 +70,6 @@ namespace campvis {
static_cast<Geometry1DTransferFunction*>(p_transferFunction.getTF())->addGeometry(TFGeometry1D::createQuad(cgt::vec2(0.f, 1.f), cgt::col4(0, 0, 0, 255), cgt::col4(255, 255, 255, 255))); static_cast<Geometry1DTransferFunction*>(p_transferFunction.getTF())->addGeometry(TFGeometry1D::createQuad(cgt::vec2(0.f, 1.f), cgt::col4(0, 0, 0, 255), cgt::col4(255, 255, 255, 255)));
GLCtxtMgr.registerContextAndInitGlew(this, "DataContainerInspector"); GLCtxtMgr.registerContextAndInitGlew(this, "DataContainerInspector");
GLCtxtMgr.releaseContext(this, false);
addProperty(p_currentSlice); addProperty(p_currentSlice);
addProperty(p_transferFunction); addProperty(p_transferFunction);
...@@ -103,10 +102,12 @@ namespace campvis { ...@@ -103,10 +102,12 @@ namespace campvis {
p_renderGChannel.setVisible(false); p_renderGChannel.setVisible(false);
p_renderBChannel.setVisible(false); p_renderBChannel.setVisible(false);
p_renderAChannel.setVisible(false); p_renderAChannel.setVisible(false);
init();
} }
DataContainerInspectorCanvas::~DataContainerInspectorCanvas() { DataContainerInspectorCanvas::~DataContainerInspectorCanvas() {
deinit();
} }
void DataContainerInspectorCanvas::init() { void DataContainerInspectorCanvas::init() {
...@@ -157,16 +158,17 @@ namespace campvis { ...@@ -157,16 +158,17 @@ namespace campvis {
_geometriesDirty = false; _geometriesDirty = false;
} }
if (_textures.empty()) {
return;
}
glPushAttrib(GL_ALL_ATTRIB_BITS); glPushAttrib(GL_ALL_ATTRIB_BITS);
glViewport(0, 0, size_.x, size_.y); glViewport(0, 0, size_.x, size_.y);
glClearColor(0.7f, 0.7f, 0.7f, 1.f); glClearColor(0.7f, 0.7f, 0.7f, 1.f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
LGL_ERROR; LGL_ERROR;
if (_textures.empty()) {
glPopAttrib();
return;
}
// update layout dimensions // update layout dimensions
_numTiles.x = ceil(sqrt(static_cast<float>(_textures.size()))); _numTiles.x = ceil(sqrt(static_cast<float>(_textures.size())));
_numTiles.y = ceil(static_cast<float>(_textures.size()) / _numTiles.x); _numTiles.y = ceil(static_cast<float>(_textures.size()) / _numTiles.x);
...@@ -252,13 +254,17 @@ namespace campvis { ...@@ -252,13 +254,17 @@ namespace campvis {
void DataContainerInspectorCanvas::invalidate() { void DataContainerInspectorCanvas::invalidate() {
// only if inited // only if inited
if (_quad != 0 && _paintShader != 0) { if (_quad != 0 && _paintShader != 0) {
this->makeCurrent();
paint();
this->swap();
// avoid recursive paints. // avoid recursive paints.
if (! cgt::GlContextManager::getRef().checkWhetherThisThreadHasAcquiredOpenGlContext()) { // if (! cgt::GlContextManager::getRef().checkWhetherThisThreadHasAcquiredOpenGlContext()) {
SimpleJobProc.enqueueJob([this] () { // SimpleJobProc.enqueueJob(
cgt::GLContextScopedLock lock(this); // [this] () {
paint(); // cgt::GLContextScopedLock lock(this);
}); // paint();
} // });
// }
} }
} }
......
...@@ -146,14 +146,6 @@ namespace campvis { ...@@ -146,14 +146,6 @@ namespace campvis {
*/ */
virtual void paint(); virtual void paint();
/**
* Gets called when the data collection of this pipeline has changed and thus has notified its observers.
* If \a name equals the name of the renderTarget, the s_renderTargetChanged signal will be emitted.
* \param name Name of the added data.
* \param dh DataHandle to the newly added data.
*/
void onDataContainerDataAdded(const std::string& name, DataHandle dh);
/** /**
* Slot getting called when one of the observed properties changed and notifies its observers. * Slot getting called when one of the observed properties changed and notifies its observers.
* \param prop Property that emitted the signal * \param prop Property that emitted the signal
......
...@@ -386,17 +386,10 @@ namespace campvis { ...@@ -386,17 +386,10 @@ namespace campvis {
} }
void DataContainerInspectorWidget::init() { void DataContainerInspectorWidget::init() {
if (_canvas != 0)
_canvas->init();
_inited = true; _inited = true;
} }
void DataContainerInspectorWidget::deinit() { void DataContainerInspectorWidget::deinit() {
_inited = false;
if (_canvas != 0)
_canvas->deinit();
_pcWidget->updatePropCollection(0, 0); _pcWidget->updatePropCollection(0, 0);
if (_dataContainer != 0) { if (_dataContainer != 0) {
...@@ -408,6 +401,8 @@ namespace campvis { ...@@ -408,6 +401,8 @@ namespace campvis {
if(_propEditorWid != nullptr) if(_propEditorWid != nullptr)
_propEditorWid->deinit(); _propEditorWid->deinit();
_inited = false;
} }
void DataContainerInspectorWidget::onDCTWidgetSelectionModelSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { void DataContainerInspectorWidget::onDCTWidgetSelectionModelSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
......
...@@ -435,8 +435,6 @@ namespace campvis { ...@@ -435,8 +435,6 @@ namespace campvis {
} }
void MainWindow::onBtnProcessorFactoryClicked() { void MainWindow::onBtnProcessorFactoryClicked() {
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard;
std::string name = this->_cbProcessorFactory->currentText().toStdString(); std::string name = this->_cbProcessorFactory->currentText().toStdString();
if (_selectedPipeline == nullptr) if (_selectedPipeline == nullptr)
return; return;
...@@ -447,9 +445,11 @@ namespace campvis { ...@@ -447,9 +445,11 @@ namespace campvis {
if (p == nullptr) if (p == nullptr)
return; return;
p->init(); GLJobProc.enqueueJobBlocking([&]() {
_selectedPipeline->addProcessor(p); p->init();
});
_selectedPipeline->addProcessor(p);
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines); emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
} }
......
...@@ -44,7 +44,7 @@ namespace campvis { ...@@ -44,7 +44,7 @@ namespace campvis {
_logDisplay, SLOT(append(const QString&))); _logDisplay, SLOT(append(const QString&)));
} }
void QTextEditLog::logFiltered(const std::string& cat, LogLevel level, const std::string& msg, void QTextEditLog::logFiltered(const std::string& cat, cgt::LogLevel level, const std::string& msg,
const std::string& /*extendedInfo*/) const std::string& /*extendedInfo*/)
{ {
std::string output = ""; std::string output = "";
......
...@@ -33,14 +33,12 @@ ...@@ -33,14 +33,12 @@
#include <QTextEdit> #include <QTextEdit>
#include <QTextDocument> #include <QTextDocument>
using namespace cgt;
namespace campvis { namespace campvis {
/** /**
* QTextEditLog implements logging to a QTextEdit instance. * QTextEditLog implements logging to a QTextEdit instance.
*/ */
class CAMPVIS_APPLICATION_API QTextEditLog : private QObject, public Log { class CAMPVIS_APPLICATION_API QTextEditLog : private QObject, public cgt::Log {
Q_OBJECT Q_OBJECT
...@@ -77,7 +75,7 @@ namespace campvis { ...@@ -77,7 +75,7 @@ namespace campvis {
protected: protected:
QTextEdit* _logDisplay; QTextEdit* _logDisplay;
void logFiltered(const std::string &cat, LogLevel level, const std::string &msg, const std::string &extendedInfo=""); void logFiltered(const std::string &cat, cgt::LogLevel level, const std::string &msg, const std::string &extendedInfo="");
}; };
} }
......
# Try to find Win32 Qt DLLs to be copied to the bin directory. Once done this will define:
# QT_DLLS_FOUND
# QT_DEBUG_DLLS
# QT_RELEASE_DLLS
#
# Note: FIND_PACKAGE(Qt4 ...) has to be called before in order for ${QT_LIBRARY_DIR}
# and ${QT_BINARY_DIR} to be defined!
# DLLs are either located in Qt library or binary directory
IF(EXISTS ${QT_LIBRARY_DIR}/QtCored4.dll)
SET(DLL_DIR ${QT_LIBRARY_DIR})
ELSEIF(EXISTS ${QT_BINARY_DIR}/QtCored4.dll)
SET(DLL_DIR ${QT_BINARY_DIR})
ELSEIF(EXISTS ${QT_LIBRARY_DIR}/QtCore4.dll)
SET(DLL_DIR ${QT_LIBRARY_DIR})
ELSEIF(EXISTS ${QT_BINARY_DIR}/QtCore4.dll)
SET(DLL_DIR ${QT_BINARY_DIR})
ENDIF()
IF(DLL_DIR)
SET(QT_DLLS_FOUND TRUE)
FOREACH(component ${Qt4DLLs_FIND_COMPONENTS})
IF(EXISTS ${DLL_DIR}/${component}d4.dll)
LIST(APPEND QT_DEBUG_DLLS ${DLL_DIR}/${component}d4.dll)
ELSE()
MESSAGE("Failed to find Qt Debug DLL: ${component}d4.dll")
SET(QT_DLLS_FOUND FALSE)
ENDIF()
IF(EXISTS ${DLL_DIR}/${component}4.dll)
LIST(APPEND QT_RELEASE_DLLS ${DLL_DIR}/${component}4.dll)
ELSE()
MESSAGE(WARNING "Failed to find Qt Release DLL: ${component}4.dll")
SET(QT_DLLS_FOUND FALSE)
ENDIF()
ENDFOREACH()
ELSE()
SET(QT_DLLS_FOUND FALSE)
ENDIF()
UNSET(Qt4DLLsCAMPVIS_DIR)
MARK_AS_ADVANCED(Qt4DLLsCAMPVIS_DIR)
...@@ -196,10 +196,19 @@ ENDIF() ...@@ -196,10 +196,19 @@ ENDIF()
# minimum Qt version # minimum Qt version
IF(CAMPVIS_BUILD_APPLICATION) IF(CAMPVIS_BUILD_APPLICATION)
FIND_PACKAGE(Qt4 ${CampvisRequiredQtVersion} REQUIRED QtCore QtGui QtOpenGL) SET(CampvisRequiredQtVersion "5.0")
INCLUDE(${QT_USE_FILE})
# Tell CMake to run moc when necessary:
SET(CMAKE_AUTOMOC ON)
# As moc files are generated in the binary dir, tell CMake to always look for includes there:
SET(CMAKE_INCLUDE_CURRENT_DIR ON)
FIND_PACKAGE(Qt5Widgets REQUIRED)
FIND_PACKAGE(Qt5OpenGL REQUIRED)
RESOLVE_QT5_DLL_LOCATIONS("Core;Gui;OpenGL;Widgets")
SET(CGT_WITH_QT true) SET(CGT_WITH_QT true)
SET(CampvisRequiredQtVersion "4.8")
ENDIF(CAMPVIS_BUILD_APPLICATION) ENDIF(CAMPVIS_BUILD_APPLICATION)
......
...@@ -263,6 +263,16 @@ MACRO(LIST_SUBDIRECTORIES Result Directory AbsolutePath) ...@@ -263,6 +263,16 @@ MACRO(LIST_SUBDIRECTORIES Result Directory AbsolutePath)
LIST(SORT ${Result}) LIST(SORT ${Result})
ENDMACRO(LIST_SUBDIRECTORIES) ENDMACRO(LIST_SUBDIRECTORIES)
# Resolve Qt5 DLL locations
MACRO(RESOLVE_QT5_DLL_LOCATIONS Components)
FOREACH(component ${Components})
GET_TARGET_PROPERTY(DebugLocation "Qt5::${component}" LOCATION_DEBUG)
GET_TARGET_PROPERTY(ReleaseLocation "Qt5::${component}" LOCATION)
LIST(APPEND CampvisExternalDllsDebug ${DebugLocation})
LIST(APPEND CampvisExternalDllsRelease ${ReleaseLocation})
ENDFOREACH()
ENDMACRO(RESOLVE_QT5_DLL_LOCATIONS)
# copies the passed debug and release DLLs to bin/Debug and bin/Release, resp. # copies the passed debug and release DLLs to bin/Debug and bin/Release, resp.
MACRO(COPY_EXTERNAL_DLLS DebugDLLs ReleaseDLLs failOnError) MACRO(COPY_EXTERNAL_DLLS DebugDLLs ReleaseDLLs failOnError)
MESSAGE(STATUS "* Copying external DLLs") MESSAGE(STATUS "* Copying external DLLs")
......
...@@ -41,8 +41,10 @@ namespace campvis { ...@@ -41,8 +41,10 @@ namespace campvis {
return nullptr; return nullptr;
} }
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard; ImageRepresentationGL* toReturn = nullptr;
ImageRepresentationGL* toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), wtp); GLJobProc.enqueueJobBlocking([&]() {
toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), wtp);
});
switch (wtp._baseType) { switch (wtp._baseType) {
case WeaklyTypedPointer::UINT8: case WeaklyTypedPointer::UINT8:
...@@ -74,8 +76,10 @@ namespace campvis { ...@@ -74,8 +76,10 @@ namespace campvis {
return toReturn; return toReturn;
} }
else if (const ImageRepresentationLocal* tester = dynamic_cast<const ImageRepresentationLocal*>(source)) { else if (const ImageRepresentationLocal* tester = dynamic_cast<const ImageRepresentationLocal*>(source)) {
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard; ImageRepresentationGL* toReturn = nullptr;
ImageRepresentationGL* toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), tester->getWeaklyTypedPointer()); GLJobProc.enqueueJobBlocking([&]() {
toReturn = ImageRepresentationGL::create(const_cast<ImageData*>(tester->getParent()), tester->getWeaklyTypedPointer());
});
return toReturn; return toReturn;
} }
...@@ -92,12 +96,15 @@ namespace campvis { ...@@ -92,12 +96,15 @@ namespace campvis {
return ImageRepresentationLocal::create(tester->getParent(), tester->getWeaklyTypedPointer()); return ImageRepresentationLocal::create(tester->getParent(), tester->getWeaklyTypedPointer());
} }
else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) { else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) {
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard; ImageRepresentationLocal* toReturn = nullptr;
WeaklyTypedPointer wtp = tester->getWeaklyTypedPointerCopy();
if (wtp._pointer != nullptr)
return ImageRepresentationLocal::create(source->getParent(), wtp);
return nullptr; GLJobProc.enqueueJobBlocking([&]() {
WeaklyTypedPointer wtp = tester->getWeaklyTypedPointerCopy();
if (wtp._pointer != nullptr)
toReturn = ImageRepresentationLocal::create(source->getParent(), wtp);
});
return toReturn;
} }
return nullptr; return nullptr;
......
...@@ -96,16 +96,17 @@ namespace campvis { ...@@ -96,16 +96,17 @@ namespace campvis {
else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) { else if (const ImageRepresentationGL* tester = dynamic_cast<const ImageRepresentationGL*>(source)) {
// converting from GL representation // converting from GL representation
cgt::OpenGLJobProcessor::ScopedSynchronousGlJobExecution jobGuard; GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>* toReturn = nullptr;
GLJobProc.enqueueJobBlocking([&]() {
if (cgt::Texture::calcMatchingDataType(tester->getTexture()->getInternalFormat()) != TypeTraits<BASETYPE, NUMCHANNELS>::glDataType)
LDEBUGC("CAMPVis.core.datastructures.GenericLocalConversion", "Performing conversion between data types, you may lose information or the resulting data may show other unexpected features.");
if (cgt::Texture::calcMatchingDataType(tester->getTexture()->getInternalFormat()) != TypeTraits<BASETYPE, NUMCHANNELS>::glDataType) WeaklyTypedPointer wtp = tester->getWeaklyTypedPointerConvert(TypeTraits<BASETYPE, NUMCHANNELS>::glDataType);
LDEBUGC("CAMPVis.core.datastructures.GenericLocalConversion", "Performing conversion between data types, you may lose information or the resulting data may show other unexpected features."); if (wtp._pointer != nullptr)
toReturn = GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(tester->getParent(), static_cast<ElementType*>(wtp._pointer));
WeaklyTypedPointer wtp = tester->getWeaklyTypedPointerConvert(TypeTraits<BASETYPE, NUMCHANNELS>::glDataType); });
if (wtp._pointer != nullptr)
return GenericImageRepresentationLocal<BASETYPE, NUMCHANNELS>::create(tester->getParent(), static_cast<ElementType*>(wtp._pointer));
return nullptr; return toReturn;
} }
else if (const ThisType* tester = dynamic_cast<const ThisType*>(source)) { else if (const ThisType* tester = dynamic_cast<const ThisType*>(source)) {
......
...@@ -72,7 +72,7 @@ namespace campvis { ...@@ -72,7 +72,7 @@ namespace campvis {
GLCtxtMgr.releaseContext(backgroundGlContext, false); GLCtxtMgr.releaseContext(backgroundGlContext, false);
GLJobProc.setContext(backgroundGlContext); GLJobProc.setContext(backgroundGlContext);
GLJobProc.start(); startOpenGlThreadAndMoveQtThreadAffinity(cgt::OpenGLJobProcessor::getPtr(), backgroundGlContext);
} }
void deinit() { void deinit() {
...@@ -91,6 +91,36 @@ namespace campvis { ...@@ -91,6 +91,36 @@ namespace campvis {
ProcessorFactory::deinit(); ProcessorFactory::deinit();
} }
CAMPVIS_CORE_API void startOpenGlThreadAndMoveQtThreadAffinity(cgt::Runnable* runnable, cgt::GLCanvas* canvas) {
// welcome to a complex signalling ping-pong to move the OpenGL context thread affinity
// we will use targetThread as signalling variable and initialize it with nullptr:
void* targetThread = nullptr;
// start the new thread with special init function
runnable->start([&]() {
// the init function sets the signal variable to this thread's thread.
targetThread = canvas->getCurrentThreadPointer();
// wait until the signal variable has been reset to nullptr, since later calls in this
// thread may rely on the QGLContext's thread affinity already been moved.
while (targetThread != nullptr)
std::this_thread::yield();
targetThread = nullptr;
});
// Meanwhile in the main thread:
// wait until the signal variable has been set by the freshly created thread
while (targetThread == nullptr)
std::this_thread::yield();
// set the QGLContext's thread affinity
canvas->moveThreadAffinity(targetThread);
// reset the signal variable so that the new thread can continue.
targetThread = nullptr;
}
CAMPVIS_CORE_API std::string completePath(const std::string& filename) { CAMPVIS_CORE_API std::string completePath(const std::string& filename) {
if (! cgt::ShaderManager::isInited()) if (! cgt::ShaderManager::isInited())
return ""; return "";
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <vector> #include <vector>
namespace cgt { namespace cgt {
class Runnable;
class GLCanvas; class GLCanvas;
} }