From 0531f90675404a4456fb98da5931fa068fb0b43b Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 18 Apr 2016 00:22:05 -0700 Subject: [PATCH] Adding state sorting for free --- .../render-utils/src/MeshPartPayload.cpp | 4 +- .../render-utils/src/RenderDeferredTask.cpp | 37 +++++++++++++- .../render-utils/src/RenderDeferredTask.h | 18 +++++++ libraries/render/src/render/DrawTask.cpp | 51 +++++++++++++++++++ libraries/render/src/render/DrawTask.h | 1 + 5 files changed, 107 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index b85bd94798..a273d92112 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -246,8 +246,8 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat // Texcoord transforms ? if (locations->texcoordMatrices >= 0) { - //batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); - batch._glUniformMatrix4fv(locations->texcoordMatrices, (materialKey.isLightmapMap() ? 2 : 1), false, (const float*)&texcoordTransform); + batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform); + // batch._glUniformMatrix4fv(locations->texcoordMatrices, (materialKey.isLightmapMap() ? 2 : 1), false, (const float*)&texcoordTransform); } } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index f725d9149c..0924c8ed28 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"); @@ -170,7 +170,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend for (auto job : _jobs) { job.run(sceneContext, renderContext); } -}; +} void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems) { assert(renderContext->args); @@ -200,6 +200,39 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont config->setNumDrawn((int)inItems.size()); } + +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 cb0ba1b58c..a0e0004388 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -41,6 +41,7 @@ class DrawConfig : 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: @@ -48,6 +49,7 @@ public: void setNumDrawn(int num) { _numDrawn = num; emit numDrawnChanged(); } int maxDrawn{ -1 }; + bool stateSort{ true }; signals: void numDrawnChanged(); @@ -72,6 +74,22 @@ protected: int _maxDrawn; // initialized by Config }; +class DrawStateSortDeferred { +public: + using Config = DrawConfig; + 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..259dc037dd 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);