aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h')
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h306
1 files changed, 265 insertions, 41 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 12b48c1451..297df2232a 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -58,11 +58,14 @@
#include <private/qsgnodeupdater_p.h>
#include <private/qsgrendernode_p.h>
#include <private/qdatabuffer_p.h>
+#include <private/qsgtexture_p.h>
#include <QtCore/QBitArray>
-
+#include <QtCore/QStack>
#include <QtGui/QOpenGLFunctions>
+#include <QtGui/private/qrhi_p.h>
+
QT_BEGIN_NAMESPACE
class QOpenGLVertexArrayObject;
@@ -300,10 +303,11 @@ struct Buffer {
// Data is only valid while preparing the upload. Exception is if we are using the
// broken IBO workaround or we are using a visualization mode.
char *data;
+ QRhiBuffer *buf;
+ uint nonDynamicChangeCount;
};
struct Element {
-
Element()
: boundsComputed(false)
, boundsOutsideFloatRange(false)
@@ -334,6 +338,8 @@ struct Element {
Rect bounds; // in device coordinates
int order = 0;
+ QRhiShaderResourceBindings *srb = nullptr;
+ QRhiGraphicsPipeline *ps = nullptr;
uint boundsComputed : 1;
uint boundsOutsideFloatRange : 1;
@@ -390,6 +396,48 @@ enum BatchCompatibility
BatchIsCompatible
};
+struct ClipState
+{
+ enum ClipTypeBit
+ {
+ NoClip = 0x00,
+ ScissorClip = 0x01,
+ StencilClip = 0x02
+ };
+ Q_DECLARE_FLAGS(ClipType, ClipTypeBit)
+
+ const QSGClipNode *clipList;
+ ClipType type;
+ QRhiScissor scissor;
+ int stencilRef;
+
+ inline void reset();
+};
+
+struct StencilClipState
+{
+ StencilClipState() : drawCalls(1) { }
+
+ bool updateStencilBuffer = false;
+ QRhiShaderResourceBindings *srb = nullptr;
+ QRhiBuffer *vbuf = nullptr;
+ QRhiBuffer *ibuf = nullptr;
+ QRhiBuffer *ubuf = nullptr;
+
+ struct StencilDrawCall {
+ int stencilRef;
+ int vertexCount;
+ int indexCount;
+ QRhiCommandBuffer::IndexFormat indexFormat;
+ quint32 vbufOffset;
+ quint32 ibufOffset;
+ quint32 ubufOffset;
+ };
+ QDataBuffer<StencilDrawCall> drawCalls;
+
+ inline void reset();
+};
+
struct Batch
{
Batch() : drawSets(1) {}
@@ -403,6 +451,7 @@ struct Batch
// pseudo-constructor...
void init() {
+ // Only non-reusable members are reset here. See Renderer::newBatch().
first = nullptr;
root = nullptr;
vertexCount = 0;
@@ -413,6 +462,9 @@ struct Batch
positionAttribute = -1;
uploadedThisFrame = false;
isRenderNode = false;
+ ubufDataValid = false;
+ clipState.reset();
+ blendConstant = QColor();
}
Element *first;
@@ -429,16 +481,21 @@ struct Batch
uint needsUpload : 1;
uint merged : 1;
uint isRenderNode : 1;
+ uint ubufDataValid : 1;
mutable uint uploadedThisFrame : 1; // solely for debugging purposes
Buffer vbo;
Buffer ibo;
+ QRhiBuffer *ubuf;
+ ClipState clipState;
+ StencilClipState stencilClipState;
+ QColor blendConstant;
QDataBuffer<DrawSet> drawSets;
};
-// NOTE: Node is zero-allocated by the Allocator.
+// NOTE: Node is zero-initialized by the Allocator.
struct Node
{
QSGNode *sgNode;
@@ -574,28 +631,41 @@ class ShaderManager : public QObject
Q_OBJECT
public:
struct Shader {
- ~Shader() { delete program; }
- int id_zRange;
- int pos_order;
- QSGMaterialShader *program;
+ ~Shader() {
+ delete programRhi.program;
+ delete programGL.program;
+ }
+ struct {
+ QSGMaterialShader *program = nullptr;
+ int pos_order;
+ } programGL;
+ struct {
+ QSGMaterialRhiShader *program = nullptr;
+ QRhiVertexInputLayout inputLayout;
+ QVarLengthArray<QRhiGraphicsShaderStage, 2> shaderStages;
+ } programRhi;
float lastOpacity;
};
- ShaderManager(QSGDefaultRenderContext *ctx) : visualizeProgram(nullptr), blitProgram(nullptr), context(ctx) { }
+ ShaderManager(QSGDefaultRenderContext *ctx) : blitProgram(nullptr), context(ctx) { }
~ShaderManager() {
qDeleteAll(rewrittenShaders);
qDeleteAll(stockShaders);
}
+ void clearCachedRendererData();
+
+ using ShaderResourceBindingList = QVarLengthArray<QRhiShaderResourceBinding, 8>;
+
+ QRhiShaderResourceBindings *srb(const ShaderResourceBindingList &bindings);
+
public Q_SLOTS:
void invalidated();
public:
- Shader *prepareMaterial(QSGMaterial *material);
- Shader *prepareMaterialNoRewrite(QSGMaterial *material);
-
- QOpenGLShaderProgram *visualizeProgram;
+ Shader *prepareMaterial(QSGMaterial *material, bool enableRhiShaders = false, const QSGGeometry *geometry = nullptr);
+ Shader *prepareMaterialNoRewrite(QSGMaterial *material, bool enableRhiShaders = false, const QSGGeometry *geometry = nullptr);
private:
QHash<QSGMaterialType *, Shader *> rewrittenShaders;
@@ -603,14 +673,55 @@ private:
QOpenGLShaderProgram *blitProgram;
QSGDefaultRenderContext *context;
+
+ QHash<ShaderResourceBindingList, QRhiShaderResourceBindings *> srbCache;
};
-class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer, public QOpenGLFunctions
+struct GraphicsState
{
-public:
- Renderer(QSGDefaultRenderContext *);
- ~Renderer();
+ bool depthTest = false;
+ bool depthWrite = false;
+ QRhiGraphicsPipeline::CompareOp depthFunc = QRhiGraphicsPipeline::Less;
+ bool blending = false;
+ QRhiGraphicsPipeline::BlendFactor srcColor = QRhiGraphicsPipeline::One;
+ QRhiGraphicsPipeline::BlendFactor dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
+ QRhiGraphicsPipeline::ColorMask colorWrite = QRhiGraphicsPipeline::ColorMask(0xF);
+ QRhiGraphicsPipeline::CullMode cullMode = QRhiGraphicsPipeline::None;
+ bool usesScissor = false;
+ bool stencilTest = false;
+ int sampleCount = 1;
+ QSGGeometry::DrawingMode drawMode = QSGGeometry::DrawTriangles;
+ float lineWidth = 1.0f;
+};
+
+bool operator==(const GraphicsState &a, const GraphicsState &b) Q_DECL_NOTHROW;
+bool operator!=(const GraphicsState &a, const GraphicsState &b) Q_DECL_NOTHROW;
+uint qHash(const GraphicsState &s, uint seed = 0) Q_DECL_NOTHROW;
+
+struct GraphicsPipelineStateKey
+{
+ GraphicsState state;
+ const ShaderManager::Shader *sms;
+ const QRhiRenderPassDescriptor *rpDesc;
+ const QRhiShaderResourceBindings *layoutCompatibleSrb;
+};
+
+bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) Q_DECL_NOTHROW;
+bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) Q_DECL_NOTHROW;
+uint qHash(const GraphicsPipelineStateKey &k, uint seed = 0) Q_DECL_NOTHROW;
+
+struct RenderPassState
+{
+ QRhiViewport viewport;
+ QColor clearColor;
+ QRhiDepthStencilClearValue dsClear;
+ bool viewportSet;
+ bool scissorSet;
+};
+class Visualizer
+{
+public:
enum VisualizeMode {
VisualizeNothing,
VisualizeBatches,
@@ -619,20 +730,36 @@ public:
VisualizeOverdraw
};
+ Visualizer(Renderer *renderer);
+ virtual ~Visualizer();
+
+ VisualizeMode mode() const { return m_visualizeMode; }
+ void setMode(VisualizeMode mode) { m_visualizeMode = mode; }
+
+ virtual void visualizeChangesPrepare(Node *n, uint parentChanges = 0);
+ virtual void prepareVisualize() = 0;
+ virtual void visualize() = 0;
+
+ virtual void releaseResources() = 0;
+
+protected:
+ Renderer *m_renderer;
+ VisualizeMode m_visualizeMode;
+ QHash<Node *, uint> m_visualizeChangeSet;
+};
+
+class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer, public QOpenGLFunctions
+{
+public:
+ Renderer(QSGDefaultRenderContext *);
+ ~Renderer();
+
protected:
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override;
void render() override;
void releaseCachedResources() override;
private:
- enum ClipTypeBit
- {
- NoClip = 0x00,
- ScissorClip = 0x01,
- StencilClip = 0x02
- };
- Q_DECLARE_FLAGS(ClipType, ClipTypeBit)
-
enum RebuildFlag {
BuildRenderListsForTaggedRoots = 0x0001,
BuildRenderLists = 0x0002,
@@ -641,7 +768,10 @@ private:
};
friend class Updater;
+ friend class OpenGLVisualizer;
+ friend class RhiVisualizer;
+ void destroyGraphicsResources();
void map(Buffer *buffer, int size, bool isIndexBuf = false);
void unmap(Buffer *buffer, bool isIndexBuf = false);
@@ -658,16 +788,41 @@ private:
void invalidateBatchAndOverlappingRenderOrders(Batch *batch);
void uploadBatch(Batch *b);
- void uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, quint16 *iBase, int *indexCount);
+ void uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, void *iBasePtr, int *indexCount);
+
+ struct PreparedRenderBatch {
+ const Batch *batch;
+ ShaderManager::Shader *sms;
+ };
void renderBatches();
- void renderMergedBatch(const Batch *batch);
- void renderUnmergedBatch(const Batch *batch);
- ClipType updateStencilClip(const QSGClipNode *clip);
+ bool ensurePipelineState(Element *e, const ShaderManager::Shader *sms);
+ QRhiTexture *dummyTexture();
+ void updateMaterialDynamicData(ShaderManager::Shader *sms, QSGMaterialRhiShader::RenderState &renderState,
+ QSGMaterial *material, ShaderManager::ShaderResourceBindingList *bindings,
+ const Batch *batch, int ubufOffset, int ubufRegionSize);
+ void updateMaterialStaticData(ShaderManager::Shader *sms, QSGMaterialRhiShader::RenderState &renderState,
+ QSGMaterial *material, Batch *batch, bool *gstateChanged);
+ void checkLineWidth(QSGGeometry *g);
+ bool prepareRenderMergedBatch(Batch *batch, PreparedRenderBatch *renderBatch);
+ void renderMergedBatch(PreparedRenderBatch *renderBatch);
+ bool prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *renderBatch);
+ void renderUnmergedBatch(PreparedRenderBatch *renderBatch);
+ void setGraphicsPipeline(QRhiCommandBuffer *cb, const Batch *batch, Element *e);
+ void renderMergedBatch(const Batch *batch); // GL
+ void renderUnmergedBatch(const Batch *batch); // GL
+ ClipState::ClipType updateStencilClip(const QSGClipNode *clip);
void updateClip(const QSGClipNode *clipList, const Batch *batch);
+ void applyClipStateToGraphicsState();
+ QRhiGraphicsPipeline *buildStencilPipeline(const Batch *batch, bool firstStencilClipInBatch);
+ void updateClipState(const QSGClipNode *clipList, Batch *batch);
+ void enqueueStencilDraw(const Batch *batch);
const QMatrix4x4 &matrixForRoot(Node *node);
void renderRenderNode(Batch *batch);
+ bool prepareRhiRenderNode(Batch *batch, PreparedRenderBatch *renderBatch);
+ void renderRhiRenderNode(const Batch *batch);
void setActiveShader(QSGMaterialShader *program, ShaderManager::Shader *shader);
+ void setActiveRhiShader(QSGMaterialRhiShader *program, ShaderManager::Shader *shader);
bool changeBatchRoot(Node *node, Node *newRoot);
void registerBatchRoot(Node *childRoot, Node *parentRoot);
@@ -683,15 +838,8 @@ private:
inline Batch *newBatch();
void invalidateAndRecycleBatch(Batch *b);
- void visualize();
- void visualizeBatch(Batch *b);
- void visualizeClipping(QSGNode *node);
- void visualizeChangesPrepare(Node *n, uint parentChanges = 0);
- void visualizeChanges(Node *n);
- void visualizeOverdraw();
- void visualizeOverdraw_helper(Node *node);
- void visualizeDrawGeometry(const QSGGeometry *g);
void setCustomRenderMode(const QByteArray &mode) override;
+ bool hasCustomRenderModeWithContinuousUpdate() const override;
QSGDefaultRenderContext *m_context;
QSet<Node *> m_taggedRoots;
@@ -722,29 +870,54 @@ private:
int m_batchNodeThreshold;
int m_batchVertexThreshold;
+ Visualizer *m_visualizer;
+
// Stuff used during rendering only...
- ShaderManager *m_shaderManager;
+ ShaderManager *m_shaderManager; // per rendercontext, shared
QSGMaterial *m_currentMaterial;
QSGMaterialShader *m_currentProgram;
+ QSGMaterialRhiShader *m_currentRhiProgram;
ShaderManager::Shader *m_currentShader;
+ ClipState m_currentClipState;
+ // *** legacy (GL) only
QRect m_currentScissorRect;
int m_currentStencilValue;
QOpenGLShaderProgram m_clipProgram;
int m_clipMatrixId;
const QSGClipNode *m_currentClip;
- ClipType m_currentClipType;
+ ClipState::ClipType m_currentClipType;
+ // ***
QDataBuffer<char> m_vertexUploadPool;
QDataBuffer<char> m_indexUploadPool;
// For minimal OpenGL core profile support
QOpenGLVertexArrayObject *m_vao;
- QHash<Node *, uint> m_visualizeChanceSet;
- VisualizeMode m_visualizeMode;
-
Allocator<Node, 256> m_nodeAllocator;
Allocator<Element, 64> m_elementAllocator;
+
+ QRhiResourceUpdateBatch *m_resourceUpdates = nullptr;
+ uint m_ubufAlignment;
+ bool m_uint32IndexForRhi;
+ GraphicsState m_gstate;
+ RenderPassState m_pstate;
+ QStack<GraphicsState> m_gstateStack;
+ QHash<GraphicsPipelineStateKey, QRhiGraphicsPipeline *> m_pipelines;
+ QHash<QSGSamplerDescription, QRhiSampler *> m_samplers;
+ QRhiTexture *m_dummyTexture = nullptr;
+
+ struct StencilClipCommonData {
+ QRhiGraphicsPipeline *replacePs = nullptr;
+ QRhiGraphicsPipeline *incrPs = nullptr;
+ QShader vs;
+ QShader fs;
+ QRhiVertexInputLayout inputLayout;
+ QRhiGraphicsPipeline::Topology topology;
+ inline void reset();
+ } m_stencilClipCommon;
+
+ inline int mergedIndexElemSize() const;
};
Batch *Renderer::newBatch()
@@ -753,18 +926,69 @@ Batch *Renderer::newBatch()
int size = m_batchPool.size();
if (size) {
b = m_batchPool.at(size - 1);
+ // vbo, ibo, ubuf, stencil-related buffers are reused
m_batchPool.resize(size - 1);
} else {
b = new Batch();
Q_ASSERT(offsetof(Batch, ibo) == sizeof(Buffer) + offsetof(Batch, vbo));
memset(&b->vbo, 0, sizeof(Buffer) * 2); // Clear VBO & IBO
+ b->ubuf = nullptr;
+ b->stencilClipState.reset();
}
+ // initialize (when new batch) or reset (when reusing a batch) the non-reusable fields
b->init();
return b;
}
+int Renderer::mergedIndexElemSize() const
+{
+ return m_uint32IndexForRhi ? sizeof(quint32) : sizeof(quint16);
+}
+
+void Renderer::StencilClipCommonData::reset()
+{
+ delete replacePs;
+ replacePs = nullptr;
+
+ delete incrPs;
+ incrPs = nullptr;
+
+ vs = QShader();
+ fs = QShader();
+}
+
+void ClipState::reset()
+{
+ clipList = nullptr;
+ type = NoClip;
+ stencilRef = 0;
+}
+
+void StencilClipState::reset()
+{
+ updateStencilBuffer = false;
+
+ delete srb;
+ srb = nullptr;
+
+ delete vbuf;
+ vbuf = nullptr;
+
+ delete ibuf;
+ ibuf = nullptr;
+
+ delete ubuf;
+ ubuf = nullptr;
+
+ drawCalls.reset();
}
+}
+
+Q_DECLARE_TYPEINFO(QSGBatchRenderer::GraphicsState, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QSGBatchRenderer::GraphicsPipelineStateKey, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QSGBatchRenderer::RenderPassState, Q_MOVABLE_TYPE);
+
QT_END_NAMESPACE
#endif // QSGBATCHRENDERER_P_H