aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compute-renderpass.cpp63
-rw-r--r--src/dx12-command-buffer.cpp47
-rw-r--r--src/dx12-device.cpp239
-rw-r--r--src/main.cpp1053
-rw-r--r--src/primitive-renderpass.cpp152
-rw-r--r--src/vk-api.cpp1257
-rw-r--r--src/vk-bindless.cpp238
-rw-r--r--src/vk-command-buffer.cpp216
-rw-r--r--src/vk-context.cpp319
-rw-r--r--src/vk-device.cpp1311
-rw-r--r--src/vk-renderer.cpp284
-rw-r--r--src/vk-utils.cpp42
12 files changed, 2821 insertions, 2400 deletions
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<device_buffer> src_buffer, handle<device_texture> 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<UINT>(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 <cstdint>
+#include <cstdio>
+
+#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<uint32_t>(QueueType::GRAPHICS)].type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+ D3D12_COMMAND_QUEUE_DESC queue_desc{
+ .Type = queues[static_cast<uint32_t>(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<uint32_t>(QueueType::GRAPHICS)].dx_queue));
+ assert(hr == S_OK);
+
+ queue_desc.Type = queues[static_cast<uint32_t>(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<uint32_t>(QueueType::ASYNC_COMPUTE)].dx_queue));
+ assert(hr == S_OK);
+
+ queue_desc.Type = queues[static_cast<uint32_t>(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<uint32_t>(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_surface> 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<uint32_t>(QueueType::GRAPHICS)].dx_queue, desc.window_handle, &swapchain_desc1, nullptr, nullptr, &surface.swapchain);
+ assert(hr == S_OK);
+
+ return surfaces.add(surface);
+ }
+
+ handle<device_buffer> 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_texture> 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<uint16_t>(texture.depth),
+ .MipLevels = static_cast<uint16_t>(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<uint32_t>(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<uint32_t>(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 <chrono>
-#include <filesystem>
+// ===============
+// windows.h stuff
+// ===============
+#if defined(_WIN32)
+ #if defined(_M_AMD64)
+ #define _AMD64_
+ #endif
+ #include <basetsd.h>
+ #include <windef.h>
+ #include <winnt.h>
+ #include <winbase.h>
+ #include <winuser.h>
+ #include <winnls.h>
+ #include <fileapi.h>
+ #include <shlwapi.h>
+ #include <handleapi.h>
+ #include <errhandlingapi.h>
+#endif // _WIN32
-#include "imgui.h"
-#ifdef ENABLE_RENDERDOC
-#include <renderdoc.h>
-#endif
-#include "compute-renderpass.hpp"
-#include "primitive-renderpass.hpp"
-#include "scene.hpp"
-#include "vk-renderer.hpp"
-#include "window.hpp"
-#include "utils.hpp"
+// -------------------
+// thirdparties
+// -------------------
+#define IMGUI_DISABLE_WIN32_FUNCTIONS
+#include "imgui.cpp"
+#include "imgui_draw.cpp"
+#include "imgui_tables.cpp"
+#include "imgui_widgets.cpp"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include <stb_image.h>
+
+#include <simdjson.h>
+#include "simdjson.cpp"
+
+#define ENABLE_RENDERDOC 1
+#if ENABLE_RENDERDOC
+#include <renderdoc_app.h>
-#if defined(LINUX)
-#include <dlfcn.h>
-#include <unistd.h>
-#elif defined(WINDOWS)
-#include <Windows.h>
+
+
+#define RD_START_CAPTURE if(rdoc_api != nullptr) rdoc_api->StartFrameCapture(nullptr, nullptr)
+#define RD_END_CAPTURE if(rdoc_api != nullptr) rdoc_api->EndFrameCapture(nullptr, nullptr)
+#else
+#define RD_START_CAPTURE
+#define RD_END_CAPTURE
+#endif // ENABLE_RENDERDOC
+
+#define VK 1
+#define DX12 0
+#if DX12
+#include "dx12-device.hpp"
+#include "dx12-command-buffer.hpp"
+#else
+#include "vulkan-loader.cpp"
+#include "vk-utils.cpp"
+#include "vk-device.cpp"
+#include "vk-bindless.cpp"
+#include "vk-command-buffer.cpp"
#endif
-struct VkVertex {
- float x, y;
- float u, v;
- uint32_t color;
- uint32_t padding[3];
-};
+#include "vec3.cpp"
+#include "utils.cpp"
+#include "window.cpp"
+#include "camera.cpp"
+#include "mesh.cpp"
+#include "gltf.cpp"
+#include "bvh.cpp"
+#include "scene.cpp"
+
+
+
+// -------------------
+// GLOBALS
+// -------------------
+LARGE_INTEGER freq;
+std::vector<handle<device_texture>> debug_texture_list;
+
+#if ENABLE_RENDERDOC
+RENDERDOC_API_1_6_0 *rdoc_api = nullptr;
+#endif // ENABLE_RENDERDOC
+
+void watch_func() {
+ printf("change");
+}
+
+void ui(scene* scene, float frame_time) {
+ static float max_fps = 0.f;
+ static float max_frame_time = 0.f;
+ float fps = 1000U / (frame_time > 0.001f ? frame_time : 0.001f);
+ if (fps > max_fps) {
+ max_fps = fps;
+ }
+ if (frame_time > max_frame_time) {
+ max_frame_time = frame_time;
+ }
-void update_ui(scene& main_scene, float delta_time) {
ImGui::NewFrame();
+ const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
+ ImGuiWindowFlags wnd_flags = ImGuiWindowFlags_NoMove;
+ ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkSize.x - 250, main_viewport->WorkPos.y), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(250, 720), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowPos({0.f, 0.f});
- ImGui::SetNextWindowSize({0.f, 0.f});
- ImGui::Begin("Debug", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar);
+ ImGui::Begin("Debug", nullptr, wnd_flags);
+ if (ImGui::CollapsingHeader("Perfs")) {
+ ImGui::SeparatorText("Metrics");
+ ImGui::Text("FPS : %f\n", fps);
+ ImGui::Text("Max FPS : %f\n", max_fps);
+ ImGui::Text("frame_time : %f ms\n", frame_time);
+ ImGui::Text("max frame_time : %f ms\n", max_frame_time);
- ImGui::Text("frame per second %u\n", static_cast<uint32_t>(1000.f / delta_time));
- ImGui::Text("frame time %f ms\n", delta_time);
- ImGui::Text("frame count %u\n", main_scene.meta.sample_index);
+ ImGui::SeparatorText("Markers");
+ for (uint32_t index = 0U; index < marker_count; index++ ) {
+ uint64_t diff = marker_counter_end[index] - marker_counter_start[index];
+ uint64_t time = (diff * 1000000ULL) / freq.QuadPart;
- if (ImGui::Checkbox("depth of field", (bool*)&main_scene.meta.enable_dof)) {
- main_scene.meta.sample_index = 1;
+ ImGui::Text("%s time : %f ms\n", marker_names[index], static_cast<float>(time) / 1000U);
+ }
}
- ImGui::SliderInt("max bounces", (int32_t *)&main_scene.meta.max_bounce, 1, 250);
- ImGui::SliderInt("min bounces", (int32_t *)&main_scene.meta.min_bounce, 1, main_scene.meta.max_bounce);
- if (ImGui::SliderInt("downscale factor", (int32_t *)&main_scene.meta.downscale_factor, 1, 32)) {
- main_scene.meta.sample_index = 1;
+ if (ImGui::CollapsingHeader("Images")) {
+ for (const handle<device_texture>& handle : debug_texture_list) {
+ const device_texture& tex = vkdevice::get().get_texture(handle);
+ const char* name = tex.name;
+ ImGui::Text(name ? name : DUMMY_NAME);
+ ImGui::Image(tex.get_sampled_index(), ImVec2(128, 128));
+ }
}
- if (ImGui::Checkbox("debug bvh", (bool *)&main_scene.meta.debug_bvh)) {
- main_scene.meta.sample_index = 1;
+ if (ImGui::CollapsingHeader("Scene")) {
+ ImGui::SliderInt("Max bounce", reinterpret_cast<int*>(&scene->meta.max_bounce), 5, 100);
+ ImGui::SliderInt("Min bounce", reinterpret_cast<int*>(&scene->meta.min_bounce), 1, 5);
+
+ ImGui::Checkbox("DOF", reinterpret_cast<bool*>(&scene->meta.enable_dof));
+ ImGui::Checkbox("Debug BVH", reinterpret_cast<bool*>(&scene->meta.debug_bvh));
+ if (ImGui::SliderInt("Scale facotr", reinterpret_cast<int*>(&scene->meta.downscale_factor), 1, 20)) {
+ scene->meta.sample_index = 1U;
+ }
}
ImGui::End();
- bool open = true;
- ImGui::ShowDemoWindow(&open);
-
ImGui::EndFrame();
-
ImGui::Render();
}
-void render(scene& main_scene, vkrenderer& renderer) {
- // To start a frame capture, call StartFrameCapture.
- // You can specify NULL, NULL for the device to capture on if you have only
- // one device and either no windows at all or only one window, and it will
- // capture from that device. See the documentation below for a longer
- // explanation if(rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL);
+int main() {
+ // From Microsoft doc
+ // https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency
+ // The frequency of the performance counter is fixed at system boot and is
+ // consistent across all processors so you only need to query the frequency
+ // from QueryPerformanceFrequency as the application initializes,
+ // and then cache the result.
+ QueryPerformanceFrequency(&freq);
- main_scene.scene_buffer->write(&main_scene.meta, renderer.frame_index() * sizeof(main_scene.meta), sizeof(main_scene.meta));
+ BEGIN_MARKER(STARTUP);
+#if ENABLE_RENDERDOC
+ {
+ HMODULE mod = GetModuleHandleA("renderdoc.dll");
+ if (!mod) {
+ // https://github.com/baldurk/renderdoc/issues/1556
+ // If you load one copy of the dll yourself but a different copy of the dll is registered as a vulkan layer then both copies will be loaded because they're loaded from different paths.
+ // They'll be mutually incompatible (you can't use the API fetched from one to capture from another), and other things may break or cause crashes
+ mod = LoadLibraryA("C:/Program Files/RenderDoc/renderdoc.dll");
- // ImDrawData* draw_data = ImGui::GetDrawData();
+ }
- // ui_pass->set_viewport(0.f, 0.f, (float)draw_data->DisplaySize.x, (float)draw_data->DisplaySize.y);
+ if (mod) {
+ pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
+ int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, (void **)&rdoc_api);
+ assert(ret == 1);
+ (void)ret;
- // auto previous_size = ui_primitives.size();
- // auto commands_count = 0U;
+ rdoc_api->MaskOverlayBits(eRENDERDOC_Overlay_All, eRENDERDOC_Overlay_All);
- // for (int32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) {
- // commands_count += draw_data->CmdLists[draw_list_index]->CmdBuffer.size();
- // }
+ RENDERDOC_InputButton key = RENDERDOC_InputButton::eRENDERDOC_Key_F10;
+ rdoc_api->SetCaptureKeys(&key, 1U);
+ }
+ }
+#endif
- // if (ui_primitives.size() < commands_count) {
- // ui_primitives.resize(commands_count);
+ constexpr size_t window_width = 1280U;
+ constexpr size_t window_height = 720U;
+ window wnd { window_width, window_height };
- // for (size_t index = previous_size; index < ui_primitives.size(); index++) {
- // ui_primitives[index] = renderer.create_primitive(*ui_pass);
- // ui_primitives[index]->set_pipeline(ui_shader_name);
- // ui_primitives[index]->set_constant_offset(64);
- // ui_primitives[index]->set_constant(32, ui_texture);
- // ui_primitives[index]->set_constant(36, ui_texture_sampler);
- // }
- // }
+ ImGui::CreateContext();
+ ImGuiIO &io = ImGui::GetIO();
+ io.DisplaySize.x = window_width;
+ io.DisplaySize.y = window_height;
- // float scale[] {
- // 2.f / draw_data->DisplaySize.x,
- // 2.f / draw_data->DisplaySize.y,
- // };
- // float translate[] {
- // -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x),
- // -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y),
- // };
+ const float aspect_ratio = 16.f / 9.f;
- // if (!ui_vertex_buffer || ui_vertex_buffer->size < draw_data->TotalVtxCount * sizeof(VkVertex)) {
- // ui_vertex_buffer = renderer.create_buffer(draw_data->TotalVtxCount * sizeof(VkVertex), false);
+ point3 position { 13.f, 2.f, -3.f };
+ point3 target {};
+ const float v_fov = 90.f;
+ const float aperture = 0.1f;
+ const float focus_distance = 10.f;
- // for (auto& primitive : ui_primitives) {
- // primitive->set_constant(0, ui_vertex_buffer);
- // }
- // }
+#if VK
+ auto& device = vkdevice::get();
+#else
+ auto& device = dx12::device::get();
+#endif
+ device.init();
- // if (!ui_index_buffer || ui_index_buffer->size < draw_data->TotalIdxCount * sizeof(ImDrawIdx)) {
- // ui_index_buffer = renderer.create_index_buffer(draw_data->TotalIdxCount * sizeof(ImDrawIdx), false);
+ scene main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), window_width, window_height);
- // for (auto& primitive : ui_primitives) {
- // primitive->set_index_buffer(ui_index_buffer);
- // }
- // }
+ handle<device_surface> surface_handle = device.create_surface({
+ .window_handle = wnd.handle,
+#if VK
+ .surface_format = {
+ .format = VK_FORMAT_B8G8R8A8_UNORM,
+ .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+ },
+ .present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR,
+ .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
+#else
+ .surface_format = DXGI_FORMAT_R16G16B16A16_FLOAT,
+ .present_mode = DXGI_SWAP_EFFECT_FLIP_DISCARD,
+ .usages = DXGI_USAGE_RENDER_TARGET_OUTPUT,
+#endif
+ .image_count = 2U,
+ });
+ const device_surface& surface = device.get_surface(surface_handle);
- // off_t vertex_buffer_offset = 0;
- // off_t index_buffer_offset = 0;
- // std::vector<VkVertex> vertices;
- // uint32_t draw_call_index = 0;
- // for (int32_t draw_list_index = 0; draw_list_index < draw_data->CmdListsCount; draw_list_index++) {
- // auto& vertex_buffer = draw_data->CmdLists[draw_list_index]->VtxBuffer;
- // auto& index_buffer = draw_data->CmdLists[draw_list_index]->IdxBuffer;
- // vertices.resize(vertex_buffer.size());
- // for (int32_t vert_index = 0; vert_index < vertex_buffer.Size; vert_index++) {
- // vertices[vert_index] = *((VkVertex*)&vertex_buffer[vert_index]);
- // }
+ // ==============
+ // create buffers
+ // ==============
+ const handle<device_buffer> staging_buffer_handle = device.create_buffer({
+ .size = 128 * MB,
+#if VK
+ .usages = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
+ .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
+#else
+ .map = true,
+ .states = D3D12_RESOURCE_STATE_COPY_SOURCE,
+ .usages = D3D12_RESOURCE_FLAG_NONE,
+ .heap_type = D3D12_HEAP_TYPE_UPLOAD,
+#endif
+ });
+ const device_buffer& staging_buffer = device.get_buffer(staging_buffer_handle);
- // renderer.update_buffer(ui_vertex_buffer, vertices.data(), vertex_buffer_offset * sizeof(VkVertex), vertices.size() * sizeof(VkVertex));
- // renderer.update_buffer(ui_index_buffer, index_buffer.Data, index_buffer_offset * sizeof(ImDrawIdx), index_buffer.size() * sizeof(ImDrawIdx));
+ const handle<device_buffer> vertex_buffer_handle = device.create_buffer({
+ .size = MB * sizeof(uint32_t),
+#if VK
+ .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
+#else
+ #endif
+ });
- // ImDrawList* draw_list = draw_data->CmdLists[draw_list_index];
- // for (auto& draw_cmd: draw_list->CmdBuffer) {
- // auto& current_primitive = ui_primitives[draw_call_index];
- // current_primitive->set_constant(8, (uint64_t*)&scale);
- // current_primitive->set_constant(16, (uint64_t*)&translate);
+ const handle<device_buffer> index_buffer_handle = device.create_buffer({
+ .size = MB * sizeof(uint32_t),
+#if VK
+ .usages = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
+ .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
+#else
+#endif
+ });
- // ImVec2 pos = draw_data->DisplayPos;
- // current_primitive->set_scissor(
- // (int32_t)draw_cmd.ClipRect.x - pos.x,
- // (int32_t)draw_cmd.ClipRect.y - pos.y,
- // (uint32_t)draw_cmd.ClipRect.z - pos.x,
- // (uint32_t)draw_cmd.ClipRect.w - pos.y
- // );
+ device_buffer vertex_buffer = device.get_buffer(vertex_buffer_handle);
+ device_buffer index_buffer = device.get_buffer(index_buffer_handle);
- // current_primitive->set_draw_info(
- // draw_cmd.ElemCount,
- // index_buffer_offset + draw_cmd.IdxOffset,
- // vertex_buffer_offset + draw_cmd.VtxOffset
- // );
- // ui_pass->add_primitive(current_primitive);
- // draw_call_index++;
- // }
+ // ================
+ // create pipelines
+ // ================
+#if VK
+ size_t code_size = 0U;
+ uint8_t* code = read_file("shaders/test.comp.spv", &code_size);
+ handle<device_pipeline> compute = device.create_compute_pipeline({
+ .cs_code = code,
+ .cs_code_size = code_size,
+ });
- // vertex_buffer_offset += vertex_buffer.Size;
- // index_buffer_offset += index_buffer.Size;
- // }
+ size_t rt_code_size = 0U;
+ uint8_t* rt_code = read_file("shaders/compute.comp.spv", &rt_code_size);
+ handle<device_pipeline> raytracing = device.create_compute_pipeline({
+ .cs_code = rt_code,
+ .cs_code_size = rt_code_size,
+ });
+ size_t tonemapping_code_size = 0U;
+ uint8_t* tonemapping_code = read_file("shaders/tonemapping.comp.spv", &tonemapping_code_size);
+ handle<device_pipeline> tonemapping = device.create_compute_pipeline({
+ .cs_code = tonemapping_code,
+ .cs_code_size = tonemapping_code_size,
+ });
- // ui_pass->set_color_attachment(0, renderer.back_buffer());
+ std::array<VkFormat, 1U> formats { surface.surface_format.format };
+ size_t vertex_code_size = 0U;
+ uint8_t* vertex_code = read_file("shaders/api-test-ui.vert.spv", &vertex_code_size);
+ size_t fragment_code_size = 0U;
+ uint8_t* fragment_code = read_file("shaders/api-test-ui.frag.spv", &fragment_code_size);
+ handle<device_pipeline> graphics = device.create_graphics_pipeline({
+ .vs_code = vertex_code,
+ .vs_code_size = vertex_code_size,
+ .fs_code = fragment_code,
+ .fs_code_size = fragment_code_size,
+ .color_attachments_format = formats
+ });
- renderer.render();
+ size_t transmittance_lut_code_size = 0U;
+ u8* transmittance_lut_code = read_file("shaders/transmittance_lut.comp.spv", &transmittance_lut_code_size);
+ handle<device_pipeline> transmittance_lut_compute = device.create_compute_pipeline({
+ .cs_code = transmittance_lut_code,
+ .cs_code_size = transmittance_lut_code_size,
+ .name = "transmittance_lut_comp",
+ });
+#endif
- main_scene.meta.sample_index++;
-}
+ // ==============
+ // Image loading
+ // ==============
+ int image_width;
+ int image_height;
+ int channels;
+ uint8_t* data = stbi_load("../models/sponza/466164707995436622.jpg", &image_width, &image_height, &channels, 4);
+ size_t size = static_cast<size_t>(image_width) * image_height * 4U;
+ memcpy(staging_buffer.mapped_ptr, data, size);
+ off_t buffer_offset = image_width * image_height * 4;
+ data = stbi_load("../models/sponza/715093869573992647.jpg", &image_width, &image_height, &channels, 4);
+ size = static_cast<size_t>(image_width) * image_height * 4U;
+ auto* addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + buffer_offset);
+ memcpy(addr, data, size);
-#if defined(ENABLE_RENDERDOC)
-RENDERDOC_API_1_1_2 enable_renderdoc() {
- RENDERDOC_API_1_1_2 *rdoc_api = nullptr;
+ u8 *pixels = nullptr;
+ int atlas_width;
+ int atlas_height;
+ io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height);
-#ifdef WINDOWS
- // At init, on windows
- if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) {
- auto RENDERDOC_GetAPI =
- (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI");
- int ret =
- RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api);
- assert(ret == 1);
- }
-#elif defined(LINUX)
- // At init, on linux/android.
- // For android replace librenderdoc.so with libVkLayer_GLES_RenderDoc.so
- if (void *mod = dlopen("librenderdoc.so", RTLD_NOW | RTLD_NOLOAD)) {
- pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dlsym(mod, "RENDERDOC_GetAPI");
- int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api);
- assert(ret == 1);
- }
+ off_t ui_offset = 2L * buffer_offset;
+ size = static_cast<size_t>(atlas_width) * atlas_height * 4U;
+ addr = static_cast<void*>(static_cast<uint8_t*>(staging_buffer.mapped_ptr) + ui_offset);
+ memcpy(addr, pixels, size);
+
+
+ // ==============
+ // create texures
+ // ==============
+ const handle<device_texture> gpu_texture_handle = device.create_texture({
+ .width = static_cast<uint32_t>(image_width),
+ .height = static_cast<uint32_t>(image_height),
+#if VK
+ .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .states = D3D12_RESOURCE_STATE_COPY_DEST,
+ .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
+ .format = DXGI_FORMAT_R8G8B8A8_UNORM,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
#endif
+ });
- return rdoc_api;
-}
+ const handle<device_texture> second_texture = device.create_texture({
+ .width = static_cast<uint32_t>(image_width),
+ .height = static_cast<uint32_t>(image_height),
+#if VK
+ .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .states = D3D12_RESOURCE_STATE_COPY_DEST,
+ .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
+ .format = DXGI_FORMAT_R8G8B8A8_UNORM,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
#endif
+ });
-int main() {
+ const handle<device_texture> output_texture_handle = device.create_texture({
+ .width = static_cast<uint32_t>(image_width),
+ .height = static_cast<uint32_t>(image_height),
+#if VK
+ .usages = VK_IMAGE_USAGE_STORAGE_BIT,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
+ .format = DXGI_FORMAT_R8G8B8A8_UNORM,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+#endif
+ });
+
+ const handle<device_texture> ui_texture_handle = device.create_texture({
+ .width = static_cast<uint32_t>(atlas_width),
+ .height = static_cast<uint32_t>(atlas_height),
+#if VK
+ .usages = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .states = D3D12_RESOURCE_STATE_COPY_DEST,
+ .usages = D3D12_RESOURCE_FLAG_NONE,
+ .format = DXGI_FORMAT_R8G8B8A8_UNORM,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+#endif
+ .name = "glyph atlas"
+ });
-#if defined(ENABLE_RENDERDOC)
- auto* rdoc_api = enable_renderdoc();
+ const handle<device_texture> acc_handle = device.create_texture({
+ .width = static_cast<uint32_t>(window_width),
+ .height = static_cast<uint32_t>(window_height),
+#if VK
+ .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
+ .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
+ .format = DXGI_FORMAT_R32G32B32A32_FLOAT,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
#endif
+ .name = "accumulation texture"
+ });
- const float aspect_ratio = 16.0 / 9.0;
- const auto width = 400;
- auto height = (uint32_t)(width / aspect_ratio);
+ const handle<device_texture> result_handle = device.create_texture({
+ .width = static_cast<uint32_t>(window_width),
+ .height = static_cast<uint32_t>(window_height),
+#if VK
+ .usages = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
+ .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .states = D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
+ .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
+ .format = DXGI_FORMAT_R32G32B32A32_FLOAT,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+#endif
+ .name = "output texture"
+ });
- window wnd { width, height };
+ const handle<device_texture> transmittance_lut_handle = device.create_texture({
+ .width = static_cast<uint32_t>(1024),
+ .height = static_cast<uint32_t>(1024),
+#if VK
+ .usages = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
+ .format = VK_FORMAT_R16G16B16A16_SFLOAT,
+ .type = VK_IMAGE_TYPE_2D,
+#else
+ .usages = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
+ .format = DXGI_FORMAT_R8G8B8A8_UNORM,
+ .type = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
+#endif
+ .name = "transmittance_lut",
+ });
- float delta_time = 0.f;
- uint64_t frame_count = 0;
- auto start = std::chrono::high_resolution_clock::now();
- auto end = std::chrono::high_resolution_clock::now();
+#if VK
+ u32 acc_storage_index = device.get_texture(acc_handle).get_storage_index();
+ u32 result_storage_index = device.get_texture(result_handle).get_storage_index();
+#endif
- point3 position { 13.f, 2.f, -3.f };
- point3 target {};
- const auto v_fov = 90.f;
- const auto aperture = 0.1f;
- const auto focus_distance = 10.f;
+ const device_texture& ui_texture = device.get_texture(ui_texture_handle);
+ const device_texture& transmittance_lut = device.get_texture(transmittance_lut_handle);
+ debug_texture_list.push_back(transmittance_lut_handle);
- vkrenderer renderer { wnd };
+ io.Fonts->SetTexID(reinterpret_cast<void*>(static_cast<uintptr_t>(ui_texture.get_sampled_index())));
- ImGui::CreateContext();
- ImGuiIO &io = ImGui::GetIO();
- io.DisplaySize.x = (float)width;
- io.DisplaySize.y = (float)height;
- auto main_scene = scene(camera(position, target, v_fov, aspect_ratio, aperture, focus_distance), width, height);
+#if VK
+ std::array<graphics_command_buffer, 4U> graphics_command_buffers;
+ device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), QueueType::GRAPHICS, "graphics_cmd_buf");
+#else
+ std::array<dx12::graphics_command_buffer, 4U> graphics_command_buffers;
+ device.allocate_command_buffers(graphics_command_buffers.data(), graphics_command_buffers.size(), dx12::QueueType::GRAPHICS);
+#endif
- auto *raytracing_pass = renderer.create_compute_renderpass();
- raytracing_pass->set_pipeline("compute");
- watcher::watch_file(std::filesystem::path("../shaders/compute.comp"), [&]() {
- LPCSTR app_name = "glslc.exe --target-env=vulkan1.2 -std=460 ../shaders/compute.comp -o shaders/compute.comp.spv -I \"../shaders/include\"\0";
- STARTUPINFO start_info {};
- PROCESS_INFORMATION proc_info {};
- if (FAILED(CreateProcessA(
- app_name,
- nullptr,
- nullptr,
- nullptr,
- FALSE,
- 0,
- nullptr,
- nullptr,
- &start_info,
- &proc_info
- )))
- log_last_error();
- WaitForSingleObject(proc_info.hProcess, INFINITE);
- CloseHandle(proc_info.hProcess);
- CloseHandle(proc_info.hThread);
+ // =============
+ // API test code
+ // =============
+ RD_START_CAPTURE;
+ graphics_command_buffers[0].start();
+
+#if VK
+ graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+ graphics_command_buffers[0].barrier(ui_texture_handle, VK_PIPELINE_STAGE_2_TRANSFER_BIT, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+#endif
+
+ graphics_command_buffers[0].copy(staging_buffer_handle, gpu_texture_handle);
+ graphics_command_buffers[0].copy(staging_buffer_handle, second_texture, buffer_offset);
+ graphics_command_buffers[0].copy(staging_buffer_handle, ui_texture_handle, ui_offset);
+#if VK
+ graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
+ graphics_command_buffers[0].barrier(second_texture, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL);
- raytracing_pass->set_pipeline("compute");
- });
- auto *accumulation_texture = vkrenderer::create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT);
- auto *output_texture = vkrenderer::create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT);
- raytracing_pass->set_constant(0, main_scene.scene_buffer);
- raytracing_pass->set_constant(8, main_scene.bvh_buffer);
- raytracing_pass->set_constant(16, main_scene.indices_buffer);
- raytracing_pass->set_constant(24, main_scene.positions_buffer);
- raytracing_pass->set_constant(32, main_scene.normals_buffer);
- raytracing_pass->set_constant(40, main_scene.uvs_buffer);
- raytracing_pass->set_constant(48, main_scene.materials_buffer);
- raytracing_pass->set_dispatch_size(width / 8 + 1, height / 8 + 1, 1);
+ {
+ device_buffer& draws_uniform_buffer = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW);
+ {
+ struct params {
+ u32 input1;
+ u32 input2;
+ u32 output;
+ u32 pad;
+ } *params = draws_uniform_buffer.allocate<struct params>();
+ params->input1 = device.get_texture(second_texture).get_storage_index();
+ params->input2 = device.get_texture(gpu_texture_handle).get_storage_index();
+ params->output = device.get_texture(output_texture_handle).get_storage_index();
- // uint8_t *pixels = nullptr;
- // int atlas_width, atlas_height;
- // io.Fonts->GetTexDataAsRGBA32(&pixels, &atlas_width, &atlas_height);
- // auto *ui_texture = renderer.create_2d_texture(atlas_width, atlas_height, VK_FORMAT_R8G8B8A8_UNORM);
- // io.Fonts->SetTexID((void *)&ui_texture);
+ graphics_command_buffers[0].dispatch({
+ .pipeline = compute,
+ .group_size = { .vec = { static_cast<u32>(image_width), static_cast<u32>(image_height), 1U }},
+ .local_group_size = { .vec = { 8U, 8U, 1U }},
+ });
+ }
- // renderer.update_image(ui_texture, pixels);
- // auto ui_texture_sampler = renderer.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
+ {
+ struct params {
+ u32 lut_id;
+ u32 width;
+ u32 height;
+ u32 pad;
+ } *params = draws_uniform_buffer.allocate<struct params>();
+ params->lut_id = transmittance_lut.get_storage_index();
+ params->width = transmittance_lut.width;
+ params->height = transmittance_lut.height;
- // Buffer* ui_vertex_buffer = nullptr;
- // Buffer* ui_index_buffer = nullptr;
+ graphics_command_buffers[0].dispatch({
+ .pipeline = transmittance_lut_compute,
+ .group_size = { .vec = { 1024U, 1024U, 1U }},
+ .local_group_size = { .vec { 8U, 8U, 1U }},
+ });
+ }
+ }
- // const char* ui_shader_name = "ui";
- // std::vector<Primitive*> ui_primitives;
- // auto ui_pass = renderer.create_primitive_renderpass();
- // ui_pass->set_viewport(0.f, 0.f, (float)width, (float)height);
- // ui_pass->add_color_attachment(renderer.back_buffer_format());
- // ui_pass->finalize_render_pass();
+ graphics_command_buffers[0].barrier(gpu_texture_handle, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+#endif
- auto can_render = true;
+ graphics_command_buffers[0].stop();
- while (wnd.isOpen) {
- end = std::chrono::high_resolution_clock::now();
+ device.submit(graphics_command_buffers.data(), 1);
+ device.wait();
- delta_time = std::chrono::duration<float, std::milli>(end - start).count();
+ RD_END_CAPTURE;
- start = std::chrono::high_resolution_clock::now();
+ END_MARKER(STARTUP);
- io.DeltaTime = delta_time;
+ watch_file("../shaders/compute.comp", watch_func);
- watcher::pull_changes();
+#if VK
+ std::array<handle<device_texture>, 1U> color_attachment {};
+ constexpr uint32_t virtual_frames_count = 2U;
+ float delta = 0.f; // milliseconds
+ u32 speed = 1U;
+ uint32_t frame_count = 0U;
+ while(wnd.isOpen) {
+ vec3 dir = { 0.f, 0.f, 0.f };
+ float rot = 0.f;
+ LARGE_INTEGER start_qpc;
+ QueryPerformanceCounter(&start_qpc);
wnd.poll_events();
- for (auto &event : wnd.events) {
- switch (event.type) {
- case EVENT_TYPES::RESIZE: {
- main_scene.meta.width = event.width;
- main_scene.meta.height = event.height;
+ pull_changes();
- io.DisplaySize.x = (float)event.width;
- io.DisplaySize.y = (float)event.height;
+ uint32_t virtual_frame_index = frame_count % virtual_frames_count;
+ auto command_buffer = graphics_command_buffers[2U + virtual_frame_index];
- if (event.width == 0 && event.height == 0) {
- can_render = false;
- } else {
- can_render = true;
- renderer.recreate_swapchain();
- main_scene.meta.cam.set_aspect_ratio((float)event.width / (float)event.height);
+ main_scene.meta.sample_index++;
- delete accumulation_texture;
- delete output_texture);
- accumulation_texture = vkrenderer::create_2d_texture(event.width, event.height, VK_FORMAT_R32G32B32A32_SFLOAT);
- output_texture = vkrenderer::create_2d_texture(event.width, event.height, VK_FORMAT_R32G32B32A32_SFLOAT);
- raytracing_pass->set_dispatch_size(event.width / 8 + 1, event.height / 8 + 1, 1);
+ //
+ // IOs
+ //
+ {
+ io.AddMouseButtonEvent(BUTTON::LEFT, wnd.mouse[BUTTON::LEFT]);
+ io.AddMouseButtonEvent(BUTTON::RIGHT, wnd.mouse[BUTTON::LEFT]);
+ io.AddMouseButtonEvent(BUTTON::MIDDLE, wnd.mouse[BUTTON::LEFT]);
+ for (event& event : wnd.events) {
+ if (event.type == EVENT_TYPE::MOUSE_MOVE) {
+ io.AddMousePosEvent(static_cast<float>(event.data.position.x), static_cast<float>(event.data.position.y));
+ } else if (event.type == EVENT_TYPE::MOUSE_WHEEL) {
+ io.AddMouseWheelEvent(static_cast<float>(event.data.delta.x), static_cast<float>(event.data.delta.y));
}
- main_scene.meta.sample_index = 1;
+ if (event.type == EVENT_TYPE::KEY_PRESS) {
+ if (event.data.key == KEY::F2) {
+#if ENABLE_RENDERDOC
+ if (!rdoc_api->IsTargetControlConnected()) {
+ rdoc_api->LaunchReplayUI(true, nullptr);
+ }
+#endif
+ }
+ }
- break;
+ if (event.type == EVENT_TYPE::KEY_DOWN) {
+ if (event.data.key == KEY::W) {
+ dir += main_scene.meta.cam.forward;
+ }
+ if (event.data.key == KEY::A) {
+ dir += -main_scene.meta.cam.right;
+ }
+ if (event.data.key == KEY::S) {
+ dir += -main_scene.meta.cam.forward;
+ }
+ if (event.data.key == KEY::D) {
+ dir += main_scene.meta.cam.right;
+ }
+ if (event.data.key == KEY::SPACE) {
+ dir += vec3 { 0.f, 1.f, 0.f };
+ }
+ if (event.data.key == KEY::LCTRL) {
+ dir += vec3 { 0.f, -1.f, 0.f };
+ }
+ if (event.data.key == KEY::E) {
+ rot += 0.001f;
+ }
+ if (event.data.key == KEY::Q) {
+ rot += -0.001f;
+ }
+ if (event.data.key == KEY::PAGE_UP) {
+ speed++;
+ }
+ if (event.data.key == KEY::PAGE_DOWN) {
+ if (speed > 1U) {
+ speed--;
+ }
+ }
+
+ }
}
- case EVENT_TYPES::KEY_PRESS: {
- auto move_speed = 1.f * delta_time;
- if (wnd.keyboard[KEYS::LSHIFT] || wnd.keyboard[KEYS::RSHIFT]) { move_speed *= 10.f; }
+ }
- vec3 move_vec{};
+ if (!dir.is_zero()) {
+ main_scene.meta.cam.move(dir.normalize() * delta * static_cast<float>(speed));
+ main_scene.meta.sample_index = 1U;
+ }
+ if (rot != 0.f) {
+ main_scene.meta.cam.rotate_y(rot * delta * static_cast<float>(speed));
+ main_scene.meta.sample_index = 1U;
+ }
- switch (event.key) {
- case KEYS::W: {
- move_vec = main_scene.meta.cam.forward * move_speed;
- break;
- }
+ ui(&main_scene, delta);
- case KEYS::S: {
- move_vec = -main_scene.meta.cam.forward * move_speed;
- break;
- }
- case KEYS::D: {
- move_vec = main_scene.meta.cam.right * move_speed;
- break;
- }
- case KEYS::A: {
- move_vec = -main_scene.meta.cam.right * move_speed;
- break;
- }
- case KEYS::E: {
- main_scene.meta.cam.rotate_y(0.001f * delta_time);
- main_scene.meta.sample_index = 1;
- break;
- }
- case KEYS::Q: {
- main_scene.meta.cam.rotate_y(-0.001f * delta_time);
- main_scene.meta.sample_index = 1;
- break;
- }
- case KEYS::SPACE: {
- move_vec = main_scene.meta.cam.up * move_speed;
- break;
- }
- case KEYS::LCTRL: {
- move_vec = -main_scene.meta.cam.up * move_speed;
- break;
- }
- default:
- break;
- }
+ ImGuiMouseCursor cursor_style = ImGui::GetMouseCursor();
+ window::set_cursor(static_cast<CURSOR_TYPE>(cursor_style));
- main_scene.meta.cam.move(move_vec);
+ // ==================
+ // copy ImGui buffers
+ // ==================
+ const ImDrawData* draw_data = ImGui::GetDrawData();
+ {
+ u32 vertex_offset = 0;
+ u32 index_offset = 0;
+ for (s32 index = 0U; index < draw_data->CmdListsCount; index++) {
+ ImDrawList* cmd_list = draw_data->CmdLists[index];
- if (!move_vec.near_zero()) { main_scene.meta.sample_index = 1; }
+ size_t vertex_bytes_size = sizeof(ImDrawVert) * cmd_list->VtxBuffer.size();
+ u8* vtx_ptr = static_cast<uint8_t*>(vertex_buffer.mapped_ptr) + vertex_offset;
+ memcpy(vtx_ptr, cmd_list->VtxBuffer.Data, vertex_bytes_size);
+ vertex_offset += static_cast<off_t>(vertex_bytes_size);
- break;
- }
- case EVENT_TYPES::BUTTON_PRESS: {
- if (event.button == BUTTONS::LEFT) { io.MouseDown[0] = true; }
- if (event.button == BUTTONS::RIGHT) { io.MouseDown[1] = true; }
- break;
+ size_t index_bytes_size = sizeof(ImDrawIdx) * cmd_list->IdxBuffer.size();
+ memcpy(static_cast<uint8_t*>(index_buffer.mapped_ptr) + index_offset, cmd_list->IdxBuffer.Data, index_bytes_size);
+ index_offset += static_cast<off_t>(index_bytes_size);
}
- case EVENT_TYPES::BUTTON_RELEASE: {
- if (event.button == BUTTONS::LEFT) { io.MouseDown[0] = false; }
- if (event.button == BUTTONS::RIGHT) { io.MouseDown[1] = false; }
- break;
+ }
+
+ // ======================
+ // global uniforms update
+ // ======================
+ {
+ metadata * const globals = vkdevice::get().get_bindingmodel().get_uniform_buffer(UniformTypes::GLOBAL).allocate<metadata>();
+ memcpy(static_cast<void*>(globals), &main_scene.meta, sizeof(main_scene.meta));
+ }
+
+ // TODO: Refactor backbuffer acquisition
+ auto backbuffer = surface.swapchain_images[device.acquire_image_index(surface_handle)];
+ color_attachment[0] = backbuffer;
+
+ // RD_START_CAPTURE;
+ command_buffer.start();
+
+ command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
+
+ {
+ if (virtual_frame_index == 0) {
+ command_buffer.barrier(result_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
+ command_buffer.barrier(acc_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL);
+ } else {
+ command_buffer.barrier(result_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL);
+ command_buffer.barrier(acc_handle, VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
}
- case EVENT_TYPES::MOUSE_MOVE: {
- io.MousePos = ImVec2{(float)event.x, (float)event.y};
- break;
+
+ {
+ struct params {
+ uintptr_t bvh_buffer;
+ uintptr_t indices_buffer;
+ uintptr_t positions_buffer;
+ uintptr_t normals_buffer;
+ uintptr_t uvs_buffer;
+ uintptr_t materials_buffer;
+ u32 output_id;
+ u32 accumulation_id;
+ };
+ struct params* uniforms = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW).allocate<params>();
+ uniforms->bvh_buffer = main_scene.bvh_buffer_address();
+ uniforms->indices_buffer = main_scene.indices_buffer_address();
+ uniforms->positions_buffer = main_scene.positions_buffer_address();
+ uniforms->normals_buffer = main_scene.normals_buffer_address();
+ uniforms->uvs_buffer = main_scene.uvs_buffer_address();
+ uniforms->materials_buffer = main_scene.materials_buffer_address();
+ uniforms->output_id = (virtual_frame_index == 0U) ? result_storage_index : acc_storage_index;
+ uniforms->accumulation_id = (virtual_frame_index == 0U) ? acc_storage_index : result_storage_index;
+
+ command_buffer.dispatch({
+ .pipeline = raytracing,
+ .group_size = { .vec { window_width / main_scene.meta.downscale_factor, window_height / main_scene.meta.downscale_factor, 1U, } },
+ .local_group_size = { .vec { 8U, 8U, 1U, } },
+ });
}
- default:
- break;
+
+ {
+ struct params {
+ u32 output_id;
+ u32 accumulation_id;
+ } *uniforms = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW).allocate<params>();
+ // TODO: Refactor backbuffer acquisition
+ uniforms->output_id = device.get_texture(backbuffer).get_storage_index();
+ uniforms->accumulation_id = (virtual_frame_index == 0U) ? result_storage_index : acc_storage_index;
+
+ command_buffer.dispatch({
+ .pipeline = tonemapping,
+ .group_size = { .vec { window_width / main_scene.meta.downscale_factor, window_height / main_scene.meta.downscale_factor, 1U, } },
+ .local_group_size = { .vec { 8U, 8U, 1U, } },
+ });
}
}
- wnd.events.clear();
+ command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, VK_ACCESS_2_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- raytracing_pass->set_ouput_texture(output_texture);
- raytracing_pass->set_constant(60, accumulation_texture);
+ command_buffer.begin_renderpass({
+ .render_area = {
+ .x = static_cast<int32_t>(draw_data->DisplayPos.x),
+ .y = static_cast<int32_t>(draw_data->DisplayPos.y),
+ .width = static_cast<uint32_t>(draw_data->DisplaySize.x),
+ .height = static_cast<uint32_t>(draw_data->DisplaySize.y),
+ },
+ .color_attachments = color_attachment,
+ });
- renderer.begin_frame();
+ auto& draws_uniform_buffer = device.get_bindingmodel().get_uniform_buffer(UniformTypes::DRAW);
+ uint32_t vertex_offset = 0;
+ uint32_t index_offset = 0;
+ for (s32 index = 0U ; index < draw_data->CmdListsCount; index++) {
+ auto* cmd_list = draw_data->CmdLists[index];
- // update_ui(main_scene, delta_time);
-
- if (can_render) {
- render(main_scene, renderer);
+ for (auto& draw_command : cmd_list->CmdBuffer) {
+ ImTextureID texture_id = draw_command.TexRef.GetTexID();
+ {
+ struct ui_params {
+ u64 vertex_buffer;
+ float scale[2U];
+ float translate[2U];
+ uint32_t texture_index;
+ u32 padding;
+ };
+ struct ui_params* ui_param = draws_uniform_buffer.allocate<ui_params>();
+ *ui_param = ui_params{
+ .vertex_buffer = vertex_buffer.device_address,
+ .scale {
+ 2.f / draw_data->DisplaySize.x,
+ 2.f / draw_data->DisplaySize.y,
+ },
+ .translate {
+ -1.f - draw_data->DisplayPos.x * (2.f / draw_data->DisplaySize.x),
+ -1.f - draw_data->DisplayPos.y * (2.f / draw_data->DisplaySize.y),
+ },
+ .texture_index = *reinterpret_cast<uint32_t*>(&texture_id),
+ };
+ }
- std::swap(output_texture, accumulation_texture);
+ command_buffer.draw_indexed({
+ .pipeline = graphics,
+ .index_buffer = index_buffer_handle,
+ .vertex_count = draw_command.ElemCount,
+ .vertex_offset = draw_command.VtxOffset + vertex_offset,
+ .index_offset = draw_command.IdxOffset + index_offset,
+ .instance_count = 1U,
+ });
+ }
+ vertex_offset += cmd_list->VtxBuffer.size();
+ index_offset += cmd_list->IdxBuffer.size();
}
- renderer.finish_frame();
+ command_buffer.end_renderpass();
+ command_buffer.barrier(backbuffer, VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
+
+ command_buffer.stop();
+
+ device.submit_before_present(surface_handle, &command_buffer, 1U);
+ device.present(surface_handle);
+ // device.wait();
+ LARGE_INTEGER end_qpc;
+ QueryPerformanceCounter(&end_qpc);
+ LONGLONG diff_qpc = end_qpc.QuadPart - start_qpc.QuadPart;
+ delta = static_cast<float>(diff_qpc * 1000LL) / freq.QuadPart;
frame_count++;
+
+ // RD_END_CAPTURE;
}
- //-------------------------
- // Image exporter
- //-------------------------
- // PPM format header
- // std::cout << "P3\n" << width << '\n' << height << "\n255" << std::endl;
- // auto output_image = renderer.output_image();
- // for (size_t index = 0; index < height * width; index++) {
- // write_color(std::cout, output_image[index]);
- // }
+ device.wait();
+
+ main_scene.deinit();
+
+ device.destroy_surface(surface_handle);
+
+ device.destroy_pipeline(compute);
+ device.destroy_pipeline(graphics);
+ device.destroy_pipeline(raytracing);
+ device.destroy_pipeline(tonemapping);
+
+ device.destroy_pipeline(transmittance_lut_compute);
+ device.destroy_texture(transmittance_lut_handle);
+
+ device.destroy_texture(gpu_texture_handle);
+ device.destroy_texture(second_texture);
+ device.destroy_texture(output_texture_handle);
+ device.destroy_texture(ui_texture_handle);
+ device.destroy_texture(acc_handle);
+ device.destroy_texture(result_handle);
+
+ device.destroy_buffer(staging_buffer_handle);
+ device.destroy_buffer(vertex_buffer_handle);
+ device.destroy_buffer(index_buffer_handle);
+ device.deinit();
- // std::cerr << "Done !" << std::endl;
+ ImGui::DestroyContext();
+#endif // VK
return 0;
}
diff --git a/src/primitive-renderpass.cpp b/src/primitive-renderpass.cpp
deleted file mode 100644
index 45d48e8..0000000
--- a/src/primitive-renderpass.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-#include "primitive-renderpass.hpp"
-
-#include "vulkan-loader.hpp"
-
-
-Primitive::Primitive(PrimitiveRenderpass& render_pass)
- : api(vkrenderer::api), primitive_render_pass(render_pass)
- {};
-
-void Primitive::set_pipeline(const char* shader_name) {
- std::vector<VkDynamicState> dynamic_states {
- VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR
- };
-
- pipeline = api.create_graphics_pipeline(shader_name, (VkShaderStageFlagBits)(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT), primitive_render_pass.render_pass, dynamic_states);
-}
-
-void Primitive::set_constant_offset(off_t offset) {
- constant_offset = offset;
-}
-
-void Primitive::set_constant(off_t offset, uint64_t* constant) {
- memcpy(constants + offset, constant, sizeof(uint64_t));
-}
-
-void Primitive::set_constant(off_t offset, Texture* texture) {
- const auto& image = api.get_image(texture->device_image);
-
- memcpy(constants + offset, (void*)&image.bindless_storage_index, sizeof(bindless_index));
-}
-
-void Primitive::set_constant(off_t offset, Buffer* buffer) {
- const auto& device_buffer = api.get_buffer(buffer->device_buffer);
- memcpy(constants + offset, (void*)&device_buffer.device_address, sizeof(VkDeviceAddress));
-}
-
-void Primitive::set_constant(off_t offset, Sampler* sampler) {
- const auto& device_sampler = api.get_sampler(sampler->device_sampler);
- memcpy(constants + offset, (void*)&device_sampler.bindless_index, sizeof(bindless_index));
-}
-
-void Primitive::set_index_buffer(Buffer* buffer) {
- this->index_buffer = buffer;
-}
-
-void Primitive::set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height) {
- scissor.offset.x = x;
- scissor.offset.y = y;
- scissor.extent.width = width;
- scissor.extent.height = height;
-}
-
-void Primitive::set_draw_info(size_t vertex_count, off_t indices_off, off_t vertex_off) {
- this->element_count = vertex_count;
- this->indices_offset = indices_off;
- this->vertex_offset = vertex_off;
-}
-
-void Primitive::render(VkCommandBuffer command_buffer) {
- vkCmdSetScissor(command_buffer, 0, 1, &scissor);
-
- api.update_constants(command_buffer, VK_SHADER_STAGE_ALL_GRAPHICS, constant_offset, 64, (void*)&constants);
-
- api.draw(
- command_buffer,
- pipeline,
- index_buffer->device_buffer,
- element_count,
- indices_offset,
- vertex_offset
- );
-};
-
-
-PrimitiveRenderpass::PrimitiveRenderpass(vkapi& api)
- : Renderpass(api) {
- };
-
-void PrimitiveRenderpass::add_primitive(Primitive* new_primitive) {
- primitives.push_back(new_primitive);
-}
-
-void PrimitiveRenderpass::add_color_attachment(VkFormat format) {
- color_attachments_format.push_back(format);
-}
-
-void PrimitiveRenderpass::set_viewport(float x, float y, float width, float height) {
- viewport.x = x;
- viewport.y = y;
- viewport.width = width;
- viewport.height = height;
-}
-
-void PrimitiveRenderpass::set_color_attachment(uint32_t index, Texture* attachment) {
- const auto& device_image = api.get_image(attachment->device_image);
-
- if (device_image.size.width != framebuffers[0].size.width ||
- device_image.size.height != framebuffers[0].size.height) {
- recreate_framebuffers();
- }
-
-
- color_attachments[index] = attachment;
- color_attachments_view[index] = device_image.view;
-}
-
-void PrimitiveRenderpass::finalize_render_pass() {
- render_pass = api.create_render_pass(color_attachments_format, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
- create_framebuffers();
-
- color_attachments.resize(color_attachments_format.size());
- color_attachments_view.resize(color_attachments_format.size());
-}
-
-void PrimitiveRenderpass::execute(vkrenderer& renderer, VkCommandBuffer command_buffer) {
- VkExtent2D extent = { .width = (uint32_t)viewport.width, .height = (uint32_t)viewport.height };
-
- for (auto& attachment : color_attachments) {
- api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, attachment->device_image);
- }
-
-
- api.begin_render_pass(command_buffer, render_pass, color_attachments_view, framebuffers[renderer.frame_index()], extent);
-
- vkCmdSetViewport(command_buffer, 0, 1, &viewport);
-
- for (auto* primitive : primitives) {
- primitive->render(command_buffer);
- }
-
- api.end_render_pass(command_buffer);
-
- primitives.clear();
-}
-
-void PrimitiveRenderpass::create_framebuffers() {
- VkExtent2D size { .width = (uint32_t) viewport.width, .height = (uint32_t) viewport.height };
-
- for(auto& framebuffer : framebuffers) {
- framebuffer = api.create_framebuffer(render_pass, color_attachments_format, size);
- }
-}
-
-void PrimitiveRenderpass::recreate_framebuffers() {
- for (auto& framebuffer: framebuffers) {
- api.destroy_framebuffer(framebuffer);
- }
-
- create_framebuffers();
-}
diff --git a/src/vk-api.cpp b/src/vk-api.cpp
deleted file mode 100644
index 2040b44..0000000
--- a/src/vk-api.cpp
+++ /dev/null
@@ -1,1257 +0,0 @@
-#include "vk-api.hpp"
-
-#include <cassert>
-#include <filesystem>
-
-#include <vk_mem_alloc.h>
-
-#include "utils.hpp"
-#include "vk-context.hpp"
-#include "window.hpp"
-
-#include "vulkan-loader.hpp"
-
-#ifdef _DEBUG
-#define VKRESULT(result) assert(result == VK_SUCCESS);
-#else
-#define VKRESULT(result) result;
-#endif
-
-
-vkapi::vkapi(vkcontext& context)
- : context(context) {
- VkDescriptorPoolSize descriptor_pools_sizes[] = {
- {
- .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
- .descriptorCount = (uint32_t)global_descriptor::pool_size,
- },
- {
- .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = (uint32_t)global_descriptor::pool_size,
- },
- {
- .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
- .descriptorCount = (uint32_t)global_descriptor::pool_size,
- },
- {
- .type = VK_DESCRIPTOR_TYPE_SAMPLER,
- .descriptorCount = (uint32_t)global_descriptor::pool_size,
- }
- };
-
- VkDescriptorPoolCreateInfo descriptor_pool_create_info = {};
- descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- descriptor_pool_create_info.pNext = nullptr;
- descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
- descriptor_pool_create_info.maxSets = 0xff;
- descriptor_pool_create_info.poolSizeCount = sizeof(descriptor_pools_sizes) / sizeof(descriptor_pools_sizes[0]);
- descriptor_pool_create_info.pPoolSizes = descriptor_pools_sizes;
-
- VKRESULT(vkCreateDescriptorPool(context.device, &descriptor_pool_create_info, nullptr, &descriptor_pool))
-
- // Global descriptor
- VkDescriptorSetLayoutBinding bindless_layout_bindings[] = {
- {
- .binding = 0,
- .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
- .descriptorCount = global_descriptor::pool_size,
- .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- },
- {
- .binding = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
- .descriptorCount = global_descriptor::pool_size,
- .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- },
- {
- .binding = 2,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = global_descriptor::pool_size,
- .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- },
- };
-
- VkDescriptorBindingFlags flags[3] = {
- VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT,
- };
-
- VkDescriptorSetLayoutBindingFlagsCreateInfo descriptor_set_layout_binding_flags = {};
- descriptor_set_layout_binding_flags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
- descriptor_set_layout_binding_flags.pNext = VK_NULL_HANDLE;
- descriptor_set_layout_binding_flags.bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags);
- descriptor_set_layout_binding_flags.pBindingFlags = flags;
-
- VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info = {};
- descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- descriptor_set_layout_create_info.pNext = &descriptor_set_layout_binding_flags;
- descriptor_set_layout_create_info.flags = 0;
- descriptor_set_layout_create_info.bindingCount = sizeof(bindless_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding);
- descriptor_set_layout_create_info.pBindings = bindless_layout_bindings;
-
- VKRESULT(vkCreateDescriptorSetLayout(context.device, &descriptor_set_layout_create_info, nullptr, &bindless_descriptor.set_layout))
-
-
- VkPushConstantRange push_constants[] = {
- {
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
- .offset = 0,
- .size = 64,
- },
- {
- .stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS,
- .offset = 64,
- .size = 64,
- },
- // {
- // .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
- // .offset = 64,
- // .size = 32,
- // },
- // {
- // .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
- // .offset = 96,
- // .size = 32,
- // },
- };
-
- VkPipelineLayoutCreateInfo layout_create_info = {};
- layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- layout_create_info.pNext = nullptr;
- layout_create_info.flags = 0;
- layout_create_info.setLayoutCount = 1;
- layout_create_info.pSetLayouts = &bindless_descriptor.set_layout;
- layout_create_info.pushConstantRangeCount = sizeof(push_constants) / sizeof(VkPushConstantRange);
- layout_create_info.pPushConstantRanges = push_constants;
-
- VKRESULT(vkCreatePipelineLayout(context.device, &layout_create_info, nullptr, &bindless_descriptor.pipeline_layout))
-
-
- VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {};
- descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- descriptor_set_allocate_info.pNext = VK_NULL_HANDLE;
- descriptor_set_allocate_info.descriptorPool = descriptor_pool;
- descriptor_set_allocate_info.descriptorSetCount = 1;
- descriptor_set_allocate_info.pSetLayouts = &bindless_descriptor.set_layout;
-
- vkAllocateDescriptorSets(context.device, &descriptor_set_allocate_info, &bindless_descriptor.set);
-}
-
-vkapi::~vkapi() {
- // Free resources
- for (handle buffer_handle = 0; buffer_handle < buffers.size(); buffer_handle++) {
- destroy_buffer(buffer_handle);
- }
-
- for (handle image_handle = 0; image_handle < images.size(); image_handle++) {
- destroy_image(image_handle);
- }
-
- for (handle sampler_handle = 0; sampler_handle < samplers.size(); sampler_handle++) {
- destroy_sampler(sampler_handle);
- }
-
- // Free bindless descriptor stuff
- vkDestroyDescriptorSetLayout(context.device, bindless_descriptor.set_layout, nullptr);
- vkDestroyPipelineLayout(context.device, bindless_descriptor.pipeline_layout, nullptr);
- vkFreeDescriptorSets(context.device, descriptor_pool, 1, &bindless_descriptor.set);
-
- vkDestroyDescriptorPool(context.device, descriptor_pool, nullptr);
-}
-
-handle vkapi::create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, uint32_t mem_usage) {
- auto* buffer = new struct buffer();
-
- VkBufferCreateInfo buffer_info = {};
- buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
- buffer_info.size = data_size;
- buffer_info.usage = buffer_usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR;
-
- VmaAllocationCreateInfo alloc_create_info = {};
- alloc_create_info.usage = (VmaMemoryUsage)mem_usage;
- alloc_create_info.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
-
- VmaAllocationInfo alloc_info{};
-
- VKRESULT(vmaCreateBuffer(context.allocator, &buffer_info, &alloc_create_info, &buffer->handle, &buffer->alloc, &alloc_info))
-
- VkBufferDeviceAddressInfo buffer_device_address_info = {};
- buffer_device_address_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
- buffer_device_address_info.pNext = VK_NULL_HANDLE;
- buffer_device_address_info.buffer = buffer->handle;
-
- buffer->size = data_size;
-
- buffer->device_address = vkGetBufferDeviceAddress(context.device, &buffer_device_address_info);
- buffer->device_ptr = alloc_info.pMappedData;
-
- buffers.push_back(buffer);
-
- return buffers.size() - 1;
-}
-
-void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size) {
- VkBufferCopy buffer_copy = {};
- buffer_copy.srcOffset = 0;
- buffer_copy.dstOffset = 0;
- buffer_copy.size = size;
-
- vkCmdCopyBuffer(cmd_buf, buffers[src]->handle, buffers[dst]->handle, 1, &buffer_copy);
-}
-
-// TODO: Change handle type, here we don't know what type of ressources we are working with
-void vkapi::copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size, size_t buffer_offset) {
- auto& dst_image = images[dst];
-
- VkImageSubresourceLayers image_subresource_layers = {};
- image_subresource_layers.aspectMask = dst_image->subresource_range.aspectMask;
- image_subresource_layers.mipLevel = 0;
- image_subresource_layers.baseArrayLayer = 0;
- image_subresource_layers.layerCount = 1;
-
- VkBufferImageCopy buffer_to_image_copy = {};
- buffer_to_image_copy.bufferOffset = buffer_offset;
- buffer_to_image_copy.bufferRowLength = 0;
- buffer_to_image_copy.bufferImageHeight = 0;
- buffer_to_image_copy.imageSubresource = image_subresource_layers;
- buffer_to_image_copy.imageOffset = { 0, 0, 0 };
- buffer_to_image_copy.imageExtent = dst_image->size;
-
- vkCmdCopyBufferToImage(cmd_buf, buffers[src]->handle, dst_image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_to_image_copy);
-}
-
-void vkapi::destroy_buffer(handle buffer) {
- vmaDestroyBuffer(context.allocator, buffers[buffer]->handle, buffers[buffer]->alloc);
-
- // TODO: Free the element once using freelists
- // buffers.erase(buffer.handle);
-}
-
-handle vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages) {
- auto* image = new struct image();
-
- image->size = size;
-
- image->subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- image->subresource_range.baseMipLevel = 0;
- image->subresource_range.levelCount = 1;
- image->subresource_range.baseArrayLayer = 0;
- image->subresource_range.layerCount = 1;
-
- VkImageCreateInfo img_create_info = {};
- img_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- img_create_info.pNext = VK_NULL_HANDLE;
- img_create_info.flags = 0;
- img_create_info.imageType = VK_IMAGE_TYPE_2D;
- img_create_info.format = format;
- img_create_info.extent = size;
- img_create_info.mipLevels = 1;
- img_create_info.arrayLayers = 1;
- img_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
- img_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
- img_create_info.usage = usages;
- img_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- img_create_info.queueFamilyIndexCount = 0;
- img_create_info.pQueueFamilyIndices = nullptr;
- img_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-
- VmaAllocationCreateInfo alloc_create_info = {};
- alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_ONLY;
-
- VmaAllocationInfo alloc_info{};
-
- VKRESULT(vmaCreateImage(context.allocator, &img_create_info, &alloc_create_info, &image->handle, &image->alloc, &alloc_info))
-
- VkImageViewCreateInfo image_view_create_info = {};
- image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- image_view_create_info.pNext = nullptr;
- image_view_create_info.flags = 0;
- image_view_create_info.image = image->handle;
- image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
- image_view_create_info.format = format;
- image_view_create_info.components = {
- VK_COMPONENT_SWIZZLE_IDENTITY,
- VK_COMPONENT_SWIZZLE_IDENTITY,
- VK_COMPONENT_SWIZZLE_IDENTITY,
- VK_COMPONENT_SWIZZLE_IDENTITY
- };
- image_view_create_info.subresourceRange = image->subresource_range;
-
- VKRESULT(vkCreateImageView(context.device, &image_view_create_info, VK_NULL_HANDLE, &image->view))
-
- image->format = format;
- image->usages = usages;
-
- images.push_back(image);
-
- auto image_handle = images.size() - 1;
-
- if ((usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0U) {
- image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
- update_descriptor_image(image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
- }
-
- if ((usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) {
- image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
- update_descriptor_image(image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
- }
-
- return image_handle;
-}
-
-void vkapi::destroy_image(handle image) {
- auto* current_image = images[image];
-
- if (current_image->bindless_storage_index != 0U) {
- bindless_descriptor.free(current_image->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
- }
-
- if (current_image->bindless_sampled_index != 0U) {
- bindless_descriptor.free(current_image->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
- }
-
- vmaDestroyImage(context.allocator, current_image->handle, current_image->alloc);
- vkDestroyImageView(context.device, current_image->view, nullptr);
-
- // TODO: Free once using freelist
- // images.erase(image.handle);
-}
-
-std::vector<handle> vkapi::create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count) {
- std::vector<handle> images_handles(image_count);
-
- for (size_t image_index = 0; image_index < image_count; image_index++) {
- images_handles[image_index] = create_image(size, format, usages);
- }
-
- return images_handles;
-}
-
-void vkapi::destroy_images(std::vector<handle>& imgs) {
- for (auto handle : imgs) {
- destroy_image(handle);
- }
-}
-
-VkFence vkapi::create_fence() const {
- VkFence fence;
- VkFenceCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- create_info.pNext = nullptr;
- create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
- VKRESULT(vkCreateFence(context.device, &create_info, nullptr, &fence))
-
- return fence;
-}
-
-void vkapi::destroy_fence(VkFence fence) const {
- vkDestroyFence(context.device, fence, nullptr);
-}
-
-std::vector<VkFence> vkapi::create_fences(size_t fences_count) const {
- std::vector<VkFence> fences{ fences_count };
-
- for (size_t fence_index = 0; fence_index < fences_count; fence_index++) {
- fences[fence_index] = create_fence();
- }
-
- return fences;
-}
-
-void vkapi::destroy_fences(VkFence fences[], size_t fences_count) const {
- for (size_t index{ 0 }; index < fences_count; index++) {
- vkDestroyFence(context.device, fences[index], nullptr);
- }
-}
-
-VkSemaphore vkapi::create_semaphore() const {
- VkSemaphore semaphore;
- VkSemaphoreCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- create_info.pNext = nullptr;
- create_info.flags = 0;
-
- VKRESULT(vkCreateSemaphore(context.device, &create_info, nullptr, &semaphore))
-
- return semaphore;
-}
-
-void vkapi::destroy_semaphore(VkSemaphore semaphore) const {
- vkDestroySemaphore(context.device, semaphore, nullptr);
-}
-
-std::vector<VkSemaphore> vkapi::create_semaphores(size_t semaphores_count) const {
- std::vector<VkSemaphore> semaphores{ semaphores_count };
-
- for (size_t semaphore_index{ 0 }; semaphore_index < semaphores_count; semaphore_index++) {
- semaphores[semaphore_index] = create_semaphore();
- }
-
- return semaphores;
-}
-
-void vkapi::destroy_semaphores(VkSemaphore semaphores[], size_t semaphores_count) const {
- for (size_t index{ 0 }; index < semaphores_count; index++) {
- vkDestroySemaphore(context.device, semaphores[index], nullptr);
- }
-}
-
-handle vkapi::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) {
- VkSamplerCreateInfo sampler_create_info = {};
- sampler_create_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
- sampler_create_info.pNext = VK_NULL_HANDLE;
- sampler_create_info.flags = 0;
- sampler_create_info.magFilter = filter;
- sampler_create_info.minFilter = filter;
- sampler_create_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
- sampler_create_info.addressModeU = address_mode;
- sampler_create_info.addressModeV = address_mode;
- sampler_create_info.addressModeW = address_mode;
- sampler_create_info.mipLodBias = 0.f;
- sampler_create_info.anisotropyEnable = VK_FALSE;
- sampler_create_info.compareEnable = VK_FALSE;
- sampler_create_info.compareOp = VK_COMPARE_OP_ALWAYS;
- sampler_create_info.minLod = 0.f;
- sampler_create_info.maxLod = 0.f;
- sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
- sampler_create_info.unnormalizedCoordinates = VK_FALSE;
-
- struct sampler* sampler = new struct sampler();
- VKRESULT(vkCreateSampler(context.device, &sampler_create_info, VK_NULL_HANDLE, &sampler->handle))
-
- sampler->bindless_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLER);
-
-
- samplers.push_back(sampler);
-
- update_descriptor_sampler(samplers.size() - 1);
-
- return samplers.size() - 1;
-}
-
-void vkapi::destroy_sampler(handle sampler) {
- auto* current_sampler = samplers[sampler];
- bindless_descriptor.free(current_sampler->bindless_index, VK_DESCRIPTOR_TYPE_SAMPLER);
-
- vkDestroySampler(context.device, current_sampler->handle, VK_NULL_HANDLE);
-
- // samplers.erase(sampler.handle);
-}
-
-VkCommandPool vkapi::create_command_pool() const {
- VkCommandPoolCreateInfo cmd_pool_create_info = {};
- cmd_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- cmd_pool_create_info.pNext = nullptr;
- cmd_pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- cmd_pool_create_info.queueFamilyIndex = context.graphics_queue.index;
-
- VkCommandPool command_pool;
- VKRESULT(vkCreateCommandPool(context.device, &cmd_pool_create_info, nullptr, &command_pool))
-
- return command_pool;
-}
-
-void vkapi::allocate_command_buffers(VkCommandPool command_pool, VkCommandBuffer* command_buffers, size_t count) const {
- VkCommandBufferAllocateInfo cmd_buf_allocate_info = {};
- cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- cmd_buf_allocate_info.pNext = VK_NULL_HANDLE;
- cmd_buf_allocate_info.commandPool = command_pool;
- cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- cmd_buf_allocate_info.commandBufferCount = count;
-
- vkAllocateCommandBuffers(context.device, &cmd_buf_allocate_info, command_buffers);
-}
-
-// TODO: attachment structure
-VkRenderPass vkapi::create_render_pass(std::vector<VkFormat>& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout) {
- std::vector<VkAttachmentDescription> attachments_description = {};
- std::vector<VkAttachmentReference> attachments_reference = {};
-
- for (size_t attachment_index = 0; attachment_index < color_attachments_format.size(); attachment_index++) {
- auto format = color_attachments_format[attachment_index];
- VkAttachmentDescription attachment_description = {};
- attachment_description.flags = 0;
- attachment_description.format = format;
- attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
- attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; // TODO: Set based on render pass usage
- attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // TODO: Set based on render pass usage
-
- attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachment_description.initialLayout = initial_layout;
- attachment_description.finalLayout = final_layout;
-
- attachments_description.push_back(attachment_description);
-
- VkAttachmentReference attachment_reference = {};
- attachment_reference.attachment = attachment_index;
- attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- attachments_reference.push_back(attachment_reference);
- }
-
- VkSubpassDescription subpass_description = {};
- subpass_description.flags = 0;
- subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass_description.colorAttachmentCount = attachments_reference.size();
- subpass_description.pColorAttachments = attachments_reference.data();
- subpass_description.pDepthStencilAttachment = VK_NULL_HANDLE;
- subpass_description.pResolveAttachments = VK_NULL_HANDLE;
- subpass_description.preserveAttachmentCount = 0;
- subpass_description.pPreserveAttachments = VK_NULL_HANDLE;
-
-
- VkSubpassDependency subpass_dependency[2] = {};
- subpass_dependency[0].srcSubpass = VK_SUBPASS_EXTERNAL;
- subpass_dependency[0].dstSubpass = 1; // First subpass attachment is used in
- subpass_dependency[0].srcStageMask = VK_PIPELINE_STAGE_NONE_KHR;
- subpass_dependency[0].dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
- subpass_dependency[0].srcAccessMask = 0;
- subpass_dependency[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- subpass_dependency[0].dependencyFlags = 0;
-
-
- subpass_dependency[1].srcSubpass = 1; // Last subpass attachment is used in
- subpass_dependency[1].dstSubpass = VK_SUBPASS_EXTERNAL;
- subpass_dependency[1].srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
- subpass_dependency[1].dstStageMask = VK_PIPELINE_STAGE_NONE_KHR;
- subpass_dependency[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- subpass_dependency[1].dstAccessMask = 0;
- subpass_dependency[1].dependencyFlags = 0;
-
-
- VkRenderPass render_pass;
- VkRenderPassCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- create_info.pNext = VK_NULL_HANDLE;
- create_info.flags = 0;
- create_info.attachmentCount = attachments_description.size();
- create_info.pAttachments = attachments_description.data();
- create_info.subpassCount = 1;
- create_info.pSubpasses = &subpass_description;
- // create_info.dependencyCount = sizeof(subpass_dependency) / sizeof(VkSubpassDependency);
- // create_info.pDependencies = subpass_dependency;
-
- VKRESULT(vkCreateRenderPass(context.device, &create_info, VK_NULL_HANDLE, &render_pass))
-
- return render_pass;
-}
-
-void vkapi::destroy_render_pass(VkRenderPass render_pass) {
- vkDestroyRenderPass(context.device, render_pass, VK_NULL_HANDLE);
-}
-
-framebuffer vkapi::create_framebuffer(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size) {
- VkFramebuffer framebuffer_handle;
-
- std::vector<VkFramebufferAttachmentImageInfo> attachments_image_infos(formats.size());
- for (size_t index = 0; index < formats.size(); index++) {
- VkFramebufferAttachmentImageInfo attachments_image_info = {};
- attachments_image_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO;
- attachments_image_info.pNext = VK_NULL_HANDLE;
- attachments_image_info.flags = 0;
- attachments_image_info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- attachments_image_info.width = size.width;
- attachments_image_info.height = size.height;
- attachments_image_info.layerCount = 1;
- attachments_image_info.viewFormatCount = 1;
- attachments_image_info.pViewFormats = &formats[index];
-
- attachments_image_infos[index] = attachments_image_info;
- }
-
- VkFramebufferAttachmentsCreateInfo attachments_create_info = {};
- attachments_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO;
- attachments_create_info.pNext = VK_NULL_HANDLE;
- attachments_create_info.attachmentImageInfoCount = attachments_image_infos.size();
- attachments_create_info.pAttachmentImageInfos = attachments_image_infos.data();
-
- VkFramebufferCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- create_info.pNext = &attachments_create_info;
- create_info.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
- create_info.renderPass = render_pass;
- create_info.attachmentCount = formats.size();
- create_info.pAttachments = VK_NULL_HANDLE;
- create_info.width = size.width;
- create_info.height = size.height;
- create_info.layers = 1;
-
- VKRESULT(vkCreateFramebuffer(context.device, &create_info, VK_NULL_HANDLE, &framebuffer_handle))
-
- return { .handle = framebuffer_handle, .size = size };
-}
-
-std::vector<framebuffer> vkapi::create_framebuffers(VkRenderPass render_pass, std::vector<VkFormat>& formats, VkExtent2D size, uint32_t framebuffer_count) {
- std::vector<framebuffer> framebuffers{ framebuffer_count };
-
- for (auto& framebuffer : framebuffers) {
- framebuffer = create_framebuffer(render_pass, formats, size);
- }
-
- return framebuffers;
-}
-
-void vkapi::destroy_framebuffer(framebuffer framebuffer) const {
- VKRESULT(vkDeviceWaitIdle(context.device))
-
- vkDestroyFramebuffer(context.device, framebuffer.handle, VK_NULL_HANDLE);
-}
-
-void vkapi::destroy_framebuffers(std::vector<framebuffer>& framebuffers) const {
- VKRESULT(vkDeviceWaitIdle(context.device))
-
- for (auto& framebuffer : framebuffers) {
- vkDestroyFramebuffer(context.device, framebuffer.handle, VK_NULL_HANDLE);
- }
-}
-
-pipeline vkapi::create_compute_pipeline(const char* shader_name) const {
- pipeline pipeline{
- .bind_point = VK_PIPELINE_BIND_POINT_COMPUTE
- };
-
- auto shader_filename = std::string(shader_name) + ".comp.spv";
- auto shader_path = std::filesystem::path{ "./shaders" } / shader_filename;
- auto shader_code = read_file(shader_path.string().c_str());
- assert(!shader_code.empty());
-
- pipeline.shader_modules.resize(1);
-
- VkShaderModuleCreateInfo shader_create_info = {};
- shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shader_create_info.pNext = VK_NULL_HANDLE;
- shader_create_info.flags = 0;
- shader_create_info.codeSize = shader_code.size();
- shader_create_info.pCode = reinterpret_cast<uint32_t*>(shader_code.data());
-
- VKRESULT(vkCreateShaderModule(context.device, &shader_create_info, VK_NULL_HANDLE, (pipeline.shader_modules).data()))
-
- VkPipelineShaderStageCreateInfo stage_create_info = {};
- stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- stage_create_info.pNext = VK_NULL_HANDLE;
- stage_create_info.flags = 0;
- stage_create_info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
- stage_create_info.module = pipeline.shader_modules[0];
- stage_create_info.pName = "main";
- stage_create_info.pSpecializationInfo = VK_NULL_HANDLE;
-
-
- VkComputePipelineCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
- create_info.pNext = VK_NULL_HANDLE;
- create_info.flags = 0;
- create_info.stage = stage_create_info;
- create_info.layout = bindless_descriptor.pipeline_layout;
-
- VKRESULT(vkCreateComputePipelines(
- context.device,
- VK_NULL_HANDLE,
- 1,
- &create_info,
- nullptr,
- &pipeline.handle))
-
- return pipeline;
-}
-
-pipeline vkapi::create_graphics_pipeline(const char* shader_name, VkShaderStageFlagBits shader_stages, VkRenderPass render_pass, std::vector<VkDynamicState>& dynamic_states) const {
- pipeline pipeline{
- .bind_point = VK_PIPELINE_BIND_POINT_GRAPHICS
- };
-
- std::vector<VkPipelineShaderStageCreateInfo> stages_create_info = {};
-
- for (VkShaderStageFlags stage_flag = VK_SHADER_STAGE_VERTEX_BIT; stage_flag <= VK_SHADER_STAGE_ALL_GRAPHICS; stage_flag <<= 2) {
- if ((stage_flag & shader_stages) != 0U) {
- VkShaderModule shader_module;
-
- auto shader_filename = std::string(shader_name) + shader_stage_extension(stage_flag) + ".spv";
- auto shader_path = std::filesystem::path{ "./shaders" } / shader_filename;
- std::vector<uint8_t> shader_code = read_file(shader_path.string().c_str());
- assert(!shader_code.empty());
-
- VkShaderModuleCreateInfo shader_create_info = {};
- shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shader_create_info.pNext = nullptr;
- shader_create_info.flags = 0;
- shader_create_info.codeSize = shader_code.size();
- shader_create_info.pCode = reinterpret_cast<uint32_t*>(shader_code.data());
-
- VKRESULT(vkCreateShaderModule(context.device, &shader_create_info, nullptr, &shader_module))
-
- pipeline.shader_modules.push_back(shader_module);
-
- VkPipelineShaderStageCreateInfo stage_create_info = {};
- stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- stage_create_info.pNext = nullptr;
- stage_create_info.flags = 0;
- stage_create_info.stage = (VkShaderStageFlagBits)stage_flag;
- stage_create_info.module = shader_module;
- stage_create_info.pName = "main";
- stage_create_info.pSpecializationInfo = nullptr;
-
- stages_create_info.push_back(stage_create_info);
- }
- }
-
-
- VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info = {};
- vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-
- VkPipelineInputAssemblyStateCreateInfo input_assembly_state_create_info = {};
- input_assembly_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- input_assembly_state_create_info.pNext = nullptr;
- input_assembly_state_create_info.flags = 0;
- input_assembly_state_create_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
-
- VkPipelineViewportStateCreateInfo viewport_state_create_info = {};
- viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewport_state_create_info.pNext = nullptr;
- viewport_state_create_info.flags = 0;
- viewport_state_create_info.viewportCount = 1;
- viewport_state_create_info.pViewports = VK_NULL_HANDLE;
- viewport_state_create_info.scissorCount = 1;
- viewport_state_create_info.pScissors = VK_NULL_HANDLE;
-
- VkPipelineRasterizationStateCreateInfo rasterization_state_create_info = {};
- rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterization_state_create_info.pNext = nullptr;
- rasterization_state_create_info.flags = 0;
- rasterization_state_create_info.depthClampEnable = VK_FALSE;
- rasterization_state_create_info.rasterizerDiscardEnable = VK_FALSE;
- rasterization_state_create_info.polygonMode = VK_POLYGON_MODE_FILL;
- rasterization_state_create_info.cullMode = VK_CULL_MODE_NONE;
- rasterization_state_create_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- rasterization_state_create_info.depthBiasEnable = VK_FALSE;
- rasterization_state_create_info.lineWidth = 1.f;
-
- VkPipelineMultisampleStateCreateInfo multisample_state_create_info = {};
- multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisample_state_create_info.pNext = nullptr;
- multisample_state_create_info.flags = 0;
- multisample_state_create_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- multisample_state_create_info.sampleShadingEnable = VK_FALSE;
- multisample_state_create_info.minSampleShading = 1.f;
-
- VkPipelineColorBlendAttachmentState color_attachment_state = {};
- color_attachment_state.blendEnable = VK_TRUE;
- color_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
- color_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- color_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
- color_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
- color_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- color_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
- color_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
-
- VkPipelineColorBlendStateCreateInfo color_blend_state_create_info = {};
- color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- color_blend_state_create_info.pNext = nullptr;
- color_blend_state_create_info.flags = 0;
- color_blend_state_create_info.logicOpEnable = VK_FALSE;
- color_blend_state_create_info.attachmentCount = 1;
- color_blend_state_create_info.pAttachments = &color_attachment_state;
-
- VkPipelineDynamicStateCreateInfo dynamic_state_create_info = {};
- dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
- dynamic_state_create_info.pNext = VK_NULL_HANDLE;
- dynamic_state_create_info.flags = 0;
- dynamic_state_create_info.dynamicStateCount = dynamic_states.size();
- dynamic_state_create_info.pDynamicStates = dynamic_states.data();
-
- VkGraphicsPipelineCreateInfo pipeline_create_info = {};
- pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipeline_create_info.pNext = nullptr;
- pipeline_create_info.flags = 0;
- pipeline_create_info.stageCount = stages_create_info.size();
- pipeline_create_info.pStages = stages_create_info.data();
- pipeline_create_info.pVertexInputState = &vertex_input_state_create_info;
- pipeline_create_info.pInputAssemblyState = &input_assembly_state_create_info;
- pipeline_create_info.pViewportState = &viewport_state_create_info;
- pipeline_create_info.pRasterizationState = &rasterization_state_create_info;
- pipeline_create_info.pMultisampleState = &multisample_state_create_info;
- pipeline_create_info.pColorBlendState = &color_blend_state_create_info;
- pipeline_create_info.pDynamicState = &dynamic_state_create_info;
- pipeline_create_info.layout = bindless_descriptor.pipeline_layout;
- pipeline_create_info.renderPass = render_pass;
- pipeline_create_info.subpass = 0;
-
- VKRESULT(vkCreateGraphicsPipelines(context.device, VK_NULL_HANDLE, 1, &pipeline_create_info, VK_NULL_HANDLE, &pipeline.handle))
-
- return pipeline;
-}
-
-void vkapi::destroy_pipeline(pipeline& pipeline) const {
- for (auto& shader_module : pipeline.shader_modules) {
- vkDestroyShaderModule(context.device, shader_module, nullptr);
- }
-
- vkDestroyPipeline(context.device, pipeline.handle, nullptr);
-}
-
-VkSurfaceKHR vkapi::create_surface(window& wnd) const {
- VkSurfaceKHR surface;
-
-#if defined(LINUX)
- VkXcbSurfaceCreateInfoKHR create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
- create_info.pNext = nullptr;
- create_info.flags = 0;
- create_info.connection = wnd.connection;
- create_info.window = wnd.win;
-
- VKRESULT(vkCreateXcbSurfaceKHR(context.instance, &create_info, nullptr, &surface))
-#elif defined(WINDOWS)
- VkWin32SurfaceCreateInfoKHR create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
- create_info.pNext = nullptr;
- create_info.flags = 0;
- create_info.hinstance = GetModuleHandle(nullptr);
- create_info.hwnd = wnd.handle;
-
- VKRESULT(vkCreateWin32SurfaceKHR(context.instance, &create_info, nullptr, &surface))
-#elif defined(MACOS)
- VkMetalSurfaceCreateInfoEXT create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
- create_info.pNext = nullptr;
- create_info.flags = 0;
- // create_info.pLayer = GetModuleHandle(NULL);
-
- VKRESULT(vkCreateMetalSurfaceEXT(context.instance, &create_info, nullptr, &surface))
-#endif
-
- return surface;
-}
-
-void vkapi::destroy_surface(VkSurfaceKHR surface) {
- vkDestroySurfaceKHR(context.instance, surface, nullptr);
-}
-
-swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain) {
- swapchain swapchain;
-
- VkBool32 queue_support_presentation = VK_FALSE;
- VKRESULT(vkGetPhysicalDeviceSurfaceSupportKHR(context.physical_device, context.graphics_queue.index, surface, &queue_support_presentation))
-
- assert(queue_support_presentation == VK_TRUE);
-
- VkSurfaceCapabilitiesKHR caps;
- VKRESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.physical_device, surface, &caps))
-
- swapchain.extent = caps.currentExtent;
-
- if (swapchain.extent.width < caps.minImageExtent.width) {
- swapchain.extent.width = caps.minImageExtent.width;
- } else if (swapchain.extent.width > caps.maxImageExtent.width) {
- swapchain.extent.width = caps.maxImageExtent.width;
- }
-
- if (swapchain.extent.height < caps.minImageExtent.height) {
- swapchain.extent.height = caps.minImageExtent.height;
- } else if (swapchain.extent.height > caps.maxImageExtent.height) {
- swapchain.extent.height = caps.maxImageExtent.height;
- }
-
-
- uint32_t supported_formats_count = 0;
- VKRESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(context.physical_device, surface, &supported_formats_count, VK_NULL_HANDLE))
-
- std::vector<VkSurfaceFormatKHR> supported_formats{ supported_formats_count };
- VKRESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(context.physical_device, surface, &supported_formats_count, supported_formats.data()))
-
-
- uint32_t supported_present_modes_count = 0;
- VKRESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(context.physical_device, surface, &supported_present_modes_count, VK_NULL_HANDLE))
-
- std::vector<VkPresentModeKHR> supported_present_modes{ supported_present_modes_count };
- VKRESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(context.physical_device, surface, &supported_present_modes_count, supported_present_modes.data()))
-
-
- swapchain.surface_format = supported_formats[0];
-
- VkSwapchainCreateInfoKHR create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- create_info.pNext = nullptr;
- create_info.flags = 0;
- create_info.surface = surface;
- create_info.minImageCount = min_image_count;
- create_info.imageFormat = swapchain.surface_format.format;
- create_info.imageColorSpace = swapchain.surface_format.colorSpace;
- create_info.imageExtent = swapchain.extent;
- create_info.imageArrayLayers = 1;
- create_info.imageUsage = usages;
- create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- create_info.preTransform = caps.currentTransform;
- create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- create_info.presentMode = supported_present_modes[0];
- create_info.clipped = VK_TRUE;
- create_info.oldSwapchain = old_swapchain;
-
- VKRESULT(vkCreateSwapchainKHR(context.device, &create_info, nullptr, &swapchain.handle))
-
-
- VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &swapchain.image_count, VK_NULL_HANDLE))
-
- swapchain.images = std::vector<handle>(swapchain.image_count);
- auto vk_images = std::vector<VkImage>(swapchain.image_count);
-
- VKRESULT(vkGetSwapchainImagesKHR(context.device, swapchain.handle, &swapchain.image_count, vk_images.data()))
-
-
- VkImageSubresourceRange image_subresource_range = {};
- image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- image_subresource_range.baseMipLevel = 0;
- image_subresource_range.levelCount = 1;
- image_subresource_range.baseArrayLayer = 0;
- image_subresource_range.layerCount = 1;
-
- VkExtent3D image_size = {
- .width = swapchain.extent.width,
- .height = swapchain.extent.height,
- .depth = 1,
- };
-
- for (size_t image_index = 0; image_index < swapchain.image_count; image_index++) {
- auto* current_image = new struct image();
-
- current_image->handle = vk_images[image_index];
- current_image->size = image_size;
- current_image->subresource_range = image_subresource_range;
- current_image->usages = usages;
-
-
- VkImageViewCreateInfo image_view_create_info = {};
- image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- image_view_create_info.pNext = nullptr;
- image_view_create_info.flags = 0;
- image_view_create_info.image = current_image->handle;
- image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
- image_view_create_info.format = swapchain.surface_format.format;
- image_view_create_info.components = {
- VK_COMPONENT_SWIZZLE_IDENTITY,
- VK_COMPONENT_SWIZZLE_IDENTITY,
- VK_COMPONENT_SWIZZLE_IDENTITY,
- VK_COMPONENT_SWIZZLE_IDENTITY
- };
- image_view_create_info.subresourceRange = image_subresource_range;
-
- VKRESULT(vkCreateImageView(context.device, &image_view_create_info, nullptr, &current_image->view))
-
- images.push_back(current_image);
-
- auto current_image_handle = images.size() - 1;
-
- if ((usages & VK_IMAGE_USAGE_STORAGE_BIT) != 0U) {
- current_image->bindless_storage_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
- update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
- }
-
- if ((usages & VK_IMAGE_USAGE_SAMPLED_BIT) != 0U) {
- current_image->bindless_sampled_index = bindless_descriptor.allocate(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
- update_descriptor_image(current_image_handle, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
- }
-
- swapchain.images[image_index] = current_image_handle;
- }
-
- return swapchain;
-}
-
-void vkapi::destroy_swapchain(swapchain& swapchain) {
- VKRESULT(vkDeviceWaitIdle(context.device))
-
- for (auto& image : swapchain.images) {
- // TODO: Change this
- if (images[image]->bindless_storage_index != 0)
- bindless_descriptor.free(images[image]->bindless_storage_index, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
- if (images[image]->bindless_sampled_index != 0)
- bindless_descriptor.free(images[image]->bindless_sampled_index, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
-
- vkDestroyImageView(context.device, images[image]->view, nullptr);
- }
- vkDestroySwapchainKHR(context.device, swapchain.handle, nullptr);
-}
-
-void vkapi::update_descriptor_image(handle img, VkDescriptorType type) {
- VkDescriptorImageInfo descriptor_image_info;
- VkWriteDescriptorSet write_descriptor;
-
- auto* current_image = images[img];
-
- descriptor_image_info.sampler = VK_NULL_HANDLE;
- descriptor_image_info.imageView = current_image->view;
- descriptor_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptor.pNext = nullptr;
- write_descriptor.dstSet = bindless_descriptor.set;
- write_descriptor.dstBinding = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? 2 : 1;
- write_descriptor.dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? current_image->bindless_storage_index : current_image->bindless_sampled_index;
- write_descriptor.descriptorCount = 1;
- write_descriptor.descriptorType = type;
- write_descriptor.pImageInfo = &descriptor_image_info;
- write_descriptor.pBufferInfo = VK_NULL_HANDLE;
- write_descriptor.pTexelBufferView = VK_NULL_HANDLE;
-
- vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr);
-}
-
-void vkapi::update_descriptor_images(std::vector<handle>& handles, VkDescriptorType type) {
- std::vector<VkDescriptorImageInfo> descriptor_images_info{ images.size() };
- std::vector<VkWriteDescriptorSet> writes_descriptor{ images.size() };
-
- for (size_t image_index = 0; image_index < images.size(); image_index++) {
- auto image = images[handles[image_index]];
- descriptor_images_info[image_index].sampler = VK_NULL_HANDLE;
- descriptor_images_info[image_index].imageView = image->view;
- descriptor_images_info[image_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- writes_descriptor[image_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- writes_descriptor[image_index].pNext = nullptr;
- writes_descriptor[image_index].dstSet = bindless_descriptor.set;
- writes_descriptor[image_index].dstBinding = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? 2 : 1;
- writes_descriptor[image_index].dstArrayElement = type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ? image->bindless_storage_index : image->bindless_sampled_index;
- writes_descriptor[image_index].descriptorCount = 1;
- writes_descriptor[image_index].descriptorType = type;
- writes_descriptor[image_index].pImageInfo = &descriptor_images_info[image_index];
- writes_descriptor[image_index].pBufferInfo = VK_NULL_HANDLE;
- writes_descriptor[image_index].pTexelBufferView = VK_NULL_HANDLE;
- }
-
- vkUpdateDescriptorSets(context.device, writes_descriptor.size(), writes_descriptor.data(), 0, nullptr);
-}
-
-void vkapi::update_descriptor_sampler(handle sampler) {
- VkDescriptorImageInfo descriptor_image_info;
- VkWriteDescriptorSet write_descriptor;
- auto current_sampler = samplers[sampler];
-
- descriptor_image_info.sampler = current_sampler->handle;
- descriptor_image_info.imageView = VK_NULL_HANDLE;
- descriptor_image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- write_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptor.pNext = nullptr;
- write_descriptor.dstSet = bindless_descriptor.set;
- write_descriptor.dstBinding = 0;
- write_descriptor.dstArrayElement = current_sampler->bindless_index;
- write_descriptor.descriptorCount = 1;
- write_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
- write_descriptor.pImageInfo = &descriptor_image_info;
- write_descriptor.pBufferInfo = VK_NULL_HANDLE;
- write_descriptor.pTexelBufferView = VK_NULL_HANDLE;
-
- vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr);
-}
-
-void vkapi::update_descriptor_samplers(std::vector<handle>& handles) {
- std::vector<VkDescriptorImageInfo> descriptor_images_info{ samplers.size() };
- std::vector<VkWriteDescriptorSet> writes_descriptor{ samplers.size() };
-
- for (size_t sampler_index = 0; sampler_index < samplers.size(); sampler_index++) {
- auto sampler = samplers[handles[sampler_index]];
- descriptor_images_info[sampler_index].sampler = sampler->handle;
- descriptor_images_info[sampler_index].imageView = VK_NULL_HANDLE;
- descriptor_images_info[sampler_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
-
- writes_descriptor[sampler_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- writes_descriptor[sampler_index].pNext = nullptr;
- writes_descriptor[sampler_index].dstSet = bindless_descriptor.set;
- writes_descriptor[sampler_index].dstBinding = 0;
- writes_descriptor[sampler_index].dstArrayElement = sampler->bindless_index;
- writes_descriptor[sampler_index].descriptorCount = 1;
- writes_descriptor[sampler_index].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
- writes_descriptor[sampler_index].pImageInfo = &descriptor_images_info[sampler_index];
- writes_descriptor[sampler_index].pBufferInfo = VK_NULL_HANDLE;
- writes_descriptor[sampler_index].pTexelBufferView = VK_NULL_HANDLE;
- }
-
- vkUpdateDescriptorSets(context.device, writes_descriptor.size(), writes_descriptor.data(), 0, nullptr);
-}
-
-void vkapi::update_constants(VkCommandBuffer command_buffer, VkShaderStageFlagBits shader_stage, off_t offset, size_t size, void* data) {
- vkCmdPushConstants(command_buffer, bindless_descriptor.pipeline_layout, shader_stage, offset, size, data);
-}
-
-void vkapi::start_record(VkCommandBuffer command_buffer) {
- VkCommandBufferBeginInfo cmd_buf_begin_info = {};
- cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmd_buf_begin_info.pNext = nullptr;
- cmd_buf_begin_info.flags = 0;
- cmd_buf_begin_info.pInheritanceInfo = nullptr;
-
- vkBeginCommandBuffer(command_buffer, &cmd_buf_begin_info);
-}
-
-void vkapi::image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image) {
- auto* current_image = images[image];
-
- VkImageMemoryBarrier image_barrier = {};
- image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- image_barrier.pNext = nullptr;
- image_barrier.srcAccessMask = current_image->previous_access;
- image_barrier.dstAccessMask = dst_access;
- image_barrier.oldLayout = current_image->previous_layout;
- image_barrier.newLayout = dst_layout;
- image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- image_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- image_barrier.image = current_image->handle;
- image_barrier.subresourceRange = current_image->subresource_range;
-
- vkCmdPipelineBarrier(
- command_buffer,
- current_image->previous_stage,
- dst_stage,
- 0,
- 0,
- nullptr,
- 0,
- nullptr,
- 1,
- &image_barrier);
-
- current_image->previous_layout = dst_layout;
- current_image->previous_access = dst_access;
- current_image->previous_stage = dst_stage;
-}
-
-void vkapi::begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector<VkImageView>& attachments, framebuffer framebuffer, VkExtent2D size) {
- VkRect2D render_area = {
- {
- 0,
- 0,
- },
- size
- };
-
- VkRenderPassAttachmentBeginInfo attachment_begin_info = {};
- attachment_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO;
- attachment_begin_info.pNext = VK_NULL_HANDLE;
- attachment_begin_info.attachmentCount = attachments.size();
- attachment_begin_info.pAttachments = attachments.data();
-
- VkClearValue clear_value{ .color{ .float32{ 0.f, 0.f, 0.f, 1.f } } };
- VkRenderPassBeginInfo render_pass_begin_info = {};
- render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- render_pass_begin_info.pNext = &attachment_begin_info;
- render_pass_begin_info.renderPass = render_pass;
- render_pass_begin_info.framebuffer = framebuffer.handle;
- render_pass_begin_info.renderArea = render_area;
- render_pass_begin_info.clearValueCount = 1;
- render_pass_begin_info.pClearValues = &clear_value;
-
- vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
-}
-
-void vkapi::end_render_pass(VkCommandBuffer command_buffer) {
- vkCmdEndRenderPass(command_buffer);
-}
-
-void vkapi::run_compute_pipeline(VkCommandBuffer command_buffer, pipeline& pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z) {
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr);
-
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.handle);
-
- vkCmdDispatch(command_buffer, group_count_x, group_count_y, group_count_z);
-}
-
-void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t vertex_count, uint32_t vertex_offset) {
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr);
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle);
-
- vkCmdDraw(command_buffer, vertex_count, 1, vertex_offset, 0);
-}
-
-void vkapi::draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t index_count, uint32_t index_offset, uint32_t vertex_offset) {
- vkCmdBindIndexBuffer(command_buffer, buffers[index_buffer]->handle, 0, VK_INDEX_TYPE_UINT16);
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr);
- vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.handle);
-
- vkCmdDrawIndexed(command_buffer, index_count, 1, index_offset, vertex_offset, 0);
-}
-
-void vkapi::blit_full(VkCommandBuffer command_buffer, handle src, handle dst) {
- auto* src_image = images[src];
- auto* dst_image = images[dst];
-
- VkImageSubresourceLayers images_subres_layers{
- .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
- .mipLevel = 0,
- .baseArrayLayer = 0,
- .layerCount = 1,
- };
-
- VkOffset3D start_offset{
- .x = 0,
- .y = 0,
- .z = 0,
- };
- VkOffset3D end_offset{
- .x = (int32_t)dst_image->size.width,
- .y = (int32_t)dst_image->size.height,
- .z = (int32_t)dst_image->size.depth,
- };
-
- VkImageBlit blit_region{
- .srcSubresource = images_subres_layers,
- .srcOffsets = { start_offset, end_offset },
- .dstSubresource = images_subres_layers,
- .dstOffsets = { start_offset, end_offset },
- };
-
- vkCmdBlitImage(command_buffer, src_image->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit_region, VK_FILTER_NEAREST);
-}
-
-void vkapi::end_record(VkCommandBuffer command_buffer){
- VKRESULT(vkEndCommandBuffer(command_buffer))
-}
-
-VkResult vkapi::submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const {
- VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-
- VkSubmitInfo submit_info = {};
- submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.pNext = nullptr;
- submit_info.waitSemaphoreCount = wait_semaphore != nullptr ? 1 : 0;
- submit_info.pWaitSemaphores = &wait_semaphore;
- submit_info.pWaitDstStageMask = wait_semaphore != nullptr ? &wait_stage : VK_NULL_HANDLE;
- submit_info.signalSemaphoreCount = signal_semaphore != nullptr ? 1 : 0;
- submit_info.pSignalSemaphores = &signal_semaphore;
- submit_info.commandBufferCount = command_buffers_count;
- submit_info.pCommandBuffers = command_buffers;
-
- return vkQueueSubmit(context.graphics_queue.handle, 1, &submit_info, submission_fence);
-}
-
-VkResult vkapi::present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const {
- VkPresentInfoKHR present_info = {};
- present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- present_info.pNext = nullptr;
- present_info.waitSemaphoreCount = 1;
- present_info.pWaitSemaphores = &wait_semaphore;
- present_info.swapchainCount = 1;
- present_info.pSwapchains = &swapchain.handle;
- present_info.pImageIndices = &image_index;
- present_info.pResults = nullptr;
-
- return vkQueuePresentKHR(context.graphics_queue.handle, &present_info);
-}
-
-const char* vkapi::shader_stage_extension(VkShaderStageFlags shader_stage) {
- switch (shader_stage) {
- case VK_SHADER_STAGE_VERTEX_BIT: {
- return ".vert";
- }
- case VK_SHADER_STAGE_FRAGMENT_BIT: {
- return ".frag";
- }
- case VK_SHADER_STAGE_COMPUTE_BIT: {
- return ".comp";
- }
- default:
- assert(true && "Stage not supported");
- return "";
- }
-}
diff --git a/src/vk-bindless.cpp b/src/vk-bindless.cpp
new file mode 100644
index 0000000..9e517df
--- /dev/null
+++ b/src/vk-bindless.cpp
@@ -0,0 +1,238 @@
+#include "vk-bindless.hpp"
+
+#include "vk-device.hpp"
+#include "vk-utils.hpp"
+
+device_buffer& bindless_model::get_uniform_buffer(enum UniformTypes type) const {
+ return vkdevice::get().get_buffer(uniform_buffers[type]);
+}
+
+void bindless_model::init() {
+ vkdevice& render_device = vkdevice::get();
+ VkDevice device = render_device.get_device();
+
+ // -------------------------
+ // create immutable samplers
+ // -------------------------
+ {
+ VkSamplerCreateInfo create_info{
+ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+ .pNext = VK_NULL_HANDLE,
+ .flags = 0,
+ .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
+ .mipLodBias = 0.f,
+ .anisotropyEnable = VK_FALSE,
+ .compareEnable = VK_FALSE,
+ .compareOp = VK_COMPARE_OP_NEVER,
+ .minLod = 0.f,
+ .maxLod = 0.f,
+ .borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
+ .unnormalizedCoordinates = VK_FALSE,
+ };
+
+ // Nearest sampler
+ {
+ VkFilter filter = VK_FILTER_NEAREST;
+ VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+
+ create_info.magFilter = filter,
+ create_info.minFilter = filter,
+ create_info.addressModeU = address_mode,
+ create_info.addressModeV = address_mode,
+ create_info.addressModeW = address_mode,
+
+ VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::NEAREST]));
+ }
+
+ // Linear sampler
+ {
+ VkFilter filter = VK_FILTER_LINEAR;
+ VkSamplerAddressMode address_mode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+
+ create_info.magFilter = filter,
+ create_info.minFilter = filter,
+ create_info.addressModeU = address_mode,
+ create_info.addressModeV = address_mode,
+ create_info.addressModeW = address_mode,
+
+ VKCHECK(vkCreateSampler(device, &create_info, VK_NULL_HANDLE, &samplers[SamplerType::LINEAR]));
+ }
+ }
+
+ // Set 0 global resources
+ // Binding 0 Storage images
+ // Binding 1 Sampled images
+ // Binding 2 Samplers
+ {
+ VkDescriptorSetLayoutBinding set_layout_bindings[]{
+ {
+ .binding = 0U,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER,
+ .descriptorCount = SamplerType::MAX_SAMPLER,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = samplers,
+ },
+ {
+ .binding = 1U,
+ .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = set_descriptors_count,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ {
+ .binding = 2U,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .descriptorCount = set_descriptors_count,
+ .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ .pImmutableSamplers = nullptr,
+ },
+ };
+
+ VkDescriptorBindingFlags flags[]{
+ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT,
+ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT,
+ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT,
+ };
+
+ VkDescriptorSetLayoutBindingFlagsCreateInfo layout_binding_flags{
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
+ .pNext = VK_NULL_HANDLE,
+ .bindingCount = sizeof(flags) / sizeof(VkDescriptorBindingFlags),
+ .pBindingFlags = flags,
+ };
+
+ VkDescriptorSetLayoutCreateInfo create_info{
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ .pNext = &layout_binding_flags,
+ .flags = 0U,
+ .bindingCount = sizeof(set_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding),
+ .pBindings = set_layout_bindings,
+ };
+
+ VKCHECK(vkCreateDescriptorSetLayout(device, &create_info, nullptr, &global_set_layout));
+ }
+
+ // ----------------------
+ // create layout
+ // ----------------------
+ {
+ VkPushConstantRange push_constant {
+ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT,
+ .offset = 0U,
+ .size = push_constant_slot_size * push_constant_slots,
+ };
+
+ VkPipelineLayoutCreateInfo create_info{
+ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0U,
+ .setLayoutCount = 1U,
+ .pSetLayouts = &global_set_layout,
+ .pushConstantRangeCount = 1U,
+ .pPushConstantRanges = &push_constant,
+ };
+
+ VKCHECK(vkCreatePipelineLayout(device, &create_info, nullptr, &global_layout));
+ }
+
+ // ----------------------
+ // create descriptor pool
+ // ----------------------
+ {
+ VkDescriptorPoolSize pool_sizes[]{
+ {
+ .type = VK_DESCRIPTOR_TYPE_SAMPLER,
+ .descriptorCount = set_descriptors_count,
+ },
+ {
+ .type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ .descriptorCount = set_descriptors_count,
+ },
+ {
+ .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .descriptorCount = set_descriptors_count,
+ },
+ };
+
+ VkDescriptorPoolCreateInfo descriptor_pool_create_info{
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0U,
+ .maxSets = descriptor_pool_allocable_sets_count,
+ .poolSizeCount = sizeof(pool_sizes) / sizeof(VkDescriptorPoolSize),
+ .pPoolSizes = pool_sizes,
+ };
+ VKCHECK(vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool));
+ }
+
+ // -----------------------
+ // create descriptors sets
+ // -----------------------
+ {
+ VkDescriptorSetAllocateInfo allocate_info{
+ .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ .pNext = nullptr,
+ .descriptorPool = descriptor_pool,
+ .descriptorSetCount = 1U,
+ .pSetLayouts = &global_set_layout,
+ };
+ VKCHECK(vkAllocateDescriptorSets(device, &allocate_info, &global_set));
+ }
+
+ // ---------------------
+ // global uniform buffer
+ // ---------------------
+ {
+ uniform_buffers[UniformTypes::GLOBAL] = render_device.create_buffer({
+ .size = globals_uniform_buffer_size,
+ .usages = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
+ .name = "global uniform buffer",
+ });
+ }
+
+ // ---------------------
+ // passes uniform buffer
+ // ---------------------
+ {
+ uniform_buffers[UniformTypes::PASS] = render_device.create_buffer({
+ .size = passes_uniform_buffer_size,
+ .usages = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
+ .name = "passes uniform buffer"
+ });
+ }
+
+ // --------------------
+ // draws uniform buffer
+ // --------------------
+ {
+ uniform_buffers[UniformTypes::DRAW] = render_device.create_buffer({
+ .size = draws_uniform_buffer_size,
+ .usages = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
+ .memory_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
+ .memory_usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
+ .name = "draws uniform buffer",
+ });
+ }
+}
+
+void bindless_model::deinit() {
+ vkdevice& render_device = vkdevice::get();
+ VkDevice device = render_device.get_device();
+
+ vkDestroyDescriptorPool(device, descriptor_pool, nullptr);
+
+ vkDestroyDescriptorSetLayout(device, global_set_layout, nullptr);
+ vkDestroyPipelineLayout(device, global_layout, nullptr);
+
+ render_device.destroy_buffer(uniform_buffers[UniformTypes::GLOBAL]);
+ render_device.destroy_buffer(uniform_buffers[UniformTypes::PASS]);
+ render_device.destroy_buffer(uniform_buffers[UniformTypes::DRAW]);
+
+ for (VkSampler sampler : samplers) {
+ vkDestroySampler(device, sampler, nullptr);
+ }
+}
diff --git a/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<device_texture> 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<device_buffer> buffer_handle, ::handle<device_texture> 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<VkRenderingAttachmentInfo> 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<float>(params.render_area.x),
+ .y = static_cast<float>(params.render_area.y),
+ .width = static_cast<float>(params.render_area.width),
+ .height = static_cast<float>(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<uint32_t>(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<int32_t>(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 <iostream>
-#include <cassert>
-#include <vector>
-#include <array>
-
-#define VMA_IMPLEMENTATION
-#include <vk_mem_alloc.h>
-
-#include "vulkan-loader.hpp"
-
-#ifdef _DEBUG
-#define VKRESULT(result) assert(result == VK_SUCCESS);
-#else
-#define VKRESULT(result) result;
-#endif
-
-VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
- VkDebugUtilsMessageTypeFlagsEXT type,
- const VkDebugUtilsMessengerCallbackDataEXT *data,
- void*)
-{
- const char* severity_cstr = nullptr;
- switch(severity) {
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
- severity_cstr = "VERBOSE";
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
- severity_cstr = "INFO";
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
- severity_cstr = "WARNING";
- break;
- case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
- severity_cstr = "ERROR";
- break;
- default:
- break;
- }
-
- const char* type_cstr = nullptr;
- switch(type) {
- case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT:
- type_cstr = "GENERAL";
- break;
- case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT:
- type_cstr = "VALIDATION";
- break;
- case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT:
- type_cstr = "PERFORMANCE";
- break;
- default:
- break;
- }
-
- std::cerr << "[" << severity_cstr << "_" << type_cstr << "]: " << data->pMessage << std::endl;
- return VK_FALSE;
-}
-
-
-vkcontext::vkcontext() {
- load_vulkan();
-
- create_instance();
- create_device();
- create_debugger();
- create_memory_allocator();
-}
-
-vkcontext::~vkcontext() {
- vmaDestroyAllocator(allocator);
- vkDestroyDevice(device, nullptr);
- vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
- vkDestroyInstance(instance, nullptr);
-}
-
-
-void vkcontext::create_instance() {
- VkApplicationInfo app_info = {};
- app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- app_info.pApplicationName = "path-tracer";
- app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.pEngineName = "gpu-path-tracer";
- app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.apiVersion = VK_API_VERSION_1_2;
-
- const char* needed_layers[] = {
-#if defined(_DEBUG)
- "VK_LAYER_KHRONOS_validation",
-#endif
- };
- auto needed_layers_count = sizeof(needed_layers) / sizeof(needed_layers[0]);
-
- check_available_instance_layers(needed_layers, needed_layers_count);
-
- constexpr const char* needed_extensions[] = {
- VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
- "VK_KHR_surface",
-#if defined(LINUX)
- "VK_KHR_xcb_surface"
-#elif defined(WINDOWS)
- "VK_KHR_win32_surface"
-#elif defined(MACOS)
- "VK_EXT_metal_surface"
-#endif
- };
- constexpr auto needed_extensions_count = sizeof(needed_extensions) / sizeof(needed_extensions[0]);
-
- check_available_instance_extensions(needed_extensions, needed_extensions_count);
-
- VkInstanceCreateInfo instance_create_info = {};
- instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- instance_create_info.pApplicationInfo = &app_info;
- instance_create_info.enabledLayerCount = needed_layers_count;
- instance_create_info.ppEnabledLayerNames = needed_layers;
- instance_create_info.enabledExtensionCount = needed_extensions_count;
- instance_create_info.ppEnabledExtensionNames = needed_extensions;
-
- VKRESULT(vkCreateInstance(&instance_create_info, nullptr, &instance))
-
- load_instance_functions(instance);
-
- std::cerr << "Instance ready" << std::endl;
-}
-
-void vkcontext::create_debugger() {
- VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengeCreateInfo {
- VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
- nullptr,
- 0,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
- VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
- DebugCallback,
- nullptr,
- };
-
- VKRESULT(vkCreateDebugUtilsMessengerEXT(
- instance,
- &debugUtilsMessengeCreateInfo,
- nullptr,
- &debugMessenger
- ))
-}
-
-void vkcontext::create_device() {
- select_physical_device();
-
- graphics_queue = {
- .usages = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT,
- };
- auto queue_priority = 1.f;
- graphics_queue.index = select_queue(graphics_queue.usages);
- auto queue_create_info = VkDeviceQueueCreateInfo {
- .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
- .queueFamilyIndex = graphics_queue.index,
- .queueCount = 1,
-
- .pQueuePriorities = &queue_priority
- };
-
- VkPhysicalDeviceVulkan12Features physical_device_12_features = {};
- physical_device_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
- physical_device_12_features.pNext = VK_NULL_HANDLE;
- physical_device_12_features.bufferDeviceAddress = VK_TRUE;
- physical_device_12_features.runtimeDescriptorArray = VK_TRUE;
- physical_device_12_features.shaderStorageImageArrayNonUniformIndexing = VK_TRUE;
- physical_device_12_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE;
- physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE;
- physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE;
- physical_device_12_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE;
- physical_device_12_features.imagelessFramebuffer = VK_TRUE;
-
- VkPhysicalDeviceFeatures2 device_features = {};
- device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- device_features.pNext = &physical_device_12_features;
-
- const char* device_ext[] = {
- "VK_KHR_swapchain",
- };
-
- VkDeviceCreateInfo device_create_info = {};
- device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- device_create_info.pNext = &device_features;
- device_create_info.pQueueCreateInfos = &queue_create_info;
- device_create_info.queueCreateInfoCount = 1;
- device_create_info.ppEnabledExtensionNames = device_ext;
- device_create_info.enabledExtensionCount = sizeof(device_ext) / sizeof(device_ext[0]);
- device_create_info.enabledLayerCount = 0; // Deprecated https://www.khronos.org/registry/vulkan/specs/1.2/html/chap31.html#extendingvulkan-layers-devicelayerdeprecation
-
- VKRESULT(vkCreateDevice(physical_device, &device_create_info, nullptr, &device))
-
- load_device_functions(device);
-
- vkGetDeviceQueue(device, graphics_queue.index, 0, &graphics_queue.handle);
-
- std::cerr << "Device ready" << std::endl;
-}
-
-void vkcontext::create_memory_allocator() {
- VmaAllocatorCreateInfo allocator_info = {};
- allocator_info.vulkanApiVersion = VK_API_VERSION_1_2;
- allocator_info.physicalDevice = physical_device;
- allocator_info.device = device;
- allocator_info.instance = instance;
- allocator_info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
-
- vmaCreateAllocator(&allocator_info, &allocator);
-}
-
-
-void vkcontext::select_physical_device() {
- uint32_t physical_devices_count = 0;
- vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr);
-
- if (physical_devices_count < 1) {
- std::cerr << "No physical device found !" << std::endl;
- }
-
- std::vector<VkPhysicalDevice> physical_devices { physical_devices_count };
- vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data());
-
-
- for (auto& physical_dev: physical_devices) {
- if (support_required_features(physical_dev)) {
- physical_device = physical_dev;
- }
- }
-
- assert(physical_device != VK_NULL_HANDLE);
-}
-
-uint32_t vkcontext::select_queue(VkQueueFlags queue_usage) const {
- uint32_t queue_properties_count = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr);
-
- std::vector<VkQueueFamilyProperties> queue_properties { queue_properties_count };
- vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data());
-
- for (uint32_t properties_index = 0; properties_index < queue_properties_count; properties_index++) {
- if ((queue_properties[properties_index].queueFlags & queue_usage) != 0U) {
- return properties_index;
- }
- }
-
- assert(true);
- return UINT_MAX;
-}
-
-void vkcontext::check_available_instance_layers(const char* needed_layers[], size_t needed_layers_count) {
- uint32_t property_count = 0;
- vkEnumerateInstanceLayerProperties(&property_count, VK_NULL_HANDLE);
-
- std::vector<VkLayerProperties> layer_properties { property_count };
- vkEnumerateInstanceLayerProperties(&property_count, layer_properties.data());
-
- uint32_t available_needed_layers_count = 0;
-
- for (auto layer_property: layer_properties) {
- for (auto layer_index { 0U }; layer_index < needed_layers_count; layer_index++) {
- if (strcmp(layer_property.layerName, needed_layers[layer_index]) == 0) {
- available_needed_layers_count++;
- }
- }
- }
-
- assert(available_needed_layers_count == needed_layers_count);
-}
-
-void vkcontext::check_available_instance_extensions(const char* needed_extensions[], size_t needed_extensions_count) {
- uint32_t vulkan_extensions_count = 0;
- vkEnumerateInstanceExtensionProperties(VK_NULL_HANDLE, &vulkan_extensions_count, VK_NULL_HANDLE);
-
- std::vector<VkExtensionProperties> vulkan_extensions_properties { vulkan_extensions_count };
- vkEnumerateInstanceExtensionProperties(VK_NULL_HANDLE, &vulkan_extensions_count, vulkan_extensions_properties.data());
-
- uint32_t available_needed_extensions_count = 0;
- for (auto& extension: vulkan_extensions_properties) {
- for (auto extension_index { 0U }; extension_index < needed_extensions_count; extension_index++) {
- if (strcmp(extension.extensionName, needed_extensions[extension_index]) == 0) {
- available_needed_extensions_count++;
- }
- }
- }
-
- // assert(available_needed_extensions_count == needed_extensions_count);
-}
-
-bool vkcontext::support_required_features(VkPhysicalDevice physical_device) {
- VkPhysicalDeviceProperties physical_device_properties = {};
-
- vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties);
-
- VkPhysicalDeviceVulkan12Features vulkan_12_features = {};
- vulkan_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
-
- VkPhysicalDeviceFeatures2 physical_device_features = {};
- physical_device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
- physical_device_features.pNext = &vulkan_12_features;
-
- vkGetPhysicalDeviceFeatures2(physical_device, &physical_device_features);
-
- if (vulkan_12_features.bufferDeviceAddress == VK_TRUE &&
- vulkan_12_features.runtimeDescriptorArray == VK_TRUE &&
- vulkan_12_features.shaderStorageImageArrayNonUniformIndexing == VK_TRUE &&
- vulkan_12_features.shaderSampledImageArrayNonUniformIndexing == VK_TRUE &&
- vulkan_12_features.descriptorBindingPartiallyBound == VK_TRUE &&
- vulkan_12_features.descriptorBindingPartiallyBound == VK_TRUE &&
- vulkan_12_features.descriptorBindingUpdateUnusedWhilePending == VK_TRUE &&
- vulkan_12_features.imagelessFramebuffer == VK_TRUE) {
- std::cerr << "Using physical device " << physical_device_properties.deviceName << std::endl;
- return true;
- }
-
- std::cerr << "Physical device " << physical_device_properties.deviceName << " is missing some features" << std::endl;
- return false;
-}
-
diff --git a/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 <vk_mem_alloc.h>
+
+static VkShaderModule create_shader_module(VkDevice device, uint8_t* code, size_t code_size) {
+ VkShaderModule shader_module;
+ VkShaderModuleCreateInfo create_info{
+ .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0U,
+ .codeSize = code_size,
+ .pCode = reinterpret_cast<uint32_t*>(code),
+ };
+
+ VKCHECK(vkCreateShaderModule(device, &create_info, nullptr, &shader_module));
+ return shader_module;
+}
+
+
+vkdevice vkdevice::render_device = vkdevice();
+
+void vkdevice::init() {
+ queues[static_cast<uint32_t>(QueueType::GRAPHICS)] = {
+ .usages = VK_QUEUE_GRAPHICS_BIT |
+ VK_QUEUE_COMPUTE_BIT |
+ VK_QUEUE_TRANSFER_BIT,
+ };
+ queues[static_cast<uint32_t>(QueueType::ASYNC_COMPUTE)] = {
+ .usages = VK_QUEUE_COMPUTE_BIT,
+ };
+ queues[static_cast<uint32_t>(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<device_texture> vkdevice::create_texture(const texture_desc& desc) {
+ device_texture device_texture;
+ // TODO: This must always be present since we want to display images in ImGui
+ const_cast<texture_desc&>(desc).usages |= VK_IMAGE_USAGE_SAMPLED_BIT;
+ device_texture.init(desc);
+
+ return textures.add(device_texture);
+}
+
+handle<device_sampler> vkdevice::create_sampler(const sampler_desc& desc) {
+ device_sampler device_sampler;
+ device_sampler.init(desc);
+
+ return samplers.add(device_sampler);
+}
+
+handle<device_buffer> 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<VmaMemoryUsage>(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<device_pipeline> 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<uint32_t>(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<uint64_t>(device_pipeline.vk_pipeline),
+ .pObjectName = desc.name,
+ };
+ vkSetDebugUtilsObjectNameEXT(device, &object_name);
+ }
+
+ return pipelines.add(device_pipeline);
+}
+
+handle<device_pipeline> 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<uint64_t>(device_pipeline.vk_pipeline),
+ .pObjectName = desc.name,
+ };
+ vkSetDebugUtilsObjectNameEXT(device, &object_name);
+ }
+
+ return pipelines.add(device_pipeline);
+}
+
+handle<device_surface> 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<device_semaphore> 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<uint64_t>(semaphore.vk_semaphore),
+ .pObjectName = name,
+ };
+ vkSetDebugUtilsObjectNameEXT(device, &object_name);
+ }
+ return semaphores.add(semaphore);
+}
+
+void vkdevice::destroy_texture(handle<device_texture> handle) {
+ auto& texture = get_texture(handle);
+
+ texture.release();
+ textures.remove(handle);
+}
+
+void vkdevice::destroy_buffer(handle<device_buffer> handle) {
+ const auto& buffer = get_buffer(handle);
+
+ vmaDestroyBuffer(gpu_allocator, buffer.vk_buffer, buffer.alloc);
+ buffers.remove(handle);
+}
+
+void vkdevice::destroy_pipeline(handle<device_pipeline> handle) {
+ const auto& pipeline = vkdevice::get_pipeline(handle);
+
+ vkDestroyPipeline(device, pipeline.vk_pipeline, nullptr);
+ pipelines.remove(handle);
+}
+
+void vkdevice::destroy_semaphore(handle<device_semaphore> handle) {
+ auto& semaphore = vkdevice::get_semaphore(handle);
+
+ vkDestroySemaphore(device, semaphore.vk_semaphore, nullptr);
+ semaphores.remove(handle);
+}
+
+void vkdevice::destroy_surface(handle<device_surface> handle) {
+ auto& surface = vkdevice::get_surface(handle);
+
+ for (auto texture_index{0U}; texture_index < surface.image_count; texture_index++) {
+ auto texture_handle = surface.swapchain_images[texture_index];
+ destroy_texture(texture_handle);
+ }
+
+ for (uint32_t index = 0u; index < surface.image_count; index++) {
+ destroy_semaphore(surface.acquire_semaphores[index]);
+ destroy_semaphore(surface.submit_semaphores[index]);
+ }
+
+ vkDestroySwapchainKHR(device, surface.vk_swapchain, nullptr);
+
+ vkDestroySurfaceKHR(instance, surface.vk_surface, nullptr);
+}
+
+// uint64_t vkdevice::submit(std::span<command_buffer> buffers, handle<device_semaphore> wait_handle, handle<device_semaphore> signal_handle, handle<device_semaphore> 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<uint32_t>(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<uint32_t>(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<uint32_t>(queue_type)].vk_queue, 1, &submit_info, nullptr));
+
+ return fence.value;
+}
+
+uint64_t vkdevice::submit_before_present(handle<device_surface> surface_handle, command_buffer* cmd_buffers, uint32_t count) {
+ assert((max_submitable_command_buffers - count) >= 0);
+ const 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<uint32_t>(queue_type)].vk_queue, 1, &submit_info, nullptr));
+
+ return fence.value;
+}
+
+void vkdevice::present(handle<device_surface> 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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint64_t>(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<uint32_t>(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<VkSurfaceFormatKHR> 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<VkPresentModeKHR> 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<VkImage> 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<uint32_t>(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<VkQueueFamilyProperties> queue_properties{ queue_properties_count };
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data());
+
+ for (auto index{ 0U }; index < static_cast<uint32_t>(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<uint32_t>(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<VkPhysicalDevice> physical_devices{ physical_devices_count };
+ vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data());
+
+ physical_device_props = VkPhysicalDeviceProperties2 {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
+ .pNext = nullptr,
+ };
+
+ for (auto& physical_dev : physical_devices) {
+ if (device_support_features(physical_dev)) {
+ physical_device = physical_dev;
+
+ return;
+ }
+ }
+
+ 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<uint64_t>(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<VkWriteDescriptorSet> 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<uint32_t>(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<device_surface> 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 <cstring>
-#include <cassert>
-
-#include <vk_mem_alloc.h>
-
-#include "vulkan-loader.hpp"
-
-#include "compute-renderpass.hpp"
-#include "primitive-renderpass.hpp"
-
-#include "texture.hpp"
-
-#include "window.hpp"
-
-#ifdef _DEBUG
-#define VKRESULT(result) assert(result == VK_SUCCESS);
-#else
-#define VKRESULT(result) result;
-#endif
-
-auto vkrenderer::context = vkcontext();
-auto vkrenderer::api = vkapi(vkrenderer::context);
-auto vkrenderer::upload_queue = std::vector<Texture*>();
-
-vkrenderer::vkrenderer(window& wnd) {
- platform_surface = api.create_surface(wnd);
- swapchain = api.create_swapchain(
- platform_surface,
- min_swapchain_image_count,
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT |
- VK_IMAGE_USAGE_STORAGE_BIT,
- VK_NULL_HANDLE
- );
-
- swapchain_textures.resize(swapchain.image_count);
- for (size_t index = 0; index < swapchain.image_count; index++) {
- swapchain_textures[index] = new Texture(swapchain.images[index]);
- }
-
- tonemapping_pipeline = api.create_compute_pipeline("tonemapping");
-
- graphics_command_pool = api.create_command_pool();
- api.allocate_command_buffers(graphics_command_pool, graphics_command_buffers, virtual_frames_count);
-
- for(size_t index { 0 }; index < virtual_frames_count; index++) {
- submission_fences[index] = api.create_fence();
- execution_semaphores[index] = api.create_semaphore();
- acquire_semaphores[index] = api.create_semaphore();
-
- copy_command_pools[index] = api.create_command_pool();
- api.allocate_command_buffers(copy_command_pools[index], &copy_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, &copy_command_buffers[index]);
- vkDestroyCommandPool(context.device, copy_command_pools[index], nullptr);
- }
-
- api.destroy_fences(submission_fences, virtual_frames_count);
- api.destroy_semaphores(execution_semaphores, virtual_frames_count);
- api.destroy_semaphores(acquire_semaphores, virtual_frames_count);
-
- vkFreeCommandBuffers(context.device, graphics_command_pool, virtual_frames_count, graphics_command_buffers);
- vkDestroyCommandPool(context.device, graphics_command_pool, nullptr);
-
-
- api.destroy_pipeline(tonemapping_pipeline);
-
- api.destroy_swapchain(swapchain);
- api.destroy_surface(platform_surface);
-}
-void vkrenderer::recreate_swapchain() {
- VKRESULT(vkWaitForFences(context.device, vkrenderer::virtual_frames_count, submission_fences, VK_TRUE, UINT64_MAX))
-
- auto swapchain_image_usages = api.get_image(swapchain.images[0]).usages;
- struct swapchain old_swapchain = swapchain;
- swapchain = api.create_swapchain(
- platform_surface,
- min_swapchain_image_count,
- swapchain_image_usages,
- old_swapchain.handle
- );
-
- api.destroy_swapchain(old_swapchain);
-
- swapchain_textures.resize(swapchain.image_count);
- for (size_t index = 0; index < swapchain.image_count; index++) {
- swapchain_textures[index] = new Texture(swapchain.images[index]);
- }
-}
-
-void vkrenderer::queue_image_update(Texture* texture) {
- upload_queue.push_back(texture);
-}
-
-void vkrenderer::update_images() {
- if(upload_queue.empty())
- return;
-
- auto* staging_buffer = staging_buffers[virtual_frame_index];
- staging_buffer->reset();
-
- VkCommandBuffer command_buffer = copy_command_buffers[virtual_frame_index];
- vkrenderer::api.start_record(command_buffer);
-
- while(!upload_queue.empty()) {
- auto* texture = upload_queue.back();
- auto texture_size = texture->size();
- auto offset = staging_buffer->alloc(texture_size);
-
- if (offset == RingBuffer::invalid_alloc)
- break;
-
- upload_queue.pop_back();
-
- staging_buffer->write(texture->data, offset, texture_size);
-
- vkrenderer::api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, texture->device_image);
- vkrenderer::api.copy_buffer(command_buffer, staging_buffer->device_buffer, texture->device_image, 0, offset);
- vkrenderer::api.image_barrier(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, texture->device_image);
- }
-
- vkrenderer::api.end_record(command_buffer);
-
- recorded_command_buffers.push_back(command_buffer);
-}
-
-Buffer* vkrenderer::create_buffer(size_t size) {
- return new Buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
-}
-
-Buffer* vkrenderer::create_index_buffer(size_t size) {
- return new Buffer(size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
-}
-
-Buffer* vkrenderer::create_staging_buffer(size_t size) {
- return new Buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
-}
-
-Texture* vkrenderer::create_2d_texture(size_t width, size_t height, VkFormat format, Sampler *sampler) {
- return new Texture(width, height, 1, format, sampler);
-}
-
-// TODO: Check if a similar sampler has been allocated
-Sampler* vkrenderer::create_sampler(VkFilter filter, VkSamplerAddressMode address_mode) {
- auto* sampler = new Sampler();
-
- sampler->device_sampler = api.create_sampler(filter, address_mode);
-
- return sampler;
-}
-
-ComputeRenderpass* vkrenderer::create_compute_renderpass() {
- renderpasses.push_back(new ComputeRenderpass(api));
-
- return (ComputeRenderpass*)renderpasses.back();
-}
-
-PrimitiveRenderpass* vkrenderer::create_primitive_renderpass() {
- renderpasses.push_back(new PrimitiveRenderpass(api));
-
- return (PrimitiveRenderpass*)renderpasses.back();
-}
-
-Primitive* vkrenderer::create_primitive(PrimitiveRenderpass& primitive_render_pass) {
- return new Primitive(primitive_render_pass);
-}
-
-void vkrenderer::render() {
- swapchain_image_index = 0;
- auto acquire_result = vkAcquireNextImageKHR(context.device, swapchain.handle, UINT64_MAX, acquire_semaphores[virtual_frame_index], VK_NULL_HANDLE, &swapchain_image_index);
- handle_swapchain_result(acquire_result);
-
- api.start_record(graphics_command_buffers[virtual_frame_index]);
-
- auto* cmd_buf = graphics_command_buffers[virtual_frame_index];
-
- // wait for transfer operations
-
- for (auto& renderpass: renderpasses) {
- renderpass->execute(*this, cmd_buf);
-
- api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, ((ComputeRenderpass*)renderpass)->output_texture->device_image);
-
- api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, swapchain.images[swapchain_image_index]);
-
- api.blit_full(cmd_buf, ((ComputeRenderpass*)renderpass)->output_texture->device_image, swapchain.images[swapchain_image_index]);
- }
-
-
- // api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, swapchain.images[swapchain_image_index]);
-
- // renderpasses[1]->execute(*this, cmd_buf);
-
- api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, swapchain.images[swapchain_image_index]);
-
- api.end_record(cmd_buf);
-
- recorded_command_buffers.push_back(cmd_buf);
-}
-
-void vkrenderer::begin_frame() {
- recorded_command_buffers.clear();
-
- VKRESULT(vkWaitForFences(context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX))
- VKRESULT(vkResetFences(context.device, 1, &submission_fences[virtual_frame_index]))
-
- update_images();
-}
-
-void vkrenderer::finish_frame() {
- api.submit(recorded_command_buffers.data(), recorded_command_buffers.size(), acquire_semaphores[virtual_frame_index], execution_semaphores[virtual_frame_index], submission_fences[virtual_frame_index]);
-
- auto present_result = api.present(swapchain, swapchain_image_index, execution_semaphores[virtual_frame_index]);
- handle_swapchain_result(present_result);
-
- virtual_frame_index = ++virtual_frame_index % virtual_frames_count;
-}
-
-
-
-// private functions
-void vkrenderer::handle_swapchain_result(VkResult function_result) {
- switch(function_result) {
- case VK_ERROR_OUT_OF_DATE_KHR:
- return recreate_swapchain();
- case VK_ERROR_SURFACE_LOST_KHR:
- assert(true && "surface lost");
- default:
- return;
- }
-}
-
-
-
-Buffer::Buffer(size_t size, VkBufferUsageFlagBits usage)
- : buffer_size(size), usage(usage) {
- device_buffer = vkrenderer::api.create_buffer(size, usage, VMA_MEMORY_USAGE_CPU_TO_GPU);
-}
-
-Buffer::~Buffer() {
- vkrenderer::api.destroy_buffer(device_buffer);
-}
-
-void Buffer::write(void* data, off_t alloc_offset, size_t data_size) const {
- auto api_buffer = vkrenderer::api.get_buffer(device_buffer);
-
- std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size);
-}
-
-void Buffer::resize(size_t new_size) {
- auto old_device_buffer = device_buffer;
- new_size = static_cast<uint32_t>(exp2(ceil(log2((double)new_size))));
-
- device_buffer = vkrenderer::api.create_buffer(new_size, usage, VMA_MEMORY_USAGE_CPU_TO_GPU);
-
- auto old_buffer = vkrenderer::api.get_buffer(device_buffer);
- auto new_buffer = vkrenderer::api.get_buffer(device_buffer);
- std::memcpy(new_buffer.device_ptr, old_buffer.device_ptr, buffer_size);
-
- buffer_size = new_size;
-
- vkrenderer::api.destroy_buffer(old_device_buffer);
-}
-
-
-RingBuffer::RingBuffer(size_t size)
- : buffer_size(size) {
- device_buffer = vkrenderer::api.create_buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
- }
diff --git a/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;
+}