diff options
Diffstat (limited to 'src/render/backend/commandthread.cpp')
-rw-r--r-- | src/render/backend/commandthread.cpp | 108 |
1 files changed, 87 insertions, 21 deletions
diff --git a/src/render/backend/commandthread.cpp b/src/render/backend/commandthread.cpp index 9e764f0dd..387fc1113 100644 --- a/src/render/backend/commandthread.cpp +++ b/src/render/backend/commandthread.cpp @@ -38,7 +38,13 @@ ****************************************************************************/ #include "commandthread_p.h" +#include <Qt3DRender/private/glcommands_p.h> +#include <Qt3DRender/private/offscreensurfacehelper_p.h> +#include <Qt3DRender/private/graphicscontext_p.h> +#include <Qt3DRender/private/shadercache_p.h> #include <QOpenGLContext> +#include <QOffscreenSurface> +#include <QDebug> QT_BEGIN_NAMESPACE @@ -51,6 +57,13 @@ CommandThread::CommandThread(Renderer *renderer) , m_renderer(renderer) , m_waitForStartSemaphore(0) , m_initializedSemaphore(0) + , m_commandRequestedSemaphore(0) + , m_commandExecutionSemaphore(0) + , m_mainContext(nullptr) + , m_shaderCache(nullptr) + , m_offsreenSurfaceHelper(nullptr) + , m_currentCommand(nullptr) + , m_running(0) { } @@ -58,8 +71,13 @@ CommandThread::~CommandThread() { } +void CommandThread::setShaderCache(ShaderCache *shaderCache) +{ + m_shaderCache = shaderCache; +} + // Called by RenderThread or MainThread (Scene3d) -void CommandThread::initialize(QOpenGLContext *mainContext) +void CommandThread::initialize(QOpenGLContext *mainContext, OffscreenSurfaceHelper *offsreenSurfaceHelper) { // Start the thread start(); @@ -68,36 +86,58 @@ void CommandThread::initialize(QOpenGLContext *mainContext) m_waitForStartSemaphore.acquire(); m_mainContext = mainContext; - Q_ASSERT(m_mainContext); + m_offsreenSurfaceHelper = offsreenSurfaceHelper; + Q_ASSERT(m_mainContext && offsreenSurfaceHelper); + m_running.fetchAndStoreOrdered(1); // Allow thread to proceed m_initializedSemaphore.release(); } -// Called by RenderThread of MainThread (Scene3D) +// Called by RenderThread or MainThread (Scene3D) void CommandThread::shutdown() { - // Tell thread to exit event loop - QThread::quit(); + m_running.fetchAndStoreOrdered(0); + + // Unblock thread + m_commandRequestedSemaphore.release(1); // Wait for thread to exit wait(); // Reset semaphores (in case we ever want to restart) - m_waitForStartSemaphore.release(m_waitForStartSemaphore.available()); - m_initializedSemaphore.release(m_initializedSemaphore.available()); + m_waitForStartSemaphore.acquire(m_waitForStartSemaphore.available()); + m_initializedSemaphore.acquire(m_initializedSemaphore.available()); + m_commandRequestedSemaphore.acquire(m_commandRequestedSemaphore.available()); + m_commandExecutionSemaphore.acquire(m_commandExecutionSemaphore.available()); m_localContext.reset(); } // Any thread can call this, this is a blocking command -void CommandThread::executeCommand(Command *command) +void CommandThread::executeCommand(GLCommand *command) { if (!isRunning()) return; - QMetaObject::invokeMethod(this, - "executeCommandInternal", - Qt::BlockingQueuedConnection, - Q_ARG(Command*, command)); + + // We lock to prevent any other call to executeCommand to be executed + // before we have received the result of our command + m_blockingCallerMutex.lock(); + + // Store command to be executed + m_currentCommand = command; + + // Allow thread to proceed and execute command + m_commandRequestedSemaphore.release(); + + // Wait for thread to be done + m_commandExecutionSemaphore.acquire(); + + // Reset command + m_currentCommand = nullptr; + + // Unlock blocking semaphore so that other calls to executeCommand + // can proceed + m_blockingCallerMutex.unlock(); } void CommandThread::run() @@ -108,18 +148,44 @@ void CommandThread::run() // Wait for initialize to be completed m_initializedSemaphore.acquire(); + Q_ASSERT(m_mainContext && m_shaderCache); + // Initialize shared context and resources for the thread m_localContext.reset(new QOpenGLContext()); m_localContext->setShareContext(m_mainContext); - - // Launch exec loop - QThread::exec(); -} - -// Executed in the Command Thread -void CommandThread::executeCommandInternal(Command *command) -{ - command->execute(m_renderer, m_localContext.data()); + m_localContext->create(); + + // Initialize GraphicsContext + m_graphicsContext.reset(new GraphicsContext()); + m_graphicsContext->setShaderCache(m_shaderCache); + m_graphicsContext->setOpenGLContext(m_localContext.data()); + + bool initialized = false; + while (true) { + + // Wait for command + m_commandRequestedSemaphore.acquire(); + + // Are we still running? + if (!m_running.load()) { + m_graphicsContext->doneCurrent(); + // to prevent executeCommand being locked + m_commandExecutionSemaphore.release(); + break; + } + + if (Q_UNLIKELY(!initialized)) { + QOffscreenSurface *offscreenSurface = m_offsreenSurfaceHelper->offscreenSurface(); + Q_ASSERT(offscreenSurface); + m_graphicsContext->makeCurrent(offscreenSurface); + initialized = true; + } + + m_currentCommand->execute(m_renderer, m_graphicsContext.data()); + + // Allow caller to proceed as we are done with the command + m_commandExecutionSemaphore.release(); + } } } // Render |