diff --git a/meson.build b/meson.build index 7e53f1d..2b610de 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ deps = [dependency('glfw3'), dependency('vulkan'), dependency('dl'), dependency( glslc = find_program('glslc') -shaders = ['src/vertex_simple.vert', 'src/fragment_simple.frag', 'src/compute_simple.comp'] +shaders = ['src/vertex_simple.vert', 'src/fragment_simple.frag', 'src/compute_simple.comp', 'src/compute_simple2.comp'] foreach shader : shaders out = (shader.split('.')[-2] + '.spv').split('/')[-1] diff --git a/src/compute_simple.comp b/src/compute_simple.comp index 8b62771..3efd7cd 100644 --- a/src/compute_simple.comp +++ b/src/compute_simple.comp @@ -3,14 +3,10 @@ layout(local_size_x_id = 1) in; -layout(binding = 0) uniform Input { +layout(binding = 0) buffer Data { uint num; -} in_vals; - -layout(binding = 1) buffer Output { - uint num; -} out_vals; +} vals; void main() { - out_vals.num = in_vals.num; + vals.num = 15; } diff --git a/src/compute_simple2.comp b/src/compute_simple2.comp new file mode 100644 index 0000000..dd1a2d0 --- /dev/null +++ b/src/compute_simple2.comp @@ -0,0 +1,12 @@ +#version 450 +#extension GL_EXT_debug_printf : enable + +layout(local_size_x_id = 1) in; + +layout(binding = 0) buffer Data { + uint num; +} vals; + +void main() { + vals.num = vals.num * 2; +} diff --git a/src/vlk_compute.c b/src/vlk_compute.c index 05f913f..19581d2 100644 --- a/src/vlk_compute.c +++ b/src/vlk_compute.c @@ -51,14 +51,11 @@ typedef struct ApplicationState { VkDescriptorPool descriptor_pool; VkDescriptorSet descriptor_sets; VkPipelineLayout pipeline_layout; - VkPipeline pipeline; + VkPipeline pipeline[2]; VkBuffer input_buffer; VkDeviceMemory input_buffer_memory; - VkBuffer output_buffer; - VkDeviceMemory output_buffer_memory; - VkFence compute_done; } compute; } ApplicationState; @@ -397,16 +394,10 @@ void create_descriptor_set_layout(ApplicationState* state) { VkDescriptorSetLayoutBinding input_binding = {0}; input_binding.binding = 0; input_binding.descriptorCount = 1; - input_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + input_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; input_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - VkDescriptorSetLayoutBinding output_binding = {0}; - output_binding.binding = 1; - output_binding.descriptorCount = 1; - output_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - output_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - - VkDescriptorSetLayoutBinding bindings[2] = {input_binding, output_binding}; + VkDescriptorSetLayoutBinding bindings[1] = {input_binding}; VkDescriptorSetLayoutCreateInfo layout_info = {0}; layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; @@ -455,58 +446,79 @@ VkShaderModule create_shader_module(ApplicationState* state, const char* code, s return ret; } -void create_compute_pipeline(ApplicationState* state) { - VkShaderModule compute_shader_module; - size_t compute_shader_size; - char* compute_shader = load_file("./compute_simple.spv", &compute_shader_size); - - compute_shader_module = create_shader_module(state, compute_shader, compute_shader_size); - - VkPipelineShaderStageCreateInfo compute_shader_stage_info = {0}; - compute_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - compute_shader_stage_info.stage = VK_SHADER_STAGE_COMPUTE_BIT; - compute_shader_stage_info.module = compute_shader_module; - compute_shader_stage_info.pName = "main"; - - VkPipelineLayoutCreateInfo pipeline_layout_create_info = {0}; - pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_create_info.setLayoutCount = 1; - pipeline_layout_create_info.pSetLayouts = &state->compute.descriptor_set_layout; - pipeline_layout_create_info.pushConstantRangeCount = 0; - pipeline_layout_create_info.pPushConstantRanges = NULL; - - if (vkCreatePipelineLayout(state->device, &pipeline_layout_create_info, NULL, &state->compute.pipeline_layout) != VK_SUCCESS) { +void create_compute_pipelines(ApplicationState* state) { + VkShaderModule compute_shader_module0; + VkShaderModule compute_shader_module1; + size_t compute_shader_size0; + size_t compute_shader_size1; + char* compute_shader0 = load_file("./compute_simple.spv", &compute_shader_size0); + char* compute_shader1 = load_file("./compute_simple2.spv", &compute_shader_size1); + + compute_shader_module0 = create_shader_module(state, compute_shader0, compute_shader_size0); + compute_shader_module1 = create_shader_module(state, compute_shader1, compute_shader_size1); + + VkPipelineShaderStageCreateInfo compute_shader_stage_info0 = {0}; + compute_shader_stage_info0.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + compute_shader_stage_info0.stage = VK_SHADER_STAGE_COMPUTE_BIT; + compute_shader_stage_info0.module = compute_shader_module0; + compute_shader_stage_info0.pName = "main"; + + VkPipelineShaderStageCreateInfo compute_shader_stage_info1 = {0}; + compute_shader_stage_info1.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + compute_shader_stage_info1.stage = VK_SHADER_STAGE_COMPUTE_BIT; + compute_shader_stage_info1.module = compute_shader_module1; + compute_shader_stage_info1.pName = "main"; + + VkPipelineLayoutCreateInfo pipeline_layout_create_info0 = {0}; + pipeline_layout_create_info0.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipeline_layout_create_info0.setLayoutCount = 1; + pipeline_layout_create_info0.pSetLayouts = &state->compute.descriptor_set_layout; + pipeline_layout_create_info0.pushConstantRangeCount = 0; + pipeline_layout_create_info0.pPushConstantRanges = NULL; + + if (vkCreatePipelineLayout(state->device, &pipeline_layout_create_info0, NULL, &state->compute.pipeline_layout) != VK_SUCCESS) { printf("failed to create pipeline layout"); exit(1); } printf("created pipeline layout\n"); - VkComputePipelineCreateInfo create_info = {0}; - create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - create_info.layout = state->compute.pipeline_layout; - create_info.basePipelineHandle = VK_NULL_HANDLE; - create_info.stage = compute_shader_stage_info; - create_info.flags = 0; + VkComputePipelineCreateInfo create_info0 = {0}; + create_info0.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + create_info0.layout = state->compute.pipeline_layout; + create_info0.basePipelineHandle = VK_NULL_HANDLE; + create_info0.stage = compute_shader_stage_info0; + create_info0.flags = 0; + + VkComputePipelineCreateInfo create_info1 = {0}; + create_info1.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + create_info1.layout = state->compute.pipeline_layout; + create_info1.basePipelineHandle = VK_NULL_HANDLE; + create_info1.stage = compute_shader_stage_info1; + create_info1.flags = 0; + + if (vkCreateComputePipelines(state->device, VK_NULL_HANDLE, 1, &create_info0, NULL, &state->compute.pipeline[0]) != VK_SUCCESS) { + printf("failed to create compute pipeline\n"); + exit(1); + } - if (vkCreateComputePipelines(state->device, VK_NULL_HANDLE, 1, &create_info, NULL, &state->compute.pipeline) != VK_SUCCESS) { + if (vkCreateComputePipelines(state->device, VK_NULL_HANDLE, 1, &create_info1, NULL, &state->compute.pipeline[1]) != VK_SUCCESS) { printf("failed to create compute pipeline\n"); exit(1); } printf("created compute pipeline\n"); - vkDestroyShaderModule(state->device, compute_shader_module, NULL); + vkDestroyShaderModule(state->device, compute_shader_module0, NULL); + vkDestroyShaderModule(state->device, compute_shader_module1, NULL); return; } void create_descriptor_pool(ApplicationState* state) { - VkDescriptorPoolSize pool_size[2] = {0}; - pool_size[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + VkDescriptorPoolSize pool_size[1] = {0}; + pool_size[0].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; pool_size[0].descriptorCount = 1; - pool_size[1].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - pool_size[1].descriptorCount = 1; VkDescriptorPoolCreateInfo pool_info = {0}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -534,42 +546,26 @@ void create_descriptor_sets(ApplicationState* state) { exit(1); } - create_buffer(state, sizeof(uint32_t), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &state->compute.input_buffer, &state->compute.input_buffer_memory); create_buffer(state, sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - &state->compute.output_buffer, &state->compute.output_buffer_memory); + &state->compute.input_buffer, &state->compute.input_buffer_memory); VkDescriptorBufferInfo in_buffer_info = {0}; - VkDescriptorBufferInfo out_buffer_info = {0}; in_buffer_info.buffer = state->compute.input_buffer; in_buffer_info.range = sizeof(uint32_t); - out_buffer_info.buffer = state->compute.output_buffer; - out_buffer_info.range = sizeof(uint32_t); - - VkWriteDescriptorSet descriptor_writes[2] = {0}; + VkWriteDescriptorSet descriptor_writes[1] = {0}; descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptor_writes[0].dstSet = state->compute.descriptor_sets; descriptor_writes[0].dstBinding = 0; descriptor_writes[0].dstArrayElement = 0; - descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; descriptor_writes[0].descriptorCount = 1; descriptor_writes[0].pBufferInfo = &in_buffer_info; descriptor_writes[0].pImageInfo = NULL; descriptor_writes[0].pTexelBufferView = NULL; - descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptor_writes[1].dstSet = state->compute.descriptor_sets; - descriptor_writes[1].dstBinding = 1; - descriptor_writes[1].dstArrayElement = 0; - descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptor_writes[1].descriptorCount = 1; - descriptor_writes[1].pBufferInfo = &out_buffer_info; - descriptor_writes[1].pImageInfo = NULL; - descriptor_writes[1].pTexelBufferView = NULL; - vkUpdateDescriptorSets(state->device, ARRSIZE(descriptor_writes), descriptor_writes, 0, NULL); printf("allocated and written descriptor sets\n"); @@ -595,7 +591,7 @@ void init_vulkan(ApplicationState* state) { pick_physical_device(state); create_logical_device(state); create_descriptor_set_layout(state); - create_compute_pipeline(state); + create_compute_pipelines(state); create_descriptor_pool(state); create_descriptor_sets(state); setup_compute_queues(state); @@ -607,12 +603,11 @@ void terminate(ApplicationState* state) { // vkDestroyCommandPool(state->device, state->compute.command_pool, NULL); vkFreeMemory(state->device, state->compute.input_buffer_memory, NULL); - vkFreeMemory(state->device, state->compute.output_buffer_memory, NULL); vkDestroyBuffer(state->device, state->compute.input_buffer, NULL); - vkDestroyBuffer(state->device, state->compute.output_buffer, NULL); vkDestroyDescriptorPool(state->device, state->compute.descriptor_pool, NULL); - vkDestroyPipeline(state->device, state->compute.pipeline, NULL); + vkDestroyPipeline(state->device, state->compute.pipeline[0], NULL); + vkDestroyPipeline(state->device, state->compute.pipeline[1], NULL); vkDestroyPipelineLayout(state->device, state->compute.pipeline_layout, NULL); vkDestroyDescriptorSetLayout(state->device, state->compute.descriptor_set_layout, NULL); vkDestroyCommandPool(state->device, state->compute.command_pool, NULL); @@ -634,10 +629,18 @@ int main() { exit(1); } - vkCmdBindPipeline(state.compute.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, state.compute.pipeline); + vkCmdBindPipeline(state.compute.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, state.compute.pipeline[0]); vkCmdBindDescriptorSets(state.compute.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, state.compute.pipeline_layout, 0, 1, &state.compute.descriptor_sets, 0, NULL); vkCmdDispatch(state.compute.command_buffer, 1, 1, 1); + vkCmdBindPipeline(state.compute.command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, state.compute.pipeline[1]); + struct VkMemoryBarrier barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + vkCmdPipelineBarrier(state.compute.command_buffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &barrier, 0, NULL, 0, NULL); + vkCmdDispatch(state.compute.command_buffer, 1, 1, 1); printf("start recording command buffer\n"); @@ -667,10 +670,7 @@ int main() { vkWaitForFences(state.device, 1, &state.compute.compute_done, VK_TRUE, UINT64_MAX); vkQueueWaitIdle(state.compute.queue); - vkMapMemory(state.device, state.compute.output_buffer_memory, 0, sizeof(uint32_t), 0, (void**)&data); printf("submit complete, result: %X\n", *data); - vkUnmapMemory(state.device, state.compute.output_buffer_memory); - terminate(&state);