From 88c58cc276ee953a90b7ac8f45d8e5803932205e Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Apr 2016 10:51:31 -0700 Subject: [PATCH 1/4] Adding the simple state sort to draw opaque deferred --- .../render-utils/src/RenderDeferredTask.cpp | 34 ++++++++++++- .../render-utils/src/RenderDeferredTask.h | 38 ++++++++++++++ libraries/render/src/render/DrawTask.cpp | 51 +++++++++++++++++++ libraries/render/src/render/DrawTask.h | 1 + 4 files changed, 123 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index ba5b2a59d5..a391b5cde6 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -96,7 +96,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("PrepareDeferred"); // Render opaque objects in DeferredBuffer - addJob("DrawOpaqueDeferred", opaques, shapePlumber); + addJob("DrawOpaqueDeferred", opaques, shapePlumber); // Once opaque is all rendered create stencil background addJob("DrawOpaqueStencil"); @@ -201,6 +201,38 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont }); } +void DrawStateSortDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems) { + assert(renderContext->args); + assert(renderContext->args->_viewFrustum); + + auto config = std::static_pointer_cast(renderContext->jobConfig); + + RenderArgs* args = renderContext->args; + + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->_viewFrustum->evalProjectionMatrix(projMat); + args->_viewFrustum->evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setViewTransform(viewMat); + + if (_stateSort) { + renderStateSortShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + } else { + renderShapes(sceneContext, renderContext, _shapePlumber, inItems, _maxDrawn); + } + args->_batch = nullptr; + }); + + config->setNumDrawn((int)inItems.size()); +} + DrawOverlay3D::DrawOverlay3D(bool opaque) : _shapePlumber(std::make_shared()), _opaquePass(opaque) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 9fb6802992..9ca1a37e52 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -72,6 +72,44 @@ protected: int _maxDrawn; // initialized by Config }; +class DrawStateSortConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(int numDrawn READ getNumDrawn NOTIFY numDrawnChanged) + Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) + Q_PROPERTY(bool stateSort MEMBER stateSort NOTIFY dirty) +public: + + int getNumDrawn() { return numDrawn; } + void setNumDrawn(int num) { numDrawn = num; emit numDrawnChanged(); } + + int maxDrawn{ -1 }; + bool stateSort{ true }; + +signals: + void numDrawnChanged(); + void dirty(); + +protected: + int numDrawn{ 0 }; +}; + +class DrawStateSortDeferred { +public: + using Config = DrawStateSortConfig; + using JobModel = render::Job::ModelI; + + DrawStateSortDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {} + + void configure(const Config& config) { _maxDrawn = config.maxDrawn; _stateSort = config.stateSort; } + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemBounds& inItems); + +protected: + render::ShapePlumberPointer _shapePlumber; + int _maxDrawn; // initialized by Config + bool _stateSort; +}; + + class DrawStencilDeferred { public: using JobModel = render::Job::Model; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 08ff97fd17..3ddda9d5d0 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -65,6 +65,57 @@ void render::renderShapes(const SceneContextPointer& sceneContext, const RenderC } } +void render::renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, + const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems) { + auto& scene = sceneContext->_scene; + RenderArgs* args = renderContext->args; + + int numItemsToDraw = (int)inItems.size(); + if (maxDrawnItems != -1) { + numItemsToDraw = glm::min(numItemsToDraw, maxDrawnItems); + } + + using SortedPipelines = std::vector< render::ShapeKey >; + using SortedShapes = std::unordered_map< render::ShapeKey, std::vector< Item >, render::ShapeKey::Hash, render::ShapeKey::KeyEqual >; + SortedPipelines sortedPipelines; + SortedShapes sortedShapes; + std::vector< Item > ownPipelineBucket; + + + for (auto i = 0; i < numItemsToDraw; ++i) { + auto item = scene->getItem(inItems[i].id); + + { + assert(item.getKey().isShape()); + const auto& key = item.getShapeKey(); + if (key.isValid() && !key.hasOwnPipeline()) { + auto& bucket = sortedShapes[key]; + if (bucket.empty()) { + sortedPipelines.push_back(key); + } + bucket.push_back(item); + } else if (key.hasOwnPipeline()) { + ownPipelineBucket.push_back(item); + } else { + qDebug() << "Item could not be rendered: invalid key ?" << key; + } + } + } + + // THen render + for (auto& pipelineKey : sortedPipelines) { + auto& bucket = sortedShapes[pipelineKey]; + args->_pipeline = shapeContext->pickPipeline(args, pipelineKey); + for (auto& item : bucket) { + item.render(args); + } + } + args->_pipeline = nullptr; + for (auto& item : ownPipelineBucket) { + item.render(args); + } +} + void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inLights) { assert(renderContext->args); assert(renderContext->args->_viewFrustum); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 8a0f951028..aa564980c4 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -18,6 +18,7 @@ namespace render { void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1); void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); +void renderStateSortShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemBounds& inItems, int maxDrawnItems = -1); From d746fba142d271aed425c61a5b9ac98a82363fe9 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Apr 2016 11:18:28 -0700 Subject: [PATCH 2/4] Cleaning up the stats.qml --- examples/utilities/render/stats.qml | 29 +++++++++++++-------- libraries/gpu/src/gpu/Context.h | 2 ++ libraries/gpu/src/gpu/GLBackendPipeline.cpp | 3 +++ libraries/render/src/render/EngineStats.cpp | 2 ++ libraries/render/src/render/EngineStats.h | 7 +++++ 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/examples/utilities/render/stats.qml b/examples/utilities/render/stats.qml index e6cd03b3c3..72df7db91c 100644 --- a/examples/utilities/render/stats.qml +++ b/examples/utilities/render/stats.qml @@ -80,11 +80,6 @@ Item { label: "GPU", color: "#1AC567" }, - { - prop: "frameTextureCount", - label: "Frame", - color: "#E2334D" - }, { prop: "textureGPUTransferCount", label: "Transfer", @@ -114,13 +109,7 @@ Item { prop: "textureGPUVirtualMemoryUsage", label: "GPU Virtual", color: "#9495FF" - }, - { - prop: "frameTextureMemoryUsage", - label: "Frame", - color: "#E2334D" } - ] } @@ -170,6 +159,24 @@ Item { ] } + PlotPerf { + title: "State Changes" + height: parent.evalEvenHeight() + object: stats.config + plots: [ + { + prop: "frameTextureCount", + label: "Textures", + color: "#00B4EF" + }, + { + prop: "frameSetPipelineCount", + label: "Pipelines", + color: "#E2334D" + } + ] + } + property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred") property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred") property var drawLightConfig: Render.getConfig("DrawLight") diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 869db97be7..5325d600f4 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -39,6 +39,8 @@ public: int _DSNumAPIDrawcalls = 0; int _DSNumDrawcalls = 0; int _DSNumTriangles = 0; + + int _PSNumSetPipelines = 0; ContextStats() {} ContextStats(const ContextStats& stats) = default; diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 60ec478a8e..36554f0c3f 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -64,6 +64,9 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) { return; } + // A true new Pipeline + _stats._PSNumSetPipelines++; + // null pipeline == reset if (!pipeline) { _pipeline._pipeline.reset(); diff --git a/libraries/render/src/render/EngineStats.cpp b/libraries/render/src/render/EngineStats.cpp index 4b0936d326..a17845134a 100644 --- a/libraries/render/src/render/EngineStats.cpp +++ b/libraries/render/src/render/EngineStats.cpp @@ -49,5 +49,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte config->frameTextureRate = config->frameTextureCount * frequency; config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded; + config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines - gpuStats._PSNumSetPipelines; + config->emitDirty(); } diff --git a/libraries/render/src/render/EngineStats.h b/libraries/render/src/render/EngineStats.h index ab58d2af38..e777e60a4e 100644 --- a/libraries/render/src/render/EngineStats.h +++ b/libraries/render/src/render/EngineStats.h @@ -47,6 +47,9 @@ namespace render { Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty) Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty) + Q_PROPERTY(quint32 frameSetPipelineCount MEMBER frameSetPipelineCount NOTIFY dirty) + + public: EngineStatsConfig() : Job::Config(true) {} @@ -73,6 +76,10 @@ namespace render { quint32 frameTextureRate{ 0 }; qint64 frameTextureMemoryUsage{ 0 }; + quint32 frameSetPipelineCount{ 0 }; + + + void emitDirty() { emit dirty(); } signals: From 0ae54b9abc9d894d01c6501460231f94db249c3b Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Apr 2016 11:45:48 -0700 Subject: [PATCH 3/4] Typo --- libraries/render/src/render/DrawTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 3ddda9d5d0..0ed9480186 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -102,7 +102,7 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons } } - // THen render + // Then render for (auto& pipelineKey : sortedPipelines) { auto& bucket = sortedShapes[pipelineKey]; args->_pipeline = shapeContext->pickPipeline(args, pipelineKey); From 9087de22bd2a52d462ca0e22677233281385a5ef Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Apr 2016 16:10:11 -0700 Subject: [PATCH 4/4] Fixing the extra spaces --- libraries/render/src/render/DrawTask.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 0ed9480186..34dfe53e34 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -75,11 +75,11 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons numItemsToDraw = glm::min(numItemsToDraw, maxDrawnItems); } - using SortedPipelines = std::vector< render::ShapeKey >; - using SortedShapes = std::unordered_map< render::ShapeKey, std::vector< Item >, render::ShapeKey::Hash, render::ShapeKey::KeyEqual >; + using SortedPipelines = std::vector; + using SortedShapes = std::unordered_map, render::ShapeKey::Hash, render::ShapeKey::KeyEqual>; SortedPipelines sortedPipelines; SortedShapes sortedShapes; - std::vector< Item > ownPipelineBucket; + std::vector ownPipelineBucket; for (auto i = 0; i < numItemsToDraw; ++i) {