diff options
| -rw-r--r-- | api-test/main.cpp | 653 | ||||
| -rw-r--r-- | api-test/vk-bindless.cpp | 431 | ||||
| -rw-r--r-- | build.bat | 16 | ||||
| -rw-r--r-- | include/api-test/handle.hpp | 24 | ||||
| -rw-r--r-- | include/api-test/resource-manager.hpp | 22 | ||||
| -rw-r--r-- | include/api-test/texture.hpp | 17 | ||||
| -rw-r--r-- | include/api-test/vk-bindless.hpp | 93 | ||||
| -rw-r--r-- | include/buffer.hpp (renamed from include/api-test/buffer.hpp) | 0 | ||||
| -rw-r--r-- | include/bvh-node.hpp | 320 | ||||
| -rw-r--r-- | include/compute-renderpass.hpp | 41 | ||||
| -rw-r--r-- | include/dx12-command-buffer.hpp (renamed from include/api-test/dx12-command-buffer.hpp) | 0 | ||||
| -rw-r--r-- | include/dx12-device-types.hpp (renamed from include/api-test/dx12-device-types.hpp) | 0 | ||||
| -rw-r--r-- | include/dx12-device.hpp (renamed from include/api-test/dx12-device.hpp) | 0 | ||||
| -rw-r--r-- | include/freelist.hpp (renamed from include/api-test/freelist.hpp) | 39 | ||||
| -rw-r--r-- | include/handle.hpp | 13 | ||||
| -rw-r--r-- | include/primitive-renderpass.hpp | 93 | ||||
| -rw-r--r-- | include/renderpass.hpp | 22 | ||||
| -rw-r--r-- | include/texture.hpp | 86 | ||||
| -rw-r--r-- | include/vk-api.hpp | 219 | ||||
| -rw-r--r-- | include/vk-bindless.hpp | 49 | ||||
| -rw-r--r-- | include/vk-command-buffer.hpp (renamed from include/api-test/vk-command-buffer.hpp) | 30 | ||||
| -rw-r--r-- | include/vk-context.hpp | 49 | ||||
| -rw-r--r-- | include/vk-device-types.hpp (renamed from include/api-test/vk-device-types.hpp) | 57 | ||||
| -rw-r--r-- | include/vk-device.hpp (renamed from include/api-test/vk-device.hpp) | 30 | ||||
| -rw-r--r-- | include/vk-renderer.hpp | 164 | ||||
| -rw-r--r-- | include/vk-utils.hpp (renamed from include/api-test/vk-utils.hpp) | 6 | ||||
| -rw-r--r-- | src/compute-renderpass.cpp | 63 | ||||
| -rw-r--r-- | src/dx12-command-buffer.cpp (renamed from api-test/dx12-command-buffer.cpp) | 0 | ||||
| -rw-r--r-- | src/dx12-device.cpp (renamed from api-test/dx12-device.cpp) | 0 | ||||
| -rw-r--r-- | src/main.cpp | 1053 | ||||
| -rw-r--r-- | src/primitive-renderpass.cpp | 152 | ||||
| -rw-r--r-- | src/vk-api.cpp | 1257 | ||||
| -rw-r--r-- | src/vk-bindless.cpp | 238 | ||||
| -rw-r--r-- | src/vk-command-buffer.cpp (renamed from api-test/vk-command-buffer.cpp) | 75 | ||||
| -rw-r--r-- | src/vk-context.cpp | 319 | ||||
| -rw-r--r-- | src/vk-device.cpp (renamed from api-test/vk-device.cpp) | 127 | ||||
| -rw-r--r-- | src/vk-renderer.cpp | 284 | ||||
| -rw-r--r-- | src/vk-utils.cpp (renamed from api-test/vk-utils.cpp) | 2 |
38 files changed, 1215 insertions, 4829 deletions
diff --git a/api-test/main.cpp b/api-test/main.cpp deleted file mode 100644 index f4a825d..0000000 --- a/api-test/main.cpp +++ /dev/null @@ -1,653 +0,0 @@ -// #include <cassert> -// #include <cstdio> -// #include <array> - -#define STB_IMAGE_IMPLEMENTATION -// #include <stb_image.h> - -#include "imgui.cpp" -#include "imgui_draw.cpp" -#include "imgui_tables.cpp" -#include "imgui_widgets.cpp" -#include "imgui_demo.cpp" - -#define API_TEST - -#include "../src/vulkan-loader.cpp" -#include "../src/window.cpp" -#include "../src/vec3.cpp" -#include "../src/camera.cpp" -#include "../src/scene.cpp" -#include "../src/utils.cpp" -#include "../src/bvh.cpp" -#include "../src/gltf.cpp" -#include "../src/mesh.cpp" - -#include "vk-utils.cpp" -#include "vk-device.cpp" -#include "vk-bindless.cpp" -#include "vk-command-buffer.cpp" - -// #include "handle.hpp" -// #include "window.hpp" -// #include "utils.hpp" - -#ifdef VK -#include <vk_mem_alloc.h> -#include "vk-device.hpp" -#include "vk-command-buffer.hpp" -#else -#include "dx12-device.hpp" -#include "dx12-command-buffer.hpp" -#endif - -struct device_texture; - -#define VK -// #define DX12 - -#ifdef DEBUG -#define ENABLE_RENDERDOC -#endif // _DEBUG - -#include "camera.hpp" -#include "scene.hpp" - -#ifdef ENABLE_RENDERDOC -#include <renderdoc_app.h> - -#define RD_START_CAPTURE if(rdoc_api != nullptr) rdoc_api->StartFrameCapture(nullptr, nullptr) -#define RD_END_CAPTURE if(rdoc_api != nullptr) rdoc_api->EndFrameCapture(nullptr, nullptr) - -RENDERDOC_API_1_6_0 *rdoc_api = nullptr; -#else -#define RD_START_CAPTURE (0) -#define RD_END_CAPTURE (0) -#endif // ENABLE_RENDERDOC - -static constexpr size_t Kb = 1024U; -static constexpr size_t Mb = 1024U * Kb; - -static uintptr_t transmittance_LUT_tex_id = 0U; - -void ui(uint64_t frame_time) { - static float max_fps = 0.f; - static uint64_t max_frame_time = 1000U; - float fps = static_cast<float>(1000000U / frame_time); - if (fps > max_fps) { - max_fps = fps; - } - if (frame_time > max_frame_time) { - max_frame_time = frame_time; - } - ImGui::NewFrame(); - ImGui::Text("FPS : %f\n", fps); - ImGui::Text("Max FPS : %f\n", max_fps); - ImGui::Text("frame_time : %f ms\n", frame_time / 1000.f); - ImGui::Text("max frame_time : %f ms\n", max_frame_time / 1000.f); - - ImGui::Text("LUT"); - ImGui::Image(transmittance_LUT_tex_id, ImVec2(128, 128)); - ImGui::EndFrame(); - ImGui::Render(); -} - -void update_buffers(ImDrawData* draw_data, const device_buffer& vertex_buffer, const device_buffer& index_buffer) { - off_t vertex_offset = 0; - off_t index_offset = 0; - for (auto index {0} ; index < draw_data->CmdListsCount; index++) { - auto* cmd_list = draw_data->CmdLists[index]; - - size_t vertex_bytes_size = sizeof(ImDrawVert) * cmd_list->VtxBuffer.size(); - auto* vtx_ptr = static_cast<uint8_t*>(vertex_buffer.mapped_ptr) + vertex_offset; - memcpy(vtx_ptr, cmd_list->VtxBuffer.Data, vertex_bytes_size); - vertex_offset += static_cast<off_t>(vertex_bytes_size); - - size_t index_bytes_size = sizeof(ImDrawIdx) * cmd_list->IdxBuffer.size(); - memcpy(static_cast<uint8_t*>(index_buffer.mapped_ptr) + index_offset, cmd_list->IdxBuffer.Data, index_bytes_size); - index_offset += static_cast<off_t>(index_bytes_size); - } -} - -int main() { - LARGE_INTEGER freq; - // From Microsoft doc - // https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency - // The frequency of the performance counter is fixed at system boot and is - // consistent across all processors so you only need to query the frequency - // from QueryPerformanceFrequency as the application initializes, - // and then cache the result. - QueryPerformanceFrequency(&freq); - -#ifdef ENABLE_RENDERDOC - { - HMODULE mod = GetModuleHandleA("renderdoc.dll"); - // if (!mod) { - // mod = LoadLibraryA("renderdoc.dll"); - // } - - if (mod) { - auto RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - assert(RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, (void **)&rdoc_api) == 1); - } - - // if (!rdoc_api->IsTargetControlConnected()) { - // rdoc_api->LaunchReplayUI(true, nullptr); - // } - } -#endif - - constexpr size_t window_width = 1280U; - constexpr size_t window_height = 720U; - window wnd { window_width, window_height }; - - ImGui::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); - io.DisplaySize.x = window_width; - io.DisplaySize.y = window_height; - - const float aspect_ratio = 16.f / 9.f; - - 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; - -#ifdef VK - auto& device = vkdevice::get_render_device(); -#else - auto& device = dx12::device::get_render_device(); -#endif - device.init(); - -#ifdef VK - auto main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), window_width, window_height); -#endif - - auto surface_handle = device.create_surface({ - .window_handle = wnd.handle, -#ifdef VK - .surface_format = { - .format = VK_FORMAT_B8G8R8A8_UNORM, - .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 | VK_IMAGE_USAGE_STORAGE_BIT, -#else - .surface_format = DXGI_FORMAT_R16G16B16A16_FLOAT, - .present_mode = DXGI_SWAP_EFFECT_FLIP_DISCARD, - .usages = DXGI_USAGE_RENDER_TARGET_OUTPUT, -#endif - .image_count = 2U, - }); - auto& surface = device.get_surface(surface_handle); - - constexpr size_t image_size = 1024U; - constexpr size_t image_count = 4U; - auto staging_buffer_handle = device.create_buffer({ - .size = image_size * image_size * sizeof(uint32_t) * image_count, -#ifdef VK - .usages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, -#else - - .map = true, - .states = D3D12_RESOURCE_STATE_COPY_SOURCE, - .usages = D3D12_RESOURCE_FLAG_NONE, - .heap_type = D3D12_HEAP_TYPE_UPLOAD, -#endif - }); - const auto& staging_buffer = device.get_buffer(staging_buffer_handle); - - // API test code - int width; - int height; - int channels; - uint8_t* data = stbi_load("../models/sponza/466164707995436622.jpg", &width, &height, &channels, 4); - size_t size = static_cast<size_t>(width) * height * 4U; - memcpy(staging_buffer.mapped_ptr, data, size); - - auto gpu_texture_handle = device.create_texture({ - .width = static_cast<uint32_t>(width), - .height = static_cast<uint32_t>(height), -#ifdef VK - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_COPY_DEST, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - - off_t buffer_offset = width * height * 4; - data = stbi_load("../models/sponza/715093869573992647.jpg", &width, &height, &channels, 4); - size = static_cast<size_t>(width) * height * 4U; - auto* addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + buffer_offset); - memcpy(addr, data, size); - - auto second_texture = device.create_texture({ - .width = static_cast<uint32_t>(width), - .height = static_cast<uint32_t>(height), -#ifdef VK - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_COPY_DEST, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - - auto output_texture_handle = device.create_texture({ - .width = static_cast<uint32_t>(width), - .height = static_cast<uint32_t>(height), -#ifdef VK - .usages = VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - - uint8_t *pixels = nullptr; - int atlas_width; - int atlas_height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); - const auto ui_texture_handle = device.create_texture({ - .width = static_cast<uint32_t>(atlas_width), - .height = static_cast<uint32_t>(atlas_height), -#ifdef VK - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_COPY_DEST, - .usages = D3D12_RESOURCE_FLAG_NONE, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - const auto& ui_texture = device.get_texture(ui_texture_handle); - // io.Fonts->SetTexID(*(void **)&ui_texture_handle.id); - io.Fonts->SetTexID(reinterpret_cast<void*>(ui_texture.get_sampled_index())); - - off_t ui_offset = 2L * buffer_offset; - size = static_cast<size_t>(atlas_width) * atlas_height * 4U; - addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + ui_offset); - memcpy(addr, pixels, size); - - auto vertex_buffer_handle = device.create_buffer({ - .size = Mb * sizeof(uint32_t), -#ifdef VK - .usages = VK_BUFFER_USAGE_STORAGE_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, -#else - #endif - }); - auto vertex_buffer = device.get_buffer(vertex_buffer_handle); - - auto index_buffer_handle = device.create_buffer({ - .size = Mb * sizeof(uint32_t), -#ifdef VK - .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, -#else -#endif - }); - auto index_buffer = device.get_buffer(index_buffer_handle); - -#ifdef VK - auto code = read_file("shaders/test.comp.spv"); - 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, - }); -#endif - const auto acc_handle = device.create_texture({ - .width = static_cast<uint32_t>(window_width), - .height = static_cast<uint32_t>(window_height), -#ifdef VK - .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R32G32B32A32_FLOAT, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - -#ifdef VK - auto acc_storage_index = device.get_texture(acc_handle).get_storage_index(); -#endif - - const auto result_handle = device.create_texture({ - .width = static_cast<uint32_t>(window_width), - .height = static_cast<uint32_t>(window_height), -#ifdef VK - .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R32G32B32A32_FLOAT, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); -#ifdef VK - auto result_storage_index = device.get_texture(result_handle).get_storage_index(); -#endif - -#ifdef VK - std::array<VkFormat, 1U> 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_graphics_pipeline({ - .vs_code = vertex_code, - .fs_code = fragment_code, - .color_attachments_format = formats - }); -#endif - -#ifdef VK - std::array<graphics_command_buffer, 4U> graphics_command_buffers; - device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), QueueType::GRAPHICS, "graphics_cmd_buf"); -#else - std::array<dx12::graphics_command_buffer, 4U> graphics_command_buffers; - device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), dx12::QueueType::GRAPHICS); -#endif - - - handle<device_texture> transmittance_lut_handle = device.create_texture({ - .width = static_cast<uint32_t>(1024), - .height = static_cast<uint32_t>(1024), -#ifdef VK - .usages = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .format = VK_FORMAT_R16G16B16A16_SFLOAT, - .type = VK_IMAGE_TYPE_2D, -#else - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - .name = "transmittance_lut", - }); - device_texture transmittance_lut = device.get_texture(transmittance_lut_handle); - transmittance_LUT_tex_id = transmittance_lut.get_sampled_index(); - - std::vector<uint8_t> transmittance_lut_code = read_file("shaders/transmittance_lut.comp.spv"); - handle<device_pipeline> transmittance_lut_compute = device.create_compute_pipeline({ - .cs_code = transmittance_lut_code, - .name = "transmittance_lut_comp", - }); - - - // API test code - RD_START_CAPTURE; - - graphics_command_buffers[0].start(); - -#ifdef VK - graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - graphics_command_buffers[0].barrier(ui_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); -#endif - - graphics_command_buffers[0].copy(staging_buffer_handle, gpu_texture_handle); - graphics_command_buffers[0].copy(staging_buffer_handle, second_texture, buffer_offset); - graphics_command_buffers[0].copy(staging_buffer_handle, ui_texture_handle, ui_offset); -#ifdef VK - 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); - - { - 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].dispatch({ - .pipeline = transmittance_lut_compute, - .group_size = { .vec = { 1024U, 1024U, 1U }}, - .local_group_size = { .vec { 8U, 8U, 1U }}, - .params = { - transmittance_lut.get_storage_index(), - uint64_t(transmittance_lut.width) << 32U | transmittance_lut.height, - } - }); - } - - 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); -#endif - - graphics_command_buffers[0].stop(); - - device.submit(graphics_command_buffers.data(), 1); - device.wait(); - - RD_END_CAPTURE; - - // watcher::watch_file(std::filesystem::path("../shaders/compute.comp"), [&]() { - // printf("change"); - // }); - -#ifdef VK - std::array<handle<device_texture>, 1U> color_attachment {}; - constexpr uint32_t virtual_frames_count = 2U; - uint64_t frame_time = 1U; - uint32_t frame_count = 0U; - while(wnd.isOpen) { - LARGE_INTEGER start_qpc; - QueryPerformanceCounter(&start_qpc); - wnd.poll_events(); - - watcher::pull_changes(); - - uint32_t virtual_frame_index = frame_count % virtual_frames_count; - 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<float>(event.data.position.x); - io.MousePos.y = static_cast<float>(event.data.position.y); - } - - io.MouseDown[0] = event.type == EVENT_TYPES::BUTTON_PRESS; - } - - ui(frame_time); - - auto* draw_data = ImGui::GetDrawData(); - update_buffers(draw_data, vertex_buffer, index_buffer); - - const auto& scene_buffer = device.get_buffer(main_scene.scene_buffer_handle); - main_scene.meta.sample_index = frame_count; - uint8_t* ptr = static_cast<uint8_t*>(scene_buffer.mapped_ptr); - memcpy(static_cast<void*>(ptr), &main_scene.meta, sizeof(main_scene.meta)); - memcpy(static_cast<void*>(ptr + sizeof(main_scene.meta)), &main_scene.meta, sizeof(main_scene.meta)); - memcpy(static_cast<void*>(ptr + sizeof(main_scene.meta) * 2U), &main_scene.meta, sizeof(main_scene.meta)); - - // 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.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.begin_renderpass({ - .render_area = { - .x = static_cast<int32_t>(draw_data->DisplayPos.x), - .y = static_cast<int32_t>(draw_data->DisplayPos.y), - .width = static_cast<uint32_t>(draw_data->DisplaySize.x), - .height = static_cast<uint32_t>(draw_data->DisplaySize.y), - }, - .color_attachments = color_attachment, - }); - - auto& draws_uniform_buffer = device.get_bindingmodel().get_draws_uniform_buffer(); - uint32_t vertex_offset = 0; - uint32_t index_offset = 0; - for (auto index {0} ; index < draw_data->CmdListsCount; index++) { - auto* cmd_list = draw_data->CmdLists[index]; - - for (auto& draw_command : cmd_list->CmdBuffer) { - auto offset = draws_uniform_buffer.offset; - ImTextureID texture_id = draw_command.TexRef.GetTexID(); - { - 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_params>(); - *ui_param = ui_params{ - // .vertex_buffer = vertex_buffer.device_address, - .scale { - 2.f / draw_data->DisplaySize.x, - 2.f / draw_data->DisplaySize.y, - }, - .translate { - -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x), - -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y), - }, - .texture_index = *reinterpret_cast<uint32_t*>(&texture_id), - }; - } - - command_buffer.draw_indexed({ - .pipeline = graphics, - .index_buffer = index_buffer_handle, - .vertex_count = draw_command.ElemCount, - .vertex_offset = draw_command.VtxOffset + vertex_offset, - .index_offset = draw_command.IdxOffset + index_offset, - .instance_count = 1U, - .uniforms_address = draws_uniform_buffer.device_address + offset, - .vertex_address = vertex_buffer.device_address, - }); - } - vertex_offset += cmd_list->VtxBuffer.size(); - index_offset += cmd_list->IdxBuffer.size(); - } - - command_buffer.end_renderpass(); - 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_before_present(surface_handle, &command_buffer, 1U); - device.present(surface_handle); - device.wait(); - - LARGE_INTEGER end_qpc; - QueryPerformanceCounter(&end_qpc); - LONGLONG diff_qpc = end_qpc.QuadPart - start_qpc.QuadPart; - frame_time = (diff_qpc * 1000000ULL) / freq.QuadPart; - frame_count++; - - // RD_END_CAPTURE; - } - - device.wait(); - device.destroy_surface(surface_handle); - - device.destroy_pipeline(compute); - device.destroy_pipeline(graphics); - 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); - device.destroy_buffer(index_buffer_handle); - device.deinit(); - - ImGui::DestroyContext(); -#endif // VK - - return 0; -} diff --git a/api-test/vk-bindless.cpp b/api-test/vk-bindless.cpp deleted file mode 100644 index d3d6415..0000000 --- a/api-test/vk-bindless.cpp +++ /dev/null @@ -1,431 +0,0 @@ -#include "vk-bindless.hpp" - -#include <vk_mem_alloc.h> -#include <vulkan/vulkan_core.h> - -#include "vk-device.hpp" -#include "vk-utils.hpp" -#include "vulkan-loader.hpp" - -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); -} - -bindless_model bindless_model::create_bindless_model() { - bindless_model bindless; - auto& render_device = vkdevice::get_render_device(); - auto* device = render_device.get_device(); -#ifndef USE_VK_DESCRIPTOR_BUFFER - bindless.create_immutable_samplers(device); - bindless.create_layout(device); - bindless.create_descriptor_pool(device); - bindless.allocate_sets(device); - - // VkWriteDescriptorSet writes_descriptor_set[BindlessSetType::MAX]; - - // { - 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.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 | 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 = 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, - .pNext = nullptr, - .flags = 0U, - .size = desc.size, - .usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr, - }; - - VmaAllocatorCreateFlags alloc_create_flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - VmaAllocationCreateInfo alloc_create_info{ - .flags = alloc_create_flags, - .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, - .requiredFlags = desc.memory_properties, - .preferredFlags = 0U, - .memoryTypeBits = 0U, - .pool = nullptr, - .pUserData = nullptr, - }; - - VmaAllocationInfo alloc_info{}; - - VKCHECK(vmaCreateBuffer(gpu_allocator, &create_info, &alloc_create_info, &device_buffer.vk_buffer, &device_buffer.alloc, &alloc_info)); - - device_buffer.mapped_ptr = alloc_info.pMappedData; - - return { buffers.add(device_buffer) }; -#endif - - return bindless; -} - -void bindless_model::destroy_bindless_model(bindless_model& bindless) { - auto& render_device = vkdevice::get_render_device(); - auto* device = vkdevice::get_render_device().get_device(); - vkDestroyDescriptorPool(device, bindless.descriptor_pool, nullptr); - - for (auto index{ 0U }; index < BindlessSetType::MAX; index++) { - vkDestroyDescriptorSetLayout(device, bindless.sets_layout[index], 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.draws_uniform_buffer_handle); -} - -void bindless_model::create_layout(VkDevice device) { - // Set 0 global resources - // Binding 0 Storage images - // Binding 1 Sampled images - // Binding 2 Samplers - // Binding 3 Dynamic Uniform Buffer - { - VkDescriptorSetLayoutBinding set_layout_bindings[]{ - { - .binding = 0U, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = SamplerType::MAX_SAMPLER, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = samplers, - }, - { - .binding = 1U, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = set_descriptors_count, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = nullptr, - }, - { - .binding = 2U, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = set_descriptors_count, - .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{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, - .pNext = VK_NULL_HANDLE, - .bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags), - .pBindingFlags = flags, - }; - - VkDescriptorSetLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = &layout_binding_flags, - .flags = 0U, - .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), - .pBindings = set_layout_bindings, - }; - - VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::GLOBAL])); - } - - // Set 1 per instance uniforms - // Binding 0 Dynamic Uniform Buffer - { - VkDescriptorSetLayoutBinding set_layout_bindings[]{ - { - .binding = 0U, - .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, - }, - }; - - VkDescriptorSetLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), - .pBindings = set_layout_bindings, - }; - - VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::INSTANCES_UNIFORMS])); - } - - // Set 2 per draw uniforms - // Binding 0 Dynamic Uniform Buffer - { - VkDescriptorSetLayoutBinding set_layout_bindings[]{ - { - .binding = 0U, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = nullptr, - }, - }; - - VkDescriptorSetLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), - .pBindings = set_layout_bindings, - }; - - VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::DRAWS_UNIFORMS])); - } - - { - 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, - }, - }; - - - 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 -void bindless_model::create_descriptor_pool(VkDevice device) { - VkDescriptorPoolSize pool_sizes[]{ - { - .type = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = set_descriptors_count, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = set_descriptors_count, - }, - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = set_descriptors_count, - }, - { - .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = 8U, - }, - }; - - VkDescriptorPoolCreateInfo descriptor_pool_create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .maxSets = descriptor_pool_allocable_sets_count, - .poolSizeCount = sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize), - .pPoolSizes = pool_sizes, - }; - VKCHECK(vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool)); -} - -void bindless_model::allocate_sets(VkDevice device) { - VkDescriptorSetAllocateInfo allocate_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .pNext = nullptr, - .descriptorPool = descriptor_pool, - .descriptorSetCount = 1U, - .pSetLayouts = &sets_layout[BindlessSetType::GLOBAL], - }; - VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::GLOBAL])); - - allocate_info.pSetLayouts = &sets_layout[BindlessSetType::INSTANCES_UNIFORMS], - VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::INSTANCES_UNIFORMS])); - - allocate_info.pSetLayouts = &sets_layout[BindlessSetType::DRAWS_UNIFORMS], - VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::DRAWS_UNIFORMS])); -} - -void bindless_model::create_immutable_samplers(VkDevice device) { - VkSamplerCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, - .pNext = VK_NULL_HANDLE, - .flags = 0, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, - .mipLodBias = 0.f, - .anisotropyEnable = VK_FALSE, - .compareEnable = VK_FALSE, - .compareOp = VK_COMPARE_OP_NEVER, - .minLod = 0.f, - .maxLod = 0.f, - .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - .unnormalizedCoordinates = VK_FALSE, - }; - - // Nearest sampler creation - { - VkFilter filter = VK_FILTER_NEAREST; - VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - create_info.magFilter = filter, - create_info.minFilter = filter, - create_info.addressModeU = address_mode, - create_info.addressModeV = address_mode, - create_info.addressModeW = address_mode, - - VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::NEAREST])); - } - - // Linear sampler creation - { - VkFilter filter = VK_FILTER_LINEAR; - VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - create_info.magFilter = filter, - create_info.minFilter = filter, - create_info.addressModeU = address_mode, - create_info.addressModeV = address_mode, - create_info.addressModeW = address_mode, - - VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::LINEAR])); - } -} - -void bindless_model::destroy_immutable_samplers(VkDevice device) { - for (auto* sampler : samplers) { - vkDestroySampler(device, sampler, nullptr); - } -} -#else -#endif @@ -41,13 +41,13 @@ set DEBUG_L_FLAGS= set RELEASE_C_FLAGS= if %MSVC% EQU 1 ( - set C_FLAGS=/nologo /W4 /WX /Zi /Fo:%BUILD_DIR%\ /Iinclude /Iinclude\api-test /I%VULKAN_SDK%\Include /external:W0 /external:Ithirdparty /external:Ithirdparty\imgui /std:c++20 /DNOMINMAX /EHsc /c /Tp + set C_FLAGS=/nologo /W4 /WX /Zi /Fo:%BUILD_DIR%\ /Iinclude /I%VULKAN_SDK%\Include /external:W0 /external:Ithirdparty /external:Ithirdparty\imgui /std:c++20 /DNOMINMAX /EHsc /c /Tp set DEBUG_C_FLAGS=/DDEBUG /Od set RELEASE_C_FLAGS=/DNDEBUG /O2 set DEBUG_L_FLAGS=/DEBUG ) else ( - set C_FLAGS=--target=x86_64-pc-windows-msvc -pedantic -I include -I include\api-test -I %VULKAN_SDK%\Include -isystem thirdparty -isystem thirdparty\imgui -std=c++20 -DNOMINMAX -c -msse4.1 -Wno-missing-designated-field-initializers + set C_FLAGS=--target=x86_64-pc-windows-msvc -pedantic -I include -I %VULKAN_SDK%\Include -isystem thirdparty -isystem thirdparty\imgui -std=c++20 -DNOMINMAX -c -msse4.1 -Wno-missing-designated-field-initializers set DEBUG_C_FLAGS=-DDEBUG -g -O0 set RELEASE_C_FLAGS=-DNDEBUG -O2 @@ -76,19 +76,19 @@ if 0 EQU 1 ( :: set src=main dx12-device dx12-command-buffer :: (for %%s in (%api%) do ( :: call set OBJS=%%OBJS%% %BUILD_DIR%\%%s.obj -:: echo %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% api-test\%%s.cpp -:: %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% api-test\%%s.cpp +:: echo %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% src\%%s.cpp +:: %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% src\%%s.cpp :: )) :: link multiple objs :: link %L_FLAGS% /OUT:%BUILD_DIR%\main.exe %OBJS% kernel32.lib user32.lib :: compiles the project as a single compilation unit if %MSVC% EQU 1 ( - echo %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% api-test\main.cpp - %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% api-test\main.cpp + echo %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% src\main.cpp + %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% src\main.cpp ) else ( - echo %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% api-test\main.cpp - %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% api-test\main.cpp + echo %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% src\main.cpp + %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% src\main.cpp ) link %L_FLAGS% /OUT:%BUILD_DIR%\main.exe %BUILD_DIR%\main.obj kernel32.lib user32.lib shlwapi.lib diff --git a/include/api-test/handle.hpp b/include/api-test/handle.hpp deleted file mode 100644 index 2c52c01..0000000 --- a/include/api-test/handle.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include <cstdint> - -// template<typename T> -// struct handle { -// uint32_t id = handle::invalid_id; -// -// [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } -// -// static constexpr uint32_t invalid_id = -1U; -// }; - -template<typename U> -struct handle { - uint32_t id = invalid_id; - uint32_t generation = 0U; - - [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } - - static constexpr uint32_t invalid_id = UINT32_MAX; - - // static constexpr handle<U> invalid_handle {}; -}; diff --git a/include/api-test/resource-manager.hpp b/include/api-test/resource-manager.hpp deleted file mode 100644 index f414367..0000000 --- a/include/api-test/resource-manager.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "handle.hpp" -#include "freelist.hpp" -#include "texture.hpp" -#include "buffer.hpp" - -class resourcemanager { -public: - - handle<texture> create_texture(const texture_desc& desc); - - handle<buffer> create_buffer(const buffer_desc& desc); - - const texture& get_texture(handle<texture> handle); - - const buffer& get_buffer(handle<buffer> handle); - -private: - freelist<texture> textures; - freelist<buffer> buffers; -}; diff --git a/include/api-test/texture.hpp b/include/api-test/texture.hpp deleted file mode 100644 index 59bfec1..0000000 --- a/include/api-test/texture.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include <cstdint> - -#include <vulkan/vulkan_core.h> - -#include "handle.hpp" - -struct device_texture; - -class texture { -public: - texture(handle<device_texture> handle); - -private: - handle<device_texture> handle; -}; diff --git a/include/api-test/vk-bindless.hpp b/include/api-test/vk-bindless.hpp deleted file mode 100644 index a5686ff..0000000 --- a/include/api-test/vk-bindless.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include <cstdint> - -#include <vulkan/vulkan_core.h> - -#include "handle.hpp" - -enum BindlessSetType : uint32_t { - GLOBAL, - INSTANCES_UNIFORMS, - DRAWS_UNIFORMS, - MAX, -}; - -enum ConstantType : uint32_t { - GLOBALS, - INSTANCES, - DRAWS, - VERTEX_BUFFER -}; - -enum SamplerType : uint32_t { - NEAREST, - LINEAR, - MAX_SAMPLER, -}; - -struct device_buffer; - -struct bindless_model { -#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 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<device_buffer> globals_uniform_buffer_handle; - handle<device_buffer> instances_uniform_buffer_handle; - handle<device_buffer> draws_uniform_buffer_handle; - - static constexpr size_t descriptor_pool_allocable_sets_count = 64U; - static constexpr uint32_t set_descriptors_count = 1024U; - - void create_layout(VkDevice device); - void create_descriptor_pool(VkDevice device); - void allocate_sets(VkDevice device); - - void destroy_descriptor_pool(VkDevice device); - - void create_immutable_samplers(VkDevice device); - - void destroy_immutable_samplers(VkDevice device); - - 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 - VkPipelineLayout layout; - VkDescriptorSetLayout sets_layout[BindlessSetType::MAX]; - - static constexpr size_t descriptor_pool_allocable_sets_count = 64U; - static constexpr uint32_t set_descriptors_count[BindlessSetType::MAX]{ 1024U }; - - static bindless_model create_bindless_model(VkDevice device); - - static void destroy_bindless_model(VkDevice device, bindless_model& bindless); - - private: - void create_layout(VkDevice device); - - handle<device_buffer> storage_image_descriptors; - handle<device_buffer> sampled_image_descriptors; -#endif -}; diff --git a/include/api-test/buffer.hpp b/include/buffer.hpp index 64c4881..64c4881 100644 --- a/include/api-test/buffer.hpp +++ b/include/buffer.hpp diff --git a/include/bvh-node.hpp b/include/bvh-node.hpp deleted file mode 100644 index 525e1c8..0000000 --- a/include/bvh-node.hpp +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef __BVH_NODE_HPP_
-#define __BVH_NODE_HPP_
-
-#include <vector>
-#include <algorithm>
-#include <iostream>
-
-#include "aabb.hpp"
-// #include "sphere.hpp"
-#include "triangle.hpp"
-
-struct bvh_node {
- aabb bounding_box;
-
- int32_t next_id = -1;
- int32_t primitive_id = -1;
- uint32_t padding[2];
-};
-
-struct packed_bvh_node {
- float min[3];
- int32_t next_id = -1;
- float max[3];
- int32_t primitive_id = -1;
-};
-
-struct temp_node : public bvh_node {
- int32_t left_id;
- int32_t df_id;
-};
-
-class bvh {
-public:
- // bvh(std::vector<sphere>& spheres, std::vector<packed_bvh_node>& packed_nodes)
- // :spheres(spheres) {
- // packed_nodes.resize(2 * spheres.size() - 1);
- // temp_nodes = std::vector<temp_node>(2 * spheres.size() - 1);
- // leafs = std::vector<temp_node>(spheres.size());
-
- // for (uint32_t id = 0; id < spheres.size(); id++) {
- // leafs[id].bounding_box = aabb(spheres[id].center, spheres[id].radius);
- // leafs[id].primitive_id = id;
- // }
-
- // temp_nodes[0] = temp_node();
-
- // temp_nodes[0].bounding_box = compute_bounds(0, spheres.size());
- // subdivide(0, 0, spheres.size());
-
- // set_depth_first_order();
-
- // for (uint32_t id = 0; id < temp_nodes.size(); id++) {
- // auto old_node = temp_nodes[id];
- // auto &node = packed_nodes[old_node.df_id];
-
- // node.primitive_id = old_node.primitive_id;
-
- // node.min[0] = old_node.bounding_box.minimum.v[0];
- // node.min[1] = old_node.bounding_box.minimum.v[1];
- // node.min[2] = old_node.bounding_box.minimum.v[2];
-
- // node.max[0] = old_node.bounding_box.maximum.v[0];
- // node.max[1] = old_node.bounding_box.maximum.v[1];
- // node.max[2] = old_node.bounding_box.maximum.v[2];
-
- // if (old_node.next_id != -1) {
- // node.next_id = temp_nodes[old_node.next_id].df_id;
- // }
- // }
-
- // // exporter();
- // }
-
- bvh(std::vector<triangle>& triangles, std::vector<packed_bvh_node>& packed_nodes)
- :triangles(triangles) {
- packed_nodes.resize(2 * triangles.size() - 1);
- temp_nodes = std::vector<temp_node>(2 * triangles.size() - 1);
- leafs = std::vector<temp_node>(triangles.size());
-
- for (uint32_t id = 0; id < triangles.size(); id++) {
- leafs[id].bounding_box = aabb(triangles[id]);
- leafs[id].primitive_id = id;
- }
-
- temp_nodes[0] = temp_node();
-
- temp_nodes[0].bounding_box = compute_bounds(0, triangles.size());
- subdivide(0, 0, triangles.size());
-
- set_depth_first_order();
-
- for (uint32_t id = 0; id < temp_nodes.size(); id++) {
- auto old_node = temp_nodes[id];
- auto &node = packed_nodes[old_node.df_id];
-
- node.primitive_id = old_node.primitive_id;
-
- node.min[0] = old_node.bounding_box.minimum.v[0];
- node.min[1] = old_node.bounding_box.minimum.v[1];
- node.min[2] = old_node.bounding_box.minimum.v[2];
-
- node.max[0] = old_node.bounding_box.maximum.v[0];
- node.max[1] = old_node.bounding_box.maximum.v[1];
- node.max[2] = old_node.bounding_box.maximum.v[2];
-
- if (old_node.next_id != -1) {
- node.next_id = temp_nodes[old_node.next_id].df_id;
- }
- }
-
- // exporter();
- }
-
- //-------------------------
- // BVH exporter for graphviz
- //-------------------------
- void exporter() {
- std::cout << "digraph bvh {" << std::endl;
-
- traverse_depth_first(temp_nodes, 0);
-
- // traverse_depth_first_ordered(-1, 0);
-
- std::cout << "}" << std::endl;
- }
-
- bool traverse_depth_first(std::vector<temp_node>& nodes, int32_t id) {
- if (id <= 0) {
- std::cout << ";" << std::endl;
- return false;
- }
-
- std::cout << " -> " << id;
- if (traverse_depth_first(nodes, nodes[id].left_id)) {
- std::cout << "\t " << id;
- traverse_depth_first(nodes, nodes[id].left_id + 1);
- }
-
- return true;
- }
-
- int32_t traverse_depth_first_ordered(std::vector<bvh_node>& nodes, int32_t parent_id, int32_t id) {
- if (id == -1) {
- return -1;
- }
-
- if (nodes[id].primitive_id == -1) {
- int32_t left = id + 1;
- int32_t next_id;
-
- std::cout << "\t " << parent_id << " -> " << id << ";\n";
- next_id = traverse_depth_first_ordered(nodes, id, left);
-
- if (next_id != -1) {
- return traverse_depth_first_ordered(nodes, id, next_id);
- }
- } else if (nodes[id].primitive_id != -1 && nodes[id].next_id != -1) {
- std::cout << "\t " << parent_id << " -> " << id << ";\n";
- return nodes[id].next_id;
- } else {
- std::cout << "\t " << parent_id << " -> " << id << ";\n";
- }
-
- return -1;
- }
-
- std::vector<temp_node> temp_nodes;
- std::vector<temp_node> leafs;
-
- // std::vector<sphere>& spheres;
- std::vector<triangle>& triangles;
-
- uint32_t next_node_id = 0;
-
-private:
-
- static constexpr uint32_t buckets_count = 12;
-
- aabb compute_bounds(uint32_t begin, uint32_t end) {
- aabb global_box = aabb();
-
- for (uint32_t id = begin; id < end; id++) {
- global_box.union_with(leafs[id].bounding_box);
- }
-
- return global_box;
- }
-
- void subdivide(uint32_t parent_id, uint32_t begin, uint32_t end) {
- size_t count = end - begin;
- if (count == 1) {
- temp_nodes[parent_id] = leafs[begin];
- return;
- }
-
- auto left_id = ++next_node_id;
- auto right_id = ++next_node_id;
-
- temp_nodes[parent_id].left_id = left_id;
-
- if (count == 2) {
- temp_nodes[left_id] = leafs[begin];
- temp_nodes[right_id] = leafs[begin + 1];
- } else {
- auto parent_bb = temp_nodes[parent_id].bounding_box;
- int32_t split_axis = parent_bb.maximum_axis();
-
- if (count <= 4) {
- // Subdivide the node by splitting the set in two equal parts
- std::sort(leafs.begin() + begin, leafs.begin() + end,
- // [&](const bvh_node& a, const bvh_node& b) {
- // return spheres[a.primitive_id].center[split_axis] < spheres[b.primitive_id].center[split_axis];
- // }
- [&](const bvh_node& a, const bvh_node& b) {
- return triangles[a.primitive_id].center()[split_axis] < triangles[b.primitive_id].center()[split_axis];
- }
- );
-
- temp_nodes[left_id].bounding_box = compute_bounds(begin, begin + (count / 2));
- temp_nodes[right_id].bounding_box = compute_bounds(begin + (count / 2), end);
-
- subdivide(left_id, begin, begin + (count / 2));
- subdivide(right_id, begin + (count / 2), end);
- } else {
- // Subdivide based on SAH
- struct Bucket {
- uint32_t count = 0;
- aabb bb;
- };
- Bucket buckets[buckets_count];
-
- // Split the set in N spatial buckets
- // Simplify the optimal split axis search to just an axis between each bucket
- aabb centroid_bounds;
-
- for (size_t i = begin; i < end; i++) {
- auto primitive = triangles[leafs[i].primitive_id];
- centroid_bounds.union_with(primitive.center());
- // auto primitive = spheres[leafs[i].primitive_id];
- // centroid_bounds.union_with(primitive.center);
- }
-
- float split_axis_size = centroid_bounds.maximum[split_axis] - centroid_bounds.minimum[split_axis];
- for (size_t i = begin; i < end; i++) {
- auto primitive = triangles[leafs[i].primitive_id];
- auto normalized_offset = (primitive.center()[split_axis] - centroid_bounds.minimum[split_axis]) / split_axis_size;
- // auto primitive = spheres[leafs[i].primitive_id];
- // auto normalized_offset = (primitive.center[split_axis] - centroid_bounds.minimum[split_axis]) / split_axis_size;
- uint32_t bucket_index = normalized_offset * buckets_count;
- if (bucket_index == buckets_count) {
- bucket_index -= 1;
- }
-
- buckets[bucket_index].count++;
- buckets[bucket_index].bb.union_with(leafs[i].bounding_box);
- }
-
- // Compute each potential split axis cost
- float buckets_cost[buckets_count - 1] = { 0.f };
- for (size_t bucket_index = 0; bucket_index < buckets_count - 1; bucket_index++) {
- aabb right_side_bb, left_side_bb;
- float right_side_count = 0, left_side_count = 0;
-
- for (size_t i = 0; i <= bucket_index; i++) {
- left_side_bb.union_with(buckets[i].bb);
- left_side_count += buckets[i].count;
- }
-
- for (size_t i = bucket_index + 1; i < buckets_count; i++) {
- right_side_bb.union_with(buckets[i].bb);
- right_side_count += buckets[i].count;
- }
-
- float left = left_side_count * left_side_bb.surface_area();
- float right = right_side_count * right_side_bb.surface_area();
- buckets_cost[bucket_index] = 0.125f + (left + right) / parent_bb.surface_area();
- }
-
- float min_cost = buckets_cost[0];
- uint32_t min_cost_bucket = 0;
- for (size_t bucket_index = 1; bucket_index < buckets_count - 1; bucket_index++) {
- if (buckets_cost[bucket_index] < min_cost) {
- min_cost = buckets_cost[bucket_index];
- min_cost_bucket = bucket_index;
- }
- }
-
- uint32_t middle_primitive_index = buckets[0].count;
- for (size_t bucket_index = 1; bucket_index <= min_cost_bucket; bucket_index++) {
- middle_primitive_index += buckets[bucket_index].count;
- }
-
- temp_nodes[left_id].bounding_box = compute_bounds(begin, begin + middle_primitive_index);
- temp_nodes[right_id].bounding_box = compute_bounds(begin + middle_primitive_index, end);
-
- subdivide(left_id, begin, begin + middle_primitive_index);
- subdivide(right_id, begin + middle_primitive_index, end);
- }
- }
- }
-
- void set_depth_first_order() {
- int32_t df_index = 0;
- depth_first_order(0, -1, df_index);
- }
-
-
- void depth_first_order(int32_t id, int32_t next_id, int32_t &new_id) {
- auto &node = temp_nodes[id];
- node.next_id = next_id;
- node.df_id = new_id++;
-
- if (node.left_id > 0) {
- depth_first_order(node.left_id, node.left_id + 1, new_id);
- depth_first_order(node.left_id + 1, next_id, new_id);
- }
- }
-};
-
-#endif // !__BVH_NODE_HPP_
diff --git a/include/compute-renderpass.hpp b/include/compute-renderpass.hpp deleted file mode 100644 index 6799171..0000000 --- a/include/compute-renderpass.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "renderpass.hpp" -#include "vk-api.hpp" - -class Texture; -class Buffer; - -class ComputeRenderpass : public Renderpass { - public: - - ComputeRenderpass(vkapi& api); - ~ComputeRenderpass() override; - - void set_pipeline(const char* shader_name); - - void set_dispatch_size(size_t count_x, size_t count_y, size_t count_z); - - void set_ouput_texture(Texture* out_texture); - - void set_constant(off_t offset, uint64_t* constant); - void set_constant(off_t offset, Texture* texture); - void set_constant(off_t offset, Buffer* buffer); - - // TODO: Do not use vulkan api type - void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) final; - - Texture* output_texture; - - private: - - std::vector<Texture*> input_textures; - - uint8_t constants[64]; - - size_t group_count_x; - size_t group_count_y; - size_t group_count_z; - - pipeline pipeline; -}; diff --git a/include/api-test/dx12-command-buffer.hpp b/include/dx12-command-buffer.hpp index e9de39a..e9de39a 100644 --- a/include/api-test/dx12-command-buffer.hpp +++ b/include/dx12-command-buffer.hpp diff --git a/include/api-test/dx12-device-types.hpp b/include/dx12-device-types.hpp index 4b2fc42..4b2fc42 100644 --- a/include/api-test/dx12-device-types.hpp +++ b/include/dx12-device-types.hpp diff --git a/include/api-test/dx12-device.hpp b/include/dx12-device.hpp index baa5b60..baa5b60 100644 --- a/include/api-test/dx12-device.hpp +++ b/include/dx12-device.hpp diff --git a/include/api-test/freelist.hpp b/include/freelist.hpp index cbcd56d..2df1ca5 100644 --- a/include/api-test/freelist.hpp +++ b/include/freelist.hpp @@ -1,10 +1,9 @@ #pragma once -#include <vector> -#include <cassert> +#include "utils.hpp" #include "handle.hpp" -static constexpr uint32_t default_element_count = 1024U; +static constexpr u32 default_element_count = 1024U; template<typename T, const size_t initial_size = default_element_count> class freelist { @@ -31,6 +30,8 @@ class freelist { // elements[0U].next_free = element.next_free; element.item = std::move(item); + assert(element.generation + 1 != UINT32_MAX); + return { id, ++element.generation }; } @@ -54,9 +55,21 @@ class freelist { static constexpr uint32_t invalid_id = UINT32_MAX; + struct element { + union { + T item; + uint32_t next_free = freelist<T>::invalid_id; + }; + uint32_t generation = 0U; + }; + + const std::vector<freelist::element>& get_list() const { + return elements; + } + private: void grow(size_t grow_size) { - auto size = elements.size(); + size_t size = elements.size(); uint32_t next_free = static_cast<uint32_t>(size); next_free_id = next_free; @@ -70,17 +83,11 @@ private: ); } + // this makes it impossible to know + elements.back().next_free = freelist<T>::invalid_id; elements.back().next_free = freelist<T>::invalid_id; } - struct element { - union { - T item; - uint32_t next_free = freelist<T>::invalid_id; - }; - uint32_t generation = 0U; - }; - std::vector<element> elements; uint32_t next_free_id; }; @@ -97,7 +104,7 @@ class idlist { // auto id = elements[0U].next_free; auto id = next_free_id; - if (id == idlist<T>::invalid_id) { + if (id == idlist::invalid_id) { grow(elements.size()); // id = elements[0U].next_free; @@ -107,7 +114,7 @@ class idlist { auto& element = elements[id]; next_free_id = element.next_free; elements[0U].next_free = element.next_free; - element.next_free = idlist<T>::invalid_id; + element.next_free = idlist::invalid_id; return { id, ++element.generation }; } @@ -138,11 +145,11 @@ private: ); } - elements.back().next_free = idlist<T>::invalid_id; + elements.back().next_free = idlist::invalid_id; } struct element { - uint32_t next_free = idlist<T>::invalid_id; + uint32_t next_free = idlist::invalid_id; uint32_t generation = 0U; }; diff --git a/include/handle.hpp b/include/handle.hpp new file mode 100644 index 0000000..484b217 --- /dev/null +++ b/include/handle.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include <cstdint> + +template<typename U> +struct handle { + uint32_t id = invalid_id; + uint32_t generation = 0U; + + [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } + + static constexpr uint32_t invalid_id = UINT32_MAX; +}; diff --git a/include/primitive-renderpass.hpp b/include/primitive-renderpass.hpp deleted file mode 100644 index 95562fe..0000000 --- a/include/primitive-renderpass.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include <vector> - -#include "renderpass.hpp" -#include "vk-renderer.hpp" - -class Buffer; -class Texture; -class Sampler; -class Primitive; - -class PrimitiveRenderpass : public Renderpass { - public: - - PrimitiveRenderpass(vkapi& api); - - void add_primitive(Primitive* new_primitive); - - void add_color_attachment(VkFormat format); - - void set_depth_stencil(Texture* depth_stencil); - - void set_viewport(float x, float y, float width, float height); - - void set_color_attachment(uint32_t index, Texture* attachment); - - void finalize_render_pass(); - - void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) final; - - VkRenderPass render_pass = VK_NULL_HANDLE; - - private: - - void create_framebuffers(); - - void recreate_framebuffers(); - - VkViewport viewport = { .minDepth = 0.f, .maxDepth = 1.f }; - - std::vector<Texture*> color_attachments; - std::vector<VkImageView> color_attachments_view; - std::vector<VkFormat> color_attachments_format; - - framebuffer framebuffers[vkrenderer::virtual_frames_count]; - - std::vector<Primitive*> primitives; -}; - - -class Primitive { - public: - - Primitive(PrimitiveRenderpass& render_pass); - - void set_pipeline(const char* shader_name); - - void set_constant_offset(off_t offset); - void set_constant(off_t offset, uint64_t* constant); - void set_constant(off_t offset, Texture* texture); - void set_constant(off_t offset, Buffer* buffer); - void set_constant(off_t offset, Sampler* sampler); - - void set_index_buffer(Buffer* buffer); - - void set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height); - - void set_draw_info(size_t vertex_count, off_t indices_off, off_t vertex_off); - - void render(VkCommandBuffer command_buffer); - - -private: - - vkapi& api; - - PrimitiveRenderpass& primitive_render_pass; - - pipeline pipeline; - - Buffer* index_buffer; - - size_t element_count; - off_t indices_offset; - off_t vertex_offset; - - off_t constant_offset; - - VkRect2D scissor = {}; - - uint8_t constants[64]; -}; diff --git a/include/renderpass.hpp b/include/renderpass.hpp deleted file mode 100644 index da116dd..0000000 --- a/include/renderpass.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -using VkCommandBuffer = struct VkCommandBuffer_T*; - -class vkrenderer; -class vkapi; - -class Renderpass { - public: - - Renderpass(vkapi& api) - :api(api) - {}; - - virtual ~Renderpass() = default; - - // TODO: Do not use vulkan api type - virtual void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) = 0; - - protected: - vkapi &api; -}; diff --git a/include/texture.hpp b/include/texture.hpp index aac7b69..59bfec1 100644 --- a/include/texture.hpp +++ b/include/texture.hpp @@ -1,83 +1,17 @@ -#include <cstdint> - -using VkImage = struct VkImage_T*; - -struct TextureDesc { - VkImageType type; - VkFormat format; - VkExtent size; - VkImageUsageFlags usages; -}; - -class Texture { - public: - Texture(const TextureDesc desc) - : description(desc) { - create_device_image(); - } - - // Texture(handle image_handle) { - // const auto& image = vkrenderer::api.get_image(image_handle); - // width = image.size.width; - // height = image.size.height; - // depth = image.size.depth; - - // device_image = image_handle; - // } - - // Texture(size_t width, size_t height, size_t depth, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM, Sampler* texture_sampler = nullptr) - // : width(width), height(height), depth(depth) { - // sampler = texture_sampler; - // device_image = vkrenderer::api.create_image( - // { .width = (uint32_t)width, .height = (uint32_t)height, .depth = 1 }, - // format, - // VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - // } +#pragma once - void update(void* new_data) { - if (data == nullptr) { - free(data); - } - data = new_data; - - vkrenderer::queue_image_update(this); - } - - ~Texture() { - vkrenderer::api.destroy_image(device_image); - - if (data == nullptr) { - free(data); - } - } - - [[nodiscard]] size_t size() const { - const auto& image = vkrenderer::api.get_image(device_image); - return width * height * depth * pixel_size(image.format); - } - - static size_t pixel_size(VkFormat format) { - switch (format) { - case VK_FORMAT_R8G8B8A8_UNORM: - return 4; - default: - return 0; - } - } - - // Sampler* sampler = nullptr; +#include <cstdint> - private: - void create_device_image(); +#include <vulkan/vulkan_core.h> - void* data = nullptr; +#include "handle.hpp" - size_t width = 0; - size_t height = 0; - size_t depth = 0; +struct device_texture; - TextureDesc description; +class texture { +public: + texture(handle<device_texture> handle); - VmaAllocationInfo alloc_info; - VkImage device_image; +private: + handle<device_texture> handle; }; diff --git a/include/vk-api.hpp b/include/vk-api.hpp deleted file mode 100644 index a3442f1..0000000 --- a/include/vk-api.hpp +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef __VK_API_HPP_ -#define __VK_API_HPP_ - -#include <cassert> -#include <vector> - -#include <vulkan/vulkan_core.h> - -using VmaAllocation = struct VmaAllocation_T*; - -struct buffer { - VmaAllocation alloc; - void* device_ptr; - VkBuffer handle; - size_t size; - VkDeviceAddress device_address; -}; - -struct pipeline { - std::vector<VkShaderModule> shader_modules; - VkPipeline handle = VK_NULL_HANDLE; - VkPipelineBindPoint bind_point; -}; - -using bindless_index = uint32_t; -using handle = uint32_t; - -struct image { - VkImage handle; - VkImageView view; - VmaAllocation alloc; - VkImageSubresourceRange subresource_range; - VkFormat format; - VkExtent3D size; - VkImageUsageFlags usages; - bindless_index bindless_storage_index = 0; - bindless_index bindless_sampled_index = 0; - - VkImageLayout previous_layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkPipelineStageFlags previous_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkAccessFlags previous_access = 0; -}; - -struct swapchain { - uint32_t image_count; - std::vector<handle> images; - VkSwapchainKHR handle; - VkSurfaceFormatKHR surface_format; - VkExtent2D extent; -}; - -struct framebuffer { - VkFramebuffer handle; - VkExtent2D size; -}; - -struct sampler { - VkSampler handle; - bindless_index bindless_index; -}; - -struct global_descriptor { - VkDescriptorSetLayout set_layout; - VkPipelineLayout pipeline_layout; - VkDescriptorSet set; - - std::vector<uint32_t> index_pool[3]; - - static constexpr uint32_t pool_size = 1024U; - - global_descriptor() { - for (int32_t index = pool_size; index > 0; index--) { - index_pool[0].push_back((uint32_t)index); - index_pool[1].push_back((uint32_t)index); - index_pool[2].push_back((uint32_t)index); - } - } - - uint32_t allocate(VkDescriptorType type) { - auto& pool = index_pool[descriptor_type_binding(type)]; - auto index = pool.back(); - pool.pop_back(); - - return index; - } - - void free(uint32_t index, VkDescriptorType type) { - assert(index != 0); - index_pool[descriptor_type_binding(type)].push_back(index); - } - - static int32_t descriptor_type_binding(VkDescriptorType type) { - switch (type) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - return 0; - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - return 1; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - return 2; - default: - assert(true && "descriptor type not supported"); - return -1; - } - } -}; - -class window; -class vkcontext; - -class vkapi { - public: - vkapi(vkcontext& context); - ~vkapi(); - - handle create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, uint32_t mem_usage); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size, size_t buffer_offset = 0); - void destroy_buffer(handle buffer); - - - handle create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages); - void destroy_image(handle image); - std::vector<handle> create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count); - void destroy_images(std::vector<handle>& imgs); - - - [[nodiscard]] VkFence create_fence() const; - void destroy_fence(VkFence fence) const; - [[nodiscard]] std::vector<VkFence> create_fences(size_t fences_count) const; - void destroy_fences(VkFence fences[], size_t fences_count) const; - - - [[nodiscard]] VkSemaphore create_semaphore() const; - void destroy_semaphore(VkSemaphore semaphore) const; - [[nodiscard]] std::vector<VkSemaphore> create_semaphores(size_t semaphores_count) const; - void destroy_semaphores(VkSemaphore semaphores[], size_t semaphores_count) const; - - handle create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - void destroy_sampler(handle sampler); - - - [[nodiscard]] VkCommandPool create_command_pool() const; - - void allocate_command_buffers(VkCommandPool command_pool, VkCommandBuffer* command_buffers, size_t count) const; - - - VkRenderPass create_render_pass(std::vector<VkFormat>& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout); - VkRenderPass create_render_pass(std::vector<VkFormat>& color_attachments_format, VkFormat depth_attachement_format); - void destroy_render_pass(VkRenderPass render_pass); - - - framebuffer create_framebuffer(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size); - std::vector<framebuffer> create_framebuffers(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size, uint32_t framebuffer_count); - void destroy_framebuffer(framebuffer framebuffer) const; - void destroy_framebuffers(std::vector<framebuffer>& framebuffers) const; - - - pipeline create_compute_pipeline(const char* shader_name) const; - pipeline create_graphics_pipeline(const char* shader_name, VkShaderStageFlagBits shader_stages, VkRenderPass render_pass, std::vector<VkDynamicState>& dynamic_states) const; - void destroy_pipeline(pipeline& pipeline) const; - - - VkSurfaceKHR create_surface(window& wnd) const; - void destroy_surface(VkSurfaceKHR surface); - - - swapchain create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain); - void destroy_swapchain(swapchain& swapchain); - - void update_descriptor_image(handle img, VkDescriptorType type); - void update_descriptor_images(std::vector<handle>& images, VkDescriptorType type); - void update_descriptor_sampler(handle sampler); - void update_descriptor_samplers(std::vector<handle>& samplers); - - - void update_constants(VkCommandBuffer command_buffer, VkShaderStageFlagBits shader_stage, off_t offset, size_t size, void* data); - - void start_record(VkCommandBuffer command_buffer); - - void image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image); - - void begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector<VkImageView>& attachments, framebuffer framebuffer, VkExtent2D size); - void end_render_pass(VkCommandBuffer command_buffer); - - void run_compute_pipeline(VkCommandBuffer command_buffer, pipeline& pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z); - - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t vertex_count, uint32_t vertex_offset); - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t primitive_count, uint32_t indices_offset, uint32_t vertices_offset); - - void blit_full(VkCommandBuffer command_buffer, handle src_image, handle dst_image); - - void end_record(VkCommandBuffer command_buffer); - - VkResult submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const; - - VkResult present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const; - - const buffer& get_buffer(handle buffer_handle) { return *buffers[buffer_handle]; }; - - const image& get_image(handle image_handle) { return *images[image_handle]; }; - - const sampler& get_sampler(handle sampler_handle) { return *samplers[sampler_handle]; }; - - vkcontext& context; - - private: - global_descriptor bindless_descriptor; - - static const char* shader_stage_extension(VkShaderStageFlags shader_stage); - - // TODO: Use freelists instead - std::vector<buffer*> buffers; - std::vector<image*> images; - std::vector<sampler*> samplers; - - VkDescriptorPool descriptor_pool; -}; - -#endif // !__VK_API_HPP_ diff --git a/include/vk-bindless.hpp b/include/vk-bindless.hpp new file mode 100644 index 0000000..008e420 --- /dev/null +++ b/include/vk-bindless.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include <vulkan/vulkan_core.h> + +#include "handle.hpp" + +enum UniformTypes : uint32_t { + GLOBAL, + PASS, + DRAW, + MAX, +}; + +enum SamplerType : uint32_t { + NEAREST, + LINEAR, + MAX_SAMPLER, +}; + +struct device_buffer; + +struct bindless_model { + [[nodiscard]] device_buffer& get_uniform_buffer(enum UniformTypes type) const; + + void init(); + + void deinit(); + + VkPipelineLayout global_layout; + VkDescriptorSet global_set; + +public: + static constexpr size_t push_constant_slot_size = sizeof(uintptr_t); + static constexpr size_t push_constant_slots = 3U; + +private: + VkDescriptorSetLayout global_set_layout; + VkDescriptorPool descriptor_pool; + handle<device_buffer> uniform_buffers[UniformTypes::MAX]; + + static constexpr size_t descriptor_pool_allocable_sets_count = 64U; + static constexpr uint32_t set_descriptors_count = 1024U; + + VkSampler samplers[SamplerType::MAX_SAMPLER]; + + static constexpr size_t globals_uniform_buffer_size = 64 * KB; + static constexpr size_t passes_uniform_buffer_size = 64 * KB; + static constexpr size_t draws_uniform_buffer_size = 64 * KB; +}; diff --git a/include/api-test/vk-command-buffer.hpp b/include/vk-command-buffer.hpp index 08652fd..82d5439 100644 --- a/include/api-test/vk-command-buffer.hpp +++ b/include/vk-command-buffer.hpp @@ -1,37 +1,17 @@ #pragma once -#include <cstdint> -#include <span> - -#include <vulkan/vulkan_core.h> - #include "handle.hpp" - -#include "vec3.hpp" - #include "vk-device-types.hpp" +#include "vec3.hpp" struct device_texture; 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<device_pipeline> pipeline; vec3u group_size; vec3u local_group_size; - uint64_t params[static_cast<uint32_t>(PARAM_BINDING::MAX)]; }; struct renderpass_params { @@ -54,10 +34,6 @@ struct draw_params { 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 { @@ -67,10 +43,6 @@ struct draw_indexed_params { uint32_t vertex_offset; uint32_t index_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 command_buffer { diff --git a/include/vk-context.hpp b/include/vk-context.hpp deleted file mode 100644 index 0dfd256..0000000 --- a/include/vk-context.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include <vulkan/vulkan_core.h> - -using VmaAllocator = struct VmaAllocator_T*; - -struct queue { - VkQueue handle; - uint32_t index; - VkQueueFlags usages; -}; - -class vkcontext { - public: - vkcontext(); - - ~vkcontext(); - - VkInstance instance; - - VkPhysicalDevice physical_device; - VkDevice device; - - VmaAllocator allocator; - - queue graphics_queue; - - private: - void create_instance(); - - void create_debugger(); - - void create_device(); - - void create_memory_allocator(); - - void select_physical_device(); - - [[nodiscard]] uint32_t select_queue(VkQueueFlags queue_usage) const; - - static void check_available_instance_layers(const char* needed_layers[], size_t needed_layers_count); - - static void check_available_instance_extensions(const char* needed_extensions[], size_t needed_extensions_count); - - static bool support_required_features(VkPhysicalDevice physical_device); - - - VkDebugUtilsMessengerEXT debugMessenger; -}; diff --git a/include/api-test/vk-device-types.hpp b/include/vk-device-types.hpp index eddf40c..94f9560 100644 --- a/include/api-test/vk-device-types.hpp +++ b/include/vk-device-types.hpp @@ -1,8 +1,6 @@ #pragma once -#include <vulkan/vulkan_core.h> - -#include <span> +#include <cstdint> #include "freelist.hpp" @@ -60,6 +58,8 @@ struct device_texture { uint32_t depth = 1U; uint32_t mips = 1U; + const char* name = nullptr; + private: handle<void> storage_index; handle<void> sampled_index; @@ -110,52 +110,56 @@ struct buffer_desc { VkBufferUsageFlags usages; VkMemoryPropertyFlags memory_properties; uint32_t memory_usage; + const char* name; }; -#define ALIGN(value, alignment) \ - (((value) + ((alignment) - 1)) & ~((alignment) - 1)) - struct device_buffer { template<typename T> T* allocate() { - // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; - size_t alloc_size = ALIGN(sizeof(T), 16); - if (offset + alloc_size > size) { + u32 alloc_size = sizeof(T); + if (allocated_size + alloc_size > size) { reset(); } - auto* addr = (T*)(static_cast<uint8_t*>(mapped_ptr) + offset); - offset += alloc_size; + offset = allocated_size; + T* addr = (T*)(static_cast<uint8_t*>(mapped_ptr) + offset); + allocated_size += alloc_size; return addr; } - void* allocate(uint64_t alloc_size) { - // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; - alloc_size = ALIGN(alloc_size, 16); - if (offset + alloc_size > size) { + void* allocate(u32 alloc_size) { + if (allocated_size + alloc_size > size) { reset(); } - auto* addr = (void*)(static_cast<uint8_t*>(mapped_ptr) + offset); - offset += alloc_size; + offset = allocated_size; + void* addr = (void*)(static_cast<uint8_t*>(mapped_ptr) + offset); + allocated_size += alloc_size; return addr; } void reset() { + allocated_size = 0U; offset = 0U; } - uint64_t offset = 0U; - VkBuffer vk_buffer; - VmaAllocation alloc; - VkDeviceAddress device_address = 0U; - void* mapped_ptr; - size_t size; + u32 offset = 0U; + u32 allocated_size = 0U; + VkBuffer vk_buffer; + VmaAllocation alloc; + VkDeviceAddress device_address = 0U; + void* mapped_ptr; + size_t size; + VkBufferUsageFlagBits2 usages; + + const char* name; }; struct graphics_pipeline_desc { - std::span<uint8_t> vs_code; - std::span<uint8_t> fs_code; + uint8_t* vs_code; + size_t vs_code_size; + uint8_t* fs_code; + size_t fs_code_size; std::span<VkFormat> color_attachments_format; VkFormat depth_attachment_format; VkFormat stencil_attachment_format; @@ -163,7 +167,8 @@ struct graphics_pipeline_desc { }; struct compute_pipeline_desc { - std::span<uint8_t> cs_code; + uint8_t* cs_code; + size_t cs_code_size; const char* name; }; diff --git a/include/api-test/vk-device.hpp b/include/vk-device.hpp index 1b04bb3..e2e8c99 100644 --- a/include/api-test/vk-device.hpp +++ b/include/vk-device.hpp @@ -1,13 +1,8 @@ #pragma once -#include <cstdint> -#include <span> - -#include <vulkan/vulkan_core.h> - #include "freelist.hpp" -#include "vk-device-types.hpp" #include "vk-bindless.hpp" +#include "vk-command-buffer.hpp" using VmaAllocator = struct VmaAllocator_T*; @@ -16,17 +11,17 @@ class window; class vkdevice { struct queue { - VkQueue vk_queue; - uint32_t index; + VkQueue vk_queue = VK_NULL_HANDLE; + uint32_t index = UINT32_MAX; VkQueueFlags usages; - VkCommandPool command_pool; + VkCommandPool command_pool = VK_NULL_HANDLE; }; public: void init(); void deinit(); - static inline vkdevice& get_render_device() { + static inline vkdevice& get() { return render_device; } @@ -89,7 +84,11 @@ class vkdevice { return bindless; } - inline VkDevice get_device() { + const freelist<device_texture>& get_textures() const { + return textures; + } + + inline VkDevice get_device() const { return device; } @@ -97,6 +96,10 @@ class vkdevice { return gpu_allocator; } + inline const VkPhysicalDeviceLimits& get_device_limits() const { + return physical_device_props.properties.limits; + } + // uint64_t submit(std::span<command_buffer> buffers, handle<device_semaphore> wait_handle, handle<device_semaphore> signal_handle, handle<device_semaphore> fence_handle); uint32_t acquire_image_index(handle<device_surface> surface_handle); uint64_t submit_before_present(handle<device_surface> surface_handle, command_buffer* buffers, uint32_t count); @@ -112,8 +115,6 @@ class vkdevice { void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type, const char* name); - VkShaderModule create_shader_module(const std::span<uint8_t>& shader_code); - void create_swapchain(const surface_desc& desc, device_surface& surface); // TODO: Wrap in a struct called adapter ? @@ -127,7 +128,7 @@ class vkdevice { void pick_physical_device(); - static bool device_support_features(VkPhysicalDevice physical_dev); + bool device_support_features(VkPhysicalDevice physical_dev); void create_debug_layer_callback(); @@ -135,6 +136,7 @@ class vkdevice { VkInstance instance; VkPhysicalDevice physical_device; + VkPhysicalDeviceProperties2 physical_device_props; VkDevice device; VmaAllocator gpu_allocator; diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp deleted file mode 100644 index 1317912..0000000 --- a/include/vk-renderer.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef __VK_RENDERER_HPP_ -#define __VK_RENDERER_HPP_ - -#include <cstdint> -#include <format> -#include <vector> - -#include "vk-context.hpp" -#include "vk-api.hpp" - - -class Renderpass; -class ComputeRenderpass; -class PrimitiveRenderpass; -class Primitive; -class window; - -class Texture; -class Sampler; -class RingBuffer; - - -class Buffer { - public: - - Buffer(size_t size, VkBufferUsageFlagBits usage); - ~Buffer(); - - void write(void* data, off_t alloc_offset, size_t data_size) const; - - void resize(size_t new_size); - - handle device_buffer; - - size_t buffer_size; - - VkBufferUsageFlagBits usage; -}; - - -class vkrenderer { - public: - vkrenderer(window& wnd); - - ~vkrenderer(); - - void recreate_swapchain(); - - - void update_images(); - - void begin_frame(); - - void finish_frame(); - - static void queue_image_update(Texture* texture); - - static Buffer* create_buffer(size_t size); - - static Buffer* create_index_buffer(size_t size); - - static Buffer* create_staging_buffer(size_t size); - - static Sampler* create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - - - ComputeRenderpass* create_compute_renderpass(); - - PrimitiveRenderpass* create_primitive_renderpass(); - - Primitive* create_primitive(PrimitiveRenderpass& primitive_render_pass); - - void render(); - - [[nodiscard]]uint32_t frame_index() const { return this->virtual_frame_index; } - - [[nodiscard]]Texture* back_buffer() const { return swapchain_textures[swapchain_image_index]; } - - [[nodiscard]]VkFormat back_buffer_format() const { return swapchain.surface_format.format; } - - static constexpr uint32_t virtual_frames_count = 2; - - static vkcontext context; - - static vkapi api; - - private: - - - void handle_swapchain_result(VkResult function_result); - - std::vector<Renderpass*> renderpasses; - - uint32_t virtual_frame_index = 0; - uint32_t swapchain_image_index = 0; - - VkCommandBuffer graphics_command_buffers[virtual_frames_count]; - VkCommandBuffer copy_command_buffers[virtual_frames_count]; - - RingBuffer* staging_buffers[virtual_frames_count]; - - - pipeline tonemapping_pipeline; - - VkFence submission_fences[virtual_frames_count]; - VkSemaphore execution_semaphores[virtual_frames_count]; - VkSemaphore acquire_semaphores[virtual_frames_count]; - - VkCommandPool graphics_command_pool; - VkCommandPool copy_command_pools[virtual_frames_count]; - - VkSurfaceKHR platform_surface; - swapchain swapchain; - std::vector<Texture*> swapchain_textures; - std::vector<VkCommandBuffer> recorded_command_buffers; - - const uint32_t min_swapchain_image_count = 3; - - static std::vector<Texture*> upload_queue; -}; - -class RingBuffer { - public: - - static const size_t invalid_alloc = -1; - - RingBuffer(size_t size); - - [[nodiscard]]size_t alloc(size_t alloc_size) { - assert(alloc_size > 0 && alloc_size <= buffer_size); - - auto alloc_offset = ptr; - - if (alloc_offset <= buffer_size - alloc_size) { - ptr += alloc_size; - return alloc_offset; - } - - return invalid_alloc; - } - - void write(void* data, size_t alloc_offset, size_t data_size) const { - auto api_buffer = vkrenderer::api.get_buffer(device_buffer); - - std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size); - } - - void reset() { - ptr = 0; - } - - handle device_buffer; - - size_t buffer_size; - size_t ptr = 0; -}; - -class Sampler { - public: - - handle device_sampler; -}; - -#endif // !__VK_RENDERER_HPP_ diff --git a/include/api-test/vk-utils.hpp b/include/vk-utils.hpp index 205e103..f26d2a3 100644 --- a/include/api-test/vk-utils.hpp +++ b/include/vk-utils.hpp @@ -1,13 +1,9 @@ #pragma once -#include <cassert> - -#include <vulkan/vulkan_core.h> - #ifdef _DEBUG #define VKCHECK(result) assert((result) == VK_SUCCESS) #else -#define VKCHECK(result) result +#define VKCHECK(result) (void)result #endif VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, diff --git a/src/compute-renderpass.cpp b/src/compute-renderpass.cpp deleted file mode 100644 index d5dbaa0..0000000 --- a/src/compute-renderpass.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "compute-renderpass.hpp" - -#include "vk-renderer.hpp" - -ComputeRenderpass::ComputeRenderpass(vkapi& api) - : Renderpass(api) -{} - -ComputeRenderpass::~ComputeRenderpass() { - api.destroy_pipeline(pipeline); -} - -void ComputeRenderpass::set_pipeline(const char* shader_name) { - if (this->pipeline.handle != VK_NULL_HANDLE) - api.destroy_pipeline(this->pipeline); - this->pipeline = api.create_compute_pipeline(shader_name); -} - -void ComputeRenderpass::set_ouput_texture(Texture* out_texture) { - this->output_texture = out_texture; - - const auto& image = api.get_image(output_texture->device_image); - - // TODO: Remove hardcoded offset - memcpy(constants + 56, &image.bindless_storage_index, sizeof(bindless_index)); -} - -void ComputeRenderpass::set_dispatch_size(size_t count_x, size_t count_y, size_t count_z) { - group_count_x = count_x; - group_count_y = count_y; - group_count_z = count_z; -} - -void ComputeRenderpass::set_constant(off_t offset, uint64_t* constant) { - memcpy(constants + offset, constant, sizeof(uint64_t)); -} - -void ComputeRenderpass::set_constant(off_t offset, Texture* texture) { - const auto& image = api.get_image(texture->device_image); - - memcpy(constants + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index)); - - input_textures.push_back(texture); -} - -void ComputeRenderpass::set_constant(off_t offset, Buffer* buffer) { - auto device_buffer = api.get_buffer(buffer->device_buffer); - memcpy(constants + offset, (void*)&device_buffer.device_address, sizeof(VkDeviceAddress)); -} - -void ComputeRenderpass::execute(vkrenderer&, VkCommandBuffer command_buffer) { - api.update_constants(command_buffer, VK_SHADER_STAGE_COMPUTE_BIT, 0, 64, (void*)&constants); - - for (auto& texture: input_textures) { - api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT, texture->device_image); - } - - api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT, output_texture->device_image); - - api.run_compute_pipeline(command_buffer, pipeline, group_count_x, group_count_y, group_count_z); - - input_textures.clear(); -} diff --git a/api-test/dx12-command-buffer.cpp b/src/dx12-command-buffer.cpp index 0310dfd..0310dfd 100644 --- a/api-test/dx12-command-buffer.cpp +++ b/src/dx12-command-buffer.cpp diff --git a/api-test/dx12-device.cpp b/src/dx12-device.cpp index ac328ed..ac328ed 100644 --- a/api-test/dx12-device.cpp +++ b/src/dx12-device.cpp diff --git a/src/main.cpp b/src/main.cpp index 1acf2fb..4d56a3c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,437 +1,840 @@ -#include <chrono> -#include <filesystem> +// =============== +// windows.h stuff +// =============== +#if defined(_WIN32) + #if defined(_M_AMD64) + #define _AMD64_ + #endif + #include <basetsd.h> + #include <windef.h> + #include <winnt.h> + #include <winbase.h> + #include <winuser.h> + #include <winnls.h> + #include <fileapi.h> + #include <shlwapi.h> + #include <handleapi.h> + #include <errhandlingapi.h> +#endif // _WIN32 -#include "imgui.h" -#ifdef ENABLE_RENDERDOC -#include <renderdoc.h> -#endif -#include "compute-renderpass.hpp" -#include "primitive-renderpass.hpp" -#include "scene.hpp" -#include "vk-renderer.hpp" -#include "window.hpp" -#include "utils.hpp" +// ------------------- +// thirdparties +// ------------------- +#define IMGUI_DISABLE_WIN32_FUNCTIONS +#include "imgui.cpp" +#include "imgui_draw.cpp" +#include "imgui_tables.cpp" +#include "imgui_widgets.cpp" + +#define STB_IMAGE_IMPLEMENTATION +#include <stb_image.h> + +#include <simdjson.h> +#include "simdjson.cpp" + +#define ENABLE_RENDERDOC 1 +#if ENABLE_RENDERDOC +#include <renderdoc_app.h> -#if defined(LINUX) -#include <dlfcn.h> -#include <unistd.h> -#elif defined(WINDOWS) -#include <Windows.h> + + +#define RD_START_CAPTURE if(rdoc_api != nullptr) rdoc_api->StartFrameCapture(nullptr, nullptr) +#define RD_END_CAPTURE if(rdoc_api != nullptr) rdoc_api->EndFrameCapture(nullptr, nullptr) +#else +#define RD_START_CAPTURE +#define RD_END_CAPTURE +#endif // ENABLE_RENDERDOC + +#define VK 1 +#define DX12 0 +#if DX12 +#include "dx12-device.hpp" +#include "dx12-command-buffer.hpp" +#else +#include "vulkan-loader.cpp" +#include "vk-utils.cpp" +#include "vk-device.cpp" +#include "vk-bindless.cpp" +#include "vk-command-buffer.cpp" #endif -struct VkVertex { - float x, y; - float u, v; - uint32_t color; - uint32_t padding[3]; -}; +#include "vec3.cpp" +#include "utils.cpp" +#include "window.cpp" +#include "camera.cpp" +#include "mesh.cpp" +#include "gltf.cpp" +#include "bvh.cpp" +#include "scene.cpp" + + + +// ------------------- +// GLOBALS +// ------------------- +LARGE_INTEGER freq; +std::vector<handle<device_texture>> debug_texture_list; + +#if ENABLE_RENDERDOC +RENDERDOC_API_1_6_0 *rdoc_api = nullptr; +#endif // ENABLE_RENDERDOC + +void watch_func() { + printf("change"); +} + +void ui(scene* scene, float frame_time) { + static float max_fps = 0.f; + static float max_frame_time = 0.f; + float fps = 1000U / (frame_time > 0.001f ? frame_time : 0.001f); + if (fps > max_fps) { + max_fps = fps; + } + if (frame_time > max_frame_time) { + max_frame_time = frame_time; + } -void update_ui(scene& main_scene, float delta_time) { ImGui::NewFrame(); + const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ImGuiWindowFlags wnd_flags = ImGuiWindowFlags_NoMove; + ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkSize.x - 250, main_viewport->WorkPos.y), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(250, 720), ImGuiCond_FirstUseEver); - ImGui::SetNextWindowPos({0.f, 0.f}); - ImGui::SetNextWindowSize({0.f, 0.f}); - ImGui::Begin("Debug", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); + ImGui::Begin("Debug", nullptr, wnd_flags); + if (ImGui::CollapsingHeader("Perfs")) { + ImGui::SeparatorText("Metrics"); + ImGui::Text("FPS : %f\n", fps); + ImGui::Text("Max FPS : %f\n", max_fps); + ImGui::Text("frame_time : %f ms\n", frame_time); + ImGui::Text("max frame_time : %f ms\n", max_frame_time); - ImGui::Text("frame per second %u\n", static_cast<uint32_t>(1000.f / delta_time)); - ImGui::Text("frame time %f ms\n", delta_time); - ImGui::Text("frame count %u\n", main_scene.meta.sample_index); + ImGui::SeparatorText("Markers"); + for (uint32_t index = 0U; index < marker_count; index++ ) { + uint64_t diff = marker_counter_end[index] - marker_counter_start[index]; + uint64_t time = (diff * 1000000ULL) / freq.QuadPart; - if (ImGui::Checkbox("depth of field", (bool*)&main_scene.meta.enable_dof)) { - main_scene.meta.sample_index = 1; + ImGui::Text("%s time : %f ms\n", marker_names[index], static_cast<float>(time) / 1000U); + } } - ImGui::SliderInt("max bounces", (int32_t *)&main_scene.meta.max_bounce, 1, 250); - ImGui::SliderInt("min bounces", (int32_t *)&main_scene.meta.min_bounce, 1, main_scene.meta.max_bounce); - if (ImGui::SliderInt("downscale factor", (int32_t *)&main_scene.meta.downscale_factor, 1, 32)) { - main_scene.meta.sample_index = 1; + if (ImGui::CollapsingHeader("Images")) { + for (const handle<device_texture>& handle : debug_texture_list) { + const device_texture& tex = vkdevice::get().get_texture(handle); + const char* name = tex.name; + ImGui::Text(name ? name : DUMMY_NAME); + ImGui::Image(tex.get_sampled_index(), ImVec2(128, 128)); + } } - if (ImGui::Checkbox("debug bvh", (bool *)&main_scene.meta.debug_bvh)) { - main_scene.meta.sample_index = 1; + if (ImGui::CollapsingHeader("Scene")) { + ImGui::SliderInt("Max bounce", reinterpret_cast<int*>(&scene->meta.max_bounce), 5, 100); + ImGui::SliderInt("Min bounce", reinterpret_cast<int*>(&scene->meta.min_bounce), 1, 5); + + ImGui::Checkbox("DOF", reinterpret_cast<bool*>(&scene->meta.enable_dof)); + ImGui::Checkbox("Debug BVH", reinterpret_cast<bool*>(&scene->meta.debug_bvh)); + if (ImGui::SliderInt("Scale facotr", reinterpret_cast<int*>(&scene->meta.downscale_factor), 1, 20)) { + scene->meta.sample_index = 1U; + } } ImGui::End(); - bool open = true; - ImGui::ShowDemoWindow(&open); - ImGui::EndFrame(); - ImGui::Render(); } -void render(scene& main_scene, vkrenderer& renderer) { - // To start a frame capture, call StartFrameCapture. - // You can specify NULL, NULL for the device to capture on if you have only - // one device and either no windows at all or only one window, and it will - // capture from that device. See the documentation below for a longer - // explanation if(rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL); +int main() { + // From Microsoft doc + // https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency + // The frequency of the performance counter is fixed at system boot and is + // consistent across all processors so you only need to query the frequency + // from QueryPerformanceFrequency as the application initializes, + // and then cache the result. + QueryPerformanceFrequency(&freq); - main_scene.scene_buffer->write(&main_scene.meta, renderer.frame_index() * sizeof(main_scene.meta), sizeof(main_scene.meta)); + BEGIN_MARKER(STARTUP); +#if ENABLE_RENDERDOC + { + HMODULE mod = GetModuleHandleA("renderdoc.dll"); + if (!mod) { + // https://github.com/baldurk/renderdoc/issues/1556 + // If you load one copy of the dll yourself but a different copy of the dll is registered as a vulkan layer then both copies will be loaded because they're loaded from different paths. + // They'll be mutually incompatible (you can't use the API fetched from one to capture from another), and other things may break or cause crashes + mod = LoadLibraryA("C:/Program Files/RenderDoc/renderdoc.dll"); - // ImDrawData* draw_data = ImGui::GetDrawData(); + } - // ui_pass->set_viewport(0.f, 0.f, (float)draw_data->DisplaySize.x, (float)draw_data->DisplaySize.y); + if (mod) { + pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); + int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, (void **)&rdoc_api); + assert(ret == 1); + (void)ret; - // auto previous_size = ui_primitives.size(); - // auto commands_count = 0U; + rdoc_api->MaskOverlayBits(eRENDERDOC_Overlay_All, eRENDERDOC_Overlay_All); - // for (int32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) { - // commands_count += draw_data->CmdLists[draw_list_index]->CmdBuffer.size(); - // } + RENDERDOC_InputButton key = RENDERDOC_InputButton::eRENDERDOC_Key_F10; + rdoc_api->SetCaptureKeys(&key, 1U); + } + } +#endif - // if (ui_primitives.size() < commands_count) { - // ui_primitives.resize(commands_count); + constexpr size_t window_width = 1280U; + constexpr size_t window_height = 720U; + window wnd { window_width, window_height }; - // for (size_t index = previous_size; index < ui_primitives.size(); index++) { - // ui_primitives[index] = renderer.create_primitive(*ui_pass); - // ui_primitives[index]->set_pipeline(ui_shader_name); - // ui_primitives[index]->set_constant_offset(64); - // ui_primitives[index]->set_constant(32, ui_texture); - // ui_primitives[index]->set_constant(36, ui_texture_sampler); - // } - // } + ImGui::CreateContext(); + ImGuiIO &io = ImGui::GetIO(); + io.DisplaySize.x = window_width; + io.DisplaySize.y = window_height; - // float scale[] { - // 2.f / draw_data->DisplaySize.x, - // 2.f / draw_data->DisplaySize.y, - // }; - // float translate[] { - // -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x), - // -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y), - // }; + const float aspect_ratio = 16.f / 9.f; - // if (!ui_vertex_buffer || ui_vertex_buffer->size < draw_data->TotalVtxCount * sizeof(VkVertex)) { - // ui_vertex_buffer = renderer.create_buffer(draw_data->TotalVtxCount * sizeof(VkVertex), false); + point3 position { 13.f, 2.f, -3.f }; + point3 target {}; + const float v_fov = 90.f; + const float aperture = 0.1f; + const float focus_distance = 10.f; - // for (auto& primitive : ui_primitives) { - // primitive->set_constant(0, ui_vertex_buffer); - // } - // } +#if VK + auto& device = vkdevice::get(); +#else + auto& device = dx12::device::get(); +#endif + device.init(); - // if (!ui_index_buffer || ui_index_buffer->size < draw_data->TotalIdxCount * sizeof(ImDrawIdx)) { - // ui_index_buffer = renderer.create_index_buffer(draw_data->TotalIdxCount * sizeof(ImDrawIdx), false); + scene main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), window_width, window_height); - // for (auto& primitive : ui_primitives) { - // primitive->set_index_buffer(ui_index_buffer); - // } - // } + handle<device_surface> surface_handle = device.create_surface({ + .window_handle = wnd.handle, +#if VK + .surface_format = { + .format = VK_FORMAT_B8G8R8A8_UNORM, + .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 | VK_IMAGE_USAGE_STORAGE_BIT, +#else + .surface_format = DXGI_FORMAT_R16G16B16A16_FLOAT, + .present_mode = DXGI_SWAP_EFFECT_FLIP_DISCARD, + .usages = DXGI_USAGE_RENDER_TARGET_OUTPUT, +#endif + .image_count = 2U, + }); + const device_surface& surface = device.get_surface(surface_handle); - // off_t vertex_buffer_offset = 0; - // off_t index_buffer_offset = 0; - // std::vector<VkVertex> vertices; - // uint32_t draw_call_index = 0; - // for (int32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) { - // auto& vertex_buffer = draw_data->CmdLists[draw_list_index]->VtxBuffer; - // auto& index_buffer = draw_data->CmdLists[draw_list_index]->IdxBuffer; - // vertices.resize(vertex_buffer.size()); - // for (int32_t vert_index = 0; vert_index < vertex_buffer.Size; vert_index++) { - // vertices[vert_index] = *((VkVertex*)&vertex_buffer[vert_index]); - // } + // ============== + // create buffers + // ============== + const handle<device_buffer> staging_buffer_handle = device.create_buffer({ + .size = 128 * MB, +#if VK + .usages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, +#else + .map = true, + .states = D3D12_RESOURCE_STATE_COPY_SOURCE, + .usages = D3D12_RESOURCE_FLAG_NONE, + .heap_type = D3D12_HEAP_TYPE_UPLOAD, +#endif + }); + const device_buffer& staging_buffer = device.get_buffer(staging_buffer_handle); - // renderer.update_buffer(ui_vertex_buffer, vertices.data(), vertex_buffer_offset * sizeof(VkVertex), vertices.size() * sizeof(VkVertex)); - // renderer.update_buffer(ui_index_buffer, index_buffer.Data, index_buffer_offset * sizeof(ImDrawIdx), index_buffer.size() * sizeof(ImDrawIdx)); + const handle<device_buffer> vertex_buffer_handle = device.create_buffer({ + .size = MB * sizeof(uint32_t), +#if VK + .usages = VK_BUFFER_USAGE_STORAGE_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, +#else + #endif + }); - // ImDrawList* draw_list = draw_data->CmdLists[draw_list_index]; - // for (auto& draw_cmd: draw_list->CmdBuffer) { - // auto& current_primitive = ui_primitives[draw_call_index]; - // current_primitive->set_constant(8, (uint64_t*)&scale); - // current_primitive->set_constant(16, (uint64_t*)&translate); + const handle<device_buffer> index_buffer_handle = device.create_buffer({ + .size = MB * sizeof(uint32_t), +#if VK + .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, +#else +#endif + }); - // ImVec2 pos = draw_data->DisplayPos; - // current_primitive->set_scissor( - // (int32_t)draw_cmd.ClipRect.x - pos.x, - // (int32_t)draw_cmd.ClipRect.y - pos.y, - // (uint32_t)draw_cmd.ClipRect.z - pos.x, - // (uint32_t)draw_cmd.ClipRect.w - pos.y - // ); + device_buffer vertex_buffer = device.get_buffer(vertex_buffer_handle); + device_buffer index_buffer = device.get_buffer(index_buffer_handle); - // current_primitive->set_draw_info( - // draw_cmd.ElemCount, - // index_buffer_offset + draw_cmd.IdxOffset, - // vertex_buffer_offset + draw_cmd.VtxOffset - // ); - // ui_pass->add_primitive(current_primitive); - // draw_call_index++; - // } + // ================ + // create pipelines + // ================ +#if VK + size_t code_size = 0U; + uint8_t* code = read_file("shaders/test.comp.spv", &code_size); + handle<device_pipeline> compute = device.create_compute_pipeline({ + .cs_code = code, + .cs_code_size = code_size, + }); - // vertex_buffer_offset += vertex_buffer.Size; - // index_buffer_offset += index_buffer.Size; - // } + size_t rt_code_size = 0U; + uint8_t* rt_code = read_file("shaders/compute.comp.spv", &rt_code_size); + handle<device_pipeline> raytracing = device.create_compute_pipeline({ + .cs_code = rt_code, + .cs_code_size = rt_code_size, + }); + size_t tonemapping_code_size = 0U; + uint8_t* tonemapping_code = read_file("shaders/tonemapping.comp.spv", &tonemapping_code_size); + handle<device_pipeline> tonemapping = device.create_compute_pipeline({ + .cs_code = tonemapping_code, + .cs_code_size = tonemapping_code_size, + }); - // ui_pass->set_color_attachment(0, renderer.back_buffer()); + std::array<VkFormat, 1U> formats { surface.surface_format.format }; + size_t vertex_code_size = 0U; + uint8_t* vertex_code = read_file("shaders/api-test-ui.vert.spv", &vertex_code_size); + size_t fragment_code_size = 0U; + uint8_t* fragment_code = read_file("shaders/api-test-ui.frag.spv", &fragment_code_size); + handle<device_pipeline> graphics = device.create_graphics_pipeline({ + .vs_code = vertex_code, + .vs_code_size = vertex_code_size, + .fs_code = fragment_code, + .fs_code_size = fragment_code_size, + .color_attachments_format = formats + }); - renderer.render(); + size_t transmittance_lut_code_size = 0U; + u8* transmittance_lut_code = read_file("shaders/transmittance_lut.comp.spv", &transmittance_lut_code_size); + handle<device_pipeline> transmittance_lut_compute = device.create_compute_pipeline({ + .cs_code = transmittance_lut_code, + .cs_code_size = transmittance_lut_code_size, + .name = "transmittance_lut_comp", + }); +#endif - main_scene.meta.sample_index++; -} + // ============== + // Image loading + // ============== + int image_width; + int image_height; + int channels; + uint8_t* data = stbi_load("../models/sponza/466164707995436622.jpg", &image_width, &image_height, &channels, 4); + size_t size = static_cast<size_t>(image_width) * image_height * 4U; + memcpy(staging_buffer.mapped_ptr, data, size); + off_t buffer_offset = image_width * image_height * 4; + data = stbi_load("../models/sponza/715093869573992647.jpg", &image_width, &image_height, &channels, 4); + size = static_cast<size_t>(image_width) * image_height * 4U; + auto* addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + buffer_offset); + memcpy(addr, data, size); -#if defined(ENABLE_RENDERDOC) -RENDERDOC_API_1_1_2 enable_renderdoc() { - RENDERDOC_API_1_1_2 *rdoc_api = nullptr; + u8 *pixels = nullptr; + int atlas_width; + int atlas_height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); -#ifdef WINDOWS - // At init, on windows - if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) { - auto RENDERDOC_GetAPI = - (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - int ret = - RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); - assert(ret == 1); - } -#elif defined(LINUX) - // At init, on linux/android. - // For android replace librenderdoc.so with libVkLayer_GLES_RenderDoc.so - if (void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD)) { - pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI"); - int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); - assert(ret == 1); - } + off_t ui_offset = 2L * buffer_offset; + size = static_cast<size_t>(atlas_width) * atlas_height * 4U; + addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + ui_offset); + memcpy(addr, pixels, size); + + + // ============== + // create texures + // ============== + const handle<device_texture> gpu_texture_handle = device.create_texture({ + .width = static_cast<uint32_t>(image_width), + .height = static_cast<uint32_t>(image_height), +#if VK + .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .format = VK_FORMAT_R8G8B8A8_UNORM, + .type = VK_IMAGE_TYPE_2D, +#else + .states = D3D12_RESOURCE_STATE_COPY_DEST, + .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + .format = DXGI_FORMAT_R8G8B8A8_UNORM, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, #endif + }); - return rdoc_api; -} + const handle<device_texture> second_texture = device.create_texture({ + .width = static_cast<uint32_t>(image_width), + .height = static_cast<uint32_t>(image_height), +#if VK + .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R8G8B8A8_UNORM, + .type = VK_IMAGE_TYPE_2D, +#else + .states = D3D12_RESOURCE_STATE_COPY_DEST, + .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + .format = DXGI_FORMAT_R8G8B8A8_UNORM, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, #endif + }); -int main() { + const handle<device_texture> output_texture_handle = device.create_texture({ + .width = static_cast<uint32_t>(image_width), + .height = static_cast<uint32_t>(image_height), +#if VK + .usages = VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R8G8B8A8_UNORM, + .type = VK_IMAGE_TYPE_2D, +#else + .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + .format = DXGI_FORMAT_R8G8B8A8_UNORM, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, +#endif + }); + + const handle<device_texture> ui_texture_handle = device.create_texture({ + .width = static_cast<uint32_t>(atlas_width), + .height = static_cast<uint32_t>(atlas_height), +#if VK + .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .format = VK_FORMAT_R8G8B8A8_UNORM, + .type = VK_IMAGE_TYPE_2D, +#else + .states = D3D12_RESOURCE_STATE_COPY_DEST, + .usages = D3D12_RESOURCE_FLAG_NONE, + .format = DXGI_FORMAT_R8G8B8A8_UNORM, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, +#endif + .name = "glyph atlas" + }); -#if defined(ENABLE_RENDERDOC) - auto* rdoc_api = enable_renderdoc(); + const handle<device_texture> acc_handle = device.create_texture({ + .width = static_cast<uint32_t>(window_width), + .height = static_cast<uint32_t>(window_height), +#if VK + .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .type = VK_IMAGE_TYPE_2D, +#else + .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + .format = DXGI_FORMAT_R32G32B32A32_FLOAT, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, #endif + .name = "accumulation texture" + }); - const float aspect_ratio = 16.0 / 9.0; - const auto width = 400; - auto height = (uint32_t)(width / aspect_ratio); + const handle<device_texture> result_handle = device.create_texture({ + .width = static_cast<uint32_t>(window_width), + .height = static_cast<uint32_t>(window_height), +#if VK + .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .type = VK_IMAGE_TYPE_2D, +#else + .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + .format = DXGI_FORMAT_R32G32B32A32_FLOAT, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, +#endif + .name = "output texture" + }); - window wnd { width, height }; + const handle<device_texture> transmittance_lut_handle = device.create_texture({ + .width = static_cast<uint32_t>(1024), + .height = static_cast<uint32_t>(1024), +#if VK + .usages = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .format = VK_FORMAT_R16G16B16A16_SFLOAT, + .type = VK_IMAGE_TYPE_2D, +#else + .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, + .format = DXGI_FORMAT_R8G8B8A8_UNORM, + .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, +#endif + .name = "transmittance_lut", + }); - float delta_time = 0.f; - uint64_t frame_count = 0; - auto start = std::chrono::high_resolution_clock::now(); - auto end = std::chrono::high_resolution_clock::now(); +#if VK + u32 acc_storage_index = device.get_texture(acc_handle).get_storage_index(); + u32 result_storage_index = device.get_texture(result_handle).get_storage_index(); +#endif - 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; + const device_texture& ui_texture = device.get_texture(ui_texture_handle); + const device_texture& transmittance_lut = device.get_texture(transmittance_lut_handle); + debug_texture_list.push_back(transmittance_lut_handle); - vkrenderer renderer { wnd }; + io.Fonts->SetTexID(reinterpret_cast<void*>(static_cast<uintptr_t>(ui_texture.get_sampled_index()))); - ImGui::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); - io.DisplaySize.x = (float)width; - io.DisplaySize.y = (float)height; - auto main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), width, height); +#if VK + std::array<graphics_command_buffer, 4U> graphics_command_buffers; + device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), QueueType::GRAPHICS, "graphics_cmd_buf"); +#else + std::array<dx12::graphics_command_buffer, 4U> graphics_command_buffers; + device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), dx12::QueueType::GRAPHICS); +#endif - auto *raytracing_pass = renderer.create_compute_renderpass(); - raytracing_pass->set_pipeline("compute"); - watcher::watch_file(std::filesystem::path("../shaders/compute.comp"), [&]() { - LPCSTR app_name = "glslc.exe --target-env=vulkan1.2 -std=460 ../shaders/compute.comp -o shaders/compute.comp.spv -I \"../shaders/include\"\0"; - STARTUPINFO start_info {}; - PROCESS_INFORMATION proc_info {}; - if (FAILED(CreateProcessA( - app_name, - nullptr, - nullptr, - nullptr, - FALSE, - 0, - nullptr, - nullptr, - &start_info, - &proc_info - ))) - log_last_error(); - WaitForSingleObject(proc_info.hProcess, INFINITE); - CloseHandle(proc_info.hProcess); - CloseHandle(proc_info.hThread); + // ============= + // API test code + // ============= + RD_START_CAPTURE; + graphics_command_buffers[0].start(); + +#if VK + graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + graphics_command_buffers[0].barrier(ui_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); +#endif + + graphics_command_buffers[0].copy(staging_buffer_handle, gpu_texture_handle); + graphics_command_buffers[0].copy(staging_buffer_handle, second_texture, buffer_offset); + graphics_command_buffers[0].copy(staging_buffer_handle, ui_texture_handle, ui_offset); +#if VK + 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); - raytracing_pass->set_pipeline("compute"); - }); - auto *accumulation_texture = vkrenderer::create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); - auto *output_texture = vkrenderer::create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); - raytracing_pass->set_constant(0, main_scene.scene_buffer); - raytracing_pass->set_constant(8, main_scene.bvh_buffer); - raytracing_pass->set_constant(16, main_scene.indices_buffer); - raytracing_pass->set_constant(24, main_scene.positions_buffer); - raytracing_pass->set_constant(32, main_scene.normals_buffer); - raytracing_pass->set_constant(40, main_scene.uvs_buffer); - raytracing_pass->set_constant(48, main_scene.materials_buffer); - raytracing_pass->set_dispatch_size(width / 8 + 1, height / 8 + 1, 1); + { + device_buffer& draws_uniform_buffer = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW); + { + struct params { + u32 input1; + u32 input2; + u32 output; + u32 pad; + } *params = draws_uniform_buffer.allocate<struct params>(); + params->input1 = device.get_texture(second_texture).get_storage_index(); + params->input2 = device.get_texture(gpu_texture_handle).get_storage_index(); + params->output = device.get_texture(output_texture_handle).get_storage_index(); - // uint8_t *pixels = nullptr; - // int atlas_width, atlas_height; - // io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); - // auto *ui_texture = renderer.create_2d_texture(atlas_width, atlas_height, VK_FORMAT_R8G8B8A8_UNORM); - // io.Fonts->SetTexID((void *)&ui_texture); + graphics_command_buffers[0].dispatch({ + .pipeline = compute, + .group_size = { .vec = { static_cast<u32>(image_width), static_cast<u32>(image_height), 1U }}, + .local_group_size = { .vec = { 8U, 8U, 1U }}, + }); + } - // renderer.update_image(ui_texture, pixels); - // auto ui_texture_sampler = renderer.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + { + struct params { + u32 lut_id; + u32 width; + u32 height; + u32 pad; + } *params = draws_uniform_buffer.allocate<struct params>(); + params->lut_id = transmittance_lut.get_storage_index(); + params->width = transmittance_lut.width; + params->height = transmittance_lut.height; - // Buffer* ui_vertex_buffer = nullptr; - // Buffer* ui_index_buffer = nullptr; + graphics_command_buffers[0].dispatch({ + .pipeline = transmittance_lut_compute, + .group_size = { .vec = { 1024U, 1024U, 1U }}, + .local_group_size = { .vec { 8U, 8U, 1U }}, + }); + } + } - // const char* ui_shader_name = "ui"; - // std::vector<Primitive*> ui_primitives; - // auto ui_pass = renderer.create_primitive_renderpass(); - // ui_pass->set_viewport(0.f, 0.f, (float)width, (float)height); - // ui_pass->add_color_attachment(renderer.back_buffer_format()); - // ui_pass->finalize_render_pass(); + 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); +#endif - auto can_render = true; + graphics_command_buffers[0].stop(); - while (wnd.isOpen) { - end = std::chrono::high_resolution_clock::now(); + device.submit(graphics_command_buffers.data(), 1); + device.wait(); - delta_time = std::chrono::duration<float, std::milli>(end - start).count(); + RD_END_CAPTURE; - start = std::chrono::high_resolution_clock::now(); + END_MARKER(STARTUP); - io.DeltaTime = delta_time; + watch_file("../shaders/compute.comp", watch_func); - watcher::pull_changes(); +#if VK + std::array<handle<device_texture>, 1U> color_attachment {}; + constexpr uint32_t virtual_frames_count = 2U; + float delta = 0.f; // milliseconds + u32 speed = 1U; + uint32_t frame_count = 0U; + while(wnd.isOpen) { + vec3 dir = { 0.f, 0.f, 0.f }; + float rot = 0.f; + LARGE_INTEGER start_qpc; + QueryPerformanceCounter(&start_qpc); wnd.poll_events(); - for (auto &event : wnd.events) { - switch (event.type) { - case EVENT_TYPES::RESIZE: { - main_scene.meta.width = event.width; - main_scene.meta.height = event.height; + pull_changes(); - io.DisplaySize.x = (float)event.width; - io.DisplaySize.y = (float)event.height; + uint32_t virtual_frame_index = frame_count % virtual_frames_count; + auto command_buffer = graphics_command_buffers[2U + virtual_frame_index]; - if (event.width == 0 && event.height == 0) { - can_render = false; - } else { - can_render = true; - renderer.recreate_swapchain(); - main_scene.meta.cam.set_aspect_ratio((float)event.width / (float)event.height); + main_scene.meta.sample_index++; - delete accumulation_texture; - delete output_texture); - accumulation_texture = vkrenderer::create_2d_texture(event.width, event.height, VK_FORMAT_R32G32B32A32_SFLOAT); - output_texture = vkrenderer::create_2d_texture(event.width, event.height, VK_FORMAT_R32G32B32A32_SFLOAT); - raytracing_pass->set_dispatch_size(event.width / 8 + 1, event.height / 8 + 1, 1); + // + // IOs + // + { + io.AddMouseButtonEvent(BUTTON::LEFT, wnd.mouse[BUTTON::LEFT]); + io.AddMouseButtonEvent(BUTTON::RIGHT, wnd.mouse[BUTTON::LEFT]); + io.AddMouseButtonEvent(BUTTON::MIDDLE, wnd.mouse[BUTTON::LEFT]); + for (event& event : wnd.events) { + if (event.type == EVENT_TYPE::MOUSE_MOVE) { + io.AddMousePosEvent(static_cast<float>(event.data.position.x), static_cast<float>(event.data.position.y)); + } else if (event.type == EVENT_TYPE::MOUSE_WHEEL) { + io.AddMouseWheelEvent(static_cast<float>(event.data.delta.x), static_cast<float>(event.data.delta.y)); } - main_scene.meta.sample_index = 1; + if (event.type == EVENT_TYPE::KEY_PRESS) { + if (event.data.key == KEY::F2) { +#if ENABLE_RENDERDOC + if (!rdoc_api->IsTargetControlConnected()) { + rdoc_api->LaunchReplayUI(true, nullptr); + } +#endif + } + } - break; + if (event.type == EVENT_TYPE::KEY_DOWN) { + if (event.data.key == KEY::W) { + dir += main_scene.meta.cam.forward; + } + if (event.data.key == KEY::A) { + dir += -main_scene.meta.cam.right; + } + if (event.data.key == KEY::S) { + dir += -main_scene.meta.cam.forward; + } + if (event.data.key == KEY::D) { + dir += main_scene.meta.cam.right; + } + if (event.data.key == KEY::SPACE) { + dir += vec3 { 0.f, 1.f, 0.f }; + } + if (event.data.key == KEY::LCTRL) { + dir += vec3 { 0.f, -1.f, 0.f }; + } + if (event.data.key == KEY::E) { + rot += 0.001f; + } + if (event.data.key == KEY::Q) { + rot += -0.001f; + } + if (event.data.key == KEY::PAGE_UP) { + speed++; + } + if (event.data.key == KEY::PAGE_DOWN) { + if (speed > 1U) { + speed--; + } + } + + } } - case EVENT_TYPES::KEY_PRESS: { - auto move_speed = 1.f * delta_time; - if (wnd.keyboard[KEYS::LSHIFT] || wnd.keyboard[KEYS::RSHIFT]) { move_speed *= 10.f; } + } - vec3 move_vec{}; + if (!dir.is_zero()) { + main_scene.meta.cam.move(dir.normalize() * delta * static_cast<float>(speed)); + main_scene.meta.sample_index = 1U; + } + if (rot != 0.f) { + main_scene.meta.cam.rotate_y(rot * delta * static_cast<float>(speed)); + main_scene.meta.sample_index = 1U; + } - switch (event.key) { - case KEYS::W: { - move_vec = main_scene.meta.cam.forward * move_speed; - break; - } + ui(&main_scene, delta); - case KEYS::S: { - move_vec = -main_scene.meta.cam.forward * move_speed; - break; - } - case KEYS::D: { - move_vec = main_scene.meta.cam.right * move_speed; - break; - } - case KEYS::A: { - move_vec = -main_scene.meta.cam.right * move_speed; - break; - } - case KEYS::E: { - main_scene.meta.cam.rotate_y(0.001f * delta_time); - main_scene.meta.sample_index = 1; - break; - } - case KEYS::Q: { - main_scene.meta.cam.rotate_y(-0.001f * delta_time); - main_scene.meta.sample_index = 1; - break; - } - case KEYS::SPACE: { - move_vec = main_scene.meta.cam.up * move_speed; - break; - } - case KEYS::LCTRL: { - move_vec = -main_scene.meta.cam.up * move_speed; - break; - } - default: - break; - } + ImGuiMouseCursor cursor_style = ImGui::GetMouseCursor(); + window::set_cursor(static_cast<CURSOR_TYPE>(cursor_style)); - main_scene.meta.cam.move(move_vec); + // ================== + // copy ImGui buffers + // ================== + const ImDrawData* draw_data = ImGui::GetDrawData(); + { + u32 vertex_offset = 0; + u32 index_offset = 0; + for (s32 index = 0U; index < draw_data->CmdListsCount; index++) { + ImDrawList* cmd_list = draw_data->CmdLists[index]; - if (!move_vec.near_zero()) { main_scene.meta.sample_index = 1; } + size_t vertex_bytes_size = sizeof(ImDrawVert) * cmd_list->VtxBuffer.size(); + u8* vtx_ptr = static_cast<uint8_t*>(vertex_buffer.mapped_ptr) + vertex_offset; + memcpy(vtx_ptr, cmd_list->VtxBuffer.Data, vertex_bytes_size); + vertex_offset += static_cast<off_t>(vertex_bytes_size); - break; - } - case EVENT_TYPES::BUTTON_PRESS: { - if (event.button == BUTTONS::LEFT) { io.MouseDown[0] = true; } - if (event.button == BUTTONS::RIGHT) { io.MouseDown[1] = true; } - break; + size_t index_bytes_size = sizeof(ImDrawIdx) * cmd_list->IdxBuffer.size(); + memcpy(static_cast<uint8_t*>(index_buffer.mapped_ptr) + index_offset, cmd_list->IdxBuffer.Data, index_bytes_size); + index_offset += static_cast<off_t>(index_bytes_size); } - case EVENT_TYPES::BUTTON_RELEASE: { - if (event.button == BUTTONS::LEFT) { io.MouseDown[0] = false; } - if (event.button == BUTTONS::RIGHT) { io.MouseDown[1] = false; } - break; + } + + // ====================== + // global uniforms update + // ====================== + { + metadata * const globals = vkdevice::get().get_bindingmodel().get_uniform_buffer(UniformTypes::GLOBAL).allocate<metadata>(); + memcpy(static_cast<void*>(globals), &main_scene.meta, sizeof(main_scene.meta)); + } + + // 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.barrier(backbuffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + { + 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); } - case EVENT_TYPES::MOUSE_MOVE: { - io.MousePos = ImVec2{(float)event.x, (float)event.y}; - break; + + { + struct params { + uintptr_t bvh_buffer; + uintptr_t indices_buffer; + uintptr_t positions_buffer; + uintptr_t normals_buffer; + uintptr_t uvs_buffer; + uintptr_t materials_buffer; + u32 output_id; + u32 accumulation_id; + }; + struct params* uniforms = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW).allocate<params>(); + uniforms->bvh_buffer = main_scene.bvh_buffer_address(); + uniforms->indices_buffer = main_scene.indices_buffer_address(); + uniforms->positions_buffer = main_scene.positions_buffer_address(); + uniforms->normals_buffer = main_scene.normals_buffer_address(); + uniforms->uvs_buffer = main_scene.uvs_buffer_address(); + uniforms->materials_buffer = main_scene.materials_buffer_address(); + uniforms->output_id = (virtual_frame_index == 0U) ? result_storage_index : acc_storage_index; + uniforms->accumulation_id = (virtual_frame_index == 0U) ? acc_storage_index : result_storage_index; + + command_buffer.dispatch({ + .pipeline = raytracing, + .group_size = { .vec { window_width / main_scene.meta.downscale_factor, window_height / main_scene.meta.downscale_factor, 1U, } }, + .local_group_size = { .vec { 8U, 8U, 1U, } }, + }); } - default: - break; + + { + struct params { + u32 output_id; + u32 accumulation_id; + } *uniforms = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW).allocate<params>(); + // TODO: Refactor backbuffer acquisition + uniforms->output_id = device.get_texture(backbuffer).get_storage_index(); + uniforms->accumulation_id = (virtual_frame_index == 0U) ? result_storage_index : acc_storage_index; + + command_buffer.dispatch({ + .pipeline = tonemapping, + .group_size = { .vec { window_width / main_scene.meta.downscale_factor, window_height / main_scene.meta.downscale_factor, 1U, } }, + .local_group_size = { .vec { 8U, 8U, 1U, } }, + }); } } - wnd.events.clear(); + command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - raytracing_pass->set_ouput_texture(output_texture); - raytracing_pass->set_constant(60, accumulation_texture); + command_buffer.begin_renderpass({ + .render_area = { + .x = static_cast<int32_t>(draw_data->DisplayPos.x), + .y = static_cast<int32_t>(draw_data->DisplayPos.y), + .width = static_cast<uint32_t>(draw_data->DisplaySize.x), + .height = static_cast<uint32_t>(draw_data->DisplaySize.y), + }, + .color_attachments = color_attachment, + }); - renderer.begin_frame(); + auto& draws_uniform_buffer = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW); + uint32_t vertex_offset = 0; + uint32_t index_offset = 0; + for (s32 index = 0U ; index < draw_data->CmdListsCount; index++) { + auto* cmd_list = draw_data->CmdLists[index]; - // update_ui(main_scene, delta_time); - - if (can_render) { - render(main_scene, renderer); + for (auto& draw_command : cmd_list->CmdBuffer) { + ImTextureID texture_id = draw_command.TexRef.GetTexID(); + { + struct ui_params { + u64 vertex_buffer; + float scale[2U]; + float translate[2U]; + uint32_t texture_index; + u32 padding; + }; + struct ui_params* ui_param = draws_uniform_buffer.allocate<ui_params>(); + *ui_param = ui_params{ + .vertex_buffer = vertex_buffer.device_address, + .scale { + 2.f / draw_data->DisplaySize.x, + 2.f / draw_data->DisplaySize.y, + }, + .translate { + -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x), + -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y), + }, + .texture_index = *reinterpret_cast<uint32_t*>(&texture_id), + }; + } - std::swap(output_texture, accumulation_texture); + command_buffer.draw_indexed({ + .pipeline = graphics, + .index_buffer = index_buffer_handle, + .vertex_count = draw_command.ElemCount, + .vertex_offset = draw_command.VtxOffset + vertex_offset, + .index_offset = draw_command.IdxOffset + index_offset, + .instance_count = 1U, + }); + } + vertex_offset += cmd_list->VtxBuffer.size(); + index_offset += cmd_list->IdxBuffer.size(); } - renderer.finish_frame(); + command_buffer.end_renderpass(); + 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_before_present(surface_handle, &command_buffer, 1U); + device.present(surface_handle); + // device.wait(); + LARGE_INTEGER end_qpc; + QueryPerformanceCounter(&end_qpc); + LONGLONG diff_qpc = end_qpc.QuadPart - start_qpc.QuadPart; + delta = static_cast<float>(diff_qpc * 1000LL) / freq.QuadPart; frame_count++; + + // RD_END_CAPTURE; } - //------------------------- - // Image exporter - //------------------------- - // PPM format header - // std::cout << "P3\n" << width << '\n' << height << "\n255" << std::endl; - // auto output_image = renderer.output_image(); - // for (size_t index = 0; index < height * width; index++) { - // write_color(std::cout, output_image[index]); - // } + device.wait(); + + main_scene.deinit(); + + device.destroy_surface(surface_handle); + + device.destroy_pipeline(compute); + device.destroy_pipeline(graphics); + device.destroy_pipeline(raytracing); + device.destroy_pipeline(tonemapping); + + device.destroy_pipeline(transmittance_lut_compute); + device.destroy_texture(transmittance_lut_handle); + + 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); + device.destroy_buffer(index_buffer_handle); + device.deinit(); - // std::cerr << "Done !" << std::endl; + ImGui::DestroyContext(); +#endif // VK return 0; } diff --git a/src/primitive-renderpass.cpp b/src/primitive-renderpass.cpp deleted file mode 100644 index 45d48e8..0000000 --- a/src/primitive-renderpass.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "primitive-renderpass.hpp" - -#include "vulkan-loader.hpp" - - -Primitive::Primitive(PrimitiveRenderpass& render_pass) - : api(vkrenderer::api), primitive_render_pass(render_pass) - {}; - -void Primitive::set_pipeline(const char* shader_name) { - std::vector<VkDynamicState> dynamic_states { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - - pipeline = api.create_graphics_pipeline(shader_name, (VkShaderStageFlagBits)(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT), primitive_render_pass.render_pass, dynamic_states); -} - -void Primitive::set_constant_offset(off_t offset) { - constant_offset = offset; -} - -void Primitive::set_constant(off_t offset, uint64_t* constant) { - memcpy(constants + offset, constant, sizeof(uint64_t)); -} - -void Primitive::set_constant(off_t offset, Texture* texture) { - const auto& image = api.get_image(texture->device_image); - - memcpy(constants + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index)); -} - -void Primitive::set_constant(off_t offset, Buffer* buffer) { - const auto& device_buffer = api.get_buffer(buffer->device_buffer); - memcpy(constants + offset, (void*)&device_buffer.device_address, sizeof(VkDeviceAddress)); -} - -void Primitive::set_constant(off_t offset, Sampler* sampler) { - const auto& device_sampler = api.get_sampler(sampler->device_sampler); - memcpy(constants + offset, (void*)&device_sampler.bindless_index, sizeof(bindless_index)); -} - -void Primitive::set_index_buffer(Buffer* buffer) { - this->index_buffer = buffer; -} - -void Primitive::set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height) { - scissor.offset.x = x; - scissor.offset.y = y; - scissor.extent.width = width; - scissor.extent.height = height; -} - -void Primitive::set_draw_info(size_t vertex_count, off_t indices_off, off_t vertex_off) { - this->element_count = vertex_count; - this->indices_offset = indices_off; - this->vertex_offset = vertex_off; -} - -void Primitive::render(VkCommandBuffer command_buffer) { - vkCmdSetScissor(command_buffer, 0, 1, &scissor); - - api.update_constants(command_buffer, VK_SHADER_STAGE_ALL_GRAPHICS, constant_offset, 64, (void*)&constants); - - api.draw( - command_buffer, - pipeline, - index_buffer->device_buffer, - element_count, - indices_offset, - vertex_offset - ); -}; - - -PrimitiveRenderpass::PrimitiveRenderpass(vkapi& api) - : Renderpass(api) { - }; - -void PrimitiveRenderpass::add_primitive(Primitive* new_primitive) { - primitives.push_back(new_primitive); -} - -void PrimitiveRenderpass::add_color_attachment(VkFormat format) { - color_attachments_format.push_back(format); -} - -void PrimitiveRenderpass::set_viewport(float x, float y, float width, float height) { - viewport.x = x; - viewport.y = y; - viewport.width = width; - viewport.height = height; -} - -void PrimitiveRenderpass::set_color_attachment(uint32_t index, Texture* attachment) { - const auto& device_image = api.get_image(attachment->device_image); - - if (device_image.size.width != framebuffers[0].size.width || - device_image.size.height != framebuffers[0].size.height) { - recreate_framebuffers(); - } - - - color_attachments[index] = attachment; - color_attachments_view[index] = device_image.view; -} - -void PrimitiveRenderpass::finalize_render_pass() { - render_pass = api.create_render_pass(color_attachments_format, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - create_framebuffers(); - - color_attachments.resize(color_attachments_format.size()); - color_attachments_view.resize(color_attachments_format.size()); -} - -void PrimitiveRenderpass::execute(vkrenderer& renderer, VkCommandBuffer command_buffer) { - VkExtent2D extent = { .width = (uint32_t)viewport.width, .height = (uint32_t)viewport.height }; - - for (auto& attachment : color_attachments) { - api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, attachment->device_image); - } - - - api.begin_render_pass(command_buffer, render_pass, color_attachments_view, framebuffers[renderer.frame_index()], extent); - - vkCmdSetViewport(command_buffer, 0, 1, &viewport); - - for (auto* primitive : primitives) { - primitive->render(command_buffer); - } - - api.end_render_pass(command_buffer); - - primitives.clear(); -} - -void PrimitiveRenderpass::create_framebuffers() { - VkExtent2D size { .width = (uint32_t) viewport.width, .height = (uint32_t) viewport.height }; - - for(auto& framebuffer : framebuffers) { - framebuffer = api.create_framebuffer(render_pass, color_attachments_format, size); - } -} - -void PrimitiveRenderpass::recreate_framebuffers() { - for (auto& framebuffer: framebuffers) { - api.destroy_framebuffer(framebuffer); - } - - create_framebuffers(); -} diff --git a/src/vk-api.cpp b/src/vk-api.cpp deleted file mode 100644 index 2040b44..0000000 --- a/src/vk-api.cpp +++ /dev/null @@ -1,1257 +0,0 @@ -#include "vk-api.hpp" - -#include <cassert> -#include <filesystem> - -#include <vk_mem_alloc.h> - -#include "utils.hpp" -#include "vk-context.hpp" -#include "window.hpp" - -#include "vulkan-loader.hpp" - -#ifdef _DEBUG -#define VKRESULT(result) assert(result == VK_SUCCESS); -#else -#define VKRESULT(result) result; -#endif - - -vkapi::vkapi(vkcontext& context) - : context(context) { - VkDescriptorPoolSize descriptor_pools_sizes[] = { - { - .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = (uint32_t)global_descriptor::pool_size, - }, - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = (uint32_t)global_descriptor::pool_size, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = (uint32_t)global_descriptor::pool_size, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = (uint32_t)global_descriptor::pool_size, - } - }; - - VkDescriptorPoolCreateInfo descriptor_pool_create_info = {}; - descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptor_pool_create_info.pNext = nullptr; - descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - descriptor_pool_create_info.maxSets = 0xff; - descriptor_pool_create_info.poolSizeCount = sizeof(descriptor_pools_sizes) / sizeof(descriptor_pools_sizes[0]); - descriptor_pool_create_info.pPoolSizes = descriptor_pools_sizes; - - VKRESULT(vkCreateDescriptorPool(context.device, &descriptor_pool_create_info, nullptr, &descriptor_pool)) - - // Global descriptor - VkDescriptorSetLayoutBinding bindless_layout_bindings[] = { - { - .binding = 0, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = global_descriptor::pool_size, - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - }, - { - .binding = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = global_descriptor::pool_size, - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - }, - { - .binding = 2, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = global_descriptor::pool_size, - .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - }, - }; - - VkDescriptorBindingFlags flags[3] = { - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, - }; - - VkDescriptorSetLayoutBindingFlagsCreateInfo descriptor_set_layout_binding_flags = {}; - descriptor_set_layout_binding_flags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO; - descriptor_set_layout_binding_flags.pNext = VK_NULL_HANDLE; - descriptor_set_layout_binding_flags.bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags); - descriptor_set_layout_binding_flags.pBindingFlags = flags; - - VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info = {}; - descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptor_set_layout_create_info.pNext = &descriptor_set_layout_binding_flags; - descriptor_set_layout_create_info.flags = 0; - descriptor_set_layout_create_info.bindingCount = sizeof(bindless_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding); - descriptor_set_layout_create_info.pBindings = bindless_layout_bindings; - - VKRESULT(vkCreateDescriptorSetLayout(context.device, &descriptor_set_layout_create_info, nullptr, &bindless_descriptor.set_layout)) - - - VkPushConstantRange push_constants[] = { - { - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, - .offset = 0, - .size = 64, - }, - { - .stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS, - .offset = 64, - .size = 64, - }, - // { - // .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - // .offset = 64, - // .size = 32, - // }, - // { - // .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, - // .offset = 96, - // .size = 32, - // }, - }; - - VkPipelineLayoutCreateInfo layout_create_info = {}; - layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_create_info.pNext = nullptr; - layout_create_info.flags = 0; - layout_create_info.setLayoutCount = 1; - layout_create_info.pSetLayouts = &bindless_descriptor.set_layout; - layout_create_info.pushConstantRangeCount = sizeof(push_constants) / sizeof(VkPushConstantRange); - layout_create_info.pPushConstantRanges = push_constants; - - VKRESULT(vkCreatePipelineLayout(context.device, &layout_create_info, nullptr, &bindless_descriptor.pipeline_layout)) - - - VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {}; - descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptor_set_allocate_info.pNext = VK_NULL_HANDLE; - descriptor_set_allocate_info.descriptorPool = descriptor_pool; - descriptor_set_allocate_info.descriptorSetCount = 1; - descriptor_set_allocate_info.pSetLayouts = &bindless_descriptor.set_layout; - - vkAllocateDescriptorSets(context.device, &descriptor_set_allocate_info, &bindless_descriptor.set); -} - -vkapi::~vkapi() { - // Free resources - for (handle buffer_handle = 0; buffer_handle < buffers.size(); buffer_handle++) { - destroy_buffer(buffer_handle); - } - - for (handle image_handle = 0; image_handle < images.size(); image_handle++) { - destroy_image(image_handle); - } - - for (handle sampler_handle = 0; sampler_handle < samplers.size(); sampler_handle++) { - destroy_sampler(sampler_handle); - } - - // Free bindless descriptor stuff - vkDestroyDescriptorSetLayout(context.device, bindless_descriptor.set_layout, nullptr); - vkDestroyPipelineLayout(context.device, bindless_descriptor.pipeline_layout, nullptr); - vkFreeDescriptorSets(context.device, descriptor_pool, 1, &bindless_descriptor.set); - - vkDestroyDescriptorPool(context.device, descriptor_pool, nullptr); -} - -handle vkapi::create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, uint32_t mem_usage) { - auto* buffer = new struct buffer(); - - VkBufferCreateInfo buffer_info = {}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = data_size; - buffer_info.usage = buffer_usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; - - VmaAllocationCreateInfo alloc_create_info = {}; - alloc_create_info.usage = (VmaMemoryUsage)mem_usage; - alloc_create_info.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - - VmaAllocationInfo alloc_info{}; - - VKRESULT(vmaCreateBuffer(context.allocator, &buffer_info, &alloc_create_info, &buffer->handle, &buffer->alloc, &alloc_info)) - - VkBufferDeviceAddressInfo buffer_device_address_info = {}; - buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - buffer_device_address_info.pNext = VK_NULL_HANDLE; - buffer_device_address_info.buffer = buffer->handle; - - buffer->size = data_size; - - buffer->device_address = vkGetBufferDeviceAddress(context.device, &buffer_device_address_info); - buffer->device_ptr = alloc_info.pMappedData; - - buffers.push_back(buffer); - - return buffers.size() - 1; -} - -void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size) { - VkBufferCopy buffer_copy = {}; - buffer_copy.srcOffset = 0; - buffer_copy.dstOffset = 0; - buffer_copy.size = size; - - vkCmdCopyBuffer(cmd_buf, buffers[src]->handle, buffers[dst]->handle, 1, &buffer_copy); -} - -// TODO: Change handle type, here we don't know what type of ressources we are working with -void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size, size_t buffer_offset) { - auto& dst_image = images[dst]; - - VkImageSubresourceLayers image_subresource_layers = {}; - image_subresource_layers.aspectMask = dst_image->subresource_range.aspectMask; - image_subresource_layers.mipLevel = 0; - image_subresource_layers.baseArrayLayer = 0; - image_subresource_layers.layerCount = 1; - - VkBufferImageCopy buffer_to_image_copy = {}; - buffer_to_image_copy.bufferOffset = buffer_offset; - buffer_to_image_copy.bufferRowLength = 0; - buffer_to_image_copy.bufferImageHeight = 0; - buffer_to_image_copy.imageSubresource = image_subresource_layers; - buffer_to_image_copy.imageOffset = { 0, 0, 0 }; - buffer_to_image_copy.imageExtent = dst_image->size; - - vkCmdCopyBufferToImage(cmd_buf, buffers[src]->handle, dst_image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy); -} - -void vkapi::destroy_buffer(handle buffer) { - vmaDestroyBuffer(context.allocator, buffers[buffer]->handle, buffers[buffer]->alloc); - - // TODO: Free the element once using freelists - // buffers.erase(buffer.handle); -} - -handle vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages) { - auto* image = new struct image(); - - image->size = size; - - image->subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image->subresource_range.baseMipLevel = 0; - image->subresource_range.levelCount = 1; - image->subresource_range.baseArrayLayer = 0; - image->subresource_range.layerCount = 1; - - VkImageCreateInfo img_create_info = {}; - img_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - img_create_info.pNext = VK_NULL_HANDLE; - img_create_info.flags = 0; - img_create_info.imageType = VK_IMAGE_TYPE_2D; - img_create_info.format = format; - img_create_info.extent = size; - img_create_info.mipLevels = 1; - img_create_info.arrayLayers = 1; - img_create_info.samples = VK_SAMPLE_COUNT_1_BIT; - img_create_info.tiling = VK_IMAGE_TILING_OPTIMAL; - img_create_info.usage = usages; - img_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - img_create_info.queueFamilyIndexCount = 0; - img_create_info.pQueueFamilyIndices = nullptr; - img_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - VmaAllocationCreateInfo alloc_create_info = {}; - alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_ONLY; - - VmaAllocationInfo alloc_info{}; - - VKRESULT(vmaCreateImage(context.allocator, &img_create_info, &alloc_create_info, &image->handle, &image->alloc, &alloc_info)) - - VkImageViewCreateInfo image_view_create_info = {}; - image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - image_view_create_info.pNext = nullptr; - image_view_create_info.flags = 0; - image_view_create_info.image = image->handle; - image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - image_view_create_info.format = format; - image_view_create_info.components = { - VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY - }; - image_view_create_info.subresourceRange = image->subresource_range; - - VKRESULT(vkCreateImageView(context.device, &image_view_create_info, VK_NULL_HANDLE, &image->view)) - - image->format = format; - image->usages = usages; - - images.push_back(image); - - auto image_handle = images.size() - 1; - - if ((usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0U) { - image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - update_descriptor_image(image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - } - - if ((usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) { - image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - update_descriptor_image(image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - } - - return image_handle; -} - -void vkapi::destroy_image(handle image) { - auto* current_image = images[image]; - - if (current_image->bindless_storage_index != 0U) { - bindless_descriptor.free(current_image->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - } - - if (current_image->bindless_sampled_index != 0U) { - bindless_descriptor.free(current_image->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - } - - vmaDestroyImage(context.allocator, current_image->handle, current_image->alloc); - vkDestroyImageView(context.device, current_image->view, nullptr); - - // TODO: Free once using freelist - // images.erase(image.handle); -} - -std::vector<handle> vkapi::create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count) { - std::vector<handle> images_handles(image_count); - - for (size_t image_index = 0; image_index < image_count; image_index++) { - images_handles[image_index] = create_image(size, format, usages); - } - - return images_handles; -} - -void vkapi::destroy_images(std::vector<handle>& imgs) { - for (auto handle : imgs) { - destroy_image(handle); - } -} - -VkFence vkapi::create_fence() const { - VkFence fence; - VkFenceCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - create_info.pNext = nullptr; - create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - VKRESULT(vkCreateFence(context.device, &create_info, nullptr, &fence)) - - return fence; -} - -void vkapi::destroy_fence(VkFence fence) const { - vkDestroyFence(context.device, fence, nullptr); -} - -std::vector<VkFence> vkapi::create_fences(size_t fences_count) const { - std::vector<VkFence> fences{ fences_count }; - - for (size_t fence_index = 0; fence_index < fences_count; fence_index++) { - fences[fence_index] = create_fence(); - } - - return fences; -} - -void vkapi::destroy_fences(VkFence fences[], size_t fences_count) const { - for (size_t index{ 0 }; index < fences_count; index++) { - vkDestroyFence(context.device, fences[index], nullptr); - } -} - -VkSemaphore vkapi::create_semaphore() const { - VkSemaphore semaphore; - VkSemaphoreCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - create_info.pNext = nullptr; - create_info.flags = 0; - - VKRESULT(vkCreateSemaphore(context.device, &create_info, nullptr, &semaphore)) - - return semaphore; -} - -void vkapi::destroy_semaphore(VkSemaphore semaphore) const { - vkDestroySemaphore(context.device, semaphore, nullptr); -} - -std::vector<VkSemaphore> vkapi::create_semaphores(size_t semaphores_count) const { - std::vector<VkSemaphore> semaphores{ semaphores_count }; - - for (size_t semaphore_index{ 0 }; semaphore_index < semaphores_count; semaphore_index++) { - semaphores[semaphore_index] = create_semaphore(); - } - - return semaphores; -} - -void vkapi::destroy_semaphores(VkSemaphore semaphores[], size_t semaphores_count) const { - for (size_t index{ 0 }; index < semaphores_count; index++) { - vkDestroySemaphore(context.device, semaphores[index], nullptr); - } -} - -handle vkapi::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) { - VkSamplerCreateInfo sampler_create_info = {}; - sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - sampler_create_info.pNext = VK_NULL_HANDLE; - sampler_create_info.flags = 0; - sampler_create_info.magFilter = filter; - sampler_create_info.minFilter = filter; - sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - sampler_create_info.addressModeU = address_mode; - sampler_create_info.addressModeV = address_mode; - sampler_create_info.addressModeW = address_mode; - sampler_create_info.mipLodBias = 0.f; - sampler_create_info.anisotropyEnable = VK_FALSE; - sampler_create_info.compareEnable = VK_FALSE; - sampler_create_info.compareOp = VK_COMPARE_OP_ALWAYS; - sampler_create_info.minLod = 0.f; - sampler_create_info.maxLod = 0.f; - sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - sampler_create_info.unnormalizedCoordinates = VK_FALSE; - - struct sampler* sampler = new struct sampler(); - VKRESULT(vkCreateSampler(context.device, &sampler_create_info, VK_NULL_HANDLE, &sampler->handle)) - - sampler->bindless_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLER); - - - samplers.push_back(sampler); - - update_descriptor_sampler(samplers.size() - 1); - - return samplers.size() - 1; -} - -void vkapi::destroy_sampler(handle sampler) { - auto* current_sampler = samplers[sampler]; - bindless_descriptor.free(current_sampler->bindless_index, VK_DESCRIPTOR_TYPE_SAMPLER); - - vkDestroySampler(context.device, current_sampler->handle, VK_NULL_HANDLE); - - // samplers.erase(sampler.handle); -} - -VkCommandPool vkapi::create_command_pool() const { - VkCommandPoolCreateInfo cmd_pool_create_info = {}; - cmd_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmd_pool_create_info.pNext = nullptr; - cmd_pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - cmd_pool_create_info.queueFamilyIndex = context.graphics_queue.index; - - VkCommandPool command_pool; - VKRESULT(vkCreateCommandPool(context.device, &cmd_pool_create_info, nullptr, &command_pool)) - - return command_pool; -} - -void vkapi::allocate_command_buffers(VkCommandPool command_pool, VkCommandBuffer* command_buffers, size_t count) const { - VkCommandBufferAllocateInfo cmd_buf_allocate_info = {}; - cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmd_buf_allocate_info.pNext = VK_NULL_HANDLE; - cmd_buf_allocate_info.commandPool = command_pool; - cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmd_buf_allocate_info.commandBufferCount = count; - - vkAllocateCommandBuffers(context.device, &cmd_buf_allocate_info, command_buffers); -} - -// TODO: attachment structure -VkRenderPass vkapi::create_render_pass(std::vector<VkFormat>& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout) { - std::vector<VkAttachmentDescription> attachments_description = {}; - std::vector<VkAttachmentReference> attachments_reference = {}; - - for (size_t attachment_index = 0; attachment_index < color_attachments_format.size(); attachment_index++) { - auto format = color_attachments_format[attachment_index]; - VkAttachmentDescription attachment_description = {}; - attachment_description.flags = 0; - attachment_description.format = format; - attachment_description.samples = VK_SAMPLE_COUNT_1_BIT; - attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // TODO: Set based on render pass usage - attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // TODO: Set based on render pass usage - - attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment_description.initialLayout = initial_layout; - attachment_description.finalLayout = final_layout; - - attachments_description.push_back(attachment_description); - - VkAttachmentReference attachment_reference = {}; - attachment_reference.attachment = attachment_index; - attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - attachments_reference.push_back(attachment_reference); - } - - VkSubpassDescription subpass_description = {}; - subpass_description.flags = 0; - subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass_description.colorAttachmentCount = attachments_reference.size(); - subpass_description.pColorAttachments = attachments_reference.data(); - subpass_description.pDepthStencilAttachment = VK_NULL_HANDLE; - subpass_description.pResolveAttachments = VK_NULL_HANDLE; - subpass_description.preserveAttachmentCount = 0; - subpass_description.pPreserveAttachments = VK_NULL_HANDLE; - - - VkSubpassDependency subpass_dependency[2] = {}; - subpass_dependency[0].srcSubpass = VK_SUBPASS_EXTERNAL; - subpass_dependency[0].dstSubpass = 1; // First subpass attachment is used in - subpass_dependency[0].srcStageMask = VK_PIPELINE_STAGE_NONE_KHR; - subpass_dependency[0].dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - subpass_dependency[0].srcAccessMask = 0; - subpass_dependency[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - subpass_dependency[0].dependencyFlags = 0; - - - subpass_dependency[1].srcSubpass = 1; // Last subpass attachment is used in - subpass_dependency[1].dstSubpass = VK_SUBPASS_EXTERNAL; - subpass_dependency[1].srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - subpass_dependency[1].dstStageMask = VK_PIPELINE_STAGE_NONE_KHR; - subpass_dependency[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - subpass_dependency[1].dstAccessMask = 0; - subpass_dependency[1].dependencyFlags = 0; - - - VkRenderPass render_pass; - VkRenderPassCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - create_info.pNext = VK_NULL_HANDLE; - create_info.flags = 0; - create_info.attachmentCount = attachments_description.size(); - create_info.pAttachments = attachments_description.data(); - create_info.subpassCount = 1; - create_info.pSubpasses = &subpass_description; - // create_info.dependencyCount = sizeof(subpass_dependency) / sizeof(VkSubpassDependency); - // create_info.pDependencies = subpass_dependency; - - VKRESULT(vkCreateRenderPass(context.device, &create_info, VK_NULL_HANDLE, &render_pass)) - - return render_pass; -} - -void vkapi::destroy_render_pass(VkRenderPass render_pass) { - vkDestroyRenderPass(context.device, render_pass, VK_NULL_HANDLE); -} - -framebuffer vkapi::create_framebuffer(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size) { - VkFramebuffer framebuffer_handle; - - std::vector<VkFramebufferAttachmentImageInfo> attachments_image_infos(formats.size()); - for (size_t index = 0; index < formats.size(); index++) { - VkFramebufferAttachmentImageInfo attachments_image_info = {}; - attachments_image_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO; - attachments_image_info.pNext = VK_NULL_HANDLE; - attachments_image_info.flags = 0; - attachments_image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - attachments_image_info.width = size.width; - attachments_image_info.height = size.height; - attachments_image_info.layerCount = 1; - attachments_image_info.viewFormatCount = 1; - attachments_image_info.pViewFormats = &formats[index]; - - attachments_image_infos[index] = attachments_image_info; - } - - VkFramebufferAttachmentsCreateInfo attachments_create_info = {}; - attachments_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO; - attachments_create_info.pNext = VK_NULL_HANDLE; - attachments_create_info.attachmentImageInfoCount = attachments_image_infos.size(); - attachments_create_info.pAttachmentImageInfos = attachments_image_infos.data(); - - VkFramebufferCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - create_info.pNext = &attachments_create_info; - create_info.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT; - create_info.renderPass = render_pass; - create_info.attachmentCount = formats.size(); - create_info.pAttachments = VK_NULL_HANDLE; - create_info.width = size.width; - create_info.height = size.height; - create_info.layers = 1; - - VKRESULT(vkCreateFramebuffer(context.device, &create_info, VK_NULL_HANDLE, &framebuffer_handle)) - - return { .handle = framebuffer_handle, .size = size }; -} - -std::vector<framebuffer> vkapi::create_framebuffers(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size, uint32_t framebuffer_count) { - std::vector<framebuffer> framebuffers{ framebuffer_count }; - - for (auto& framebuffer : framebuffers) { - framebuffer = create_framebuffer(render_pass, formats, size); - } - - return framebuffers; -} - -void vkapi::destroy_framebuffer(framebuffer framebuffer) const { - VKRESULT(vkDeviceWaitIdle(context.device)) - - vkDestroyFramebuffer(context.device, framebuffer.handle, VK_NULL_HANDLE); -} - -void vkapi::destroy_framebuffers(std::vector<framebuffer>& framebuffers) const { - VKRESULT(vkDeviceWaitIdle(context.device)) - - for (auto& framebuffer : framebuffers) { - vkDestroyFramebuffer(context.device, framebuffer.handle, VK_NULL_HANDLE); - } -} - -pipeline vkapi::create_compute_pipeline(const char* shader_name) const { - pipeline pipeline{ - .bind_point = VK_PIPELINE_BIND_POINT_COMPUTE - }; - - auto shader_filename = std::string(shader_name) + ".comp.spv"; - auto shader_path = std::filesystem::path{ "./shaders" } / shader_filename; - auto shader_code = read_file(shader_path.string().c_str()); - assert(!shader_code.empty()); - - pipeline.shader_modules.resize(1); - - VkShaderModuleCreateInfo shader_create_info = {}; - shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - shader_create_info.pNext = VK_NULL_HANDLE; - shader_create_info.flags = 0; - shader_create_info.codeSize = shader_code.size(); - shader_create_info.pCode = reinterpret_cast<uint32_t*>(shader_code.data()); - - VKRESULT(vkCreateShaderModule(context.device, &shader_create_info, VK_NULL_HANDLE, (pipeline.shader_modules).data())) - - VkPipelineShaderStageCreateInfo stage_create_info = {}; - stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stage_create_info.pNext = VK_NULL_HANDLE; - stage_create_info.flags = 0; - stage_create_info.stage = VK_SHADER_STAGE_COMPUTE_BIT; - stage_create_info.module = pipeline.shader_modules[0]; - stage_create_info.pName = "main"; - stage_create_info.pSpecializationInfo = VK_NULL_HANDLE; - - - VkComputePipelineCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - create_info.pNext = VK_NULL_HANDLE; - create_info.flags = 0; - create_info.stage = stage_create_info; - create_info.layout = bindless_descriptor.pipeline_layout; - - VKRESULT(vkCreateComputePipelines( - context.device, - VK_NULL_HANDLE, - 1, - &create_info, - nullptr, - &pipeline.handle)) - - return pipeline; -} - -pipeline vkapi::create_graphics_pipeline(const char* shader_name, VkShaderStageFlagBits shader_stages, VkRenderPass render_pass, std::vector<VkDynamicState>& dynamic_states) const { - pipeline pipeline{ - .bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS - }; - - std::vector<VkPipelineShaderStageCreateInfo> stages_create_info = {}; - - for (VkShaderStageFlags stage_flag = VK_SHADER_STAGE_VERTEX_BIT; stage_flag <= VK_SHADER_STAGE_ALL_GRAPHICS; stage_flag <<= 2) { - if ((stage_flag & shader_stages) != 0U) { - VkShaderModule shader_module; - - auto shader_filename = std::string(shader_name) + shader_stage_extension(stage_flag) + ".spv"; - auto shader_path = std::filesystem::path{ "./shaders" } / shader_filename; - std::vector<uint8_t> shader_code = read_file(shader_path.string().c_str()); - assert(!shader_code.empty()); - - VkShaderModuleCreateInfo shader_create_info = {}; - shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - shader_create_info.pNext = nullptr; - shader_create_info.flags = 0; - shader_create_info.codeSize = shader_code.size(); - shader_create_info.pCode = reinterpret_cast<uint32_t*>(shader_code.data()); - - VKRESULT(vkCreateShaderModule(context.device, &shader_create_info, nullptr, &shader_module)) - - pipeline.shader_modules.push_back(shader_module); - - VkPipelineShaderStageCreateInfo stage_create_info = {}; - stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stage_create_info.pNext = nullptr; - stage_create_info.flags = 0; - stage_create_info.stage = (VkShaderStageFlagBits)stage_flag; - stage_create_info.module = shader_module; - stage_create_info.pName = "main"; - stage_create_info.pSpecializationInfo = nullptr; - - stages_create_info.push_back(stage_create_info); - } - } - - - VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = {}; - vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - - VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = {}; - input_assembly_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly_state_create_info.pNext = nullptr; - input_assembly_state_create_info.flags = 0; - input_assembly_state_create_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkPipelineViewportStateCreateInfo viewport_state_create_info = {}; - viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state_create_info.pNext = nullptr; - viewport_state_create_info.flags = 0; - viewport_state_create_info.viewportCount = 1; - viewport_state_create_info.pViewports = VK_NULL_HANDLE; - viewport_state_create_info.scissorCount = 1; - viewport_state_create_info.pScissors = VK_NULL_HANDLE; - - VkPipelineRasterizationStateCreateInfo rasterization_state_create_info = {}; - rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterization_state_create_info.pNext = nullptr; - rasterization_state_create_info.flags = 0; - rasterization_state_create_info.depthClampEnable = VK_FALSE; - rasterization_state_create_info.rasterizerDiscardEnable = VK_FALSE; - rasterization_state_create_info.polygonMode = VK_POLYGON_MODE_FILL; - rasterization_state_create_info.cullMode = VK_CULL_MODE_NONE; - rasterization_state_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rasterization_state_create_info.depthBiasEnable = VK_FALSE; - rasterization_state_create_info.lineWidth = 1.f; - - VkPipelineMultisampleStateCreateInfo multisample_state_create_info = {}; - multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisample_state_create_info.pNext = nullptr; - multisample_state_create_info.flags = 0; - multisample_state_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisample_state_create_info.sampleShadingEnable = VK_FALSE; - multisample_state_create_info.minSampleShading = 1.f; - - VkPipelineColorBlendAttachmentState color_attachment_state = {}; - color_attachment_state.blendEnable = VK_TRUE; - color_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; - color_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_attachment_state.colorBlendOp = VK_BLEND_OP_ADD; - color_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - color_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - color_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD; - color_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = {}; - color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blend_state_create_info.pNext = nullptr; - color_blend_state_create_info.flags = 0; - color_blend_state_create_info.logicOpEnable = VK_FALSE; - color_blend_state_create_info.attachmentCount = 1; - color_blend_state_create_info.pAttachments = &color_attachment_state; - - VkPipelineDynamicStateCreateInfo dynamic_state_create_info = {}; - dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_create_info.pNext = VK_NULL_HANDLE; - dynamic_state_create_info.flags = 0; - dynamic_state_create_info.dynamicStateCount = dynamic_states.size(); - dynamic_state_create_info.pDynamicStates = dynamic_states.data(); - - VkGraphicsPipelineCreateInfo pipeline_create_info = {}; - pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_create_info.pNext = nullptr; - pipeline_create_info.flags = 0; - pipeline_create_info.stageCount = stages_create_info.size(); - pipeline_create_info.pStages = stages_create_info.data(); - pipeline_create_info.pVertexInputState = &vertex_input_state_create_info; - pipeline_create_info.pInputAssemblyState = &input_assembly_state_create_info; - pipeline_create_info.pViewportState = &viewport_state_create_info; - pipeline_create_info.pRasterizationState = &rasterization_state_create_info; - pipeline_create_info.pMultisampleState = &multisample_state_create_info; - pipeline_create_info.pColorBlendState = &color_blend_state_create_info; - pipeline_create_info.pDynamicState = &dynamic_state_create_info; - pipeline_create_info.layout = bindless_descriptor.pipeline_layout; - pipeline_create_info.renderPass = render_pass; - pipeline_create_info.subpass = 0; - - VKRESULT(vkCreateGraphicsPipelines(context.device, VK_NULL_HANDLE, 1, &pipeline_create_info, VK_NULL_HANDLE, &pipeline.handle)) - - return pipeline; -} - -void vkapi::destroy_pipeline(pipeline& pipeline) const { - for (auto& shader_module : pipeline.shader_modules) { - vkDestroyShaderModule(context.device, shader_module, nullptr); - } - - vkDestroyPipeline(context.device, pipeline.handle, nullptr); -} - -VkSurfaceKHR vkapi::create_surface(window& wnd) const { - VkSurfaceKHR surface; - -#if defined(LINUX) - VkXcbSurfaceCreateInfoKHR create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.connection = wnd.connection; - create_info.window = wnd.win; - - VKRESULT(vkCreateXcbSurfaceKHR(context.instance, &create_info, nullptr, &surface)) -#elif defined(WINDOWS) - VkWin32SurfaceCreateInfoKHR create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.hinstance = GetModuleHandle(nullptr); - create_info.hwnd = wnd.handle; - - VKRESULT(vkCreateWin32SurfaceKHR(context.instance, &create_info, nullptr, &surface)) -#elif defined(MACOS) - VkMetalSurfaceCreateInfoEXT create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; - create_info.pNext = nullptr; - create_info.flags = 0; - // create_info.pLayer = GetModuleHandle(NULL); - - VKRESULT(vkCreateMetalSurfaceEXT(context.instance, &create_info, nullptr, &surface)) -#endif - - return surface; -} - -void vkapi::destroy_surface(VkSurfaceKHR surface) { - vkDestroySurfaceKHR(context.instance, surface, nullptr); -} - -swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain) { - swapchain swapchain; - - VkBool32 queue_support_presentation = VK_FALSE; - VKRESULT(vkGetPhysicalDeviceSurfaceSupportKHR(context.physical_device, context.graphics_queue.index, surface, &queue_support_presentation)) - - assert(queue_support_presentation == VK_TRUE); - - VkSurfaceCapabilitiesKHR caps; - VKRESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.physical_device, surface, &caps)) - - swapchain.extent = caps.currentExtent; - - if (swapchain.extent.width < caps.minImageExtent.width) { - swapchain.extent.width = caps.minImageExtent.width; - } else if (swapchain.extent.width > caps.maxImageExtent.width) { - swapchain.extent.width = caps.maxImageExtent.width; - } - - if (swapchain.extent.height < caps.minImageExtent.height) { - swapchain.extent.height = caps.minImageExtent.height; - } else if (swapchain.extent.height > caps.maxImageExtent.height) { - swapchain.extent.height = caps.maxImageExtent.height; - } - - - uint32_t supported_formats_count = 0; - VKRESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(context.physical_device, surface, &supported_formats_count, VK_NULL_HANDLE)) - - std::vector<VkSurfaceFormatKHR> supported_formats{ supported_formats_count }; - VKRESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(context.physical_device, surface, &supported_formats_count, supported_formats.data())) - - - uint32_t supported_present_modes_count = 0; - VKRESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(context.physical_device, surface, &supported_present_modes_count, VK_NULL_HANDLE)) - - std::vector<VkPresentModeKHR> supported_present_modes{ supported_present_modes_count }; - VKRESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(context.physical_device, surface, &supported_present_modes_count, supported_present_modes.data())) - - - swapchain.surface_format = supported_formats[0]; - - VkSwapchainCreateInfoKHR create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - create_info.pNext = nullptr; - create_info.flags = 0; - create_info.surface = surface; - create_info.minImageCount = min_image_count; - create_info.imageFormat = swapchain.surface_format.format; - create_info.imageColorSpace = swapchain.surface_format.colorSpace; - create_info.imageExtent = swapchain.extent; - create_info.imageArrayLayers = 1; - create_info.imageUsage = usages; - create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - create_info.preTransform = caps.currentTransform; - create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - create_info.presentMode = supported_present_modes[0]; - create_info.clipped = VK_TRUE; - create_info.oldSwapchain = old_swapchain; - - VKRESULT(vkCreateSwapchainKHR(context.device, &create_info, nullptr, &swapchain.handle)) - - - VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &swapchain.image_count, VK_NULL_HANDLE)) - - swapchain.images = std::vector<handle>(swapchain.image_count); - auto vk_images = std::vector<VkImage>(swapchain.image_count); - - VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &swapchain.image_count, vk_images.data())) - - - VkImageSubresourceRange image_subresource_range = {}; - image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - image_subresource_range.baseMipLevel = 0; - image_subresource_range.levelCount = 1; - image_subresource_range.baseArrayLayer = 0; - image_subresource_range.layerCount = 1; - - VkExtent3D image_size = { - .width = swapchain.extent.width, - .height = swapchain.extent.height, - .depth = 1, - }; - - for (size_t image_index = 0; image_index < swapchain.image_count; image_index++) { - auto* current_image = new struct image(); - - current_image->handle = vk_images[image_index]; - current_image->size = image_size; - current_image->subresource_range = image_subresource_range; - current_image->usages = usages; - - - VkImageViewCreateInfo image_view_create_info = {}; - image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - image_view_create_info.pNext = nullptr; - image_view_create_info.flags = 0; - image_view_create_info.image = current_image->handle; - image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - image_view_create_info.format = swapchain.surface_format.format; - image_view_create_info.components = { - VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY - }; - image_view_create_info.subresourceRange = image_subresource_range; - - VKRESULT(vkCreateImageView(context.device, &image_view_create_info, nullptr, ¤t_image->view)) - - images.push_back(current_image); - - auto current_image_handle = images.size() - 1; - - if ((usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0U) { - current_image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - } - - if ((usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) { - current_image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - } - - swapchain.images[image_index] = current_image_handle; - } - - return swapchain; -} - -void vkapi::destroy_swapchain(swapchain& swapchain) { - VKRESULT(vkDeviceWaitIdle(context.device)) - - for (auto& image : swapchain.images) { - // TODO: Change this - if (images[image]->bindless_storage_index != 0) - bindless_descriptor.free(images[image]->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE); - if (images[image]->bindless_sampled_index != 0) - bindless_descriptor.free(images[image]->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - - vkDestroyImageView(context.device, images[image]->view, nullptr); - } - vkDestroySwapchainKHR(context.device, swapchain.handle, nullptr); -} - -void vkapi::update_descriptor_image(handle img, VkDescriptorType type) { - VkDescriptorImageInfo descriptor_image_info; - VkWriteDescriptorSet write_descriptor; - - auto* current_image = images[img]; - - descriptor_image_info.sampler = VK_NULL_HANDLE; - descriptor_image_info.imageView = current_image->view; - descriptor_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptor.pNext = nullptr; - write_descriptor.dstSet = bindless_descriptor.set; - write_descriptor.dstBinding = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? 2 : 1; - write_descriptor.dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? current_image->bindless_storage_index : current_image->bindless_sampled_index; - write_descriptor.descriptorCount = 1; - write_descriptor.descriptorType = type; - write_descriptor.pImageInfo = &descriptor_image_info; - write_descriptor.pBufferInfo = VK_NULL_HANDLE; - write_descriptor.pTexelBufferView = VK_NULL_HANDLE; - - vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr); -} - -void vkapi::update_descriptor_images(std::vector<handle>& handles, VkDescriptorType type) { - std::vector<VkDescriptorImageInfo> descriptor_images_info{ images.size() }; - std::vector<VkWriteDescriptorSet> writes_descriptor{ images.size() }; - - for (size_t image_index = 0; image_index < images.size(); image_index++) { - auto image = images[handles[image_index]]; - descriptor_images_info[image_index].sampler = VK_NULL_HANDLE; - descriptor_images_info[image_index].imageView = image->view; - descriptor_images_info[image_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - writes_descriptor[image_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writes_descriptor[image_index].pNext = nullptr; - writes_descriptor[image_index].dstSet = bindless_descriptor.set; - writes_descriptor[image_index].dstBinding = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? 2 : 1; - writes_descriptor[image_index].dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? image->bindless_storage_index : image->bindless_sampled_index; - writes_descriptor[image_index].descriptorCount = 1; - writes_descriptor[image_index].descriptorType = type; - writes_descriptor[image_index].pImageInfo = &descriptor_images_info[image_index]; - writes_descriptor[image_index].pBufferInfo = VK_NULL_HANDLE; - writes_descriptor[image_index].pTexelBufferView = VK_NULL_HANDLE; - } - - vkUpdateDescriptorSets(context.device, writes_descriptor.size(), writes_descriptor.data(), 0, nullptr); -} - -void vkapi::update_descriptor_sampler(handle sampler) { - VkDescriptorImageInfo descriptor_image_info; - VkWriteDescriptorSet write_descriptor; - auto current_sampler = samplers[sampler]; - - descriptor_image_info.sampler = current_sampler->handle; - descriptor_image_info.imageView = VK_NULL_HANDLE; - descriptor_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write_descriptor.pNext = nullptr; - write_descriptor.dstSet = bindless_descriptor.set; - write_descriptor.dstBinding = 0; - write_descriptor.dstArrayElement = current_sampler->bindless_index; - write_descriptor.descriptorCount = 1; - write_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - write_descriptor.pImageInfo = &descriptor_image_info; - write_descriptor.pBufferInfo = VK_NULL_HANDLE; - write_descriptor.pTexelBufferView = VK_NULL_HANDLE; - - vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr); -} - -void vkapi::update_descriptor_samplers(std::vector<handle>& handles) { - std::vector<VkDescriptorImageInfo> descriptor_images_info{ samplers.size() }; - std::vector<VkWriteDescriptorSet> writes_descriptor{ samplers.size() }; - - for (size_t sampler_index = 0; sampler_index < samplers.size(); sampler_index++) { - auto sampler = samplers[handles[sampler_index]]; - descriptor_images_info[sampler_index].sampler = sampler->handle; - descriptor_images_info[sampler_index].imageView = VK_NULL_HANDLE; - descriptor_images_info[sampler_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - writes_descriptor[sampler_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writes_descriptor[sampler_index].pNext = nullptr; - writes_descriptor[sampler_index].dstSet = bindless_descriptor.set; - writes_descriptor[sampler_index].dstBinding = 0; - writes_descriptor[sampler_index].dstArrayElement = sampler->bindless_index; - writes_descriptor[sampler_index].descriptorCount = 1; - writes_descriptor[sampler_index].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; - writes_descriptor[sampler_index].pImageInfo = &descriptor_images_info[sampler_index]; - writes_descriptor[sampler_index].pBufferInfo = VK_NULL_HANDLE; - writes_descriptor[sampler_index].pTexelBufferView = VK_NULL_HANDLE; - } - - vkUpdateDescriptorSets(context.device, writes_descriptor.size(), writes_descriptor.data(), 0, nullptr); -} - -void vkapi::update_constants(VkCommandBuffer command_buffer, VkShaderStageFlagBits shader_stage, off_t offset, size_t size, void* data) { - vkCmdPushConstants(command_buffer, bindless_descriptor.pipeline_layout, shader_stage, offset, size, data); -} - -void vkapi::start_record(VkCommandBuffer command_buffer) { - VkCommandBufferBeginInfo cmd_buf_begin_info = {}; - cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_buf_begin_info.pNext = nullptr; - cmd_buf_begin_info.flags = 0; - cmd_buf_begin_info.pInheritanceInfo = nullptr; - - vkBeginCommandBuffer(command_buffer, &cmd_buf_begin_info); -} - -void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image) { - auto* current_image = images[image]; - - VkImageMemoryBarrier image_barrier = {}; - image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - image_barrier.pNext = nullptr; - image_barrier.srcAccessMask = current_image->previous_access; - image_barrier.dstAccessMask = dst_access; - image_barrier.oldLayout = current_image->previous_layout; - image_barrier.newLayout = dst_layout; - image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - image_barrier.image = current_image->handle; - image_barrier.subresourceRange = current_image->subresource_range; - - vkCmdPipelineBarrier( - command_buffer, - current_image->previous_stage, - dst_stage, - 0, - 0, - nullptr, - 0, - nullptr, - 1, - &image_barrier); - - current_image->previous_layout = dst_layout; - current_image->previous_access = dst_access; - current_image->previous_stage = dst_stage; -} - -void vkapi::begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector<VkImageView>& attachments, framebuffer framebuffer, VkExtent2D size) { - VkRect2D render_area = { - { - 0, - 0, - }, - size - }; - - VkRenderPassAttachmentBeginInfo attachment_begin_info = {}; - attachment_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO; - attachment_begin_info.pNext = VK_NULL_HANDLE; - attachment_begin_info.attachmentCount = attachments.size(); - attachment_begin_info.pAttachments = attachments.data(); - - VkClearValue clear_value{ .color{ .float32{ 0.f, 0.f, 0.f, 1.f } } }; - VkRenderPassBeginInfo render_pass_begin_info = {}; - render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - render_pass_begin_info.pNext = &attachment_begin_info; - render_pass_begin_info.renderPass = render_pass; - render_pass_begin_info.framebuffer = framebuffer.handle; - render_pass_begin_info.renderArea = render_area; - render_pass_begin_info.clearValueCount = 1; - render_pass_begin_info.pClearValues = &clear_value; - - vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); -} - -void vkapi::end_render_pass(VkCommandBuffer command_buffer) { - vkCmdEndRenderPass(command_buffer); -} - -void vkapi::run_compute_pipeline(VkCommandBuffer command_buffer, pipeline& pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z) { - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr); - - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.handle); - - vkCmdDispatch(command_buffer, group_count_x, group_count_y, group_count_z); -} - -void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t vertex_count, uint32_t vertex_offset) { - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle); - - vkCmdDraw(command_buffer, vertex_count, 1, vertex_offset, 0); -} - -void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t index_count, uint32_t index_offset, uint32_t vertex_offset) { - vkCmdBindIndexBuffer(command_buffer, buffers[index_buffer]->handle, 0, VK_INDEX_TYPE_UINT16); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr); - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle); - - vkCmdDrawIndexed(command_buffer, index_count, 1, index_offset, vertex_offset, 0); -} - -void vkapi::blit_full(VkCommandBuffer command_buffer, handle src, handle dst) { - auto* src_image = images[src]; - auto* dst_image = images[dst]; - - VkImageSubresourceLayers images_subres_layers{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - VkOffset3D start_offset{ - .x = 0, - .y = 0, - .z = 0, - }; - VkOffset3D end_offset{ - .x = (int32_t)dst_image->size.width, - .y = (int32_t)dst_image->size.height, - .z = (int32_t)dst_image->size.depth, - }; - - VkImageBlit blit_region{ - .srcSubresource = images_subres_layers, - .srcOffsets = { start_offset, end_offset }, - .dstSubresource = images_subres_layers, - .dstOffsets = { start_offset, end_offset }, - }; - - vkCmdBlitImage(command_buffer, src_image->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit_region, VK_FILTER_NEAREST); -} - -void vkapi::end_record(VkCommandBuffer command_buffer){ - VKRESULT(vkEndCommandBuffer(command_buffer)) -} - -VkResult vkapi::submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const { - VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - - VkSubmitInfo submit_info = {}; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = nullptr; - submit_info.waitSemaphoreCount = wait_semaphore != nullptr ? 1 : 0; - submit_info.pWaitSemaphores = &wait_semaphore; - submit_info.pWaitDstStageMask = wait_semaphore != nullptr ? &wait_stage : VK_NULL_HANDLE; - submit_info.signalSemaphoreCount = signal_semaphore != nullptr ? 1 : 0; - submit_info.pSignalSemaphores = &signal_semaphore; - submit_info.commandBufferCount = command_buffers_count; - submit_info.pCommandBuffers = command_buffers; - - return vkQueueSubmit(context.graphics_queue.handle, 1, &submit_info, submission_fence); -} - -VkResult vkapi::present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const { - VkPresentInfoKHR present_info = {}; - present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - present_info.pNext = nullptr; - present_info.waitSemaphoreCount = 1; - present_info.pWaitSemaphores = &wait_semaphore; - present_info.swapchainCount = 1; - present_info.pSwapchains = &swapchain.handle; - present_info.pImageIndices = &image_index; - present_info.pResults = nullptr; - - return vkQueuePresentKHR(context.graphics_queue.handle, &present_info); -} - -const char* vkapi::shader_stage_extension(VkShaderStageFlags shader_stage) { - switch (shader_stage) { - case VK_SHADER_STAGE_VERTEX_BIT: { - return ".vert"; - } - case VK_SHADER_STAGE_FRAGMENT_BIT: { - return ".frag"; - } - case VK_SHADER_STAGE_COMPUTE_BIT: { - return ".comp"; - } - default: - assert(true && "Stage not supported"); - return ""; - } -} diff --git a/src/vk-bindless.cpp b/src/vk-bindless.cpp new file mode 100644 index 0000000..9e517df --- /dev/null +++ b/src/vk-bindless.cpp @@ -0,0 +1,238 @@ +#include "vk-bindless.hpp" + +#include "vk-device.hpp" +#include "vk-utils.hpp" + +device_buffer& bindless_model::get_uniform_buffer(enum UniformTypes type) const { + return vkdevice::get().get_buffer(uniform_buffers[type]); +} + +void bindless_model::init() { + vkdevice& render_device = vkdevice::get(); + VkDevice device = render_device.get_device(); + + // ------------------------- + // create immutable samplers + // ------------------------- + { + VkSamplerCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = VK_NULL_HANDLE, + .flags = 0, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .mipLodBias = 0.f, + .anisotropyEnable = VK_FALSE, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_NEVER, + .minLod = 0.f, + .maxLod = 0.f, + .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + .unnormalizedCoordinates = VK_FALSE, + }; + + // Nearest sampler + { + VkFilter filter = VK_FILTER_NEAREST; + VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + create_info.magFilter = filter, + create_info.minFilter = filter, + create_info.addressModeU = address_mode, + create_info.addressModeV = address_mode, + create_info.addressModeW = address_mode, + + VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::NEAREST])); + } + + // Linear sampler + { + VkFilter filter = VK_FILTER_LINEAR; + VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + create_info.magFilter = filter, + create_info.minFilter = filter, + create_info.addressModeU = address_mode, + create_info.addressModeV = address_mode, + create_info.addressModeW = address_mode, + + VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::LINEAR])); + } + } + + // Set 0 global resources + // Binding 0 Storage images + // Binding 1 Sampled images + // Binding 2 Samplers + { + VkDescriptorSetLayoutBinding set_layout_bindings[]{ + { + .binding = 0U, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = SamplerType::MAX_SAMPLER, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = samplers, + }, + { + .binding = 1U, + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = set_descriptors_count, + .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = 2U, + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = set_descriptors_count, + .stageFlags = VK_SHADER_STAGE_COMPUTE_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, + }; + + VkDescriptorSetLayoutBindingFlagsCreateInfo layout_binding_flags{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + .pNext = VK_NULL_HANDLE, + .bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags), + .pBindingFlags = flags, + }; + + VkDescriptorSetLayoutCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = &layout_binding_flags, + .flags = 0U, + .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), + .pBindings = set_layout_bindings, + }; + + VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &global_set_layout)); + } + + // ---------------------- + // create layout + // ---------------------- + { + VkPushConstantRange push_constant { + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, + .offset = 0U, + .size = push_constant_slot_size * push_constant_slots, + }; + + VkPipelineLayoutCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .setLayoutCount = 1U, + .pSetLayouts = &global_set_layout, + .pushConstantRangeCount = 1U, + .pPushConstantRanges = &push_constant, + }; + + VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &global_layout)); + } + + // ---------------------- + // create descriptor pool + // ---------------------- + { + VkDescriptorPoolSize pool_sizes[]{ + { + .type = VK_DESCRIPTOR_TYPE_SAMPLER, + .descriptorCount = set_descriptors_count, + }, + { + .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .descriptorCount = set_descriptors_count, + }, + { + .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .descriptorCount = set_descriptors_count, + }, + }; + + VkDescriptorPoolCreateInfo descriptor_pool_create_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .maxSets = descriptor_pool_allocable_sets_count, + .poolSizeCount = sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize), + .pPoolSizes = pool_sizes, + }; + VKCHECK(vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool)); + } + + // ----------------------- + // create descriptors sets + // ----------------------- + { + VkDescriptorSetAllocateInfo allocate_info{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = descriptor_pool, + .descriptorSetCount = 1U, + .pSetLayouts = &global_set_layout, + }; + VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &global_set)); + } + + // --------------------- + // global uniform buffer + // --------------------- + { + uniform_buffers[UniformTypes::GLOBAL] = render_device.create_buffer({ + .size = globals_uniform_buffer_size, + .usages = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "global uniform buffer", + }); + } + + // --------------------- + // passes uniform buffer + // --------------------- + { + uniform_buffers[UniformTypes::PASS] = render_device.create_buffer({ + .size = passes_uniform_buffer_size, + .usages = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "passes uniform buffer" + }); + } + + // -------------------- + // draws uniform buffer + // -------------------- + { + uniform_buffers[UniformTypes::DRAW] = render_device.create_buffer({ + .size = draws_uniform_buffer_size, + .usages = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, + .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, + .name = "draws uniform buffer", + }); + } +} + +void bindless_model::deinit() { + vkdevice& render_device = vkdevice::get(); + VkDevice device = render_device.get_device(); + + vkDestroyDescriptorPool(device, descriptor_pool, nullptr); + + vkDestroyDescriptorSetLayout(device, global_set_layout, nullptr); + vkDestroyPipelineLayout(device, global_layout, nullptr); + + render_device.destroy_buffer(uniform_buffers[UniformTypes::GLOBAL]); + render_device.destroy_buffer(uniform_buffers[UniformTypes::PASS]); + render_device.destroy_buffer(uniform_buffers[UniformTypes::DRAW]); + + for (VkSampler sampler : samplers) { + vkDestroySampler(device, sampler, nullptr); + } +} diff --git a/api-test/vk-command-buffer.cpp b/src/vk-command-buffer.cpp index bdb0e40..26c2d03 100644 --- a/api-test/vk-command-buffer.cpp +++ b/src/vk-command-buffer.cpp @@ -1,11 +1,6 @@ #include "vk-command-buffer.hpp" -#include <vulkan/vulkan_core.h> - -#include "vulkan-loader.hpp" - -#include "vk-device.hpp" -#include "vk-utils.hpp" +uintptr_t constants[3U] = { 0U }; void command_buffer::start() const { VkCommandBufferBeginInfo begin_info{ @@ -17,20 +12,15 @@ void command_buffer::start() const { VKCHECK(vkBeginCommandBuffer(vk_command_buffer, &begin_info)); - 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); - // } + const bindless_model& bindless = vkdevice::get().get_bindingmodel(); + const device_buffer& global_uniforms = bindless.get_uniform_buffer(UniformTypes::GLOBAL); + constants[UniformTypes::GLOBAL] = global_uniforms.device_address + global_uniforms.offset; + if (queue_type == QueueType::GRAPHICS) { - 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); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.global_layout, 0, 1U, &bindless.global_set, 0U, nullptr); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.global_layout, 0, 1U, &bindless.global_set, 0U, nullptr); } else if (queue_type == QueueType::ASYNC_COMPUTE) { - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 0U, nullptr); + vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.global_layout, 0, 1U, &bindless.global_set, 0U, nullptr); } } @@ -39,7 +29,7 @@ void command_buffer::stop() const { } void command_buffer::barrier(handle<device_texture> texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const { - auto& texture = vkdevice::get_render_device().get_texture(texture_handle); + auto& texture = vkdevice::get().get_texture(texture_handle); VkImageSubresourceRange subresource_range{ .aspectMask = texture.aspects, @@ -83,7 +73,7 @@ void command_buffer::barrier(handle<device_texture> texture_handle, VkPipelineSt } void command_buffer::copy(handle<device_buffer> buffer_handle, ::handle<device_texture> texture_handle, uint64_t offset) const { - auto& device = vkdevice::get_render_device(); + auto& device = vkdevice::get(); const auto& buffer = device.get_buffer(buffer_handle); const auto& texture = device.get_texture(texture_handle); @@ -111,17 +101,15 @@ void command_buffer::copy(handle<device_buffer> buffer_handle, ::handle<device_t } void graphics_command_buffer::dispatch(const dispatch_params& params) const { - const auto& pipeline = vkdevice::get_render_device().get_pipeline(params.pipeline); - const auto& bindless = vkdevice::get_render_device().get_bindingmodel(); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, static_cast<uint32_t>(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<uint32_t>(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]); - } + const device_pipeline& pipeline = vkdevice::get().get_pipeline(params.pipeline); + const bindless_model& bindless = vkdevice::get().get_bindingmodel(); vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); + const device_buffer& draw_uniforms = bindless.get_uniform_buffer(UniformTypes::DRAW); + constants[UniformTypes::DRAW] = draw_uniforms.device_address + draw_uniforms.offset; + vkCmdPushConstants(vk_command_buffer, bindless.global_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0U, sizeof(constants), &constants); + 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; @@ -133,7 +121,7 @@ void graphics_command_buffer::begin_renderpass(const renderpass_params& params) for (auto index{ 0U }; index < params.color_attachments.size(); index++) { auto& attachment_info = attachments_info[index]; - auto& attachment = vkdevice::get_render_device().get_texture(params.color_attachments[index]); + auto& attachment = vkdevice::get().get_texture(params.color_attachments[index]); attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; attachment_info.pNext = nullptr; @@ -183,45 +171,40 @@ void graphics_command_buffer::begin_renderpass(const renderpass_params& params) }; vkCmdBeginRendering(vk_command_buffer, &rendering_info); + const bindless_model& bindless = vkdevice::get().get_bindingmodel(); + const device_buffer& pass_uniforms = bindless.get_uniform_buffer(UniformTypes::PASS); + constants[UniformTypes::PASS] = pass_uniforms.device_address + pass_uniforms.offset; + 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<uint32_t>(BindlessSetType::GLOBAL), 1U, &bindless.sets[BindlessSetType::GLOBAL], 1U, ¶ms.uniforms_offset); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.layout, static_cast<uint32_t>(BindlessSetType::GLOBAL), 1U, &bindless.sets[BindlessSetType::GLOBAL], 1U, ¶ms.uniforms_offset); } void graphics_command_buffer::draw(const draw_params& params) const { - auto& device = vkdevice::get_render_device(); + auto& device = vkdevice::get(); 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<uint32_t>(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 device_buffer& draw_uniforms = bindless.get_uniform_buffer(UniformTypes::DRAW); + constants[UniformTypes::DRAW] = draw_uniforms.device_address + draw_uniforms.offset; + vkCmdPushConstants(vk_command_buffer, bindless.global_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0U, sizeof(constants), &constants); 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(); + auto& device = vkdevice::get(); 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<uint32_t>(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 device_buffer& draw_uniforms = bindless.get_uniform_buffer(UniformTypes::DRAW); + constants[UniformTypes::DRAW] = draw_uniforms.device_address + draw_uniforms.offset; + vkCmdPushConstants(vk_command_buffer, bindless.global_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT, 0U, sizeof(constants), &constants); const auto& index_buffer = device.get_buffer(params.index_buffer); vkCmdBindIndexBuffer(vk_command_buffer, index_buffer.vk_buffer, 0U, VK_INDEX_TYPE_UINT16); diff --git a/src/vk-context.cpp b/src/vk-context.cpp deleted file mode 100644 index 1a6a78d..0000000 --- a/src/vk-context.cpp +++ /dev/null @@ -1,319 +0,0 @@ -#include "vk-context.hpp" - -#include <iostream> -#include <cassert> -#include <vector> -#include <array> - -#define VMA_IMPLEMENTATION -#include <vk_mem_alloc.h> - -#include "vulkan-loader.hpp" - -#ifdef _DEBUG -#define VKRESULT(result) assert(result == VK_SUCCESS); -#else -#define VKRESULT(result) result; -#endif - -VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT *data, - void*) -{ - const char* severity_cstr = nullptr; - switch(severity) { - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - severity_cstr = "VERBOSE"; - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - severity_cstr = "INFO"; - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - severity_cstr = "WARNING"; - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - severity_cstr = "ERROR"; - break; - default: - break; - } - - const char* type_cstr = nullptr; - switch(type) { - case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: - type_cstr = "GENERAL"; - break; - case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: - type_cstr = "VALIDATION"; - break; - case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: - type_cstr = "PERFORMANCE"; - break; - default: - break; - } - - std::cerr << "[" << severity_cstr << "_" << type_cstr << "]: " << data->pMessage << std::endl; - return VK_FALSE; -} - - -vkcontext::vkcontext() { - load_vulkan(); - - create_instance(); - create_device(); - create_debugger(); - create_memory_allocator(); -} - -vkcontext::~vkcontext() { - vmaDestroyAllocator(allocator); - vkDestroyDevice(device, nullptr); - vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr); - vkDestroyInstance(instance, nullptr); -} - - -void vkcontext::create_instance() { - VkApplicationInfo app_info = {}; - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.pApplicationName = "path-tracer"; - app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - app_info.pEngineName = "gpu-path-tracer"; - app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0); - app_info.apiVersion = VK_API_VERSION_1_2; - - const char* needed_layers[] = { -#if defined(_DEBUG) - "VK_LAYER_KHRONOS_validation", -#endif - }; - auto needed_layers_count = sizeof(needed_layers) / sizeof(needed_layers[0]); - - check_available_instance_layers(needed_layers, needed_layers_count); - - constexpr const char* needed_extensions[] = { - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - "VK_KHR_surface", -#if defined(LINUX) - "VK_KHR_xcb_surface" -#elif defined(WINDOWS) - "VK_KHR_win32_surface" -#elif defined(MACOS) - "VK_EXT_metal_surface" -#endif - }; - constexpr auto needed_extensions_count = sizeof(needed_extensions) / sizeof(needed_extensions[0]); - - check_available_instance_extensions(needed_extensions, needed_extensions_count); - - VkInstanceCreateInfo instance_create_info = {}; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pApplicationInfo = &app_info; - instance_create_info.enabledLayerCount = needed_layers_count; - instance_create_info.ppEnabledLayerNames = needed_layers; - instance_create_info.enabledExtensionCount = needed_extensions_count; - instance_create_info.ppEnabledExtensionNames = needed_extensions; - - VKRESULT(vkCreateInstance(&instance_create_info, nullptr, &instance)) - - load_instance_functions(instance); - - std::cerr << "Instance ready" << std::endl; -} - -void vkcontext::create_debugger() { - VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengeCreateInfo { - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - nullptr, - 0, - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, - DebugCallback, - nullptr, - }; - - VKRESULT(vkCreateDebugUtilsMessengerEXT( - instance, - &debugUtilsMessengeCreateInfo, - nullptr, - &debugMessenger - )) -} - -void vkcontext::create_device() { - select_physical_device(); - - graphics_queue = { - .usages = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT, - }; - auto queue_priority = 1.f; - graphics_queue.index = select_queue(graphics_queue.usages); - auto queue_create_info = VkDeviceQueueCreateInfo { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .queueFamilyIndex = graphics_queue.index, - .queueCount = 1, - - .pQueuePriorities = &queue_priority - }; - - VkPhysicalDeviceVulkan12Features physical_device_12_features = {}; - physical_device_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - physical_device_12_features.pNext = VK_NULL_HANDLE; - physical_device_12_features.bufferDeviceAddress = VK_TRUE; - physical_device_12_features.runtimeDescriptorArray = VK_TRUE; - physical_device_12_features.shaderStorageImageArrayNonUniformIndexing = VK_TRUE; - physical_device_12_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; - physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE; - physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE; - physical_device_12_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; - physical_device_12_features.imagelessFramebuffer = VK_TRUE; - - VkPhysicalDeviceFeatures2 device_features = {}; - device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - device_features.pNext = &physical_device_12_features; - - const char* device_ext[] = { - "VK_KHR_swapchain", - }; - - VkDeviceCreateInfo device_create_info = {}; - device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.pNext = &device_features; - device_create_info.pQueueCreateInfos = &queue_create_info; - device_create_info.queueCreateInfoCount = 1; - device_create_info.ppEnabledExtensionNames = device_ext; - device_create_info.enabledExtensionCount = sizeof(device_ext) / sizeof(device_ext[0]); - device_create_info.enabledLayerCount = 0; // Deprecated https://www.khronos.org/registry/vulkan/specs/1.2/html/chap31.html#extendingvulkan-layers-devicelayerdeprecation - - VKRESULT(vkCreateDevice(physical_device, &device_create_info, nullptr, &device)) - - load_device_functions(device); - - vkGetDeviceQueue(device, graphics_queue.index, 0, &graphics_queue.handle); - - std::cerr << "Device ready" << std::endl; -} - -void vkcontext::create_memory_allocator() { - VmaAllocatorCreateInfo allocator_info = {}; - allocator_info.vulkanApiVersion = VK_API_VERSION_1_2; - allocator_info.physicalDevice = physical_device; - allocator_info.device = device; - allocator_info.instance = instance; - allocator_info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; - - vmaCreateAllocator(&allocator_info, &allocator); -} - - -void vkcontext::select_physical_device() { - uint32_t physical_devices_count = 0; - vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr); - - if (physical_devices_count < 1) { - std::cerr << "No physical device found !" << std::endl; - } - - std::vector<VkPhysicalDevice> physical_devices { physical_devices_count }; - vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data()); - - - for (auto& physical_dev: physical_devices) { - if (support_required_features(physical_dev)) { - physical_device = physical_dev; - } - } - - assert(physical_device != VK_NULL_HANDLE); -} - -uint32_t vkcontext::select_queue(VkQueueFlags queue_usage) const { - uint32_t queue_properties_count = 0; - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr); - - std::vector<VkQueueFamilyProperties> queue_properties { queue_properties_count }; - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data()); - - for (uint32_t properties_index = 0; properties_index < queue_properties_count; properties_index++) { - if ((queue_properties[properties_index].queueFlags & queue_usage) != 0U) { - return properties_index; - } - } - - assert(true); - return UINT_MAX; -} - -void vkcontext::check_available_instance_layers(const char* needed_layers[], size_t needed_layers_count) { - uint32_t property_count = 0; - vkEnumerateInstanceLayerProperties(&property_count, VK_NULL_HANDLE); - - std::vector<VkLayerProperties> layer_properties { property_count }; - vkEnumerateInstanceLayerProperties(&property_count, layer_properties.data()); - - uint32_t available_needed_layers_count = 0; - - for (auto layer_property: layer_properties) { - for (auto layer_index { 0U }; layer_index < needed_layers_count; layer_index++) { - if (strcmp(layer_property.layerName, needed_layers[layer_index]) == 0) { - available_needed_layers_count++; - } - } - } - - assert(available_needed_layers_count == needed_layers_count); -} - -void vkcontext::check_available_instance_extensions(const char* needed_extensions[], size_t needed_extensions_count) { - uint32_t vulkan_extensions_count = 0; - vkEnumerateInstanceExtensionProperties(VK_NULL_HANDLE, &vulkan_extensions_count, VK_NULL_HANDLE); - - std::vector<VkExtensionProperties> vulkan_extensions_properties { vulkan_extensions_count }; - vkEnumerateInstanceExtensionProperties(VK_NULL_HANDLE, &vulkan_extensions_count, vulkan_extensions_properties.data()); - - uint32_t available_needed_extensions_count = 0; - for (auto& extension: vulkan_extensions_properties) { - for (auto extension_index { 0U }; extension_index < needed_extensions_count; extension_index++) { - if (strcmp(extension.extensionName, needed_extensions[extension_index]) == 0) { - available_needed_extensions_count++; - } - } - } - - // assert(available_needed_extensions_count == needed_extensions_count); -} - -bool vkcontext::support_required_features(VkPhysicalDevice physical_device) { - VkPhysicalDeviceProperties physical_device_properties = {}; - - vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties); - - VkPhysicalDeviceVulkan12Features vulkan_12_features = {}; - vulkan_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - - VkPhysicalDeviceFeatures2 physical_device_features = {}; - physical_device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - physical_device_features.pNext = &vulkan_12_features; - - vkGetPhysicalDeviceFeatures2(physical_device, &physical_device_features); - - if (vulkan_12_features.bufferDeviceAddress == VK_TRUE && - vulkan_12_features.runtimeDescriptorArray == VK_TRUE && - vulkan_12_features.shaderStorageImageArrayNonUniformIndexing == VK_TRUE && - vulkan_12_features.shaderSampledImageArrayNonUniformIndexing == VK_TRUE && - vulkan_12_features.descriptorBindingPartiallyBound == VK_TRUE && - vulkan_12_features.descriptorBindingPartiallyBound == VK_TRUE && - vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE && - vulkan_12_features.imagelessFramebuffer == VK_TRUE) { - std::cerr << "Using physical device " << physical_device_properties.deviceName << std::endl; - return true; - } - - std::cerr << "Physical device " << physical_device_properties.deviceName << " is missing some features" << std::endl; - return false; -} - diff --git a/api-test/vk-device.cpp b/src/vk-device.cpp index 1e7b385..6fa3533 100644 --- a/api-test/vk-device.cpp +++ b/src/vk-device.cpp @@ -1,16 +1,22 @@ #include "vk-device.hpp" -#include <cassert> -#include <vector> - -#include <vulkan/vulkan_core.h> - #define VMA_IMPLEMENTATION #include <vk_mem_alloc.h> -#include "vk-utils.hpp" -#include "vulkan-loader.hpp" -#include "vk-command-buffer.hpp" +static VkShaderModule create_shader_module(VkDevice device, uint8_t* code, size_t code_size) { + VkShaderModule shader_module; + VkShaderModuleCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .codeSize = code_size, + .pCode = reinterpret_cast<uint32_t*>(code), + }; + + VKCHECK(vkCreateShaderModule(device, &create_info, nullptr, &shader_module)); + return shader_module; +} + vkdevice vkdevice::render_device = vkdevice(); @@ -39,7 +45,7 @@ void vkdevice::init() { create_memory_allocator(); - bindless = bindless_model::create_bindless_model(); + bindless.init(); auto semaphore = create_semaphore({ .type = VK_SEMAPHORE_TYPE_TIMELINE, @@ -50,7 +56,7 @@ void vkdevice::init() { void vkdevice::deinit() { vkDeviceWaitIdle(device); - bindless_model::destroy_bindless_model(bindless); + bindless.deinit(); vmaDestroyAllocator(gpu_allocator); @@ -74,6 +80,8 @@ void vkdevice::wait() { vkDeviceWaitIdle(device); }; handle<device_texture> vkdevice::create_texture(const texture_desc& desc) { device_texture device_texture; + // TODO: This must always be present since we want to display images in ImGui + const_cast<texture_desc&>(desc).usages |= VK_IMAGE_USAGE_SAMPLED_BIT; device_texture.init(desc); return textures.add(device_texture); @@ -88,7 +96,9 @@ handle<device_sampler> vkdevice::create_sampler(const sampler_desc& desc) { handle<device_buffer> vkdevice::create_buffer(const buffer_desc& desc) { device_buffer device_buffer{ - .size = desc.size, + .size = desc.size, + .usages = desc.usages, + .name = desc.name, }; VkBufferCreateInfo create_info{ @@ -118,6 +128,7 @@ handle<device_buffer> vkdevice::create_buffer(const buffer_desc& desc) { VmaAllocationInfo alloc_info{}; VKCHECK(vmaCreateBuffer(gpu_allocator, &create_info, &alloc_create_info, &device_buffer.vk_buffer, &device_buffer.alloc, &alloc_info)); + vmaSetAllocationName(render_device.get_allocator(), device_buffer.alloc, desc.name); if ((desc.usages & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0U) { VkBufferDeviceAddressInfo address_info { @@ -142,7 +153,7 @@ handle<device_pipeline> vkdevice::create_graphics_pipeline(const graphics_pipeli .pNext = nullptr, .flags = 0U, .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = create_shader_module(desc.vs_code), + .module = create_shader_module(device, desc.vs_code, desc.vs_code_size), .pName = "main", .pSpecializationInfo = nullptr, }, @@ -151,7 +162,7 @@ handle<device_pipeline> vkdevice::create_graphics_pipeline(const graphics_pipeli .pNext = nullptr, .flags = 0U, .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = create_shader_module(desc.fs_code), + .module = create_shader_module(device, desc.fs_code, desc.fs_code_size), .pName = "main", .pSpecializationInfo = nullptr, }, @@ -259,7 +270,7 @@ handle<device_pipeline> vkdevice::create_graphics_pipeline(const graphics_pipeli .pDepthStencilState = nullptr, .pColorBlendState = &color_blend_state_create_info, .pDynamicState = &dynamic_state_create_info, - .layout = bindless.graphics_layout, + .layout = bindless.global_layout, .renderPass = nullptr, .subpass = 0U, .basePipelineHandle = nullptr, @@ -296,7 +307,7 @@ handle<device_pipeline> vkdevice::create_compute_pipeline(const compute_pipeline .pNext = nullptr, .flags = 0U, .stage = VK_SHADER_STAGE_COMPUTE_BIT, - .module = create_shader_module(desc.cs_code), + .module = create_shader_module(device, desc.cs_code, desc.cs_code_size), .pName = "main", .pSpecializationInfo = nullptr, }; @@ -306,7 +317,7 @@ handle<device_pipeline> vkdevice::create_compute_pipeline(const compute_pipeline .pNext = nullptr, .flags = 0U, .stage = stage_create_info, - .layout = bindless.compute_layout, + .layout = bindless.global_layout, .basePipelineHandle = nullptr, .basePipelineIndex = 0, }; @@ -517,20 +528,20 @@ void vkdevice::destroy_surface(handle<device_surface> handle) { // return ret; // } -uint64_t vkdevice::submit(command_buffer* buffers, uint32_t count) { +uint64_t vkdevice::submit(command_buffer* cmd_buffers, uint32_t count) { assert((max_submitable_command_buffers - count) >= 0); - const auto queue_type = buffers[0].queue_type; + const auto queue_type = cmd_buffers[0].queue_type; // VkCommandBufferSubmitInfo command_buffers_info[count]; VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; for (auto index{ 0U }; index < count; index++) { - assert(queue_type == buffers[index].queue_type); + assert(queue_type == cmd_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.commandBuffer = cmd_buffers[index].vk_command_buffer; command_buffer_info.deviceMask = 0U; } @@ -563,25 +574,25 @@ uint64_t vkdevice::submit(command_buffer* buffers, uint32_t count) { return fence.value; } -uint64_t vkdevice::submit_before_present(handle<device_surface> surface_handle, command_buffer* buffers, uint32_t count) { +uint64_t vkdevice::submit_before_present(handle<device_surface> surface_handle, command_buffer* cmd_buffers, uint32_t count) { assert((max_submitable_command_buffers - count) >= 0); - const auto queue_type = buffers[0].queue_type; + const QueueType queue_type = cmd_buffers[0].queue_type; // VkCommandBufferSubmitInfo command_buffers_info[count]; VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; - for (auto index{ 0U }; index < count; index++) { - assert(queue_type == buffers[index].queue_type); + for (uint32_t index{ 0U }; index < count; index++) { + assert(queue_type == cmd_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.commandBuffer = cmd_buffers[index].vk_command_buffer; command_buffer_info.deviceMask = 0U; } - const auto& surface = get_surface(surface_handle); - auto& wait = get_semaphore(surface.acquire_semaphores[surface.frame_index]); + const device_surface& surface = get_surface(surface_handle); + device_semaphore& wait = get_semaphore(surface.acquire_semaphores[surface.frame_index]); VkSemaphoreSubmitInfo wait_semaphore_info = { .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, .pNext = nullptr, @@ -630,7 +641,7 @@ uint64_t vkdevice::submit_before_present(handle<device_surface> surface_handle, } void vkdevice::present(handle<device_surface> surface_handle) { - auto& surface = vkdevice::get_render_device().get_surface(surface_handle); + auto& surface = render_device.get_surface(surface_handle); VkResult result; VkPresentInfoKHR present_info{ .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -652,7 +663,7 @@ void vkdevice::present(handle<device_surface> surface_handle) { } // private -void vkdevice::allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type, const char* name) { +void vkdevice::allocate_command_buffers(command_buffer* cmd_buffers, size_t count, QueueType type, const char* name) { assert((max_allocable_command_buffers - count) >= 0); const auto& queue = queues[static_cast<uint32_t>(type)]; VkCommandBuffer command_buffers[max_allocable_command_buffers]; @@ -667,9 +678,9 @@ void vkdevice::allocate_command_buffers(command_buffer* buffers, size_t count, Q VKCHECK(vkAllocateCommandBuffers(device, &allocate_info, command_buffers)); - for (auto index{ 0U }; index < count; index++) { - buffers[index].vk_command_buffer = command_buffers[index]; - buffers[index].queue_type = type; + for (uint32_t index{ 0U }; index < count; index++) { + cmd_buffers[index].vk_command_buffer = command_buffers[index]; + cmd_buffers[index].queue_type = type; if (name) { VkDebugUtilsObjectNameInfoEXT object_name{ @@ -684,21 +695,6 @@ void vkdevice::allocate_command_buffers(command_buffer* buffers, size_t count, Q } } -VkShaderModule vkdevice::create_shader_module(const std::span<uint8_t>& shader_code) { - VkShaderModule shader_module; - const auto& code = shader_code; - VkShaderModuleCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .codeSize = code.size(), - .pCode = reinterpret_cast<uint32_t*>(code.data()), - }; - - VKCHECK(vkCreateShaderModule(device, &create_info, nullptr, &shader_module)); - return shader_module; -} - void vkdevice::create_swapchain(const surface_desc& desc, device_surface& surface) { VkSurfaceKHR vk_surface = surface.vk_surface; @@ -808,6 +804,7 @@ void vkdevice::create_swapchain(const surface_desc& desc, device_surface& surfac .format = desc.surface_format.format, .type = VK_IMAGE_TYPE_2D, .vk_image = images[index], + .name = "swapchain image" }); } } @@ -932,10 +929,15 @@ void vkdevice::create_device() { } void vkdevice::create_memory_allocator() { + VmaVulkanFunctions functions = { + .vkGetInstanceProcAddr = vkGetInstanceProcAddr, + .vkGetDeviceProcAddr = vkGetDeviceProcAddr, + }; VmaAllocatorCreateInfo create_info{ .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, .physicalDevice = physical_device, .device = device, + .pVulkanFunctions = &functions, .instance = instance, .vulkanApiVersion = VK_API_VERSION_1_2, }; @@ -966,9 +968,15 @@ void vkdevice::pick_physical_device() { std::vector<VkPhysicalDevice> physical_devices{ physical_devices_count }; vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data()); + physical_device_props = VkPhysicalDeviceProperties2 { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = nullptr, + }; + for (auto& physical_dev : physical_devices) { if (device_support_features(physical_dev)) { physical_device = physical_dev; + return; } } @@ -979,13 +987,9 @@ void vkdevice::pick_physical_device() { bool vkdevice::device_support_features(VkPhysicalDevice physical_dev) { // limits { - VkPhysicalDeviceProperties2 props{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, - .pNext = nullptr, - }; - vkGetPhysicalDeviceProperties2(physical_dev, &props); + vkGetPhysicalDeviceProperties2(physical_dev, &physical_device_props); - VkPhysicalDeviceLimits* limits = &props.properties.limits; + VkPhysicalDeviceLimits* limits = &physical_device_props.properties.limits; if (limits->maxPerStageDescriptorSampledImages < 0x10000 || limits->maxPerStageDescriptorStorageImages < 0x10000 || limits->maxDescriptorSetSampledImages < 0x10000 || @@ -1024,6 +1028,7 @@ bool vkdevice::device_support_features(VkPhysicalDevice physical_dev) { { VkPhysicalDeviceVulkan13Features vulkan_13_features{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = nullptr, }; VkPhysicalDeviceFeatures2 physical_device_features{ @@ -1067,7 +1072,7 @@ 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(); + auto& render_device = vkdevice::get(); const auto& bindless = render_device.get_bindingmodel(); auto* device = render_device.get_device(); @@ -1076,6 +1081,7 @@ void device_texture::init(const texture_desc& desc) { width = desc.width; height = desc.height; mips = desc.mips; + name = desc.name; aspects = ((desc.usages & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0U) ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_COLOR_BIT; @@ -1116,6 +1122,7 @@ void device_texture::init(const texture_desc& desc) { }; VKCHECK(vmaCreateImage(render_device.get_allocator(), &create_info, &alloc_create_info, &vk_image, &alloc, nullptr)); + vmaSetAllocationName(render_device.get_allocator(), alloc, desc.name); } if (desc.name) { @@ -1147,7 +1154,8 @@ void device_texture::init(const texture_desc& desc) { write_descriptor_sets.push_back({ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, - .dstSet = bindless.sets[BindlessSetType::GLOBAL], + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstSet = bindless.global_set, .dstBinding = 2U, .dstArrayElement = storage_index.id, .descriptorCount = sizeof(images_info) / sizeof(VkDescriptorImageInfo), @@ -1163,7 +1171,8 @@ void device_texture::init(const texture_desc& desc) { write_descriptor_sets.push_back({ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, - .dstSet = bindless.sets[BindlessSetType::GLOBAL], + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstSet = bindless.global_set, .dstBinding = 1U, .dstArrayElement = sampled_index.id, .descriptorCount = sizeof(images_info) / sizeof(VkDescriptorImageInfo), @@ -1178,7 +1187,7 @@ void device_texture::init(const texture_desc& desc) { } void device_texture::release() { - auto& render_device = vkdevice::get_render_device(); + auto& render_device = vkdevice::get(); auto* device = render_device.get_device(); auto* gpu_allocator = render_device.get_allocator(); @@ -1203,7 +1212,7 @@ void device_texture::release() { } void device_texture::create_views() { - auto* device = vkdevice::get_render_device().get_device(); + auto* device = vkdevice::get().get_device(); VkImageViewCreateInfo create_info{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -1239,7 +1248,7 @@ void device_texture::create_views() { void device_sampler::init(const sampler_desc& desc) { - auto& render_device = vkdevice::get_render_device(); + auto& render_device = vkdevice::get(); // const auto& bindless = render_device.get_bindingmodel(); auto* device = render_device.get_device(); diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp deleted file mode 100644 index ddff268..0000000 --- a/src/vk-renderer.cpp +++ /dev/null @@ -1,284 +0,0 @@ -#include "vk-renderer.hpp" - -#include <cstring> -#include <cassert> - -#include <vk_mem_alloc.h> - -#include "vulkan-loader.hpp" - -#include "compute-renderpass.hpp" -#include "primitive-renderpass.hpp" - -#include "texture.hpp" - -#include "window.hpp" - -#ifdef _DEBUG -#define VKRESULT(result) assert(result == VK_SUCCESS); -#else -#define VKRESULT(result) result; -#endif - -auto vkrenderer::context = vkcontext(); -auto vkrenderer::api = vkapi(vkrenderer::context); -auto vkrenderer::upload_queue = std::vector<Texture*>(); - -vkrenderer::vkrenderer(window& wnd) { - platform_surface = api.create_surface(wnd); - swapchain = api.create_swapchain( - platform_surface, - min_swapchain_image_count, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_STORAGE_BIT, - VK_NULL_HANDLE - ); - - swapchain_textures.resize(swapchain.image_count); - for (size_t index = 0; index < swapchain.image_count; index++) { - swapchain_textures[index] = new Texture(swapchain.images[index]); - } - - tonemapping_pipeline = api.create_compute_pipeline("tonemapping"); - - graphics_command_pool = api.create_command_pool(); - api.allocate_command_buffers(graphics_command_pool, graphics_command_buffers, virtual_frames_count); - - for(size_t index { 0 }; index < virtual_frames_count; index++) { - submission_fences[index] = api.create_fence(); - execution_semaphores[index] = api.create_semaphore(); - acquire_semaphores[index] = api.create_semaphore(); - - copy_command_pools[index] = api.create_command_pool(); - api.allocate_command_buffers(copy_command_pools[index], ©_command_buffers[index], 1); - - // staging_buffers[index] = create_staging_buffer(4096 * 4096 * sizeof(uint32_t)); - staging_buffers[index] = new RingBuffer(4096ULL * 4096ULL * sizeof(uint32_t)); - } -} - -vkrenderer::~vkrenderer() { - VKRESULT(vkWaitForFences(context.device, virtual_frames_count, submission_fences, VK_TRUE, UINT64_MAX)) - - for (auto& renderpass : renderpasses) { - delete renderpass; - } - - for(size_t index { 0 }; index < virtual_frames_count; index++) { - vkFreeCommandBuffers(context.device, copy_command_pools[index], 1, ©_command_buffers[index]); - vkDestroyCommandPool(context.device, copy_command_pools[index], nullptr); - } - - api.destroy_fences(submission_fences, virtual_frames_count); - api.destroy_semaphores(execution_semaphores, virtual_frames_count); - api.destroy_semaphores(acquire_semaphores, virtual_frames_count); - - vkFreeCommandBuffers(context.device, graphics_command_pool, virtual_frames_count, graphics_command_buffers); - vkDestroyCommandPool(context.device, graphics_command_pool, nullptr); - - - api.destroy_pipeline(tonemapping_pipeline); - - api.destroy_swapchain(swapchain); - api.destroy_surface(platform_surface); -} -void vkrenderer::recreate_swapchain() { - VKRESULT(vkWaitForFences(context.device, vkrenderer::virtual_frames_count, submission_fences, VK_TRUE, UINT64_MAX)) - - auto swapchain_image_usages = api.get_image(swapchain.images[0]).usages; - struct swapchain old_swapchain = swapchain; - swapchain = api.create_swapchain( - platform_surface, - min_swapchain_image_count, - swapchain_image_usages, - old_swapchain.handle - ); - - api.destroy_swapchain(old_swapchain); - - swapchain_textures.resize(swapchain.image_count); - for (size_t index = 0; index < swapchain.image_count; index++) { - swapchain_textures[index] = new Texture(swapchain.images[index]); - } -} - -void vkrenderer::queue_image_update(Texture* texture) { - upload_queue.push_back(texture); -} - -void vkrenderer::update_images() { - if(upload_queue.empty()) - return; - - auto* staging_buffer = staging_buffers[virtual_frame_index]; - staging_buffer->reset(); - - VkCommandBuffer command_buffer = copy_command_buffers[virtual_frame_index]; - vkrenderer::api.start_record(command_buffer); - - while(!upload_queue.empty()) { - auto* texture = upload_queue.back(); - auto texture_size = texture->size(); - auto offset = staging_buffer->alloc(texture_size); - - if (offset == RingBuffer::invalid_alloc) - break; - - upload_queue.pop_back(); - - staging_buffer->write(texture->data, offset, texture_size); - - vkrenderer::api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, texture->device_image); - vkrenderer::api.copy_buffer(command_buffer, staging_buffer->device_buffer, texture->device_image, 0, offset); - vkrenderer::api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, texture->device_image); - } - - vkrenderer::api.end_record(command_buffer); - - recorded_command_buffers.push_back(command_buffer); -} - -Buffer* vkrenderer::create_buffer(size_t size) { - return new Buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); -} - -Buffer* vkrenderer::create_index_buffer(size_t size) { - return new Buffer(size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); -} - -Buffer* vkrenderer::create_staging_buffer(size_t size) { - return new Buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); -} - -Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat format, Sampler *sampler) { - return new Texture(width, height, 1, format, sampler); -} - -// TODO: Check if a similar sampler has been allocated -Sampler* vkrenderer::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) { - auto* sampler = new Sampler(); - - sampler->device_sampler = api.create_sampler(filter, address_mode); - - return sampler; -} - -ComputeRenderpass* vkrenderer::create_compute_renderpass() { - renderpasses.push_back(new ComputeRenderpass(api)); - - return (ComputeRenderpass*)renderpasses.back(); -} - -PrimitiveRenderpass* vkrenderer::create_primitive_renderpass() { - renderpasses.push_back(new PrimitiveRenderpass(api)); - - return (PrimitiveRenderpass*)renderpasses.back(); -} - -Primitive* vkrenderer::create_primitive(PrimitiveRenderpass& primitive_render_pass) { - return new Primitive(primitive_render_pass); -} - -void vkrenderer::render() { - swapchain_image_index = 0; - auto acquire_result = vkAcquireNextImageKHR(context.device, swapchain.handle, UINT64_MAX, acquire_semaphores[virtual_frame_index], VK_NULL_HANDLE, &swapchain_image_index); - handle_swapchain_result(acquire_result); - - api.start_record(graphics_command_buffers[virtual_frame_index]); - - auto* cmd_buf = graphics_command_buffers[virtual_frame_index]; - - // wait for transfer operations - - for (auto& renderpass: renderpasses) { - renderpass->execute(*this, cmd_buf); - - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, ((ComputeRenderpass*)renderpass)->output_texture->device_image); - - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, swapchain.images[swapchain_image_index]); - - api.blit_full(cmd_buf, ((ComputeRenderpass*)renderpass)->output_texture->device_image, swapchain.images[swapchain_image_index]); - } - - - // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, swapchain.images[swapchain_image_index]); - - // renderpasses[1]->execute(*this, cmd_buf); - - api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]); - - api.end_record(cmd_buf); - - recorded_command_buffers.push_back(cmd_buf); -} - -void vkrenderer::begin_frame() { - recorded_command_buffers.clear(); - - VKRESULT(vkWaitForFences(context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) - VKRESULT(vkResetFences(context.device, 1, &submission_fences[virtual_frame_index])) - - update_images(); -} - -void vkrenderer::finish_frame() { - api.submit(recorded_command_buffers.data(), recorded_command_buffers.size(), acquire_semaphores[virtual_frame_index], execution_semaphores[virtual_frame_index], submission_fences[virtual_frame_index]); - - auto present_result = api.present(swapchain, swapchain_image_index, execution_semaphores[virtual_frame_index]); - handle_swapchain_result(present_result); - - virtual_frame_index = ++virtual_frame_index % virtual_frames_count; -} - - - -// private functions -void vkrenderer::handle_swapchain_result(VkResult function_result) { - switch(function_result) { - case VK_ERROR_OUT_OF_DATE_KHR: - return recreate_swapchain(); - case VK_ERROR_SURFACE_LOST_KHR: - assert(true && "surface lost"); - default: - return; - } -} - - - -Buffer::Buffer(size_t size, VkBufferUsageFlagBits usage) - : buffer_size(size), usage(usage) { - device_buffer = vkrenderer::api.create_buffer(size, usage, VMA_MEMORY_USAGE_CPU_TO_GPU); -} - -Buffer::~Buffer() { - vkrenderer::api.destroy_buffer(device_buffer); -} - -void Buffer::write(void* data, off_t alloc_offset, size_t data_size) const { - auto api_buffer = vkrenderer::api.get_buffer(device_buffer); - - std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size); -} - -void Buffer::resize(size_t new_size) { - auto old_device_buffer = device_buffer; - new_size = static_cast<uint32_t>(exp2(ceil(log2((double)new_size)))); - - device_buffer = vkrenderer::api.create_buffer(new_size, usage, VMA_MEMORY_USAGE_CPU_TO_GPU); - - auto old_buffer = vkrenderer::api.get_buffer(device_buffer); - auto new_buffer = vkrenderer::api.get_buffer(device_buffer); - std::memcpy(new_buffer.device_ptr, old_buffer.device_ptr, buffer_size); - - buffer_size = new_size; - - vkrenderer::api.destroy_buffer(old_device_buffer); -} - - -RingBuffer::RingBuffer(size_t size) - : buffer_size(size) { - device_buffer = vkrenderer::api.create_buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - } diff --git a/api-test/vk-utils.cpp b/src/vk-utils.cpp index 4df6424..89f5741 100644 --- a/api-test/vk-utils.cpp +++ b/src/vk-utils.cpp @@ -1,7 +1,5 @@ #include "vk-utils.hpp" -#include <cstdio> - VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* data, |
