diff options
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h')
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 306 |
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 |