drafting along the RenderTHread class

This commit is contained in:
Sam Gateau 2018-07-25 10:50:15 +02:00
parent 7def4bf29b
commit c24083c1f0
8 changed files with 187 additions and 45 deletions

View file

@ -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>

View file

@ -157,7 +157,7 @@ public:
void updateSecondaryCameraViewFrustum();
void updateCamera(RenderArgs& renderArgs, float deltaTime);
bool shouldPaint() const;
// bool shouldPaint() const;
// void paintGL();
void resizeGL();

View file

@ -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() {

View file

@ -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;

View file

@ -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();
}

View file

@ -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 };

View file

@ -0,0 +1 @@
#include "RenderThread.h"

View 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