trying to integrate legacy index buffer rendering

This commit is contained in:
2023-11-06 22:24:40 +01:00
parent 4c567b60f3
commit 46a0befb80
16 changed files with 203 additions and 87 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ set(SLANG_BINARY_DIR ${SLANG_ROOT}/bin/linux-x64/release)
ExternalProject_Add(slang-build
SOURCE_DIR ${SLANG_ROOT}
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}
CONFIGURE_COMMAND premake5 --file=${CMAKE_SOURCE_DIR}/external/slang/premake5.lua gmake2 --arch=x64 --deps=true --build-location=build/linux
CONFIGURE_COMMAND ${CMAKE_SOURCE_DIR}/premake5 --file=${CMAKE_SOURCE_DIR}/external/slang/premake5.lua gmake2 --arch=x64 --deps=true --build-location=build/linux
BUILD_COMMAND make -C ${CMAKE_SOURCE_DIR}/external/slang/build/linux config=${SLANG_CONFIG}
INSTALL_COMMAND ""
)
+1 -1
+53 -59
View File
@@ -177,71 +177,64 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialAss
}
Array<Meshlet> meshlets;
if (Gfx::useMeshShading)
meshlets.reserve(indices.size() / (3ull * Gfx::numPrimitivesPerMeshlet));
std::set<uint32> uniqueVertices;
Meshlet current = {
.numVertices = 0,
.numPrimitives = 0,
};
auto insertAndGetIndex = [&uniqueVertices, &current](uint32 index) -> int8_t
{
meshlets.reserve(indices.size() / (3ull * Gfx::numPrimitivesPerMeshlet));
std::set<uint32> uniqueVertices;
Meshlet current = {
auto [it, inserted] = uniqueVertices.insert(index);
if (inserted)
{
if (current.numVertices == Gfx::numVerticesPerMeshlet)
{
return -1;
}
current.uniqueVertices[current.numVertices] = index;
return current.numVertices++;
}
else
{
for (uint32 i = 0; i < current.numVertices; ++i)
{
if (current.uniqueVertices[i] == index)
{
return i;
}
}
assert(false);
}
};
auto completeMeshlet = [&meshlets, &current, &uniqueVertices]() {
meshlets.add(current);
current = {
.numVertices = 0,
.numPrimitives = 0,
};
auto insertAndGetIndex = [&uniqueVertices, &current](uint32 index) -> int8_t
{
auto [it, inserted] = uniqueVertices.insert(index);
if (inserted)
{
if (current.numVertices == Gfx::numVerticesPerMeshlet)
{
return -1;
}
current.uniqueVertices[current.numVertices] = index;
return current.numVertices++;
}
else
{
for (uint32 i = 0; i < current.numVertices; ++i)
{
if (current.uniqueVertices[i] == index)
{
return i;
}
}
assert(false);
}
};
auto completeMeshlet = [&meshlets, &current, &uniqueVertices]() {
meshlets.add(current);
current = {
.numVertices = 0,
.numPrimitives = 0,
};
uniqueVertices.clear();
};
for (size_t faceIndex = 0; faceIndex < mesh->mNumFaces; ++faceIndex)
{
auto i1 = insertAndGetIndex(mesh->mFaces[faceIndex].mIndices[0]);
auto i2 = insertAndGetIndex(mesh->mFaces[faceIndex].mIndices[1]);
auto i3 = insertAndGetIndex(mesh->mFaces[faceIndex].mIndices[2]);
if (i1 == -1 || i2 == -1 || i3 == -1)
{
completeMeshlet();
}
current.primitiveLayout[current.numPrimitives * 3 + 0] = i1;
current.primitiveLayout[current.numPrimitives * 3 + 1] = i2;
current.primitiveLayout[current.numPrimitives * 3 + 2] = i3;
current.numPrimitives++;
if (current.numPrimitives == Gfx::numPrimitivesPerMeshlet)
{
completeMeshlet();
}
}
vertexData->loadMesh(id, meshlets);
}
else
uniqueVertices.clear();
};
for (size_t faceIndex = 0; faceIndex < mesh->mNumFaces; ++faceIndex)
{
// \! todo
auto i1 = insertAndGetIndex(mesh->mFaces[faceIndex].mIndices[0]);
auto i2 = insertAndGetIndex(mesh->mFaces[faceIndex].mIndices[1]);
auto i3 = insertAndGetIndex(mesh->mFaces[faceIndex].mIndices[2]);
if (i1 == -1 || i2 == -1 || i3 == -1)
{
completeMeshlet();
}
current.primitiveLayout[current.numPrimitives * 3 + 0] = i1;
current.primitiveLayout[current.numPrimitives * 3 + 1] = i2;
current.primitiveLayout[current.numPrimitives * 3 + 2] = i3;
current.numPrimitives++;
if (current.numPrimitives == Gfx::numPrimitivesPerMeshlet)
{
completeMeshlet();
}
}
vertexData->loadMesh(id, meshlets);
collider.physicsMesh.addCollider(positions, indices, Matrix4(1.0f));
@@ -262,6 +255,7 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array<PMaterialAss
});
globalMeshes[meshIndex]->meshlets = std::move(meshlets);
globalMeshes[meshIndex]->vertexCount = mesh->mNumVertices;
globalMeshes[meshIndex]->indexBuffer = std::move(indexBuffer);
}
}
+1 -1
View File
@@ -165,7 +165,7 @@ namespace Gfx
{
static constexpr bool useAsyncCompute = true;
static constexpr bool waitIdleOnSubmit = true;
static constexpr bool useMeshShading = true;
extern bool useMeshShading = false; // enable if supported
static constexpr uint32 numFramesBuffered = 3;
// meshlet dimensions curated by NVIDIA
+2
View File
@@ -1,6 +1,7 @@
#pragma once
#include "Asset/MaterialInstanceAsset.h"
#include "VertexData.h"
#include "Graphics/Buffer.h"
namespace Seele
{
@@ -13,6 +14,7 @@ public:
VertexData* vertexData;
MeshId id;
uint64 vertexCount;
Gfx::OIndexBuffer indexBuffer;
PMaterialInstanceAsset referencedMaterial;
Array<Meshlet> meshlets;
void save(ArchiveBuffer& buffer) const;
+52 -14
View File
@@ -1,5 +1,7 @@
#include "BasePass.h"
#include "Graphics/Enums.h"
#include "Graphics/Graphics.h"
#include "Graphics/Initializer.h"
#include "Graphics/Shader.h"
#include "Window/Window.h"
#include "Component/Camera.h"
@@ -73,10 +75,18 @@ void BasePass::render()
graphics->beginRenderPass(renderPass);
Gfx::ShaderPermutation permutation;
permutation.hasFragment = true;
permutation.useMeshShading = true;
permutation.hasTaskShader = true;
std::memcpy(permutation.taskFile, "MeshletBasePass", std::strlen("MeshletBasePass"));
std::memcpy(permutation.vertexMeshFile, "MeshletBasePass", std::strlen("MeshletBasePass"));
if(Gfx::useMeshShading)
{
permutation.useMeshShading = true;
permutation.hasTaskShader = true;
std::memcpy(permutation.taskFile, "MeshletBasePass", sizeof("MeshletBasePass"));
std::memcpy(permutation.vertexMeshFile, "MeshletBasePass", sizeof("MeshletBasePass"));
}
else
{
permutation.useMeshShading = false;
std::memcpy(permutation.vertexMeshFile, "LegacyBasePass", sizeof("LegacyBasePass"));
}
std::memcpy(permutation.fragmentFile, "BasePass", std::strlen("BasePass"));
for (VertexData* vertexData : VertexData::getList())
{
@@ -105,15 +115,30 @@ void BasePass::render()
const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id);
assert(collection != nullptr);
Gfx::MeshPipelineCreateInfo pipelineInfo;
pipelineInfo.taskShader = collection->taskShader;
pipelineInfo.meshShader = collection->meshShader;
pipelineInfo.fragmentShader = collection->fragmentShader;
pipelineInfo.pipelineLayout = layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_LESS_OR_EQUAL;
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInfo);
command->bindPipeline(pipeline);
if(Gfx::useMeshShading)
{
Gfx::MeshPipelineCreateInfo pipelineInfo;
pipelineInfo.taskShader = collection->taskShader;
pipelineInfo.meshShader = collection->meshShader;
pipelineInfo.fragmentShader = collection->fragmentShader;
pipelineInfo.pipelineLayout = layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_LESS_OR_EQUAL;
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInfo);
command->bindPipeline(pipeline);
}
else
{
Gfx::LegacyPipelineCreateInfo pipelineInfo;
pipelineInfo.vertexDeclaration = collection->vertexDeclaration;
pipelineInfo.vertexShader = collection->vertexShader;
pipelineInfo.fragmentShader = collection->fragmentShader;
pipelineInfo.pipelineLayout = layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_LESS_OR_EQUAL;
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInfo);
command->bindPipeline(pipeline);
}
descriptorSets[INDEX_VERTEX_DATA] = vertexData->getVertexDataSet();
for (const auto& [_, instance] : materialData.instances)
@@ -121,7 +146,20 @@ void BasePass::render()
descriptorSets[INDEX_MATERIAL] = instance.materialInstance->getDescriptorSet();
descriptorSets[INDEX_SCENE_DATA] = instance.descriptorSet;
command->bindDescriptor(descriptorSets);
command->dispatch(instance.numMeshes, 1, 1);
if(Gfx::useMeshShading)
{
command->dispatch(instance.numMeshes, 1, 1);
}
else
{
uint32 instanceOffset = 0;
for(const auto& mesh : instance.meshes)
{
uint32 vertexOffset = vertexData->getMeshOffset(mesh.id);
command->bindIndexBuffer(mesh.indexBuffer);
command->drawIndexed(mesh.indexBuffer->getNumIndices(), 1, 0, vertexOffset, instanceOffset);
}
}
}
}
}
@@ -1,4 +1,5 @@
#include "DepthPrepass.h"
#include "Graphics/Enums.h"
#include "Graphics/Graphics.h"
#include "Graphics/Shader.h"
#include "Window/Window.h"
@@ -38,10 +39,18 @@ void DepthPrepass::render()
depthAttachment->getTexture()->transferOwnership(Gfx::QueueType::GRAPHICS);
Gfx::ShaderPermutation permutation;
permutation.hasFragment = false;
permutation.useMeshShading = true;
permutation.hasTaskShader = true;
std::memcpy(permutation.taskFile, "MeshletBasePass", sizeof("MeshletBasePass"));
std::memcpy(permutation.vertexMeshFile, "MeshletBasePass", sizeof("MeshletBasePass"));
if(Gfx::useMeshShading)
{
permutation.useMeshShading = true;
permutation.hasTaskShader = true;
std::memcpy(permutation.taskFile, "MeshletBasePass", sizeof("MeshletBasePass"));
std::memcpy(permutation.vertexMeshFile, "MeshletBasePass", sizeof("MeshletBasePass"));
}
else
{
permutation.useMeshShading = false;
std::memcpy(permutation.vertexMeshFile, "LegacyBasePass", sizeof("LegacyBasePass"));
}
graphics->beginRenderPass(renderPass);
for (VertexData* vertexData : VertexData::getList())
{
@@ -65,17 +74,53 @@ void DepthPrepass::render()
layout->addDescriptorLayout(INDEX_SCENE_DATA, vertexData->getInstanceDataLayout());
layout->create();
Gfx::MeshPipelineCreateInfo pipelineInfo;
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInfo);
command->bindPipeline(pipeline);
const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id);
assert(collection != nullptr);
if(Gfx::useMeshShading)
{
Gfx::MeshPipelineCreateInfo pipelineInfo;
pipelineInfo.taskShader = collection->taskShader;
pipelineInfo.meshShader = collection->meshShader;
pipelineInfo.fragmentShader = collection->fragmentShader;
pipelineInfo.pipelineLayout = layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_LESS_OR_EQUAL;
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInfo);
command->bindPipeline(pipeline);
}
else
{
Gfx::LegacyPipelineCreateInfo pipelineInfo;
pipelineInfo.vertexDeclaration = collection->vertexDeclaration;
pipelineInfo.vertexShader = collection->vertexShader;
pipelineInfo.fragmentShader = collection->fragmentShader;
pipelineInfo.pipelineLayout = layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.depthStencilState.depthCompareOp = Gfx::SE_COMPARE_OP_LESS_OR_EQUAL;
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(pipelineInfo);
command->bindPipeline(pipeline);
}
descriptorSets[INDEX_VERTEX_DATA] = vertexData->getVertexDataSet();
for (const auto&[_, instance]: materialData.instances)
for (const auto& [_, instance] : materialData.instances)
{
descriptorSets[INDEX_MATERIAL] = instance.materialInstance->getDescriptorSet();
descriptorSets[INDEX_SCENE_DATA] = instance.descriptorSet;
command->bindDescriptor(descriptorSets);
command->dispatch(instance.numMeshes, 1, 1);
if(Gfx::useMeshShading)
{
command->dispatch(instance.numMeshes, 1, 1);
}
else
{
uint32 instanceOffset = 0;
for(const auto& mesh : instance.meshes)
{
uint32 vertexOffset = vertexData->getMeshOffset(mesh.id);
command->bindIndexBuffer(mesh.indexBuffer);
command->drawIndexed(mesh.indexBuffer->getNumIndices(), 1, 0, vertexOffset, instanceOffset);
}
}
}
}
}
+1
View File
@@ -126,6 +126,7 @@ public:
virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) = 0;
virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0;
virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) = 0;
virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) = 0;
virtual void dispatch(uint32 groupX, uint32 groupY, uint32 groupZ) = 0;
std::string name;
};
+2
View File
@@ -1,4 +1,5 @@
#include "Shader.h"
#include "Graphics/Initializer.h"
#include "Graphics/RenderPass/DepthPrepass.h"
#include "Graphics/RenderPass/BasePass.h"
#include <format>
@@ -121,6 +122,7 @@ ShaderCollection& ShaderCompiler::createShaders(ShaderPermutation permutation)
createInfo.entryPoint = "fragmentMain";
collection.fragmentShader = graphics->createFragmentShader(createInfo);
}
collection.vertexDeclaration = graphics->createVertexDeclaration(Array<VertexElement>());
PermutationId perm = PermutationId(permutation);
shaders[perm] = std::move(collection);
@@ -1,4 +1,5 @@
#pragma once
#include "Graphics/Initializer.h"
#include "Math/Vector.h"
#include "VertexData.h"
@@ -15,6 +16,7 @@ public:
void loadNormals(MeshId id, const Array<Vector>& data);
void loadTangents(MeshId id, const Array<Vector>& data);
void loadBiTangents(MeshId id, const Array<Vector>& data);
virtual Gfx::PVertexDeclaration getDeclaration() override;
virtual void serializeMesh(MeshId id, uint64 numVertices, ArchiveBuffer& buffer) override;
virtual void deserializeMesh(MeshId id, ArchiveBuffer& buffer) override;
virtual void init(Gfx::PGraphics graphics) override;
+7 -1
View File
@@ -28,7 +28,8 @@ void VertexData::updateMesh(const Component::Transform& transform, PMesh mesh)
.id = mesh->id,
.instance = InstanceData {
.transformMatrix = transform.toMatrix(),
}
},
.indexBuffer = mesh->indexBuffer,
});
}
@@ -150,6 +151,11 @@ MeshId VertexData::allocateVertexData(uint64 numVertices)
return res;
}
uint32 VertexData::getMeshOffset(MeshId id)
{
return meshOffsets[id];
}
List<VertexData*> vertexDataList;
List<VertexData*> VertexData::getList()
+4 -1
View File
@@ -1,4 +1,5 @@
#pragma once
#include "Graphics/Initializer.h"
#include "Material/MaterialInstance.h"
#include "Component/Transform.h"
#include "Containers/List.h"
@@ -37,12 +38,13 @@ public:
{
MeshId id;
InstanceData instance;
Gfx::PIndexBuffer indexBuffer;
};
struct MaterialInstanceData
{
PMaterialInstance materialInstance;
Gfx::PDescriptorSet descriptorSet;
uint32_t numMeshes; // not necessarily equal to meshes.size() if a MeshId has multiple meshes
uint32 numMeshes; // not necessarily equal to meshes.size() if a MeshId has multiple meshes
Array<MeshInstanceData> meshes;
};
struct MaterialData
@@ -61,6 +63,7 @@ public:
void loadMesh(MeshId id, Array<Meshlet> meshlets);
void createDescriptors();
MeshId allocateVertexData(uint64 numVertices);
uint32 getMeshOffset(MeshId id);
virtual void serializeMesh(MeshId id, uint64 numVertices, ArchiveBuffer& buffer) = 0;
virtual void deserializeMesh(MeshId id, ArchiveBuffer& buffer) = 0;
virtual void bindBuffers(Gfx::PRenderCommand command) = 0;
@@ -8,6 +8,7 @@
#include "Pipeline.h"
#include "DescriptorSets.h"
#include "RenderTarget.h"
#include <vulkan/vulkan_core.h>
using namespace Seele;
using namespace Seele::Vulkan;
@@ -310,6 +311,11 @@ void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, int32 firstVe
vkCmdDraw(handle, vertexCount, instanceCount, firstVertex, firstInstance);
}
void RenderCommand::drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance)
{
assert(threadId == std::this_thread::get_id());
vkCmdDrawIndexed(handle, indexCount, instanceCount, firstIndex, vertexOffset, firstIndex);
}
void RenderCommand::dispatch(uint32 groupX, uint32 groupY, uint32 groupZ)
{
assert(threadId == std::this_thread::get_id());
@@ -88,6 +88,7 @@ public:
virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override;
virtual void pushConstants(Gfx::PPipelineLayout layout, Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override;
virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) override;
virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) override;
virtual void dispatch(uint32 groupX, uint32 groupY, uint32 groupZ) override;
private:
PGraphicsPipeline pipeline;
+15
View File
@@ -2,6 +2,7 @@
#include "Graphics.h"
#include "Allocator.h"
#include "Buffer.h"
#include "Graphics/Enums.h"
#include "PipelineCache.h"
#include "CommandBuffer.h"
#include "Initializer.h"
@@ -10,6 +11,8 @@
#include "Framebuffer.h"
#include "Shader.h"
#include <GLFW/glfw3.h>
#include <cstring>
#include <vulkan/vulkan_core.h>
using namespace Seele;
using namespace Seele::Vulkan;
@@ -466,6 +469,18 @@ void Graphics::pickPhysicalDevice()
physicalDevice = bestDevice;
vkGetPhysicalDeviceProperties(physicalDevice, &props);
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
uint32 count = 0;
vkEnumerateDeviceExtensionProperties(physicalDevice, "VK_EXT_mesh_shader", &count, nullptr);
Array<VkExtensionProperties> extensionProps(count);
vkEnumerateDeviceExtensionProperties(physicalDevice, "VK_EXT_mesh_shader", &count, extensionProps.data());
for(size_t i = 0; i < count; ++i)
{
if(std::strcmp("VK_EXT_mesh_shader", extensionProps[i].extensionName) == 0)
{
Gfx::useMeshShading = true;
break;
}
}
}
void Graphics::createDevice(GraphicsInitializer initializer)
@@ -9,6 +9,7 @@
using namespace Seele;
using namespace Seele::Vulkan;
double useMeshShading = false;
double currentFrameDelta = 0;
double Gfx::getCurrentFrameDelta()
{