From c3aac9026951e2a6e35e76b9c7d36e114a281453 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Tue, 5 May 2026 00:43:54 +0200 Subject: Remove old api and move api-test content to src and include dirs --- src/compute-renderpass.cpp | 63 -- src/dx12-command-buffer.cpp | 47 ++ src/dx12-device.cpp | 239 ++++++++ src/main.cpp | 1123 ++++++++++++++++++++++++------------ src/primitive-renderpass.cpp | 152 ----- src/vk-api.cpp | 1257 ---------------------------------------- src/vk-bindless.cpp | 238 ++++++++ src/vk-command-buffer.cpp | 216 +++++++ src/vk-context.cpp | 319 ---------- src/vk-device.cpp | 1311 ++++++++++++++++++++++++++++++++++++++++++ src/vk-renderer.cpp | 284 --------- src/vk-utils.cpp | 42 ++ 12 files changed, 2856 insertions(+), 2435 deletions(-) delete mode 100644 src/compute-renderpass.cpp create mode 100644 src/dx12-command-buffer.cpp create mode 100644 src/dx12-device.cpp delete mode 100644 src/primitive-renderpass.cpp delete mode 100644 src/vk-api.cpp create mode 100644 src/vk-bindless.cpp create mode 100644 src/vk-command-buffer.cpp delete mode 100644 src/vk-context.cpp create mode 100644 src/vk-device.cpp delete mode 100644 src/vk-renderer.cpp create mode 100644 src/vk-utils.cpp (limited to 'src') 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/src/dx12-command-buffer.cpp b/src/dx12-command-buffer.cpp new file mode 100644 index 0000000..0310dfd --- /dev/null +++ b/src/dx12-command-buffer.cpp @@ -0,0 +1,47 @@ +#include "dx12-command-buffer.hpp" + +#include "dx12-device.hpp" + +namespace dx12 { + void command_buffer::start() const { + HRESULT hr = command_allocator->Reset(); + assert(hr == S_OK); + + hr = dx12_command_buffer->Reset(command_allocator, nullptr); + assert(hr == S_OK); + + auto& device = dx12::device::get_render_device(); + dx12_command_buffer->SetDescriptorHeaps(2U, dx12::device::get_bindless_model().get_heaps()); + } + + void command_buffer::stop() const { + HRESULT hr = dx12_command_buffer->Close(); + assert(hr == S_OK); + } + + void command_buffer::copy(handle src_buffer, handle dst_texture, uint64_t offset) const { + auto& dst = device::get_render_device().get_texture(dst_texture); + D3D12_TEXTURE_COPY_LOCATION dst_copy_location { + .pResource = dst.resource, + .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + .SubresourceIndex = 0U, + }; + + auto& src = device::get_render_device().get_buffer(src_buffer); + D3D12_TEXTURE_COPY_LOCATION src_copy_location { + .pResource = src.resource, + .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, + .PlacedFootprint = { + .Offset = offset, + .Footprint = { + .Format = dst.format, + .Width = dst.width, + .Height = dst.height, + .Depth = dst.depth, + .RowPitch = static_cast(dst.row_pitch), + }, + }, + }; + dx12_command_buffer->CopyTextureRegion(&dst_copy_location, 0U, 0U, 0U, &src_copy_location, nullptr); + } +} diff --git a/src/dx12-device.cpp b/src/dx12-device.cpp new file mode 100644 index 0000000..ac328ed --- /dev/null +++ b/src/dx12-device.cpp @@ -0,0 +1,239 @@ +#include "dx12-device.hpp" + +#include +#include + +#include "dx12-command-buffer.hpp" + +namespace dx12 { + device device::render_device = dx12::device(); + + void device::init() { + HRESULT hr = S_OK; + hr = CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, IID_PPV_ARGS(&factory)); + assert(hr == S_OK); + + uint32_t index = 0U; + while (factory->EnumAdapters(index, &adapter) != DXGI_ERROR_NOT_FOUND) { + DXGI_ADAPTER_DESC desc; + SUCCEEDED(adapter->GetDesc(&desc)); + printf("%S\n", desc.Description); + index++; + } + + SUCCEEDED(factory->EnumAdapters(0U, &adapter)); + + if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug_interface)))) { + debug_interface->EnableDebugLayer(); + } + + hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&device)); + assert(hr == S_OK); + + queues[static_cast(QueueType::GRAPHICS)].type = D3D12_COMMAND_LIST_TYPE_DIRECT; + D3D12_COMMAND_QUEUE_DESC queue_desc{ + .Type = queues[static_cast(QueueType::GRAPHICS)].type, + .Priority = D3D12_COMMAND_QUEUE_PRIORITY::D3D12_COMMAND_QUEUE_PRIORITY_HIGH, + .Flags = D3D12_COMMAND_QUEUE_FLAGS::D3D12_COMMAND_QUEUE_FLAG_NONE, + .NodeMask = 0U, + }; + device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&queues[static_cast(QueueType::GRAPHICS)].dx_queue)); + assert(hr == S_OK); + + queue_desc.Type = queues[static_cast(QueueType::ASYNC_COMPUTE)].type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY::D3D12_COMMAND_QUEUE_PRIORITY_HIGH, + device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&queues[static_cast(QueueType::ASYNC_COMPUTE)].dx_queue)); + assert(hr == S_OK); + + queue_desc.Type = queues[static_cast(QueueType::TRANSFER)].type = D3D12_COMMAND_LIST_TYPE_COPY; + queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY::D3D12_COMMAND_QUEUE_PRIORITY_HIGH, + device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&queues[static_cast(QueueType::TRANSFER)].dx_queue)); + assert(hr == S_OK); + + hr = device->CreateFence(0U, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); + assert(hr == S_OK); + + D3D12MA::ALLOCATOR_DESC allocator_desc { + .pDevice = device, + .pAdapter = adapter, + }; + + hr = D3D12MA::CreateAllocator(&allocator_desc, &allocator); + assert(hr == S_OK); + + model.init(); + } + + handle device::create_surface(const surface_desc& desc) { + device_surface surface { + }; + DXGI_SAMPLE_DESC sample_desc{ + .Count = 1U, + .Quality = 0U, + }; + DXGI_SWAP_CHAIN_DESC1 swapchain_desc1{ + .Width = 0U, + .Height = 0U, + .Format = desc.surface_format, + .Stereo = FALSE, + .SampleDesc = sample_desc, + .BufferUsage = desc.usages, + .BufferCount = desc.image_count, + .Scaling = DXGI_SCALING_NONE, + .SwapEffect = desc.present_mode, + .AlphaMode = DXGI_ALPHA_MODE_IGNORE, + .Flags = 0U, + }; + HRESULT hr = factory->CreateSwapChainForHwnd(queues[static_cast(QueueType::GRAPHICS)].dx_queue, desc.window_handle, &swapchain_desc1, nullptr, nullptr, &surface.swapchain); + assert(hr == S_OK); + + return surfaces.add(surface); + } + + handle device::create_buffer(const buffer_desc& desc) { + device_buffer buffer { + .size = desc.size, + }; + + DXGI_SAMPLE_DESC sample_desc { + .Count = 1U, + .Quality = 0U, + }; + D3D12_RESOURCE_DESC resource_desc { + .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER, + .Alignment = 0U, + .Width = buffer.size, + .Height = 1U, + .DepthOrArraySize = 1U, + .MipLevels = 1U, + .Format = DXGI_FORMAT_UNKNOWN, + .SampleDesc = sample_desc, + .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + .Flags = desc.usages, + }; + D3D12MA::ALLOCATION_DESC allocation_desc { + .HeapType = desc.heap_type, + }; + HRESULT hr = allocator->CreateResource(&allocation_desc, &resource_desc, desc.states, nullptr, &buffer.alloc, IID_PPV_ARGS(&buffer.resource)); + assert(hr == S_OK); + + if (desc.map) { + hr = buffer.resource->Map(0U, nullptr, &buffer.mapped_ptr); + assert(hr == S_OK); + } + + return buffers.add(buffer); + } + + handle device::create_texture(const texture_desc& desc) { + device_texture texture { + .width = desc.width, + .height = desc.height, + .depth = desc.depth, + .mips = desc.mips, + .format = desc.format, + }; + + DXGI_SAMPLE_DESC sample_desc { + .Count = 1U, + .Quality = 0U, + }; + D3D12_RESOURCE_DESC resource_desc { + .Dimension = desc.type, + .Alignment = 0U, + .Width = texture.width, + .Height = texture.height, + .DepthOrArraySize = static_cast(texture.depth), + .MipLevels = static_cast(texture.mips), + .Format = desc.format, + .SampleDesc = sample_desc, + .Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN, + .Flags = desc.usages, + }; + D3D12MA::ALLOCATION_DESC allocation_desc { + .HeapType = D3D12_HEAP_TYPE_DEFAULT, + }; + + HRESULT hr = allocator->CreateResource(&allocation_desc, &resource_desc, desc.states, nullptr, &texture.alloc, IID_PPV_ARGS(&texture.resource)); + assert(hr == S_OK); + + D3D12_PLACED_SUBRESOURCE_FOOTPRINT place_footprint; + UINT num_rows = 0U; + UINT64 total_bytes = 0U; + device->GetCopyableFootprints(&resource_desc, 0U, 1U, 0U, &place_footprint, &num_rows, &texture.row_pitch, &total_bytes); + + return textures.add(texture); + } + + void device::allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type) { + HRESULT hr = S_OK; + for (uint32_t index = 0U; index < count; index++) { + buffers[index].queue_type = type; + + auto list_type = queues[static_cast(type)].type; + hr = device->CreateCommandAllocator(list_type, IID_PPV_ARGS(&buffers[index].command_allocator)); + assert(hr == S_OK); + + hr = device->CreateCommandList(0U, list_type, buffers[index].command_allocator, nullptr, IID_PPV_ARGS(&buffers[index].dx12_command_buffer)); + assert(hr == S_OK); + + hr = buffers[index].dx12_command_buffer->Close(); + assert(hr == S_OK); + } + } + + uint32_t device::submit(command_buffer* buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); + const auto queue_type = buffers[0].queue_type; + auto& queue = queues[static_cast(buffers[0].queue_type)]; + ID3D12CommandList* lists[max_submitable_command_buffers] = { nullptr }; + + for (auto index{ 0U }; index < count; index++) { + assert(queue_type == buffers[index].queue_type); + + lists[index] = buffers[index].dx12_command_buffer; + } + + queue.dx_queue->ExecuteCommandLists(count, lists); + HRESULT hr = queue.dx_queue->Signal(fence, ++fence_value); + assert(hr == S_OK); + + for (uint32_t index = 0U; index < count; index++) { + auto& buffer = buffers[index]; + + hr = buffer.dx12_command_buffer->Reset(buffer.command_allocator, nullptr); + assert(hr == S_OK); + } + + return fence_value; + } + + void device::wait() { + for (auto& queue : queues) { + queue.dx_queue->Wait(fence, fence_value); + } + } + + void device::bindless_model::init() { + ID3D12Device* device = device::get_render_device().get_device(); + + D3D12_DESCRIPTOR_HEAP_DESC resources_descriptor_heap_desc { + .Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + .NumDescriptors = D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2, + .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + .NodeMask = 0U, + }; + + HRESULT hr = device->CreateDescriptorHeap(&resources_descriptor_heap_desc, IID_PPV_ARGS(&resources_heap)); + assert(hr == S_OK); + + D3D12_DESCRIPTOR_HEAP_DESC samplers_descriptor_heap_desc { + .Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + .NumDescriptors = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE, + .Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, + .NodeMask = 0U, + }; + hr = device->CreateDescriptorHeap(&samplers_descriptor_heap_desc, IID_PPV_ARGS(&samplers_heap)); + assert(hr == S_OK); + } +} 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 -#include +// =============== +// windows.h stuff +// =============== +#if defined(_WIN32) + #if defined(_M_AMD64) + #define _AMD64_ + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#endif // _WIN32 + + + +// ------------------- +// 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 + +#include +#include "simdjson.cpp" + +#define ENABLE_RENDERDOC 1 +#if ENABLE_RENDERDOC +#include + + + +#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 -#include "imgui.h" +#include "vec3.cpp" +#include "utils.cpp" +#include "window.cpp" +#include "camera.cpp" +#include "mesh.cpp" +#include "gltf.cpp" +#include "bvh.cpp" +#include "scene.cpp" -#ifdef ENABLE_RENDERDOC -#include -#endif -#include "compute-renderpass.hpp" -#include "primitive-renderpass.hpp" -#include "scene.hpp" -#include "vk-renderer.hpp" -#include "window.hpp" -#include "utils.hpp" - -#if defined(LINUX) -#include -#include -#elif defined(WINDOWS) -#include -#endif -struct VkVertex { - float x, y; - float u, v; - uint32_t color; - uint32_t padding[3]; -}; +// ------------------- +// GLOBALS +// ------------------- +LARGE_INTEGER freq; +std::vector> debug_texture_list; -void update_ui(scene& main_scene, float delta_time) { - ImGui::NewFrame(); +#if ENABLE_RENDERDOC +RENDERDOC_API_1_6_0 *rdoc_api = nullptr; +#endif // ENABLE_RENDERDOC - ImGui::SetNextWindowPos({0.f, 0.f}); - ImGui::SetNextWindowSize({0.f, 0.f}); - ImGui::Begin("Debug", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); +void watch_func() { + printf("change"); +} - ImGui::Text("frame per second %u\n", static_cast(1000.f / delta_time)); - ImGui::Text("frame time %f ms\n", delta_time); - ImGui::Text("frame count %u\n", main_scene.meta.sample_index); +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; + } - if (ImGui::Checkbox("depth of field", (bool*)&main_scene.meta.enable_dof)) { - main_scene.meta.sample_index = 1; + 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::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::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; + + ImGui::Text("%s time : %f ms\n", marker_names[index], static_cast(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& 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(&scene->meta.max_bounce), 5, 100); + ImGui::SliderInt("Min bounce", reinterpret_cast(&scene->meta.min_bounce), 1, 5); + + ImGui::Checkbox("DOF", reinterpret_cast(&scene->meta.enable_dof)); + ImGui::Checkbox("Debug BVH", reinterpret_cast(&scene->meta.debug_bvh)); + if (ImGui::SliderInt("Scale facotr", reinterpret_cast(&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); - - main_scene.scene_buffer->write(&main_scene.meta, renderer.frame_index() * sizeof(main_scene.meta), sizeof(main_scene.meta)); - - - // ImDrawData* draw_data = ImGui::GetDrawData(); - - // ui_pass->set_viewport(0.f, 0.f, (float)draw_data->DisplaySize.x, (float)draw_data->DisplaySize.y); - - // auto previous_size = ui_primitives.size(); - // auto commands_count = 0U; - - // 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(); - // } - - // if (ui_primitives.size() < commands_count) { - // ui_primitives.resize(commands_count); - - // 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); - // } - // } - - // 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), - // }; - - // 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); - - // for (auto& primitive : ui_primitives) { - // primitive->set_constant(0, ui_vertex_buffer); - // } - // } - - // 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); - - // for (auto& primitive : ui_primitives) { - // primitive->set_index_buffer(ui_index_buffer); - // } - // } - - // off_t vertex_buffer_offset = 0; - // off_t index_buffer_offset = 0; - // std::vector 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]); - // } - - // 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)); - - // 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); - - // 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 - // ); - - // 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++; - // } - - // vertex_buffer_offset += vertex_buffer.Size; - // index_buffer_offset += index_buffer.Size; - // } - - // ui_pass->set_color_attachment(0, renderer.back_buffer()); - - renderer.render(); - - main_scene.meta.sample_index++; -} +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); + + 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"); + + } + 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; -#if defined(ENABLE_RENDERDOC) -RENDERDOC_API_1_1_2 enable_renderdoc() { - RENDERDOC_API_1_1_2 *rdoc_api = nullptr; + rdoc_api->MaskOverlayBits(eRENDERDOC_Overlay_All, eRENDERDOC_Overlay_All); -#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); + RENDERDOC_InputButton key = RENDERDOC_InputButton::eRENDERDOC_Key_F10; + rdoc_api->SetCaptureKeys(&key, 1U); + } } #endif - return rdoc_api; -} + 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 float v_fov = 90.f; + const float aperture = 0.1f; + const float focus_distance = 10.f; + +#if VK + auto& device = vkdevice::get(); +#else + auto& device = dx12::device::get(); +#endif + device.init(); + + scene main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), window_width, window_height); + + handle 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); + + + // ============== + // create buffers + // ============== + const handle 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); + + const handle 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 + }); -int main() { + const handle 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 + }); + + device_buffer vertex_buffer = device.get_buffer(vertex_buffer_handle); + device_buffer index_buffer = device.get_buffer(index_buffer_handle); + + + // ================ + // create pipelines + // ================ +#if VK + size_t code_size = 0U; + uint8_t* code = read_file("shaders/test.comp.spv", &code_size); + handle compute = device.create_compute_pipeline({ + .cs_code = code, + .cs_code_size = code_size, + }); + + size_t rt_code_size = 0U; + uint8_t* rt_code = read_file("shaders/compute.comp.spv", &rt_code_size); + handle 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 tonemapping = device.create_compute_pipeline({ + .cs_code = tonemapping_code, + .cs_code_size = tonemapping_code_size, + }); -#if defined(ENABLE_RENDERDOC) - auto* rdoc_api = enable_renderdoc(); + std::array 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 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 + }); + + size_t transmittance_lut_code_size = 0U; + u8* transmittance_lut_code = read_file("shaders/transmittance_lut.comp.spv", &transmittance_lut_code_size); + handle transmittance_lut_compute = device.create_compute_pipeline({ + .cs_code = transmittance_lut_code, + .cs_code_size = transmittance_lut_code_size, + .name = "transmittance_lut_comp", + }); #endif - const float aspect_ratio = 16.0 / 9.0; - const auto width = 400; - auto height = (uint32_t)(width / aspect_ratio); + // ============== + // 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(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(image_width) * image_height * 4U; + auto* addr = static_cast(static_cast(staging_buffer.mapped_ptr) + buffer_offset); + memcpy(addr, data, size); + + u8 *pixels = nullptr; + int atlas_width; + int atlas_height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); + + off_t ui_offset = 2L * buffer_offset; + size = static_cast(atlas_width) * atlas_height * 4U; + addr = static_cast(static_cast(staging_buffer.mapped_ptr) + ui_offset); + memcpy(addr, pixels, size); + + + // ============== + // create texures + // ============== + const handle gpu_texture_handle = device.create_texture({ + .width = static_cast(image_width), + .height = static_cast(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 + }); - window wnd { width, height }; + const handle second_texture = device.create_texture({ + .width = static_cast(image_width), + .height = static_cast(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 + }); - 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(); + const handle output_texture_handle = device.create_texture({ + .width = static_cast(image_width), + .height = static_cast(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 + }); - 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 handle ui_texture_handle = device.create_texture({ + .width = static_cast(atlas_width), + .height = static_cast(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" + }); - vkrenderer renderer { wnd }; + const handle acc_handle = device.create_texture({ + .width = static_cast(window_width), + .height = static_cast(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" + }); - 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); - - 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); - - raytracing_pass->set_pipeline("compute"); + const handle result_handle = device.create_texture({ + .width = static_cast(window_width), + .height = static_cast(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" }); - 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); + const handle transmittance_lut_handle = device.create_texture({ + .width = static_cast(1024), + .height = static_cast(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", + }); - // 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); +#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 - // renderer.update_image(ui_texture, pixels); - // auto ui_texture_sampler = renderer.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + 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); - // Buffer* ui_vertex_buffer = nullptr; - // Buffer* ui_index_buffer = nullptr; + io.Fonts->SetTexID(reinterpret_cast(static_cast(ui_texture.get_sampled_index()))); - // const char* ui_shader_name = "ui"; - // std::vector 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(); - auto can_render = true; +#if VK + std::array graphics_command_buffers; + device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), QueueType::GRAPHICS, "graphics_cmd_buf"); +#else + std::array graphics_command_buffers; + device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), dx12::QueueType::GRAPHICS); +#endif - while (wnd.isOpen) { - end = std::chrono::high_resolution_clock::now(); - delta_time = std::chrono::duration(end - start).count(); + // ============= + // API test code + // ============= + RD_START_CAPTURE; + graphics_command_buffers[0].start(); - start = std::chrono::high_resolution_clock::now(); +#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 - io.DeltaTime = delta_time; + 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); + + + { + 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(); + 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(); + + graphics_command_buffers[0].dispatch({ + .pipeline = compute, + .group_size = { .vec = { static_cast(image_width), static_cast(image_height), 1U }}, + .local_group_size = { .vec = { 8U, 8U, 1U }}, + }); + } - watcher::pull_changes(); + { + struct params { + u32 lut_id; + u32 width; + u32 height; + u32 pad; + } *params = draws_uniform_buffer.allocate(); + params->lut_id = transmittance_lut.get_storage_index(); + params->width = transmittance_lut.width; + params->height = transmittance_lut.height; + + graphics_command_buffers[0].dispatch({ + .pipeline = transmittance_lut_compute, + .group_size = { .vec = { 1024U, 1024U, 1U }}, + .local_group_size = { .vec { 8U, 8U, 1U }}, + }); + } + } - wnd.poll_events(); + 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 - for (auto &event : wnd.events) { - switch (event.type) { - case EVENT_TYPES::RESIZE: { - main_scene.meta.width = event.width; - main_scene.meta.height = event.height; - - io.DisplaySize.x = (float)event.width; - io.DisplaySize.y = (float)event.height; - - 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); - - 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); - } + graphics_command_buffers[0].stop(); - main_scene.meta.sample_index = 1; + device.submit(graphics_command_buffers.data(), 1); + device.wait(); - break; - } - 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; } + RD_END_CAPTURE; - vec3 move_vec{}; + END_MARKER(STARTUP); - switch (event.key) { - case KEYS::W: { - move_vec = main_scene.meta.cam.forward * move_speed; - break; - } + watch_file("../shaders/compute.comp", watch_func); - 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; +#if VK + std::array, 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(); + + pull_changes(); + + uint32_t virtual_frame_index = frame_count % virtual_frames_count; + auto command_buffer = graphics_command_buffers[2U + virtual_frame_index]; + + main_scene.meta.sample_index++; + + // + // 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(event.data.position.x), static_cast(event.data.position.y)); + } else if (event.type == EVENT_TYPE::MOUSE_WHEEL) { + io.AddMouseWheelEvent(static_cast(event.data.delta.x), static_cast(event.data.delta.y)); } - default: - break; + + 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 + } } - main_scene.meta.cam.move(move_vec); + 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--; + } + } - if (!move_vec.near_zero()) { main_scene.meta.sample_index = 1; } + } + } + } - break; + if (!dir.is_zero()) { + main_scene.meta.cam.move(dir.normalize() * delta * static_cast(speed)); + main_scene.meta.sample_index = 1U; + } + if (rot != 0.f) { + main_scene.meta.cam.rotate_y(rot * delta * static_cast(speed)); + main_scene.meta.sample_index = 1U; + } + + ui(&main_scene, delta); + + ImGuiMouseCursor cursor_style = ImGui::GetMouseCursor(); + window::set_cursor(static_cast(cursor_style)); + + // ================== + // 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]; + + size_t vertex_bytes_size = sizeof(ImDrawVert) * cmd_list->VtxBuffer.size(); + u8* vtx_ptr = static_cast(vertex_buffer.mapped_ptr) + vertex_offset; + memcpy(vtx_ptr, cmd_list->VtxBuffer.Data, vertex_bytes_size); + vertex_offset += static_cast(vertex_bytes_size); + + size_t index_bytes_size = sizeof(ImDrawIdx) * cmd_list->IdxBuffer.size(); + memcpy(static_cast(index_buffer.mapped_ptr) + index_offset, cmd_list->IdxBuffer.Data, index_bytes_size); + index_offset += static_cast(index_bytes_size); } - case EVENT_TYPES::BUTTON_PRESS: { - if (event.button == BUTTONS::LEFT) { io.MouseDown[0] = true; } - if (event.button == BUTTONS::RIGHT) { io.MouseDown[1] = true; } - break; + } + + // ====================== + // global uniforms update + // ====================== + { + metadata * const globals = vkdevice::get().get_bindingmodel().get_uniform_buffer(UniformTypes::GLOBAL).allocate(); + memcpy(static_cast(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::BUTTON_RELEASE: { - if (event.button == BUTTONS::LEFT) { io.MouseDown[0] = false; } - if (event.button == BUTTONS::RIGHT) { io.MouseDown[1] = false; } - 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(); + 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, } }, + }); } - case EVENT_TYPES::MOUSE_MOVE: { - io.MousePos = ImVec2{(float)event.x, (float)event.y}; - break; + + { + struct params { + u32 output_id; + u32 accumulation_id; + } *uniforms = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW).allocate(); + // 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, } }, + }); } - default: - break; + } + + 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(draw_data->DisplayPos.x), + .y = static_cast(draw_data->DisplayPos.y), + .width = static_cast(draw_data->DisplaySize.x), + .height = static_cast(draw_data->DisplaySize.y), + }, + .color_attachments = color_attachment, + }); + + 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]; + + 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_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(&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, + }); } + vertex_offset += cmd_list->VtxBuffer.size(); + index_offset += cmd_list->IdxBuffer.size(); } - wnd.events.clear(); + 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(); - raytracing_pass->set_ouput_texture(output_texture); - raytracing_pass->set_constant(60, accumulation_texture); + LARGE_INTEGER end_qpc; + QueryPerformanceCounter(&end_qpc); + LONGLONG diff_qpc = end_qpc.QuadPart - start_qpc.QuadPart; + delta = static_cast(diff_qpc * 1000LL) / freq.QuadPart; + frame_count++; - renderer.begin_frame(); + // RD_END_CAPTURE; + } - // update_ui(main_scene, delta_time); + device.wait(); - if (can_render) { - render(main_scene, renderer); + main_scene.deinit(); - std::swap(output_texture, accumulation_texture); - } + device.destroy_surface(surface_handle); - renderer.finish_frame(); + device.destroy_pipeline(compute); + device.destroy_pipeline(graphics); + device.destroy_pipeline(raytracing); + device.destroy_pipeline(tonemapping); - frame_count++; - } + 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(); - //------------------------- - // 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]); - // } - - // 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 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 -#include - -#include - -#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 vkapi::create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count) { - std::vector 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& 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 vkapi::create_fences(size_t fences_count) const { - std::vector 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 vkapi::create_semaphores(size_t semaphores_count) const { - std::vector 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& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout) { - std::vector attachments_description = {}; - std::vector 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& formats, VkExtent2D size) { - VkFramebuffer framebuffer_handle; - - std::vector 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 vkapi::create_framebuffers(VkRenderPass render_pass, std::vector& formats, VkExtent2D size, uint32_t framebuffer_count) { - std::vector 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& 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(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& dynamic_states) const { - pipeline pipeline{ - .bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS - }; - - std::vector 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 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(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 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 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(swapchain.image_count); - auto vk_images = std::vector(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& handles, VkDescriptorType type) { - std::vector descriptor_images_info{ images.size() }; - std::vector 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& handles) { - std::vector descriptor_images_info{ samplers.size() }; - std::vector 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& 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/src/vk-command-buffer.cpp b/src/vk-command-buffer.cpp new file mode 100644 index 0000000..26c2d03 --- /dev/null +++ b/src/vk-command-buffer.cpp @@ -0,0 +1,216 @@ +#include "vk-command-buffer.hpp" + +uintptr_t constants[3U] = { 0U }; + +void command_buffer::start() const { + VkCommandBufferBeginInfo begin_info{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + .pInheritanceInfo = nullptr + }; + + VKCHECK(vkBeginCommandBuffer(vk_command_buffer, &begin_info)); + + 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.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.global_layout, 0, 1U, &bindless.global_set, 0U, nullptr); + } +} + +void command_buffer::stop() const { + VKCHECK(vkEndCommandBuffer(vk_command_buffer)); +} + +void command_buffer::barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const { + auto& texture = vkdevice::get().get_texture(texture_handle); + + VkImageSubresourceRange subresource_range{ + .aspectMask = texture.aspects, + .baseMipLevel = 0U, + .levelCount = 1U, + .baseArrayLayer = 0U, + .layerCount = 1U, + }; + + VkImageMemoryBarrier2 image_barrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = texture.stage, + .srcAccessMask = texture.access, + .dstStageMask = stage, + .dstAccessMask = access, + .oldLayout = texture.layout, + .newLayout = layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture.vk_image, + .subresourceRange = subresource_range, + }; + + VkDependencyInfo dependency_info{ + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pNext = nullptr, + .dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT, + .memoryBarrierCount = 0U, + .pMemoryBarriers = nullptr, + .bufferMemoryBarrierCount = 0U, + .pBufferMemoryBarriers = nullptr, + .imageMemoryBarrierCount = 1U, + .pImageMemoryBarriers = &image_barrier, + }; + vkCmdPipelineBarrier2(vk_command_buffer, &dependency_info); + + texture.layout = layout; + texture.stage = stage; + texture.access = access; +} + +void command_buffer::copy(handle buffer_handle, ::handle texture_handle, uint64_t offset) const { + auto& device = vkdevice::get(); + const auto& buffer = device.get_buffer(buffer_handle); + const auto& texture = device.get_texture(texture_handle); + + VkImageSubresourceLayers image_subresource_layers{ + .aspectMask = texture.aspects, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + VkBufferImageCopy buffer_to_image_copy{ + .bufferOffset = offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = image_subresource_layers, + .imageOffset = { .x = 0, .y = 0, .z = 0 }, + .imageExtent = { + .width = texture.width, + .height = texture.height, + .depth = texture.depth, + }, + }; + + vkCmdCopyBufferToImage(vk_command_buffer, buffer.vk_buffer, texture.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy); +} + +void graphics_command_buffer::dispatch(const dispatch_params& params) const { + 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; + vkCmdDispatch(vk_command_buffer, x, y, z); +} + +void graphics_command_buffer::begin_renderpass(const renderpass_params& params) const { + std::vector attachments_info(params.color_attachments.size()); + + for (auto index{ 0U }; index < params.color_attachments.size(); index++) { + auto& attachment_info = attachments_info[index]; + auto& attachment = vkdevice::get().get_texture(params.color_attachments[index]); + + attachment_info.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + attachment_info.pNext = nullptr; + attachment_info.imageView = attachment.whole_view; + attachment_info.imageLayout = attachment.layout; + attachment_info.resolveMode = VK_RESOLVE_MODE_NONE; + attachment_info.resolveImageView = nullptr; + attachment_info.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment_info.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment_info.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment_info.clearValue = VkClearValue{ + .color = { + .float32 = { 0.f, 0.f, 0.f, 0.f }, + }, + }; + } + + VkRect2D scissor{ + .offset{ + .x = params.render_area.x, + .y = params.render_area.x, + }, + .extent{ + .width = params.render_area.width, + .height = params.render_area.height, + }, + }; + VkViewport viewport{ + .x = static_cast(params.render_area.x), + .y = static_cast(params.render_area.y), + .width = static_cast(params.render_area.width), + .height = static_cast(params.render_area.height), + .minDepth = 0.f, + .maxDepth = 1.f, + }; + VkRenderingInfo rendering_info{ + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .pNext = nullptr, + .flags = 0U, + .renderArea = scissor, + .layerCount = 1U, + .viewMask = 0U, + .colorAttachmentCount = static_cast(attachments_info.size()), + .pColorAttachments = attachments_info.data(), + .pDepthAttachment = nullptr, + .pStencilAttachment = nullptr, + }; + 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); +} + +void graphics_command_buffer::draw(const draw_params& params) const { + auto& device = vkdevice::get(); + const auto& pipeline = device.get_pipeline(params.pipeline); + + const auto& bindless = device.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); + + 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(); + const auto& pipeline = device.get_pipeline(params.pipeline); + + const auto& bindless = device.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); + + const auto& index_buffer = device.get_buffer(params.index_buffer); + vkCmdBindIndexBuffer(vk_command_buffer, index_buffer.vk_buffer, 0U, VK_INDEX_TYPE_UINT16); + vkCmdDrawIndexed(vk_command_buffer, params.vertex_count, params.instance_count, params.index_offset, static_cast(params.vertex_offset), 0U); +} + +void graphics_command_buffer::end_renderpass() const { + vkCmdEndRendering(vk_command_buffer); +} 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 -#include -#include -#include - -#define VMA_IMPLEMENTATION -#include - -#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 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 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 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 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/src/vk-device.cpp b/src/vk-device.cpp new file mode 100644 index 0000000..6fa3533 --- /dev/null +++ b/src/vk-device.cpp @@ -0,0 +1,1311 @@ +#include "vk-device.hpp" + +#define VMA_IMPLEMENTATION +#include + +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(code), + }; + + VKCHECK(vkCreateShaderModule(device, &create_info, nullptr, &shader_module)); + return shader_module; +} + + +vkdevice vkdevice::render_device = vkdevice(); + +void vkdevice::init() { + queues[static_cast(QueueType::GRAPHICS)] = { + .usages = VK_QUEUE_GRAPHICS_BIT | + VK_QUEUE_COMPUTE_BIT | + VK_QUEUE_TRANSFER_BIT, + }; + queues[static_cast(QueueType::ASYNC_COMPUTE)] = { + .usages = VK_QUEUE_COMPUTE_BIT, + }; + queues[static_cast(QueueType::TRANSFER)] = { + .usages = VK_QUEUE_TRANSFER_BIT, + }; + + load_vulkan(); + + create_instance(); + +#ifdef _DEBUG + create_debug_layer_callback(); +#endif // _DEBUG + + create_device(); + + create_memory_allocator(); + + bindless.init(); + + auto semaphore = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_TIMELINE, + }, "timeline_semaphore"); + timeline_semaphore = get_semaphore(semaphore); +} + +void vkdevice::deinit() { + vkDeviceWaitIdle(device); + + bindless.deinit(); + + vmaDestroyAllocator(gpu_allocator); + + for (auto& queue : queues) { + vkDestroyCommandPool(device, queue.command_pool, nullptr); + } + + vkDestroySemaphore(device, timeline_semaphore.vk_semaphore, nullptr); + + vkDestroyDevice(device, nullptr); + +#ifdef _DEBUG + vkDestroyDebugUtilsMessengerEXT(instance, debug_messenger, nullptr); +#endif // _DEBUG + + vkDestroyInstance(instance, nullptr); +} + + +void vkdevice::wait() { vkDeviceWaitIdle(device); }; + +handle 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(desc).usages |= VK_IMAGE_USAGE_SAMPLED_BIT; + device_texture.init(desc); + + return textures.add(device_texture); +} + +handle vkdevice::create_sampler(const sampler_desc& desc) { + device_sampler device_sampler; + device_sampler.init(desc); + + return samplers.add(device_sampler); +} + +handle vkdevice::create_buffer(const buffer_desc& desc) { + device_buffer device_buffer{ + .size = desc.size, + .usages = desc.usages, + .name = desc.name, + }; + + VkBufferCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .size = desc.size, + .usage = desc.usages, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; + + VmaAllocatorCreateFlags alloc_create_flags = + desc.memory_usage != VMA_MEMORY_USAGE_GPU_ONLY ? VMA_ALLOCATION_CREATE_MAPPED_BIT : 0U; + + VmaAllocationCreateInfo alloc_create_info{ + .flags = alloc_create_flags, + .usage = static_cast(desc.memory_usage), + .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)); + vmaSetAllocationName(render_device.get_allocator(), device_buffer.alloc, desc.name); + + if ((desc.usages & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0U) { + VkBufferDeviceAddressInfo address_info { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .pNext = nullptr, + .buffer = device_buffer.vk_buffer, + }; + device_buffer.device_address = vkGetBufferDeviceAddress(device, &address_info); + } + + device_buffer.mapped_ptr = alloc_info.pMappedData; + + return buffers.add(device_buffer); +} + +handle vkdevice::create_graphics_pipeline(const graphics_pipeline_desc& desc) { + device_pipeline device_pipeline{ + }; + + VkPipelineShaderStageCreateInfo shader_stages_create_info[2U]{ { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = create_shader_module(device, desc.vs_code, desc.vs_code_size), + .pName = "main", + .pSpecializationInfo = nullptr, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = create_shader_module(device, desc.fs_code, desc.fs_code_size), + .pName = "main", + .pSpecializationInfo = nullptr, + }, + }; + + VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + }; + + VkPipelineInputAssemblyStateCreateInfo input_assembly_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + + VkPipelineViewportStateCreateInfo viewport_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .viewportCount = 1U, + .pViewports = nullptr, + .scissorCount = 1U, + .pScissors = nullptr, + }; + + VkPipelineRasterizationStateCreateInfo rasterization_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .lineWidth = 1.f, + }; + + VkPipelineMultisampleStateCreateInfo multisample_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 1.f, + }; + + VkPipelineColorBlendAttachmentState color_attachment_state{ + .blendEnable = VK_TRUE, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + }; + + VkPipelineColorBlendStateCreateInfo color_blend_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .attachmentCount = 1, + .pAttachments = &color_attachment_state, + }; + + VkDynamicState dynamic_states[]{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + + VkPipelineDynamicStateCreateInfo dynamic_state_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .dynamicStateCount = sizeof(dynamic_states) / sizeof(VkDynamicState), + .pDynamicStates = dynamic_states, + }; + + VkPipelineRenderingCreateInfo pipeline_rendering_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = nullptr, + .viewMask = 0U, + .colorAttachmentCount = static_cast(desc.color_attachments_format.size()), + .pColorAttachmentFormats = desc.color_attachments_format.data(), + .depthAttachmentFormat = VK_FORMAT_UNDEFINED, + .stencilAttachmentFormat = VK_FORMAT_UNDEFINED, + }; + + VkGraphicsPipelineCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &pipeline_rendering_create_info, + .flags = 0U, + .stageCount = sizeof(shader_stages_create_info) / sizeof(VkPipelineShaderStageCreateInfo), + .pStages = shader_stages_create_info, + .pVertexInputState = &vertex_input_state_create_info, + .pInputAssemblyState = &input_assembly_create_info, + .pTessellationState = nullptr, + .pViewportState = &viewport_state_create_info, + .pRasterizationState = &rasterization_state_create_info, + .pMultisampleState = &multisample_state_create_info, + .pDepthStencilState = nullptr, + .pColorBlendState = &color_blend_state_create_info, + .pDynamicState = &dynamic_state_create_info, + .layout = bindless.global_layout, + .renderPass = nullptr, + .subpass = 0U, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; + + device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS; + VKCHECK(vkCreateGraphicsPipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); + + for(auto& stage_create_info : shader_stages_create_info) { + vkDestroyShaderModule(device, stage_create_info.module, nullptr); + } + + if (desc.name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_PIPELINE, + .objectHandle = reinterpret_cast(device_pipeline.vk_pipeline), + .pObjectName = desc.name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + + return pipelines.add(device_pipeline); +} + +handle vkdevice::create_compute_pipeline(const compute_pipeline_desc& desc) { + device_pipeline device_pipeline{ + }; + + VkPipelineShaderStageCreateInfo stage_create_info{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = create_shader_module(device, desc.cs_code, desc.cs_code_size), + .pName = "main", + .pSpecializationInfo = nullptr, + }; + + VkComputePipelineCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .stage = stage_create_info, + .layout = bindless.global_layout, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; + + device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; + VKCHECK(vkCreateComputePipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); + + vkDestroyShaderModule(device, stage_create_info.module, nullptr); + + if (desc.name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_PIPELINE, + .objectHandle = reinterpret_cast(device_pipeline.vk_pipeline), + .pObjectName = desc.name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + + return pipelines.add(device_pipeline); +} + +handle vkdevice::create_surface(const surface_desc& desc) { + device_surface device_surface { + }; + + { + VkWin32SurfaceCreateInfoKHR create_info{ + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0U, + .hinstance = GetModuleHandle(nullptr), + .hwnd = desc.window_handle, + }; + + VKCHECK(vkCreateWin32SurfaceKHR(instance, &create_info, nullptr, &device_surface.vk_surface)); + } + + create_swapchain(desc, device_surface); + + assert(surface_desc::max_image_count >= device_surface.image_count); + + for (uint32_t index = 0u; index < device_surface.image_count; index++) { + device_surface.acquire_semaphores[index] = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_BINARY, + }, "acquire_semaphore"); + device_surface.submit_semaphores[index] = create_semaphore({ + .type = VK_SEMAPHORE_TYPE_BINARY, + }, "submit_semaphore"); + } + + return surfaces.add(device_surface); +} + +handle vkdevice::create_semaphore(const semaphore_desc& desc, const char* name) { + device_semaphore semaphore { + .value = desc.initial_value, + }; + VkSemaphoreTypeCreateInfo semaphore_type_create_info{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .pNext = nullptr, + .semaphoreType = desc.type, + .initialValue = desc.initial_value, + }; + + VkSemaphoreCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &semaphore_type_create_info, + .flags = 0U, + }; + + VKCHECK(vkCreateSemaphore(device, &create_info, nullptr, &semaphore.vk_semaphore)); + + if (name) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_SEMAPHORE, + .objectHandle = reinterpret_cast(semaphore.vk_semaphore), + .pObjectName = name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + return semaphores.add(semaphore); +} + +void vkdevice::destroy_texture(handle handle) { + auto& texture = get_texture(handle); + + texture.release(); + textures.remove(handle); +} + +void vkdevice::destroy_buffer(handle handle) { + const auto& buffer = get_buffer(handle); + + vmaDestroyBuffer(gpu_allocator, buffer.vk_buffer, buffer.alloc); + buffers.remove(handle); +} + +void vkdevice::destroy_pipeline(handle handle) { + const auto& pipeline = vkdevice::get_pipeline(handle); + + vkDestroyPipeline(device, pipeline.vk_pipeline, nullptr); + pipelines.remove(handle); +} + +void vkdevice::destroy_semaphore(handle handle) { + auto& semaphore = vkdevice::get_semaphore(handle); + + vkDestroySemaphore(device, semaphore.vk_semaphore, nullptr); + semaphores.remove(handle); +} + +void vkdevice::destroy_surface(handle handle) { + auto& surface = vkdevice::get_surface(handle); + + for (auto texture_index{0U}; texture_index < surface.image_count; texture_index++) { + auto texture_handle = surface.swapchain_images[texture_index]; + destroy_texture(texture_handle); + } + + for (uint32_t index = 0u; index < surface.image_count; index++) { + destroy_semaphore(surface.acquire_semaphores[index]); + destroy_semaphore(surface.submit_semaphores[index]); + } + + vkDestroySwapchainKHR(device, surface.vk_swapchain, nullptr); + + vkDestroySurfaceKHR(instance, surface.vk_surface, nullptr); +} + +// uint64_t vkdevice::submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle) { +// assert((max_submitable_command_buffers - buffers.size()) >= 0); +// const auto queue_type = buffers[0].queue_type; +// +// VkCommandBufferSubmitInfo command_buffers_info[buffers.size()]; +// +// for (auto index{ 0U }; index < buffers.size(); index++) { +// assert(queue_type == buffers[index].queue_type); +// +// auto& command_buffer_info = command_buffers_info[index]; +// command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; +// command_buffer_info.pNext = nullptr; +// command_buffer_info.commandBuffer = buffers[index].vk_command_buffer; +// command_buffer_info.deviceMask = 0U; +// } +// +// VkSemaphoreSubmitInfo wait_semaphore_info{ +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, +// .deviceIndex = 0U, +// }; +// +// VkSemaphoreSubmitInfo signal_semaphore_infos[2U]; +// +// VkSubmitInfo2 submit_info{ +// .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, +// .pNext = nullptr, +// .flags = 0U, +// .waitSemaphoreInfoCount = 0U, +// .commandBufferInfoCount = static_cast(buffers.size()), +// .pCommandBufferInfos = command_buffers_info, +// .pSignalSemaphoreInfos = signal_semaphore_infos, +// }; +// +// if (wait_handle.is_valid()) { +// const auto& wait = vkdevice::get_render_device().get_semaphore(wait_handle); +// wait_semaphore_info.semaphore = wait.vk_semaphore; +// wait_semaphore_info.value = wait.value; +// submit_info.waitSemaphoreInfoCount++; +// submit_info.pWaitSemaphoreInfos = &wait_semaphore_info; +// } +// +// if (signal_handle.is_valid()) { +// auto& signal = vkdevice::get_render_device().get_semaphore(signal_handle); +// signal_semaphore_infos[0U] = { +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .semaphore = signal.vk_semaphore, +// .value = signal.value, +// .stageMask = VK_PIPELINE_STAGE_2_NONE, +// .deviceIndex = 0U, +// }; +// submit_info.signalSemaphoreInfoCount++; +// } +// +// uint64_t ret = -1; +// +// if (fence_handle.is_valid()) { +// auto& fence = vkdevice::get_render_device().get_semaphore(fence_handle); +// auto fence_index = submit_info.signalSemaphoreInfoCount; +// signal_semaphore_infos[fence_index] = { +// .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, +// .pNext = nullptr, +// .semaphore = fence.vk_semaphore, +// .value = ++fence.value, +// .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, +// .deviceIndex = 0U, +// }; +// ret = fence.value; +// } +// +// VKCHECK(vkQueueSubmit2(queues[static_cast(queue_type)].vk_queue, 1, &submit_info, nullptr)); +// +// return ret; +// } + +uint64_t vkdevice::submit(command_buffer* cmd_buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); + 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 == 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 = cmd_buffers[index].vk_command_buffer; + command_buffer_info.deviceMask = 0U; + } + + VkSubmitInfo2 submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0U, + .waitSemaphoreInfoCount = 0U, + .pWaitSemaphoreInfos = nullptr, + .commandBufferInfoCount = count, + .pCommandBufferInfos = command_buffers_info, + }; + + auto& fence = timeline_semaphore; + VkSemaphoreSubmitInfo signal_semaphore_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = fence.vk_semaphore, + .value = ++fence.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + }; + submit_info.signalSemaphoreInfoCount = sizeof(signal_semaphore_infos) / sizeof(signal_semaphore_infos[0U]); + submit_info.pSignalSemaphoreInfos = signal_semaphore_infos; + + VKCHECK(vkQueueSubmit2(queues[static_cast(queue_type)].vk_queue, 1, &submit_info, nullptr)); + + return fence.value; +} + +uint64_t vkdevice::submit_before_present(handle surface_handle, command_buffer* cmd_buffers, uint32_t count) { + assert((max_submitable_command_buffers - count) >= 0); + const QueueType queue_type = cmd_buffers[0].queue_type; + + // VkCommandBufferSubmitInfo command_buffers_info[count]; + VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; + + 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 = cmd_buffers[index].vk_command_buffer; + command_buffer_info.deviceMask = 0U; + } + + 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, + .semaphore = wait.vk_semaphore, + .value = wait.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }; + + VkSubmitInfo2 submit_info{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .pNext = nullptr, + .flags = 0U, + .waitSemaphoreInfoCount = 1U, + .pWaitSemaphoreInfos = &wait_semaphore_info, + .commandBufferInfoCount = count, + .pCommandBufferInfos = command_buffers_info, + }; + + auto& fence = timeline_semaphore; + auto& signal = get_semaphore(surface.submit_semaphores[surface.frame_index]); + VkSemaphoreSubmitInfo signal_semaphore_infos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = fence.vk_semaphore, + .value = ++fence.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .pNext = nullptr, + .semaphore = signal.vk_semaphore, + .value = signal.value, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + .deviceIndex = 0U, + }, + }; + submit_info.signalSemaphoreInfoCount = sizeof(signal_semaphore_infos) / sizeof(signal_semaphore_infos[0U]); + submit_info.pSignalSemaphoreInfos = signal_semaphore_infos; + + VKCHECK(vkQueueSubmit2(queues[static_cast(queue_type)].vk_queue, 1, &submit_info, nullptr)); + + return fence.value; +} + +void vkdevice::present(handle surface_handle) { + auto& surface = render_device.get_surface(surface_handle); + VkResult result; + VkPresentInfoKHR present_info{ + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = nullptr, + .swapchainCount = 1U, + .pSwapchains = &surface.vk_swapchain, + .pImageIndices = &surface.image_index, + .pResults = &result, + }; + + const auto& semaphore = get_semaphore(surface.submit_semaphores[surface.frame_index]); + present_info.waitSemaphoreCount = 1U; + present_info.pWaitSemaphores = &semaphore.vk_semaphore; + + VKCHECK(vkQueuePresentKHR(queues[static_cast(QueueType::GRAPHICS)].vk_queue, &present_info)); + + VKCHECK(result); + surface.frame_index = (surface.frame_index + 1) % surface.image_count; +} + +// private +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(type)]; + VkCommandBuffer command_buffers[max_allocable_command_buffers]; + + VkCommandBufferAllocateInfo allocate_info{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = nullptr, + .commandPool = queue.command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = static_cast(count), + }; + + VKCHECK(vkAllocateCommandBuffers(device, &allocate_info, command_buffers)); + + 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{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_COMMAND_BUFFER, + .objectHandle = reinterpret_cast(command_buffers[index]), + .pObjectName = name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + } +} + +void vkdevice::create_swapchain(const surface_desc& desc, device_surface& surface) { + VkSurfaceKHR vk_surface = surface.vk_surface; + + auto& queue = queues[static_cast(QueueType::GRAPHICS)]; + + { + VkBool32 supported = VK_FALSE; + VKCHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue.index, vk_surface, &supported)); + + assert(supported); + } + + VkSurfaceCapabilitiesKHR surface_capabilities; + VKCHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, vk_surface, &surface_capabilities)); + + VkExtent2D extent = surface_capabilities.currentExtent; + if (extent.width < surface_capabilities.minImageExtent.width) { + extent.width = surface_capabilities.minImageExtent.width; + } else if (extent.width > surface_capabilities.maxImageExtent.width) { + extent.width = surface_capabilities.maxImageExtent.width; + } + + if (extent.height < surface_capabilities.minImageExtent.height) { + extent.height = surface_capabilities.minImageExtent.height; + } else if (extent.height > surface_capabilities.maxImageExtent.height) { + extent.height = surface_capabilities.maxImageExtent.height; + } + + { + auto supported = false; + auto supported_formats_count = 0U; + VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, vk_surface, &supported_formats_count, nullptr)); + + std::vector supported_formats{ supported_formats_count }; + VKCHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, vk_surface, &supported_formats_count, supported_formats.data())); + + for (auto& surface_format : supported_formats) { + if (surface_format.format == desc.surface_format.format && + surface_format.colorSpace == desc.surface_format.colorSpace) { + supported = true; + break; + } + } + + assert(supported); + } + + { + auto supported = false; + auto supported_present_modes_count = 0U; + VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, vk_surface, &supported_present_modes_count, nullptr)); + + std::vector supported_present_modes{ supported_present_modes_count }; + VKCHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, vk_surface, &supported_present_modes_count, supported_present_modes.data())); + + for (auto& present_mode : supported_present_modes) { + if (present_mode == desc.present_mode) { + supported = true; + break; + } + } + + assert(supported); + } + + assert(desc.image_count >= surface_capabilities.minImageCount); + assert(desc.image_count <= surface_capabilities.maxImageCount); + + VkSwapchainCreateInfoKHR create_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0U, + .surface = vk_surface, + .minImageCount = desc.image_count, + .imageFormat = desc.surface_format.format, + .imageColorSpace = desc.surface_format.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1U, + .imageUsage = desc.usages, + .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0U, + .pQueueFamilyIndices = nullptr, + .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = desc.present_mode, + .clipped = VK_TRUE, + .oldSwapchain = nullptr, + }; + + VKCHECK(vkCreateSwapchainKHR(device, &create_info, nullptr, &surface.vk_swapchain)); + + surface.surface_format = desc.surface_format; + + vkGetSwapchainImagesKHR(device, surface.vk_swapchain, &surface.image_count, nullptr); + assert(surface.image_count <= surface_desc::max_image_count); + + std::vector images {surface.image_count}; + vkGetSwapchainImagesKHR(device, surface.vk_swapchain, &surface.image_count, images.data()); + + for (auto index {0U}; index < surface.image_count; index++) { + surface.swapchain_images[index] = create_texture({ + .width = extent.width, + .height = extent.height, + .depth = 1U, + .mips = 1U, + .usages = desc.usages, + .format = desc.surface_format.format, + .type = VK_IMAGE_TYPE_2D, + .vk_image = images[index], + .name = "swapchain image" + }); + } +} + +// ----------------- vkadapter ----------------- + +void vkdevice::create_instance() { + VkApplicationInfo app_info{ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pApplicationName = "path-tracer", + .applicationVersion = VK_MAKE_VERSION(1, 0, 0), + .pEngineName = "gpu-path-tracer", + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_API_VERSION_1_3, + }; + + constexpr const char* instance_layers[]{ + "VK_LAYER_KHRONOS_validation", + }; + + constexpr const char* instance_extensions[]{ + VK_EXT_DEBUG_UTILS_EXTENSION_NAME, + "VK_KHR_surface", + "VK_KHR_win32_surface" + }; + + VkInstanceCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .pApplicationInfo = &app_info, + .enabledLayerCount = sizeof(instance_layers) / sizeof(instance_layers[0]), + .ppEnabledLayerNames = instance_layers, + .enabledExtensionCount = sizeof(instance_extensions) / sizeof(instance_extensions[0]), + .ppEnabledExtensionNames = instance_extensions, + }; + + VKCHECK(vkCreateInstance(&create_info, nullptr, &instance)); + + load_instance_functions(instance); +} + +void vkdevice::create_device() { + pick_physical_device(); + + float queue_priority = 1.f; + VkDeviceQueueCreateInfo queue_create_infos[static_cast(QueueType::MAX)]; + + for (auto& queue_create_info : queue_create_infos) { + queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info.pNext = nullptr; + queue_create_info.flags = 0U; + queue_create_info.queueCount = 1; + queue_create_info.pQueuePriorities = &queue_priority; + } + + auto queue_properties_count = 0U; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr); + + std::vector queue_properties{ queue_properties_count }; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data()); + + for (auto index{ 0U }; index < static_cast(QueueType::MAX); index++) { + auto& queue = queues[index]; + + for (auto properties_index{ 0U }; properties_index < queue_properties_count; properties_index++) { + auto& queue_property = queue_properties[properties_index]; + + if ((queue_property.queueFlags & queue.usages) == queue.usages) { + queue_create_infos[index].queueFamilyIndex = queue.index = properties_index; + queue_property.queueFlags = 0U; + } + } + } + + constexpr const char* device_extensions[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + // VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME + }; + + VkPhysicalDeviceVulkan12Features physical_device_12_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .pNext = nullptr, + .shaderSampledImageArrayNonUniformIndexing = VK_TRUE, + .shaderStorageImageArrayNonUniformIndexing = VK_TRUE, + .descriptorBindingUpdateUnusedWhilePending = VK_TRUE, + .descriptorBindingPartiallyBound = VK_TRUE, + .runtimeDescriptorArray = VK_TRUE, + .timelineSemaphore = VK_TRUE, + .bufferDeviceAddress = VK_TRUE, + }; + + VkPhysicalDeviceVulkan13Features physical_device_13_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = &physical_device_12_features, + .synchronization2 = VK_TRUE, + .dynamicRendering = VK_TRUE, + }; + + VkDeviceCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = &physical_device_13_features, + .flags = 0U, + .queueCreateInfoCount = static_cast(QueueType::MAX), + .pQueueCreateInfos = queue_create_infos, + .enabledLayerCount = 0, + .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = sizeof(device_extensions) / sizeof(device_extensions[0]), + .ppEnabledExtensionNames = device_extensions, + .pEnabledFeatures = nullptr, + }; + + VKCHECK(vkCreateDevice(physical_device, &create_info, nullptr, &device)); + + load_device_functions(device); + + for (auto& queue : queues) { + vkGetDeviceQueue(device, queue.index, 0, &queue.vk_queue); + } + + create_command_pools(); +} + +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, + }; + + VKCHECK(vmaCreateAllocator(&create_info, &gpu_allocator)); +} + +void vkdevice::create_command_pools() { + VkCommandPoolCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, + }; + + for (auto& queue : queues) { + create_info.queueFamilyIndex = queue.index; + + VKCHECK(vkCreateCommandPool(device, &create_info, nullptr, &queue.command_pool)); + } +} + +void vkdevice::pick_physical_device() { + auto physical_devices_count = 0U; + vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr); + + assert(physical_devices_count > 0); + + std::vector 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; + } + } + + assert(true); +} + +bool vkdevice::device_support_features(VkPhysicalDevice physical_dev) { + // limits + { + vkGetPhysicalDeviceProperties2(physical_dev, &physical_device_props); + + VkPhysicalDeviceLimits* limits = &physical_device_props.properties.limits; + if (limits->maxPerStageDescriptorSampledImages < 0x10000 || + limits->maxPerStageDescriptorStorageImages < 0x10000 || + limits->maxDescriptorSetSampledImages < 0x10000 || + limits->maxDescriptorSetStorageImages < 0x10000) { + return false; + } + } + + // Vulkan 1.2 physical device features support + { + VkPhysicalDeviceVulkan12Features vulkan_12_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + }; + + VkPhysicalDeviceFeatures2 physical_device_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &vulkan_12_features, + }; + + vkGetPhysicalDeviceFeatures2(physical_dev, &physical_device_features); + + // clang-format off + if (vulkan_12_features.bufferDeviceAddress == VK_FALSE || + vulkan_12_features.runtimeDescriptorArray == VK_FALSE || + vulkan_12_features.shaderStorageImageArrayNonUniformIndexing == VK_FALSE || + vulkan_12_features.shaderSampledImageArrayNonUniformIndexing == VK_FALSE || + vulkan_12_features.descriptorBindingPartiallyBound == VK_FALSE || + vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_FALSE || + vulkan_12_features.imagelessFramebuffer == VK_FALSE) { + return false; + } + // clang-format on + } + + // Vulkan 1.3 physical device features support + { + VkPhysicalDeviceVulkan13Features vulkan_13_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, + .pNext = nullptr, + }; + + VkPhysicalDeviceFeatures2 physical_device_features{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = &vulkan_13_features, + }; + + vkGetPhysicalDeviceFeatures2(physical_dev, &physical_device_features); + + if (vulkan_13_features.synchronization2 == VK_FALSE || + vulkan_13_features.dynamicRendering == VK_FALSE) { + return false; + } + } + + return true; +} + +void vkdevice::create_debug_layer_callback() { +#ifdef _DEBUG + VkDebugUtilsMessengerCreateInfoEXT create_info{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0U, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + .pfnUserCallback = debug_callback, + .pUserData = nullptr, + }; + + VKCHECK(vkCreateDebugUtilsMessengerEXT(instance, &create_info, nullptr, &debug_messenger)); +#endif // _DEBUG +} + + +idlist<> device_texture::sampled_indices = {}; +idlist<> device_texture::storage_indices = {}; +idlist<> device_sampler::sampler_indices = {}; + +void device_texture::init(const texture_desc& desc) { + auto& render_device = vkdevice::get(); + const auto& bindless = render_device.get_bindingmodel(); + auto* device = render_device.get_device(); + + vk_image = desc.vk_image; + format = desc.format; + 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; + + assert(mips <= texture_desc::max_mips); + + if (vk_image == nullptr) { + VkImageCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .imageType = desc.type, + .format = desc.format, + .extent = { + .width = desc.width, + .height = desc.height, + .depth = desc.depth + }, + .mipLevels = desc.mips, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = desc.usages, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VmaAllocationCreateInfo alloc_create_info{ + .flags = 0U, + .usage = VMA_MEMORY_USAGE_GPU_ONLY, + .requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .preferredFlags = 0U, + .memoryTypeBits = 0U, + .pool = nullptr, + .pUserData = nullptr, + }; + + 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) { + VkDebugUtilsObjectNameInfoEXT object_name{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_IMAGE, + .objectHandle = reinterpret_cast(vk_image), + .pObjectName = desc.name, + }; + vkSetDebugUtilsObjectNameEXT(device, &object_name); + } + + create_views(); + + // TODO: Handle mips views + VkDescriptorImageInfo images_info[]{ + { + nullptr, + whole_view, + VK_IMAGE_LAYOUT_GENERAL, + }, + }; + + std::vector write_descriptor_sets; + if ((desc.usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0) { + storage_index = storage_indices.add(); + + write_descriptor_sets.push_back({ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstSet = bindless.global_set, + .dstBinding = 2U, + .dstArrayElement = storage_index.id, + .descriptorCount = sizeof(images_info) / sizeof(VkDescriptorImageInfo), + .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, + .pImageInfo = images_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + } + if ((desc.usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0) { + sampled_index = sampled_indices.add(); + + write_descriptor_sets.push_back({ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + .dstSet = bindless.global_set, + .dstBinding = 1U, + .dstArrayElement = sampled_index.id, + .descriptorCount = sizeof(images_info) / sizeof(VkDescriptorImageInfo), + .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + .pImageInfo = images_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + } + + vkUpdateDescriptorSets(device, static_cast(write_descriptor_sets.size()), write_descriptor_sets.data(), 0U, nullptr); +} + +void device_texture::release() { + auto& render_device = vkdevice::get(); + auto* device = render_device.get_device(); + auto* gpu_allocator = render_device.get_allocator(); + + if (alloc != nullptr) { + vmaDestroyImage(gpu_allocator, vk_image, alloc); + } + + vkDestroyImageView(device, whole_view, nullptr); + + for (auto mip_index{ 0U }; mip_index < mips; mip_index++) { + const auto& mip_view = mips_views[mip_index]; + vkDestroyImageView(device, mip_view, nullptr); + } + + if (storage_index.is_valid()) { + storage_indices.remove(storage_index); + } + + if (sampled_index.is_valid()) { + sampled_indices.remove(sampled_index); + } +} + +void device_texture::create_views() { + auto* device = vkdevice::get().get_device(); + + VkImageViewCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .image = vk_image, + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .format = format, + .components = { + .r = VK_COMPONENT_SWIZZLE_R, + .g = VK_COMPONENT_SWIZZLE_G, + .b = VK_COMPONENT_SWIZZLE_B, + .a = VK_COMPONENT_SWIZZLE_A, + }, + .subresourceRange = { + .aspectMask = aspects, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }; + + for (auto mip_index{ 0U }; mip_index < mips; mip_index++) { + create_info.subresourceRange.baseMipLevel = mip_index; + VKCHECK(vkCreateImageView(device, &create_info, nullptr, &mips_views[mip_index])); + } + + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.levelCount = mips; + VKCHECK(vkCreateImageView(device, &create_info, nullptr, &whole_view)); +} + + +void device_sampler::init(const sampler_desc& desc) { + auto& render_device = vkdevice::get(); + // const auto& bindless = render_device.get_bindingmodel(); + auto* device = render_device.get_device(); + + VkSamplerCreateInfo sampler_create_info{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0U, + .magFilter = desc.mag_filter, + .minFilter = desc.min_filter, + .mipmapMode = desc.mipmap_mode, + .addressModeU = desc.address_mode_u, + .addressModeV = desc.address_mode_v, + .addressModeW = desc.address_mode_w, + .mipLodBias = desc.mip_lod_bias, + .anisotropyEnable = desc.anisotropy, + .maxAnisotropy = desc.max_anisotropy, + .compareEnable = desc.compare_enabled, + .compareOp = desc.compare_op, + .minLod = desc.min_lod, + .maxLod = desc.max_lod, + .borderColor = desc.border_color, + .unnormalizedCoordinates = desc.unnomalized_coords, + }; + + VKCHECK(vkCreateSampler(device, &sampler_create_info, nullptr, &vk_sampler)); + + sampler_index = sampler_indices.add(); + + // VkWriteDescriptorSet write_descriptor_set{ + // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + // .pNext = nullptr, + // .dstSet = bindless.sets[BindlessSetType::GLOBAL], + // .dstBinding = 1U, + // .dstArrayElement = sampler_index.id, + // .descriptorCount = 1U, + // .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + // .pImageInfo = images_info, + // .pBufferInfo = nullptr, + // .pTexelBufferView = nullptr, + // }); +} + + +uint32_t vkdevice::acquire_image_index(handle surface_handle) { + auto& surface = get_surface(surface_handle); + const auto& signal = get_semaphore(surface.acquire_semaphores[surface.frame_index]); + + VkSemaphoreWaitInfo wait_info { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .pNext = nullptr, + .flags = 0U, + .semaphoreCount = 1U, + .pSemaphores = &timeline_semaphore.vk_semaphore, + .pValues = &timeline_semaphore.value, + }; + vkWaitSemaphores(device, &wait_info, UINT64_MAX); + VKCHECK(vkAcquireNextImageKHR(device, surface.vk_swapchain, UINT64_MAX, signal.vk_semaphore, nullptr, &surface.image_index)); + + return surface.image_index; +} 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 -#include - -#include - -#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(); - -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(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/src/vk-utils.cpp b/src/vk-utils.cpp new file mode 100644 index 0000000..89f5741 --- /dev/null +++ b/src/vk-utils.cpp @@ -0,0 +1,42 @@ +#include "vk-utils.hpp" + +VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(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; + } + + fprintf(stderr, "[%s_%s]:%s\n", severity_cstr, type_cstr, data->pMessage); + return VK_FALSE; +} -- cgit v1.3