Skip to content

Commit

Permalink
add fence and start collecting stacktrace after new errors
Browse files Browse the repository at this point in the history
  • Loading branch information
leanid committed Jan 12, 2025
1 parent bab7db9 commit 99b5b00
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 26 deletions.
2 changes: 1 addition & 1 deletion 00-basic-prog/18-stacktrace/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.20...3.28)
cmake_minimum_required(VERSION 3.31)

project(18-stacktrace CXX)

Expand Down
13 changes: 13 additions & 0 deletions 02-vulkan/08-vk-framebuffer-cmd-2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ target_link_libraries(
Vulkan::Vulkan
SDL3::SDL3-shared)

# cmake-format: off
target_link_libraries(
08-vk-framebuffer-cmd-2
PRIVATE
$<$<CXX_COMPILER_ID:GNU>:
$<IF:$<VERSION_GREATER_EQUAL:${CMAKE_CXX_COMPILER_VERSION},14.0.0>,
stdc++exp,
$<$<VERSION_GREATER_EQUAL:${CMAKE_CXX_COMPILER_VERSION},12.1.1>:
stdc++_libbacktrace>
>
>)
# cmake-format: on

# Find the shader files
file(GLOB_RECURSE shader_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert
Expand Down
25 changes: 24 additions & 1 deletion 02-vulkan/08-vk-framebuffer-cmd-2/main.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
#include <ios>
#include <iostream>
#include <memory>
#include <thread>

#include <SDL3/SDL.h>
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_vulkan.h>
#include <thread>

#include "platform_sdl3.hxx"

Expand Down Expand Up @@ -94,6 +94,29 @@ int main(int argc, char** argv)
vk_debug_callback_ext };
render render(platform, hints);

bool running = true;
while (running)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type) // NOLINT
{
case SDL_EVENT_QUIT:
running = false;
break;
case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_ESCAPE)
running = false;
break;
}
}

render.draw();

// running = false;
// std::this_thread::sleep_for(std::chrono::seconds(2));
}
render.draw();

std::this_thread::sleep_for(std::chrono::seconds(2));
Expand Down
113 changes: 94 additions & 19 deletions 02-vulkan/08-vk-framebuffer-cmd-2/render.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
#include <ranges>
#include <set>
#include <sstream>
#include <stacktrace>
#include <stdexcept>
#include <string_view>
#include <tuple>

namespace om::vulkan
{
/// @breaf maximum number of frames to be processed simultaneously by the GPU
static constexpr size_t max_frames_in_gpu = 2;

/// @concurency note
/// A callback will always be executed in the same thread as the originating
/// Vulkan call.
Expand Down Expand Up @@ -77,7 +81,8 @@ debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
break;
}

const char* severity_name = "unknown";
const char* severity_name = "unknown";
bool print_stacktrace = false;

switch (severity)
{
Expand All @@ -91,7 +96,8 @@ debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
severity_name = "warning";
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
severity_name = "error";
severity_name = "error";
print_stacktrace = true;
break;
default:
break;
Expand All @@ -103,6 +109,12 @@ debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
cerr << "vk: [" << severity_name << "] [" << msg_type_name << "] " << msg
<< "\n objects: " << msg_extended << endl;

if (print_stacktrace)
{
cerr << std::stacktrace::current() << endl;
std::terminate();
}

return VK_FALSE;
}

Expand Down Expand Up @@ -185,14 +197,33 @@ void render::draw()
auto image_index = devices.logical.acquireNextImageKHR(
swapchain,
std::numeric_limits<uint64_t>::max(),
semaphores.image_available,
nullptr);
synchronization.image_available.at(current_frame_index),
synchronization.gpu_fence.at(current_frame_index));

if (image_index.result != vk::Result::eSuccess)
{
throw std::runtime_error("error: can't acquire next image");
}

auto fence_op_result = devices.logical.waitForFences(
1,
&synchronization.gpu_fence.at(current_frame_index),
vk::True,
std::numeric_limits<uint64_t>::max());

if (fence_op_result != vk::Result::eSuccess)
{
throw std::runtime_error("error: can't wait for fence");
}

fence_op_result = devices.logical.resetFences(
1, &synchronization.gpu_fence.at(current_frame_index));

if (fence_op_result != vk::Result::eSuccess)
{
throw std::runtime_error("error: can't reset fence");
}

// Submit command buffer to queue

vk::PipelineStageFlags wait_stages =
Expand All @@ -201,30 +232,37 @@ void render::draw()
auto& cmd_buffer = command_buffers.at(image_index.value);

vk::SubmitInfo submit_info{};
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &semaphores.image_available;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores =
&synchronization.image_available.at(current_frame_index);
submit_info.pWaitDstStageMask = &wait_stages;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmd_buffer;
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &semaphores.render_finished;
submit_info.pSignalSemaphores =
&synchronization.render_finished.at(current_frame_index);

render_queue.submit(submit_info, {});
render_queue.submit(submit_info,
// set fence to vk::True after queue finish execution
synchronization.gpu_fence.at(current_frame_index));

// Present image to screen
vk::PresentInfoKHR present_info{};
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = &semaphores.render_finished;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &image_index.value;
present_info.pWaitSemaphores =
&synchronization.render_finished.at(current_frame_index);
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &image_index.value;

auto result = presentation_queue.presentKHR(present_info);

if (result != vk::Result::eSuccess)
{
throw std::runtime_error("error: can't present image to screen");
}

current_frame_index = (current_frame_index + 1) % max_frames_in_gpu;
}

void render::create_instance(bool enable_validation_layers,
Expand Down Expand Up @@ -1207,17 +1245,54 @@ void render::record_commands()

void render::create_synchronization_objects()
{
vk::SemaphoreCreateInfo semaphore_info{};
semaphores.image_available =
devices.logical.createSemaphore(semaphore_info);
semaphores.render_finished =
devices.logical.createSemaphore(semaphore_info);
synchronization.image_available.resize(max_frames_in_gpu);
synchronization.render_finished.resize(max_frames_in_gpu);
synchronization.gpu_fence.resize(max_frames_in_gpu);

struct gen_sem
{
render& self;
std::string name;
int index;

vk::Semaphore operator()()
{
auto semaphore = self.devices.logical.createSemaphore({});
self.set_object_name(semaphore, name + std::to_string(index++));
return semaphore;
}
};

std::ranges::generate(
synchronization.image_available,
gen_sem{ .self = *this, .name = "image_available_", .index = 0 });

std::ranges::generate(
synchronization.render_finished,
gen_sem{ .self = *this, .name = "render_finished_", .index = 0 });

std::ranges::generate(synchronization.gpu_fence,
[this, i = 0]() mutable
{
vk::FenceCreateInfo info{};
auto fence = devices.logical.createFence(info);
set_object_name(fence,
"fence_" + std::to_string(i++));
return fence;
});
}

void render::destroy_synchronization_objects()
{
devices.logical.destroy(semaphores.render_finished);
devices.logical.destroy(semaphores.image_available);
auto destroy_sem = [this](vk::Semaphore& semaphore)
{ devices.logical.destroy(semaphore); };

std::ranges::for_each(synchronization.image_available, destroy_sem);
std::ranges::for_each(synchronization.render_finished, destroy_sem);

std::ranges::for_each(synchronization.gpu_fence,
[this](vk::Fence& fence)
{ devices.logical.destroy(fence); });
}

vk::Extent2D render::choose_best_swapchain_image_resolution(
Expand Down
14 changes: 9 additions & 5 deletions 02-vulkan/08-vk-framebuffer-cmd-2/render.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private:
friend std::ostream& operator<<(std::ostream& os,
const swapchain_details_t& details);
// debug functions
void set_object_name(auto object, const char* name)
void set_object_name(auto object, const std::string& name)
{
if (!hints_.enable_debug_callback_ext)
{
Expand All @@ -172,7 +172,7 @@ private:
name_info.objectType = object.objectType;
name_info.objectHandle = reinterpret_cast<uint64_t>(
static_cast<decltype(object)::NativeType>(object));
name_info.pObjectName = name;
name_info.pObjectName = name.c_str();
devices.logical.setDebugUtilsObjectNameEXT(name_info, dynamic_loader);
}

Expand All @@ -188,6 +188,9 @@ private:
// debug extension is not available on macOS
vk::DebugUtilsMessengerEXT debug_extension;

// mod(max_frames_in_gpu) used to avoid blocking the CPU
uint32_t current_frame_index = 0;

struct
{
vk::PhysicalDevice physical;
Expand Down Expand Up @@ -218,9 +221,10 @@ private:
// sinhronization
struct
{
vk::Semaphore image_available{};
vk::Semaphore render_finished{};
} semaphores;
std::vector<vk::Semaphore> image_available{}; // GPU to GPU only sync
std::vector<vk::Semaphore> render_finished{}; // GPU to CPU sync
std::vector<vk::Fence> gpu_fence{};
} synchronization;

struct queue_family_indexes
{
Expand Down

0 comments on commit 99b5b00

Please sign in to comment.