mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 01:30:18 +02:00
drafting along the RenderTHread class
This commit is contained in:
parent
7def4bf29b
commit
c24083c1f0
8 changed files with 187 additions and 45 deletions
|
@ -2425,6 +2425,7 @@ void Application::cleanupBeforeQuit() {
|
|||
}
|
||||
|
||||
_window->saveGeometry();
|
||||
|
||||
// _gpuContext->shutdown();
|
||||
|
||||
// Destroy third party processes after scripts have finished using them.
|
||||
|
@ -4178,41 +4179,37 @@ bool Application::acceptSnapshot(const QString& urlString) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t _renderedFrameIndex { INVALID_FRAME };
|
||||
|
||||
bool Application::shouldPaint() const {
|
||||
if (_aboutToQuit || _window->isMinimized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto displayPlugin = getActiveDisplayPlugin();
|
||||
|
||||
#ifdef DEBUG_PAINT_DELAY
|
||||
static uint64_t paintDelaySamples{ 0 };
|
||||
static uint64_t paintDelayUsecs{ 0 };
|
||||
|
||||
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
|
||||
|
||||
static const int PAINT_DELAY_THROTTLE = 1000;
|
||||
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
|
||||
qCDebug(interfaceapp).nospace() <<
|
||||
"Paint delay (" << paintDelaySamples << " samples): " <<
|
||||
(float)paintDelaySamples / paintDelayUsecs << "us";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Throttle if requested
|
||||
//if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
if (displayPlugin->isThrottled() && !_graphicsEngine.shouldPaint()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sync up the _renderedFrameIndex
|
||||
_renderedFrameIndex = displayPlugin->presentCount();
|
||||
return true;
|
||||
}
|
||||
//
|
||||
//bool Application::shouldPaint() const {
|
||||
// if (_aboutToQuit || _window->isMinimized()) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// auto displayPlugin = getActiveDisplayPlugin();
|
||||
//
|
||||
//#ifdef DEBUG_PAINT_DELAY
|
||||
// static uint64_t paintDelaySamples{ 0 };
|
||||
// static uint64_t paintDelayUsecs{ 0 };
|
||||
//
|
||||
// paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
|
||||
//
|
||||
// static const int PAINT_DELAY_THROTTLE = 1000;
|
||||
// if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
|
||||
// qCDebug(interfaceapp).nospace() <<
|
||||
// "Paint delay (" << paintDelaySamples << " samples): " <<
|
||||
// (float)paintDelaySamples / paintDelayUsecs << "us";
|
||||
// }
|
||||
//#endif
|
||||
//
|
||||
// // Throttle if requested
|
||||
// //if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
// if (displayPlugin->isThrottled() && !_graphicsEngine.shouldPaint()) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
//}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
|
|
|
@ -157,7 +157,7 @@ public:
|
|||
void updateSecondaryCameraViewFrustum();
|
||||
|
||||
void updateCamera(RenderArgs& renderArgs, float deltaTime);
|
||||
bool shouldPaint() const;
|
||||
// bool shouldPaint() const;
|
||||
// void paintGL();
|
||||
void resizeGL();
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ void GraphicsEngine::initializeGPU(GLWidget* glwidget) {
|
|||
|
||||
_renderEventHandler = new RenderEventHandler(
|
||||
glwidget->qglContext(),
|
||||
[this]() { return this->shouldPaint(); },
|
||||
[this]() { this->render_performFrame(); }
|
||||
);
|
||||
|
||||
|
@ -147,12 +148,37 @@ static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SI
|
|||
|
||||
|
||||
bool GraphicsEngine::shouldPaint() const {
|
||||
// Throttle if requested
|
||||
if ((static_cast<RenderEventHandler*>(_renderEventHandler)->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
// if (_aboutToQuit || _window->isMinimized()) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
|
||||
#ifdef DEBUG_PAINT_DELAY
|
||||
static uint64_t paintDelaySamples{ 0 };
|
||||
static uint64_t paintDelayUsecs{ 0 };
|
||||
|
||||
paintDelayUsecs += displayPlugin->getPaintDelayUsecs();
|
||||
|
||||
static const int PAINT_DELAY_THROTTLE = 1000;
|
||||
if (++paintDelaySamples % PAINT_DELAY_THROTTLE == 0) {
|
||||
qCDebug(interfaceapp).nospace() <<
|
||||
"Paint delay (" << paintDelaySamples << " samples): " <<
|
||||
(float)paintDelaySamples / paintDelayUsecs << "us";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Throttle if requested
|
||||
//if (displayPlugin->isThrottled() && (_graphicsEngine._renderEventHandler->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
if ( displayPlugin->isThrottled() &&
|
||||
(static_cast<RenderEventHandler*>(_renderEventHandler)->_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// }
|
||||
}
|
||||
|
||||
bool GraphicsEngine::checkPendingRenderEvent() {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <render/Engine.h>
|
||||
|
||||
#include "RenderThread.h"
|
||||
|
||||
#include <OctreeConstants.h>
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
|
@ -51,6 +53,8 @@ public:
|
|||
render::EnginePointer getRenderEngine() const { return _renderEngine; }
|
||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||
|
||||
FrameQueuePointer getFrameQueue() const { return _frameQueue; }
|
||||
|
||||
// Same as the one in application
|
||||
bool shouldPaint() const;
|
||||
bool checkPendingRenderEvent();
|
||||
|
@ -79,6 +83,8 @@ protected:
|
|||
|
||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||
|
||||
FrameQueuePointer _frameQueue{ new FrameQueue() };
|
||||
|
||||
QObject* _renderEventHandler{ nullptr };
|
||||
friend class RenderEventHandler;
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
|
||||
#include "CrashHandler.h"
|
||||
|
||||
RenderEventHandler::RenderEventHandler(QOpenGLContext* context, RenderCall renderCall) :
|
||||
RenderEventHandler::RenderEventHandler(QOpenGLContext* context, CheckCall checkCall, RenderCall renderCall) :
|
||||
_checkCall(checkCall),
|
||||
_renderCall(renderCall)
|
||||
{
|
||||
_renderContext = new OffscreenGLCanvas();
|
||||
|
@ -52,7 +53,7 @@ void RenderEventHandler::resumeThread() {
|
|||
}
|
||||
|
||||
void RenderEventHandler::render() {
|
||||
if (qApp->shouldPaint()) {
|
||||
if (_checkCall()) {
|
||||
_lastTimeRendered.start();
|
||||
_renderCall();
|
||||
}
|
||||
|
|
|
@ -28,10 +28,13 @@ class RenderEventHandler : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
|
||||
using CheckCall = std::function <bool()>;
|
||||
using RenderCall = std::function <void()>;
|
||||
|
||||
CheckCall _checkCall;
|
||||
RenderCall _renderCall;
|
||||
|
||||
RenderEventHandler(QOpenGLContext* context, RenderCall renderCall);
|
||||
RenderEventHandler(QOpenGLContext* context, CheckCall checkCall, RenderCall renderCall);
|
||||
|
||||
QElapsedTimer _lastTimeRendered;
|
||||
std::atomic<bool> _pendingRenderEvent{ true };
|
||||
|
|
1
interface/src/graphics/RenderThread.cpp
Normal file
1
interface/src/graphics/RenderThread.cpp
Normal file
|
@ -0,0 +1 @@
|
|||
#include "RenderThread.h"
|
108
interface/src/graphics/RenderThread.h
Normal file
108
interface/src/graphics/RenderThread.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
#ifndef PRODUCERCONSUMERPIPE_H
|
||||
#define PRODUCERCONSUMERPIPE_H
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
|
||||
// Producer is blocked if the consumer doesn't consume enough
|
||||
// Consumer reads same value if producer doesn't produce enough
|
||||
template <class T>
|
||||
class ProducerConsumerPipe {
|
||||
public:
|
||||
|
||||
ProducerConsumerPipe();
|
||||
ProducerConsumerPipe(const T& initValue);
|
||||
|
||||
const T& read();
|
||||
void read(T& value, const T& resetValue);
|
||||
void write(const T& value);
|
||||
bool isWritePossible();
|
||||
|
||||
private:
|
||||
|
||||
short _readIndex;
|
||||
short _writeIndex;
|
||||
std::array<T, 3> _values;
|
||||
std::array<std::atomic_flag, 3> _used;
|
||||
|
||||
void initialize();
|
||||
void updateReadIndex();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ProducerConsumerPipe<T>::ProducerConsumerPipe() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ProducerConsumerPipe<T>::ProducerConsumerPipe(const T& initValue) {
|
||||
_values.fill(initValue);
|
||||
initialize();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ProducerConsumerPipe<T>::initialize() {
|
||||
_readIndex = 0;
|
||||
_writeIndex = 2;
|
||||
_used[_readIndex].test_and_set(std::memory_order_acquire);
|
||||
_used[_writeIndex].test_and_set(std::memory_order_acquire);
|
||||
_used[1].clear();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ProducerConsumerPipe<T>::updateReadIndex() {
|
||||
int nextReadIndex = (_readIndex + 1) % _values.size();
|
||||
|
||||
if (!_used[nextReadIndex].test_and_set(std::memory_order_acquire)) {
|
||||
int readIndex = _readIndex;
|
||||
_used[readIndex].clear(std::memory_order_release);
|
||||
_readIndex = nextReadIndex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T& ProducerConsumerPipe<T>::read() {
|
||||
updateReadIndex();
|
||||
return _values[_readIndex];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ProducerConsumerPipe<T>::read(T& value, const T& resetValue) {
|
||||
updateReadIndex();
|
||||
value = _values[_readIndex];
|
||||
_values[_readIndex] = resetValue;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool ProducerConsumerPipe<T>::isWritePossible() {
|
||||
int nextWriteIndex = (_writeIndex + 1) % _values.size();
|
||||
return (_used[nextWriteIndex].test_and_set(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void ProducerConsumerPipe<T>::write(const T& value) {
|
||||
int nextWriteIndex = (_writeIndex + 1) % _values.size();
|
||||
int writeIndex = _writeIndex;
|
||||
|
||||
_values[writeIndex] = value;
|
||||
|
||||
while (_used[nextWriteIndex].test_and_set(std::memory_order_acquire)) {
|
||||
// spin
|
||||
std::this_thread::yield();
|
||||
}
|
||||
_used[writeIndex].clear(std::memory_order_release);
|
||||
_writeIndex = nextWriteIndex;
|
||||
}
|
||||
|
||||
|
||||
#include <gpu/Frame.h>
|
||||
|
||||
using FrameQueue = ProducerConsumerPipe<gpu::FramePointer>;
|
||||
|
||||
using FrameQueuePointer = std::shared_ptr<FrameQueue>;
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue