From a3da2f8f3dad554d6ee76bb36e77ef04755a114c Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Tue, 24 Sep 2024 16:17:58 +0200 Subject: [PATCH] tidy --- include/application.hpp | 3 + include/simulation.hpp | 20 +-- include/vulkan/buffer.hpp | 2 + include/vulkan/descriptor_pool.hpp | 7 +- shaders/normal.comp | 35 ++++-- shaders/pbd.comp | 13 +- src/simulation.cpp | 196 +++++++++++++++++------------ src/vulkan/application.cpp | 9 +- src/vulkan/descriptor_pool.cpp | 55 +++++--- 9 files changed, 211 insertions(+), 129 deletions(-) diff --git a/include/application.hpp b/include/application.hpp index 4682322..4697ce6 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -16,6 +16,9 @@ #include #include +using std::unique_ptr, std::make_unique; +using std::vector; + class Instance; class Swapchain; class GraphicsPipeline; diff --git a/include/simulation.hpp b/include/simulation.hpp index f0d6df9..8c28e62 100644 --- a/include/simulation.hpp +++ b/include/simulation.hpp @@ -10,16 +10,20 @@ public: Simulation(); ~Simulation(); private: - Buffer* vertexBuffer; - Buffer* edgeBuffer; - Buffer* triangleBuffer; - Buffer* faceBuffer; - Buffer* tetrahedronBuffer; + unique_ptr vertexBuffer; + unique_ptr faceBuffer; + unique_ptr edgeBuffer; + unique_ptr triangleBuffer; + unique_ptr tetrahedronBuffer; + void createMeshBuffers(); - ComputePipeline* pbdPipeline = nullptr; - ComputePipeline* normalPipeline = nullptr; + unique_ptr sizeInformationBuffer; - std::vector> softBodies; + unique_ptr pbdPipeline; + unique_ptr normalPipeline; + void createComputePipelines(); + + vector> softBodies; void recordDrawCommands() override; void recordComputeCommands(VkCommandBuffer cmdBuffer) override; }; \ No newline at end of file diff --git a/include/vulkan/buffer.hpp b/include/vulkan/buffer.hpp index bcd7da4..8b70ca8 100644 --- a/include/vulkan/buffer.hpp +++ b/include/vulkan/buffer.hpp @@ -19,6 +19,8 @@ public: VmaAllocation allocation = VK_NULL_HANDLE; VmaAllocationInfo allocationInfo {}; VkDeviceSize size; + Buffer(const Buffer& other) = delete; + Buffer& operator =(const Buffer& other) = delete; private: void copyTo(Buffer* dst); }; \ No newline at end of file diff --git a/include/vulkan/descriptor_pool.hpp b/include/vulkan/descriptor_pool.hpp index ab122b0..8f32366 100644 --- a/include/vulkan/descriptor_pool.hpp +++ b/include/vulkan/descriptor_pool.hpp @@ -8,7 +8,8 @@ class Buffer; enum class DescriptorSet { WORLD = 0, - MESH = 1 + MESH = 1, + SIMULATION = 2 }; class DescriptorPool { @@ -16,9 +17,9 @@ public: DescriptorPool(); ~DescriptorPool(); - void bindBuffer(Buffer* buffer, VkDescriptorType type, DescriptorSet set, uint32_t binding); + void bindBuffer(const Buffer& buffer, VkDescriptorType type, DescriptorSet set, uint32_t binding); std::map sets; - std::map setLayouts; + std::map layouts; private: VkDescriptorPool handle = VK_NULL_HANDLE; diff --git a/shaders/normal.comp b/shaders/normal.comp index 5647617..bc28a3d 100644 --- a/shaders/normal.comp +++ b/shaders/normal.comp @@ -20,10 +20,15 @@ struct Face { layout (std430, set = 0, binding = 0) buffer VertexBuffer { Vertex vertices[]; }; -layout (std430, set = 0, binding = 3) buffer FaceBuffer { +layout (std430, set = 0, binding = 1) buffer FaceBuffer { Face faces[]; }; +layout (std140, set = 0, binding = 5) uniform Sizes { + uint vertexCount; + uint faceCount; +}; + layout (push_constant) uniform PushConstants { uint state; @@ -42,13 +47,11 @@ void atomicAddVec3(uint vID, vec3 add){ } } -void reset(){ - uint vID = gl_GlobalInvocationID.x; +void reset(uint vID){ vertices[vID].normal = floatBitsToUint(vec3(0, 0, 0)); } -void accumulate(){ - uint fID = gl_GlobalInvocationID.x; +void accumulate(uint fID){ Face f = faces[fID]; Vertex v1 = vertices[f.a]; @@ -61,15 +64,27 @@ void accumulate(){ atomicAddVec3(f.c, weightedNormal); } -void norm(){ - uint vID = gl_GlobalInvocationID.x; +void norm(uint vID){ vertices[vID].normal = floatBitsToUint(normalize(uintBitsToFloat(vertices[vID].normal))); } void main() { + uint id = gl_GlobalInvocationID.x; switch (state){ - case 0: reset(); break; - case 1: accumulate(); break; - case 2: norm(); break; + case 0: + if (id < vertexCount){ + reset(id); + } + break; + case 1: + if (id < faceCount){ + accumulate(id); + } + break; + case 2: + if (id < vertexCount){ + norm(id); + } + break; } } \ No newline at end of file diff --git a/shaders/pbd.comp b/shaders/pbd.comp index 1f38fa5..d9e342c 100644 --- a/shaders/pbd.comp +++ b/shaders/pbd.comp @@ -1,6 +1,6 @@ #version 450 -layout (local_size_x = 32) in; +layout (local_size_x = 256) in; struct Vertex { vec3 position; @@ -8,10 +8,19 @@ struct Vertex { vec3 normal; }; -layout (std140, set = 0, binding = 0) buffer VertexBuffer { +layout (std430, set = 0, binding = 0) buffer VertexBuffer { Vertex vertices[]; }; +layout (std140, set = 1, binding = 0) uniform UBO { + float dt; + vec3 gravity; +}; + +layout (push_constant) uniform PushConstants { + uint state; +}; + void main() { } \ No newline at end of file diff --git a/src/simulation.cpp b/src/simulation.cpp index c775095..21e565d 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -9,70 +9,38 @@ #include "vulkan/descriptor_pool.hpp" Simulation::Simulation() { - Mesh sphere("models/sphere_high.ply"); - Mesh bunny("models/bunny_high.ply"); - - auto body = std::make_unique(&sphere, 0.3f); - - for (size_t i = 0; i < 500; i++){ - auto copy = std::make_unique(*body.get()); - copy->applyOffset({i / 2.f, 0, 0}); - softBodies.push_back(std::move(copy)); - } - - vector vertices; - vector edges; - vector triangles; - vector faces; - vector tetrahedra; - - for (const std::unique_ptr &softBody : softBodies){ - softBody->firstIndex = faces.size() * 3; - softBody->vertexOffset = static_cast(vertices.size()); - - vertices.insert(vertices.end(), softBody->vertices.begin(), softBody->vertices.end()); - edges.insert(edges.end(), softBody->edges.begin(), softBody->edges.end()); - triangles.insert(triangles.end(), softBody->triangles.begin(), softBody->triangles.end()); - faces.insert(faces.end(), softBody->faces.begin(), softBody->faces.end()); - tetrahedra.insert(tetrahedra.end(), softBody->tetrahedra.begin(), softBody->tetrahedra.end()); + createMeshBuffers(); - for (auto iter = faces.begin() + softBody->firstIndex / 3; iter != faces.end(); iter++){ - iter->a += softBody->vertexOffset; - iter->b += softBody->vertexOffset; - iter->c += softBody->vertexOffset; - } - } + struct SizeInformation { + uint32_t vertexCount; + uint32_t faceCount; - class SimulationBuffer : public Buffer { - public: - SimulationBuffer(void* data, VkDeviceSize size, VkBufferUsageFlags additionalUsageFlags=0) - : Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {} + uint32_t edgeCount; + uint32_t triangleCount; + uint32_t tetrahedronCount; }; - - vertexBuffer = new SimulationBuffer(vertices.data(), vertices.size() * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - edgeBuffer = new SimulationBuffer(edges.data(), edges.size() * sizeof(Edge)); - triangleBuffer = new SimulationBuffer(triangles.data(), triangles.size() * sizeof(Triangle)); - faceBuffer = new SimulationBuffer(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - tetrahedronBuffer = new SimulationBuffer(tetrahedra.data(), tetrahedra.size() * sizeof(Tetrahedron)); - - descriptorPool->bindBuffer(vertexBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); - descriptorPool->bindBuffer(edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1); - descriptorPool->bindBuffer(triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); - descriptorPool->bindBuffer(faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); - descriptorPool->bindBuffer(tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); - - pbdPipeline = new ComputePipeline("shaders/pbd.spv", {descriptorPool->setLayouts[DescriptorSet::MESH]}); - - - normalPipeline = new ComputePipeline("shaders/normal.spv", { - descriptorPool->setLayouts[DescriptorSet::MESH] - },{ - { - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, - .offset = 0, - .size = sizeof(uint32_t) - } - }); + SizeInformation sizeInformation {}; + sizeInformation.vertexCount = vertexBuffer->size / sizeof(Vertex); + sizeInformation.faceCount = faceBuffer->size / sizeof(Face); + + sizeInformationBuffer = make_unique( + sizeof(SizeInformation), &sizeInformation, sizeof(sizeInformation), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0); + + descriptorPool->bindBuffer(*vertexBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 0); + descriptorPool->bindBuffer(*faceBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 1); + descriptorPool->bindBuffer(*edgeBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 2); + descriptorPool->bindBuffer(*triangleBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 3); + descriptorPool->bindBuffer(*tetrahedronBuffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, DescriptorSet::MESH, 4); + descriptorPool->bindBuffer(*sizeInformationBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::MESH, 5); + + createComputePipelines(); + + char* stats; + vmaBuildStatsString(Instance::instance->allocator, &stats, VK_TRUE); + // printf("%s", stats); + vmaFreeStatsString(Instance::instance->allocator, stats); } void Simulation::recordDrawCommands() { @@ -88,6 +56,15 @@ void Simulation::recordDrawCommands() { } void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { +#define BlOCK_SIZE 256 + + auto getGroupCount = [](uint32_t threads, uint32_t blockSize){ + return (threads - 1) / blockSize + 1; + }; + + uint32_t vertexGroupCount = getGroupCount(vertexBuffer->size / sizeof(Vertex), BlOCK_SIZE); + uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pbdPipeline->handle); VkMemoryBarrier barrier {}; @@ -100,8 +77,7 @@ void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { size_t subSteps = 1; for (size_t i = 0; i < subSteps; i++){ - uint32_t preSolveInvocations = 1; - vkCmdDispatch(cmdBuffer, preSolveInvocations, 1, 1); + vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); uint32_t partitionCount = 1; @@ -110,22 +86,14 @@ void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { vkCmdDispatch(cmdBuffer, partitionSize, 1, 1); vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); } - uint32_t postSolveInvocations = 1; - vkCmdDispatch(cmdBuffer, postSolveInvocations, 1, 1); + + vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); + vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, nullptr, 0, nullptr); } vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->handle); vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, normalPipeline->layout, 0, 1, &descriptorPool->sets[DescriptorSet::MESH], 0, nullptr); -#define BlOCK_SIZE 256 - - auto getGroupCount = [](uint32_t threads, uint32_t blockSize){ - return (threads - 1) / blockSize + 1; - }; - - uint32_t vertexGroupCount = getGroupCount(vertexBuffer->size / sizeof(Vertex), BlOCK_SIZE); - uint32_t faceGroupCount = getGroupCount(faceBuffer->size / sizeof(Face), BlOCK_SIZE); - uint32_t state = 0; vkCmdPushConstants(cmdBuffer, normalPipeline->layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(uint32_t), &state); vkCmdDispatch(cmdBuffer, vertexGroupCount, 1, 1); @@ -143,11 +111,77 @@ void Simulation::recordComputeCommands(VkCommandBuffer cmdBuffer) { } Simulation::~Simulation() { - delete vertexBuffer; - delete edgeBuffer; - delete triangleBuffer; - delete faceBuffer; - delete tetrahedronBuffer; - delete pbdPipeline; - delete normalPipeline; + +} + +void Simulation::createMeshBuffers() { + Mesh sphere("models/sphere_high.ply"); + Mesh bunny("models/bunny_high.ply"); + + auto body = std::make_unique(&sphere, 0.3f); + + for (size_t i = 0; i < 500; i++){ + auto copy = std::make_unique(*body.get()); + copy->applyOffset({i / 2.f, 0, 0}); + softBodies.push_back(std::move(copy)); + } + + vector vertices; + vector edges; + vector triangles; + vector faces; + vector tetrahedra; + + for (const std::unique_ptr &softBody : softBodies){ + softBody->firstIndex = faces.size() * 3; + softBody->vertexOffset = static_cast(vertices.size()); + + vertices.insert(vertices.end(), softBody->vertices.begin(), softBody->vertices.end()); + edges.insert(edges.end(), softBody->edges.begin(), softBody->edges.end()); + triangles.insert(triangles.end(), softBody->triangles.begin(), softBody->triangles.end()); + faces.insert(faces.end(), softBody->faces.begin(), softBody->faces.end()); + tetrahedra.insert(tetrahedra.end(), softBody->tetrahedra.begin(), softBody->tetrahedra.end()); + + for (auto face = faces.begin() + softBody->firstIndex / 3; face != faces.end(); face++){ + face->a += softBody->vertexOffset; + face->b += softBody->vertexOffset; + face->c += softBody->vertexOffset; + } + } + + class SimulationBuffer : public Buffer { + public: + SimulationBuffer(void* data, VkDeviceSize size, VkBufferUsageFlags additionalUsageFlags=0) + : Buffer(size, data, size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | additionalUsageFlags, VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, 0) {} + }; + + vertexBuffer = make_unique(vertices.data(), vertices.size() * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + faceBuffer = make_unique(faces.data(), faces.size() * sizeof(Face), VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + edgeBuffer = make_unique(edges.data(), edges.size() * sizeof(Edge)); + triangleBuffer = make_unique(triangles.data(), triangles.size() * sizeof(Triangle)); + tetrahedronBuffer = make_unique(tetrahedra.data(), tetrahedra.size() * sizeof(Tetrahedron)); +} + +void Simulation::createComputePipelines() { + vector layouts; + vector pushRanges; + + { + layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); + pbdPipeline = unique_ptr(new ComputePipeline("shaders/pbd.spv", layouts)); + } + + layouts.clear(); + pushRanges.clear(); + + { + layouts.push_back(descriptorPool->layouts[DescriptorSet::MESH]); + pushRanges.push_back({ + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .offset = 0, + .size = sizeof(uint32_t) + }); + normalPipeline = unique_ptr(new ComputePipeline("shaders/normal.spv", layouts, pushRanges)); + } + } diff --git a/src/vulkan/application.cpp b/src/vulkan/application.cpp index aebcad7..f03e898 100644 --- a/src/vulkan/application.cpp +++ b/src/vulkan/application.cpp @@ -19,7 +19,7 @@ Application::Application() { descriptorPool = new DescriptorPool(); graphicsPipeline = new GraphicsPipeline("shaders/vert.spv", "shaders/frag.spv", swapchain->renderPass, - {descriptorPool->setLayouts[DescriptorSet::WORLD]}); + {descriptorPool->layouts[DescriptorSet::WORLD]}); VkDeviceSize bufferSize = sizeof(UniformBufferObject); @@ -28,13 +28,8 @@ Application::Application() { VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE, VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT); - descriptorPool->bindBuffer(uniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); + descriptorPool->bindBuffer(*uniformBuffer, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, DescriptorSet::WORLD, 0); camera = new Camera(swapchain->extent); - - char* stats; - vmaBuildStatsString(Instance::instance->allocator, &stats, VK_TRUE); - // printf("%s", stats); - vmaFreeStatsString(Instance::instance->allocator, stats); } void Application::updateUniformBuffer() { diff --git a/src/vulkan/descriptor_pool.cpp b/src/vulkan/descriptor_pool.cpp index 8b82f74..714ad8e 100644 --- a/src/vulkan/descriptor_pool.cpp +++ b/src/vulkan/descriptor_pool.cpp @@ -18,25 +18,44 @@ DescriptorPool::DescriptorPool() { vkCreateDescriptorPool(Instance::instance->device, &poolInfo, nullptr, &handle); std::map> setBindings; - setBindings[DescriptorSet::WORLD].push_back({ - .binding = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT - }); - for (uint32_t i = 0; i < 5; i++){ - setBindings[DescriptorSet::MESH].push_back({ - .binding = i, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + auto addBinding = [&setBindings](DescriptorSet set, VkDescriptorType type, VkShaderStageFlags stageFlags){ + uint32_t binding = setBindings[set].size(); + setBindings[set].push_back({ + .binding = binding, + .descriptorType = type, .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT + .stageFlags = stageFlags }); - } + }; + + // camera + addBinding(DescriptorSet::WORLD, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT); + + // vertices + addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + // faces + addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + // edges + addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + // triangles + addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + // tetrahedra + addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + // sizes + addBinding(DescriptorSet::MESH, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); + + // dt + addBinding(DescriptorSet::SIMULATION, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT); for (const auto &[set, bindings] : setBindings) createLayout(set, bindings); - for (const auto &[set, layout] : setLayouts){ + for (const auto &[set, layout] : layouts){ VkDescriptorSetAllocateInfo allocateInfo {}; allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocateInfo.descriptorPool = handle; @@ -49,15 +68,15 @@ DescriptorPool::DescriptorPool() { DescriptorPool::~DescriptorPool() { vkDestroyDescriptorPool(Instance::instance->device, handle, nullptr); - for (const auto &[type, layout] : setLayouts) + for (const auto &[type, layout] : layouts) vkDestroyDescriptorSetLayout(Instance::instance->device, layout, nullptr); } -void DescriptorPool::bindBuffer(Buffer *buffer, VkDescriptorType type, DescriptorSet set, uint32_t binding) { +void DescriptorPool::bindBuffer(const Buffer& buffer, VkDescriptorType type, DescriptorSet set, uint32_t binding) { VkDescriptorBufferInfo bufferInfo {}; - bufferInfo.buffer = buffer->handle; + bufferInfo.buffer = buffer.handle; bufferInfo.offset = 0; - bufferInfo.range = buffer->size; + bufferInfo.range = buffer.size; VkWriteDescriptorSet descriptorWrite {}; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -77,5 +96,5 @@ void DescriptorPool::createLayout(DescriptorSet set, const std::vectordevice, &layoutCreateInfo, nullptr, &setLayouts[set]); + vkCreateDescriptorSetLayout(Instance::instance->device, &layoutCreateInfo, nullptr, &layouts[set]); }