mirror of
https://github.com/lubosz/overte.git
synced 2025-04-18 04:18:17 +02:00
Merge pull request #6613 from jherico/threaded_qml
Moving QML rendering off the main thread
This commit is contained in:
commit
30fd96b509
6 changed files with 105 additions and 106 deletions
|
@ -8,16 +8,18 @@
|
|||
#include "OffscreenQmlSurface.h"
|
||||
#include "OglplusHelpers.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtQml>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlComponent>
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWindow>
|
||||
#include <QQuickRenderControl>
|
||||
#include <QWaitCondition>
|
||||
#include <QMutex>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtQml/QtQml>
|
||||
#include <QtQml/QQmlEngine>
|
||||
#include <QtQml/QQmlComponent>
|
||||
#include <QtQuick/QQuickItem>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtQuick/QQuickRenderControl>
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
#include <shared/NsightHelpers.h>
|
||||
#include <PerfStat.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -25,8 +27,6 @@
|
|||
#include "GLEscrow.h"
|
||||
#include "OffscreenGLCanvas.h"
|
||||
|
||||
// FIXME move to threaded rendering with Qt 5.5
|
||||
//#define QML_THREADED
|
||||
|
||||
// Time between receiving a request to render the offscreen UI actually triggering
|
||||
// the render. Could possibly be increased depending on the framerate we expect to
|
||||
|
@ -56,13 +56,11 @@ private:
|
|||
Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
|
||||
Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
|
||||
|
||||
#ifdef QML_THREADED
|
||||
static const QEvent::Type INIT = QEvent::Type(QEvent::User + 1);
|
||||
static const QEvent::Type RENDER = QEvent::Type(QEvent::User + 2);
|
||||
static const QEvent::Type RESIZE = QEvent::Type(QEvent::User + 3);
|
||||
static const QEvent::Type STOP = QEvent::Type(QEvent::User + 4);
|
||||
static const QEvent::Type UPDATE = QEvent::Type(QEvent::User + 5);
|
||||
#endif
|
||||
|
||||
class OffscreenQmlRenderer : public OffscreenGLCanvas {
|
||||
friend class OffscreenQmlSurface;
|
||||
|
@ -70,22 +68,30 @@ public:
|
|||
|
||||
OffscreenQmlRenderer(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) {
|
||||
OffscreenGLCanvas::create(shareContext);
|
||||
#ifdef QML_THREADED
|
||||
|
||||
_renderControl = new QMyQuickRenderControl();
|
||||
|
||||
// Create a QQuickWindow that is associated with out render control. Note that this
|
||||
// window never gets created or shown, meaning that it will never get an underlying
|
||||
// native (platform) window.
|
||||
QQuickWindow::setDefaultAlphaBuffer(true);
|
||||
// Weirdness... QQuickWindow NEEDS to be created on the rendering thread, or it will refuse to render
|
||||
// because it retains an internal 'context' object that retains the thread it was created on,
|
||||
// regardless of whether you later move it to another thread.
|
||||
_quickWindow = new QQuickWindow(_renderControl);
|
||||
_quickWindow->setColor(QColor(255, 255, 255, 0));
|
||||
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
|
||||
|
||||
// Qt 5.5
|
||||
_renderControl->prepareThread(_renderThread);
|
||||
_renderControl->prepareThread(&_thread);
|
||||
_context->moveToThread(&_thread);
|
||||
moveToThread(&_thread);
|
||||
_thread.setObjectName("QML Thread");
|
||||
_thread.start();
|
||||
post(INIT);
|
||||
#else
|
||||
init();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QML_THREADED
|
||||
bool event(QEvent *e)
|
||||
{
|
||||
bool event(QEvent *e) {
|
||||
switch (int(e->type())) {
|
||||
case INIT:
|
||||
{
|
||||
|
@ -120,7 +126,6 @@ public:
|
|||
QCoreApplication::postEvent(this, new QEvent(type));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
|
@ -143,27 +148,9 @@ private:
|
|||
|
||||
|
||||
void init() {
|
||||
_renderControl = new QMyQuickRenderControl();
|
||||
connect(_renderControl, &QQuickRenderControl::renderRequested, _surface, &OffscreenQmlSurface::requestRender);
|
||||
connect(_renderControl, &QQuickRenderControl::sceneChanged, _surface, &OffscreenQmlSurface::requestUpdate);
|
||||
|
||||
// Create a QQuickWindow that is associated with out render control. Note that this
|
||||
// window never gets created or shown, meaning that it will never get an underlying
|
||||
// native (platform) window.
|
||||
QQuickWindow::setDefaultAlphaBuffer(true);
|
||||
// Weirdness... QQuickWindow NEEDS to be created on the rendering thread, or it will refuse to render
|
||||
// because it retains an internal 'context' object that retains the thread it was created on,
|
||||
// regardless of whether you later move it to another thread.
|
||||
_quickWindow = new QQuickWindow(_renderControl);
|
||||
_quickWindow->setColor(QColor(255, 255, 255, 0));
|
||||
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
|
||||
|
||||
#ifdef QML_THREADED
|
||||
// However, because we want to use synchronous events with the quickwindow, we need to move it back to the main
|
||||
// thread after it's created.
|
||||
_quickWindow->moveToThread(qApp->thread());
|
||||
#endif
|
||||
|
||||
if (!makeCurrent()) {
|
||||
qWarning("Failed to make context current on render thread");
|
||||
return;
|
||||
|
@ -189,17 +176,15 @@ private:
|
|||
|
||||
doneCurrent();
|
||||
|
||||
#ifdef QML_THREADED
|
||||
_context->moveToThread(QCoreApplication::instance()->thread());
|
||||
_cond.wakeOne();
|
||||
#endif
|
||||
}
|
||||
|
||||
void resize(const QSize& newSize) {
|
||||
void resize() {
|
||||
// Update our members
|
||||
if (_quickWindow) {
|
||||
_quickWindow->setGeometry(QRect(QPoint(), newSize));
|
||||
_quickWindow->contentItem()->setSize(newSize);
|
||||
_quickWindow->setGeometry(QRect(QPoint(), _newSize));
|
||||
_quickWindow->contentItem()->setSize(_newSize);
|
||||
}
|
||||
|
||||
// Qt bug in 5.4 forces this check of pixel ratio,
|
||||
|
@ -209,7 +194,7 @@ private:
|
|||
pixelRatio = _renderControl->_renderWindow->devicePixelRatio();
|
||||
}
|
||||
|
||||
uvec2 newOffscreenSize = toGlm(newSize * pixelRatio);
|
||||
uvec2 newOffscreenSize = toGlm(_newSize * pixelRatio);
|
||||
_textures.setSize(newOffscreenSize);
|
||||
if (newOffscreenSize == _size) {
|
||||
return;
|
||||
|
@ -222,7 +207,7 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio;
|
||||
qDebug() << "Offscreen UI resizing to " << _newSize.width() << "x" << _newSize.height() << " with pixel ratio " << pixelRatio;
|
||||
setupFbo();
|
||||
doneCurrent();
|
||||
}
|
||||
|
@ -237,54 +222,44 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
//Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _size);
|
||||
//Q_ASSERT(toGlm(_quickWindow->geometry().size()) == _textures._size);
|
||||
|
||||
_renderControl->sync();
|
||||
#ifdef QML_THREADED
|
||||
_cond.wakeOne();
|
||||
lock->unlock();
|
||||
#endif
|
||||
|
||||
|
||||
using namespace oglplus;
|
||||
|
||||
_quickWindow->setRenderTarget(GetName(*_fbo), QSize(_size.x, _size.y));
|
||||
|
||||
TexturePtr texture = _textures.getNextTexture();
|
||||
_fbo->Bind(Framebuffer::Target::Draw);
|
||||
_fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0);
|
||||
_fbo->Complete(Framebuffer::Target::Draw);
|
||||
//Context::Clear().ColorBuffer();
|
||||
{
|
||||
_renderControl->render();
|
||||
// FIXME The web browsers seem to be leaving GL in an error state.
|
||||
// Need a debug context with sync logging to figure out why.
|
||||
// for now just clear the errors
|
||||
glGetError();
|
||||
PROFILE_RANGE("qml_render")
|
||||
TexturePtr texture = _textures.getNextTexture();
|
||||
_fbo->Bind(Framebuffer::Target::Draw);
|
||||
_fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0);
|
||||
_fbo->Complete(Framebuffer::Target::Draw);
|
||||
{
|
||||
_renderControl->render();
|
||||
// FIXME The web browsers seem to be leaving GL in an error state.
|
||||
// Need a debug context with sync logging to figure out why.
|
||||
// for now just clear the errors
|
||||
glGetError();
|
||||
}
|
||||
// FIXME probably unecessary
|
||||
DefaultFramebuffer().Bind(Framebuffer::Target::Draw);
|
||||
_quickWindow->resetOpenGLState();
|
||||
_escrow.submit(GetName(*texture));
|
||||
}
|
||||
// FIXME probably unecessary
|
||||
DefaultFramebuffer().Bind(Framebuffer::Target::Draw);
|
||||
_quickWindow->resetOpenGLState();
|
||||
_escrow.submit(GetName(*texture));
|
||||
_lastRenderTime = usecTimestampNow();
|
||||
}
|
||||
|
||||
void aboutToQuit() {
|
||||
#ifdef QML_THREADED
|
||||
QMutexLocker lock(&_quitMutex);
|
||||
_quit = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void stop() {
|
||||
#ifdef QML_THREADED
|
||||
QMutexLocker lock(&_quitMutex);
|
||||
QMutexLocker lock(&_mutex);
|
||||
post(STOP);
|
||||
_cond.wait(&_mutex);
|
||||
#else
|
||||
cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool allowNewFrame(uint8_t fps) {
|
||||
|
@ -297,13 +272,12 @@ private:
|
|||
QQuickWindow* _quickWindow{ nullptr };
|
||||
QMyQuickRenderControl* _renderControl{ nullptr };
|
||||
|
||||
#ifdef QML_THREADED
|
||||
QThread _thread;
|
||||
QMutex _mutex;
|
||||
QWaitCondition _cond;
|
||||
QMutex _quitMutex;
|
||||
#endif
|
||||
|
||||
QSize _newSize;
|
||||
bool _quit;
|
||||
FramebufferPtr _fbo;
|
||||
RenderbufferPtr _depthStencil;
|
||||
|
@ -346,9 +320,7 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
}
|
||||
|
||||
void OffscreenQmlSurface::resize(const QSize& newSize) {
|
||||
#ifdef QML_THREADED
|
||||
QMutexLocker _locker(&(_renderer->_mutex));
|
||||
#endif
|
||||
|
||||
if (!_renderer || !_renderer->_quickWindow) {
|
||||
QSize currentSize = _renderer->_quickWindow->geometry().size();
|
||||
if (newSize == currentSize) {
|
||||
|
@ -362,11 +334,12 @@ void OffscreenQmlSurface::resize(const QSize& newSize) {
|
|||
_rootItem->setSize(newSize);
|
||||
}
|
||||
|
||||
#ifdef QML_THREADED
|
||||
{
|
||||
QMutexLocker _locker(&(_renderer->_mutex));
|
||||
_renderer->_newSize = newSize;
|
||||
}
|
||||
|
||||
_renderer->post(RESIZE);
|
||||
#else
|
||||
_renderer->resize(newSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
QQuickItem* OffscreenQmlSurface::getRootItem() {
|
||||
|
@ -466,11 +439,7 @@ void OffscreenQmlSurface::updateQuick() {
|
|||
}
|
||||
|
||||
if (_render) {
|
||||
#ifdef QML_THREADED
|
||||
_renderer->post(RENDER);
|
||||
#else
|
||||
_renderer->render(nullptr);
|
||||
#endif
|
||||
_render = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,13 +16,6 @@
|
|||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
|
||||
ProfileRange::ProfileRange(const char *name) {
|
||||
nvtxRangePush(name);
|
||||
}
|
||||
ProfileRange::~ProfileRange() {
|
||||
nvtxRangePop();
|
||||
}
|
||||
|
||||
ProfileRangeBatch::ProfileRangeBatch(gpu::Batch& batch, const char *name) : _batch(batch) {
|
||||
_batch.pushProfileRange(name);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
||||
#include "Framebuffer.h"
|
||||
#include "Pipeline.h"
|
||||
#include "Query.h"
|
||||
|
@ -22,18 +24,6 @@
|
|||
#include "Texture.h"
|
||||
#include "Transform.h"
|
||||
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
class ProfileRange {
|
||||
public:
|
||||
ProfileRange(const char *name);
|
||||
~ProfileRange();
|
||||
};
|
||||
#define PROFILE_RANGE(name) ProfileRange profileRangeThis(name);
|
||||
#else
|
||||
#define PROFILE_RANGE(name)
|
||||
#endif
|
||||
|
||||
class QDebug;
|
||||
|
||||
namespace gpu {
|
||||
|
|
|
@ -4,3 +4,4 @@ set(TARGET_NAME shared)
|
|||
setup_hifi_library(Gui Network Script Widgets)
|
||||
|
||||
target_zlib()
|
||||
target_nsight()
|
||||
|
|
22
libraries/shared/src/shared/NsightHelpers.cpp
Normal file
22
libraries/shared/src/shared/NsightHelpers.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/12/10
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "NsightHelpers.h"
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
#include "nvToolsExt.h"
|
||||
|
||||
ProfileRange::ProfileRange(const char *name) {
|
||||
nvtxRangePush(name);
|
||||
}
|
||||
|
||||
ProfileRange::~ProfileRange() {
|
||||
nvtxRangePop();
|
||||
}
|
||||
|
||||
#endif
|
24
libraries/shared/src/shared/NsightHelpers.h
Normal file
24
libraries/shared/src/shared/NsightHelpers.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/12/10
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_gl_NsightHelpers_h
|
||||
#define hifi_gl_NsightHelpers_h
|
||||
|
||||
#if defined(NSIGHT_FOUND)
|
||||
class ProfileRange {
|
||||
public:
|
||||
ProfileRange(const char *name);
|
||||
~ProfileRange();
|
||||
};
|
||||
#define PROFILE_RANGE(name) ProfileRange profileRangeThis(name);
|
||||
#else
|
||||
#define PROFILE_RANGE(name)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue