mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 20:06:02 +02:00
Merge pull request #7697 from samcake/orange
Introduce a simple state sort for drawing opaque items
This commit is contained in:
commit
5d550197bd
9 changed files with 155 additions and 12 deletions
|
@ -80,11 +80,6 @@ Item {
|
||||||
label: "GPU",
|
label: "GPU",
|
||||||
color: "#1AC567"
|
color: "#1AC567"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
prop: "frameTextureCount",
|
|
||||||
label: "Frame",
|
|
||||||
color: "#E2334D"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
prop: "textureGPUTransferCount",
|
prop: "textureGPUTransferCount",
|
||||||
label: "Transfer",
|
label: "Transfer",
|
||||||
|
@ -114,13 +109,7 @@ Item {
|
||||||
prop: "textureGPUVirtualMemoryUsage",
|
prop: "textureGPUVirtualMemoryUsage",
|
||||||
label: "GPU Virtual",
|
label: "GPU Virtual",
|
||||||
color: "#9495FF"
|
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 drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred")
|
||||||
property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred")
|
property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred")
|
||||||
property var drawLightConfig: Render.getConfig("DrawLight")
|
property var drawLightConfig: Render.getConfig("DrawLight")
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
int _DSNumAPIDrawcalls = 0;
|
int _DSNumAPIDrawcalls = 0;
|
||||||
int _DSNumDrawcalls = 0;
|
int _DSNumDrawcalls = 0;
|
||||||
int _DSNumTriangles = 0;
|
int _DSNumTriangles = 0;
|
||||||
|
|
||||||
|
int _PSNumSetPipelines = 0;
|
||||||
|
|
||||||
ContextStats() {}
|
ContextStats() {}
|
||||||
ContextStats(const ContextStats& stats) = default;
|
ContextStats(const ContextStats& stats) = default;
|
||||||
|
|
|
@ -64,6 +64,9 @@ void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A true new Pipeline
|
||||||
|
_stats._PSNumSetPipelines++;
|
||||||
|
|
||||||
// null pipeline == reset
|
// null pipeline == reset
|
||||||
if (!pipeline) {
|
if (!pipeline) {
|
||||||
_pipeline._pipeline.reset();
|
_pipeline._pipeline.reset();
|
||||||
|
|
|
@ -96,7 +96,7 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
||||||
addJob<PrepareDeferred>("PrepareDeferred");
|
addJob<PrepareDeferred>("PrepareDeferred");
|
||||||
|
|
||||||
// Render opaque objects in DeferredBuffer
|
// Render opaque objects in DeferredBuffer
|
||||||
addJob<DrawDeferred>("DrawOpaqueDeferred", opaques, shapePlumber);
|
addJob<DrawStateSortDeferred>("DrawOpaqueDeferred", opaques, shapePlumber);
|
||||||
|
|
||||||
// Once opaque is all rendered create stencil background
|
// Once opaque is all rendered create stencil background
|
||||||
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
||||||
|
@ -200,6 +200,38 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
config->setNumDrawn((int)inItems.size());
|
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<Config>(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) :
|
DrawOverlay3D::DrawOverlay3D(bool opaque) :
|
||||||
_shapePlumber(std::make_shared<ShapePlumber>()),
|
_shapePlumber(std::make_shared<ShapePlumber>()),
|
||||||
_opaquePass(opaque) {
|
_opaquePass(opaque) {
|
||||||
|
|
|
@ -72,6 +72,44 @@ protected:
|
||||||
int _maxDrawn; // initialized by Config
|
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::ItemBounds, Config>;
|
||||||
|
|
||||||
|
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 {
|
class DrawStencilDeferred {
|
||||||
public:
|
public:
|
||||||
using JobModel = render::Job::Model<DrawStencilDeferred>;
|
using JobModel = render::Job::Model<DrawStencilDeferred>;
|
||||||
|
|
|
@ -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) {
|
void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inLights) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->_viewFrustum);
|
assert(renderContext->args->_viewFrustum);
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace render {
|
||||||
|
|
||||||
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, int maxDrawnItems = -1);
|
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 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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,5 +49,7 @@ void EngineStats::run(const SceneContextPointer& sceneContext, const RenderConte
|
||||||
config->frameTextureRate = config->frameTextureCount * frequency;
|
config->frameTextureRate = config->frameTextureCount * frequency;
|
||||||
config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded;
|
config->frameTextureMemoryUsage = _gpuStats._RSAmountTextureMemoryBounded - gpuStats._RSAmountTextureMemoryBounded;
|
||||||
|
|
||||||
|
config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines - gpuStats._PSNumSetPipelines;
|
||||||
|
|
||||||
config->emitDirty();
|
config->emitDirty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ namespace render {
|
||||||
Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty)
|
Q_PROPERTY(quint32 frameTextureRate MEMBER frameTextureRate NOTIFY dirty)
|
||||||
Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty)
|
Q_PROPERTY(quint32 frameTextureMemoryUsage MEMBER frameTextureMemoryUsage NOTIFY dirty)
|
||||||
|
|
||||||
|
Q_PROPERTY(quint32 frameSetPipelineCount MEMBER frameSetPipelineCount NOTIFY dirty)
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EngineStatsConfig() : Job::Config(true) {}
|
EngineStatsConfig() : Job::Config(true) {}
|
||||||
|
|
||||||
|
@ -73,6 +76,10 @@ namespace render {
|
||||||
quint32 frameTextureRate{ 0 };
|
quint32 frameTextureRate{ 0 };
|
||||||
qint64 frameTextureMemoryUsage{ 0 };
|
qint64 frameTextureMemoryUsage{ 0 };
|
||||||
|
|
||||||
|
quint32 frameSetPipelineCount{ 0 };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void emitDirty() { emit dirty(); }
|
void emitDirty() { emit dirty(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
Loading…
Reference in a new issue