Skip to content
Snippets Groups Projects
Commit 03b69290 authored by Alexander Gauggel's avatar Alexander Gauggel
Browse files

[#87] WIP: meshlets semi working state

parent 704482d6
No related branches found
No related tags found
1 merge request!74Resolve "Mesh Shader Implementation"
Pipeline #26378 failed
File added
......@@ -28,5 +28,5 @@ vec3 colorFromIndex(uint i){
void main() {
outColor = normalize(passNormal) * 0.5 + 0.5;
outColor = colorFromIndex(passTaskIndex);
//outColor = colorFromIndex(passTaskIndex);
}
\ No newline at end of file
......@@ -2,10 +2,10 @@
#extension GL_ARB_separate_shader_objects : enable
#extension GL_NV_mesh_shader : require
layout(local_size_x=30) in;
layout(local_size_x=32) in;
layout(triangles) out;
layout(max_vertices=30, max_primitives=10) out;
layout(max_vertices=64, max_primitives=126) out;
layout( push_constant ) uniform constants{
mat4 mvp;
......@@ -27,31 +27,58 @@ layout(std430, binding = 0) readonly buffer vertexBuffer
layout(std430, binding = 1) readonly buffer indexBuffer
{
uint indices[]; // breaks for 16 bit indices
uint localIndices[]; // breaks for 16 bit indices
};
struct Meshlet{
uint vertexOffset;
uint vertexCount;
uint indexOffset;
uint indexCount;
};
layout(std430, binding = 2) readonly buffer meshletBuffer
{
Meshlet meshlets[];
};
taskNV in Task {
uint baseID;
uint meshletIndex;
} IN;
void main() {
uint workIndex = gl_LocalInvocationID.x;
gl_PrimitiveIndicesNV[workIndex] = workIndex;
Meshlet meshlet = meshlets[IN.meshletIndex];
const uint verticesPerMeshTask = 30;
uint previousMeshGroupCount = IN.baseID;
uint indexBufferIndex = previousMeshGroupCount * verticesPerMeshTask + workIndex;
uint index = indices[indexBufferIndex];
// set vertices
for(uint i = 0; i < 2; i++){
vec3 inPos = vertices[index].position;
vec3 inNormal = vertices[index].normal;
uint workIndex = gl_LocalInvocationID.x + 32 * i;
if(workIndex >= meshlet.vertexCount){
break;
}
gl_MeshVerticesNV[workIndex].gl_Position = mvp * vec4(inPos, 1);
passNormal[workIndex] = inNormal;
passTaskIndex[workIndex] = previousMeshGroupCount;
uint vertexIndex = meshlet.vertexOffset + workIndex;
Vertex vertex = vertices[vertexIndex];
gl_MeshVerticesNV[workIndex].gl_Position = mvp * vec4(vertex.position, 1);
passNormal[workIndex] = vertex.normal;
// passTaskIndex[workIndex] = IN.meshletIndex;
}
// set local indices
for(uint i = 0; i < 12; i++){
uint workIndex = gl_LocalInvocationID.x + i * 32;
if(workIndex >= meshlet.indexCount){
break;
}
uint indexBufferIndex = meshlet.indexOffset + workIndex;
gl_PrimitiveIndicesNV[workIndex] = localIndices[indexBufferIndex];
}
if(gl_LocalInvocationID.x == 0){
gl_PrimitiveCountNV = 10;
gl_PrimitiveCountNV = meshlet.indexCount / 3;
}
}
\ No newline at end of file
......@@ -5,14 +5,10 @@
layout(local_size_x=1) in;
taskNV out Task {
uint baseID;
uint meshletIndex;
} OUT;
layout( push_constant ) uniform constants{
mat4 mvp;
};
void main() {
gl_TaskCountNV = 1;
OUT.baseID = gl_GlobalInvocationID.x;
gl_TaskCountNV = 1;
OUT.meshletIndex = gl_GlobalInvocationID.x;
}
\ No newline at end of file
......@@ -8,6 +8,7 @@
#include <vkcv/gui/GUI.hpp>
#include <vkcv/asset/asset_loader.hpp>
#include "MeshStruct.hpp"
#include <Map>
struct Vertex {
glm::vec3 position;
......@@ -16,6 +17,13 @@ struct Vertex {
float padding1;
};
struct Meshlet {
uint32_t vertexOffset;
uint32_t vertexCount;
uint32_t indexOffset;
uint32_t indexCount;
};
std::vector<Vertex> convertToVertices(
const std::vector<uint8_t>& vertexData,
const uint64_t vertexCount,
......@@ -45,6 +53,117 @@ std::vector<Vertex> convertToVertices(
return vertices;
}
struct MeshShaderModelData {
std::vector<Vertex> vertices;
std::vector<uint32_t> localIndices;
std::vector<Meshlet> meshlets;
};
MeshShaderModelData createMeshShaderModelData(
const std::vector<Vertex>& inVertices,
const std::vector<uint32_t>& inIndices) {
MeshShaderModelData data;
size_t currentIndex = 0;
const size_t maxVerticesPerMeshlet = 64;
const size_t maxIndicesPerMeshlet = 126 * 3;
bool indicesAreLeft = true;
while (indicesAreLeft) {
Meshlet meshlet;
meshlet.indexCount = 0;
meshlet.vertexCount = 0;
meshlet.indexOffset = data.localIndices.size();
meshlet.vertexOffset = data.vertices.size();
std::map<uint32_t, uint32_t> globalToLocalIndexMap;
while (true) {
indicesAreLeft = currentIndex + 1 <= inIndices.size();
if (!indicesAreLeft) {
break;
}
bool enoughSpaceForIndices = meshlet.indexCount + 3 < maxIndicesPerMeshlet;
if (!enoughSpaceForIndices) {
break;
}
size_t vertexCountToAdd = 0;
for (int i = 0; i < 3; i++) {
const uint32_t globalIndex = inIndices[currentIndex + i];
const bool containsVertex = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end();
if (!containsVertex) {
vertexCountToAdd++;
}
}
bool enoughSpaceForVertices = meshlet.vertexCount + vertexCountToAdd < maxVerticesPerMeshlet;
if (!enoughSpaceForVertices) {
break;
}
for (int i = 0; i < 3; i++) {
const uint32_t globalIndex = inIndices[currentIndex + i];
uint32_t localIndex;
const bool indexAlreadyExists = globalToLocalIndexMap.find(globalIndex) != globalToLocalIndexMap.end();
if (indexAlreadyExists) {
localIndex = globalToLocalIndexMap[globalIndex];
}
else {
localIndex = globalToLocalIndexMap.size();
globalToLocalIndexMap[globalIndex] = localIndex;
}
data.localIndices.push_back(localIndex);
}
meshlet.indexCount += 3;
currentIndex += 3;
meshlet.vertexCount += vertexCountToAdd;
}
for (const auto& iterator : globalToLocalIndexMap) {
const uint32_t globalIndex = iterator.first;
const uint32_t localIndex = iterator.second;
const Vertex v = inVertices[globalIndex];
data.vertices.push_back(v);
}
data.meshlets.push_back(meshlet);
}
return data;
}
std::vector<uint32_t> assetLoaderIndicesTo32BitIndices(const std::vector<uint8_t>& indexData, vkcv::asset::IndexType indexType) {
std::vector<uint32_t> indices;
if (indexType == vkcv::asset::IndexType::UINT16) {
for (int i = 0; i < indexData.size(); i += 2) {
const uint16_t index16Bit = *reinterpret_cast<const uint16_t*>(&(indexData[i]));
const uint32_t index32Bit = static_cast<uint32_t>(index16Bit);
indices.push_back(index32Bit);
}
}
else if (indexType == vkcv::asset::IndexType::UINT32) {
for (int i = 0; i < indexData.size(); i += 4) {
const uint32_t index32Bit = *reinterpret_cast<const uint32_t*>(&(indexData[i]));
indices.push_back(index32Bit);
}
}
else {
vkcv_log(vkcv::LogLevel::ERROR, "Unsupported index type");
}
return indices;
}
int main(int argc, const char** argv) {
const char* applicationName = "Mesh shader";
......@@ -106,18 +225,29 @@ int main(int argc, const char** argv) {
vkcv::VertexBufferBinding(static_cast<vk::DeviceSize>(attributes[2].offset), vertexBuffer.getVulkanHandle()) };
const auto& bunny = mesh.vertexGroups[0];
const auto interleavedVertices = convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]);
const std::vector<Vertex> interleavedVertices = convertToVertices(bunny.vertexBuffer.data, bunny.numVertices, attributes[0], attributes[1]);
// mesh shader buffers
auto meshBuffer = core.createBuffer<Vertex>(
const auto& assetLoaderIndexBuffer = mesh.vertexGroups[0].indexBuffer;
const std::vector<uint32_t> indexBuffer32Bit = assetLoaderIndicesTo32BitIndices(assetLoaderIndexBuffer.data, assetLoaderIndexBuffer.type);
const auto meshShaderModelData = createMeshShaderModelData(interleavedVertices, indexBuffer32Bit);
auto meshShaderVertexBuffer = core.createBuffer<Vertex>(
vkcv::BufferType::STORAGE,
interleavedVertices.size());
meshBuffer.fill(interleavedVertices);
meshShaderModelData.vertices.size());
meshShaderVertexBuffer.fill(meshShaderModelData.vertices);
auto meshShaderIndexBuffer = core.createBuffer<uint8_t>(
auto meshShaderIndexBuffer = core.createBuffer<uint32_t>(
vkcv::BufferType::STORAGE,
mesh.vertexGroups[0].indexBuffer.data.size());
meshShaderIndexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data);
meshShaderModelData.localIndices.size());
meshShaderIndexBuffer.fill(meshShaderModelData.localIndices);
auto meshletBuffer = core.createBuffer<Meshlet>(
vkcv::BufferType::STORAGE,
meshShaderModelData.meshlets.size(),
vkcv::BufferMemoryType::DEVICE_LOCAL
);
meshletBuffer.fill(meshShaderModelData.meshlets);
// attachments
const vkcv::AttachmentDescription present_color_attachment(
......@@ -219,8 +349,10 @@ int main(int argc, const char** argv) {
vkcv::DescriptorWrites meshShaderWrites;
meshShaderWrites.storageBufferWrites = {
vkcv::StorageBufferDescriptorWrite(0, meshBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(1, meshShaderIndexBuffer.getHandle()) };
vkcv::StorageBufferDescriptorWrite(0, meshShaderVertexBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(1, meshShaderIndexBuffer.getHandle()),
vkcv::StorageBufferDescriptorWrite(2, meshletBuffer.getHandle()) };
core.writeDescriptorSet( meshShaderDescriptorSet, meshShaderWrites);
vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight, 1, false).getHandle();
......@@ -267,14 +399,13 @@ int main(int argc, const char** argv) {
if (useMeshShader) {
vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(meshShaderDescriptorSet).vulkanHandle);
const uint32_t verticesPerTask = 30;
core.recordMeshShaderDrawcalls(
cmdStream,
renderPass,
meshShaderPipeline,
pushConstantData,
{ vkcv::MeshShaderDrawcall({descriptorUsage}, glm::ceil(bunny.numIndices / float(verticesPerTask))) },
{ vkcv::MeshShaderDrawcall({descriptorUsage}, meshShaderModelData.meshlets.size()) },
{ renderTargets });
}
else {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment