From c30394c3ed8698d0769f73085c94cba047c6dbd2 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sun, 12 Apr 2026 21:58:22 -0500 Subject: [PATCH] collada: per-scene pipelines and descriptor sets --- Makefile | 2 +- data/scenes/shadow_test/shadow_test.cpp | 23 +- include/collada/node_state.h | 1 + include/collada/scene.h | 2 + include/collada/scene/vulkan.h | 86 +++++- include/collada/types.h | 3 + include/vulkan_helper.h | 9 + shader/collada.hlsl | 52 +++- src/collada/node_state.cpp | 8 + src/collada/scene.cpp | 10 +- src/collada/scene/vulkan.cpp | 343 ++++++++++++++++++++++-- src/main.cpp | 21 +- src/vulkan_helper.cpp | 40 +++ 13 files changed, 531 insertions(+), 69 deletions(-) diff --git a/Makefile b/Makefile index 0e972ca..19d6106 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ CFLAGS += -I./data CFLAGS += -I../SDL3-dist/include CFLAGS += -fpic -#FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address +FLAGS += -fstack-protector -fstack-protector-all -fno-omit-frame-pointer -fsanitize=address LDFLAGS += -lm ifeq ($(UNAME),Linux) diff --git a/data/scenes/shadow_test/shadow_test.cpp b/data/scenes/shadow_test/shadow_test.cpp index b1c5331..5873acc 100644 --- a/data/scenes/shadow_test/shadow_test.cpp +++ b/data/scenes/shadow_test/shadow_test.cpp @@ -1575,6 +1575,15 @@ material const material_material__148_material = { .effect = &effect_material__148, }; +material const * const materials[] = { + &material_coloreffectr5g54b179_material, + &material_coloreffectr134g110b8_material, + &material_coloreffectr255g229b0_material, + &material_coloreffectr6g134b6_material, + &material_coloreffectr88g88b225_material, + &material_material__148_material, +}; + input_element const input_elements_position_0_3_normal_0_3_texcoord_0_3[] = { { .semantic = "POSITION", @@ -2078,9 +2087,9 @@ instance_light const instance_lights_node_point001[] = { }; channel const * const node_channels_node_point001[] = { - &node_channel_node_point001_translation_y, - &node_channel_node_point001_translation_z, &node_channel_node_point001_translation_x, + &node_channel_node_point001_translation_z, + &node_channel_node_point001_translation_y, }; node const node_node_point001 = { @@ -2168,8 +2177,8 @@ instance_light const instance_lights_node_point002[] = { }; channel const * const node_channels_node_point002[] = { - &node_channel_node_point002_translation_z, &node_channel_node_point002_translation_x, + &node_channel_node_point002_translation_z, &node_channel_node_point002_translation_y, }; @@ -2199,10 +2208,7 @@ node const node_node_point002 = { transform const transforms_node_camera001[] = { { .type = transform_type::MATRIX, - .matrix = {-0.9161802f, 0.3124457f, -0.2509807f, -3.604237f, - -0.4006261f, -0.7305838f, 0.5529431f, 4.948456f, - -0.01059775f, 0.6071451f, 0.7945203f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f}, + .matrix = {-0.9161802f, 0.3124457f, -0.2509807f, -3.604237f, -0.4006261f, -0.7305838f, 0.5529431f, 4.948456f, -0.01059775f, 0.6071451f, 0.7945203f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, }, }; @@ -2274,6 +2280,9 @@ collada::types::descriptor const descriptor = { .images = images, .images_count = (sizeof (images)) / (sizeof (images[0])), + .materials = materials, + .materials_count = (sizeof (materials)) / (sizeof (materials[0])), + .position_normal_texture_buffer = "data/scenes/shadow_test/shadow_test.vtx", .joint_weight_buffer = "data/scenes/shadow_test/shadow_test.vjw", .index_buffer = "data/scenes/shadow_test/shadow_test.idx", diff --git a/include/collada/node_state.h b/include/collada/node_state.h index ef52429..6543aa2 100644 --- a/include/collada/node_state.h +++ b/include/collada/node_state.h @@ -9,5 +9,6 @@ namespace collada::node_state { void allocate_node_instances(types::node const * const * const nodes, int nodes_count); void update_node_world_transform(instance_types::node & node_instance); + void deallocate_node_instances(int nodes_count); }; }; diff --git a/include/collada/scene.h b/include/collada/scene.h index 957e955..a013128 100644 --- a/include/collada/scene.h +++ b/include/collada/scene.h @@ -19,5 +19,7 @@ namespace collada::scene { void update(XMMATRIX const & projection, XMMATRIX const & view, float t); + + void unload_scene(); }; } diff --git a/include/collada/scene/vulkan.h b/include/collada/scene/vulkan.h index 483167c..a11d1cc 100644 --- a/include/collada/scene/vulkan.h +++ b/include/collada/scene/vulkan.h @@ -6,34 +6,87 @@ #include "collada/instance_types.h" #include "collada/scene/vulkan.h" -#include "shader_data.h" - namespace collada::scene { + // these structures are not vulkan-specific + struct Scene { + XMFLOAT4X4 projection; + XMFLOAT4 lightPosition; + }; + struct Node { + XMFLOAT4X4 modelView; + //int materialIndex; + //int _padding0[3]; + //int _padding1[4 * 3]; + }; + static_assert((sizeof (Node)) % 64 == 0); + struct MaterialColor { + XMFLOAT4 emission; + XMFLOAT4 ambient; + XMFLOAT4 diffuse; + XMFLOAT4 specular; + }; + static_assert((sizeof (MaterialColor)) % 64 == 0); + struct vulkan { // externally initialized, opaque handle VkInstance instance; VkDevice device; - VkPipelineLayout pipelineLayout; - VkDescriptorSetLayout descriptorSetLayout; // externally initialized, structures VkPhysicalDeviceProperties physicalDeviceProperties; VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; // externally initialized, enum VkFormat colorFormat; VkFormat depthFormat; - // externally initialized, pointers - ShaderData * shaderData; - ShaderDataDevice const * shaderDataDevice; + // // method initialized + // + VkPipelineLayout pipelineLayout; VkShaderModule shaderModule; - VkPipeline * pipelines; + VkPipeline * pipelines; // per-scene, one per descriptor->inputs_list_count struct { VkDeviceSize indexOffset; VkBuffer buffer; VkDeviceMemory memory; } vertexIndex; + VkDescriptorPool descriptorPool{ VK_NULL_HANDLE }; + static constexpr uint32_t maxFrames = 2; + static constexpr uint32_t perFrameDescriptorCount = 2; + static constexpr uint32_t constantDescriptorCount = 1; + static constexpr uint32_t uniformBufferDescriptorCount = maxFrames * perFrameDescriptorCount + constantDescriptorCount; + + VkDescriptorSetLayout descriptorSetLayouts[2]; // unrelated to maxFrames, unrelated to descriptorCount + VkDescriptorSet descriptorSets0[maxFrames]; + VkDescriptorSet descriptorSet1; + + struct { + Scene scene; // global(?) + Node * nodes; // per-scene + MaterialColor * materialColors; // per-scene + } shaderData; + struct { + VkDeviceMemory memory; + void * mappedData; + struct { // must match perFrameDescriptorCount + VkBuffer sceneBuffer; + VkDeviceAddress sceneOffset; + VkDeviceAddress sceneSize; + void * sceneMapped; + + VkBuffer nodesBuffer; + VkDeviceAddress nodesOffset; + VkDeviceAddress nodesSize; + void * nodesMapped; + } frame[maxFrames]; + struct { // must match constantDescriptorCount + VkBuffer materialColorsBuffer; + VkDeviceAddress materialColorsOffset; + VkDeviceAddress materialColorsSize; + void * materialColorsMapped; + } constant; + } shaderDataDevice; + // per-frame VkCommandBuffer commandBuffer; uint32_t frameIndex; @@ -44,14 +97,10 @@ namespace collada::scene { void initial_state(VkInstance instance, VkDevice device, - VkPipelineLayout pipelineLayout, - VkDescriptorSetLayout descriptorSetLayout, VkPhysicalDeviceProperties const & physicalDeviceProperties, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkFormat colorFormat, - VkFormat depthFormat, - ShaderData * shaderData, - ShaderDataDevice const * shaderDataDevice); + VkFormat depthFormat); void per_frame_state(uint32_t frameIndex); @@ -69,6 +118,10 @@ namespace collada::scene { char const * index_filename); void create_pipelines(collada::types::descriptor const * const descriptor); + void create_uniform_buffers(collada::types::descriptor const * const descriptor); + void create_descriptor_sets(); + void write_descriptor_sets(collada::types::descriptor const * const descriptor); + ////////////////////////////////////////////////////////////////////// // called by state::draw ////////////////////////////////////////////////////////////////////// @@ -92,5 +145,12 @@ namespace collada::scene { XMMATRIX const & view, int nodes_count, instance_types::node const * const node_instances); + + ////////////////////////////////////////////////////////////////////// + // called by main + ////////////////////////////////////////////////////////////////////// + + void change_frame(VkCommandBuffer commandBuffer, uint32_t frameIndex); + void destroy_all(collada::types::descriptor const * const descriptor); }; } diff --git a/include/collada/types.h b/include/collada/types.h index 45f139b..47a97ed 100644 --- a/include/collada/types.h +++ b/include/collada/types.h @@ -399,6 +399,9 @@ namespace collada::types { image const * const * const images; int const images_count; + material const * const * const materials; + int const materials_count; + //animation const * const animations; //int const animations_count; diff --git a/include/vulkan_helper.h b/include/vulkan_helper.h index 9a3ac09..a30d8b2 100644 --- a/include/vulkan_helper.h +++ b/include/vulkan_helper.h @@ -16,3 +16,12 @@ VkDeviceSize allocateFromMemoryRequirements(VkDevice device, VkMemoryAllocateFlags memoryAllocateFlags, uint32_t count, VkDeviceMemory * memory); + +VkDeviceSize allocateFromMemoryRequirements2(VkDevice device, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + VkMemoryPropertyFlags memoryPropertyFlags, + VkMemoryAllocateFlags memoryAllocateFlags, + uint32_t memoryRequirementsCount, + VkMemoryRequirements const * memoryRequirements, + VkDeviceMemory * memory, + VkDeviceSize * offsets); diff --git a/shader/collada.hlsl b/shader/collada.hlsl index a94ba6c..2ae952e 100644 --- a/shader/collada.hlsl +++ b/shader/collada.hlsl @@ -14,17 +14,54 @@ struct VSOutput float3 ViewDirection : NORMAL2; }; -struct ShaderData +struct Node +{ + column_major float4x4 ModelView; + //int MaterialIndex; +}; + +struct Scene { column_major float4x4 Projection; - column_major float4x4 ModelView[16]; float4 LightPosition; // view space }; -[[vk::binding(0, 0)]] ConstantBuffer data; +struct MaterialColor +{ + float4 Emission; + float4 Ambient; + float4 Diffuse; + float4 Specular; +}; + +/* +struct Nodes { + Node n[16]; +}; + +struct MaterialColors { + MaterialColor mc[16]; +}; +*/ + +struct SceneNodes { + Scene Scene; +}; + +struct Nodes { + Node n[11]; +}; + +// set 0: per-frame +[[vk::binding(0, 0)]] ConstantBuffer Scene; +[[vk::binding(1, 0)]] ConstantBuffer Nodes; +//[[vk::binding(1, 0)]] cbuffer asdf { Nodes Nodes; } + +// set 1: constant +//[[vk::binding(0, 1)]] ConstantBuffer MaterialColors; struct PushConstant { - int ModelViewIndex; + int NodeIndex; }; [[vk::push_constant]] @@ -33,15 +70,16 @@ struct PushConstant constants; [shader("vertex")] VSOutput VSMain(VSInput input) { - float4x4 modelView = data.ModelView[constants.ModelViewIndex]; + //[constants.NodeIndex] + float4x4 modelView = Nodes.n[constants.NodeIndex].ModelView; VSOutput output = (VSOutput)0; - output.Position = mul(data.Projection, mul(modelView, float4(input.Position.xyz, 1.0))) * float4(-1, -1, 1, 1); + output.Position = mul(Scene.Projection, mul(modelView, float4(input.Position.xyz, 1.0))) * float4(-1, -1, 1, 1); output.Normal = mul((float3x3)modelView, input.Normal); output.Texture = input.Texture.xy * 1.0; float4 viewPosition = mul(modelView, float4(input.Position.xyz, 1.0)); - output.LightDirection = (data.LightPosition - viewPosition).xyz; + output.LightDirection = (Scene.LightPosition - viewPosition).xyz; output.ViewDirection = -viewPosition.xyz; return output; diff --git a/src/collada/node_state.cpp b/src/collada/node_state.cpp index fb08b67..ad9d9a0 100644 --- a/src/collada/node_state.cpp +++ b/src/collada/node_state.cpp @@ -66,6 +66,14 @@ namespace collada::node_state { } } + void state::deallocate_node_instances(int nodes_count) + { + for (int i = 0; i < nodes_count; i++) { + free(node_instances[i].transforms); + } + free(node_instances); + } + ////////////////////////////////////////////////////////////////////// // world matrix ////////////////////////////////////////////////////////////////////// diff --git a/src/collada/scene.cpp b/src/collada/scene.cpp index 37e2098..1c55405 100644 --- a/src/collada/scene.cpp +++ b/src/collada/scene.cpp @@ -8,9 +8,12 @@ namespace collada::scene { { this->descriptor = descriptor; - vulkan.create_pipelines(descriptor); vulkan.load_vertex_index_buffer(descriptor->position_normal_texture_buffer, descriptor->index_buffer); + vulkan.create_uniform_buffers(descriptor); + vulkan.create_descriptor_sets(); + vulkan.write_descriptor_sets(descriptor); + vulkan.create_pipelines(descriptor); node_state.allocate_node_instances(descriptor->nodes, descriptor->nodes_count); } @@ -47,4 +50,9 @@ namespace collada::scene { descriptor->nodes_count, node_state.node_instances); } + + void state::unload_scene() + { + node_state.deallocate_node_instances(descriptor->nodes_count); + } } diff --git a/src/collada/scene/vulkan.cpp b/src/collada/scene/vulkan.cpp index 66f4942..59238ac 100644 --- a/src/collada/scene/vulkan.cpp +++ b/src/collada/scene/vulkan.cpp @@ -102,19 +102,13 @@ namespace collada::scene { void vulkan::initial_state(VkInstance instance, VkDevice device, - VkPipelineLayout pipelineLayout, - VkDescriptorSetLayout descriptorSetLayout, VkPhysicalDeviceProperties const & physicalDeviceProperties, VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, VkFormat colorFormat, - VkFormat depthFormat, - ShaderData * shaderData, - ShaderDataDevice const * shaderDataDevice) + VkFormat depthFormat) { this->instance = instance; this->device = device; - this->pipelineLayout = pipelineLayout; - this->descriptorSetLayout = descriptorSetLayout; this->physicalDeviceProperties = physicalDeviceProperties; this->physicalDeviceMemoryProperties = physicalDeviceMemoryProperties; @@ -122,9 +116,6 @@ namespace collada::scene { this->colorFormat = colorFormat; this->depthFormat = depthFormat; - this->shaderData = shaderData; - this->shaderDataDevice = shaderDataDevice; - load_shader(); } @@ -188,6 +179,253 @@ namespace collada::scene { vkUnmapMemory(device, vertexIndex.memory); } + + ////////////////////////////////////////////////////////////////////// + // uniform buffers + ////////////////////////////////////////////////////////////////////// + + void vulkan::create_uniform_buffers(collada::types::descriptor const * const descriptor) + { + VkMemoryRequirements memoryRequirements[uniformBufferDescriptorCount]; + VkDeviceSize offsets[uniformBufferDescriptorCount]; + + shaderData.nodes = NewM(descriptor->nodes_count); + shaderData.materialColors = NewM(descriptor->materials_count); + + uint32_t memoryRequirementsIndex = 0; + // per-frame + for (uint32_t i = 0; i < maxFrames; i++) { + // scene buffer + VkBufferCreateInfo sceneBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = (sizeof (Scene)), + .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + + VK_CHECK(vkCreateBuffer(device, &sceneBufferCreateInfo, nullptr, &shaderDataDevice.frame[i].sceneBuffer)); + vkGetBufferMemoryRequirements(device, shaderDataDevice.frame[i].sceneBuffer, &memoryRequirements[memoryRequirementsIndex++]); + + // nodes buffer + VkBufferCreateInfo nodesBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = (sizeof (Node)) * descriptor->nodes_count, + .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + VK_CHECK(vkCreateBuffer(device, &nodesBufferCreateInfo, nullptr, &shaderDataDevice.frame[i].nodesBuffer)); + vkGetBufferMemoryRequirements(device, shaderDataDevice.frame[i].nodesBuffer, &memoryRequirements[memoryRequirementsIndex++]); + }; + + // material color buffer + VkBufferCreateInfo materialColorsBufferCreateInfo{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = (sizeof (MaterialColor)) * descriptor->materials_count, + .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + VK_CHECK(vkCreateBuffer(device, &materialColorsBufferCreateInfo, nullptr, &shaderDataDevice.constant.materialColorsBuffer)); + vkGetBufferMemoryRequirements(device, shaderDataDevice.constant.materialColorsBuffer, &memoryRequirements[memoryRequirementsIndex++]); + + assert(memoryRequirementsIndex == uniformBufferDescriptorCount); + + VkMemoryPropertyFlags memoryPropertyFlags{ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT }; + VkMemoryAllocateFlags memoryAllocateFlags{ }; + VkDeviceSize allocationSize = allocateFromMemoryRequirements2(device, + physicalDeviceMemoryProperties, + memoryPropertyFlags, + memoryAllocateFlags, + uniformBufferDescriptorCount, + memoryRequirements, + &shaderDataDevice.memory, + offsets); + + VkDeviceSize offset{ 0 }; + VkDeviceSize size{ VK_WHOLE_SIZE }; + VkMemoryMapFlags flags{ 0 }; + VK_CHECK(vkMapMemory(device, shaderDataDevice.memory, offset, size, flags, &shaderDataDevice.mappedData)); + + uint32_t offsetsIndex = 0; + // this must match the same order as memoryRequirements + for (uint32_t i = 0; i < maxFrames; i++) { + shaderDataDevice.frame[i].sceneOffset = offsets[offsetsIndex]; + shaderDataDevice.frame[i].sceneSize = memoryRequirements[offsetsIndex++].size; + shaderDataDevice.frame[i].sceneMapped = (void *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.frame[i].sceneOffset); + VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.frame[i].sceneBuffer, shaderDataDevice.memory, shaderDataDevice.frame[i].sceneOffset)); + + shaderDataDevice.frame[i].nodesOffset = offsets[offsetsIndex]; + shaderDataDevice.frame[i].nodesSize = memoryRequirements[offsetsIndex++].size; + shaderDataDevice.frame[i].nodesMapped = (void *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.frame[i].nodesOffset); + VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.frame[i].nodesBuffer, shaderDataDevice.memory, shaderDataDevice.frame[i].nodesOffset)); + } + shaderDataDevice.constant.materialColorsOffset = offsets[offsetsIndex]; + shaderDataDevice.constant.materialColorsSize = memoryRequirements[offsetsIndex++].size; + shaderDataDevice.constant.materialColorsMapped = (void *)(((size_t)shaderDataDevice.mappedData) + shaderDataDevice.constant.materialColorsOffset); + VK_CHECK(vkBindBufferMemory(device, shaderDataDevice.constant.materialColorsBuffer, shaderDataDevice.memory, shaderDataDevice.constant.materialColorsOffset)); + + // if materialColorSize rounded to a multiple of nonCoherentAtomSize is larger than the size of the allocated memory, round down to VK_WHOLE_SIZE + if (shaderDataDevice.constant.materialColorsOffset + shaderDataDevice.constant.materialColorsSize > allocationSize) { + shaderDataDevice.constant.materialColorsSize = VK_WHOLE_SIZE; + } + + assert(offsetsIndex == uniformBufferDescriptorCount); + } + + ////////////////////////////////////////////////////////////////////// + // descriptor sets + ////////////////////////////////////////////////////////////////////// + + void vulkan::create_descriptor_sets() + { + // + // pool + // + VkDescriptorPoolSize descriptorPoolSizes[1]{ + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = uniformBufferDescriptorCount + 1, // why + 1? + } + }; + VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 2, + .poolSizeCount = 1, + .pPoolSizes = descriptorPoolSizes + }; + VK_CHECK(vkCreateDescriptorPool(device, &descriptorPoolCreateInfo, nullptr, &descriptorPool)); + + // + // uniform buffer descriptor set layout/allocation (set 0, per-frame) + // + { + constexpr int bindingCount = 2; + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT + } + }; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = bindingCount, + .pBindings = descriptorSetLayoutBindings + }; + VK_CHECK(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayouts[0])); + + VkDescriptorSetLayout setLayouts[maxFrames]; + for (uint32_t i = 0; i < maxFrames; i++) { + setLayouts[i] = descriptorSetLayouts[0]; + }; + + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = descriptorPool, + .descriptorSetCount = maxFrames, + .pSetLayouts = setLayouts + }; + VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, descriptorSets0)); + } + + // + // uniform buffer descriptor set layout/allocation (set 1, constant) + // + { + constexpr int bindingCount = 1; + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[bindingCount]{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT + }, + }; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .bindingCount = bindingCount, + .pBindings = descriptorSetLayoutBindings + }; + VK_CHECK(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayouts[1])); + + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &descriptorSetLayouts[1] + }; + VK_CHECK(vkAllocateDescriptorSets(device, &descriptorSetAllocateInfo, &descriptorSet1)); + } + } + + ////////////////////////////////////////////////////////////////////// + // descriptor set writes + ////////////////////////////////////////////////////////////////////// + + void vulkan::write_descriptor_sets(collada::types::descriptor const * const descriptor) + { + VkWriteDescriptorSet writeDescriptorSets[uniformBufferDescriptorCount]; + uint32_t writeIndex = 0; + + VkDescriptorBufferInfo sceneDescriptorBufferInfos[maxFrames]; + VkDescriptorBufferInfo nodesDescriptorBufferInfos[maxFrames]; + + for (uint32_t i = 0; i < maxFrames; i++) { + sceneDescriptorBufferInfos[i] = { + .buffer = shaderDataDevice.frame[i].sceneBuffer, + .offset = 0, + .range = shaderDataDevice.frame[i].sceneSize, + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSets0[i], + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &sceneDescriptorBufferInfos[i] + }; + nodesDescriptorBufferInfos[i] = { + .buffer = shaderDataDevice.frame[i].nodesBuffer, + .offset = 0, + .range = shaderDataDevice.frame[i].nodesSize, + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSets0[i], + .dstBinding = 1, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &nodesDescriptorBufferInfos[i] + }; + } + + VkDescriptorBufferInfo materialColorsDescriptorBufferInfo{ + .buffer = shaderDataDevice.constant.materialColorsBuffer, + .offset = 0, + .range = shaderDataDevice.constant.materialColorsSize, + }; + writeDescriptorSets[writeIndex++] = { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptorSet1, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &materialColorsDescriptorBufferInfo + }; + + assert(writeIndex == uniformBufferDescriptorCount); + + vkUpdateDescriptorSets(device, writeIndex, writeDescriptorSets, 0, nullptr); + } + ////////////////////////////////////////////////////////////////////// // shader ////////////////////////////////////////////////////////////////////// @@ -218,8 +456,8 @@ namespace collada::scene { VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .setLayoutCount = 1, - .pSetLayouts = &descriptorSetLayout, + .setLayoutCount = 2, + .pSetLayouts = descriptorSetLayouts, .pushConstantRangeCount = 1, .pPushConstantRanges = &pushConstantRange }; @@ -336,6 +574,8 @@ namespace collada::scene { pipelines = NewM(descriptor->inputs_list_count); VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, descriptor->inputs_list_count, pipelineCreateInfos, nullptr, pipelines)); + free(pipelineCreateInfos); + free(vertexBindingDescriptions); for (int i = 0; i < descriptor->inputs_list_count; i++) { free((void *)vertexInputStates[i].pVertexAttributeDescriptions); @@ -387,32 +627,40 @@ namespace collada::scene { instance_types::node const * const node_instances) { // store - XMStoreFloat4x4(&shaderData->projection, projection); + XMStoreFloat4x4(&shaderData.scene.projection, projection); XMVECTOR lightPosition = XMVector3Transform(XMVectorSet(-42, -40, 156, 0), view); - XMStoreFloat4(&shaderData->lightPosition, lightPosition); + XMStoreFloat4(&shaderData.scene.lightPosition, lightPosition); for (int i = 0; i < nodes_count; i++) { XMMATRIX model_view = node_instances[i].world * view; - XMStoreFloat4x4(&shaderData->modelView[i], model_view); + XMStoreFloat4x4(&shaderData.nodes[i].modelView, model_view); } // copy - - size_t frameOffset = shaderDataDevice->stride * frameIndex; - void * frameData = (void *)(((VkDeviceSize)shaderDataDevice->mappedData) + frameOffset); - VkDeviceSize frameSize{ (sizeof (ShaderData)) }; - memcpy(frameData, &shaderData->projection, frameSize); + memcpy(shaderDataDevice.frame[frameIndex].sceneMapped, &shaderData.scene, (sizeof (Scene))); + memcpy(shaderDataDevice.frame[frameIndex].nodesMapped, &shaderData.nodes[0], (sizeof (Node)) * nodes_count); // flush - VkDeviceSize flushSize{ roundAlignment(frameSize, physicalDeviceProperties.limits.nonCoherentAtomSize) }; - VkMappedMemoryRange shaderDataMemoryRange{ - .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, - .memory = shaderDataDevice->memory, - .offset = frameOffset, - .size = flushSize, + VkDeviceSize sceneFlushSize{ shaderDataDevice.frame[frameIndex].sceneSize }; + VkDeviceSize nodesFlushSize{ shaderDataDevice.frame[frameIndex].nodesSize }; + //fprintf(stderr, "sceneFlushSize %ld\n", sceneFlushSize); + //fprintf(stderr, "nodesFlushSize %ld\n", nodesFlushSize); + VkMappedMemoryRange shaderDataMemoryRanges[2]{ + { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = shaderDataDevice.memory, + .offset = shaderDataDevice.frame[frameIndex].sceneOffset, + .size = roundAlignment(sceneFlushSize, physicalDeviceProperties.limits.nonCoherentAtomSize), + }, + { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = shaderDataDevice.memory, + .offset = shaderDataDevice.frame[frameIndex].nodesOffset, + .size = roundAlignment(nodesFlushSize, physicalDeviceProperties.limits.nonCoherentAtomSize), + } }; - vkFlushMappedMemoryRanges(device, 1, &shaderDataMemoryRange); + vkFlushMappedMemoryRanges(device, 2, shaderDataMemoryRanges); } void vulkan::draw_node(int32_t node_index, @@ -423,4 +671,45 @@ namespace collada::scene { draw_instance_geometries(node.instance_geometries, node.instance_geometries_count); } + + void vulkan::change_frame(VkCommandBuffer commandBuffer, uint32_t frameIndex) + { + this->commandBuffer = commandBuffer; + this->frameIndex = frameIndex; + VkDescriptorSet descriptorSets[2] = { + descriptorSets0[frameIndex], + descriptorSet1, + }; + vkCmdBindDescriptorSets(commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + pipelineLayout, + 0, 2, descriptorSets, + 0, nullptr); + } + + void vulkan::destroy_all(collada::types::descriptor const * const descriptor) + { + free(shaderData.nodes); + free(shaderData.materialColors); + + vkDestroyBuffer(device, vertexIndex.buffer, nullptr); + vkFreeMemory(device, vertexIndex.memory, nullptr); + + for (uint32_t i = 0; i < maxFrames; i++) { + vkDestroyBuffer(device, shaderDataDevice.frame[i].sceneBuffer, nullptr); + vkDestroyBuffer(device, shaderDataDevice.frame[i].nodesBuffer, nullptr); + } + vkDestroyBuffer(device, shaderDataDevice.constant.materialColorsBuffer, nullptr); + vkFreeMemory(device, shaderDataDevice.memory, nullptr); + + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts[0], nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayouts[1], nullptr); + vkDestroyDescriptorPool(device, descriptorPool, nullptr); + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + for (int i = 0; i < descriptor->inputs_list_count; i++) { + vkDestroyPipeline(device, pipelines[i], nullptr); + } + free(pipelines); + vkDestroyShaderModule(device, shaderModule, nullptr); + } } diff --git a/src/main.cpp b/src/main.cpp index 06c55f3..4748fe6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1174,16 +1174,13 @@ int main() collada_state.vulkan.initial_state(instance, device, - pipelineLayout, - uniformBufferDescriptorSetLayout, physicalDeviceProperties, physicalDeviceMemoryProperties, surfaceFormat.format, - depthFormat, - &shaderData, - &shaderDataDevice); + depthFormat); - collada_state.load_scene(&shadow_test::descriptor); + collada::types::descriptor const * collada_scene_descriptor = &shadow_test::descriptor; + collada_state.load_scene(collada_scene_descriptor); ////////////////////////////////////////////////////////////////////// // loop @@ -1365,18 +1362,12 @@ int main() //vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0); */ - collada_state.vulkan.commandBuffer = commandBuffer; - collada_state.vulkan.frameIndex = frameIndex; + collada_state.vulkan.change_frame(commandBuffer, frameIndex); XMMATRIX projection = currentProjection(); XMMATRIX view = currentView(); collada_state.update(projection, view, 0); - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - collada_state.vulkan.pipelineLayout, - 0, 1, &uniformBufferDescriptorSets[frameIndex], - 0, nullptr); - collada_state.draw(); vkCmdEndRendering(commandBuffer); @@ -1440,6 +1431,10 @@ int main() } VK_CHECK(vkDeviceWaitIdle(device)); + + collada_state.vulkan.destroy_all(collada_scene_descriptor); + collada_state.unload_scene(); + for (uint32_t i = 0; i < maxFramesInFlight; i++) { vkDestroyFence(device, fences[i], nullptr); vkDestroySemaphore(device, presentSemaphores[i], nullptr); diff --git a/src/vulkan_helper.cpp b/src/vulkan_helper.cpp index be1f067..4d8d30a 100644 --- a/src/vulkan_helper.cpp +++ b/src/vulkan_helper.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "volk/volk.h" #include "vulkan/vk_enum_string_helper.h" @@ -62,3 +63,42 @@ VkDeviceSize allocateFromMemoryRequirements(VkDevice device, return stride; } + +VkDeviceSize allocateFromMemoryRequirements2(VkDevice device, + VkPhysicalDeviceMemoryProperties const & physicalDeviceMemoryProperties, + VkMemoryPropertyFlags memoryPropertyFlags, + VkMemoryAllocateFlags memoryAllocateFlags, + uint32_t memoryRequirementsCount, + VkMemoryRequirements const * memoryRequirements, + VkDeviceMemory * memory, + VkDeviceSize * offsets) +{ + assert(memoryRequirementsCount > 0); + uint32_t memoryTypeBits = memoryRequirements[0].memoryTypeBits; + for (uint32_t i = 1; i < memoryRequirementsCount; i++) { + assert(memoryRequirements[i].memoryTypeBits == memoryTypeBits); + } + uint32_t memoryTypeIndex = findMemoryTypeIndex(physicalDeviceMemoryProperties, + memoryTypeBits, + memoryPropertyFlags); + VkDeviceSize offset = 0; + for (uint32_t i = 0; i < memoryRequirementsCount; i++) { + offset = roundAlignment(offset, memoryRequirements[i].alignment); + offsets[i] = offset; + offset += memoryRequirements[i].size; + } + + VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO, + .flags = memoryAllocateFlags, + }; + VkMemoryAllocateInfo memoryAllocateInfo{ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memoryAllocateFlagsInfo, + .allocationSize = offset, + .memoryTypeIndex = memoryTypeIndex, + }; + VK_CHECK(vkAllocateMemory(device, &memoryAllocateInfo, nullptr, memory)); + + return offset; +}