Skip to content

Commit

Permalink
#5909: Accumulate non-alphatested surfaces without transformation mat…
Browse files Browse the repository at this point in the history
…rix across all lights, to perform one large depth draw call
  • Loading branch information
codereader committed Mar 18, 2022
1 parent 86a7e2a commit d34ec8a
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 45 deletions.
27 changes: 6 additions & 21 deletions radiantcore/rendersystem/backend/LightInteractions.cpp
Expand Up @@ -57,15 +57,11 @@ void LightInteractions::collectSurfaces(const std::set<IRenderEntityPtr>& entiti
}
}

void LightInteractions::fillDepthBuffer(OpenGLState& state, GLSLDepthFillAlphaProgram& program, const IRenderView& view, std::size_t renderTime)
void LightInteractions::fillDepthBuffer(OpenGLState& state, GLSLDepthFillAlphaProgram& program,
const IRenderView& view, std::size_t renderTime, std::vector<IGeometryStore::Slot>& untransformedObjectsWithoutAlphaTest)
{
std::vector<IGeometryStore::Slot> untransformedObjects;
std::vector<IGeometryStore::Slot> untransformedObjectsWithoutAlphaTest;
untransformedObjects.reserve(1000);
untransformedObjectsWithoutAlphaTest.reserve(10000);

// Set the modelview and projection matrix
program.setModelViewProjection(view.GetViewProjection());

for (const auto& [entity, objectsByShader] : _objectsByEntity)
{
Expand Down Expand Up @@ -128,7 +124,7 @@ void LightInteractions::fillDepthBuffer(OpenGLState& state, GLSLDepthFillAlphaPr
program.setObjectTransform(object.get().getObjectTransform());

ObjectRenderer::SubmitGeometry(object.get().getStorageLocation(), GL_TRIANGLES, _store);
++_drawCalls;
++_depthDrawCalls;
}

// All alpha-tested materials without transform need to be submitted now
Expand All @@ -137,23 +133,12 @@ void LightInteractions::fillDepthBuffer(OpenGLState& state, GLSLDepthFillAlphaPr
program.setObjectTransform(Matrix4::getIdentity());

ObjectRenderer::SubmitGeometry(untransformedObjects, GL_TRIANGLES, _store);
++_drawCalls;
++_depthDrawCalls;

untransformedObjects.clear();
}
}
}

// All objects without alpha test or transformation matrix go into one final drawcall
if (!untransformedObjectsWithoutAlphaTest.empty())
{
program.setObjectTransform(Matrix4::getIdentity());

ObjectRenderer::SubmitGeometry(untransformedObjectsWithoutAlphaTest, GL_TRIANGLES, _store);
++_drawCalls;

untransformedObjectsWithoutAlphaTest.clear();
}
}

void LightInteractions::drawInteractions(OpenGLState& state, GLSLBumpProgram& program,
Expand Down Expand Up @@ -227,7 +212,7 @@ void LightInteractions::drawInteractions(OpenGLState& state, GLSLBumpProgram& pr
pass->getProgram().setObjectTransform(object.get().getObjectTransform());

ObjectRenderer::SubmitGeometry(object.get().getStorageLocation(), GL_TRIANGLES, _store);
++_drawCalls;
++_interactionDrawCalls;
}

if (!untransformedObjects.empty())
Expand All @@ -238,7 +223,7 @@ void LightInteractions::drawInteractions(OpenGLState& state, GLSLBumpProgram& pr
pass->getProgram().setObjectTransform(Matrix4::getIdentity());

ObjectRenderer::SubmitGeometry(untransformedObjects, GL_TRIANGLES, _store);
++_drawCalls;
++_interactionDrawCalls;

untransformedObjects.clear();
}
Expand Down
17 changes: 12 additions & 5 deletions radiantcore/rendersystem/backend/LightInteractions.h
Expand Up @@ -39,21 +39,28 @@ class LightInteractions
// object mappings, grouped by entity
std::map<IRenderEntity*, ObjectsByMaterial> _objectsByEntity;

std::size_t _drawCalls;
std::size_t _interactionDrawCalls;
std::size_t _depthDrawCalls;
std::size_t _objectCount;

public:
LightInteractions(RendererLight& light, IGeometryStore& store) :
_light(light),
_store(store),
_lightBounds(light.lightAABB()),
_drawCalls(0),
_interactionDrawCalls(0),
_depthDrawCalls(0),
_objectCount(0)
{}

std::size_t getDrawCalls() const
std::size_t getInteractionDrawCalls() const
{
return _drawCalls;
return _interactionDrawCalls;
}

std::size_t getDepthDrawCalls() const
{
return _depthDrawCalls;
}

std::size_t getObjectCount() const
Expand All @@ -73,7 +80,7 @@ class LightInteractions
void collectSurfaces(const std::set<IRenderEntityPtr>& entities);

void fillDepthBuffer(OpenGLState& state, GLSLDepthFillAlphaProgram& program,
const IRenderView& view, std::size_t renderTime);
const IRenderView& view, std::size_t renderTime, std::vector<IGeometryStore::Slot>& untransformedObjectsWithoutAlphaTest);

void drawInteractions(OpenGLState& state, GLSLBumpProgram& program, const IRenderView& view, std::size_t renderTime);
};
Expand Down
8 changes: 5 additions & 3 deletions radiantcore/rendersystem/backend/LightingModeRenderResult.h
Expand Up @@ -16,12 +16,14 @@ class LightingModeRenderResult :
std::size_t entities = 0;
std::size_t objects = 0;

std::size_t drawCalls = 0;
std::size_t depthDrawCalls = 0;
std::size_t interactionDrawCalls = 0;
std::size_t nonInteractionDrawCalls = 0;

std::string toString() override
{
return fmt::format("Lights: {0} of {1} | Entities: {2} | Objects: {3} | Draws: {4}",
visibleLights, visibleLights + skippedLights, entities, objects, drawCalls);
return fmt::format("Lights: {0}/{1} | Ents: {2} | Objs: {3} | Draws: D={4}|Int={5}|Blend={6}",
visibleLights, visibleLights + skippedLights, entities, objects, depthDrawCalls, interactionDrawCalls, nonInteractionDrawCalls);
}
};

Expand Down
59 changes: 44 additions & 15 deletions radiantcore/rendersystem/backend/LightingModeRenderer.cpp
Expand Up @@ -58,19 +58,7 @@ IRenderResult::Ptr LightingModeRenderer::render(RenderStateFlags globalFlagsMask
// Set the vertex attribute pointers
ObjectRenderer::InitAttributePointers();

// Run the depth fill pass
auto depthFillState = DepthFillPass::GenerateDepthFillState(_programFactory);

// Prepare the current state for depth filling
depthFillState.applyTo(current, globalFlagsMask);

auto depthFillProgram = dynamic_cast<GLSLDepthFillAlphaProgram*>(current.glProgram);
assert(depthFillProgram);

for (auto& interactionList : interactionLists)
{
interactionList.fillDepthBuffer(current, *depthFillProgram, view, time);
}
result->depthDrawCalls += drawDepthFillPass(current, globalFlagsMask, interactionLists, view, time);

// Draw the surfaces per light and material
auto interactionState = InteractionPass::GenerateInteractionState(_programFactory);
Expand All @@ -84,16 +72,57 @@ IRenderResult::Ptr LightingModeRenderer::render(RenderStateFlags globalFlagsMask
for (auto& interactionList : interactionLists)
{
interactionList.drawInteractions(current, *interactionProgram, view, time);
result->drawCalls += interactionList.getDrawCalls();
result->interactionDrawCalls += interactionList.getInteractionDrawCalls();
}

result->drawCalls += drawNonInteractionPasses(current, globalFlagsMask, view, time);
result->nonInteractionDrawCalls += drawNonInteractionPasses(current, globalFlagsMask, view, time);

cleanupState();

return result;
}

std::size_t LightingModeRenderer::drawDepthFillPass(OpenGLState& current, RenderStateFlags globalFlagsMask,
std::vector<LightInteractions>& interactionLists, const IRenderView& view, std::size_t renderTime)
{
std::size_t drawCalls = 0;

// Run the depth fill pass
auto depthFillState = DepthFillPass::GenerateDepthFillState(_programFactory);

// Prepare the current state for depth filling
depthFillState.applyTo(current, globalFlagsMask);

auto depthFillProgram = dynamic_cast<GLSLDepthFillAlphaProgram*>(current.glProgram);
assert(depthFillProgram);

// Set the modelview and projection matrix
depthFillProgram->setModelViewProjection(view.GetViewProjection());

for (auto& interactionList : interactionLists)
{
interactionList.fillDepthBuffer(current, *depthFillProgram, view, renderTime, _untransformedObjectsWithoutAlphaTest);
drawCalls += interactionList.getDepthDrawCalls();
}

// Unbind the diffuse texture
OpenGLState::SetTextureState(current.texture0, 0, GL_TEXTURE0, GL_TEXTURE_2D);

// All objects without alpha test or transformation matrix go into one final drawcall
if (!_untransformedObjectsWithoutAlphaTest.empty())
{
depthFillProgram->setObjectTransform(Matrix4::getIdentity());
depthFillProgram->setAlphaTest(-1);

ObjectRenderer::SubmitGeometry(_untransformedObjectsWithoutAlphaTest, GL_TRIANGLES, _geometryStore);
drawCalls++;

_untransformedObjectsWithoutAlphaTest.clear();
}

return drawCalls;
}

std::size_t LightingModeRenderer::drawNonInteractionPasses(OpenGLState& current, RenderStateFlags globalFlagsMask,
const IRenderView& view, std::size_t time)
{
Expand Down
10 changes: 9 additions & 1 deletion radiantcore/rendersystem/backend/LightingModeRenderer.h
Expand Up @@ -9,6 +9,7 @@ namespace render
{

class GLProgramFactory;
class LightInteractions;

class LightingModeRenderer final :
public SceneRenderer
Expand All @@ -24,6 +25,8 @@ class LightingModeRenderer final :
// The set of registered render entities
const std::set<IRenderEntityPtr>& _entities;

std::vector<IGeometryStore::Slot> _untransformedObjectsWithoutAlphaTest;

public:
LightingModeRenderer(GLProgramFactory& programFactory,
IGeometryStore& store,
Expand All @@ -33,11 +36,16 @@ class LightingModeRenderer final :
_geometryStore(store),
_lights(lights),
_entities(entities)
{}
{
_untransformedObjectsWithoutAlphaTest.reserve(10000);
}

IRenderResult::Ptr render(RenderStateFlags globalFlagsMask, const IRenderView& view, std::size_t time) override;

private:
std::size_t drawDepthFillPass(OpenGLState& current, RenderStateFlags globalFlagsMask,
std::vector<LightInteractions>& interactionLists, const IRenderView& view, std::size_t renderTime);

std::size_t drawNonInteractionPasses(OpenGLState& current, RenderStateFlags globalFlagsMask,
const IRenderView& view, std::size_t time);
};
Expand Down

0 comments on commit d34ec8a

Please sign in to comment.