Skip to content

Commit

Permalink
Traktor: GPU occlusion culling moved to World module and are culling …
Browse files Browse the repository at this point in the history
…all instances in one pass.
  • Loading branch information
apistol78 committed May 15, 2024
1 parent a824c7b commit 9468e5a
Show file tree
Hide file tree
Showing 24 changed files with 672 additions and 411 deletions.
2 changes: 2 additions & 0 deletions code/Animation/Editor/AnimationPreviewControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "World/WorldEntityRenderers.h"
#include "World/WorldRenderSettings.h"
#include "World/WorldResourceFactory.h"
#include "World/Entity/CullingRenderer.h"
#include "World/Entity/GroupComponent.h"
#include "World/Entity/LightComponent.h"
#include "World/Entity/ProbeRenderer.h"
Expand Down Expand Up @@ -251,6 +252,7 @@ void AnimationPreviewControl::updateWorldRenderer()
Ref< world::WorldEntityRenderers > worldEntityRenderers = new world::WorldEntityRenderers();
worldEntityRenderers->add(new mesh::MeshComponentRenderer());
worldEntityRenderers->add(new weather::SkyRenderer());
worldEntityRenderers->add(new world::CullingRenderer());
worldEntityRenderers->add(new world::VolumetricFogRenderer());
worldEntityRenderers->add(new world::ProbeRenderer(
m_resourceManager,
Expand Down
2 changes: 0 additions & 2 deletions code/Mesh/Editor/MeshEditorProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include "Mesh/MeshResourceFactory.h"
#include "Mesh/Editor/MeshAsset.h"
#include "Mesh/Editor/MeshEditorProfile.h"
#include "Mesh/Instance/InstanceMeshComponentRenderer.h"
#include "Resource/Id.h"
#include "Scene/Editor/SceneEditorContext.h"
#include "Ui/Command.h"
Expand Down Expand Up @@ -69,7 +68,6 @@ void MeshEditorProfile::createEntityRenderers(
) const
{
outEntityRenderers.push_back(new mesh::MeshComponentRenderer());
outEntityRenderers.push_back(new mesh::InstanceMeshComponentRenderer());
}

void MeshEditorProfile::createControllerEditorFactories(
Expand Down
152 changes: 26 additions & 126 deletions code/Mesh/Instance/InstanceMesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "Render/Context/RenderContext.h"
#include "Render/Mesh/Mesh.h"
#include "World/IWorldRenderPass.h"
#include "World/WorldBuildContext.h"
#include "World/WorldHandles.h"
#include "World/WorldRenderView.h"

Expand All @@ -28,25 +29,21 @@ namespace traktor::mesh

render::Handle s_handleInstanceWorld(L"InstanceWorld");
render::Handle s_handleInstanceWorldLast(L"InstanceWorldLast");
render::Handle s_handleTargetSize(L"InstanceMesh_TargetSize");
render::Handle s_handleViewProjection(L"InstanceMesh_ViewProjection");
render::Handle s_handleVisibility(L"InstanceMesh_Visibility");
render::Handle s_handleCullFrustum(L"InstanceMesh_CullFrustum");
render::Handle s_handleDraw(L"InstanceMesh_Draw");
render::Handle s_handleIndexCount(L"InstanceMesh_IndexCount");
render::Handle s_handleFirstIndex(L"InstanceMesh_FirstIndex");
render::Handle s_handleInstanceOffset(L"InstanceMesh_InstanceOffset");

}

T_IMPLEMENT_RTTI_CLASS(L"traktor.mesh.InstanceMesh", InstanceMesh, IMesh)

InstanceMesh::InstanceMesh(
render::IRenderSystem* renderSystem,
const resource::Proxy< render::Shader >& shaderCull,
const resource::Proxy< render::Shader >& shaderDraw
)
: m_renderSystem(renderSystem)
, m_shaderCull(shaderCull)
, m_shaderDraw(shaderDraw)
{
}
Expand All @@ -67,113 +64,40 @@ void InstanceMesh::getTechniques(SmallSet< render::handle_t >& outHandles) const
outHandles.insert(part.first);
}

void InstanceMesh::build(
render::RenderContext* renderContext,
void InstanceMesh::cullableBuild(
const world::WorldBuildContext& context,
const world::WorldRenderView& worldRenderView,
const world::IWorldRenderPass& worldRenderPass,
render::ProgramParameters* extraParameters
render::Buffer* instanceBuffer,
render::Buffer* visibilityBuffer,
uint32_t start,
uint32_t count
)
{
bool haveAlphaBlend = false;

if (m_instances.empty())
return;

const auto it = m_parts.find(worldRenderPass.getTechnique());
if (it == m_parts.end())
return;

render::RenderContext* renderContext = context.getRenderContext();

const AlignedVector< Part >& parts = it->second;
const auto& meshParts = m_renderMesh->getParts();

const uint32_t bufferItemCount = (uint32_t)alignUp(m_instances.size(), 16);

// Lazy create the buffers.
if (!m_instanceBuffer || bufferItemCount > m_instanceAllocatedCount)
if (count > m_allocatedCount)
{
m_instanceBuffer = m_renderSystem->createBuffer(render::BufferUsage::BuStructured, bufferItemCount * sizeof(InstanceMeshData), true);
m_visibilityBuffers.resize(0);
m_drawBuffers.resize(0);
m_instanceAllocatedCount = bufferItemCount;
m_instanceBufferDirty = true;
m_allocatedCount = count;
}

const uint32_t peakCascade = worldRenderView.getCascade();
const uint32_t vbSize = (uint32_t)m_visibilityBuffers.size();
for (uint32_t i = vbSize; i < peakCascade + 1; ++i)
m_visibilityBuffers.push_back(m_renderSystem->createBuffer(render::BufferUsage::BuStructured, bufferItemCount * sizeof(float), false));

const uint32_t peakCascade = worldRenderView.getCascade();
const uint32_t dbSize = (uint32_t)m_drawBuffers.size();
for (uint32_t i = dbSize; i < (peakCascade + 1) * parts.size(); ++i)
m_drawBuffers.push_back(m_renderSystem->createBuffer(render::BufferUsage::BuStructured | render::BufferUsage::BuIndirect, bufferItemCount * sizeof(render::IndexedIndirectDraw), false));

// Update buffer is any instance has moved.
if (m_instanceBufferDirty)
{
auto ptr = (InstanceMeshData*)m_instanceBuffer->lock();
for (const auto& instance : m_instances)
{
*ptr++ = packInstanceMeshData(
instance->transform,
instance->boundingBox
);
}
m_instanceBuffer->unlock();
m_instanceBufferDirty = false;
}

render::Buffer* visibilityBuffer = m_visibilityBuffers[worldRenderView.getCascade()];

// Cull instances.
// #todo Compute blocks are executed before render pass, so for shadow map rendering all cascades
// are culled before being rendered.
{
Vector4 cullFrustum[12];

const Frustum& cf = worldRenderView.getCullFrustum();
T_FATAL_ASSERT(cf.planes.size() <= sizeof_array(cullFrustum));
for (int32_t i = 0; i < (int32_t)cf.planes.size(); ++i)
cullFrustum[i] = cf.planes[i].normal().xyz0() + Vector4(0.0f, 0.0f, 0.0f, cf.planes[i].distance());
for (int32_t i = (int32_t)cf.planes.size(); i < sizeof_array(cullFrustum); ++i)
cullFrustum[i] = Vector4::zero();

const Vector2 viewSize = worldRenderView.getViewSize();

auto renderBlock = renderContext->allocNamed< render::ComputeRenderBlock >(
str(L"InstanceMesh cull %d", worldRenderView.getCascade())
);

render::Shader::Permutation perm;
if (worldRenderPass.getTechnique() == world::s_techniqueDeferredGBufferWrite)
{
// Deferred g-buffer pass has access to HiZ texture.
m_shaderCull->setCombination(render::getParameterHandle(L"InstanceMesh_HiZ"), true, perm);
}
else
{
// All other paths use simple frustum culling only.
m_shaderCull->setCombination(render::getParameterHandle(L"InstanceMesh_HiZ"), false, perm);
}

renderBlock->program = m_shaderCull->getProgram(perm).program;

renderBlock->programParams = renderContext->alloc< render::ProgramParameters >();
renderBlock->programParams->beginParameters(renderContext);

worldRenderPass.setProgramParameters(renderBlock->programParams);

renderBlock->programParams->setVectorParameter(s_handleTargetSize, Vector4(viewSize.x, viewSize.y, 0.0f, 0.0f));
renderBlock->programParams->setMatrixParameter(s_handleViewProjection, worldRenderView.getProjection() * worldRenderView.getView());
renderBlock->programParams->setVectorArrayParameter(s_handleCullFrustum, cullFrustum, sizeof_array(cullFrustum));
renderBlock->programParams->setBufferViewParameter(s_handleInstanceWorld, m_instanceBuffer->getBufferView());
renderBlock->programParams->setBufferViewParameter(s_handleVisibility, visibilityBuffer->getBufferView());
renderBlock->programParams->endParameters(renderContext);

renderBlock->workSize[0] = (int32_t)m_instances.size();

renderContext->compute(renderBlock);
renderContext->compute< render::BarrierRenderBlock >(render::Stage::Compute, render::Stage::Compute, nullptr, 0);
}
m_drawBuffers.push_back(m_renderSystem->createBuffer(
render::BufferUsage::BuStructured | render::BufferUsage::BuIndirect,
count * sizeof(render::IndexedIndirectDraw),
false
));

// Create draw buffers from visibility buffer.
for (uint32_t i = 0; i < parts.size(); ++i)
Expand All @@ -200,11 +124,12 @@ void InstanceMesh::build(
renderBlock->programParams->beginParameters(renderContext);
renderBlock->programParams->setFloatParameter(s_handleIndexCount, primitives.getVertexCount() + 0.5f);
renderBlock->programParams->setFloatParameter(s_handleFirstIndex, primitives.offset + 0.5f);
renderBlock->programParams->setFloatParameter(s_handleInstanceOffset, start + 0.5f);
renderBlock->programParams->setBufferViewParameter(s_handleVisibility, visibilityBuffer->getBufferView());
renderBlock->programParams->setBufferViewParameter(s_handleDraw, drawBuffer->getBufferView());
renderBlock->programParams->endParameters(renderContext);

renderBlock->workSize[0] = (int32_t)m_instances.size();
renderBlock->workSize[0] = (int32_t)count;

renderContext->compute(renderBlock);
}
Expand Down Expand Up @@ -236,12 +161,12 @@ void InstanceMesh::build(
renderBlock->vertexLayout = m_renderMesh->getVertexLayout();
renderBlock->primitive = meshParts[part.meshPart].primitives.type;
renderBlock->drawBuffer = drawBuffer->getBufferView();
renderBlock->drawCount = (uint32_t)m_instances.size();
renderBlock->drawCount = (uint32_t)count;

renderBlock->programParams->beginParameters(renderContext);

if (extraParameters)
renderBlock->programParams->attachParameters(extraParameters);
//if (extraParameters)
// renderBlock->programParams->attachParameters(extraParameters);

worldRenderPass.setProgramParameters(
renderBlock->programParams,
Expand All @@ -250,38 +175,13 @@ void InstanceMesh::build(
);

// #todo Same world buffer
renderBlock->programParams->setBufferViewParameter(s_handleInstanceWorld, m_instanceBuffer->getBufferView());
renderBlock->programParams->setBufferViewParameter(s_handleInstanceWorldLast, m_instanceBuffer->getBufferView());
renderBlock->programParams->setFloatParameter(s_handleInstanceOffset, start + 0.5f);
renderBlock->programParams->setBufferViewParameter(s_handleInstanceWorld, instanceBuffer->getBufferView());
renderBlock->programParams->setBufferViewParameter(s_handleInstanceWorldLast, instanceBuffer->getBufferView());
renderBlock->programParams->endParameters(renderContext);

renderContext->draw(sp.priority, renderBlock);
}
}

InstanceMesh::Instance* InstanceMesh::allocateInstance()
{
Instance* instance = new Instance();
instance->mesh = this;
instance->transform = Transform::identity();
instance->boundingBox = m_renderMesh->getBoundingBox();
m_instances.push_back(instance);
return instance;
}

void InstanceMesh::releaseInstance(Instance*& instance)
{
T_FATAL_ASSERT(instance->mesh == this);
auto it = std::find(m_instances.begin(), m_instances.end(), instance);
m_instances.erase(it);
delete instance;
instance = nullptr;
}

void InstanceMesh::Instance::setTransform(const Transform& transform)
{
this->mesh->m_instanceBufferDirty = true;
this->transform = transform;
this->boundingBox = this->mesh->m_renderMesh->getBoundingBox().transform(transform);
}

}
67 changes: 26 additions & 41 deletions code/Mesh/Instance/InstanceMesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Mesh/IMesh.h"
#include "Render/Shader.h"
#include "Resource/Proxy.h"
#include "World/Entity/CullingComponent.h"

// import/export mechanism.
#undef T_DLLCLASS
Expand All @@ -29,22 +30,22 @@
namespace traktor::render
{

class Buffer;
//class Buffer;
class IRenderSystem;
class ProgramParameters;
class RenderContext;
//class RenderContext;
class Mesh;
class Shader;

}

namespace traktor::world
{

class IWorldRenderPass;
class WorldRenderView;

}
//namespace traktor::world
//{
//
//class IWorldRenderPass;
//class WorldRenderView;
//
//}

namespace traktor::mesh
{
Expand All @@ -56,13 +57,13 @@ namespace traktor::mesh
* automatically by the GPU in any number of instances
* using hardware instancing in a single draw call.
*/
class T_DLLCLASS InstanceMesh : public IMesh
class T_DLLCLASS InstanceMesh
: public IMesh
, public world::CullingComponent::ICullable
{
T_RTTI_CLASS;

public:
enum { MaxInstanceCount = 60 };

struct Part
{
render::handle_t shaderTechnique;
Expand All @@ -71,7 +72,6 @@ class T_DLLCLASS InstanceMesh : public IMesh

explicit InstanceMesh(
render::IRenderSystem* renderSystem,
const resource::Proxy< render::Shader >& shaderCull,
const resource::Proxy< render::Shader >& shaderDraw
);

Expand All @@ -81,29 +81,19 @@ class T_DLLCLASS InstanceMesh : public IMesh

void getTechniques(SmallSet< render::handle_t >& outHandles) const;

void build(
render::RenderContext* renderContext,
const world::WorldRenderView& worldRenderView,
const world::IWorldRenderPass& worldRenderPass,
render::ProgramParameters* extraParameters
);
/* world::CullingComponent::ICullable */

//
virtual const Aabb3& cullableGetBoundingBox() const override final { return getBoundingBox(); }

struct Instance
{
InstanceMesh* mesh;
Transform transform;
Aabb3 boundingBox;

void setTransform(const Transform& transform);
};

Instance* allocateInstance();

void releaseInstance(Instance*& instance);

//
virtual void cullableBuild(
const world::WorldBuildContext& context,
const world::WorldRenderView& worldRenderView,
const world::IWorldRenderPass& worldRenderPass,
render::Buffer* instanceBuffer,
render::Buffer* visibilityBuffer,
uint32_t start,
uint32_t count
) override final;

private:
friend class InstanceMeshResource;
Expand All @@ -113,15 +103,10 @@ class T_DLLCLASS InstanceMesh : public IMesh
SmallMap< render::handle_t, AlignedVector< Part > > m_parts;

//#todo All instances are bookkeep;ed in InstanceMesh which should be a resource.
Ref< render::IRenderSystem > m_renderSystem;
resource::Proxy< render::Shader > m_shaderCull;
Ref< render::IRenderSystem > m_renderSystem;
resource::Proxy< render::Shader > m_shaderDraw;
AlignedVector< Instance* > m_instances;
Ref< render::Buffer > m_instanceBuffer;
RefArray< render::Buffer > m_visibilityBuffers;
RefArray< render::Buffer > m_drawBuffers;
uint32_t m_instanceAllocatedCount = 0;
bool m_instanceBufferDirty = false;
uint32_t m_allocatedCount = 0;
};

}
Loading

0 comments on commit 9468e5a

Please sign in to comment.