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 --- api-test/dx12-command-buffer.cpp | 47 -- api-test/dx12-device.cpp | 239 ------ api-test/main.cpp | 653 --------------- api-test/vk-bindless.cpp | 431 ---------- api-test/vk-command-buffer.cpp | 233 ------ api-test/vk-device.cpp | 1302 ----------------------------- api-test/vk-utils.cpp | 44 - build.bat | 16 +- include/api-test/buffer.hpp | 18 - include/api-test/dx12-command-buffer.hpp | 28 - include/api-test/dx12-device-types.hpp | 74 -- include/api-test/dx12-device.hpp | 97 --- include/api-test/freelist.hpp | 151 ---- include/api-test/handle.hpp | 24 - include/api-test/resource-manager.hpp | 22 - include/api-test/texture.hpp | 17 - include/api-test/vk-bindless.hpp | 93 --- include/api-test/vk-command-buffer.hpp | 103 --- include/api-test/vk-device-types.hpp | 213 ----- include/api-test/vk-device.hpp | 161 ---- include/api-test/vk-utils.hpp | 16 - include/buffer.hpp | 18 + include/bvh-node.hpp | 320 -------- include/compute-renderpass.hpp | 41 - include/dx12-command-buffer.hpp | 28 + include/dx12-device-types.hpp | 74 ++ include/dx12-device.hpp | 97 +++ include/freelist.hpp | 158 ++++ include/handle.hpp | 13 + include/primitive-renderpass.hpp | 93 --- include/renderpass.hpp | 22 - include/texture.hpp | 86 +- include/vk-api.hpp | 219 ----- include/vk-bindless.hpp | 49 ++ include/vk-command-buffer.hpp | 75 ++ include/vk-context.hpp | 49 -- include/vk-device-types.hpp | 218 +++++ include/vk-device.hpp | 163 ++++ include/vk-renderer.hpp | 164 ---- include/vk-utils.hpp | 12 + 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 + 52 files changed, 3779 insertions(+), 7393 deletions(-) delete mode 100644 api-test/dx12-command-buffer.cpp delete mode 100644 api-test/dx12-device.cpp delete mode 100644 api-test/main.cpp delete mode 100644 api-test/vk-bindless.cpp delete mode 100644 api-test/vk-command-buffer.cpp delete mode 100644 api-test/vk-device.cpp delete mode 100644 api-test/vk-utils.cpp delete mode 100644 include/api-test/buffer.hpp delete mode 100644 include/api-test/dx12-command-buffer.hpp delete mode 100644 include/api-test/dx12-device-types.hpp delete mode 100644 include/api-test/dx12-device.hpp delete mode 100644 include/api-test/freelist.hpp delete mode 100644 include/api-test/handle.hpp delete mode 100644 include/api-test/resource-manager.hpp delete mode 100644 include/api-test/texture.hpp delete mode 100644 include/api-test/vk-bindless.hpp delete mode 100644 include/api-test/vk-command-buffer.hpp delete mode 100644 include/api-test/vk-device-types.hpp delete mode 100644 include/api-test/vk-device.hpp delete mode 100644 include/api-test/vk-utils.hpp create mode 100644 include/buffer.hpp delete mode 100644 include/bvh-node.hpp delete mode 100644 include/compute-renderpass.hpp create mode 100644 include/dx12-command-buffer.hpp create mode 100644 include/dx12-device-types.hpp create mode 100644 include/dx12-device.hpp create mode 100644 include/freelist.hpp create mode 100644 include/handle.hpp delete mode 100644 include/primitive-renderpass.hpp delete mode 100644 include/renderpass.hpp delete mode 100644 include/vk-api.hpp create mode 100644 include/vk-bindless.hpp create mode 100644 include/vk-command-buffer.hpp delete mode 100644 include/vk-context.hpp create mode 100644 include/vk-device-types.hpp create mode 100644 include/vk-device.hpp delete mode 100644 include/vk-renderer.hpp create mode 100644 include/vk-utils.hpp 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 diff --git a/api-test/dx12-command-buffer.cpp b/api-test/dx12-command-buffer.cpp deleted file mode 100644 index 0310dfd..0000000 --- a/api-test/dx12-command-buffer.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#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/api-test/dx12-device.cpp b/api-test/dx12-device.cpp deleted file mode 100644 index ac328ed..0000000 --- a/api-test/dx12-device.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#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/api-test/main.cpp b/api-test/main.cpp deleted file mode 100644 index f4a825d..0000000 --- a/api-test/main.cpp +++ /dev/null @@ -1,653 +0,0 @@ -// #include -// #include -// #include - -#define STB_IMAGE_IMPLEMENTATION -// #include - -#include "imgui.cpp" -#include "imgui_draw.cpp" -#include "imgui_tables.cpp" -#include "imgui_widgets.cpp" -#include "imgui_demo.cpp" - -#define API_TEST - -#include "../src/vulkan-loader.cpp" -#include "../src/window.cpp" -#include "../src/vec3.cpp" -#include "../src/camera.cpp" -#include "../src/scene.cpp" -#include "../src/utils.cpp" -#include "../src/bvh.cpp" -#include "../src/gltf.cpp" -#include "../src/mesh.cpp" - -#include "vk-utils.cpp" -#include "vk-device.cpp" -#include "vk-bindless.cpp" -#include "vk-command-buffer.cpp" - -// #include "handle.hpp" -// #include "window.hpp" -// #include "utils.hpp" - -#ifdef VK -#include -#include "vk-device.hpp" -#include "vk-command-buffer.hpp" -#else -#include "dx12-device.hpp" -#include "dx12-command-buffer.hpp" -#endif - -struct device_texture; - -#define VK -// #define DX12 - -#ifdef DEBUG -#define ENABLE_RENDERDOC -#endif // _DEBUG - -#include "camera.hpp" -#include "scene.hpp" - -#ifdef ENABLE_RENDERDOC -#include - -#define RD_START_CAPTURE if(rdoc_api != nullptr) rdoc_api->StartFrameCapture(nullptr, nullptr) -#define RD_END_CAPTURE if(rdoc_api != nullptr) rdoc_api->EndFrameCapture(nullptr, nullptr) - -RENDERDOC_API_1_6_0 *rdoc_api = nullptr; -#else -#define RD_START_CAPTURE (0) -#define RD_END_CAPTURE (0) -#endif // ENABLE_RENDERDOC - -static constexpr size_t Kb = 1024U; -static constexpr size_t Mb = 1024U * Kb; - -static uintptr_t transmittance_LUT_tex_id = 0U; - -void ui(uint64_t frame_time) { - static float max_fps = 0.f; - static uint64_t max_frame_time = 1000U; - float fps = static_cast(1000000U / frame_time); - if (fps > max_fps) { - max_fps = fps; - } - if (frame_time > max_frame_time) { - max_frame_time = frame_time; - } - ImGui::NewFrame(); - ImGui::Text("FPS : %f\n", fps); - ImGui::Text("Max FPS : %f\n", max_fps); - ImGui::Text("frame_time : %f ms\n", frame_time / 1000.f); - ImGui::Text("max frame_time : %f ms\n", max_frame_time / 1000.f); - - ImGui::Text("LUT"); - ImGui::Image(transmittance_LUT_tex_id, ImVec2(128, 128)); - ImGui::EndFrame(); - ImGui::Render(); -} - -void update_buffers(ImDrawData* draw_data, const device_buffer& vertex_buffer, const device_buffer& index_buffer) { - off_t vertex_offset = 0; - off_t index_offset = 0; - for (auto index {0} ; index < draw_data->CmdListsCount; index++) { - auto* cmd_list = draw_data->CmdLists[index]; - - size_t vertex_bytes_size = sizeof(ImDrawVert) * cmd_list->VtxBuffer.size(); - auto* vtx_ptr = static_cast(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); - } -} - -int main() { - LARGE_INTEGER freq; - // From Microsoft doc - // https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency - // The frequency of the performance counter is fixed at system boot and is - // consistent across all processors so you only need to query the frequency - // from QueryPerformanceFrequency as the application initializes, - // and then cache the result. - QueryPerformanceFrequency(&freq); - -#ifdef ENABLE_RENDERDOC - { - HMODULE mod = GetModuleHandleA("renderdoc.dll"); - // if (!mod) { - // mod = LoadLibraryA("renderdoc.dll"); - // } - - if (mod) { - auto RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); - assert(RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, (void **)&rdoc_api) == 1); - } - - // if (!rdoc_api->IsTargetControlConnected()) { - // rdoc_api->LaunchReplayUI(true, nullptr); - // } - } -#endif - - constexpr size_t window_width = 1280U; - constexpr size_t window_height = 720U; - window wnd { window_width, window_height }; - - ImGui::CreateContext(); - ImGuiIO &io = ImGui::GetIO(); - io.DisplaySize.x = window_width; - io.DisplaySize.y = window_height; - - const float aspect_ratio = 16.f / 9.f; - - point3 position { 13.f, 2.f, -3.f }; - point3 target {}; - const auto v_fov = 90.f; - const auto aperture = 0.1f; - const auto focus_distance = 10.f; - -#ifdef VK - auto& device = vkdevice::get_render_device(); -#else - auto& device = dx12::device::get_render_device(); -#endif - device.init(); - -#ifdef VK - auto main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), window_width, window_height); -#endif - - auto surface_handle = device.create_surface({ - .window_handle = wnd.handle, -#ifdef VK - .surface_format = { - .format = VK_FORMAT_B8G8R8A8_UNORM, - .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, - }, - .present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR, - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT, -#else - .surface_format = DXGI_FORMAT_R16G16B16A16_FLOAT, - .present_mode = DXGI_SWAP_EFFECT_FLIP_DISCARD, - .usages = DXGI_USAGE_RENDER_TARGET_OUTPUT, -#endif - .image_count = 2U, - }); - auto& surface = device.get_surface(surface_handle); - - constexpr size_t image_size = 1024U; - constexpr size_t image_count = 4U; - auto staging_buffer_handle = device.create_buffer({ - .size = image_size * image_size * sizeof(uint32_t) * image_count, -#ifdef VK - .usages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, -#else - - .map = true, - .states = D3D12_RESOURCE_STATE_COPY_SOURCE, - .usages = D3D12_RESOURCE_FLAG_NONE, - .heap_type = D3D12_HEAP_TYPE_UPLOAD, -#endif - }); - const auto& staging_buffer = device.get_buffer(staging_buffer_handle); - - // API test code - int width; - int height; - int channels; - uint8_t* data = stbi_load("../models/sponza/466164707995436622.jpg", &width, &height, &channels, 4); - size_t size = static_cast(width) * height * 4U; - memcpy(staging_buffer.mapped_ptr, data, size); - - auto gpu_texture_handle = device.create_texture({ - .width = static_cast(width), - .height = static_cast(height), -#ifdef VK - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_COPY_DEST, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - - off_t buffer_offset = width * height * 4; - data = stbi_load("../models/sponza/715093869573992647.jpg", &width, &height, &channels, 4); - size = static_cast(width) * height * 4U; - auto* addr = static_cast(static_cast(staging_buffer.mapped_ptr) + buffer_offset); - memcpy(addr, data, size); - - auto second_texture = device.create_texture({ - .width = static_cast(width), - .height = static_cast(height), -#ifdef VK - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_COPY_DEST, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - - auto output_texture_handle = device.create_texture({ - .width = static_cast(width), - .height = static_cast(height), -#ifdef VK - .usages = VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - - uint8_t *pixels = nullptr; - int atlas_width; - int atlas_height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height); - const auto ui_texture_handle = device.create_texture({ - .width = static_cast(atlas_width), - .height = static_cast(atlas_height), -#ifdef VK - .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .format = VK_FORMAT_R8G8B8A8_UNORM, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_COPY_DEST, - .usages = D3D12_RESOURCE_FLAG_NONE, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - const auto& ui_texture = device.get_texture(ui_texture_handle); - // io.Fonts->SetTexID(*(void **)&ui_texture_handle.id); - io.Fonts->SetTexID(reinterpret_cast(ui_texture.get_sampled_index())); - - 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); - - auto vertex_buffer_handle = device.create_buffer({ - .size = Mb * sizeof(uint32_t), -#ifdef VK - .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, -#else - #endif - }); - auto vertex_buffer = device.get_buffer(vertex_buffer_handle); - - auto index_buffer_handle = device.create_buffer({ - .size = Mb * sizeof(uint32_t), -#ifdef VK - .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, -#else -#endif - }); - auto index_buffer = device.get_buffer(index_buffer_handle); - -#ifdef VK - auto code = read_file("shaders/test.comp.spv"); - auto compute = device.create_compute_pipeline({ - .cs_code = code, - }); - - auto rt_code = read_file("shaders/compute.comp.spv"); - auto raytracing = device.create_compute_pipeline({ - .cs_code = rt_code, - }); - auto tonemapping_code = read_file("shaders/tonemapping.comp.spv"); - auto tonemapping = device.create_compute_pipeline({ - .cs_code = tonemapping_code, - }); -#endif - const auto acc_handle = device.create_texture({ - .width = static_cast(window_width), - .height = static_cast(window_height), -#ifdef VK - .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R32G32B32A32_FLOAT, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); - -#ifdef VK - auto acc_storage_index = device.get_texture(acc_handle).get_storage_index(); -#endif - - const auto result_handle = device.create_texture({ - .width = static_cast(window_width), - .height = static_cast(window_height), -#ifdef VK - .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .type = VK_IMAGE_TYPE_2D, -#else - .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS, - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R32G32B32A32_FLOAT, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - }); -#ifdef VK - auto result_storage_index = device.get_texture(result_handle).get_storage_index(); -#endif - -#ifdef VK - std::array formats { surface.surface_format.format }; - auto vertex_code = read_file("shaders/api-test-ui.vert.spv"); - auto fragment_code = read_file("shaders/api-test-ui.frag.spv"); - auto graphics = device.create_graphics_pipeline({ - .vs_code = vertex_code, - .fs_code = fragment_code, - .color_attachments_format = formats - }); -#endif - -#ifdef VK - std::array graphics_command_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 - - - handle transmittance_lut_handle = device.create_texture({ - .width = static_cast(1024), - .height = static_cast(1024), -#ifdef VK - .usages = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .format = VK_FORMAT_R16G16B16A16_SFLOAT, - .type = VK_IMAGE_TYPE_2D, -#else - .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, - .format = DXGI_FORMAT_R8G8B8A8_UNORM, - .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D, -#endif - .name = "transmittance_lut", - }); - device_texture transmittance_lut = device.get_texture(transmittance_lut_handle); - transmittance_LUT_tex_id = transmittance_lut.get_sampled_index(); - - std::vector transmittance_lut_code = read_file("shaders/transmittance_lut.comp.spv"); - handle transmittance_lut_compute = device.create_compute_pipeline({ - .cs_code = transmittance_lut_code, - .name = "transmittance_lut_comp", - }); - - - // API test code - RD_START_CAPTURE; - - graphics_command_buffers[0].start(); - -#ifdef VK - graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - graphics_command_buffers[0].barrier(ui_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); -#endif - - graphics_command_buffers[0].copy(staging_buffer_handle, gpu_texture_handle); - graphics_command_buffers[0].copy(staging_buffer_handle, second_texture, buffer_offset); - graphics_command_buffers[0].copy(staging_buffer_handle, ui_texture_handle, ui_offset); -#ifdef VK - graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); - graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL); - - { - graphics_command_buffers[0].dispatch({ - .pipeline = compute, - .group_size = { .vec = { image_size, image_size, 1U }}, - .local_group_size = { .vec = { 8U, 8U, 1U }}, - .params = { - device.get_texture(second_texture).get_storage_index(), // Input 1 - device.get_texture(gpu_texture_handle).get_storage_index(), // Input 2 - device.get_texture(output_texture_handle).get_storage_index(), // Output - }, - }); - - graphics_command_buffers[0].dispatch({ - .pipeline = transmittance_lut_compute, - .group_size = { .vec = { 1024U, 1024U, 1U }}, - .local_group_size = { .vec { 8U, 8U, 1U }}, - .params = { - transmittance_lut.get_storage_index(), - uint64_t(transmittance_lut.width) << 32U | transmittance_lut.height, - } - }); - } - - graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); -#endif - - graphics_command_buffers[0].stop(); - - device.submit(graphics_command_buffers.data(), 1); - device.wait(); - - RD_END_CAPTURE; - - // watcher::watch_file(std::filesystem::path("../shaders/compute.comp"), [&]() { - // printf("change"); - // }); - -#ifdef VK - std::array, 1U> color_attachment {}; - constexpr uint32_t virtual_frames_count = 2U; - uint64_t frame_time = 1U; - uint32_t frame_count = 0U; - while(wnd.isOpen) { - LARGE_INTEGER start_qpc; - QueryPerformanceCounter(&start_qpc); - wnd.poll_events(); - - watcher::pull_changes(); - - uint32_t virtual_frame_index = frame_count % virtual_frames_count; - auto command_buffer = graphics_command_buffers[2U + virtual_frame_index]; - for (auto& event : wnd.events) { - if (event.type == EVENT_TYPES::MOUSE_MOVE) { - io.MousePos.x = static_cast(event.data.position.x); - io.MousePos.y = static_cast(event.data.position.y); - } - - io.MouseDown[0] = event.type == EVENT_TYPES::BUTTON_PRESS; - } - - ui(frame_time); - - auto* draw_data = ImGui::GetDrawData(); - update_buffers(draw_data, vertex_buffer, index_buffer); - - const auto& scene_buffer = device.get_buffer(main_scene.scene_buffer_handle); - main_scene.meta.sample_index = frame_count; - uint8_t* ptr = static_cast(scene_buffer.mapped_ptr); - memcpy(static_cast(ptr), &main_scene.meta, sizeof(main_scene.meta)); - memcpy(static_cast(ptr + sizeof(main_scene.meta)), &main_scene.meta, sizeof(main_scene.meta)); - memcpy(static_cast(ptr + sizeof(main_scene.meta) * 2U), &main_scene.meta, sizeof(main_scene.meta)); - - // TODO: Refactor backbuffer acquisition - auto backbuffer = surface.swapchain_images[device.acquire_image_index(surface_handle)]; - color_attachment[0] = backbuffer; - - // RD_START_CAPTURE; - command_buffer.start(); - - command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); - - { - uint64_t textures = (virtual_frame_index == 0U) ? ((uint64_t(acc_storage_index) << 32U) | result_storage_index) : ((uint64_t(result_storage_index) << 32U) | acc_storage_index); - - if (virtual_frame_index == 0) { - command_buffer.barrier(result_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); - command_buffer.barrier(acc_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL); - } else { - command_buffer.barrier(result_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL); - command_buffer.barrier(acc_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); - } - - command_buffer.dispatch({ - .pipeline = raytracing, - .group_size = { .vec { window_width, window_height, 1U, } }, - .local_group_size = { .vec { 8U, 8U, 1U, } }, - .params = { - main_scene.scene_buffer_address(), - main_scene.bvh_buffer_address(), - main_scene.indices_buffer_address(), - main_scene.positions_buffer_address(), - main_scene.normals_buffer_address(), - main_scene.uvs_buffer_address(), - main_scene.materials_buffer_address(), - textures, - }, - }); - - // TODO: Refactor backbuffer acquisition - auto backbuffer_storage_index = device.get_texture(backbuffer).get_storage_index(); - uint64_t out = (virtual_frame_index == 0U) ? ((uint64_t(result_storage_index) << 32U) | backbuffer_storage_index) : ((uint64_t(acc_storage_index) << 32U) | backbuffer_storage_index); - command_buffer.dispatch({ - .pipeline = tonemapping, - .group_size = { .vec { window_width, window_height, 1U, } }, - .local_group_size = { .vec { 8U, 8U, 1U, } }, - .params = { - main_scene.scene_buffer_address(), - main_scene.bvh_buffer_address(), - main_scene.indices_buffer_address(), - main_scene.positions_buffer_address(), - main_scene.normals_buffer_address(), - main_scene.uvs_buffer_address(), - main_scene.materials_buffer_address(), - out, - }, - }); - } - - command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - command_buffer.begin_renderpass({ - .render_area = { - .x = static_cast(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_draws_uniform_buffer(); - uint32_t vertex_offset = 0; - uint32_t index_offset = 0; - for (auto index {0} ; index < draw_data->CmdListsCount; index++) { - auto* cmd_list = draw_data->CmdLists[index]; - - for (auto& draw_command : cmd_list->CmdBuffer) { - auto offset = draws_uniform_buffer.offset; - ImTextureID texture_id = draw_command.TexRef.GetTexID(); - { - struct ui_params { - // uintptr_t vertex_buffer; - float scale[2U]; - float translate[2U]; - uint32_t texture_index; - }; - auto* ui_param = draws_uniform_buffer.allocate(); - *ui_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, - .uniforms_address = draws_uniform_buffer.device_address + offset, - .vertex_address = vertex_buffer.device_address, - }); - } - vertex_offset += cmd_list->VtxBuffer.size(); - index_offset += cmd_list->IdxBuffer.size(); - } - - command_buffer.end_renderpass(); - command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - - command_buffer.stop(); - - device.submit_before_present(surface_handle, &command_buffer, 1U); - device.present(surface_handle); - device.wait(); - - LARGE_INTEGER end_qpc; - QueryPerformanceCounter(&end_qpc); - LONGLONG diff_qpc = end_qpc.QuadPart - start_qpc.QuadPart; - frame_time = (diff_qpc * 1000000ULL) / freq.QuadPart; - frame_count++; - - // RD_END_CAPTURE; - } - - device.wait(); - device.destroy_surface(surface_handle); - - device.destroy_pipeline(compute); - device.destroy_pipeline(graphics); - device.destroy_pipeline(raytracing); - device.destroy_pipeline(tonemapping); - - device.destroy_texture(gpu_texture_handle); - device.destroy_texture(second_texture); - device.destroy_texture(output_texture_handle); - device.destroy_texture(ui_texture_handle); - device.destroy_texture(acc_handle); - device.destroy_texture(result_handle); - - device.destroy_buffer(staging_buffer_handle); - device.destroy_buffer(vertex_buffer_handle); - device.destroy_buffer(index_buffer_handle); - device.deinit(); - - ImGui::DestroyContext(); -#endif // VK - - return 0; -} diff --git a/api-test/vk-bindless.cpp b/api-test/vk-bindless.cpp deleted file mode 100644 index d3d6415..0000000 --- a/api-test/vk-bindless.cpp +++ /dev/null @@ -1,431 +0,0 @@ -#include "vk-bindless.hpp" - -#include -#include - -#include "vk-device.hpp" -#include "vk-utils.hpp" -#include "vulkan-loader.hpp" - -device_buffer& bindless_model::get_globals_uniform_buffer() const { - auto& render_device = vkdevice::get_render_device(); - return render_device.get_buffer(globals_uniform_buffer_handle); -} - -device_buffer& bindless_model::get_draws_uniform_buffer() const { - auto& render_device = vkdevice::get_render_device(); - return render_device.get_buffer(draws_uniform_buffer_handle); -} - -bindless_model bindless_model::create_bindless_model() { - bindless_model bindless; - auto& render_device = vkdevice::get_render_device(); - auto* device = render_device.get_device(); -#ifndef USE_VK_DESCRIPTOR_BUFFER - bindless.create_immutable_samplers(device); - bindless.create_layout(device); - bindless.create_descriptor_pool(device); - bindless.allocate_sets(device); - - // VkWriteDescriptorSet writes_descriptor_set[BindlessSetType::MAX]; - - // { - bindless.globals_uniform_buffer_handle = render_device.create_buffer({ - .size = globals_uniform_buffer_size, - .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, - }); - - // const auto& buffer = render_device.get_buffer(bindless.globals_uniform_buffer_handle); - // VkDescriptorBufferInfo buffer_info { - // .buffer = buffer.vk_buffer, - // .offset = 0U, - // .range = VK_WHOLE_SIZE, - // }; - - // writes_descriptor_set[BindlessSetType::GLOBAL] = { - // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - // .pNext = nullptr, - // .dstSet = bindless.sets[BindlessSetType::GLOBAL], - // .dstBinding = 3U, - // .dstArrayElement = 0U, - // .descriptorCount = 1U, - // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - // .pImageInfo = nullptr, - // .pBufferInfo = &buffer_info, - // .pTexelBufferView = nullptr, - // }; - // } - - // { - // bindless.instances_uniform_buffer_handle = render_device.create_buffer({ - // .size = instances_uniform_buffer_size, - // .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - // .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - // .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, - // }); - - // const auto& buffer = render_device.get_buffer(bindless.instances_uniform_buffer_handle); - // VkDescriptorBufferInfo buffer_info { - // .buffer = buffer.vk_buffer, - // .offset = 0U, - // .range = VK_WHOLE_SIZE, - // }; - - // writes_descriptor_set[BindlessSetType::INSTANCES_UNIFORMS] = { - // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - // .pNext = nullptr, - // .dstSet = bindless.sets[BindlessSetType::INSTANCES_UNIFORMS], - // .dstBinding = 0U, - // .dstArrayElement = 0U, - // .descriptorCount = 1U, - // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - // .pImageInfo = nullptr, - // .pBufferInfo = &buffer_info, - // .pTexelBufferView = nullptr, - // }; - // } - - // { - bindless.draws_uniform_buffer_handle = render_device.create_buffer({ - .size = draws_uniform_buffer_size, - .usages = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, - .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU, - }); - - // const auto& buffer = render_device.get_buffer(bindless.draws_uniform_buffer_handle); - // VkDescriptorBufferInfo buffer_info { - // .buffer = buffer.vk_buffer, - // .offset = 0U, - // .range = draws_uniform_buffer_size, - // }; - - // writes_descriptor_set[BindlessSetType::DRAWS_UNIFORMS] = { - // .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - // .pNext = nullptr, - // .dstSet = bindless.sets[BindlessSetType::DRAWS_UNIFORMS], - // .dstBinding = 0U, - // .dstArrayElement = 0U, - // .descriptorCount = 1U, - // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - // .pImageInfo = nullptr, - // .pBufferInfo = &buffer_info, - // .pTexelBufferView = nullptr, - // }; - // } - - // vkUpdateDescriptorSets(device, sizeof(writes_descriptor_set) / sizeof(VkWriteDescriptorSet), writes_descriptor_set, 0U, nullptr); -#else - VkBufferCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .size = desc.size, - .usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr, - }; - - VmaAllocatorCreateFlags alloc_create_flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - VmaAllocationCreateInfo alloc_create_info{ - .flags = alloc_create_flags, - .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, - .requiredFlags = desc.memory_properties, - .preferredFlags = 0U, - .memoryTypeBits = 0U, - .pool = nullptr, - .pUserData = nullptr, - }; - - VmaAllocationInfo alloc_info{}; - - VKCHECK(vmaCreateBuffer(gpu_allocator, &create_info, &alloc_create_info, &device_buffer.vk_buffer, &device_buffer.alloc, &alloc_info)); - - device_buffer.mapped_ptr = alloc_info.pMappedData; - - return { buffers.add(device_buffer) }; -#endif - - return bindless; -} - -void bindless_model::destroy_bindless_model(bindless_model& bindless) { - auto& render_device = vkdevice::get_render_device(); - auto* device = vkdevice::get_render_device().get_device(); - vkDestroyDescriptorPool(device, bindless.descriptor_pool, nullptr); - - for (auto index{ 0U }; index < BindlessSetType::MAX; index++) { - vkDestroyDescriptorSetLayout(device, bindless.sets_layout[index], nullptr); - } - - vkDestroyPipelineLayout(device, bindless.graphics_layout, nullptr); - vkDestroyPipelineLayout(device, bindless.compute_layout, nullptr); - - bindless.destroy_immutable_samplers(device); - - // render_device.destroy_buffer(bindless.instances_uniform_buffer_handle); - render_device.destroy_buffer(bindless.draws_uniform_buffer_handle); -} - -void bindless_model::create_layout(VkDevice device) { - // Set 0 global resources - // Binding 0 Storage images - // Binding 1 Sampled images - // Binding 2 Samplers - // Binding 3 Dynamic Uniform Buffer - { - VkDescriptorSetLayoutBinding set_layout_bindings[]{ - { - .binding = 0U, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = SamplerType::MAX_SAMPLER, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = samplers, - }, - { - .binding = 1U, - .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = set_descriptors_count, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = nullptr, - }, - { - .binding = 2U, - .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = set_descriptors_count, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = nullptr, - }, - // { - // .binding = 3U, - // .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - // .descriptorCount = 1U, - // .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - // .pImmutableSamplers = nullptr, - // }, - }; - - VkDescriptorBindingFlags flags[]{ - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, - VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, - // VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT, - // 0U, - }; - - VkDescriptorSetLayoutBindingFlagsCreateInfo layout_binding_flags{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, - .pNext = VK_NULL_HANDLE, - .bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags), - .pBindingFlags = flags, - }; - - VkDescriptorSetLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = &layout_binding_flags, - .flags = 0U, - .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), - .pBindings = set_layout_bindings, - }; - - VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::GLOBAL])); - } - - // Set 1 per instance uniforms - // Binding 0 Dynamic Uniform Buffer - { - VkDescriptorSetLayoutBinding set_layout_bindings[]{ - { - .binding = 0U, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = 1U, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = nullptr, - }, - }; - - VkDescriptorSetLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), - .pBindings = set_layout_bindings, - }; - - VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::INSTANCES_UNIFORMS])); - } - - // Set 2 per draw uniforms - // Binding 0 Dynamic Uniform Buffer - { - VkDescriptorSetLayoutBinding set_layout_bindings[]{ - { - .binding = 0U, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .pImmutableSamplers = nullptr, - }, - }; - - VkDescriptorSetLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding), - .pBindings = set_layout_bindings, - }; - - VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &sets_layout[BindlessSetType::DRAWS_UNIFORMS])); - } - - { - VkPushConstantRange push_constants[] { - { - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - .offset = 0U, - .size = max_push_constants_slots_size * (max_push_constants_slots), - }, - }; - - VkPipelineLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .setLayoutCount = sizeof(sets_layout) / sizeof(VkDescriptorSetLayout), - .pSetLayouts = sets_layout, - .pushConstantRangeCount = sizeof(push_constants) / sizeof(push_constants[0]), - .pPushConstantRanges = push_constants, - }; - - VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &graphics_layout)); - } - - { - VkPushConstantRange push_constants[] { - { - .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT, - .offset = 0U, - .size = max_push_constants_slots_size * max_push_constants_slots, - }, - }; - - - VkPipelineLayoutCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .setLayoutCount = sizeof(sets_layout) / sizeof(VkDescriptorSetLayout), - .pSetLayouts = sets_layout, - .pushConstantRangeCount = sizeof(push_constants) / sizeof(push_constants[0]), - .pPushConstantRanges = push_constants, - }; - - VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &compute_layout)); - } -} - -#ifndef USE_VK_DESCRIPTOR_BUFFER -void bindless_model::create_descriptor_pool(VkDevice device) { - VkDescriptorPoolSize pool_sizes[]{ - { - .type = VK_DESCRIPTOR_TYPE_SAMPLER, - .descriptorCount = set_descriptors_count, - }, - { - .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - .descriptorCount = set_descriptors_count, - }, - { - .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, - .descriptorCount = set_descriptors_count, - }, - { - .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - .descriptorCount = 8U, - }, - }; - - VkDescriptorPoolCreateInfo descriptor_pool_create_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .maxSets = descriptor_pool_allocable_sets_count, - .poolSizeCount = sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize), - .pPoolSizes = pool_sizes, - }; - VKCHECK(vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool)); -} - -void bindless_model::allocate_sets(VkDevice device) { - VkDescriptorSetAllocateInfo allocate_info{ - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .pNext = nullptr, - .descriptorPool = descriptor_pool, - .descriptorSetCount = 1U, - .pSetLayouts = &sets_layout[BindlessSetType::GLOBAL], - }; - VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::GLOBAL])); - - allocate_info.pSetLayouts = &sets_layout[BindlessSetType::INSTANCES_UNIFORMS], - VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::INSTANCES_UNIFORMS])); - - allocate_info.pSetLayouts = &sets_layout[BindlessSetType::DRAWS_UNIFORMS], - VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &sets[BindlessSetType::DRAWS_UNIFORMS])); -} - -void bindless_model::create_immutable_samplers(VkDevice device) { - VkSamplerCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, - .pNext = VK_NULL_HANDLE, - .flags = 0, - .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, - .mipLodBias = 0.f, - .anisotropyEnable = VK_FALSE, - .compareEnable = VK_FALSE, - .compareOp = VK_COMPARE_OP_NEVER, - .minLod = 0.f, - .maxLod = 0.f, - .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - .unnormalizedCoordinates = VK_FALSE, - }; - - // Nearest sampler creation - { - VkFilter filter = VK_FILTER_NEAREST; - VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - create_info.magFilter = filter, - create_info.minFilter = filter, - create_info.addressModeU = address_mode, - create_info.addressModeV = address_mode, - create_info.addressModeW = address_mode, - - VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::NEAREST])); - } - - // Linear sampler creation - { - VkFilter filter = VK_FILTER_LINEAR; - VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - create_info.magFilter = filter, - create_info.minFilter = filter, - create_info.addressModeU = address_mode, - create_info.addressModeV = address_mode, - create_info.addressModeW = address_mode, - - VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::LINEAR])); - } -} - -void bindless_model::destroy_immutable_samplers(VkDevice device) { - for (auto* sampler : samplers) { - vkDestroySampler(device, sampler, nullptr); - } -} -#else -#endif diff --git a/api-test/vk-command-buffer.cpp b/api-test/vk-command-buffer.cpp deleted file mode 100644 index bdb0e40..0000000 --- a/api-test/vk-command-buffer.cpp +++ /dev/null @@ -1,233 +0,0 @@ -#include "vk-command-buffer.hpp" - -#include - -#include "vulkan-loader.hpp" - -#include "vk-device.hpp" -#include "vk-utils.hpp" - -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 auto& bindless = vkdevice::get_render_device().get_bindingmodel(); - const auto* global_set = &bindless.sets[BindlessSetType::GLOBAL]; - // const auto global_uniforms = bindless.get_globals_uniform_buffer(); - // if (queue_type == QueueType::GRAPHICS) { - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.graphics_layout, 0, 1U, global_set, 1U, &global_uniforms.offset); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 1U, &global_uniforms.offset); - // } else if (queue_type == QueueType::ASYNC_COMPUTE) { - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 1U, &global_uniforms.offset); - // } - if (queue_type == QueueType::GRAPHICS) { - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.graphics_layout, 0, 1U, global_set, 0U, nullptr); - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, global_set, 0U, nullptr); - } else if (queue_type == QueueType::ASYNC_COMPUTE) { - vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, 0, 1U, 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_render_device().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_render_device(); - 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 auto& pipeline = vkdevice::get_render_device().get_pipeline(params.pipeline); - const auto& bindless = vkdevice::get_render_device().get_bindingmodel(); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, static_cast(BindlessSetType::INSTANCES_UNIFORMS), 1U, &bindless.sets[BindlessSetType::INSTANCES_UNIFORMS], 1U, ¶ms.uniforms_offset); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.compute_layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); - - for (uint32_t push_index = 0U; push_index < bindless_model::max_push_constants_slots; push_index++) { - vkCmdPushConstants(vk_command_buffer, bindless.compute_layout, VK_SHADER_STAGE_COMPUTE_BIT, push_index * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.params[push_index]); - } - - vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); - - 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_render_device().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); - - vkCmdSetScissor(vk_command_buffer, 0U, 1U, &scissor); - vkCmdSetViewport(vk_command_buffer, 0U, 1U, &viewport); - - // auto& device = vkdevice::get_render_device(); - // const auto& bindless = device.get_bindingmodel(); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless.layout, static_cast(BindlessSetType::GLOBAL), 1U, &bindless.sets[BindlessSetType::GLOBAL], 1U, ¶ms.uniforms_offset); - // vkCmdBindDescriptorSets(vk_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless.layout, static_cast(BindlessSetType::GLOBAL), 1U, &bindless.sets[BindlessSetType::GLOBAL], 1U, ¶ms.uniforms_offset); -} - -void graphics_command_buffer::draw(const draw_params& params) const { - auto& device = vkdevice::get_render_device(); - const auto& pipeline = device.get_pipeline(params.pipeline); - - const auto& bindless = device.get_bindingmodel(); - // vkCmdBindDescriptorSets(vk_command_buffer, pipeline.bind_point, bindless.layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); - - vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); - - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::GLOBALS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.globals_address); - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::INSTANCES * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.instances_address); - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::DRAWS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.uniforms_address); - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::VERTEX_BUFFER * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.vertex_address); - - vkCmdDraw(vk_command_buffer, params.vertex_count, params.instance_count, params.vertex_offset, 0U); -} - -void graphics_command_buffer::draw_indexed(const draw_indexed_params& params) const { - auto& device = vkdevice::get_render_device(); - const auto& pipeline = device.get_pipeline(params.pipeline); - - const auto& bindless = device.get_bindingmodel(); - // vkCmdBindDescriptorSets(vk_command_buffer, pipeline.bind_point, bindless.layout, static_cast(BindlessSetType::DRAWS_UNIFORMS), 1U, &bindless.sets[BindlessSetType::DRAWS_UNIFORMS], 1U, ¶ms.uniforms_offset); - - vkCmdBindPipeline(vk_command_buffer, pipeline.bind_point, pipeline.vk_pipeline); - - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::GLOBALS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.globals_address); - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::INSTANCES * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.instances_address); - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::DRAWS * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.uniforms_address); - vkCmdPushConstants(vk_command_buffer, bindless.graphics_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, ConstantType::VERTEX_BUFFER * bindless_model::max_push_constants_slots_size, bindless_model::max_push_constants_slots_size, ¶ms.vertex_address); - - const auto& index_buffer = device.get_buffer(params.index_buffer); - vkCmdBindIndexBuffer(vk_command_buffer, index_buffer.vk_buffer, 0U, VK_INDEX_TYPE_UINT16); - vkCmdDrawIndexed(vk_command_buffer, params.vertex_count, params.instance_count, params.index_offset, static_cast(params.vertex_offset), 0U); -} - -void graphics_command_buffer::end_renderpass() const { - vkCmdEndRendering(vk_command_buffer); -} diff --git a/api-test/vk-device.cpp b/api-test/vk-device.cpp deleted file mode 100644 index 1e7b385..0000000 --- a/api-test/vk-device.cpp +++ /dev/null @@ -1,1302 +0,0 @@ -#include "vk-device.hpp" - -#include -#include - -#include - -#define VMA_IMPLEMENTATION -#include - -#include "vk-utils.hpp" -#include "vulkan-loader.hpp" -#include "vk-command-buffer.hpp" - -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 = bindless_model::create_bindless_model(); - - auto semaphore = create_semaphore({ - .type = VK_SEMAPHORE_TYPE_TIMELINE, - }, "timeline_semaphore"); - timeline_semaphore = get_semaphore(semaphore); -} - -void vkdevice::deinit() { - vkDeviceWaitIdle(device); - - bindless_model::destroy_bindless_model(bindless); - - 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; - 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, - }; - - 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)); - - 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(desc.vs_code), - .pName = "main", - .pSpecializationInfo = nullptr, - }, - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = create_shader_module(desc.fs_code), - .pName = "main", - .pSpecializationInfo = nullptr, - }, - }; - - 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.graphics_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(desc.cs_code), - .pName = "main", - .pSpecializationInfo = nullptr, - }; - - VkComputePipelineCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .stage = stage_create_info, - .layout = bindless.compute_layout, - .basePipelineHandle = nullptr, - .basePipelineIndex = 0, - }; - - device_pipeline.bind_point = VK_PIPELINE_BIND_POINT_COMPUTE; - VKCHECK(vkCreateComputePipelines(device, nullptr, 1U, &create_info, nullptr, &device_pipeline.vk_pipeline)); - - vkDestroyShaderModule(device, stage_create_info.module, nullptr); - - 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* buffers, uint32_t count) { - assert((max_submitable_command_buffers - count) >= 0); - const auto queue_type = buffers[0].queue_type; - - // VkCommandBufferSubmitInfo command_buffers_info[count]; - VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; - - for (auto index{ 0U }; index < count; index++) { - assert(queue_type == buffers[index].queue_type); - - auto& command_buffer_info = command_buffers_info[index]; - command_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; - command_buffer_info.pNext = nullptr; - command_buffer_info.commandBuffer = buffers[index].vk_command_buffer; - command_buffer_info.deviceMask = 0U; - } - - VkSubmitInfo2 submit_info{ - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .pNext = nullptr, - .flags = 0U, - .waitSemaphoreInfoCount = 0U, - .pWaitSemaphoreInfos = nullptr, - .commandBufferInfoCount = count, - .pCommandBufferInfos = command_buffers_info, - }; - - 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* buffers, uint32_t count) { - assert((max_submitable_command_buffers - count) >= 0); - const auto queue_type = buffers[0].queue_type; - - // VkCommandBufferSubmitInfo command_buffers_info[count]; - VkCommandBufferSubmitInfo command_buffers_info[max_submitable_command_buffers]; - - for (auto index{ 0U }; index < count; index++) { - assert(queue_type == buffers[index].queue_type); - - 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; - } - - const auto& surface = get_surface(surface_handle); - auto& 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 = vkdevice::get_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* 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 (auto index{ 0U }; index < count; index++) { - buffers[index].vk_command_buffer = command_buffers[index]; - 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); - } - } -} - -VkShaderModule vkdevice::create_shader_module(const std::span& shader_code) { - VkShaderModule shader_module; - const auto& code = shader_code; - VkShaderModuleCreateInfo create_info{ - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .flags = 0U, - .codeSize = code.size(), - .pCode = reinterpret_cast(code.data()), - }; - - VKCHECK(vkCreateShaderModule(device, &create_info, nullptr, &shader_module)); - return shader_module; -} - -void vkdevice::create_swapchain(const surface_desc& desc, device_surface& surface) { - VkSurfaceKHR vk_surface = surface.vk_surface; - - 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], - }); - } -} - -// ----------------- 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() { - VmaAllocatorCreateInfo create_info{ - .flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT, - .physicalDevice = physical_device, - .device = device, - .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()); - - 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 - { - VkPhysicalDeviceProperties2 props{ - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, - .pNext = nullptr, - }; - vkGetPhysicalDeviceProperties2(physical_dev, &props); - - VkPhysicalDeviceLimits* limits = &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, - }; - - 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_render_device(); - 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; - 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)); - } - - 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], - .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], - .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_render_device(); - 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_render_device().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_render_device(); - // 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/api-test/vk-utils.cpp b/api-test/vk-utils.cpp deleted file mode 100644 index 4df6424..0000000 --- a/api-test/vk-utils.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "vk-utils.hpp" - -#include - -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; -} diff --git a/build.bat b/build.bat index c2c9018..674eaf3 100644 --- a/build.bat +++ b/build.bat @@ -41,13 +41,13 @@ set DEBUG_L_FLAGS= set RELEASE_C_FLAGS= if %MSVC% EQU 1 ( - set C_FLAGS=/nologo /W4 /WX /Zi /Fo:%BUILD_DIR%\ /Iinclude /Iinclude\api-test /I%VULKAN_SDK%\Include /external:W0 /external:Ithirdparty /external:Ithirdparty\imgui /std:c++20 /DNOMINMAX /EHsc /c /Tp + set C_FLAGS=/nologo /W4 /WX /Zi /Fo:%BUILD_DIR%\ /Iinclude /I%VULKAN_SDK%\Include /external:W0 /external:Ithirdparty /external:Ithirdparty\imgui /std:c++20 /DNOMINMAX /EHsc /c /Tp set DEBUG_C_FLAGS=/DDEBUG /Od set RELEASE_C_FLAGS=/DNDEBUG /O2 set DEBUG_L_FLAGS=/DEBUG ) else ( - set C_FLAGS=--target=x86_64-pc-windows-msvc -pedantic -I include -I include\api-test -I %VULKAN_SDK%\Include -isystem thirdparty -isystem thirdparty\imgui -std=c++20 -DNOMINMAX -c -msse4.1 -Wno-missing-designated-field-initializers + set C_FLAGS=--target=x86_64-pc-windows-msvc -pedantic -I include -I %VULKAN_SDK%\Include -isystem thirdparty -isystem thirdparty\imgui -std=c++20 -DNOMINMAX -c -msse4.1 -Wno-missing-designated-field-initializers set DEBUG_C_FLAGS=-DDEBUG -g -O0 set RELEASE_C_FLAGS=-DNDEBUG -O2 @@ -76,19 +76,19 @@ if 0 EQU 1 ( :: set src=main dx12-device dx12-command-buffer :: (for %%s in (%api%) do ( :: call set OBJS=%%OBJS%% %BUILD_DIR%\%%s.obj -:: echo %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% api-test\%%s.cpp -:: %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% api-test\%%s.cpp +:: echo %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% src\%%s.cpp +:: %C_COMPILER% /Fd:%BUILD_DIR%\%%s.pdb %C_FLAGS% src\%%s.cpp :: )) :: link multiple objs :: link %L_FLAGS% /OUT:%BUILD_DIR%\main.exe %OBJS% kernel32.lib user32.lib :: compiles the project as a single compilation unit if %MSVC% EQU 1 ( - echo %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% api-test\main.cpp - %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% api-test\main.cpp + echo %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% src\main.cpp + %C_COMPILER% /Fd:%BUILD_DIR%\main.pdb %C_FLAGS% src\main.cpp ) else ( - echo %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% api-test\main.cpp - %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% api-test\main.cpp + echo %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% src\main.cpp + %C_COMPILER% -o %BUILD_DIR%\main.obj %C_FLAGS% src\main.cpp ) link %L_FLAGS% /OUT:%BUILD_DIR%\main.exe %BUILD_DIR%\main.obj kernel32.lib user32.lib shlwapi.lib diff --git a/include/api-test/buffer.hpp b/include/api-test/buffer.hpp deleted file mode 100644 index 64c4881..0000000 --- a/include/api-test/buffer.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -#include "handle.hpp" - -struct device_buffer; - -class buffer { -public: - buffer(handle handle); - -private: - handle handle; - -}; diff --git a/include/api-test/dx12-command-buffer.hpp b/include/api-test/dx12-command-buffer.hpp deleted file mode 100644 index e9de39a..0000000 --- a/include/api-test/dx12-command-buffer.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include "handle.hpp" -#include "dx12-device-types.hpp" - -namespace dx12 { - struct command_buffer { - void start() const; - void stop() const; - - // void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; - - void copy(handle src_buffer, handle dst_texture, uint64_t offset = 0) const; - - ID3D12CommandAllocator* command_allocator; - ID3D12GraphicsCommandList* dx12_command_buffer; - dx12::QueueType queue_type; - }; - - struct graphics_command_buffer: public command_buffer { - // void dispatch(const dispatch_params& params) const; - - // void begin_renderpass(const renderpass_params& params) const; - // void draw(const draw_params& params) const; - // void draw_indexed(const draw_indexed_params& params) const; - // void end_renderpass() const; - }; -} diff --git a/include/api-test/dx12-device-types.hpp b/include/api-test/dx12-device-types.hpp deleted file mode 100644 index 4b2fc42..0000000 --- a/include/api-test/dx12-device-types.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -#include -#include -#include - -#include - -namespace dx12 { - enum class QueueType : uint32_t { - GRAPHICS, - ASYNC_COMPUTE, - TRANSFER, - MAX, - }; - - struct buffer_desc { - uint32_t size; - bool map; - - D3D12_RESOURCE_STATES states; - D3D12_RESOURCE_FLAGS usages; - D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_DEFAULT; - }; - - struct device_buffer { - ID3D12Resource* resource; - - D3D12MA::Allocation* alloc; - uint32_t size; - void* mapped_ptr = nullptr; - }; - - - struct texture_desc { - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - - D3D12_RESOURCE_STATES states; - D3D12_RESOURCE_FLAGS usages; - DXGI_FORMAT format; - D3D12_RESOURCE_DIMENSION type; - }; - - struct device_texture { - ID3D12Resource* resource; - D3D12MA::Allocation* alloc; - - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - uint64_t row_pitch = 1U; - - DXGI_FORMAT format; - - }; - - struct surface_desc { - HWND window_handle; - DXGI_FORMAT surface_format; - DXGI_SWAP_EFFECT present_mode; - DXGI_USAGE usages; - uint32_t image_count = surface_desc::default_image_count; - - static constexpr uint32_t max_image_count = 3U; - static constexpr uint32_t default_image_count = 3U; - }; - - struct device_surface { - IDXGISwapChain1* swapchain; - }; -} diff --git a/include/api-test/dx12-device.hpp b/include/api-test/dx12-device.hpp deleted file mode 100644 index baa5b60..0000000 --- a/include/api-test/dx12-device.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include -#include - -#include "freelist.hpp" -#include "dx12-device-types.hpp" - -#include "D3D12MemAlloc.h" - -namespace dx12 { - struct command_buffer; - - class device { - struct queue { - ID3D12CommandQueue* dx_queue; - D3D12_COMMAND_LIST_TYPE type; - }; - public: - void init(); - - static inline device& get_render_device() { - return render_device; - } - - handle create_surface(const surface_desc& desc); - - handle create_buffer(const buffer_desc& desc); - - handle create_texture(const texture_desc& desc); - - void create_graphics_pipeline() {}; - - void create_compute_pipeline() {}; - - void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type); - - - [[nodiscard]] inline device_surface& get_surface(handle handle) { - return surfaces[handle]; - } - - [[nodiscard]] inline device_buffer& get_buffer(handle handle) { - return buffers[handle]; - } - - [[nodiscard]] inline device_texture& get_texture(handle handle) { - return textures[handle]; - } - - [[nodiscard]] inline ID3D12Device* get_device() const { - return device; - } - - uint32_t submit(command_buffer* buffers, uint32_t count); - - void wait(); - - private: - IDXGIFactory3* factory; - IDXGIAdapter* adapter; - ID3D12Debug* debug_interface; - - D3D12MA::Allocator* allocator; - - ID3D12Device* device; - ID3D12Fence* fence; - uint64_t fence_value = 0U; - queue queues[static_cast(QueueType::MAX)]; - - freelist surfaces; - freelist buffers; - freelist textures; - - static constexpr size_t max_allocable_command_buffers = 16U; - static constexpr size_t max_submitable_command_buffers = 16U; - - static class device render_device; - - struct bindless_model { - void init(); - - [[nodiscard]] inline ID3D12DescriptorHeap* const* get_heaps() const { - return &resources_heap; - } - - ID3D12DescriptorHeap* resources_heap; - ID3D12DescriptorHeap* samplers_heap; - } model; - - public: - [[nodiscard]] static inline const device::bindless_model& get_bindless_model() { - return render_device.model; - } - }; - -} diff --git a/include/api-test/freelist.hpp b/include/api-test/freelist.hpp deleted file mode 100644 index cbcd56d..0000000 --- a/include/api-test/freelist.hpp +++ /dev/null @@ -1,151 +0,0 @@ -#pragma once -#include -#include - -#include "handle.hpp" - -static constexpr uint32_t default_element_count = 1024U; - -template -class freelist { - public: - - freelist() { - grow(initial_size); - } - - handle add(const T& item) { - // auto id = elements[0U].next_free; - auto id = next_free_id; - - if (id == freelist::invalid_id) { - grow(elements.size()); - - // id = elements[0U].next_free; - id = next_free_id; - } - - auto& element = elements[id]; - - next_free_id = element.next_free; - // elements[0U].next_free = element.next_free; - element.item = std::move(item); - - return { id, ++element.generation }; - } - - void remove(handle handle) { - assert(handle.generation == elements[handle.id].generation); - // elements[handle.id].next_free = elements[0U].next_free; - // elements[0U].next_free = handle.id; - elements[handle.id].next_free = next_free_id; - next_free_id = handle.id; - } - - T& operator[](handle handle) { - assert(handle.generation == elements[handle.id].generation); - return elements[handle.id].item; - } - - const T& operator[](handle handle) const { - assert(handle.generation == elements[handle.id].generation); - return elements[handle.id].item; - } - - static constexpr uint32_t invalid_id = UINT32_MAX; - -private: - void grow(size_t grow_size) { - auto size = elements.size(); - uint32_t next_free = static_cast(size); - next_free_id = next_free; - - elements.reserve(size + grow_size); - - for (auto id { 0U }; id < initial_size; id++) { - elements.push_back( - { - .next_free = static_cast(++next_free % initial_size), - } - ); - } - - elements.back().next_free = freelist::invalid_id; - } - - struct element { - union { - T item; - uint32_t next_free = freelist::invalid_id; - }; - uint32_t generation = 0U; - }; - - std::vector elements; - uint32_t next_free_id; -}; - -template -class idlist { - public: - - idlist() { - grow(initial_size); - } - - handle add() { - // auto id = elements[0U].next_free; - auto id = next_free_id; - - if (id == idlist::invalid_id) { - grow(elements.size()); - - // id = elements[0U].next_free; - id = next_free_id; - } - - auto& element = elements[id]; - next_free_id = element.next_free; - elements[0U].next_free = element.next_free; - element.next_free = idlist::invalid_id; - - return { id, ++element.generation }; - } - - void remove(handle handle) { - assert(handle.generation == elements[handle.id].generation); - // elements[handle.id].next_free = elements[0U].next_free; - // elements[0U].next_free = handle.id; - elements[handle.id].next_free = next_free_id; - next_free_id = handle.id; - } - - static constexpr uint32_t invalid_id = UINT32_MAX; - -private: - void grow(size_t grow_size) { - auto size = elements.size(); - uint32_t next_free = static_cast(size); - next_free_id = next_free; - - elements.reserve(size + grow_size); - - for (auto id { 0U }; id < initial_size; id++) { - elements.push_back( - { - .next_free = static_cast(++next_free% initial_size), - } - ); - } - - elements.back().next_free = idlist::invalid_id; - } - - struct element { - uint32_t next_free = idlist::invalid_id; - uint32_t generation = 0U; - }; - - std::vector elements; - uint32_t next_free_id; -}; diff --git a/include/api-test/handle.hpp b/include/api-test/handle.hpp deleted file mode 100644 index 2c52c01..0000000 --- a/include/api-test/handle.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -// template -// struct handle { -// uint32_t id = handle::invalid_id; -// -// [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } -// -// static constexpr uint32_t invalid_id = -1U; -// }; - -template -struct handle { - uint32_t id = invalid_id; - uint32_t generation = 0U; - - [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } - - static constexpr uint32_t invalid_id = UINT32_MAX; - - // static constexpr handle invalid_handle {}; -}; diff --git a/include/api-test/resource-manager.hpp b/include/api-test/resource-manager.hpp deleted file mode 100644 index f414367..0000000 --- a/include/api-test/resource-manager.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "handle.hpp" -#include "freelist.hpp" -#include "texture.hpp" -#include "buffer.hpp" - -class resourcemanager { -public: - - handle create_texture(const texture_desc& desc); - - handle create_buffer(const buffer_desc& desc); - - const texture& get_texture(handle handle); - - const buffer& get_buffer(handle handle); - -private: - freelist textures; - freelist buffers; -}; diff --git a/include/api-test/texture.hpp b/include/api-test/texture.hpp deleted file mode 100644 index 59bfec1..0000000 --- a/include/api-test/texture.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include - -#include "handle.hpp" - -struct device_texture; - -class texture { -public: - texture(handle handle); - -private: - handle handle; -}; diff --git a/include/api-test/vk-bindless.hpp b/include/api-test/vk-bindless.hpp deleted file mode 100644 index a5686ff..0000000 --- a/include/api-test/vk-bindless.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include - -#include - -#include "handle.hpp" - -enum BindlessSetType : uint32_t { - GLOBAL, - INSTANCES_UNIFORMS, - DRAWS_UNIFORMS, - MAX, -}; - -enum ConstantType : uint32_t { - GLOBALS, - INSTANCES, - DRAWS, - VERTEX_BUFFER -}; - -enum SamplerType : uint32_t { - NEAREST, - LINEAR, - MAX_SAMPLER, -}; - -struct device_buffer; - -struct bindless_model { -#ifndef USE_VK_DESCRIPTOR_BUFFER - [[nodiscard]] device_buffer& get_draws_uniform_buffer() const; - [[nodiscard]] device_buffer& get_globals_uniform_buffer() const; - - static bindless_model create_bindless_model(); - - static void destroy_bindless_model(bindless_model& bindless); - - VkPipelineLayout graphics_layout; - VkPipelineLayout compute_layout; - VkDescriptorSet sets[BindlessSetType::MAX]; - -private: - static constexpr size_t max_push_constants_size = 128ULL; - -public: - static constexpr size_t max_push_constants_slots_size = 8U; - static constexpr size_t max_push_constants_slots = max_push_constants_size / max_push_constants_slots_size; - -private: - VkDescriptorSetLayout sets_layout[BindlessSetType::MAX]; - VkDescriptorPool descriptor_pool; - handle globals_uniform_buffer_handle; - handle instances_uniform_buffer_handle; - handle draws_uniform_buffer_handle; - - static constexpr size_t descriptor_pool_allocable_sets_count = 64U; - static constexpr uint32_t set_descriptors_count = 1024U; - - void create_layout(VkDevice device); - void create_descriptor_pool(VkDevice device); - void allocate_sets(VkDevice device); - - void destroy_descriptor_pool(VkDevice device); - - void create_immutable_samplers(VkDevice device); - - void destroy_immutable_samplers(VkDevice device); - - VkSampler samplers[SamplerType::MAX_SAMPLER]; - - static constexpr size_t globals_uniform_buffer_size = 64ULL * 1024ULL; - static constexpr size_t instances_uniform_buffer_size = 64ULL * 1024ULL; - static constexpr size_t draws_uniform_buffer_size = 64ULL * 1024ULL; -#else - VkPipelineLayout layout; - VkDescriptorSetLayout sets_layout[BindlessSetType::MAX]; - - static constexpr size_t descriptor_pool_allocable_sets_count = 64U; - static constexpr uint32_t set_descriptors_count[BindlessSetType::MAX]{ 1024U }; - - static bindless_model create_bindless_model(VkDevice device); - - static void destroy_bindless_model(VkDevice device, bindless_model& bindless); - - private: - void create_layout(VkDevice device); - - handle storage_image_descriptors; - handle sampled_image_descriptors; -#endif -}; diff --git a/include/api-test/vk-command-buffer.hpp b/include/api-test/vk-command-buffer.hpp deleted file mode 100644 index 08652fd..0000000 --- a/include/api-test/vk-command-buffer.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "handle.hpp" - -#include "vec3.hpp" - -#include "vk-device-types.hpp" - -struct device_texture; -struct device_buffer; -struct device_pipeline; - -struct dispatch_params { - enum class PARAM_BINDING : uint32_t { - PARAM1, - PARAM2, - PARAM3, - PARAM4, - PARAM5, - PARAM6, - PARAM7, - PARAM8, - MAX - }; - - handle pipeline; - vec3u group_size; - vec3u local_group_size; - uint64_t params[static_cast(PARAM_BINDING::MAX)]; -}; - -struct renderpass_params { -private: - struct rect { - int32_t x; - int32_t y; - uint32_t width; - uint32_t height; - }; - -public: - rect render_area; - std::span> color_attachments; -}; - -struct draw_params { - handle pipeline; - handle index_buffer; - uint32_t vertex_count; - uint32_t vertex_offset; - uint32_t instance_count; - uint64_t globals_address = 0U; // TODO: This is probably stupid and should be set elsewhere once ??? - uint64_t instances_address = 0U; - uint64_t uniforms_address = 0U; - uint64_t vertex_address = 0U; -}; - -struct draw_indexed_params { - handle pipeline; - handle index_buffer; - uint32_t vertex_count; - uint32_t vertex_offset; - uint32_t index_offset; - uint32_t instance_count; - uint64_t globals_address = 0U; // TODO: This is probably stupid and should be set elsewhere once ??? - uint64_t instances_address = 0U; - uint64_t uniforms_address = 0U; - uint64_t vertex_address = 0U; -}; - -struct command_buffer { - void start() const; - void stop() const; - - void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; - - void copy(handle buffer_handle, handle texture_handle, uint64_t offset = 0) const; - - VkCommandBuffer vk_command_buffer; - QueueType queue_type; -}; - -// General purpose queue -struct graphics_command_buffer: public command_buffer { - void dispatch(const dispatch_params& params) const; - - void begin_renderpass(const renderpass_params& params) const; - void draw(const draw_params& params) const; - void draw_indexed(const draw_indexed_params& params) const; - void end_renderpass() const; -}; - -struct compute_command_buffer: public command_buffer { - void dispatch(const dispatch_params& params); -}; - -struct transfer_command_buffer: public command_buffer { -}; diff --git a/include/api-test/vk-device-types.hpp b/include/api-test/vk-device-types.hpp deleted file mode 100644 index eddf40c..0000000 --- a/include/api-test/vk-device-types.hpp +++ /dev/null @@ -1,213 +0,0 @@ -#pragma once - -#include - -#include - -#include "freelist.hpp" - -using VmaAllocation = struct VmaAllocation_T*; - -enum class QueueType : uint32_t { - GRAPHICS, - ASYNC_COMPUTE, - TRANSFER, - MAX, -}; - -struct texture_desc { - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - VkImageUsageFlags usages; - VkFormat format; - VkImageType type; - VkImage vk_image = nullptr; - const char* name = nullptr; - - static constexpr auto max_mips = 16U; -}; - -struct device_texture { - void init(const texture_desc& desc); - - void release(); - - void create_views(); - - [[nodiscard]] uint32_t get_storage_index() const { - assert(storage_index.id != handle::invalid_id); - return storage_index.id; - } - - [[nodiscard]] uint32_t get_sampled_index() const { - assert(sampled_index.id != handle::invalid_id); - return sampled_index.id; - } - - VkImage vk_image = nullptr; - VkImageView whole_view = nullptr; - VkImageView mips_views[texture_desc::max_mips] = { nullptr }; - VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkPipelineStageFlags2 stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkAccessFlags2 access = VK_ACCESS_2_NONE; - VkFormat format = VK_FORMAT_UNDEFINED; - VkImageAspectFlags aspects = VK_IMAGE_ASPECT_NONE_KHR; - - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - - private: - handle storage_index; - handle sampled_index; - - VmaAllocation alloc = nullptr; - - static idlist<> storage_indices; - static idlist<> sampled_indices; -}; - - -struct sampler_desc { - VkFilter mag_filter = VK_FILTER_NEAREST; - VkFilter min_filter = VK_FILTER_NEAREST; - VkSamplerMipmapMode mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - VkSamplerAddressMode address_mode_u = VK_SAMPLER_ADDRESS_MODE_REPEAT; - VkSamplerAddressMode address_mode_v = VK_SAMPLER_ADDRESS_MODE_REPEAT; - VkSamplerAddressMode address_mode_w = VK_SAMPLER_ADDRESS_MODE_REPEAT; - float mip_lod_bias = 0.f; - VkBool32 anisotropy = VK_FALSE; - float max_anisotropy = 0.f; - VkBool32 compare_enabled = VK_FALSE; - VkCompareOp compare_op = VK_COMPARE_OP_NEVER; - float min_lod = 0.f; - float max_lod = 0.f; - VkBorderColor border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - VkBool32 unnomalized_coords = VK_FALSE; -}; - -struct device_sampler { - void init(const sampler_desc& desc); - - VkSampler vk_sampler = nullptr; - - [[nodiscard]] uint32_t get_sampler_index() const { - return sampler_index.id; - } - - private: - handle sampler_index; - - static idlist<> sampler_indices; -}; - - -struct buffer_desc { - size_t size; - VkBufferUsageFlags usages; - VkMemoryPropertyFlags memory_properties; - uint32_t memory_usage; -}; - -#define ALIGN(value, alignment) \ - (((value) + ((alignment) - 1)) & ~((alignment) - 1)) - -struct device_buffer { - template - T* allocate() { - // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; - size_t alloc_size = ALIGN(sizeof(T), 16); - if (offset + alloc_size > size) { - reset(); - } - - auto* addr = (T*)(static_cast(mapped_ptr) + offset); - offset += alloc_size; - return addr; - } - - void* allocate(uint64_t alloc_size) { - // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; - alloc_size = ALIGN(alloc_size, 16); - if (offset + alloc_size > size) { - reset(); - } - - auto* addr = (void*)(static_cast(mapped_ptr) + offset); - offset += alloc_size; - return addr; - } - - void reset() { - offset = 0U; - } - - uint64_t offset = 0U; - VkBuffer vk_buffer; - VmaAllocation alloc; - VkDeviceAddress device_address = 0U; - void* mapped_ptr; - size_t size; -}; - -struct graphics_pipeline_desc { - std::span vs_code; - std::span fs_code; - std::span color_attachments_format; - VkFormat depth_attachment_format; - VkFormat stencil_attachment_format; - const char* name; -}; - -struct compute_pipeline_desc { - std::span cs_code; - const char* name; -}; - -struct device_pipeline { - VkPipeline vk_pipeline; - VkPipelineBindPoint bind_point; -}; - -struct semaphore_desc { - VkSemaphoreType type; - uint64_t initial_value = 0U; -}; - -struct device_semaphore { - VkSemaphore vk_semaphore = nullptr; - uint64_t value; -}; - - -typedef struct HWND__* HWND; - -struct surface_desc { - HWND window_handle; - VkSurfaceFormatKHR surface_format; - VkPresentModeKHR present_mode; - VkImageUsageFlags usages; - uint32_t image_count = surface_desc::default_image_count; - - static constexpr uint32_t max_image_count = 3U; - static constexpr uint32_t default_image_count = 3U; -}; - -struct device_surface { - VkSurfaceKHR vk_surface; - VkSwapchainKHR vk_swapchain; - VkSurfaceFormatKHR surface_format; - - handle swapchain_images[surface_desc::max_image_count]; - uint32_t image_index; - uint32_t image_count; - uint32_t frame_index = 0U; - - handle acquire_semaphores[surface_desc::max_image_count]; - handle submit_semaphores[surface_desc::max_image_count]; - - uint32_t acquire_image_index(); -}; diff --git a/include/api-test/vk-device.hpp b/include/api-test/vk-device.hpp deleted file mode 100644 index 1b04bb3..0000000 --- a/include/api-test/vk-device.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "freelist.hpp" -#include "vk-device-types.hpp" -#include "vk-bindless.hpp" - -using VmaAllocator = struct VmaAllocator_T*; - -struct command_buffer; -class window; - -class vkdevice { - struct queue { - VkQueue vk_queue; - uint32_t index; - VkQueueFlags usages; - VkCommandPool command_pool; - }; - - public: - void init(); - void deinit(); - - static inline vkdevice& get_render_device() { - return render_device; - } - - handle create_texture(const texture_desc& desc); - - handle create_sampler(const sampler_desc& desc); - - handle create_buffer(const buffer_desc& desc); - - handle create_graphics_pipeline(const graphics_pipeline_desc& desc); - - handle create_compute_pipeline(const compute_pipeline_desc& desc); - - handle create_surface(const surface_desc& desc); - - handle create_semaphore(const semaphore_desc& desc, const char* name); - - void destroy_texture(handle handle); - - void destroy_sampler(handle handle); - - void destroy_buffer(handle handle); - - void destroy_pipeline(handle handle); - - void destroy_semaphore(handle handle); - - void destroy_surface(handle handle); - - template - void allocate_command_buffers(buffer_type* buffers, size_t count, QueueType queue_type, const char* name) { - allocate_command_buffers(static_cast(buffers), count, queue_type, name); - } - - [[nodiscard]] inline device_texture& get_texture(handle handle) { - return textures[handle]; - } - - [[nodiscard]] inline device_sampler& get_sampler(handle handle) { - return samplers[handle]; - } - - [[nodiscard]] inline device_buffer& get_buffer(handle handle) { - return buffers[handle]; - } - - [[nodiscard]] inline const device_pipeline& get_pipeline(handle handle) const { - return pipelines[handle]; - } - - [[nodiscard]] inline device_surface& get_surface(handle handle) { - return surfaces[handle]; - } - - [[nodiscard]] inline device_semaphore& get_semaphore(handle handle) { - return semaphores[handle]; - } - - [[nodiscard]] inline const bindless_model& get_bindingmodel() const { - return bindless; - } - - inline VkDevice get_device() { - return device; - } - - inline VmaAllocator get_allocator() { - return gpu_allocator; - } - - // uint64_t submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle); - uint32_t acquire_image_index(handle surface_handle); - uint64_t submit_before_present(handle surface_handle, command_buffer* buffers, uint32_t count); - uint64_t submit(command_buffer* buffers, uint32_t count); - - void present(handle surface_handle); - - void wait(); - - private: - vkdevice() = default; - ~vkdevice() = default; - - void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type, const char* name); - - VkShaderModule create_shader_module(const std::span& shader_code); - - void create_swapchain(const surface_desc& desc, device_surface& surface); - - // TODO: Wrap in a struct called adapter ? - void create_instance(); - - void create_device(); - - void create_memory_allocator(); - - void create_command_pools(); - - void pick_physical_device(); - - static bool device_support_features(VkPhysicalDevice physical_dev); - - void create_debug_layer_callback(); - - queue queues[static_cast(QueueType::MAX)]; - - VkInstance instance; - VkPhysicalDevice physical_device; - VkDevice device; - - VmaAllocator gpu_allocator; - - bindless_model bindless; - - static constexpr size_t max_allocable_command_buffers = 16; - static constexpr size_t max_submitable_command_buffers = 16; - - freelist textures; - freelist samplers; - freelist buffers; - freelist pipelines; - freelist surfaces; - freelist semaphores; - - device_semaphore timeline_semaphore; - - static vkdevice render_device; - -#ifdef _DEBUG - VkDebugUtilsMessengerEXT debug_messenger; -#endif // _DEBUG -}; diff --git a/include/api-test/vk-utils.hpp b/include/api-test/vk-utils.hpp deleted file mode 100644 index 205e103..0000000 --- a/include/api-test/vk-utils.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include - -#ifdef _DEBUG -#define VKCHECK(result) assert((result) == VK_SUCCESS) -#else -#define VKCHECK(result) result -#endif - -VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT* data, - void*); diff --git a/include/buffer.hpp b/include/buffer.hpp new file mode 100644 index 0000000..64c4881 --- /dev/null +++ b/include/buffer.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +#include "handle.hpp" + +struct device_buffer; + +class buffer { +public: + buffer(handle handle); + +private: + handle handle; + +}; diff --git a/include/bvh-node.hpp b/include/bvh-node.hpp deleted file mode 100644 index 525e1c8..0000000 --- a/include/bvh-node.hpp +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef __BVH_NODE_HPP_ -#define __BVH_NODE_HPP_ - -#include -#include -#include - -#include "aabb.hpp" -// #include "sphere.hpp" -#include "triangle.hpp" - -struct bvh_node { - aabb bounding_box; - - int32_t next_id = -1; - int32_t primitive_id = -1; - uint32_t padding[2]; -}; - -struct packed_bvh_node { - float min[3]; - int32_t next_id = -1; - float max[3]; - int32_t primitive_id = -1; -}; - -struct temp_node : public bvh_node { - int32_t left_id; - int32_t df_id; -}; - -class bvh { -public: - // bvh(std::vector& spheres, std::vector& packed_nodes) - // :spheres(spheres) { - // packed_nodes.resize(2 * spheres.size() - 1); - // temp_nodes = std::vector(2 * spheres.size() - 1); - // leafs = std::vector(spheres.size()); - - // for (uint32_t id = 0; id < spheres.size(); id++) { - // leafs[id].bounding_box = aabb(spheres[id].center, spheres[id].radius); - // leafs[id].primitive_id = id; - // } - - // temp_nodes[0] = temp_node(); - - // temp_nodes[0].bounding_box = compute_bounds(0, spheres.size()); - // subdivide(0, 0, spheres.size()); - - // set_depth_first_order(); - - // for (uint32_t id = 0; id < temp_nodes.size(); id++) { - // auto old_node = temp_nodes[id]; - // auto &node = packed_nodes[old_node.df_id]; - - // node.primitive_id = old_node.primitive_id; - - // node.min[0] = old_node.bounding_box.minimum.v[0]; - // node.min[1] = old_node.bounding_box.minimum.v[1]; - // node.min[2] = old_node.bounding_box.minimum.v[2]; - - // node.max[0] = old_node.bounding_box.maximum.v[0]; - // node.max[1] = old_node.bounding_box.maximum.v[1]; - // node.max[2] = old_node.bounding_box.maximum.v[2]; - - // if (old_node.next_id != -1) { - // node.next_id = temp_nodes[old_node.next_id].df_id; - // } - // } - - // // exporter(); - // } - - bvh(std::vector& triangles, std::vector& packed_nodes) - :triangles(triangles) { - packed_nodes.resize(2 * triangles.size() - 1); - temp_nodes = std::vector(2 * triangles.size() - 1); - leafs = std::vector(triangles.size()); - - for (uint32_t id = 0; id < triangles.size(); id++) { - leafs[id].bounding_box = aabb(triangles[id]); - leafs[id].primitive_id = id; - } - - temp_nodes[0] = temp_node(); - - temp_nodes[0].bounding_box = compute_bounds(0, triangles.size()); - subdivide(0, 0, triangles.size()); - - set_depth_first_order(); - - for (uint32_t id = 0; id < temp_nodes.size(); id++) { - auto old_node = temp_nodes[id]; - auto &node = packed_nodes[old_node.df_id]; - - node.primitive_id = old_node.primitive_id; - - node.min[0] = old_node.bounding_box.minimum.v[0]; - node.min[1] = old_node.bounding_box.minimum.v[1]; - node.min[2] = old_node.bounding_box.minimum.v[2]; - - node.max[0] = old_node.bounding_box.maximum.v[0]; - node.max[1] = old_node.bounding_box.maximum.v[1]; - node.max[2] = old_node.bounding_box.maximum.v[2]; - - if (old_node.next_id != -1) { - node.next_id = temp_nodes[old_node.next_id].df_id; - } - } - - // exporter(); - } - - //------------------------- - // BVH exporter for graphviz - //------------------------- - void exporter() { - std::cout << "digraph bvh {" << std::endl; - - traverse_depth_first(temp_nodes, 0); - - // traverse_depth_first_ordered(-1, 0); - - std::cout << "}" << std::endl; - } - - bool traverse_depth_first(std::vector& nodes, int32_t id) { - if (id <= 0) { - std::cout << ";" << std::endl; - return false; - } - - std::cout << " -> " << id; - if (traverse_depth_first(nodes, nodes[id].left_id)) { - std::cout << "\t " << id; - traverse_depth_first(nodes, nodes[id].left_id + 1); - } - - return true; - } - - int32_t traverse_depth_first_ordered(std::vector& nodes, int32_t parent_id, int32_t id) { - if (id == -1) { - return -1; - } - - if (nodes[id].primitive_id == -1) { - int32_t left = id + 1; - int32_t next_id; - - std::cout << "\t " << parent_id << " -> " << id << ";\n"; - next_id = traverse_depth_first_ordered(nodes, id, left); - - if (next_id != -1) { - return traverse_depth_first_ordered(nodes, id, next_id); - } - } else if (nodes[id].primitive_id != -1 && nodes[id].next_id != -1) { - std::cout << "\t " << parent_id << " -> " << id << ";\n"; - return nodes[id].next_id; - } else { - std::cout << "\t " << parent_id << " -> " << id << ";\n"; - } - - return -1; - } - - std::vector temp_nodes; - std::vector leafs; - - // std::vector& spheres; - std::vector& triangles; - - uint32_t next_node_id = 0; - -private: - - static constexpr uint32_t buckets_count = 12; - - aabb compute_bounds(uint32_t begin, uint32_t end) { - aabb global_box = aabb(); - - for (uint32_t id = begin; id < end; id++) { - global_box.union_with(leafs[id].bounding_box); - } - - return global_box; - } - - void subdivide(uint32_t parent_id, uint32_t begin, uint32_t end) { - size_t count = end - begin; - if (count == 1) { - temp_nodes[parent_id] = leafs[begin]; - return; - } - - auto left_id = ++next_node_id; - auto right_id = ++next_node_id; - - temp_nodes[parent_id].left_id = left_id; - - if (count == 2) { - temp_nodes[left_id] = leafs[begin]; - temp_nodes[right_id] = leafs[begin + 1]; - } else { - auto parent_bb = temp_nodes[parent_id].bounding_box; - int32_t split_axis = parent_bb.maximum_axis(); - - if (count <= 4) { - // Subdivide the node by splitting the set in two equal parts - std::sort(leafs.begin() + begin, leafs.begin() + end, - // [&](const bvh_node& a, const bvh_node& b) { - // return spheres[a.primitive_id].center[split_axis] < spheres[b.primitive_id].center[split_axis]; - // } - [&](const bvh_node& a, const bvh_node& b) { - return triangles[a.primitive_id].center()[split_axis] < triangles[b.primitive_id].center()[split_axis]; - } - ); - - temp_nodes[left_id].bounding_box = compute_bounds(begin, begin + (count / 2)); - temp_nodes[right_id].bounding_box = compute_bounds(begin + (count / 2), end); - - subdivide(left_id, begin, begin + (count / 2)); - subdivide(right_id, begin + (count / 2), end); - } else { - // Subdivide based on SAH - struct Bucket { - uint32_t count = 0; - aabb bb; - }; - Bucket buckets[buckets_count]; - - // Split the set in N spatial buckets - // Simplify the optimal split axis search to just an axis between each bucket - aabb centroid_bounds; - - for (size_t i = begin; i < end; i++) { - auto primitive = triangles[leafs[i].primitive_id]; - centroid_bounds.union_with(primitive.center()); - // auto primitive = spheres[leafs[i].primitive_id]; - // centroid_bounds.union_with(primitive.center); - } - - float split_axis_size = centroid_bounds.maximum[split_axis] - centroid_bounds.minimum[split_axis]; - for (size_t i = begin; i < end; i++) { - auto primitive = triangles[leafs[i].primitive_id]; - auto normalized_offset = (primitive.center()[split_axis] - centroid_bounds.minimum[split_axis]) / split_axis_size; - // auto primitive = spheres[leafs[i].primitive_id]; - // auto normalized_offset = (primitive.center[split_axis] - centroid_bounds.minimum[split_axis]) / split_axis_size; - uint32_t bucket_index = normalized_offset * buckets_count; - if (bucket_index == buckets_count) { - bucket_index -= 1; - } - - buckets[bucket_index].count++; - buckets[bucket_index].bb.union_with(leafs[i].bounding_box); - } - - // Compute each potential split axis cost - float buckets_cost[buckets_count - 1] = { 0.f }; - for (size_t bucket_index = 0; bucket_index < buckets_count - 1; bucket_index++) { - aabb right_side_bb, left_side_bb; - float right_side_count = 0, left_side_count = 0; - - for (size_t i = 0; i <= bucket_index; i++) { - left_side_bb.union_with(buckets[i].bb); - left_side_count += buckets[i].count; - } - - for (size_t i = bucket_index + 1; i < buckets_count; i++) { - right_side_bb.union_with(buckets[i].bb); - right_side_count += buckets[i].count; - } - - float left = left_side_count * left_side_bb.surface_area(); - float right = right_side_count * right_side_bb.surface_area(); - buckets_cost[bucket_index] = 0.125f + (left + right) / parent_bb.surface_area(); - } - - float min_cost = buckets_cost[0]; - uint32_t min_cost_bucket = 0; - for (size_t bucket_index = 1; bucket_index < buckets_count - 1; bucket_index++) { - if (buckets_cost[bucket_index] < min_cost) { - min_cost = buckets_cost[bucket_index]; - min_cost_bucket = bucket_index; - } - } - - uint32_t middle_primitive_index = buckets[0].count; - for (size_t bucket_index = 1; bucket_index <= min_cost_bucket; bucket_index++) { - middle_primitive_index += buckets[bucket_index].count; - } - - temp_nodes[left_id].bounding_box = compute_bounds(begin, begin + middle_primitive_index); - temp_nodes[right_id].bounding_box = compute_bounds(begin + middle_primitive_index, end); - - subdivide(left_id, begin, begin + middle_primitive_index); - subdivide(right_id, begin + middle_primitive_index, end); - } - } - } - - void set_depth_first_order() { - int32_t df_index = 0; - depth_first_order(0, -1, df_index); - } - - - void depth_first_order(int32_t id, int32_t next_id, int32_t &new_id) { - auto &node = temp_nodes[id]; - node.next_id = next_id; - node.df_id = new_id++; - - if (node.left_id > 0) { - depth_first_order(node.left_id, node.left_id + 1, new_id); - depth_first_order(node.left_id + 1, next_id, new_id); - } - } -}; - -#endif // !__BVH_NODE_HPP_ diff --git a/include/compute-renderpass.hpp b/include/compute-renderpass.hpp deleted file mode 100644 index 6799171..0000000 --- a/include/compute-renderpass.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "renderpass.hpp" -#include "vk-api.hpp" - -class Texture; -class Buffer; - -class ComputeRenderpass : public Renderpass { - public: - - ComputeRenderpass(vkapi& api); - ~ComputeRenderpass() override; - - void set_pipeline(const char* shader_name); - - void set_dispatch_size(size_t count_x, size_t count_y, size_t count_z); - - void set_ouput_texture(Texture* out_texture); - - void set_constant(off_t offset, uint64_t* constant); - void set_constant(off_t offset, Texture* texture); - void set_constant(off_t offset, Buffer* buffer); - - // TODO: Do not use vulkan api type - void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) final; - - Texture* output_texture; - - private: - - std::vector input_textures; - - uint8_t constants[64]; - - size_t group_count_x; - size_t group_count_y; - size_t group_count_z; - - pipeline pipeline; -}; diff --git a/include/dx12-command-buffer.hpp b/include/dx12-command-buffer.hpp new file mode 100644 index 0000000..e9de39a --- /dev/null +++ b/include/dx12-command-buffer.hpp @@ -0,0 +1,28 @@ +#include + +#include "handle.hpp" +#include "dx12-device-types.hpp" + +namespace dx12 { + struct command_buffer { + void start() const; + void stop() const; + + // void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; + + void copy(handle src_buffer, handle dst_texture, uint64_t offset = 0) const; + + ID3D12CommandAllocator* command_allocator; + ID3D12GraphicsCommandList* dx12_command_buffer; + dx12::QueueType queue_type; + }; + + struct graphics_command_buffer: public command_buffer { + // void dispatch(const dispatch_params& params) const; + + // void begin_renderpass(const renderpass_params& params) const; + // void draw(const draw_params& params) const; + // void draw_indexed(const draw_indexed_params& params) const; + // void end_renderpass() const; + }; +} diff --git a/include/dx12-device-types.hpp b/include/dx12-device-types.hpp new file mode 100644 index 0000000..4b2fc42 --- /dev/null +++ b/include/dx12-device-types.hpp @@ -0,0 +1,74 @@ +#pragma once +#include +#include +#include + +#include + +namespace dx12 { + enum class QueueType : uint32_t { + GRAPHICS, + ASYNC_COMPUTE, + TRANSFER, + MAX, + }; + + struct buffer_desc { + uint32_t size; + bool map; + + D3D12_RESOURCE_STATES states; + D3D12_RESOURCE_FLAGS usages; + D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_DEFAULT; + }; + + struct device_buffer { + ID3D12Resource* resource; + + D3D12MA::Allocation* alloc; + uint32_t size; + void* mapped_ptr = nullptr; + }; + + + struct texture_desc { + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + + D3D12_RESOURCE_STATES states; + D3D12_RESOURCE_FLAGS usages; + DXGI_FORMAT format; + D3D12_RESOURCE_DIMENSION type; + }; + + struct device_texture { + ID3D12Resource* resource; + D3D12MA::Allocation* alloc; + + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + uint64_t row_pitch = 1U; + + DXGI_FORMAT format; + + }; + + struct surface_desc { + HWND window_handle; + DXGI_FORMAT surface_format; + DXGI_SWAP_EFFECT present_mode; + DXGI_USAGE usages; + uint32_t image_count = surface_desc::default_image_count; + + static constexpr uint32_t max_image_count = 3U; + static constexpr uint32_t default_image_count = 3U; + }; + + struct device_surface { + IDXGISwapChain1* swapchain; + }; +} diff --git a/include/dx12-device.hpp b/include/dx12-device.hpp new file mode 100644 index 0000000..baa5b60 --- /dev/null +++ b/include/dx12-device.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include +#include + +#include "freelist.hpp" +#include "dx12-device-types.hpp" + +#include "D3D12MemAlloc.h" + +namespace dx12 { + struct command_buffer; + + class device { + struct queue { + ID3D12CommandQueue* dx_queue; + D3D12_COMMAND_LIST_TYPE type; + }; + public: + void init(); + + static inline device& get_render_device() { + return render_device; + } + + handle create_surface(const surface_desc& desc); + + handle create_buffer(const buffer_desc& desc); + + handle create_texture(const texture_desc& desc); + + void create_graphics_pipeline() {}; + + void create_compute_pipeline() {}; + + void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type); + + + [[nodiscard]] inline device_surface& get_surface(handle handle) { + return surfaces[handle]; + } + + [[nodiscard]] inline device_buffer& get_buffer(handle handle) { + return buffers[handle]; + } + + [[nodiscard]] inline device_texture& get_texture(handle handle) { + return textures[handle]; + } + + [[nodiscard]] inline ID3D12Device* get_device() const { + return device; + } + + uint32_t submit(command_buffer* buffers, uint32_t count); + + void wait(); + + private: + IDXGIFactory3* factory; + IDXGIAdapter* adapter; + ID3D12Debug* debug_interface; + + D3D12MA::Allocator* allocator; + + ID3D12Device* device; + ID3D12Fence* fence; + uint64_t fence_value = 0U; + queue queues[static_cast(QueueType::MAX)]; + + freelist surfaces; + freelist buffers; + freelist textures; + + static constexpr size_t max_allocable_command_buffers = 16U; + static constexpr size_t max_submitable_command_buffers = 16U; + + static class device render_device; + + struct bindless_model { + void init(); + + [[nodiscard]] inline ID3D12DescriptorHeap* const* get_heaps() const { + return &resources_heap; + } + + ID3D12DescriptorHeap* resources_heap; + ID3D12DescriptorHeap* samplers_heap; + } model; + + public: + [[nodiscard]] static inline const device::bindless_model& get_bindless_model() { + return render_device.model; + } + }; + +} diff --git a/include/freelist.hpp b/include/freelist.hpp new file mode 100644 index 0000000..2df1ca5 --- /dev/null +++ b/include/freelist.hpp @@ -0,0 +1,158 @@ +#pragma once + +#include "utils.hpp" +#include "handle.hpp" + +static constexpr u32 default_element_count = 1024U; + +template +class freelist { + public: + + freelist() { + grow(initial_size); + } + + handle add(const T& item) { + // auto id = elements[0U].next_free; + auto id = next_free_id; + + if (id == freelist::invalid_id) { + grow(elements.size()); + + // id = elements[0U].next_free; + id = next_free_id; + } + + auto& element = elements[id]; + + next_free_id = element.next_free; + // elements[0U].next_free = element.next_free; + element.item = std::move(item); + + assert(element.generation + 1 != UINT32_MAX); + + return { id, ++element.generation }; + } + + void remove(handle handle) { + assert(handle.generation == elements[handle.id].generation); + // elements[handle.id].next_free = elements[0U].next_free; + // elements[0U].next_free = handle.id; + elements[handle.id].next_free = next_free_id; + next_free_id = handle.id; + } + + T& operator[](handle handle) { + assert(handle.generation == elements[handle.id].generation); + return elements[handle.id].item; + } + + const T& operator[](handle handle) const { + assert(handle.generation == elements[handle.id].generation); + return elements[handle.id].item; + } + + static constexpr uint32_t invalid_id = UINT32_MAX; + + struct element { + union { + T item; + uint32_t next_free = freelist::invalid_id; + }; + uint32_t generation = 0U; + }; + + const std::vector& get_list() const { + return elements; + } + +private: + void grow(size_t grow_size) { + size_t size = elements.size(); + uint32_t next_free = static_cast(size); + next_free_id = next_free; + + elements.reserve(size + grow_size); + + for (auto id { 0U }; id < initial_size; id++) { + elements.push_back( + { + .next_free = static_cast(++next_free % initial_size), + } + ); + } + + // this makes it impossible to know + elements.back().next_free = freelist::invalid_id; + elements.back().next_free = freelist::invalid_id; + } + + std::vector elements; + uint32_t next_free_id; +}; + +template +class idlist { + public: + + idlist() { + grow(initial_size); + } + + handle add() { + // auto id = elements[0U].next_free; + auto id = next_free_id; + + if (id == idlist::invalid_id) { + grow(elements.size()); + + // id = elements[0U].next_free; + id = next_free_id; + } + + auto& element = elements[id]; + next_free_id = element.next_free; + elements[0U].next_free = element.next_free; + element.next_free = idlist::invalid_id; + + return { id, ++element.generation }; + } + + void remove(handle handle) { + assert(handle.generation == elements[handle.id].generation); + // elements[handle.id].next_free = elements[0U].next_free; + // elements[0U].next_free = handle.id; + elements[handle.id].next_free = next_free_id; + next_free_id = handle.id; + } + + static constexpr uint32_t invalid_id = UINT32_MAX; + +private: + void grow(size_t grow_size) { + auto size = elements.size(); + uint32_t next_free = static_cast(size); + next_free_id = next_free; + + elements.reserve(size + grow_size); + + for (auto id { 0U }; id < initial_size; id++) { + elements.push_back( + { + .next_free = static_cast(++next_free% initial_size), + } + ); + } + + elements.back().next_free = idlist::invalid_id; + } + + struct element { + uint32_t next_free = idlist::invalid_id; + uint32_t generation = 0U; + }; + + std::vector elements; + uint32_t next_free_id; +}; diff --git a/include/handle.hpp b/include/handle.hpp new file mode 100644 index 0000000..484b217 --- /dev/null +++ b/include/handle.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +template +struct handle { + uint32_t id = invalid_id; + uint32_t generation = 0U; + + [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } + + static constexpr uint32_t invalid_id = UINT32_MAX; +}; diff --git a/include/primitive-renderpass.hpp b/include/primitive-renderpass.hpp deleted file mode 100644 index 95562fe..0000000 --- a/include/primitive-renderpass.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include - -#include "renderpass.hpp" -#include "vk-renderer.hpp" - -class Buffer; -class Texture; -class Sampler; -class Primitive; - -class PrimitiveRenderpass : public Renderpass { - public: - - PrimitiveRenderpass(vkapi& api); - - void add_primitive(Primitive* new_primitive); - - void add_color_attachment(VkFormat format); - - void set_depth_stencil(Texture* depth_stencil); - - void set_viewport(float x, float y, float width, float height); - - void set_color_attachment(uint32_t index, Texture* attachment); - - void finalize_render_pass(); - - void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) final; - - VkRenderPass render_pass = VK_NULL_HANDLE; - - private: - - void create_framebuffers(); - - void recreate_framebuffers(); - - VkViewport viewport = { .minDepth = 0.f, .maxDepth = 1.f }; - - std::vector color_attachments; - std::vector color_attachments_view; - std::vector color_attachments_format; - - framebuffer framebuffers[vkrenderer::virtual_frames_count]; - - std::vector primitives; -}; - - -class Primitive { - public: - - Primitive(PrimitiveRenderpass& render_pass); - - void set_pipeline(const char* shader_name); - - void set_constant_offset(off_t offset); - void set_constant(off_t offset, uint64_t* constant); - void set_constant(off_t offset, Texture* texture); - void set_constant(off_t offset, Buffer* buffer); - void set_constant(off_t offset, Sampler* sampler); - - void set_index_buffer(Buffer* buffer); - - void set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height); - - void set_draw_info(size_t vertex_count, off_t indices_off, off_t vertex_off); - - void render(VkCommandBuffer command_buffer); - - -private: - - vkapi& api; - - PrimitiveRenderpass& primitive_render_pass; - - pipeline pipeline; - - Buffer* index_buffer; - - size_t element_count; - off_t indices_offset; - off_t vertex_offset; - - off_t constant_offset; - - VkRect2D scissor = {}; - - uint8_t constants[64]; -}; diff --git a/include/renderpass.hpp b/include/renderpass.hpp deleted file mode 100644 index da116dd..0000000 --- a/include/renderpass.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -using VkCommandBuffer = struct VkCommandBuffer_T*; - -class vkrenderer; -class vkapi; - -class Renderpass { - public: - - Renderpass(vkapi& api) - :api(api) - {}; - - virtual ~Renderpass() = default; - - // TODO: Do not use vulkan api type - virtual void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) = 0; - - protected: - vkapi &api; -}; diff --git a/include/texture.hpp b/include/texture.hpp index aac7b69..59bfec1 100644 --- a/include/texture.hpp +++ b/include/texture.hpp @@ -1,83 +1,17 @@ -#include - -using VkImage = struct VkImage_T*; - -struct TextureDesc { - VkImageType type; - VkFormat format; - VkExtent size; - VkImageUsageFlags usages; -}; - -class Texture { - public: - Texture(const TextureDesc desc) - : description(desc) { - create_device_image(); - } - - // Texture(handle image_handle) { - // const auto& image = vkrenderer::api.get_image(image_handle); - // width = image.size.width; - // height = image.size.height; - // depth = image.size.depth; - - // device_image = image_handle; - // } - - // Texture(size_t width, size_t height, size_t depth, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM, Sampler* texture_sampler = nullptr) - // : width(width), height(height), depth(depth) { - // sampler = texture_sampler; - // device_image = vkrenderer::api.create_image( - // { .width = (uint32_t)width, .height = (uint32_t)height, .depth = 1 }, - // format, - // VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - // } +#pragma once - void update(void* new_data) { - if (data == nullptr) { - free(data); - } - data = new_data; - - vkrenderer::queue_image_update(this); - } - - ~Texture() { - vkrenderer::api.destroy_image(device_image); - - if (data == nullptr) { - free(data); - } - } - - [[nodiscard]] size_t size() const { - const auto& image = vkrenderer::api.get_image(device_image); - return width * height * depth * pixel_size(image.format); - } - - static size_t pixel_size(VkFormat format) { - switch (format) { - case VK_FORMAT_R8G8B8A8_UNORM: - return 4; - default: - return 0; - } - } - - // Sampler* sampler = nullptr; +#include - private: - void create_device_image(); +#include - void* data = nullptr; +#include "handle.hpp" - size_t width = 0; - size_t height = 0; - size_t depth = 0; +struct device_texture; - TextureDesc description; +class texture { +public: + texture(handle handle); - VmaAllocationInfo alloc_info; - VkImage device_image; +private: + handle handle; }; diff --git a/include/vk-api.hpp b/include/vk-api.hpp deleted file mode 100644 index a3442f1..0000000 --- a/include/vk-api.hpp +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef __VK_API_HPP_ -#define __VK_API_HPP_ - -#include -#include - -#include - -using VmaAllocation = struct VmaAllocation_T*; - -struct buffer { - VmaAllocation alloc; - void* device_ptr; - VkBuffer handle; - size_t size; - VkDeviceAddress device_address; -}; - -struct pipeline { - std::vector shader_modules; - VkPipeline handle = VK_NULL_HANDLE; - VkPipelineBindPoint bind_point; -}; - -using bindless_index = uint32_t; -using handle = uint32_t; - -struct image { - VkImage handle; - VkImageView view; - VmaAllocation alloc; - VkImageSubresourceRange subresource_range; - VkFormat format; - VkExtent3D size; - VkImageUsageFlags usages; - bindless_index bindless_storage_index = 0; - bindless_index bindless_sampled_index = 0; - - VkImageLayout previous_layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkPipelineStageFlags previous_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkAccessFlags previous_access = 0; -}; - -struct swapchain { - uint32_t image_count; - std::vector images; - VkSwapchainKHR handle; - VkSurfaceFormatKHR surface_format; - VkExtent2D extent; -}; - -struct framebuffer { - VkFramebuffer handle; - VkExtent2D size; -}; - -struct sampler { - VkSampler handle; - bindless_index bindless_index; -}; - -struct global_descriptor { - VkDescriptorSetLayout set_layout; - VkPipelineLayout pipeline_layout; - VkDescriptorSet set; - - std::vector index_pool[3]; - - static constexpr uint32_t pool_size = 1024U; - - global_descriptor() { - for (int32_t index = pool_size; index > 0; index--) { - index_pool[0].push_back((uint32_t)index); - index_pool[1].push_back((uint32_t)index); - index_pool[2].push_back((uint32_t)index); - } - } - - uint32_t allocate(VkDescriptorType type) { - auto& pool = index_pool[descriptor_type_binding(type)]; - auto index = pool.back(); - pool.pop_back(); - - return index; - } - - void free(uint32_t index, VkDescriptorType type) { - assert(index != 0); - index_pool[descriptor_type_binding(type)].push_back(index); - } - - static int32_t descriptor_type_binding(VkDescriptorType type) { - switch (type) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - return 0; - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - return 1; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - return 2; - default: - assert(true && "descriptor type not supported"); - return -1; - } - } -}; - -class window; -class vkcontext; - -class vkapi { - public: - vkapi(vkcontext& context); - ~vkapi(); - - handle create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, uint32_t mem_usage); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size, size_t buffer_offset = 0); - void destroy_buffer(handle buffer); - - - handle create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages); - void destroy_image(handle image); - std::vector create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count); - void destroy_images(std::vector& imgs); - - - [[nodiscard]] VkFence create_fence() const; - void destroy_fence(VkFence fence) const; - [[nodiscard]] std::vector create_fences(size_t fences_count) const; - void destroy_fences(VkFence fences[], size_t fences_count) const; - - - [[nodiscard]] VkSemaphore create_semaphore() const; - void destroy_semaphore(VkSemaphore semaphore) const; - [[nodiscard]] std::vector create_semaphores(size_t semaphores_count) const; - void destroy_semaphores(VkSemaphore semaphores[], size_t semaphores_count) const; - - handle create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - void destroy_sampler(handle sampler); - - - [[nodiscard]] VkCommandPool create_command_pool() const; - - void allocate_command_buffers(VkCommandPool command_pool, VkCommandBuffer* command_buffers, size_t count) const; - - - VkRenderPass create_render_pass(std::vector& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout); - VkRenderPass create_render_pass(std::vector& color_attachments_format, VkFormat depth_attachement_format); - void destroy_render_pass(VkRenderPass render_pass); - - - framebuffer create_framebuffer(VkRenderPass render_pass, std::vector& formats, VkExtent2D size); - std::vector create_framebuffers(VkRenderPass render_pass, std::vector& formats, VkExtent2D size, uint32_t framebuffer_count); - void destroy_framebuffer(framebuffer framebuffer) const; - void destroy_framebuffers(std::vector& framebuffers) const; - - - pipeline create_compute_pipeline(const char* shader_name) const; - pipeline create_graphics_pipeline(const char* shader_name, VkShaderStageFlagBits shader_stages, VkRenderPass render_pass, std::vector& dynamic_states) const; - void destroy_pipeline(pipeline& pipeline) const; - - - VkSurfaceKHR create_surface(window& wnd) const; - void destroy_surface(VkSurfaceKHR surface); - - - swapchain create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain); - void destroy_swapchain(swapchain& swapchain); - - void update_descriptor_image(handle img, VkDescriptorType type); - void update_descriptor_images(std::vector& images, VkDescriptorType type); - void update_descriptor_sampler(handle sampler); - void update_descriptor_samplers(std::vector& samplers); - - - void update_constants(VkCommandBuffer command_buffer, VkShaderStageFlagBits shader_stage, off_t offset, size_t size, void* data); - - void start_record(VkCommandBuffer command_buffer); - - void image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image); - - void begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector& attachments, framebuffer framebuffer, VkExtent2D size); - void end_render_pass(VkCommandBuffer command_buffer); - - void run_compute_pipeline(VkCommandBuffer command_buffer, pipeline& pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z); - - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t vertex_count, uint32_t vertex_offset); - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t primitive_count, uint32_t indices_offset, uint32_t vertices_offset); - - void blit_full(VkCommandBuffer command_buffer, handle src_image, handle dst_image); - - void end_record(VkCommandBuffer command_buffer); - - VkResult submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const; - - VkResult present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const; - - const buffer& get_buffer(handle buffer_handle) { return *buffers[buffer_handle]; }; - - const image& get_image(handle image_handle) { return *images[image_handle]; }; - - const sampler& get_sampler(handle sampler_handle) { return *samplers[sampler_handle]; }; - - vkcontext& context; - - private: - global_descriptor bindless_descriptor; - - static const char* shader_stage_extension(VkShaderStageFlags shader_stage); - - // TODO: Use freelists instead - std::vector buffers; - std::vector images; - std::vector samplers; - - VkDescriptorPool descriptor_pool; -}; - -#endif // !__VK_API_HPP_ diff --git a/include/vk-bindless.hpp b/include/vk-bindless.hpp new file mode 100644 index 0000000..008e420 --- /dev/null +++ b/include/vk-bindless.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include "handle.hpp" + +enum UniformTypes : uint32_t { + GLOBAL, + PASS, + DRAW, + MAX, +}; + +enum SamplerType : uint32_t { + NEAREST, + LINEAR, + MAX_SAMPLER, +}; + +struct device_buffer; + +struct bindless_model { + [[nodiscard]] device_buffer& get_uniform_buffer(enum UniformTypes type) const; + + void init(); + + void deinit(); + + VkPipelineLayout global_layout; + VkDescriptorSet global_set; + +public: + static constexpr size_t push_constant_slot_size = sizeof(uintptr_t); + static constexpr size_t push_constant_slots = 3U; + +private: + VkDescriptorSetLayout global_set_layout; + VkDescriptorPool descriptor_pool; + handle uniform_buffers[UniformTypes::MAX]; + + static constexpr size_t descriptor_pool_allocable_sets_count = 64U; + static constexpr uint32_t set_descriptors_count = 1024U; + + VkSampler samplers[SamplerType::MAX_SAMPLER]; + + static constexpr size_t globals_uniform_buffer_size = 64 * KB; + static constexpr size_t passes_uniform_buffer_size = 64 * KB; + static constexpr size_t draws_uniform_buffer_size = 64 * KB; +}; diff --git a/include/vk-command-buffer.hpp b/include/vk-command-buffer.hpp new file mode 100644 index 0000000..82d5439 --- /dev/null +++ b/include/vk-command-buffer.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "handle.hpp" +#include "vk-device-types.hpp" +#include "vec3.hpp" + +struct device_texture; +struct device_buffer; +struct device_pipeline; + +struct dispatch_params { + handle pipeline; + vec3u group_size; + vec3u local_group_size; +}; + +struct renderpass_params { +private: + struct rect { + int32_t x; + int32_t y; + uint32_t width; + uint32_t height; + }; + +public: + rect render_area; + std::span> color_attachments; +}; + +struct draw_params { + handle pipeline; + handle index_buffer; + uint32_t vertex_count; + uint32_t vertex_offset; + uint32_t instance_count; +}; + +struct draw_indexed_params { + handle pipeline; + handle index_buffer; + uint32_t vertex_count; + uint32_t vertex_offset; + uint32_t index_offset; + uint32_t instance_count; +}; + +struct command_buffer { + void start() const; + void stop() const; + + void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; + + void copy(handle buffer_handle, handle texture_handle, uint64_t offset = 0) const; + + VkCommandBuffer vk_command_buffer; + QueueType queue_type; +}; + +// General purpose queue +struct graphics_command_buffer: public command_buffer { + void dispatch(const dispatch_params& params) const; + + void begin_renderpass(const renderpass_params& params) const; + void draw(const draw_params& params) const; + void draw_indexed(const draw_indexed_params& params) const; + void end_renderpass() const; +}; + +struct compute_command_buffer: public command_buffer { + void dispatch(const dispatch_params& params); +}; + +struct transfer_command_buffer: public command_buffer { +}; diff --git a/include/vk-context.hpp b/include/vk-context.hpp deleted file mode 100644 index 0dfd256..0000000 --- a/include/vk-context.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -using VmaAllocator = struct VmaAllocator_T*; - -struct queue { - VkQueue handle; - uint32_t index; - VkQueueFlags usages; -}; - -class vkcontext { - public: - vkcontext(); - - ~vkcontext(); - - VkInstance instance; - - VkPhysicalDevice physical_device; - VkDevice device; - - VmaAllocator allocator; - - queue graphics_queue; - - private: - void create_instance(); - - void create_debugger(); - - void create_device(); - - void create_memory_allocator(); - - void select_physical_device(); - - [[nodiscard]] uint32_t select_queue(VkQueueFlags queue_usage) const; - - static void check_available_instance_layers(const char* needed_layers[], size_t needed_layers_count); - - static void check_available_instance_extensions(const char* needed_extensions[], size_t needed_extensions_count); - - static bool support_required_features(VkPhysicalDevice physical_device); - - - VkDebugUtilsMessengerEXT debugMessenger; -}; diff --git a/include/vk-device-types.hpp b/include/vk-device-types.hpp new file mode 100644 index 0000000..94f9560 --- /dev/null +++ b/include/vk-device-types.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include + +#include "freelist.hpp" + +using VmaAllocation = struct VmaAllocation_T*; + +enum class QueueType : uint32_t { + GRAPHICS, + ASYNC_COMPUTE, + TRANSFER, + MAX, +}; + +struct texture_desc { + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + VkImageUsageFlags usages; + VkFormat format; + VkImageType type; + VkImage vk_image = nullptr; + const char* name = nullptr; + + static constexpr auto max_mips = 16U; +}; + +struct device_texture { + void init(const texture_desc& desc); + + void release(); + + void create_views(); + + [[nodiscard]] uint32_t get_storage_index() const { + assert(storage_index.id != handle::invalid_id); + return storage_index.id; + } + + [[nodiscard]] uint32_t get_sampled_index() const { + assert(sampled_index.id != handle::invalid_id); + return sampled_index.id; + } + + VkImage vk_image = nullptr; + VkImageView whole_view = nullptr; + VkImageView mips_views[texture_desc::max_mips] = { nullptr }; + VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkPipelineStageFlags2 stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + VkAccessFlags2 access = VK_ACCESS_2_NONE; + VkFormat format = VK_FORMAT_UNDEFINED; + VkImageAspectFlags aspects = VK_IMAGE_ASPECT_NONE_KHR; + + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + + const char* name = nullptr; + + private: + handle storage_index; + handle sampled_index; + + VmaAllocation alloc = nullptr; + + static idlist<> storage_indices; + static idlist<> sampled_indices; +}; + + +struct sampler_desc { + VkFilter mag_filter = VK_FILTER_NEAREST; + VkFilter min_filter = VK_FILTER_NEAREST; + VkSamplerMipmapMode mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + VkSamplerAddressMode address_mode_u = VK_SAMPLER_ADDRESS_MODE_REPEAT; + VkSamplerAddressMode address_mode_v = VK_SAMPLER_ADDRESS_MODE_REPEAT; + VkSamplerAddressMode address_mode_w = VK_SAMPLER_ADDRESS_MODE_REPEAT; + float mip_lod_bias = 0.f; + VkBool32 anisotropy = VK_FALSE; + float max_anisotropy = 0.f; + VkBool32 compare_enabled = VK_FALSE; + VkCompareOp compare_op = VK_COMPARE_OP_NEVER; + float min_lod = 0.f; + float max_lod = 0.f; + VkBorderColor border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + VkBool32 unnomalized_coords = VK_FALSE; +}; + +struct device_sampler { + void init(const sampler_desc& desc); + + VkSampler vk_sampler = nullptr; + + [[nodiscard]] uint32_t get_sampler_index() const { + return sampler_index.id; + } + + private: + handle sampler_index; + + static idlist<> sampler_indices; +}; + + +struct buffer_desc { + size_t size; + VkBufferUsageFlags usages; + VkMemoryPropertyFlags memory_properties; + uint32_t memory_usage; + const char* name; +}; + +struct device_buffer { + template + T* allocate() { + u32 alloc_size = sizeof(T); + if (allocated_size + alloc_size > size) { + reset(); + } + + offset = allocated_size; + T* addr = (T*)(static_cast(mapped_ptr) + offset); + allocated_size += alloc_size; + return addr; + } + + void* allocate(u32 alloc_size) { + if (allocated_size + alloc_size > size) { + reset(); + } + + offset = allocated_size; + void* addr = (void*)(static_cast(mapped_ptr) + offset); + allocated_size += alloc_size; + return addr; + } + + void reset() { + allocated_size = 0U; + offset = 0U; + } + + u32 offset = 0U; + u32 allocated_size = 0U; + VkBuffer vk_buffer; + VmaAllocation alloc; + VkDeviceAddress device_address = 0U; + void* mapped_ptr; + size_t size; + VkBufferUsageFlagBits2 usages; + + const char* name; +}; + +struct graphics_pipeline_desc { + uint8_t* vs_code; + size_t vs_code_size; + uint8_t* fs_code; + size_t fs_code_size; + std::span color_attachments_format; + VkFormat depth_attachment_format; + VkFormat stencil_attachment_format; + const char* name; +}; + +struct compute_pipeline_desc { + uint8_t* cs_code; + size_t cs_code_size; + const char* name; +}; + +struct device_pipeline { + VkPipeline vk_pipeline; + VkPipelineBindPoint bind_point; +}; + +struct semaphore_desc { + VkSemaphoreType type; + uint64_t initial_value = 0U; +}; + +struct device_semaphore { + VkSemaphore vk_semaphore = nullptr; + uint64_t value; +}; + + +typedef struct HWND__* HWND; + +struct surface_desc { + HWND window_handle; + VkSurfaceFormatKHR surface_format; + VkPresentModeKHR present_mode; + VkImageUsageFlags usages; + uint32_t image_count = surface_desc::default_image_count; + + static constexpr uint32_t max_image_count = 3U; + static constexpr uint32_t default_image_count = 3U; +}; + +struct device_surface { + VkSurfaceKHR vk_surface; + VkSwapchainKHR vk_swapchain; + VkSurfaceFormatKHR surface_format; + + handle swapchain_images[surface_desc::max_image_count]; + uint32_t image_index; + uint32_t image_count; + uint32_t frame_index = 0U; + + handle acquire_semaphores[surface_desc::max_image_count]; + handle submit_semaphores[surface_desc::max_image_count]; + + uint32_t acquire_image_index(); +}; diff --git a/include/vk-device.hpp b/include/vk-device.hpp new file mode 100644 index 0000000..e2e8c99 --- /dev/null +++ b/include/vk-device.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include "freelist.hpp" +#include "vk-bindless.hpp" +#include "vk-command-buffer.hpp" + +using VmaAllocator = struct VmaAllocator_T*; + +struct command_buffer; +class window; + +class vkdevice { + struct queue { + VkQueue vk_queue = VK_NULL_HANDLE; + uint32_t index = UINT32_MAX; + VkQueueFlags usages; + VkCommandPool command_pool = VK_NULL_HANDLE; + }; + + public: + void init(); + void deinit(); + + static inline vkdevice& get() { + return render_device; + } + + handle create_texture(const texture_desc& desc); + + handle create_sampler(const sampler_desc& desc); + + handle create_buffer(const buffer_desc& desc); + + handle create_graphics_pipeline(const graphics_pipeline_desc& desc); + + handle create_compute_pipeline(const compute_pipeline_desc& desc); + + handle create_surface(const surface_desc& desc); + + handle create_semaphore(const semaphore_desc& desc, const char* name); + + void destroy_texture(handle handle); + + void destroy_sampler(handle handle); + + void destroy_buffer(handle handle); + + void destroy_pipeline(handle handle); + + void destroy_semaphore(handle handle); + + void destroy_surface(handle handle); + + template + void allocate_command_buffers(buffer_type* buffers, size_t count, QueueType queue_type, const char* name) { + allocate_command_buffers(static_cast(buffers), count, queue_type, name); + } + + [[nodiscard]] inline device_texture& get_texture(handle handle) { + return textures[handle]; + } + + [[nodiscard]] inline device_sampler& get_sampler(handle handle) { + return samplers[handle]; + } + + [[nodiscard]] inline device_buffer& get_buffer(handle handle) { + return buffers[handle]; + } + + [[nodiscard]] inline const device_pipeline& get_pipeline(handle handle) const { + return pipelines[handle]; + } + + [[nodiscard]] inline device_surface& get_surface(handle handle) { + return surfaces[handle]; + } + + [[nodiscard]] inline device_semaphore& get_semaphore(handle handle) { + return semaphores[handle]; + } + + [[nodiscard]] inline const bindless_model& get_bindingmodel() const { + return bindless; + } + + const freelist& get_textures() const { + return textures; + } + + inline VkDevice get_device() const { + return device; + } + + inline VmaAllocator get_allocator() { + return gpu_allocator; + } + + inline const VkPhysicalDeviceLimits& get_device_limits() const { + return physical_device_props.properties.limits; + } + + // uint64_t submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle); + uint32_t acquire_image_index(handle surface_handle); + uint64_t submit_before_present(handle surface_handle, command_buffer* buffers, uint32_t count); + uint64_t submit(command_buffer* buffers, uint32_t count); + + void present(handle surface_handle); + + void wait(); + + private: + vkdevice() = default; + ~vkdevice() = default; + + void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type, const char* name); + + void create_swapchain(const surface_desc& desc, device_surface& surface); + + // TODO: Wrap in a struct called adapter ? + void create_instance(); + + void create_device(); + + void create_memory_allocator(); + + void create_command_pools(); + + void pick_physical_device(); + + bool device_support_features(VkPhysicalDevice physical_dev); + + void create_debug_layer_callback(); + + queue queues[static_cast(QueueType::MAX)]; + + VkInstance instance; + VkPhysicalDevice physical_device; + VkPhysicalDeviceProperties2 physical_device_props; + VkDevice device; + + VmaAllocator gpu_allocator; + + bindless_model bindless; + + static constexpr size_t max_allocable_command_buffers = 16; + static constexpr size_t max_submitable_command_buffers = 16; + + freelist textures; + freelist samplers; + freelist buffers; + freelist pipelines; + freelist surfaces; + freelist semaphores; + + device_semaphore timeline_semaphore; + + static vkdevice render_device; + +#ifdef _DEBUG + VkDebugUtilsMessengerEXT debug_messenger; +#endif // _DEBUG +}; diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp deleted file mode 100644 index 1317912..0000000 --- a/include/vk-renderer.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef __VK_RENDERER_HPP_ -#define __VK_RENDERER_HPP_ - -#include -#include -#include - -#include "vk-context.hpp" -#include "vk-api.hpp" - - -class Renderpass; -class ComputeRenderpass; -class PrimitiveRenderpass; -class Primitive; -class window; - -class Texture; -class Sampler; -class RingBuffer; - - -class Buffer { - public: - - Buffer(size_t size, VkBufferUsageFlagBits usage); - ~Buffer(); - - void write(void* data, off_t alloc_offset, size_t data_size) const; - - void resize(size_t new_size); - - handle device_buffer; - - size_t buffer_size; - - VkBufferUsageFlagBits usage; -}; - - -class vkrenderer { - public: - vkrenderer(window& wnd); - - ~vkrenderer(); - - void recreate_swapchain(); - - - void update_images(); - - void begin_frame(); - - void finish_frame(); - - static void queue_image_update(Texture* texture); - - static Buffer* create_buffer(size_t size); - - static Buffer* create_index_buffer(size_t size); - - static Buffer* create_staging_buffer(size_t size); - - static Sampler* create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - - - ComputeRenderpass* create_compute_renderpass(); - - PrimitiveRenderpass* create_primitive_renderpass(); - - Primitive* create_primitive(PrimitiveRenderpass& primitive_render_pass); - - void render(); - - [[nodiscard]]uint32_t frame_index() const { return this->virtual_frame_index; } - - [[nodiscard]]Texture* back_buffer() const { return swapchain_textures[swapchain_image_index]; } - - [[nodiscard]]VkFormat back_buffer_format() const { return swapchain.surface_format.format; } - - static constexpr uint32_t virtual_frames_count = 2; - - static vkcontext context; - - static vkapi api; - - private: - - - void handle_swapchain_result(VkResult function_result); - - std::vector renderpasses; - - uint32_t virtual_frame_index = 0; - uint32_t swapchain_image_index = 0; - - VkCommandBuffer graphics_command_buffers[virtual_frames_count]; - VkCommandBuffer copy_command_buffers[virtual_frames_count]; - - RingBuffer* staging_buffers[virtual_frames_count]; - - - pipeline tonemapping_pipeline; - - VkFence submission_fences[virtual_frames_count]; - VkSemaphore execution_semaphores[virtual_frames_count]; - VkSemaphore acquire_semaphores[virtual_frames_count]; - - VkCommandPool graphics_command_pool; - VkCommandPool copy_command_pools[virtual_frames_count]; - - VkSurfaceKHR platform_surface; - swapchain swapchain; - std::vector swapchain_textures; - std::vector recorded_command_buffers; - - const uint32_t min_swapchain_image_count = 3; - - static std::vector upload_queue; -}; - -class RingBuffer { - public: - - static const size_t invalid_alloc = -1; - - RingBuffer(size_t size); - - [[nodiscard]]size_t alloc(size_t alloc_size) { - assert(alloc_size > 0 && alloc_size <= buffer_size); - - auto alloc_offset = ptr; - - if (alloc_offset <= buffer_size - alloc_size) { - ptr += alloc_size; - return alloc_offset; - } - - return invalid_alloc; - } - - void write(void* data, size_t alloc_offset, size_t data_size) const { - auto api_buffer = vkrenderer::api.get_buffer(device_buffer); - - std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size); - } - - void reset() { - ptr = 0; - } - - handle device_buffer; - - size_t buffer_size; - size_t ptr = 0; -}; - -class Sampler { - public: - - handle device_sampler; -}; - -#endif // !__VK_RENDERER_HPP_ diff --git a/include/vk-utils.hpp b/include/vk-utils.hpp new file mode 100644 index 0000000..f26d2a3 --- /dev/null +++ b/include/vk-utils.hpp @@ -0,0 +1,12 @@ +#pragma once + +#ifdef _DEBUG +#define VKCHECK(result) assert((result) == VK_SUCCESS) +#else +#define VKCHECK(result) (void)result +#endif + +VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data, + void*); 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