diff options
Diffstat (limited to 'src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h')
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h | 251 |
1 files changed, 228 insertions, 23 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 12b48c1451..8564492b76 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,10 +631,19 @@ 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; + QVector<QRhiGraphicsShaderStage> shaderStages; + } programRhi; float lastOpacity; }; @@ -588,12 +654,16 @@ public: qDeleteAll(stockShaders); } + void clearCachedRendererData(); + + QRhiShaderResourceBindings *srb(const QVector<QRhiShaderResourceBinding> &bindings); + public Q_SLOTS: void invalidated(); public: - Shader *prepareMaterial(QSGMaterial *material); - Shader *prepareMaterialNoRewrite(QSGMaterial *material); + Shader *prepareMaterial(QSGMaterial *material, bool enableRhiShaders = false, const QSGGeometry *geometry = nullptr); + Shader *prepareMaterialNoRewrite(QSGMaterial *material, bool enableRhiShaders = false, const QSGGeometry *geometry = nullptr); QOpenGLShaderProgram *visualizeProgram; @@ -603,6 +673,49 @@ private: QOpenGLShaderProgram *blitProgram; QSGDefaultRenderContext *context; + + QHash<QVector<QRhiShaderResourceBinding>, QRhiShaderResourceBindings *> srbCache; +}; + +struct GraphicsState +{ + 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; +}; + +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 Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer, public QOpenGLFunctions @@ -625,14 +738,6 @@ protected: void releaseCachedResources() override; private: - enum ClipTypeBit - { - NoClip = 0x00, - ScissorClip = 0x01, - StencilClip = 0x02 - }; - Q_DECLARE_FLAGS(ClipType, ClipTypeBit) - enum RebuildFlag { BuildRenderListsForTaggedRoots = 0x0001, BuildRenderLists = 0x0002, @@ -642,6 +747,7 @@ private: friend class Updater; + void destroyGraphicsResources(); void map(Buffer *buffer, int size, bool isIndexBuf = false); void unmap(Buffer *buffer, bool isIndexBuf = false); @@ -658,16 +764,38 @@ 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, const QSGMaterialRhiShader::RenderState &renderState, + QSGMaterial *material, QVector<QRhiShaderResourceBinding> *bindings, + const Batch *batch, int ubufOffset, int ubufRegionSize); + void updateMaterialStaticData(ShaderManager::Shader *sms, const QSGMaterialRhiShader::RenderState &renderState, + QSGMaterial *material, Batch *batch, bool *gstateChanged); + 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); 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); @@ -723,17 +851,21 @@ private: int m_batchVertexThreshold; // 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; @@ -745,6 +877,28 @@ private: 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 +907,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 |