Refactor the rendernode example

By removing the Renderer abstraction it becomes easier to follow and
understand.

Change-Id: Iddacb461d51a75864983850660c5480985b3524f
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2016-05-26 14:34:00 +02:00
parent 519032e9e0
commit e1682b84bb
6 changed files with 96 additions and 114 deletions

View File

@ -45,51 +45,6 @@
#include "openglrenderer.h" #include "openglrenderer.h"
#include "d3d12renderer.h" #include "d3d12renderer.h"
CustomRenderNode::~CustomRenderNode()
{
releaseResources();
}
void CustomRenderNode::render(const RenderState *state)
{
QSGRendererInterface *ri = m_item->window()->rendererInterface();
if (!ri)
return;
if (!m_renderer) {
switch (ri->graphicsAPI()) {
case QSGRendererInterface::OpenGL:
#ifndef QT_NO_OPENGL
m_renderer = new OpenGLRenderer(m_item, this);
#endif
break;
case QSGRendererInterface::Direct3D12:
#ifdef HAS_D3D12
m_renderer = new D3D12Renderer(m_item, this);
#endif
break;
default:
break;
}
Q_ASSERT(m_renderer);
m_renderer->init();
}
m_renderer->render(state);
}
// No need to reimplement changedStates() since our rendering is so simple,
// without involving any state changes.
void CustomRenderNode::releaseResources()
{
if (!m_renderer)
return;
delete m_renderer;
m_renderer = nullptr;
}
CustomRenderItem::CustomRenderItem(QQuickItem *parent) CustomRenderItem::CustomRenderItem(QQuickItem *parent)
: QQuickItem(parent) : QQuickItem(parent)
{ {
@ -99,9 +54,26 @@ CustomRenderItem::CustomRenderItem(QQuickItem *parent)
QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) QSGNode *CustomRenderItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
{ {
CustomRenderNode *n = static_cast<CustomRenderNode *>(node); QSGRenderNode *n = static_cast<QSGRenderNode *>(node);
if (!node) if (!n) {
n = new CustomRenderNode(this); QSGRendererInterface *ri = window()->rendererInterface();
if (!ri)
return nullptr;
switch (ri->graphicsAPI()) {
case QSGRendererInterface::OpenGL:
#ifndef QT_NO_OPENGL
n = new OpenGLRenderNode(this);
break;
#endif
case QSGRendererInterface::Direct3D12:
#ifdef HAS_D3D12
n = new D3D12RenderNode(this);
break;
#endif
default:
return nullptr;
}
}
return n; return n;
} }

View File

@ -42,29 +42,6 @@
#define CUSTOMRENDERITEM_H #define CUSTOMRENDERITEM_H
#include <QQuickItem> #include <QQuickItem>
#include <QSGRenderNode>
class CustomRenderer
{
public:
virtual ~CustomRenderer() { }
virtual void init() = 0;
virtual void render(const QSGRenderNode::RenderState *state) = 0;
};
class CustomRenderNode : public QSGRenderNode
{
public:
CustomRenderNode(QQuickItem *item) : m_item(item) { }
~CustomRenderNode();
void render(const RenderState *state) override;
void releaseResources() override;
private:
QQuickItem *m_item;
CustomRenderer *m_renderer = nullptr;
};
class CustomRenderItem : public QQuickItem class CustomRenderItem : public QQuickItem
{ {

View File

@ -39,6 +39,7 @@
****************************************************************************/ ****************************************************************************/
#include "d3d12renderer.h" #include "d3d12renderer.h"
#include <QQuickItem>
#include <QQuickWindow> #include <QQuickWindow>
#include <QSGRendererInterface> #include <QSGRendererInterface>
@ -47,15 +48,34 @@
#include "vs_shader.hlslh" #include "vs_shader.hlslh"
#include "ps_shader.hlslh" #include "ps_shader.hlslh"
D3D12Renderer::D3D12Renderer(QQuickItem *item, QSGRenderNode *node) D3D12RenderNode::D3D12RenderNode(QQuickItem *item)
: m_item(item), : m_item(item)
m_node(node),
vbPtr(nullptr),
cbPtr(nullptr)
{ {
} }
void D3D12Renderer::init() D3D12RenderNode::~D3D12RenderNode()
{
releaseResources();
}
void D3D12RenderNode::releaseResources()
{
if (vbPtr) {
vertexBuffer->Unmap(0, nullptr);
vbPtr = nullptr;
}
if (cbPtr) {
constantBuffer->Unmap(0, nullptr);
cbPtr = nullptr;
}
constantBuffer = nullptr;
vertexBuffer = nullptr;
rootSignature = nullptr;
pipelineState = nullptr;
m_device = nullptr;
}
void D3D12RenderNode::init()
{ {
QSGRendererInterface *rif = m_item->window()->rendererInterface(); QSGRendererInterface *rif = m_item->window()->rendererInterface();
m_device = static_cast<ID3D12Device *>(rif->getResource(QSGRendererInterface::Device)); m_device = static_cast<ID3D12Device *>(rif->getResource(QSGRendererInterface::Device));
@ -180,22 +200,17 @@ void D3D12Renderer::init()
} }
} }
D3D12Renderer::~D3D12Renderer() void D3D12RenderNode::render(const RenderState *state)
{ {
if (vbPtr) if (!m_device)
vertexBuffer->Unmap(0, nullptr); init();
if (cbPtr)
constantBuffer->Unmap(0, nullptr);
}
void D3D12Renderer::render(const QSGRenderNode::RenderState *state)
{
QSGRendererInterface *rif = m_item->window()->rendererInterface(); QSGRendererInterface *rif = m_item->window()->rendererInterface();
ID3D12GraphicsCommandList *commandList = static_cast<ID3D12GraphicsCommandList *>(rif->getResource(QSGRendererInterface::CommandList)); ID3D12GraphicsCommandList *commandList = static_cast<ID3D12GraphicsCommandList *>(rif->getResource(QSGRendererInterface::CommandList));
Q_ASSERT(commandList); Q_ASSERT(commandList);
const int msize = 16 * sizeof(float); const int msize = 16 * sizeof(float);
memcpy(cbPtr, m_node->matrix()->constData(), msize); memcpy(cbPtr, matrix()->constData(), msize);
memcpy(cbPtr + msize, state->projectionMatrix()->constData(), msize); memcpy(cbPtr + msize, state->projectionMatrix()->constData(), msize);
const QPointF p0(m_item->width() - 1, m_item->height() - 1); const QPointF p0(m_item->width() - 1, m_item->height() - 1);

View File

@ -41,35 +41,38 @@
#ifndef D3D12RENDERER_H #ifndef D3D12RENDERER_H
#define D3D12RENDERER_H #define D3D12RENDERER_H
#include "customrenderitem.h"
#include <qsgrendernode.h> #include <qsgrendernode.h>
#ifdef HAS_D3D12 #ifdef HAS_D3D12
class QQuickItem;
#include <d3d12.h> #include <d3d12.h>
#include <wrl/client.h> #include <wrl/client.h>
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
class D3D12Renderer : public CustomRenderer class D3D12RenderNode : public QSGRenderNode
{ {
public: public:
D3D12Renderer(QQuickItem *item, QSGRenderNode *node); D3D12RenderNode(QQuickItem *item);
~D3D12Renderer(); ~D3D12RenderNode();
void init() override;
void render(const QSGRenderNode::RenderState *state) override; void render(const RenderState *state) override;
void releaseResources() override;
private: private:
void init();
QQuickItem *m_item; QQuickItem *m_item;
QSGRenderNode *m_node; ID3D12Device *m_device = nullptr;
ID3D12Device *m_device;
ComPtr<ID3D12PipelineState> pipelineState; ComPtr<ID3D12PipelineState> pipelineState;
ComPtr<ID3D12RootSignature> rootSignature; ComPtr<ID3D12RootSignature> rootSignature;
ComPtr<ID3D12Resource> vertexBuffer; ComPtr<ID3D12Resource> vertexBuffer;
ComPtr<ID3D12Resource> constantBuffer; ComPtr<ID3D12Resource> constantBuffer;
D3D12_VERTEX_BUFFER_VIEW vertexBufferView; D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
quint8 *vbPtr; quint8 *vbPtr = nullptr;
quint8 *cbPtr; quint8 *cbPtr = nullptr;
}; };
#endif // HAS_D3D12 #endif // HAS_D3D12

View File

@ -39,6 +39,7 @@
****************************************************************************/ ****************************************************************************/
#include "openglrenderer.h" #include "openglrenderer.h"
#include <QQuickItem>
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
@ -46,13 +47,28 @@
#include <QOpenGLBuffer> #include <QOpenGLBuffer>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
OpenGLRenderer::OpenGLRenderer(QQuickItem *item, QSGRenderNode *node) OpenGLRenderNode::OpenGLRenderNode(QQuickItem *item)
: m_item(item), : m_item(item)
m_node(node)
{ {
} }
void OpenGLRenderer::init() OpenGLRenderNode::~OpenGLRenderNode()
{
releaseResources();
}
// No need to reimplement changedStates() since our rendering is so simple,
// without involving any state changes.
void OpenGLRenderNode::releaseResources()
{
delete m_program;
m_program = nullptr;
delete m_vbo;
m_vbo = nullptr;
}
void OpenGLRenderNode::init()
{ {
m_program = new QOpenGLShaderProgram; m_program = new QOpenGLShaderProgram;
@ -98,18 +114,15 @@ void OpenGLRenderer::init()
m_vbo->release(); m_vbo->release();
} }
OpenGLRenderer::~OpenGLRenderer() void OpenGLRenderNode::render(const RenderState *state)
{ {
delete m_program; if (!m_program)
delete m_vbo; init();
}
void OpenGLRenderer::render(const QSGRenderNode::RenderState *state)
{
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
m_program->bind(); m_program->bind();
m_program->setUniformValue(m_matrixUniform, *state->projectionMatrix() * *m_node->matrix()); m_program->setUniformValue(m_matrixUniform, *state->projectionMatrix() * *matrix());
m_vbo->bind(); m_vbo->bind();

View File

@ -41,25 +41,27 @@
#ifndef OPENGLRENDERER_H #ifndef OPENGLRENDERER_H
#define OPENGLRENDERER_H #define OPENGLRENDERER_H
#include "customrenderitem.h"
#include <qsgrendernode.h> #include <qsgrendernode.h>
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
class QQuickItem;
class QOpenGLShaderProgram; class QOpenGLShaderProgram;
class QOpenGLBuffer; class QOpenGLBuffer;
class OpenGLRenderer : public CustomRenderer class OpenGLRenderNode : public QSGRenderNode
{ {
public: public:
OpenGLRenderer(QQuickItem *item, QSGRenderNode *node); OpenGLRenderNode(QQuickItem *item);
~OpenGLRenderer(); ~OpenGLRenderNode();
void init() override;
void render(const QSGRenderNode::RenderState *state) override; void render(const RenderState *state) override;
void releaseResources() override;
private: private:
void init();
QQuickItem *m_item; QQuickItem *m_item;
QSGRenderNode *m_node;
QOpenGLShaderProgram *m_program = nullptr; QOpenGLShaderProgram *m_program = nullptr;
int m_matrixUniform; int m_matrixUniform;
QOpenGLBuffer *m_vbo = nullptr; QOpenGLBuffer *m_vbo = nullptr;