From c4a6f4bbaaf86d50d5da103894469a9bc12a1323 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Sat, 18 Jan 2025 23:48:11 +0100 Subject: Working api prototype --- .gitmodules | 3 + api-test/CMakeLists.txt | 10 +- api-test/command-buffer.cpp | 68 +++- api-test/main.cpp | 238 ++++++++------ api-test/vk-bindless.cpp | 209 ++++++++---- api-test/vk-device.cpp | 605 +++++++++++++++++++++++------------ include/api-test/command-buffer.hpp | 35 +- include/api-test/handle.hpp | 2 + include/api-test/vk-bindless.hpp | 24 +- include/api-test/vk-device-types.hpp | 92 +++++- include/api-test/vk-device.hpp | 72 +++-- shaders/api-test-ui.frag | 20 +- shaders/api-test-ui.vert | 19 +- 13 files changed, 969 insertions(+), 428 deletions(-) diff --git a/.gitmodules b/.gitmodules index 53e4058..e1fdc4f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "vcpkg"] path = vcpkg url = git@github.com:microsoft/vcpkg.git +[submodule "tracy"] + path = tracy + url = git@github.com:wolfpld/tracy.git diff --git a/api-test/CMakeLists.txt b/api-test/CMakeLists.txt index dc92ee3..b41c325 100644 --- a/api-test/CMakeLists.txt +++ b/api-test/CMakeLists.txt @@ -8,12 +8,18 @@ add_executable( ${CMAKE_SOURCE_DIR}/src/window.cpp ${CMAKE_SOURCE_DIR}/src/utils.cpp ${CMAKE_SOURCE_DIR}/src/vulkan-loader.cpp + ${CMAKE_SOURCE_DIR}/src/gltf.cpp + ${CMAKE_SOURCE_DIR}/src/vec3.cpp + ${CMAKE_SOURCE_DIR}/src/mesh.cpp + ${CMAKE_SOURCE_DIR}/src/scene.cpp + ${CMAKE_SOURCE_DIR}/src/camera.cpp + ${CMAKE_SOURCE_DIR}/src/bvh.cpp ) -target_compile_definitions(api-test PUBLIC WINDOWS VK_NO_PROTOTYPES VK_USE_PLATFORM_WIN32_KHR) +target_compile_definitions(api-test PUBLIC WINDOWS VK_NO_PROTOTYPES VK_USE_PLATFORM_WIN32_KHR API_TEST NOMINMAX) target_compile_options(api-test - PRIVATE -Wall -Wextra + PRIVATE -Wall -Wextra -msse4.1 ) target_include_directories(api-test SYSTEM PUBLIC ${Vulkan_INCLUDE_DIRS}) diff --git a/api-test/command-buffer.cpp b/api-test/command-buffer.cpp index 79b8aef..d694f9f 100644 --- a/api-test/command-buffer.cpp +++ b/api-test/command-buffer.cpp @@ -1,6 +1,5 @@ #include "command-buffer.hpp" -#include #include #include "vulkan-loader.hpp" @@ -20,11 +19,18 @@ void command_buffer::start() const { const auto& bindless = vkdevice::get_render_device().get_bindingmodel(); const auto* global_set = &bindless.sets[BindlessSetType::GLOBAL]; + // const auto global_uniforms = bindless.get_globals_uniform_buffer(); + // if (queue_type == QueueType::GRAPHICS) { + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.graphics_layout, 0, 1U, global_set, 1U, &global_uniforms.offset); + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 1U, &global_uniforms.offset); + // } else if (queue_type == QueueType::ASYNC_COMPUTE) { + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 1U, &global_uniforms.offset); + // } if (queue_type == QueueType::GRAPHICS) { - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.layout, 0, 1U, global_set, 0U, nullptr); - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, 0, 1U, global_set, 0U, nullptr); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.graphics_layout, 0, 1U, global_set, 0U, nullptr); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 0U, nullptr); } else if (queue_type == QueueType::ASYNC_COMPUTE) { - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, 0, 1U, global_set, 0U, nullptr); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 0U, nullptr); } } @@ -107,12 +113,19 @@ void command_buffer::copy(handle buffer_handle, ::handle(BindlessSetType::INSTANCES_UNIFORMS), 1U, &bindless.sets[BindlessSetType::INSTANCES_UNIFORMS], 1U, ¶ms.uniforms_offset); - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, static_cast(BindlessSetType::INSTANCES_UNIFORMS), 1U, &bindless.sets[BindlessSetType::INSTANCES_UNIFORMS], 1U, ¶ms.uniforms_offset); + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); + + for (uint32_t push_index = 0U; push_index < bindless_model::max_push_constants_slots; push_index++) { + vkCmdPushConstants(vk_command_buffer, bindless.compute_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_index * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.params[push_index]); + } vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); - vkCmdDispatch(vk_command_buffer, params.group_size.x / params.local_group_size.x, params.group_size.y / params.local_group_size.y, params.group_size.z / params.local_group_size.z); + auto x = params.group_size.vec.x / params.local_group_size.vec.x; + auto y = params.group_size.vec.y / params.local_group_size.vec.y; + auto z = params.group_size.vec.z / params.local_group_size.vec.z; + vkCmdDispatch(vk_command_buffer, x, y, z); } void graphics_command_buffer::begin_renderpass(const renderpass_params& params) const { @@ -172,24 +185,47 @@ void graphics_command_buffer::begin_renderpass(const renderpass_params& params) vkCmdSetScissor(vk_command_buffer, 0U, 1U, &scissor); vkCmdSetViewport(vk_command_buffer, 0U, 1U, &viewport); + + // auto& device = vkdevice::get_render_device(); + // const auto& bindless = device.get_bindingmodel(); + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, static_cast(BindlessSetType::GLOBAL), 1U, &bindless.sets[BindlessSetType::GLOBAL], 1U, ¶ms.uniforms_offset); + // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.layout, static_cast(BindlessSetType::GLOBAL), 1U, &bindless.sets[BindlessSetType::GLOBAL], 1U, ¶ms.uniforms_offset); } -void graphics_command_buffer::render(const draw_params& params) const { +void graphics_command_buffer::draw(const draw_params& params) const { auto& device = vkdevice::get_render_device(); const auto& pipeline = device.get_pipeline(params.pipeline); const auto& bindless = device.get_bindingmodel(); - vkCmdBindDescriptorSets(vk_command_buffer, pipeline.bind_point, bindless.layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); + // vkCmdBindDescriptorSets(vk_command_buffer, pipeline.bind_point, bindless.layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); - if (params.index_buffer.is_valid()) { - const auto& index_buffer = device.get_buffer(params.index_buffer); - vkCmdBindIndexBuffer(vk_command_buffer, index_buffer.vk_buffer, 0U, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(vk_command_buffer, params.vertex_count, params.instance_count, params.index_offset, static_cast(params.vertex_offset), 0U); - } else { - vkCmdDraw(vk_command_buffer, params.vertex_count, params.instance_count, params.vertex_offset, 0U); - } + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::GLOBALS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.globals_address); + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::INSTANCES * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.instances_address); + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::DRAWS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.uniforms_address); + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::VERTEX_BUFFER * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.vertex_address); + + vkCmdDraw(vk_command_buffer, params.vertex_count, params.instance_count, params.vertex_offset, 0U); +} + +void graphics_command_buffer::draw_indexed(const draw_indexed_params& params) const { + auto& device = vkdevice::get_render_device(); + const auto& pipeline = device.get_pipeline(params.pipeline); + + const auto& bindless = device.get_bindingmodel(); + // vkCmdBindDescriptorSets(vk_command_buffer, pipeline.bind_point, bindless.layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); + + vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); + + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::GLOBALS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.globals_address); + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::INSTANCES * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.instances_address); + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::DRAWS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.uniforms_address); + vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::VERTEX_BUFFER * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.vertex_address); + + const auto& index_buffer = device.get_buffer(params.index_buffer); + vkCmdBindIndexBuffer(vk_command_buffer, index_buffer.vk_buffer, 0U, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_command_buffer, params.vertex_count, params.instance_count, params.index_offset, static_cast(params.vertex_offset), 0U); } void graphics_command_buffer::end_renderpass() const { diff --git a/api-test/main.cpp b/api-test/main.cpp index 583bced..0761070 100644 --- a/api-test/main.cpp +++ b/api-test/main.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -22,6 +21,9 @@ struct device_texture; #define ENABLE_RENDERDOC #endif // _DEBUG +#include "camera.hpp" +#include "scene.hpp" + #ifdef ENABLE_RENDERDOC #include @@ -93,9 +95,19 @@ int main() { io.DisplaySize.x = window_width; io.DisplaySize.y = window_height; + const float aspect_ratio = 16.0 / 9.0; + + point3 position { 13.f, 2.f, -3.f }; + point3 target {}; + const auto v_fov = 90.f; + const auto aperture = 0.1f; + const auto focus_distance = 10.f; + auto& device = vkdevice::get_render_device(); device.init(); + auto main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), window_width, window_height); + auto surface_handle = device.create_surface({ .window_handle = wnd.handle, .surface_format = { @@ -103,7 +115,7 @@ int main() { .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, }, .present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR, - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, }); auto& surface = device.get_surface(surface_handle); @@ -190,38 +202,47 @@ int main() { auto index_buffer = device.get_buffer(index_buffer_handle); auto code = read_file("shaders/test.comp.spv"); - auto compute = device.create_pipeline({ + auto compute = device.create_compute_pipeline({ .cs_code = code, }); + auto rt_code = read_file("shaders/compute.comp.spv"); + auto raytracing = device.create_compute_pipeline({ + .cs_code = rt_code, + }); + auto tonemapping_code = read_file("shaders/tonemapping.comp.spv"); + auto tonemapping = device.create_compute_pipeline({ + .cs_code = tonemapping_code, + }); + const auto acc_handle = device.create_texture({ + .width = static_cast(window_width), + .height = static_cast(window_height), + .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .type = VK_IMAGE_TYPE_2D, + }); + auto acc_storage_index = device.get_texture(acc_handle).get_storage_index(); + + const auto result_handle = device.create_texture({ + .width = static_cast(window_width), + .height = static_cast(window_height), + .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .type = VK_IMAGE_TYPE_2D, + }); + auto result_storage_index = device.get_texture(result_handle).get_storage_index(); + std::array formats { surface.surface_format.format }; auto vertex_code = read_file("shaders/api-test-ui.vert.spv"); auto fragment_code = read_file("shaders/api-test-ui.frag.spv"); - auto graphics = device.create_pipeline({ + auto graphics = device.create_graphics_pipeline({ .vs_code = vertex_code, .fs_code = fragment_code, .color_attachments_format = formats }); - auto semaphore = device.create_semaphore({ - .type = VK_SEMAPHORE_TYPE_TIMELINE, - }); - constexpr uint32_t virtual_frames_count = 2U; - handle submit_semaphores[virtual_frames_count]; - for (auto& submit_semaphore : submit_semaphores) { - submit_semaphore = device.create_semaphore({ - .type = VK_SEMAPHORE_TYPE_BINARY, - }); - } - handle acquire_semaphores[virtual_frames_count]; - for (auto& acquire_semaphore : acquire_semaphores) { - acquire_semaphore = device.create_semaphore({ - .type = VK_SEMAPHORE_TYPE_BINARY, - }); - } - std::array graphics_command_buffers; - device.allocate_command_buffers(graphics_command_buffers, QueueType::GRAPHICS); + device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), QueueType::GRAPHICS); RD_START_CAPTURE; @@ -237,47 +258,38 @@ int main() { graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); - struct compute_params { - uint32_t input1; - uint32_t input2; - uint32_t output; - }; - const auto& uniform_buffer = device.get_bindingmodel().get_uniform_buffer(); - compute_params params { - device.get_texture(second_texture).get_storage_index(), - device.get_texture(gpu_texture_handle).get_storage_index(), - device.get_texture(output_texture_handle).get_storage_index(), - }; - memcpy(uniform_buffer.mapped_ptr, ¶ms, sizeof(params)); - - graphics_command_buffers[0].dispatch({ - .pipeline = compute, - .group_size = { .vec = { image_size, image_size, 1U }}, - .local_group_size = { .vec = { 8U, 8U, 1U }}, - .uniforms_offset = 0U, - }); + { + graphics_command_buffers[0].dispatch({ + .pipeline = compute, + .group_size = { .vec = { image_size, image_size, 1U }}, + .local_group_size = { .vec = { 8U, 8U, 1U }}, + .params = { + device.get_texture(second_texture).get_storage_index(), // Input 1 + device.get_texture(gpu_texture_handle).get_storage_index(), // Input 2 + device.get_texture(output_texture_handle).get_storage_index(), // Output + }, + }); + } graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); graphics_command_buffers[0].stop(); - device.submit(std::span { static_cast(graphics_command_buffers.data()), 1 }, {}, semaphore); + device.submit(graphics_command_buffers.data(), 1); + device.wait(); RD_END_CAPTURE; - // std::array ui_command_buffers = {command_buffers[1]}; std::array, 1U> color_attachment {}; - uint32_t frame_time; + constexpr uint32_t virtual_frames_count = 2U; + uint32_t frame_time = 1U; uint32_t frame_count = 0U; while(wnd.isOpen) { auto start = std::chrono::system_clock::now(); wnd.poll_events(); uint32_t virtual_frame_index = frame_count % virtual_frames_count; - auto& submit_semaphore = submit_semaphores[virtual_frame_index]; - auto& acquire_semaphore = acquire_semaphores[virtual_frame_index]; - auto command_buffers = std::span { static_cast(graphics_command_buffers.data() + virtual_frame_index + 1U), 1 }; - graphics_command_buffer& command_buffer = graphics_command_buffers[virtual_frame_index + 1U]; + auto command_buffer = graphics_command_buffers[2U + virtual_frame_index]; for (auto& event : wnd.events) { if (event.type == EVENT_TYPES::MOUSE_MOVE) { io.MousePos.x = static_cast(event.x); @@ -292,16 +304,71 @@ int main() { auto* draw_data = ImGui::GetDrawData(); update_buffers(draw_data, vertex_buffer, index_buffer); - // device.wait(semaphore); - device.wait(submit_semaphore); + const auto& scene_buffer = device.get_buffer(main_scene.scene_buffer_handle); + main_scene.meta.sample_index = frame_count; + uint8_t* ptr = static_cast(scene_buffer.mapped_ptr); + memcpy(static_cast(ptr), &main_scene.meta, sizeof(main_scene.meta)); + memcpy(static_cast(ptr + sizeof(main_scene.meta)), &main_scene.meta, sizeof(main_scene.meta)); + memcpy(static_cast(ptr + sizeof(main_scene.meta) * 2U), &main_scene.meta, sizeof(main_scene.meta)); - surface.acquire_image_index(acquire_semaphore); - color_attachment[0] = surface.get_backbuffer_image(); + // TODO: Refactor backbuffer acquisition + auto backbuffer = surface.swapchain_images[device.acquire_image_index(surface_handle)]; + color_attachment[0] = backbuffer; RD_START_CAPTURE; - command_buffer.start(), + command_buffer.start(); + + command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + { + uint64_t textures = (virtual_frame_index == 0U) ? ((uint64_t(acc_storage_index) << 32U) | result_storage_index) : ((uint64_t(result_storage_index) << 32U) | acc_storage_index); + + if (virtual_frame_index == 0) { + command_buffer.barrier(result_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + command_buffer.barrier(acc_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL); + } else { + command_buffer.barrier(result_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL); + command_buffer.barrier(acc_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + } + + command_buffer.dispatch({ + .pipeline = raytracing, + .group_size = { .vec { window_width, window_height, 1U, } }, + .local_group_size = { .vec { 8U, 8U, 1U, } }, + .params = { + main_scene.scene_buffer_address(), + main_scene.bvh_buffer_address(), + main_scene.indices_buffer_address(), + main_scene.positions_buffer_address(), + main_scene.normals_buffer_address(), + main_scene.uvs_buffer_address(), + main_scene.materials_buffer_address(), + textures, + }, + }); + + // TODO: Refactor backbuffer acquisition + auto backbuffer_storage_index = device.get_texture(backbuffer).get_storage_index(); + uint64_t out = (virtual_frame_index == 0U) ? ((uint64_t(result_storage_index) << 32U) | backbuffer_storage_index) : ((uint64_t(acc_storage_index) << 32U) | backbuffer_storage_index); + command_buffer.dispatch({ + .pipeline = tonemapping, + .group_size = { .vec { window_width, window_height, 1U, } }, + .local_group_size = { .vec { 8U, 8U, 1U, } }, + .params = { + main_scene.scene_buffer_address(), + main_scene.bvh_buffer_address(), + main_scene.indices_buffer_address(), + main_scene.positions_buffer_address(), + main_scene.normals_buffer_address(), + main_scene.uvs_buffer_address(), + main_scene.materials_buffer_address(), + out, + }, + }); + } + + command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - command_buffer.barrier(surface.get_backbuffer_image(), VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, VK_ACCESS_2_NONE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); command_buffer.begin_renderpass({ .render_area = { .x = static_cast(draw_data->DisplayPos.x), @@ -312,21 +379,20 @@ int main() { .color_attachments = color_attachment, }); - struct draw_params { - uintptr_t vertex_buffer; - float scale[2U]; - float translate[2U]; - uint32_t texture_index; - }; - - uint32_t draw_index = 0U; - std::array draws; + auto& draws_uniform_buffer = device.get_bindingmodel().get_draws_uniform_buffer(); for (auto index {0} ; index < draw_data->CmdListsCount; index++) { auto* cmd_list = draw_data->CmdLists[index]; - - for (auto& draw_command : cmd_list->CmdBuffer) { - draws[draw_index] = draw_params{ - .vertex_buffer = vertex_buffer.device_address, + auto offset = draws_uniform_buffer.offset; + { + struct ui_params { + // uintptr_t vertex_buffer; + float scale[2U]; + float translate[2U]; + uint32_t texture_index; + }; + auto* ui_param = draws_uniform_buffer.allocate(); + *ui_param = ui_params{ + // .vertex_buffer = vertex_buffer.device_address, .scale { 2.f / draw_data->DisplaySize.x, 2.f / draw_data->DisplaySize.y, @@ -337,60 +403,52 @@ int main() { }, .texture_index = ui_texture.get_sampled_index(), }; + } - command_buffer.render({ + for (auto& draw_command : cmd_list->CmdBuffer) { + command_buffer.draw_indexed({ .pipeline = graphics, .index_buffer = index_buffer_handle, .vertex_count = draw_command.ElemCount, .vertex_offset = draw_command.VtxOffset, .index_offset = draw_command.IdxOffset, .instance_count = 1U, - .uniforms_offset = 0U, + .uniforms_address = draws_uniform_buffer.device_address + offset, + .vertex_address = vertex_buffer.device_address, }); - - draw_index++; } } - memcpy(uniform_buffer.mapped_ptr, draws.data(), sizeof(draw_params) * draw_index); - command_buffer.end_renderpass(); - command_buffer.barrier(surface.get_backbuffer_image(), VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); command_buffer.stop(); - // device.submit(command_buffers, acquire_semaphore, semaphore); - // device.wait(semaphore); - // device.present(surface_handle, {}); - - device.submit(command_buffers, acquire_semaphore, submit_semaphore); - device.present(surface_handle, submit_semaphore); + device.submit_before_present(surface_handle, &command_buffer, 1U); + device.present(surface_handle); + device.wait(); auto end = std::chrono::system_clock::now(); frame_time = std::chrono::duration_cast(end - start).count(); + frame_count++; RD_END_CAPTURE; } - device.wait(semaphore); - + device.wait(); device.destroy_surface(surface_handle); device.destroy_pipeline(compute); device.destroy_pipeline(graphics); - - device.destroy_semaphore(semaphore); - for (auto& submit_semaphore : submit_semaphores) { - device.destroy_semaphore(submit_semaphore); - } - for (auto& acquire_semaphore : acquire_semaphores) { - device.destroy_semaphore(acquire_semaphore); - } + device.destroy_pipeline(raytracing); + device.destroy_pipeline(tonemapping); device.destroy_texture(gpu_texture_handle); device.destroy_texture(second_texture); device.destroy_texture(output_texture_handle); device.destroy_texture(ui_texture_handle); + device.destroy_texture(acc_handle); + device.destroy_texture(result_handle); device.destroy_buffer(staging_buffer_handle); device.destroy_buffer(vertex_buffer_handle); diff --git a/api-test/vk-bindless.cpp b/api-test/vk-bindless.cpp index 66fd59c..d3d6415 100644 --- a/api-test/vk-bindless.cpp +++ b/api-test/vk-bindless.cpp @@ -1,12 +1,18 @@ #include "vk-bindless.hpp" #include +#include #include "vk-device.hpp" #include "vk-utils.hpp" #include "vulkan-loader.hpp" -const device_buffer& bindless_model::get_uniform_buffer() const { +device_buffer& bindless_model::get_globals_uniform_buffer() const { + auto& render_device = vkdevice::get_render_device(); + return render_device.get_buffer(globals_uniform_buffer_handle); +} + +device_buffer& bindless_model::get_draws_uniform_buffer() const { auto& render_device = vkdevice::get_render_device(); return render_device.get_buffer(draws_uniform_buffer_handle); } @@ -21,67 +27,96 @@ bindless_model bindless_model::create_bindless_model() { bindless.create_descriptor_pool(device); bindless.allocate_sets(device); - VkWriteDescriptorSet writes_descriptor_set[2U]; + // VkWriteDescriptorSet writes_descriptor_set[BindlessSetType::MAX]; - { - bindless.instances_uniform_buffer_handle = render_device.create_buffer({ - .size = instances_uniform_buffer_size, + // { + bindless.globals_uniform_buffer_handle = render_device.create_buffer({ + .size = globals_uniform_buffer_size, .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, }); - const auto& buffer = render_device.get_buffer(bindless.instances_uniform_buffer_handle); - VkDescriptorBufferInfo buffer_info { - .buffer = buffer.vk_buffer, - .offset = 0U, - .range = VK_WHOLE_SIZE, - }; - - writes_descriptor_set[0U] = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = nullptr, - .dstSet = bindless.sets[BindlessSetType::INSTANCES_UNIFORMS], - .dstBinding = 0U, - .dstArrayElement = 0U, - .descriptorCount = 1U, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .pImageInfo = nullptr, - .pBufferInfo = &buffer_info, - .pTexelBufferView = nullptr, - }; - } - - { + // const auto& buffer = render_device.get_buffer(bindless.globals_uniform_buffer_handle); + // VkDescriptorBufferInfo buffer_info { + // .buffer = buffer.vk_buffer, + // .offset = 0U, + // .range = VK_WHOLE_SIZE, + // }; + + // writes_descriptor_set[BindlessSetType::GLOBAL] = { + // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + // .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + // .dstBinding = 3U, + // .dstArrayElement = 0U, + // .descriptorCount = 1U, + // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + // .pImageInfo = nullptr, + // .pBufferInfo = &buffer_info, + // .pTexelBufferView = nullptr, + // }; + // } + + // { + // bindless.instances_uniform_buffer_handle = render_device.create_buffer({ + // .size = instances_uniform_buffer_size, + // .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + // .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + // .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + // }); + + // const auto& buffer = render_device.get_buffer(bindless.instances_uniform_buffer_handle); + // VkDescriptorBufferInfo buffer_info { + // .buffer = buffer.vk_buffer, + // .offset = 0U, + // .range = VK_WHOLE_SIZE, + // }; + + // writes_descriptor_set[BindlessSetType::INSTANCES_UNIFORMS] = { + // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + // .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::INSTANCES_UNIFORMS], + // .dstBinding = 0U, + // .dstArrayElement = 0U, + // .descriptorCount = 1U, + // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + // .pImageInfo = nullptr, + // .pBufferInfo = &buffer_info, + // .pTexelBufferView = nullptr, + // }; + // } + + // { bindless.draws_uniform_buffer_handle = render_device.create_buffer({ .size = draws_uniform_buffer_size, - .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, }); - const auto& buffer = render_device.get_buffer(bindless.draws_uniform_buffer_handle); - VkDescriptorBufferInfo buffer_info { - .buffer = buffer.vk_buffer, - .offset = 0U, - .range = VK_WHOLE_SIZE, - }; - - writes_descriptor_set[1U] = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = nullptr, - .dstSet = bindless.sets[BindlessSetType::DRAWS_UNIFORMS], - .dstBinding = 0U, - .dstArrayElement = 0U, - .descriptorCount = 1U, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .pImageInfo = nullptr, - .pBufferInfo = &buffer_info, - .pTexelBufferView = nullptr, - }; - } - - vkUpdateDescriptorSets(device, sizeof(writes_descriptor_set) / sizeof(VkWriteDescriptorSet), writes_descriptor_set, 0U, nullptr); + // const auto& buffer = render_device.get_buffer(bindless.draws_uniform_buffer_handle); + // VkDescriptorBufferInfo buffer_info { + // .buffer = buffer.vk_buffer, + // .offset = 0U, + // .range = draws_uniform_buffer_size, + // }; + + // writes_descriptor_set[BindlessSetType::DRAWS_UNIFORMS] = { + // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + // .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::DRAWS_UNIFORMS], + // .dstBinding = 0U, + // .dstArrayElement = 0U, + // .descriptorCount = 1U, + // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + // .pImageInfo = nullptr, + // .pBufferInfo = &buffer_info, + // .pTexelBufferView = nullptr, + // }; + // } + + // vkUpdateDescriptorSets(device, sizeof(writes_descriptor_set) / sizeof(VkWriteDescriptorSet), writes_descriptor_set, 0U, nullptr); #else VkBufferCreateInfo create_info{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, @@ -126,11 +161,12 @@ void bindless_model::destroy_bindless_model(bindless_model& bindless) { vkDestroyDescriptorSetLayout(device, bindless.sets_layout[index], nullptr); } - vkDestroyPipelineLayout(device, bindless.layout, nullptr); + vkDestroyPipelineLayout(device, bindless.graphics_layout, nullptr); + vkDestroyPipelineLayout(device, bindless.compute_layout, nullptr); bindless.destroy_immutable_samplers(device); - render_device.destroy_buffer(bindless.instances_uniform_buffer_handle); + // render_device.destroy_buffer(bindless.instances_uniform_buffer_handle); render_device.destroy_buffer(bindless.draws_uniform_buffer_handle); } @@ -139,6 +175,7 @@ void bindless_model::create_layout(VkDevice device) { // Binding 0 Storage images // Binding 1 Sampled images // Binding 2 Samplers + // Binding 3 Dynamic Uniform Buffer { VkDescriptorSetLayoutBinding set_layout_bindings[]{ { @@ -162,12 +199,21 @@ void bindless_model::create_layout(VkDevice device) { .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, .pImmutableSamplers = nullptr, }, + // { + // .binding = 3U, + // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + // .descriptorCount = 1U, + // .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + // .pImmutableSamplers = nullptr, + // }, }; VkDescriptorBindingFlags flags[]{ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + // VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, + // 0U, }; VkDescriptorSetLayoutBindingFlagsCreateInfo layout_binding_flags{ @@ -195,7 +241,7 @@ void bindless_model::create_layout(VkDevice device) { { .binding = 0U, .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = 1, + .descriptorCount = 1U, .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, .pImmutableSamplers = nullptr, }, @@ -236,17 +282,50 @@ void bindless_model::create_layout(VkDevice device) { VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::DRAWS_UNIFORMS])); } - VkPipelineLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .setLayoutCount = sizeof(sets_layout) / sizeof(VkDescriptorSetLayout), - .pSetLayouts = sets_layout, - .pushConstantRangeCount = 0U, - .pPushConstantRanges = nullptr, - }; + { + VkPushConstantRange push_constants[] { + { + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = 0U, + .size = max_push_constants_slots_size * (max_push_constants_slots), + }, + }; + + VkPipelineLayoutCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .setLayoutCount = sizeof(sets_layout) / sizeof(VkDescriptorSetLayout), + .pSetLayouts = sets_layout, + .pushConstantRangeCount = sizeof(push_constants) / sizeof(push_constants[0]), + .pPushConstantRanges = push_constants, + }; + + VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &graphics_layout)); + } + + { + VkPushConstantRange push_constants[] { + { + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, + .offset = 0U, + .size = max_push_constants_slots_size * max_push_constants_slots, + }, + }; + - VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &layout)); + VkPipelineLayoutCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .setLayoutCount = sizeof(sets_layout) / sizeof(VkDescriptorSetLayout), + .pSetLayouts = sets_layout, + .pushConstantRangeCount = sizeof(push_constants) / sizeof(push_constants[0]), + .pPushConstantRanges = push_constants, + }; + + VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &compute_layout)); + } } #ifndef USE_VK_DESCRIPTOR_BUFFER @@ -266,7 +345,7 @@ void bindless_model::create_descriptor_pool(VkDevice device) { }, { .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = set_descriptors_count, + .descriptorCount = 8U, }, }; @@ -307,7 +386,7 @@ void bindless_model::create_immutable_samplers(VkDevice device) { .mipLodBias = 0.f, .anisotropyEnable = VK_FALSE, .compareEnable = VK_FALSE, - .compareOp = VK_COMPARE_OP_ALWAYS, + .compareOp = VK_COMPARE_OP_NEVER, .minLod = 0.f, .maxLod = 0.f, .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, diff --git a/api-test/vk-device.cpp b/api-test/vk-device.cpp index 2b9f7eb..e1d671f 100644 --- a/api-test/vk-device.cpp +++ b/api-test/vk-device.cpp @@ -37,6 +37,11 @@ void vkdevice::init() { create_memory_allocator(); bindless = bindless_model::create_bindless_model(); + + auto semaphore = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_TIMELINE, + }); + timeline_semaphore = get_semaphore(semaphore); } vkdevice::~vkdevice() { @@ -50,6 +55,8 @@ vkdevice::~vkdevice() { vkDestroyCommandPool(device, queue.command_pool, nullptr); } + vkDestroySemaphore(device, timeline_semaphore.vk_semaphore, nullptr); + vkDestroyDevice(device, nullptr); #ifdef _DEBUG @@ -59,6 +66,8 @@ vkdevice::~vkdevice() { vkDestroyInstance(instance, nullptr); } +void vkdevice::wait() { vkDeviceWaitIdle(device); }; + handle vkdevice::create_texture(const texture_desc& desc) { device_texture device_texture; device_texture.init(desc); @@ -66,6 +75,13 @@ handle vkdevice::create_texture(const texture_desc& desc) { return textures.add(device_texture); } +handle vkdevice::create_sampler(const sampler_desc& desc) { + device_sampler device_sampler; + device_sampler.init(desc); + + return samplers.add(device_sampler); +} + handle vkdevice::create_buffer(const buffer_desc& desc) { device_buffer device_buffer{ .size = desc.size, @@ -113,172 +129,177 @@ handle vkdevice::create_buffer(const buffer_desc& desc) { return buffers.add(device_buffer); } -handle vkdevice::create_pipeline(const pipeline_desc& desc) { +handle vkdevice::create_graphics_pipeline(const graphics_pipeline_desc& desc) { device_pipeline device_pipeline{ }; - if (!desc.cs_code.empty()) { - VkPipelineShaderStageCreateInfo stage_create_info{ + + VkPipelineShaderStageCreateInfo shader_stages_create_info[2U]{ { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .pNext = nullptr, .flags = 0U, - .stage = VK_SHADER_STAGE_COMPUTE_BIT, - .module = create_shader_module(desc.cs_code), + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = create_shader_module(desc.vs_code), .pName = "main", .pSpecializationInfo = nullptr, - }; + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = create_shader_module(desc.fs_code), + .pName = "main", + .pSpecializationInfo = nullptr, + }, + }; - VkComputePipelineCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .stage = stage_create_info, - .layout = bindless.layout, - .basePipelineHandle = nullptr, - .basePipelineIndex = 0, - }; + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + }; - device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; - VKCHECK(vkCreateComputePipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); + VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; - vkDestroyShaderModule(device, stage_create_info.module, nullptr); - } else { - VkPipelineShaderStageCreateInfo shader_stages_create_info[2U]{ - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = create_shader_module(desc.vs_code), - .pName = "main", - .pSpecializationInfo = nullptr, - }, - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = create_shader_module(desc.fs_code), - .pName = "main", - .pSpecializationInfo = nullptr, - }, - }; + VkPipelineViewportStateCreateInfo viewport_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .viewportCount = 1U, + .pViewports = nullptr, + .scissorCount = 1U, + .pScissors = nullptr, + }; - VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - }; + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .lineWidth = 1.f, + }; - VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - .primitiveRestartEnable = VK_FALSE, - }; + VkPipelineMultisampleStateCreateInfo multisample_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 1.f, + }; - VkPipelineViewportStateCreateInfo viewport_state_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .viewportCount = 1U, - .pViewports = nullptr, - .scissorCount = 1U, - .pScissors = nullptr, - }; + VkPipelineColorBlendAttachmentState color_attachment_state{ + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + }; - VkPipelineRasterizationStateCreateInfo rasterization_state_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .depthClampEnable = VK_FALSE, - .rasterizerDiscardEnable = VK_FALSE, - .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_NONE, - .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, - .depthBiasEnable = VK_FALSE, - .lineWidth = 1.f, - }; + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .attachmentCount = 1, + .pAttachments = &color_attachment_state, + }; - VkPipelineMultisampleStateCreateInfo multisample_state_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, - .sampleShadingEnable = VK_FALSE, - .minSampleShading = 1.f, - }; + VkDynamicState dynamic_states[]{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; - VkPipelineColorBlendAttachmentState color_attachment_state{ - .blendEnable = VK_TRUE, - .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .alphaBlendOp = VK_BLEND_OP_ADD, - .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, - }; + VkPipelineDynamicStateCreateInfo dynamic_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .dynamicStateCount = sizeof(dynamic_states) / sizeof(VkDynamicState), + .pDynamicStates = dynamic_states, + }; - VkPipelineColorBlendStateCreateInfo color_blend_state_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .logicOpEnable = VK_FALSE, - .attachmentCount = 1, - .pAttachments = &color_attachment_state, - }; + VkPipelineRenderingCreateInfo pipeline_rendering_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = nullptr, + .viewMask = 0U, + .colorAttachmentCount = static_cast(desc.color_attachments_format.size()), + .pColorAttachmentFormats = desc.color_attachments_format.data(), + .depthAttachmentFormat = VK_FORMAT_UNDEFINED, + .stencilAttachmentFormat = VK_FORMAT_UNDEFINED, + }; - VkDynamicState dynamic_states[]{ - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - }; + VkGraphicsPipelineCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &pipeline_rendering_create_info, + .flags = 0U, + .stageCount = sizeof(shader_stages_create_info) / sizeof(VkPipelineShaderStageCreateInfo), + .pStages = shader_stages_create_info, + .pVertexInputState = &vertex_input_state_create_info, + .pInputAssemblyState = &input_assembly_create_info, + .pTessellationState = nullptr, + .pViewportState = &viewport_state_create_info, + .pRasterizationState = &rasterization_state_create_info, + .pMultisampleState = &multisample_state_create_info, + .pDepthStencilState = nullptr, + .pColorBlendState = &color_blend_state_create_info, + .pDynamicState = &dynamic_state_create_info, + .layout = bindless.graphics_layout, + .renderPass = nullptr, + .subpass = 0U, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; - VkPipelineDynamicStateCreateInfo dynamic_state_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .dynamicStateCount = sizeof(dynamic_states) / sizeof(VkDynamicState), - .pDynamicStates = dynamic_states, - }; + device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; + VKCHECK(vkCreateGraphicsPipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); - VkPipelineRenderingCreateInfo pipeline_rendering_create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, - .pNext = nullptr, - .viewMask = 0U, - .colorAttachmentCount = static_cast(desc.color_attachments_format.size()), - .pColorAttachmentFormats = desc.color_attachments_format.data(), - .depthAttachmentFormat = VK_FORMAT_UNDEFINED, - .stencilAttachmentFormat = VK_FORMAT_UNDEFINED, - }; + for(auto& stage_create_info : shader_stages_create_info) { + vkDestroyShaderModule(device, stage_create_info.module, nullptr); + } - VkGraphicsPipelineCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = &pipeline_rendering_create_info, - .flags = 0U, - .stageCount = sizeof(shader_stages_create_info) / sizeof(VkPipelineShaderStageCreateInfo), - .pStages = shader_stages_create_info, - .pVertexInputState = &vertex_input_state_create_info, - .pInputAssemblyState = &input_assembly_create_info, - .pTessellationState = nullptr, - .pViewportState = &viewport_state_create_info, - .pRasterizationState = &rasterization_state_create_info, - .pMultisampleState = &multisample_state_create_info, - .pDepthStencilState = nullptr, - .pColorBlendState = &color_blend_state_create_info, - .pDynamicState = &dynamic_state_create_info, - .layout = bindless.layout, - .renderPass = nullptr, - .subpass = 0U, - .basePipelineHandle = nullptr, - .basePipelineIndex = 0, - }; + return pipelines.add(device_pipeline); +} - device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; - VKCHECK(vkCreateGraphicsPipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); +handle vkdevice::create_compute_pipeline(const compute_pipeline_desc& desc) { + device_pipeline device_pipeline{ + }; - for(auto& stage_create_info : shader_stages_create_info) { - vkDestroyShaderModule(device, stage_create_info.module, nullptr); - } - } + VkPipelineShaderStageCreateInfo stage_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = create_shader_module(desc.cs_code), + .pName = "main", + .pSpecializationInfo = nullptr, + }; + + VkComputePipelineCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = stage_create_info, + .layout = bindless.compute_layout, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; + + device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; + VKCHECK(vkCreateComputePipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); + + vkDestroyShaderModule(device, stage_create_info.module, nullptr); return pipelines.add(device_pipeline); } @@ -301,6 +322,17 @@ handle vkdevice::create_surface(const surface_desc& desc) { create_swapchain(desc, device_surface); + assert(surface_desc::max_image_count >= device_surface.image_count); + + for (uint32_t index = 0u; index < device_surface.image_count; index++) { + device_surface.acquire_semaphores[index] = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_BINARY, + }); + device_surface.submit_semaphores[index] = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_BINARY, + }); + } + return surfaces.add(device_surface); } @@ -355,39 +387,152 @@ void vkdevice::destroy_semaphore(handle handle) { } void vkdevice::destroy_surface(handle handle) { - const auto& surface = vkdevice::get_surface(handle); + auto& surface = vkdevice::get_surface(handle); for (auto texture_index{0U}; texture_index < surface.image_count; texture_index++) { auto texture_handle = surface.swapchain_images[texture_index]; destroy_texture(texture_handle); } + for (uint32_t index = 0u; index < surface.image_count; index++) { + destroy_semaphore(surface.acquire_semaphores[index]); + destroy_semaphore(surface.submit_semaphores[index]); + } + vkDestroySwapchainKHR(device, surface.vk_swapchain, nullptr); vkDestroySurfaceKHR(instance, surface.vk_surface, nullptr); } -void vkdevice::wait(handle semaphore_handle) { - const auto& semaphore = vkdevice::get_render_device().get_semaphore(semaphore_handle); - VkSemaphoreWaitInfo wait_info { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, - .pNext = nullptr, - .flags = 0U, - .semaphoreCount = 1U, - .pSemaphores = &semaphore.vk_semaphore, - .pValues = &semaphore.value, +// uint64_t vkdevice::submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle) { +// assert((max_submitable_command_buffers - buffers.size()) >= 0); +// const auto queue_type = buffers[0].queue_type; +// +// VkCommandBufferSubmitInfo command_buffers_info[buffers.size()]; +// +// for (auto index{ 0U }; index < buffers.size(); index++) { +// assert(queue_type == buffers[index].queue_type); +// +// auto& command_buffer_info = command_buffers_info[index]; +// command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; +// command_buffer_info.pNext = nullptr; +// command_buffer_info.commandBuffer = buffers[index].vk_command_buffer; +// command_buffer_info.deviceMask = 0U; +// } +// +// VkSemaphoreSubmitInfo wait_semaphore_info{ +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, +// .deviceIndex = 0U, +// }; +// +// VkSemaphoreSubmitInfo signal_semaphore_infos[2U]; +// +// VkSubmitInfo2 submit_info{ +// .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, +// .pNext = nullptr, +// .flags = 0U, +// .waitSemaphoreInfoCount = 0U, +// .commandBufferInfoCount = static_cast(buffers.size()), +// .pCommandBufferInfos = command_buffers_info, +// .pSignalSemaphoreInfos = signal_semaphore_infos, +// }; +// +// if (wait_handle.is_valid()) { +// const auto& wait = vkdevice::get_render_device().get_semaphore(wait_handle); +// wait_semaphore_info.semaphore = wait.vk_semaphore; +// wait_semaphore_info.value = wait.value; +// submit_info.waitSemaphoreInfoCount++; +// submit_info.pWaitSemaphoreInfos = &wait_semaphore_info; +// } +// +// if (signal_handle.is_valid()) { +// auto& signal = vkdevice::get_render_device().get_semaphore(signal_handle); +// signal_semaphore_infos[0U] = { +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .semaphore = signal.vk_semaphore, +// .value = signal.value, +// .stageMask = VK_PIPELINE_STAGE_2_NONE, +// .deviceIndex = 0U, +// }; +// submit_info.signalSemaphoreInfoCount++; +// } +// +// uint64_t ret = -1; +// +// if (fence_handle.is_valid()) { +// auto& fence = vkdevice::get_render_device().get_semaphore(fence_handle); +// auto fence_index = submit_info.signalSemaphoreInfoCount; +// signal_semaphore_infos[fence_index] = { +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .semaphore = fence.vk_semaphore, +// .value = ++fence.value, +// .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, +// .deviceIndex = 0U, +// }; +// ret = fence.value; +// } +// +// VKCHECK(vkQueueSubmit2(queues[static_cast(queue_type)].vk_queue, 1, &submit_info, nullptr)); +// +// return ret; +// } + +uint32_t vkdevice::submit(command_buffer* buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); + const auto queue_type = buffers[0].queue_type; + + VkCommandBufferSubmitInfo command_buffers_info[count]; + + for (auto index{ 0U }; index < count; index++) { + assert(queue_type == buffers[index].queue_type); + + auto& command_buffer_info = command_buffers_info[index]; + command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + command_buffer_info.pNext = nullptr; + command_buffer_info.commandBuffer = buffers[index].vk_command_buffer; + command_buffer_info.deviceMask = 0U; + } + + VkSubmitInfo2 submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0U, + .waitSemaphoreInfoCount = 0U, + .pWaitSemaphoreInfos = nullptr, + .commandBufferInfoCount = count, + .pCommandBufferInfos = command_buffers_info, }; - VKCHECK(vkWaitSemaphores(device, &wait_info, -1)); - vkDeviceWaitIdle(device); + + auto& fence = timeline_semaphore; + VkSemaphoreSubmitInfo signal_semaphore_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = fence.vk_semaphore, + .value = ++fence.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + }; + submit_info.signalSemaphoreInfoCount = sizeof(signal_semaphore_infos) / sizeof(signal_semaphore_infos[0U]); + submit_info.pSignalSemaphoreInfos = signal_semaphore_infos; + + VKCHECK(vkQueueSubmit2(queues[static_cast(queue_type)].vk_queue, 1, &submit_info, nullptr)); + + return fence.value; } -void vkdevice::submit(std::span buffers, handle wait_handle, handle signal_handle) { - assert((max_submitable_command_buffers - buffers.size()) >= 0); +uint32_t vkdevice::submit_before_present(handle surface_handle, command_buffer* buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); const auto queue_type = buffers[0].queue_type; - VkCommandBufferSubmitInfo command_buffers_info[buffers.size()]; + VkCommandBufferSubmitInfo command_buffers_info[count]; - for (auto index{ 0U }; index < buffers.size(); index++) { + for (auto index{ 0U }; index < count; index++) { assert(queue_type == buffers[index].queue_type); auto& command_buffer_info = command_buffers_info[index]; @@ -397,50 +542,57 @@ void vkdevice::submit(std::span buffers, handle(buffers.size()), + .waitSemaphoreInfoCount = 1U, + .pWaitSemaphoreInfos = &wait_semaphore_info, + .commandBufferInfoCount = count, .pCommandBufferInfos = command_buffers_info, }; - if (wait_handle.is_valid()) { - const auto& wait = vkdevice::get_render_device().get_semaphore(wait_handle); - wait_semaphore_info.semaphore = wait.vk_semaphore; - wait_semaphore_info.value = wait.value; - submit_info.waitSemaphoreInfoCount = 1U; - submit_info.pWaitSemaphoreInfos = &wait_semaphore_info; - } - - if (signal_handle.is_valid()) { - auto& signal = vkdevice::get_render_device().get_semaphore(signal_handle); - signal_semaphore_info.semaphore = signal.vk_semaphore; - signal_semaphore_info.value = ++signal.value; - - submit_info.signalSemaphoreInfoCount = 1U; - submit_info.pSignalSemaphoreInfos = &signal_semaphore_info; - } + auto& fence = timeline_semaphore; + auto& signal = get_semaphore(surface.submit_semaphores[surface.frame_index]); + VkSemaphoreSubmitInfo signal_semaphore_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = fence.vk_semaphore, + .value = ++fence.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = signal.vk_semaphore, + .value = signal.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + }; + submit_info.signalSemaphoreInfoCount = sizeof(signal_semaphore_infos) / sizeof(signal_semaphore_infos[0U]); + submit_info.pSignalSemaphoreInfos = signal_semaphore_infos; VKCHECK(vkQueueSubmit2(queues[static_cast(queue_type)].vk_queue, 1, &submit_info, nullptr)); + + return fence.value; } -void vkdevice::present(handle surface_handle, handle semaphore_handle) { - const auto& surface = vkdevice::get_render_device().get_surface(surface_handle); +void vkdevice::present(handle surface_handle) { + auto& surface = vkdevice::get_render_device().get_surface(surface_handle); VkResult result; VkPresentInfoKHR present_info{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -451,15 +603,14 @@ void vkdevice::present(handle surface_handle, handle(QueueType::GRAPHICS)].vk_queue, &present_info)); VKCHECK(result); + surface.frame_index = (surface.frame_index + 1) % surface.image_count; } // private @@ -847,6 +998,7 @@ void vkdevice::create_debug_layer_callback() { idlist<> device_texture::sampled_indices = {}; idlist<> device_texture::storage_indices = {}; +idlist<> device_sampler::sampler_indices = {}; void device_texture::init(const texture_desc& desc) { auto& render_device = vkdevice::get_render_device(); @@ -1009,14 +1161,67 @@ void device_texture::create_views() { } -void device_surface::acquire_image_index(handle signal_handle) { +void device_sampler::init(const sampler_desc& desc) { auto& render_device = vkdevice::get_render_device(); + // const auto& bindless = render_device.get_bindingmodel(); auto* device = render_device.get_device(); - const auto& signal = render_device.get_semaphore(signal_handle); - vkAcquireNextImageKHR(device, vk_swapchain, -1, signal.vk_semaphore, nullptr, &image_index); + VkSamplerCreateInfo sampler_create_info{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .magFilter = desc.mag_filter, + .minFilter = desc.min_filter, + .mipmapMode = desc.mipmap_mode, + .addressModeU = desc.address_mode_u, + .addressModeV = desc.address_mode_v, + .addressModeW = desc.address_mode_w, + .mipLodBias = desc.mip_lod_bias, + .anisotropyEnable = desc.anisotropy, + .maxAnisotropy = desc.max_anisotropy, + .compareEnable = desc.compare_enabled, + .compareOp = desc.compare_op, + .minLod = desc.min_lod, + .maxLod = desc.max_lod, + .borderColor = desc.border_color, + .unnormalizedCoordinates = desc.unnomalized_coords, + }; + + VKCHECK(vkCreateSampler(device, &sampler_create_info, nullptr, &vk_sampler)); + + sampler_index = sampler_indices.add(); + + // VkWriteDescriptorSet write_descriptor_set{ + // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + // .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + // .dstBinding = 1U, + // .dstArrayElement = sampler_index.id, + // .descriptorCount = 1U, + // .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + // .pImageInfo = images_info, + // .pBufferInfo = nullptr, + // .pTexelBufferView = nullptr, + // }); } -handle device_surface::get_backbuffer_image() const { - return swapchain_images[image_index]; + +uint32_t vkdevice::acquire_image_index(handle surface_handle) { + auto& render_device = vkdevice::get_render_device(); + auto* device = render_device.get_device(); + auto& surface = get_surface(surface_handle); + const auto& signal = get_semaphore(surface.acquire_semaphores[surface.frame_index]); + + VkSemaphoreWaitInfo wait_info { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .pNext = nullptr, + .flags = 0U, + .semaphoreCount = 1U, + .pSemaphores = &timeline_semaphore.vk_semaphore, + .pValues = &timeline_semaphore.value, + }; + vkWaitSemaphores(device, &wait_info, -1); + VKCHECK(vkAcquireNextImageKHR(device, surface.vk_swapchain, -1, signal.vk_semaphore, nullptr, &surface.image_index)); + + return surface.image_index; } diff --git a/include/api-test/command-buffer.hpp b/include/api-test/command-buffer.hpp index f7a18b0..d26fa13 100644 --- a/include/api-test/command-buffer.hpp +++ b/include/api-test/command-buffer.hpp @@ -22,10 +22,22 @@ struct device_buffer; struct device_pipeline; struct dispatch_params { + enum class PARAM_BINDING : uint32_t { + PARAM1, + PARAM2, + PARAM3, + PARAM4, + PARAM5, + PARAM6, + PARAM7, + PARAM8, + MAX + }; + handle pipeline; vec3u group_size; vec3u local_group_size; - uint32_t uniforms_offset; + uint64_t params[static_cast(PARAM_BINDING::MAX)]; }; struct renderpass_params { @@ -41,14 +53,30 @@ public: rect render_area; std::span> color_attachments; }; + struct draw_params { + handle pipeline; + handle index_buffer; + uint32_t vertex_count; + uint32_t vertex_offset; + uint32_t instance_count; + uint64_t globals_address = 0U; // TODO: This is probably stupid and should be set elsewhere once ??? + uint64_t instances_address = 0U; + uint64_t uniforms_address = 0U; + uint64_t vertex_address = 0U; +}; + +struct draw_indexed_params { handle pipeline; handle index_buffer; uint32_t vertex_count; uint32_t vertex_offset; uint32_t index_offset; uint32_t instance_count; - uint32_t uniforms_offset; + uint64_t globals_address = 0U; // TODO: This is probably stupid and should be set elsewhere once ??? + uint64_t instances_address = 0U; + uint64_t uniforms_address = 0U; + uint64_t vertex_address = 0U; }; struct command_buffer { @@ -68,7 +96,8 @@ struct graphics_command_buffer: public command_buffer { void dispatch(const dispatch_params& params) const; void begin_renderpass(const renderpass_params& params) const; - void render(const draw_params& params) const; + void draw(const draw_params& params) const; + void draw_indexed(const draw_indexed_params& params) const; void end_renderpass() const; }; diff --git a/include/api-test/handle.hpp b/include/api-test/handle.hpp index 72c46a2..f07776b 100644 --- a/include/api-test/handle.hpp +++ b/include/api-test/handle.hpp @@ -19,4 +19,6 @@ struct handle { [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } static constexpr uint32_t invalid_id = -1U; + + // static constexpr handle invalid_handle {}; }; diff --git a/include/api-test/vk-bindless.hpp b/include/api-test/vk-bindless.hpp index 7b8eccc..a5686ff 100644 --- a/include/api-test/vk-bindless.hpp +++ b/include/api-test/vk-bindless.hpp @@ -13,6 +13,13 @@ enum BindlessSetType : uint32_t { MAX, }; +enum ConstantType : uint32_t { + GLOBALS, + INSTANCES, + DRAWS, + VERTEX_BUFFER +}; + enum SamplerType : uint32_t { NEAREST, LINEAR, @@ -22,19 +29,29 @@ enum SamplerType : uint32_t { struct device_buffer; struct bindless_model { -#ifndef USE_VK_DESCRIPTOR_BUFFERS - [[nodiscard]] const device_buffer& get_uniform_buffer() const; +#ifndef USE_VK_DESCRIPTOR_BUFFER + [[nodiscard]] device_buffer& get_draws_uniform_buffer() const; + [[nodiscard]] device_buffer& get_globals_uniform_buffer() const; static bindless_model create_bindless_model(); static void destroy_bindless_model(bindless_model& bindless); - VkPipelineLayout layout; + VkPipelineLayout graphics_layout; + VkPipelineLayout compute_layout; VkDescriptorSet sets[BindlessSetType::MAX]; +private: + static constexpr size_t max_push_constants_size = 128ULL; + +public: + static constexpr size_t max_push_constants_slots_size = 8U; + static constexpr size_t max_push_constants_slots = max_push_constants_size / max_push_constants_slots_size; + private: VkDescriptorSetLayout sets_layout[BindlessSetType::MAX]; VkDescriptorPool descriptor_pool; + handle globals_uniform_buffer_handle; handle instances_uniform_buffer_handle; handle draws_uniform_buffer_handle; @@ -53,6 +70,7 @@ private: VkSampler samplers[SamplerType::MAX_SAMPLER]; + static constexpr size_t globals_uniform_buffer_size = 64ULL * 1024ULL; static constexpr size_t instances_uniform_buffer_size = 64ULL * 1024ULL; static constexpr size_t draws_uniform_buffer_size = 64ULL * 1024ULL; #else diff --git a/include/api-test/vk-device-types.hpp b/include/api-test/vk-device-types.hpp index 3085e29..994f0c4 100644 --- a/include/api-test/vk-device-types.hpp +++ b/include/api-test/vk-device-types.hpp @@ -29,10 +29,12 @@ struct device_texture { void create_views(); [[nodiscard]] uint32_t get_storage_index() const { + assert(storage_index.id != handle::invalid_id); return storage_index.id; } [[nodiscard]] uint32_t get_sampled_index() const { + assert(sampled_index.id != handle::invalid_id); return sampled_index.id; } @@ -60,6 +62,41 @@ struct device_texture { static idlist<> sampled_indices; }; + +struct sampler_desc { + VkFilter mag_filter = VK_FILTER_NEAREST; + VkFilter min_filter = VK_FILTER_NEAREST; + VkSamplerMipmapMode mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + VkSamplerAddressMode address_mode_u = VK_SAMPLER_ADDRESS_MODE_REPEAT; + VkSamplerAddressMode address_mode_v = VK_SAMPLER_ADDRESS_MODE_REPEAT; + VkSamplerAddressMode address_mode_w = VK_SAMPLER_ADDRESS_MODE_REPEAT; + float mip_lod_bias = 0.f; + VkBool32 anisotropy = VK_FALSE; + float max_anisotropy = 0.f; + VkBool32 compare_enabled = VK_FALSE; + VkCompareOp compare_op = VK_COMPARE_OP_NEVER; + float min_lod = 0.f; + float max_lod = 0.f; + VkBorderColor border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + VkBool32 unnomalized_coords = VK_FALSE; +}; + +struct device_sampler { + void init(const sampler_desc& desc); + + VkSampler vk_sampler = nullptr; + + [[nodiscard]] uint32_t get_sampler_index() const { + return sampler_index.id; + } + + private: + handle sampler_index; + + static idlist<> sampler_indices; +}; + + struct buffer_desc { size_t size; VkBufferUsageFlags usages; @@ -68,6 +105,35 @@ struct buffer_desc { }; struct device_buffer { + template + T* allocate() { + // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; + size_t alloc_size = sizeof(T); + if (offset + alloc_size > size) { + reset(); + } + + auto* addr = (T*)(static_cast(mapped_ptr) + offset); + offset += alloc_size; + return addr; + } + + void* allocate(uint64_t alloc_size) { + // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; + if (offset + alloc_size > size) { + reset(); + } + + auto* addr = (void*)(static_cast(mapped_ptr) + offset); + offset += alloc_size; + return addr; + } + + void reset() { + offset = 0U; + } + + uint32_t offset = 0U; VkBuffer vk_buffer; VmaAllocation alloc; VkDeviceAddress device_address = 0U; @@ -75,8 +141,7 @@ struct device_buffer { size_t size; }; -struct pipeline_desc { - std::span cs_code; +struct graphics_pipeline_desc { std::span vs_code; std::span fs_code; std::span color_attachments_format; @@ -84,6 +149,10 @@ struct pipeline_desc { VkFormat stencil_attachment_format; }; +struct compute_pipeline_desc { + std::span cs_code; +}; + struct device_pipeline { VkPipeline vk_pipeline; VkPipelineBindPoint bind_point; @@ -114,14 +183,17 @@ struct surface_desc { }; struct device_surface { - VkSurfaceKHR vk_surface; - VkSwapchainKHR vk_swapchain; - VkSurfaceFormatKHR surface_format; + VkSurfaceKHR vk_surface; + VkSwapchainKHR vk_swapchain; + VkSurfaceFormatKHR surface_format; + + handle swapchain_images[surface_desc::max_image_count]; + uint32_t image_index; + uint32_t image_count; + uint32_t frame_index = 0U; - handle swapchain_images[surface_desc::max_image_count]; - uint32_t image_index; - uint32_t image_count; + handle acquire_semaphores[surface_desc::max_image_count]; + handle submit_semaphores[surface_desc::max_image_count]; - void acquire_image_index(handle signal_handle); - handle get_backbuffer_image() const; + uint32_t acquire_image_index(); }; diff --git a/include/api-test/vk-device.hpp b/include/api-test/vk-device.hpp index 1ece366..7f86cbb 100644 --- a/include/api-test/vk-device.hpp +++ b/include/api-test/vk-device.hpp @@ -31,9 +31,13 @@ class vkdevice { handle create_texture(const texture_desc& desc); + handle create_sampler(const sampler_desc& desc); + handle create_buffer(const buffer_desc& desc); - handle create_pipeline(const pipeline_desc& desc); + handle create_graphics_pipeline(const graphics_pipeline_desc& desc); + + handle create_compute_pipeline(const compute_pipeline_desc& desc); handle create_surface(const surface_desc& desc); @@ -41,6 +45,8 @@ class vkdevice { void destroy_texture(handle handle); + void destroy_sampler(handle handle); + void destroy_buffer(handle handle); void destroy_pipeline(handle handle); @@ -49,16 +55,20 @@ class vkdevice { void destroy_surface(handle handle); - template - void allocate_command_buffers(array_type& buffers, QueueType queue_type) { - allocate_command_buffers(static_cast(buffers.data()), buffers.size(), queue_type); + template + void allocate_command_buffers(buffer_type* buffers, size_t count, QueueType queue_type) { + allocate_command_buffers(static_cast(buffers), count, queue_type); } [[nodiscard]] inline device_texture& get_texture(handle handle) { return textures[handle]; } - [[nodiscard]] inline const device_buffer& get_buffer(handle handle) const { + [[nodiscard]] inline device_sampler& get_sampler(handle handle) { + return samplers[handle]; + } + + [[nodiscard]] inline device_buffer& get_buffer(handle handle) { return buffers[handle]; } @@ -86,11 +96,14 @@ class vkdevice { return gpu_allocator; } - void wait(handle semaphore_handle); + // uint64_t submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle); + uint32_t acquire_image_index(handle surface_handle); + uint32_t submit_before_present(handle surface_handle, command_buffer* buffers, uint32_t count); + uint32_t submit(command_buffer* buffers, uint32_t count); - void submit(std::span buffers, handle wait_handle, handle signal_handle); + void present(handle surface_handle); - void present(handle surface_handle, handle semaphore_handle); + void wait(); private: vkdevice() = default; @@ -103,38 +116,41 @@ class vkdevice { void create_swapchain(const surface_desc& desc, device_surface& surface); // TODO: Wrap in a struct called adapter ? - void create_instance(); + void create_instance(); + + void create_device(); - void create_device(); + void create_memory_allocator(); - void create_memory_allocator(); + void create_command_pools(); - void create_command_pools(); + void pick_physical_device(); - void pick_physical_device(); + static bool device_support_features(VkPhysicalDevice physical_dev); - static bool device_support_features(VkPhysicalDevice physical_dev); + void create_debug_layer_callback(); - void create_debug_layer_callback(); + queue queues[static_cast(QueueType::MAX)]; - queue queues[static_cast(QueueType::MAX)]; + VkInstance instance; + VkPhysicalDevice physical_device; + VkDevice device; - VkInstance instance; - VkPhysicalDevice physical_device; - VkDevice device; + VmaAllocator gpu_allocator; - VmaAllocator gpu_allocator; + bindless_model bindless; - bindless_model bindless; + static constexpr size_t max_allocable_command_buffers = 16; + static constexpr size_t max_submitable_command_buffers = 16; - static constexpr size_t max_allocable_command_buffers = 16; - static constexpr size_t max_submitable_command_buffers = 16; + freelist textures; + freelist samplers; + freelist buffers; + freelist pipelines; + freelist surfaces; + freelist semaphores; - freelist textures; - freelist buffers; - freelist pipelines; - freelist surfaces; - freelist semaphores; + device_semaphore timeline_semaphore; static vkdevice render_device; diff --git a/shaders/api-test-ui.frag b/shaders/api-test-ui.frag index 57630dc..06553df 100644 --- a/shaders/api-test-ui.frag +++ b/shaders/api-test-ui.frag @@ -1,3 +1,4 @@ +#extension GL_EXT_buffer_reference : require #extension GL_EXT_nonuniform_qualifier : require layout(location = 0) out vec4 o_Color; @@ -10,13 +11,24 @@ layout(location = 0) in struct { layout(set = 0, binding = 0) uniform sampler samplers[]; layout(set = 0, binding = 1) uniform texture2D textures[]; layout(set = 0, binding = 2, rgba32f) uniform image2D images[]; -layout(set = 2, binding = 0) uniform parameters { - uint vertex_buffer; +// layout(set = 2, binding = 0) uniform parameters { +// uint vertex_buffer; +// vec2 scale; +// vec2 translate; +// uint texture_index; +// } params; + +layout(buffer_reference) readonly buffer params { vec2 scale; vec2 translate; uint texture_index; -} params; + uint padding; +}; + +layout(push_constant) uniform constants { + layout(offset = 16) params ui_params; +} consts; void main() { - o_Color = In.color * texture(sampler2D(textures[nonuniformEXT(params.texture_index)], samplers[nonuniformEXT(0U)]), In.uv.xy); + o_Color = In.color * texture(sampler2D(textures[nonuniformEXT(consts.ui_params.texture_index)], samplers[nonuniformEXT(0U)]), In.uv.xy); } diff --git a/shaders/api-test-ui.vert b/shaders/api-test-ui.vert index 4824d23..9592a65 100644 --- a/shaders/api-test-ui.vert +++ b/shaders/api-test-ui.vert @@ -8,16 +8,21 @@ struct vertex { uint color; }; +layout(buffer_reference) readonly buffer params { + vec2 scale; + vec2 translate; + uint texture_index; + uint padding; +}; + layout(buffer_reference) readonly buffer vertices { vertex vertices[]; }; -layout(set = 2, binding = 0) uniform parameters { +layout(push_constant) uniform constants { + layout(offset = 16) params ui_params; vertices vertex_buffer; - vec2 scale; - vec2 translate; - uint texture_index; -} params; +} consts; out gl_PerVertex { vec4 gl_Position; @@ -30,11 +35,11 @@ layout(location = 0) out struct { void main() { - vertex v = params.vertex_buffer.vertices[gl_VertexIndex]; + vertex v = consts.vertex_buffer.vertices[gl_VertexIndex]; Out.color = unpackUnorm4x8(v.color); Out.uv = vec2(v.uv_x, v.uv_y); vec2 pos = vec2(v.pos_x, v.pos_y); - gl_Position = vec4(pos * params.scale + params.translate, 0.0, 1.0); + gl_Position = vec4(pos * consts.ui_params.scale + consts.ui_params.translate, 0.0, 1.0); } -- cgit v1.3