feat: draw meshes with instanced multi-draw indirect
This commit is contained in:
@@ -16,12 +16,24 @@ public:
|
||||
|
||||
MeshID addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh);
|
||||
const GPUMesh& getMesh(MeshID id) const;
|
||||
[[nodiscard]] const std::vector<GPUMesh>& getMeshes() const { return meshes; }
|
||||
const CPUMesh& getCPUMesh(MeshID id) const;
|
||||
[[nodiscard]] const std::string& getMeshKey(MeshID id) const;
|
||||
[[nodiscard]] std::optional<MeshID> findMeshByKey(std::string_view key) const;
|
||||
|
||||
[[nodiscard]] const GPUBuffer& getIndexBuffer() const { return indexBuffer; }
|
||||
[[nodiscard]] std::uint32_t getIndexCount() const { return indexCount; }
|
||||
[[nodiscard]] std::uint32_t getIndexCapacity() const { return indexCapacity; }
|
||||
|
||||
private:
|
||||
void uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh& gpuMesh) const;
|
||||
void uploadMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh, GPUMesh& gpuMesh);
|
||||
void ensureIndexCapacity(GfxDevice& gfxDevice, std::uint32_t requiredIndices);
|
||||
|
||||
static constexpr std::uint32_t InitialIndexCapacity = 1u << 20;
|
||||
|
||||
GPUBuffer indexBuffer;
|
||||
std::uint32_t indexCount{0};
|
||||
std::uint32_t indexCapacity{0};
|
||||
|
||||
std::vector<GPUMesh> meshes;
|
||||
std::vector<CPUMesh> cpuMeshes;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef INDIRECTDRAWLIST_H
|
||||
#define INDIRECTDRAWLIST_H
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/FrameConfig.h>
|
||||
#include <destrum/Graphics/Frustum.h>
|
||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||
#include <destrum/Graphics/Resources/Buffer.h>
|
||||
|
||||
class GfxDevice;
|
||||
struct GPUMesh;
|
||||
|
||||
// Must match InstanceData in instance_data.glsl
|
||||
struct GPUInstanceData {
|
||||
glm::mat4 transform;
|
||||
VkDeviceAddress vertexBuffer;
|
||||
std::uint32_t materialId;
|
||||
std::uint32_t padding;
|
||||
};
|
||||
static_assert(sizeof(GPUInstanceData) == 80);
|
||||
|
||||
class IndirectDrawList {
|
||||
public:
|
||||
struct View {
|
||||
std::uint32_t firstCommand{0};
|
||||
std::uint32_t commandCount{0};
|
||||
std::uint32_t instanceCount{0};
|
||||
};
|
||||
|
||||
enum class Filter {
|
||||
All,
|
||||
ShadowCasters,
|
||||
};
|
||||
|
||||
void cleanup(GfxDevice& gfxDevice);
|
||||
|
||||
void begin(std::uint32_t frameIndex);
|
||||
|
||||
View addView(
|
||||
const std::vector<GPUMesh>& meshes,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands,
|
||||
const Frustum& frustum,
|
||||
Filter filter);
|
||||
|
||||
void upload(GfxDevice& gfxDevice);
|
||||
|
||||
void draw(VkCommandBuffer cmd, const GPUBuffer& indexBuffer, const View& view) const;
|
||||
|
||||
[[nodiscard]] VkDeviceAddress getInstanceBufferAddress() const;
|
||||
|
||||
[[nodiscard]] const std::vector<GPUInstanceData>& getInstances() const { return instances; }
|
||||
[[nodiscard]] const std::vector<VkDrawIndexedIndirectCommand>& getCommands() const { return commands; }
|
||||
|
||||
private:
|
||||
struct PerFrameBuffers {
|
||||
GPUBuffer instances;
|
||||
GPUBuffer commands;
|
||||
std::size_t instanceCapacity{0};
|
||||
std::size_t commandCapacity{0};
|
||||
};
|
||||
|
||||
static constexpr std::size_t InitialInstanceCapacity = 1024;
|
||||
static constexpr std::size_t InitialCommandCapacity = 256;
|
||||
|
||||
std::array<PerFrameBuffers, FRAMES_IN_FLIGHT> frames{};
|
||||
std::uint32_t currentFrame{0};
|
||||
|
||||
std::vector<GPUInstanceData> instances;
|
||||
std::vector<VkDrawIndexedIndirectCommand> commands;
|
||||
};
|
||||
|
||||
#endif // INDIRECTDRAWLIST_H
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
VkPhysicalDeviceFeatures device{
|
||||
.imageCubeArray = VK_TRUE,
|
||||
.geometryShader = VK_TRUE,
|
||||
.multiDrawIndirect = VK_TRUE,
|
||||
.drawIndirectFirstInstance = VK_TRUE,
|
||||
.depthClamp = VK_TRUE,
|
||||
.fillModeNonSolid = VK_TRUE,
|
||||
.samplerAnisotropy = VK_TRUE,
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <destrum/Graphics/Pipeline.h>
|
||||
#include <destrum/Graphics/Camera.h>
|
||||
#include <destrum/Graphics/IndirectDrawList.h>
|
||||
#include <destrum/Graphics/Resources/Buffer.h>
|
||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||
|
||||
class GfxDevice;
|
||||
class RenderResources;
|
||||
@@ -31,19 +30,17 @@ public:
|
||||
VkCommandBuffer cmd,
|
||||
VkExtent2D renderExtent,
|
||||
const RenderResources& resources,
|
||||
const Camera& camera,
|
||||
const GPUBuffer& sceneDataBuffer,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands);
|
||||
const IndirectDrawList& drawList,
|
||||
const IndirectDrawList::View& view);
|
||||
|
||||
void draw(
|
||||
VkCommandBuffer cmd,
|
||||
VkExtent2D renderExtent,
|
||||
const RenderResources& resources,
|
||||
const Camera& camera,
|
||||
const GPUBuffer& sceneDataBuffer,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands);
|
||||
const IndirectDrawList& drawList,
|
||||
const IndirectDrawList::View& view);
|
||||
|
||||
void cleanup(VkDevice device);
|
||||
|
||||
@@ -57,11 +54,8 @@ public:
|
||||
|
||||
private:
|
||||
struct PushConstants {
|
||||
glm::mat4 transform;
|
||||
VkDeviceAddress sceneDataBuffer;
|
||||
VkDeviceAddress vertexBuffer;
|
||||
std::uint32_t materialId;
|
||||
std::uint32_t padding;
|
||||
VkDeviceAddress instanceBuffer;
|
||||
};
|
||||
|
||||
void drawMeshes(
|
||||
@@ -69,10 +63,9 @@ private:
|
||||
const Pipeline& pipeline,
|
||||
VkExtent2D renderExtent,
|
||||
const RenderResources& resources,
|
||||
const Camera& camera,
|
||||
const GPUBuffer& sceneDataBuffer,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands);
|
||||
const IndirectDrawList& drawList,
|
||||
const IndirectDrawList::View& view);
|
||||
|
||||
private:
|
||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <destrum/Graphics/Light.h>
|
||||
#include <destrum/Graphics/Pipeline.h>
|
||||
#include <destrum/Graphics/ids.h>
|
||||
#include <destrum/Graphics/MeshDrawCommand.h>
|
||||
#include <destrum/Graphics/IndirectDrawList.h>
|
||||
|
||||
class GfxDevice;
|
||||
struct GPUImage;
|
||||
@@ -32,15 +32,15 @@ public:
|
||||
void drawDirectionalShadow(
|
||||
VkCommandBuffer cmd,
|
||||
const RenderResources& resources,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands,
|
||||
const IndirectDrawList& drawList,
|
||||
const IndirectDrawList::View& view,
|
||||
const glm::mat4& lightViewProj);
|
||||
|
||||
void drawSpotShadows(
|
||||
VkCommandBuffer cmd,
|
||||
const RenderResources& resources,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands,
|
||||
const IndirectDrawList& drawList,
|
||||
const std::vector<IndirectDrawList::View>& views,
|
||||
const std::vector<glm::mat4>& lightViewProjs);
|
||||
|
||||
[[nodiscard]] glm::mat4 calculateDirectionalViewProj(const glm::vec3& lightDirection, const glm::vec3& center) const;
|
||||
@@ -57,8 +57,8 @@ public:
|
||||
private:
|
||||
struct PushConstants
|
||||
{
|
||||
glm::mat4 modelToLightClip;
|
||||
VkDeviceAddress vertexBuffer;
|
||||
glm::mat4 lightViewProj;
|
||||
VkDeviceAddress instanceBuffer;
|
||||
};
|
||||
|
||||
void beginDepthRendering(VkCommandBuffer cmd, const RenderResources& resources, const GPUImage& depthImage);
|
||||
@@ -67,8 +67,8 @@ private:
|
||||
void drawShadowCasters(
|
||||
VkCommandBuffer cmd,
|
||||
const RenderResources& resources,
|
||||
const std::vector<MeshDrawCommand>& drawCommands,
|
||||
const std::vector<std::size_t>& sortedDrawCommands,
|
||||
const IndirectDrawList& drawList,
|
||||
const IndirectDrawList::View& view,
|
||||
const glm::mat4& lightViewProj);
|
||||
|
||||
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <destrum/Graphics/Camera.h>
|
||||
#include <destrum/Graphics/IndirectDrawList.h>
|
||||
#include <destrum/Graphics/Light.h>
|
||||
#include <destrum/Graphics/Pipelines/LightCullingPipeline.h>
|
||||
#include <destrum/Graphics/Pipelines/LineRenderingPass.h>
|
||||
@@ -29,6 +30,15 @@
|
||||
class GameRenderer
|
||||
{
|
||||
public:
|
||||
struct DrawStats
|
||||
{
|
||||
std::uint32_t meshDraws{0};
|
||||
std::uint32_t indirectCommands{0};
|
||||
std::uint32_t instances{0};
|
||||
std::uint32_t mainViewCommands{0};
|
||||
std::uint32_t mainViewInstances{0};
|
||||
};
|
||||
|
||||
struct SceneData
|
||||
{
|
||||
const Camera& camera;
|
||||
@@ -106,6 +116,8 @@ public:
|
||||
return resources;
|
||||
}
|
||||
|
||||
[[nodiscard]] const DrawStats& getDrawStats() const { return lastDrawStats; }
|
||||
|
||||
void draw2D(
|
||||
VkCommandBuffer cmd,
|
||||
GfxDevice& gfxDevice,
|
||||
@@ -125,6 +137,8 @@ private:
|
||||
|
||||
std::vector<MeshDrawCommand> meshDrawCommands;
|
||||
std::vector<std::size_t> sortedMeshDrawCommands;
|
||||
IndirectDrawList drawList;
|
||||
DrawStats lastDrawStats;
|
||||
|
||||
VkFormat drawImageFormat{VK_FORMAT_R16G16B16A16_SFLOAT};
|
||||
VkFormat depthImageFormat{VK_FORMAT_D32_SFLOAT};
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
|
||||
struct GPUMesh {
|
||||
GPUBuffer vertexBuffer;
|
||||
GPUBuffer indexBuffer;
|
||||
|
||||
std::uint32_t numVertices{0};
|
||||
std::uint32_t numIndices{0};
|
||||
// offset into MeshCache::getIndexBuffer(), every mesh shares that one index buffer
|
||||
std::uint32_t firstIndex{0};
|
||||
|
||||
// AABB
|
||||
glm::vec3 minPos;
|
||||
|
||||
Reference in New Issue
Block a user