From 75c41107b9fa1751f6e425daa3c38b7c0668c4f3 Mon Sep 17 00:00:00 2001 From: Dominik Witczak Date: Fri, 1 Dec 2017 14:49:25 +0100 Subject: [PATCH] Improvements. Addresses #46, #43, #33. --- examples/DynamicBuffers/include/app.h | 11 +- examples/DynamicBuffers/src/app.cpp | 53 +-- examples/MultiViewport/include/app.h | 11 +- examples/MultiViewport/src/app.cpp | 38 +- examples/OcclusionQuery/include/app.h | 11 +- examples/OcclusionQuery/src/app.cpp | 49 ++- .../OutOfOrderRasterization/include/app.h | 14 +- examples/OutOfOrderRasterization/src/app.cpp | 108 ++--- examples/PushConstants/include/app.h | 11 +- examples/PushConstants/src/app.cpp | 43 +- include/misc/callbacks.h | 413 +++++++++++++----- include/misc/debug.h | 13 +- include/misc/dummy_window.h | 36 +- include/misc/glsl_to_spirv.h | 57 ++- include/misc/memalloc_backends/backend_vma.h | 5 +- include/misc/memory_allocator.h | 21 +- include/misc/object_tracker.h | 60 ++- include/misc/shader_module_cache.h | 9 +- include/misc/types.h | 36 +- include/misc/window.h | 71 ++- include/misc/window_factory.h | 27 +- include/misc/window_win3264.h | 45 +- include/misc/window_xcb.h | 24 +- include/wrappers/buffer.h | 19 +- include/wrappers/command_buffer.h | 21 +- include/wrappers/descriptor_pool.h | 2 +- include/wrappers/descriptor_set.h | 6 +- include/wrappers/descriptor_set_layout.h | 2 +- include/wrappers/device.h | 11 + include/wrappers/framebuffer.h | 3 +- include/wrappers/graphics_pipeline_manager.h | 44 +- include/wrappers/image.h | 60 ++- include/wrappers/instance.h | 55 +-- include/wrappers/memory_block.h | 49 +-- include/wrappers/pipeline_layout.h | 14 +- include/wrappers/pipeline_layout_manager.h | 4 +- include/wrappers/queue.h | 9 +- include/wrappers/render_pass.h | 2 +- include/wrappers/shader_module.h | 23 +- include/wrappers/swapchain.h | 8 +- src/misc/debug.cpp | 15 +- src/misc/dummy_window.cpp | 56 ++- src/misc/formats.cpp | 5 +- src/misc/glsl_to_spirv.cpp | 151 ++++--- src/misc/io.cpp | 2 +- src/misc/memalloc_backends/backend_vma.cpp | 39 +- src/misc/memory_allocator.cpp | 205 ++++----- src/misc/object_tracker.cpp | 67 ++- src/misc/shader_module_cache.cpp | 75 ++-- src/misc/types.cpp | 129 +++++- src/misc/window.cpp | 26 +- src/misc/window_factory.cpp | 26 +- src/misc/window_win3264.cpp | 96 ++-- src/misc/window_xcb.cpp | 61 +-- src/misc/xcb_loader.cpp | 8 +- src/wrappers/buffer.cpp | 50 ++- src/wrappers/command_buffer.cpp | 52 ++- src/wrappers/descriptor_pool.cpp | 4 +- src/wrappers/descriptor_set.cpp | 45 +- src/wrappers/descriptor_set_layout.cpp | 9 +- src/wrappers/device.cpp | 12 +- src/wrappers/framebuffer.cpp | 36 +- src/wrappers/graphics_pipeline_manager.cpp | 37 +- src/wrappers/image.cpp | 36 +- src/wrappers/instance.cpp | 33 +- src/wrappers/memory_block.cpp | 360 +++++++-------- src/wrappers/pipeline_layout.cpp | 9 +- src/wrappers/pipeline_layout_manager.cpp | 47 +- src/wrappers/queue.cpp | 35 +- src/wrappers/render_pass.cpp | 32 +- src/wrappers/rendering_surface.cpp | 58 ++- src/wrappers/shader_module.cpp | 35 +- src/wrappers/swapchain.cpp | 113 +++-- 73 files changed, 1933 insertions(+), 1529 deletions(-) diff --git a/examples/DynamicBuffers/include/app.h b/examples/DynamicBuffers/include/app.h index ca83f03c..fbd46c51 100644 --- a/examples/DynamicBuffers/include/app.h +++ b/examples/DynamicBuffers/include/app.h @@ -54,12 +54,11 @@ class App void init_window (); void init_vulkan (); - static void draw_frame (void* app_raw_ptr); - static VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, - VkDebugReportObjectTypeEXT object_type, - const char* layer_prefix, - const char* message, - void* user_arg); + void draw_frame (); + VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, + VkDebugReportObjectTypeEXT object_type, + const char* layer_prefix, + const char* message); void get_buffer_memory_offsets(uint32_t n_sine_pair, uint32_t* out_opt_sine1SB_offset_ptr, diff --git a/examples/DynamicBuffers/src/app.cpp b/examples/DynamicBuffers/src/app.cpp index 377b18d8..a586d1b0 100644 --- a/examples/DynamicBuffers/src/app.cpp +++ b/examples/DynamicBuffers/src/app.cpp @@ -248,39 +248,38 @@ void App::deinit() m_instance_ptr.reset(); } -void App::draw_frame(void* app_raw_ptr) +void App::draw_frame() { - App* app_ptr = static_cast(app_raw_ptr); std::shared_ptr curr_frame_signal_semaphore_ptr; std::shared_ptr curr_frame_wait_semaphore_ptr; - std::shared_ptr device_locked_ptr = app_ptr->m_device_ptr.lock(); + std::shared_ptr device_locked_ptr = m_device_ptr.lock(); static uint32_t n_frames_rendered = 0; uint32_t n_swapchain_image; std::shared_ptr present_wait_semaphore_ptr; const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; /* Determine the signal + wait semaphores to use for drawing this frame */ - app_ptr->m_n_last_semaphore_used = (app_ptr->m_n_last_semaphore_used + 1) % app_ptr->m_n_swapchain_images; + m_n_last_semaphore_used = (m_n_last_semaphore_used + 1) % m_n_swapchain_images; - curr_frame_signal_semaphore_ptr = app_ptr->m_frame_signal_semaphores[app_ptr->m_n_last_semaphore_used]; - curr_frame_wait_semaphore_ptr = app_ptr->m_frame_wait_semaphores [app_ptr->m_n_last_semaphore_used]; + curr_frame_signal_semaphore_ptr = m_frame_signal_semaphores[m_n_last_semaphore_used]; + curr_frame_wait_semaphore_ptr = m_frame_wait_semaphores [m_n_last_semaphore_used]; present_wait_semaphore_ptr = curr_frame_signal_semaphore_ptr; /* Determine the semaphore which the swapchain image */ - n_swapchain_image = app_ptr->m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr, - true); /* in_should_block */ + n_swapchain_image = m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr, + true); /* in_should_block */ /* Update time value, used by the generator compute shader */ - const uint64_t time_msec = app_ptr->m_time.get_time_in_msec(); + const uint64_t time_msec = m_time.get_time_in_msec(); const float t = time_msec / 1000.0f; - app_ptr->m_sine_props_data_buffer_ptr->write(app_ptr->m_sine_props_data_buffer_size_per_swapchain_image * n_swapchain_image, /* start_offset */ - sizeof(float), /* size */ - &t); + m_sine_props_data_buffer_ptr->write(m_sine_props_data_buffer_size_per_swapchain_image * n_swapchain_image, /* start_offset */ + sizeof(float), /* size */ + &t); /* Submit jobs to relevant queues and make sure they are correctly synchronized */ - device_locked_ptr->get_universal_queue(0)->submit_command_buffer_with_signal_wait_semaphores(app_ptr->m_command_buffers[n_swapchain_image], + device_locked_ptr->get_universal_queue(0)->submit_command_buffer_with_signal_wait_semaphores(m_command_buffers[n_swapchain_image], 1, /* n_semaphores_to_signal */ &curr_frame_signal_semaphore_ptr, 1, /* n_semaphores_to_wait_on */ @@ -289,10 +288,10 @@ void App::draw_frame(void* app_raw_ptr) false, /* should_block */ nullptr); - app_ptr->m_present_queue_ptr->present(app_ptr->m_swapchain_ptr, - n_swapchain_image, - 1, /* n_wait_semaphores */ - &present_wait_semaphore_ptr); + m_present_queue_ptr->present(m_swapchain_ptr, + n_swapchain_image, + 1, /* n_wait_semaphores */ + &present_wait_semaphore_ptr); ++n_frames_rendered; @@ -300,7 +299,7 @@ void App::draw_frame(void* app_raw_ptr) { if (n_frames_rendered >= N_FRAMES_TO_RENDER) { - app_ptr->m_window_ptr->close(); + m_window_ptr->close(); } } #endif @@ -1160,8 +1159,9 @@ void App::init_window() APP_NAME, 1280, 720, - draw_frame, - this); + true, /* in_closable */ + std::bind(&App::draw_frame, + this) ); } void App::init_vulkan() @@ -1170,11 +1170,15 @@ void App::init_vulkan() m_instance_ptr = Anvil::Instance::create(APP_NAME, /* app_name */ APP_NAME, /* engine_name */ #ifdef ENABLE_VALIDATION - on_validation_callback, + std::bind(&App::on_validation_callback, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4) ); #else - nullptr, + nullptr); #endif - nullptr); /* validation_proc_user_arg */ m_physical_device_ptr = m_instance_ptr->get_physical_device(0); @@ -1189,8 +1193,7 @@ void App::init_vulkan() VkBool32 App::on_validation_callback(VkDebugReportFlagsEXT message_flags, VkDebugReportObjectTypeEXT object_type, const char* layer_prefix, - const char* message, - void* user_arg) + const char* message) { if ((message_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { diff --git a/examples/MultiViewport/include/app.h b/examples/MultiViewport/include/app.h index d8f0dd86..510105ed 100644 --- a/examples/MultiViewport/include/app.h +++ b/examples/MultiViewport/include/app.h @@ -64,12 +64,11 @@ class App void get_scissor_viewport_info(VkRect2D* out_scissors, VkViewport* out_viewports); - static void draw_frame (void* app_raw_ptr); - static VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, - VkDebugReportObjectTypeEXT object_type, - const char* layer_prefix, - const char* message, - void* user_arg); + void draw_frame (); + VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, + VkDebugReportObjectTypeEXT object_type, + const char* layer_prefix, + const char* message); /* Private variables */ std::weak_ptr m_device_ptr; diff --git a/examples/MultiViewport/src/app.cpp b/examples/MultiViewport/src/app.cpp index 5f7d6fbe..e3c038cb 100644 --- a/examples/MultiViewport/src/app.cpp +++ b/examples/MultiViewport/src/app.cpp @@ -220,28 +220,27 @@ void App::deinit() m_window_ptr.reset(); } -void App::draw_frame(void* app_raw_ptr) +void App::draw_frame() { - App* app_ptr = static_cast(app_raw_ptr); std::shared_ptr curr_frame_signal_semaphore_ptr; std::shared_ptr curr_frame_wait_semaphore_ptr; - std::shared_ptr device_locked_ptr = app_ptr->m_device_ptr.lock(); + std::shared_ptr device_locked_ptr = m_device_ptr.lock(); static uint32_t n_frames_rendered = 0; uint32_t n_swapchain_image; std::shared_ptr present_queue_ptr = device_locked_ptr->get_universal_queue(0); const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; /* Determine the signal + wait semaphores to use for drawing this frame */ - app_ptr->m_n_last_semaphore_used = (app_ptr->m_n_last_semaphore_used + 1) % app_ptr->m_n_swapchain_images; + m_n_last_semaphore_used = (m_n_last_semaphore_used + 1) % m_n_swapchain_images; - curr_frame_signal_semaphore_ptr = app_ptr->m_frame_signal_semaphores[app_ptr->m_n_last_semaphore_used]; - curr_frame_wait_semaphore_ptr = app_ptr->m_frame_wait_semaphores [app_ptr->m_n_last_semaphore_used]; + curr_frame_signal_semaphore_ptr = m_frame_signal_semaphores[m_n_last_semaphore_used]; + curr_frame_wait_semaphore_ptr = m_frame_wait_semaphores [m_n_last_semaphore_used]; /* Determine the semaphore which the swapchain image */ - n_swapchain_image = app_ptr->m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr); + n_swapchain_image = m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr); /* Submit work chunk and present */ - device_locked_ptr->get_universal_queue(0)->submit_command_buffer_with_signal_wait_semaphores(app_ptr->m_command_buffers[n_swapchain_image], + device_locked_ptr->get_universal_queue(0)->submit_command_buffer_with_signal_wait_semaphores(m_command_buffers[n_swapchain_image], 1, /* n_semaphores_to_signal */ &curr_frame_signal_semaphore_ptr, 1, /* n_semaphores_to_wait_on */ @@ -250,7 +249,7 @@ void App::draw_frame(void* app_raw_ptr) false, /* should_block */ nullptr); /* opt_fence_ptr */ - present_queue_ptr->present(app_ptr->m_swapchain_ptr, + present_queue_ptr->present(m_swapchain_ptr, n_swapchain_image, 1, /* n_wait_semaphores */ &curr_frame_signal_semaphore_ptr); @@ -263,7 +262,7 @@ void App::draw_frame(void* app_raw_ptr) } else { - app_ptr->m_window_ptr->close(); + m_window_ptr->close(); } } #endif @@ -884,8 +883,10 @@ void App::init_window() APP_NAME, 1280, 720, - draw_frame, - this); + true, /* in_closable */ + std::bind(&App::draw_frame, + this) + ); } void App::init_vulkan() @@ -894,11 +895,15 @@ void App::init_vulkan() m_instance_ptr = Anvil::Instance::create(APP_NAME, /* app_name */ APP_NAME, /* engine_name */ #ifdef ENABLE_VALIDATION - on_validation_callback, + std::bind(&App::on_validation_callback, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4) ); #else - nullptr, + nullptr); #endif - nullptr); /* validation_proc_user_arg */ m_physical_device_ptr = m_instance_ptr->get_physical_device(0); @@ -913,8 +918,7 @@ void App::init_vulkan() VkBool32 App::on_validation_callback(VkDebugReportFlagsEXT message_flags, VkDebugReportObjectTypeEXT object_type, const char* layer_prefix, - const char* message, - void* user_arg) + const char* message) { if ((message_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { diff --git a/examples/OcclusionQuery/include/app.h b/examples/OcclusionQuery/include/app.h index d362ccd2..951ae2df 100644 --- a/examples/OcclusionQuery/include/app.h +++ b/examples/OcclusionQuery/include/app.h @@ -54,12 +54,11 @@ class App void init_window (); void init_vulkan (); - static void draw_frame (void* app_raw_ptr); - static VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, - VkDebugReportObjectTypeEXT object_type, - const char* layer_prefix, - const char* message, - void* user_arg); + void draw_frame (); + VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, + VkDebugReportObjectTypeEXT object_type, + const char* layer_prefix, + const char* message); /* Private variables */ std::weak_ptr m_device_ptr; diff --git a/examples/OcclusionQuery/src/app.cpp b/examples/OcclusionQuery/src/app.cpp index eb32425e..a2f5c29f 100644 --- a/examples/OcclusionQuery/src/app.cpp +++ b/examples/OcclusionQuery/src/app.cpp @@ -219,12 +219,11 @@ void App::deinit() m_window_ptr.reset(); } -void App::draw_frame(void* app_raw_ptr) +void App::draw_frame() { - App* app_ptr = static_cast(app_raw_ptr); std::shared_ptr curr_frame_signal_semaphore_ptr; std::shared_ptr curr_frame_wait_semaphore_ptr; - std::shared_ptr device_locked_ptr = app_ptr->m_device_ptr.lock(); + std::shared_ptr device_locked_ptr = m_device_ptr.lock(); static uint32_t n_frames_rendered = 0; uint32_t n_swapchain_image; std::shared_ptr present_queue_ptr = device_locked_ptr->get_universal_queue(0); @@ -232,29 +231,29 @@ void App::draw_frame(void* app_raw_ptr) const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; /* Determine the signal + wait semaphores to use for drawing this frame */ - app_ptr->m_n_last_semaphore_used = (app_ptr->m_n_last_semaphore_used + 1) % app_ptr->m_n_swapchain_images; + m_n_last_semaphore_used = (m_n_last_semaphore_used + 1) % m_n_swapchain_images; - curr_frame_signal_semaphore_ptr = app_ptr->m_frame_signal_semaphores[app_ptr->m_n_last_semaphore_used]; - curr_frame_wait_semaphore_ptr = app_ptr->m_frame_wait_semaphores [app_ptr->m_n_last_semaphore_used]; + curr_frame_signal_semaphore_ptr = m_frame_signal_semaphores[m_n_last_semaphore_used]; + curr_frame_wait_semaphore_ptr = m_frame_wait_semaphores [m_n_last_semaphore_used]; present_wait_semaphore_ptr = curr_frame_signal_semaphore_ptr; /* Determine the semaphore which the swapchain image */ - n_swapchain_image = app_ptr->m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr, - true); /* in_should_block */ + n_swapchain_image = m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr, + true); /* in_should_block */ /* Update time data */ - const float time = float(app_ptr->m_time.get_time_in_msec() ) / 1000.0f; + const float time = float(m_time.get_time_in_msec() ) / 1000.0f; - app_ptr->m_time_bo_ptr->write(n_swapchain_image * app_ptr->m_time_n_bytes_per_swapchain_image, /* start_offset */ - sizeof(time), - &time); + m_time_bo_ptr->write(n_swapchain_image * m_time_n_bytes_per_swapchain_image, /* start_offset */ + sizeof(time), + &time); /* Submit work chunks and present */ std::shared_ptr cmd_buffers[] = { - app_ptr->m_render_tri1_and_generate_ot_data_cmd_buffers[n_swapchain_image], - app_ptr->m_render_tri2_and_quad_cmd_buffers [n_swapchain_image] + m_render_tri1_and_generate_ot_data_cmd_buffers[n_swapchain_image], + m_render_tri2_and_quad_cmd_buffers [n_swapchain_image] }; const uint32_t n_cmd_buffers = sizeof(cmd_buffers) / sizeof(cmd_buffers[0]); @@ -267,7 +266,7 @@ void App::draw_frame(void* app_raw_ptr) &wait_stage_mask, false); /* should_block */ - present_queue_ptr->present(app_ptr->m_swapchain_ptr, + present_queue_ptr->present(m_swapchain_ptr, n_swapchain_image, 1, /* n_wait_semaphores */ &present_wait_semaphore_ptr); @@ -278,7 +277,7 @@ void App::draw_frame(void* app_raw_ptr) { if (n_frames_rendered >= N_FRAMES_TO_RENDER) { - app_ptr->m_window_ptr->close(); + m_window_ptr->close(); } } #endif @@ -964,8 +963,9 @@ void App::init_window() APP_NAME, 1280, 720, - draw_frame, - this); + true, /* in_closable */ + std::bind(&App::draw_frame, + this) ); } void App::init_vulkan() @@ -974,11 +974,15 @@ void App::init_vulkan() m_instance_ptr = Anvil::Instance::create(APP_NAME, /* app_name */ APP_NAME, /* engine_name */ #ifdef ENABLE_VALIDATION - on_validation_callback, + std::bind(&App::on_validation_callback, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4) ); #else - nullptr, + nullptr); #endif - nullptr); /* validation_proc_user_arg */ m_physical_device_ptr = m_instance_ptr->get_physical_device(0); @@ -993,8 +997,7 @@ void App::init_vulkan() VkBool32 App::on_validation_callback(VkDebugReportFlagsEXT message_flags, VkDebugReportObjectTypeEXT object_type, const char* layer_prefix, - const char* message, - void* user_arg) + const char* message) { if ((message_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { diff --git a/examples/OutOfOrderRasterization/include/app.h b/examples/OutOfOrderRasterization/include/app.h index 5c9de133..2755cd35 100644 --- a/examples/OutOfOrderRasterization/include/app.h +++ b/examples/OutOfOrderRasterization/include/app.h @@ -59,14 +59,12 @@ class App void update_fps (); void update_teapot_props(uint32_t n_current_swapchain_image); - static void draw_frame (void* app_raw_ptr); - static void on_keypress_event (void* callback_data_raw_ptr, - void* app_raw_ptr); - static VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, - VkDebugReportObjectTypeEXT object_type, - const char* layer_prefix, - const char* message, - void* user_arg); + void draw_frame (); + void on_keypress_event (Anvil::CallbackArgument* callback_data_raw_ptr); + VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, + VkDebugReportObjectTypeEXT object_type, + const char* layer_prefix, + const char* message); /* Private variables */ std::weak_ptr m_device_ptr; diff --git a/examples/OutOfOrderRasterization/src/app.cpp b/examples/OutOfOrderRasterization/src/app.cpp index dff08e2e..2486417b 100644 --- a/examples/OutOfOrderRasterization/src/app.cpp +++ b/examples/OutOfOrderRasterization/src/app.cpp @@ -260,10 +260,9 @@ void App::deinit() m_window_ptr.reset(); } -void App::draw_frame(void* app_raw_ptr) +void App::draw_frame() { - App* app_ptr = static_cast(app_raw_ptr); - std::shared_ptr device_locked_ptr = app_ptr->m_device_ptr.lock(); + std::shared_ptr device_locked_ptr = m_device_ptr.lock(); std::shared_ptr sgpu_device_locked_ptr = std::dynamic_pointer_cast(device_locked_ptr); static const VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; const uint32_t n_physical_devices = 1; @@ -274,21 +273,21 @@ void App::draw_frame(void* app_raw_ptr) const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; /* Determine the signal + wait semaphores to use for drawing this frame */ - app_ptr->m_n_last_semaphore_used = (app_ptr->m_n_last_semaphore_used + 1) % app_ptr->m_n_swapchain_images; + m_n_last_semaphore_used = (m_n_last_semaphore_used + 1) % m_n_swapchain_images; - auto& curr_frame_signal_semaphores = app_ptr->m_frame_signal_semaphore_bundles.at (app_ptr->m_n_last_semaphore_used); - const auto& curr_frame_wait_semaphores = app_ptr->m_frame_wait_semaphore_bundles.at (app_ptr->m_n_last_semaphore_used); + auto& curr_frame_signal_semaphores = m_frame_signal_semaphore_bundles.at (m_n_last_semaphore_used); + const auto& curr_frame_wait_semaphores = m_frame_wait_semaphore_bundles.at (m_n_last_semaphore_used); const auto& curr_frame_acqusition_wait_semaphore_ptr = curr_frame_wait_semaphores.semaphores.at(0); auto& curr_frame_present_wait_semaphore_ptr = curr_frame_signal_semaphores.semaphores.at(0); /* Determine the semaphore which the swapchain image */ - n_swapchain_image = app_ptr->m_swapchain_ptr->acquire_image(curr_frame_acqusition_wait_semaphore_ptr, - true); /* in_should_block */ + n_swapchain_image = m_swapchain_ptr->acquire_image(curr_frame_acqusition_wait_semaphore_ptr, + true); /* in_should_block */ /* if the frame has already been rendered to in the past, then given the fact we use FIFO presentation mode, * we should be safe to extract the timestamps which must have been written by now. */ - if (app_ptr->m_frame_drawn_status[n_swapchain_image]) + if (m_frame_drawn_status[n_swapchain_image]) { uint64_t timestamps[2]; /* top of pipe, bottom of pipe */ @@ -303,56 +302,56 @@ void App::draw_frame(void* app_raw_ptr) { auto current_physical_device_ptr = physical_devices_ptr[n_iteration]; - app_ptr->m_query_results_buffer_ptr->read(n_swapchain_image * sizeof(uint64_t) * 2, /* top of pipe, bottom of pipe */ - sizeof(timestamps), - timestamps); + m_query_results_buffer_ptr->read(n_swapchain_image * sizeof(uint64_t) * 2, /* top of pipe, bottom of pipe */ + sizeof(timestamps), + timestamps); anvil_assert(timestamps[1] != timestamps[0]); - app_ptr->m_timestamp_deltas.push_back(timestamps[1] - timestamps[0]); + m_timestamp_deltas.push_back(timestamps[1] - timestamps[0]); } - if (app_ptr->m_timestamp_deltas.size() >= N_TIMESTAMP_DELTAS_PER_AVERAGE_FPS_CALCULATION) + if (m_timestamp_deltas.size() >= N_TIMESTAMP_DELTAS_PER_AVERAGE_FPS_CALCULATION) { - app_ptr->update_fps(); + update_fps(); } } /* Update the teapot properties data for the current swapchain image */ - app_ptr->update_teapot_props(n_swapchain_image); + update_teapot_props(n_swapchain_image); /* Submit work chunks and present */ - if (app_ptr->m_ooo_enabled) + if (m_ooo_enabled) { - render_cmdbuffer_ptr = app_ptr->m_render_cmdbuffers_ooo_on.at(n_swapchain_image); + render_cmdbuffer_ptr = m_render_cmdbuffers_ooo_on.at(n_swapchain_image); } else { - render_cmdbuffer_ptr = app_ptr->m_render_cmdbuffers_ooo_off.at(n_swapchain_image); + render_cmdbuffer_ptr = m_render_cmdbuffers_ooo_off.at(n_swapchain_image); } - app_ptr->m_present_queue_ptr->submit_command_buffer_with_signal_wait_semaphores(render_cmdbuffer_ptr, - 1, /* n_semaphores_to_signal */ - &curr_frame_present_wait_semaphore_ptr, - 1, /* n_semaphores_to_wait_on */ - &curr_frame_acqusition_wait_semaphore_ptr, - &wait_stage_mask, - false /* should_block */); + m_present_queue_ptr->submit_command_buffer_with_signal_wait_semaphores(render_cmdbuffer_ptr, + 1, /* n_semaphores_to_signal */ + &curr_frame_present_wait_semaphore_ptr, + 1, /* n_semaphores_to_wait_on */ + &curr_frame_acqusition_wait_semaphore_ptr, + &wait_stage_mask, + false /* should_block */); - app_ptr->m_present_queue_ptr->present(app_ptr->m_swapchain_ptr, - n_swapchain_image, - 1, /* n_wait_semaphores */ - &curr_frame_present_wait_semaphore_ptr); + m_present_queue_ptr->present(m_swapchain_ptr, + n_swapchain_image, + 1, /* n_wait_semaphores */ + &curr_frame_present_wait_semaphore_ptr); - ++app_ptr->m_n_frames_drawn; + ++m_n_frames_drawn; - app_ptr->m_frame_drawn_status[n_swapchain_image] = true; + m_frame_drawn_status[n_swapchain_image] = true; #if defined(ENABLE_OFFSCREEN_RENDERING) { - if (app_ptr->m_n_frames_drawn >= N_FRAMES_TO_RENDER) + if (m_n_frames_drawn >= N_FRAMES_TO_RENDER) { - app_ptr->m_window_ptr->close(); + m_window_ptr->close(); } } #endif @@ -1001,13 +1000,17 @@ void App::init_window() "OutOfOrderRasterization example", WINDOW_WIDTH, WINDOW_HEIGHT, - draw_frame, - this); + true, /* in_closable */ + std::bind(&App::draw_frame, + this) ); /* Sign up for keypress notifications */ m_window_ptr->register_for_callbacks(Anvil::WINDOW_CALLBACK_ID_KEYPRESS_RELEASED, - on_keypress_event, - this); + std::bind(&App::on_keypress_event, + this, + std::placeholders::_1), + this + ); } void App::init_vulkan() @@ -1016,11 +1019,15 @@ void App::init_vulkan() m_instance_ptr = Anvil::Instance::create("OutOfOrderRasterization", /* app_name */ "OutOfOrderRasterization", /* engine_name */ #ifdef ENABLE_VALIDATION - on_validation_callback, + std::bind(&App::on_validation_callback, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4) ); #else - nullptr, + nullptr); #endif - nullptr); /* validation_proc_user_arg */ /* Determine which extensions we need to request for */ std::shared_ptr physical_device_locked_ptr(m_instance_ptr->get_physical_device(0) ); @@ -1033,12 +1040,10 @@ void App::init_vulkan() false); /* support_resettable_command_buffers */ } -void App::on_keypress_event(void* callback_data_raw_ptr, - void* app_raw_ptr) +void App::on_keypress_event(Anvil::CallbackArgument* callback_data_raw_ptr) { - App* app_ptr = static_cast (app_raw_ptr); - Anvil::KeypressReleasedCallbackData* callback_data_ptr = static_cast(callback_data_raw_ptr); - std::shared_ptr device_locked_ptr = app_ptr->m_device_ptr.lock(); + Anvil::OnKeypressReleasedCallbackArgument* callback_data_ptr = static_cast(callback_data_raw_ptr); + std::shared_ptr device_locked_ptr = m_device_ptr.lock(); #ifndef ENABLE_OFFSCREEN_RENDERING { @@ -1048,15 +1053,15 @@ void App::on_keypress_event(void* callback_data_raw_ptr, if (device_locked_ptr->is_extension_enabled("VK_AMD_rasterization_order") ) { - app_ptr->m_ooo_enabled = !app_ptr->m_ooo_enabled; + m_ooo_enabled = !m_ooo_enabled; /* Note: this code should be wrapped in a critical section */ { - app_ptr->m_timestamp_deltas.clear(); + m_timestamp_deltas.clear(); } printf("[!] Now using %s rasterization order.\n\n", - (app_ptr->m_ooo_enabled) ? "relaxed" : "strict"); + (m_ooo_enabled) ? "relaxed" : "strict"); } else { @@ -1066,7 +1071,7 @@ void App::on_keypress_event(void* callback_data_raw_ptr, else if (callback_data_ptr->released_key_id == 'r' || callback_data_ptr->released_key_id == 'R') { - app_ptr->m_should_rotate = !app_ptr->m_should_rotate; + m_should_rotate = !m_should_rotate; } } #endif @@ -1075,8 +1080,7 @@ void App::on_keypress_event(void* callback_data_raw_ptr, VkBool32 App::on_validation_callback(VkDebugReportFlagsEXT message_flags, VkDebugReportObjectTypeEXT object_type, const char* layer_prefix, - const char* message, - void* user_arg) + const char* message) { if ((message_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { diff --git a/examples/PushConstants/include/app.h b/examples/PushConstants/include/app.h index 75f746af..6235ec22 100644 --- a/examples/PushConstants/include/app.h +++ b/examples/PushConstants/include/app.h @@ -53,12 +53,11 @@ class App void init_window (); void init_vulkan (); - static void draw_frame (void* app_raw_ptr); - static VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, - VkDebugReportObjectTypeEXT object_type, - const char* layer_prefix, - const char* message, - void* user_arg); + void draw_frame (); + VkBool32 on_validation_callback(VkDebugReportFlagsEXT message_flags, + VkDebugReportObjectTypeEXT object_type, + const char* layer_prefix, + const char* message); void get_luminance_data(std::shared_ptr* out_result_ptr, uint32_t* out_result_size_ptr) const; diff --git a/examples/PushConstants/src/app.cpp b/examples/PushConstants/src/app.cpp index 1b4c6250..d69bc033 100644 --- a/examples/PushConstants/src/app.cpp +++ b/examples/PushConstants/src/app.cpp @@ -243,12 +243,11 @@ void App::deinit() m_window_ptr.reset(); } -void App::draw_frame(void* app_raw_ptr) +void App::draw_frame() { - App* app_ptr = static_cast(app_raw_ptr); std::shared_ptr curr_frame_signal_semaphore_ptr; std::shared_ptr curr_frame_wait_semaphore_ptr; - std::shared_ptr device_locked_ptr = app_ptr->m_device_ptr.lock(); + std::shared_ptr device_locked_ptr = m_device_ptr.lock(); static uint32_t n_frames_rendered = 0; uint32_t n_swapchain_image; std::shared_ptr present_queue_ptr = device_locked_ptr->get_universal_queue(0); @@ -256,21 +255,21 @@ void App::draw_frame(void* app_raw_ptr) const VkPipelineStageFlags wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; /* Determine the signal + wait semaphores to use for drawing this frame */ - app_ptr->m_n_last_semaphore_used = (app_ptr->m_n_last_semaphore_used + 1) % app_ptr->m_n_swapchain_images; + m_n_last_semaphore_used = (m_n_last_semaphore_used + 1) % m_n_swapchain_images; - curr_frame_signal_semaphore_ptr = app_ptr->m_frame_signal_semaphores[app_ptr->m_n_last_semaphore_used]; - curr_frame_wait_semaphore_ptr = app_ptr->m_frame_wait_semaphores [app_ptr->m_n_last_semaphore_used]; + curr_frame_signal_semaphore_ptr = m_frame_signal_semaphores[m_n_last_semaphore_used]; + curr_frame_wait_semaphore_ptr = m_frame_wait_semaphores [m_n_last_semaphore_used]; present_wait_semaphore_ptr = curr_frame_signal_semaphore_ptr; /* Determine the semaphore which the swapchain image */ - n_swapchain_image = app_ptr->m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr, - true); /* in_should_block */ + n_swapchain_image = m_swapchain_ptr->acquire_image(curr_frame_wait_semaphore_ptr, + true); /* in_should_block */ /* Submit work chunk and present */ - app_ptr->update_data_ub_contents(n_swapchain_image); + update_data_ub_contents(n_swapchain_image); - present_queue_ptr->submit_command_buffer_with_signal_wait_semaphores(app_ptr->m_command_buffers[n_swapchain_image], + present_queue_ptr->submit_command_buffer_with_signal_wait_semaphores(m_command_buffers[n_swapchain_image], 1, /* n_semaphores_to_signal */ &curr_frame_signal_semaphore_ptr, 1, /* n_semaphores_to_wait_on */ @@ -278,7 +277,7 @@ void App::draw_frame(void* app_raw_ptr) &wait_stage_mask, false /* should_block */); - present_queue_ptr->present(app_ptr->m_swapchain_ptr, + present_queue_ptr->present(m_swapchain_ptr, n_swapchain_image, 1, /* n_wait_semaphores */ &present_wait_semaphore_ptr); @@ -289,7 +288,7 @@ void App::draw_frame(void* app_raw_ptr) { if (n_frames_rendered >= N_FRAMES_TO_RENDER) { - app_ptr->m_window_ptr->close(); + m_window_ptr->close(); } } #endif @@ -830,8 +829,10 @@ void App::init_window() APP_NAME, 1280, 720, - draw_frame, - this); + true, /* in_closable */ + std::bind(&App::draw_frame, + this) + ); } void App::init_vulkan() @@ -840,11 +841,16 @@ void App::init_vulkan() m_instance_ptr = Anvil::Instance::create(APP_NAME, /* app_name */ APP_NAME, /* engine_name */ #ifdef ENABLE_VALIDATION - on_validation_callback, + std::bind(&App::on_validation_callback, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4) ); + #else - nullptr, + nullptr); #endif - nullptr); /* validation_proc_user_arg */ m_physical_device_ptr = m_instance_ptr->get_physical_device(0); @@ -859,8 +865,7 @@ void App::init_vulkan() VkBool32 App::on_validation_callback(VkDebugReportFlagsEXT message_flags, VkDebugReportObjectTypeEXT object_type, const char* layer_prefix, - const char* message, - void* user_arg) + const char* message) { if ((message_flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0) { diff --git a/include/misc/callbacks.h b/include/misc/callbacks.h index d2cf2cca..a2f0079a 100644 --- a/include/misc/callbacks.h +++ b/include/misc/callbacks.h @@ -32,17 +32,27 @@ #define MISC_CALLBACKS_H #include "misc/debug.h" -#include -#include +#include "misc/io.h" +#include "misc/types.h" + #ifndef _WIN32 #include #endif -#include "misc/types.h" #include namespace Anvil { + /* Helper forward declarations .. */ + struct PipelineBarrierCommand; + + + /** Prototype of a call-back handler. + * + * @param in_callback_arg Call-back specific argument. + **/ + typedef std::function< void(CallbackArgument* in_callback_arg) > CallbackFunction; + /* Defines the callback ID type. * * Each class which inherits from CallbacksSupportProvider uses its own range of callback IDs. @@ -50,28 +60,202 @@ namespace Anvil **/ typedef int CallbackID; - /** Prototype of a call-back handler. - * - * @param in_callback_arg Call-back specific argument. - * @param in_user_arg Argument, specified by the subscriber at sign-up time. - **/ - typedef void (*PFNCALLBACKPROC)(void* in_callback_arg, - void* in_user_arg); + /* Base call-back argument structure. All call-back arguments are required to derive off this class. */ + struct CallbackArgument + { + virtual ~CallbackArgument() + { + /* Stub */ + } + }; + + + typedef struct IsBufferMemoryAllocPendingQueryCallbackArgument : public Anvil::CallbackArgument + { + std::shared_ptr buffer_ptr; + bool result; + + explicit IsBufferMemoryAllocPendingQueryCallbackArgument(std::shared_ptr in_buffer_ptr) + :buffer_ptr(in_buffer_ptr), + result (false) + { + /* Stub */ + } + + IsBufferMemoryAllocPendingQueryCallbackArgument& operator=(const IsBufferMemoryAllocPendingQueryCallbackArgument&) = delete; + } IsBufferMemoryAllocPendingQueryCallbackArgument; + + typedef struct IsImageMemoryAllocPendingQueryCallbackArgument : Anvil::CallbackArgument + { + explicit IsImageMemoryAllocPendingQueryCallbackArgument(std::shared_ptr in_image_ptr) + :image_ptr(in_image_ptr), + result (false) + { + /* Stub */ + } + + IsImageMemoryAllocPendingQueryCallbackArgument& operator=(const IsImageMemoryAllocPendingQueryCallbackArgument&) = delete; + + const std::shared_ptr image_ptr; + bool result; + } IsImageMemoryAllocPendingQueryCallbackArgument; + + typedef struct OnDescriptorPoolResetCallbackArgument : public Anvil::CallbackArgument + { + DescriptorPool* descriptor_pool_ptr; + + explicit OnDescriptorPoolResetCallbackArgument(DescriptorPool* in_descriptor_pool_ptr) + { + descriptor_pool_ptr = in_descriptor_pool_ptr; + } + } OnDescriptorPoolResetCallbackArgument; + + typedef struct OnGLSLToSPIRVConversionAboutToBeStartedCallbackArgument : public Anvil::CallbackArgument + { + GLSLShaderToSPIRVGenerator* generator_ptr; + + explicit OnGLSLToSPIRVConversionAboutToBeStartedCallbackArgument(GLSLShaderToSPIRVGenerator* in_generator_ptr) + { + generator_ptr = in_generator_ptr; + } + } OnGLSLToSPIRVConversionAboutToBeStartedCallbackArgument; + + typedef struct OnKeypressReleasedCallbackArgument : public Anvil::CallbackArgument + { + KeyID released_key_id; + const Window* window_ptr; + + /** Constructor. + * + * @param in_command_buffer_ptr Command buffer instance the command is being recorded for. + * @param in_command_details_ptr Structure holding all arguments to be passed to the vkCmdBeginRenderPass() call. + **/ + explicit OnKeypressReleasedCallbackArgument(Window* in_window_ptr, + KeyID in_released_key_id) + :released_key_id(in_released_key_id), + window_ptr (in_window_ptr) + { + /* Stub */ + } + } OnKeypressReleasedCallbackArgument; + + typedef struct OnMemoryBlockNeededForBufferCallbackArgument : public Anvil::CallbackArgument + { + explicit OnMemoryBlockNeededForBufferCallbackArgument(std::shared_ptr in_buffer_ptr) + :buffer_ptr(in_buffer_ptr) + { + /* Stub */ + } + + OnMemoryBlockNeededForBufferCallbackArgument& operator=(const OnMemoryBlockNeededForBufferCallbackArgument&) = delete; + + const std::shared_ptr buffer_ptr; + } OnMemoryBlockNeededForBufferCallbackArgument; + + typedef struct OnMemoryBlockNeededForImageCallbackArgument : public Anvil::CallbackArgument + { + explicit OnMemoryBlockNeededForImageCallbackArgument(std::shared_ptr in_image_ptr) + :image_ptr(in_image_ptr) + { + /* Stub */ + } + + OnMemoryBlockNeededForImageCallbackArgument& operator=(const OnMemoryBlockNeededForImageCallbackArgument&) = delete; + + const std::shared_ptr image_ptr; + } OnMemoryBlockNeededForImageCallbackArgument; + + typedef struct OnNewBindingAddedToDescriptorSetLayoutCallbackArgument : public Anvil::CallbackArgument + { + DescriptorSetLayout* descriptor_set_layout_ptr; + + explicit OnNewBindingAddedToDescriptorSetLayoutCallbackArgument(DescriptorSetLayout* in_descriptor_set_layout_ptr) + { + descriptor_set_layout_ptr = in_descriptor_set_layout_ptr; + } + } OnNewBindingAddedToDescriptorSetLayoutCallbackArgument; + + typedef struct OnObjectRegisteredCallbackArgument : Anvil::CallbackArgument + { + void* object_raw_ptr; + ObjectType object_type; + + explicit OnObjectRegisteredCallbackArgument(const ObjectType& in_object_type, + void* in_object_raw_ptr) + { + anvil_assert(in_object_raw_ptr != nullptr); + + object_raw_ptr = in_object_raw_ptr; + object_type = in_object_type; + } + } OnObjectRegisteredCallbackArgument; + + typedef OnObjectRegisteredCallbackArgument OnObjectAboutToBeUnregisteredCallbackArgument; + + typedef struct OnPipelineBarrierCommandRecordedCallbackData : public Anvil::CallbackArgument + { + CommandBufferBase* command_buffer_ptr; + const PipelineBarrierCommand* command_details_ptr; + + /** Constructor. + * + * @param in_command_buffer_ptr Command buffer instance the command is being recorded for. + * @param in_command_details_ptr Structure holding all arguments to be passed to the vkCmdPipelineBarrier() call. + **/ + explicit OnPipelineBarrierCommandRecordedCallbackData(CommandBufferBase* in_command_buffer_ptr, + const PipelineBarrierCommand* in_command_details_ptr) + :command_buffer_ptr (in_command_buffer_ptr), + command_details_ptr(in_command_details_ptr) + { + /* Stub */ + } + } OnPipelineBarrierCommandRecordedCallbackData; + + typedef struct OnPresentRequestIssuedCallbackArgument : public Anvil::CallbackArgument + { + Swapchain* swapchain_ptr; + + explicit OnPresentRequestIssuedCallbackArgument(Swapchain* in_swapchain_ptr) + { + swapchain_ptr = in_swapchain_ptr; + } + } OnPresentRequestIssuedCallbackArgument; + + typedef struct OnRenderPassBakeNeededCallbackArgument : public Anvil::CallbackArgument + { + RenderPass* renderpass_ptr; + + explicit OnRenderPassBakeNeededCallbackArgument(RenderPass* in_renderpass_ptr) + { + renderpass_ptr = in_renderpass_ptr; + } + } OnRenderPassBakeNeededCallbackArgument; + + typedef struct OnWindowAboutToCloseCallbackArgument : public Anvil::CallbackArgument + { + Window* window_ptr; + + explicit OnWindowAboutToCloseCallbackArgument(Window* in_window_ptr) + { + window_ptr = in_window_ptr; + } + } OnWindowAboutToCloseCallbackArgument; + /** Interface which provides entrypoints that let class users sign up and sign out of * notifications. **/ class ICallbacksSupportClient { - virtual bool is_callback_registered (CallbackID in_callback_id, - PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) const = 0; - virtual void register_for_callbacks (CallbackID in_callback_id, - PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) = 0; - virtual void unregister_from_callbacks(CallbackID in_callback_id, - PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) = 0; + virtual bool is_callback_registered (CallbackID in_callback_id, + CallbackFunction in_callback_function, + void* in_callback_function_owner_ptr) const = 0; + virtual void register_for_callbacks (CallbackID in_callback_id, + CallbackFunction in_callback_function, + void* in_callback_function_owner_ptr) = 0; + virtual void unregister_from_callbacks(CallbackID in_callback_id, + CallbackFunction in_callback_function, + void* in_callback_function_owner_ptr) = 0; }; @@ -117,26 +301,24 @@ namespace Anvil /* Tells whether a given callback has already been registered * - * @param in_callback_id ID of the call-back slot. Must not exceed the maximum callback ID - * allowed by the inheriting class. - * @param in_pfn_callback_proc Callback handler. - * @param in_user_arg Optional argument to be passed with the callback. + * @param in_callback_id ID of the call-back slot. Must not exceed the maximum callback ID + * allowed by the inheriting class. + * @param in_callback_function Callback handler. + * @param in_callback_function_owner_ptr Callback owner, as specified at registration time. * * @return true if a callback with user-specified parameters has already been registered, * false otherwise. */ - bool is_callback_registered(CallbackID in_callback_id, - PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) const + bool is_callback_registered(CallbackID in_callback_id, + CallbackFunction in_callback_function, + void* in_callback_function_owner_ptr) const { - Callback callback = Callback(in_pfn_callback_proc, - in_user_arg); - anvil_assert(in_callback_id < m_callback_id_count); return std::find(m_callbacks[in_callback_id].begin(), m_callbacks[in_callback_id].end(), - callback) != m_callbacks[in_callback_id].end(); + Callback(in_callback_function, + in_callback_function_owner_ptr) ) != m_callbacks[in_callback_id].end(); } /** Registers a new call-back client. @@ -144,29 +326,36 @@ namespace Anvil * Note that the function does NOT check if the specified callback func ptr + user argument * has not already been registered. * - * @param in_callback_id ID of the call-back slot the caller intends to sign up to. The - * value must not exceed the maximum callback ID allowed by the - * inheriting class. - * @param in_pfn_callback_proc Call-back handler. Must not be nullptr. - * @param in_user_arg Optional argument to be passed with the call-back. May be nullptr. + * @param in_callback_id ID of the call-back slot the caller intends to sign up to. The + * value must not exceed the maximum callback ID allowed by the + * inheriting class. + * @param in_callback_function Call-back handler. Must not be nullptr. + * @param in_callback_owner_ptr Pointer to the object which is going to own the callback. This + * is required for correct identification of the callback at is_registered() + * or unregister() call time. Must not be null * **/ - void register_for_callbacks(CallbackID in_callback_id, - PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) + void register_for_callbacks(CallbackID in_callback_id, + CallbackFunction in_callback_function, + void* in_callback_owner_ptr) { - Callback new_callback = Callback(in_pfn_callback_proc, - in_user_arg); - - anvil_assert(in_callback_id < m_callback_id_count); - anvil_assert(in_pfn_callback_proc != nullptr); + anvil_assert(in_callback_id < m_callback_id_count); + anvil_assert(in_callback_function != nullptr); + anvil_assert(in_callback_owner_ptr != nullptr); anvil_assert(!m_callbacks_locked); - anvil_assert(std::find(m_callbacks[in_callback_id].begin(), - m_callbacks[in_callback_id].end(), - new_callback) == m_callbacks[in_callback_id].end() ); + #ifdef _DEBUG + { + anvil_assert(!is_callback_registered(in_callback_id, + in_callback_function, + in_callback_owner_ptr) ); + } + #endif - m_callbacks[in_callback_id].push_back(new_callback); + m_callbacks[in_callback_id].push_back( + Callback(in_callback_function, + in_callback_owner_ptr) + ); } /** Unregisters the client from the specified call-back slot. @@ -175,39 +364,31 @@ namespace Anvil * a preceding register_for_callbacks() call, or which has already been unregistered. * Doing so will result in an assertion failure. * - * @param in_callback_id ID of the call-back slot the caller wants to sign out from. - * The value must not exceed the maximum callback ID allowed by - * the inheriting class. - * @param in_pfn_callback_proc Call-back handler. Must not be nullptr. - * @param in_user_arg User argument specified for the call-back. + * @param in_callback_id ID of the call-back slot the caller wants to sign out from. + * The value must not exceed the maximum callback ID allowed by + * the inheriting class. + * @param in_callback_function Call-back handler. Must not be nullptr. + * @param in_callback_function_owner_ptr Call-back owner, as specified at registration time. * **/ - void unregister_from_callbacks(CallbackID in_callback_id, - PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) + void unregister_from_callbacks(CallbackID in_callback_id, + CallbackFunction in_callback_function, + void* in_callback_function_owner_ptr) { - bool has_found = false; - anvil_assert(in_callback_id < m_callback_id_count); - anvil_assert(in_pfn_callback_proc != nullptr); + anvil_assert(in_callback_function != nullptr); anvil_assert(!m_callbacks_locked); - for (auto callback_iterator = m_callbacks[in_callback_id].begin(); - callback_iterator != m_callbacks[in_callback_id].end(); - ++callback_iterator) - { - if (callback_iterator->pfn_callback_proc == in_pfn_callback_proc && - callback_iterator->user_arg == in_user_arg) - { - m_callbacks[in_callback_id].erase(callback_iterator); + auto callback_iterator = std::find(m_callbacks[in_callback_id].begin(), + m_callbacks[in_callback_id].end(), + Callback(in_callback_function, + in_callback_function_owner_ptr) ); - has_found = true; - break; - } + anvil_assert(callback_iterator != m_callbacks[in_callback_id].end() ); + if (callback_iterator != m_callbacks[in_callback_id].end() ) + { + m_callbacks[in_callback_id].erase(callback_iterator); } - - anvil_assert (has_found); - ANVIL_REDUNDANT_VARIABLE(has_found); } protected: @@ -221,11 +402,11 @@ namespace Anvil * This implementation assumes that the invoked functions will NOT alter the * callback array. If that is the case, use (slower) callback_safe() instead. * - * @param in_callback_id ID of the call-back slot to use. - * @param in_callback_arg Call-back argument to use. + * @param in_callback_id ID of the call-back slot to use. + * @param in_callback_arg_ptr Call-back argument to use. **/ - void callback(CallbackID in_callback_id, - void* in_callback_arg) + void callback(CallbackID in_callback_id, + CallbackArgument* in_callback_arg_ptr) { anvil_assert(in_callback_id < m_callback_id_count); anvil_assert(!m_callbacks_locked); @@ -236,10 +417,9 @@ namespace Anvil callback_iterator != m_callbacks[in_callback_id].end(); ++callback_iterator) { - const Callback& current_callback = *callback_iterator; + const auto& current_callback = *callback_iterator; - current_callback.pfn_callback_proc(in_callback_arg, - current_callback.user_arg); + current_callback.function(in_callback_arg_ptr); } } m_callbacks_locked = false; @@ -257,19 +437,24 @@ namespace Anvil * * This implementation is NOT MT-safe. * + * This function can potentially take a long time to execute. + * + * * @param in_callback_id ID of the call-back slot to use. * @param in_callback_arg Call-back argument to use. **/ - void callback_safe(CallbackID in_callback_id, - void* in_callback_arg) + void callback_safe(CallbackID in_callback_id, + CallbackArgument* in_callback_arg_ptr) { anvil_assert(in_callback_id < m_callback_id_count); anvil_assert(!m_callbacks_locked); bool another_iteration_needed = true; + bool first_iteration = true; std::vector invoked_callbacks; - while (another_iteration_needed) + while (another_iteration_needed && + m_callbacks[in_callback_id].size() > 0) { const std::vector cached_callbacks = m_callbacks[in_callback_id]; @@ -279,29 +464,26 @@ namespace Anvil n_current_callback < static_cast(cached_callbacks.size() ); ++n_current_callback) { - const Callback& current_callback = cached_callbacks[n_current_callback]; + const auto& current_callback = cached_callbacks[n_current_callback]; - if (std::find(invoked_callbacks.begin(), + if (first_iteration || + std::find(invoked_callbacks.begin(), invoked_callbacks.end(), current_callback) == invoked_callbacks.end() ) { - current_callback.pfn_callback_proc(in_callback_arg, - current_callback.user_arg); + current_callback.function(in_callback_arg_ptr); invoked_callbacks.push_back(current_callback); } - - if (cached_callbacks != m_callbacks[in_callback_id]) - { - another_iteration_needed = true; - break; - } } - if (!another_iteration_needed) + /* Has m_callbacks[in_callback_id] changed as a result of the callback above? */ + if (!(m_callbacks[in_callback_id] == invoked_callbacks) ) { - break; + another_iteration_needed = true; } + + first_iteration = false; } } @@ -320,45 +502,38 @@ namespace Anvil private: /* Private type definitions */ - - /** Describes an individual callback registration */ typedef struct Callback { - PFNCALLBACKPROC pfn_callback_proc; - void* user_arg; + CallbackFunction function; + void* magic; - /* Constructor. Should only be use by STL. **/ - Callback() + explicit Callback(CallbackFunction in_function, + void* in_magic) { - pfn_callback_proc = nullptr; - user_arg = nullptr; + function = in_function; + magic = in_magic; } - /** Constructor. - * - * @param in_pfn_callback_proc Function pointer to the call-back handler. - * @param in_user_arg User argument to use for the call-back. - **/ - Callback(PFNCALLBACKPROC in_pfn_callback_proc, - void* in_user_arg) + bool operator==(const Callback& in_callback) const { - pfn_callback_proc = in_pfn_callback_proc; - user_arg = in_user_arg; - } + const auto& this_target_type = function.target_type(); + const auto& this_target = function.target (); - bool operator==(const Callback& in) const - { - return (in.pfn_callback_proc == pfn_callback_proc && - in.user_arg == user_arg); + const auto& in_target_type = in_callback.function.target_type(); + const auto& in_target = in_callback.function.target (); + + return (this_target_type == in_target_type && + this_target == in_target && + magic == in_callback.magic); } } Callback; typedef std::vector Callbacks; /* Private variables */ - CallbackID m_callback_id_count; - Callbacks* m_callbacks; - bool m_callbacks_locked; + CallbackID m_callback_id_count; + Callbacks* m_callbacks; + volatile bool m_callbacks_locked; }; } /* namespace Anvil */ diff --git a/include/misc/debug.h b/include/misc/debug.h index c2feac71..b8d20002 100644 --- a/include/misc/debug.h +++ b/include/misc/debug.h @@ -24,6 +24,9 @@ #ifndef MISC_DEBUG_H #define MISC_DEBUG_H +#include "misc/types.h" + + #ifdef _DEBUG #define anvil_assert(assertion) \ if (!(assertion)) \ @@ -58,9 +61,9 @@ namespace Anvil * @param in_line Line index * @param in_message Null-terminated text string holding the tokenized condition which failed. **/ - typedef void (*PFNASSERTIONFAILEDCALLBACKPROC)(const char* in_filename, - unsigned int in_line, - const char* in_message); + typedef std::function< void(const char* in_filename, + unsigned int in_line, + const char* in_message)> AssertionFailedCallbackFunction; /** Assertion failure interceptor. * @@ -78,10 +81,10 @@ namespace Anvil /** Modifies the assertion failure handler entry-point, which is going to be used by Anvil in case * an assertion failure occurs. * - * @param in_new_callback_func_ptr New entry-point to use. Must not be nullptr. + * @param in_new_callback_func New entry-point to use. Must not be nullptr. * **/ - void set_assertion_failure_handler(PFNASSERTIONFAILEDCALLBACKPROC in_new_callback_func_ptr); + void set_assertion_failure_handler(AssertionFailedCallbackFunction in_new_callback_func); }; #endif /* MISC_DEBUG_H */ \ No newline at end of file diff --git a/include/misc/dummy_window.h b/include/misc/dummy_window.h index 588bbb8b..763ef396 100644 --- a/include/misc/dummy_window.h +++ b/include/misc/dummy_window.h @@ -35,11 +35,10 @@ namespace Anvil { public: /* Public functions */ - static std::shared_ptr create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + static std::shared_ptr create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + Anvil::PresentCallbackFunction in_present_callback_func); virtual ~DummyWindow() { @@ -69,11 +68,10 @@ namespace Anvil } protected: - DummyWindow(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + DummyWindow(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func); bool init(); }; @@ -82,11 +80,10 @@ namespace Anvil { public: /* Public methods */ - static std::shared_ptr create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + static std::shared_ptr create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func); /** Destructor */ virtual ~DummyWindowWithPNGSnapshots() @@ -112,11 +109,10 @@ namespace Anvil private: /* Private functions */ - DummyWindowWithPNGSnapshots(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + DummyWindowWithPNGSnapshots(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func); /** Grabs contents of the specified swapchain image and returns them in a raw R8G8B8A8_UNORM * format. diff --git a/include/misc/glsl_to_spirv.h b/include/misc/glsl_to_spirv.h index bf31b558..8c10639d 100644 --- a/include/misc/glsl_to_spirv.h +++ b/include/misc/glsl_to_spirv.h @@ -29,6 +29,7 @@ #define MISC_GLSL_TO_SPIRV_H #include "config.h" +#include "misc/callbacks.h" #include "misc/debug.h" #include "misc/types.h" #include @@ -82,10 +83,21 @@ namespace Anvil }; #endif + typedef enum + { + /* Call-back issued right before the conversion starts. + * + * @param callback_arg OnGLSLToSPIRVConversionAboutToBeStartedCallbackArgument instance. + */ + GLSL_SHADER_TO_SPIRV_GENERATOR_CALLBACK_ID_CONVERSION_ABOUT_TO_START, + + GLSL_SHADER_TO_SPIRV_GENERATOR_CALLBACK_ID_COUNT + } GLSLShaderToSPIRVGeneratorCallbackID; + /** Loads a GLSL shader from the file specified at creation time, customizes it with a user-specified set of #defines, * and then converts the source code to a SPIR-V blob. **/ - class GLSLShaderToSPIRVGenerator + class GLSLShaderToSPIRVGenerator : public CallbacksSupportProvider { public: /* Public type definitions */ @@ -107,17 +119,17 @@ namespace Anvil /** Creates a new GLSLShaderToSPIRVGenerator instance. * - * @param in_device_ptr Logical device, whose limit values should be passed to glslang. Must not - * be NULL. - * @param in_mode Defines type of contents specified under @param in_data. - * @param in_data If @param in_mode is MODE_LOAD_SOURCE_FROM_FILE, @param in_data holds the name - * of the file (possibly including path) where the GLSL source code is stored. - * If @param in_mode is MODE_USE_SPECIFIED_SOURCE, @param in_data holds GLSL source code - * which should be used. This mode is NOT supported if ANVIL_LINK_WITH_GLSLANG - * macro is undefined. - * @param in_shader_stage Shader stage described by the file. + * @param in_opt_device_ptr Logical device, whose limit values should be passed to glslang. May be null + * if the object is only intended to be used for forming GLSL source code. + * @param in_mode Defines type of contents specified under @param in_data. + * @param in_data If @param in_mode is MODE_LOAD_SOURCE_FROM_FILE, @param in_data holds the name + * of the file (possibly including path) where the GLSL source code is stored. + * If @param in_mode is MODE_USE_SPECIFIED_SOURCE, @param in_data holds GLSL source code + * which should be used. This mode is NOT supported if ANVIL_LINK_WITH_GLSLANG + * macro is undefined. + * @param in_shader_stage Shader stage described by the file. **/ - static std::shared_ptr create(std::weak_ptr in_device_ptr, + static std::shared_ptr create(std::weak_ptr in_opt_device_ptr, const Mode& in_mode, std::string in_data, ShaderStage in_shader_stage); @@ -240,11 +252,16 @@ namespace Anvil * Otherwise, an assertion failure will occur, as the returned string will have a size of 0. * */ - const std::string& get_glsl_source_code() const + const std::string& get_glsl_source_code() { - anvil_assert(m_final_glsl_source_code.size() != 0); + if (m_glsl_source_code_dirty) + { + bake_glsl_source_code(); - return m_final_glsl_source_code; + anvil_assert(!m_glsl_source_code_dirty); + } + + return m_glsl_source_code; } /** Tells what shader stage the encapsulated GLSL shader descirbes. */ @@ -309,6 +326,8 @@ namespace Anvil std::string in_data, ShaderStage in_shader_stage); + bool bake_glsl_source_code(); + #ifdef ANVIL_LINK_WITH_GLSLANG bool bake_spirv_blob_by_calling_glslang(const char* in_body); EShLanguage get_glslang_shader_stage () const; @@ -319,15 +338,17 @@ namespace Anvil /* Private members */ #ifdef ANVIL_LINK_WITH_GLSLANG - GLSLangLimits m_limits; - std::string m_program_info_log; - std::string m_shader_info_log; + std::unique_ptr m_limits_ptr; + std::string m_program_info_log; + std::string m_shader_info_log; #endif std::string m_data; Mode m_mode; - std::string m_final_glsl_source_code; + std::string m_glsl_source_code; + bool m_glsl_source_code_dirty; + ShaderStage m_shader_stage; std::vector m_spirv_blob; diff --git a/include/misc/memalloc_backends/backend_vma.h b/include/misc/memalloc_backends/backend_vma.h index 8d2ea537..3a7f0435 100644 --- a/include/misc/memalloc_backends/backend_vma.h +++ b/include/misc/memalloc_backends/backend_vma.h @@ -95,11 +95,8 @@ namespace Anvil * * @param in_memory_block_ptr Raw pointer to the memory block which is about to be destroyed. * Must NOT be null. Must be valid at call time. - * @param in_user_arg Pointer to VMAAllocator instance owning the allocation. Must NOT - * be null. Must be valid at call time. */ - static void on_vma_alloced_mem_block_gone_out_of_scope(Anvil::MemoryBlock* in_memory_block_ptr, - void* in_user_arg); + void on_vma_alloced_mem_block_gone_out_of_scope(Anvil::MemoryBlock* in_memory_block_ptr); private: /* Private functions */ diff --git a/include/misc/memory_allocator.h b/include/misc/memory_allocator.h index bcacc2b7..461985b4 100644 --- a/include/misc/memory_allocator.h +++ b/include/misc/memory_allocator.h @@ -37,8 +37,7 @@ namespace Anvil { - typedef void (*PFNMEMORYALLOCATORBAKECALLBACKPROC)(Anvil::MemoryAllocator* in_memory_allocator_ptr, - void* in_user_arg); + typedef std::function MemoryAllocatorBakeCallbackFunction; /** Implements a simple memory allocator. For more details, please see the header. */ class MemoryAllocator : public std::enable_shared_from_this @@ -277,12 +276,10 @@ namespace Anvil * Calling this function more than once for the same MemoryAllocator instance will trigger * an assertion failure. * - * @param in_pfn_post_bake_callback_ptr Function pointer to assign. Must not be null. - * @param in_callback_user_arg User argument to pass with the callback. Can be null. + * @param in_post_bake_callback_function Function pointer to assign. Must not be null. * */ - void set_post_bake_callback(PFNMEMORYALLOCATORBAKECALLBACKPROC in_pfn_post_bake_callback, - void* in_callback_user_arg); + void set_post_bake_callback(MemoryAllocatorBakeCallbackFunction in_post_bake_callback_function); /** Destructor. * @@ -299,12 +296,9 @@ namespace Anvil Anvil::MemoryFeatureFlags in_memory_features, uint32_t* out_opt_filtered_memory_types_ptr) const; - static void on_is_alloc_pending_for_buffer_query(void* in_callback_arg, - void* in_user_arg); - static void on_is_alloc_pending_for_image_query (void* in_callback_arg, - void* in_user_arg); - static void on_implicit_bake_needed (void* in_callback_arg, - void* in_user_arg); + void on_is_alloc_pending_for_buffer_query(CallbackArgument* in_callback_arg_ptr); + void on_is_alloc_pending_for_image_query (CallbackArgument* in_callback_arg_ptr); + void on_implicit_bake_needed (); /** Constructor. * @@ -321,8 +315,7 @@ namespace Anvil Items m_items; std::map m_per_object_pending_alloc_status; - PFNMEMORYALLOCATORBAKECALLBACKPROC m_pfn_post_bake_callback_ptr; - void* m_post_bake_callback_user_arg; + MemoryAllocatorBakeCallbackFunction m_post_bake_callback_function; }; }; diff --git a/include/misc/object_tracker.h b/include/misc/object_tracker.h index 772465c4..0202c223 100644 --- a/include/misc/object_tracker.h +++ b/include/misc/object_tracker.h @@ -32,7 +32,7 @@ * ObjectTracker::check_for_leaks() to determine, if there are any wrapper objects alive. If so, * brief info on each such instance will be printed out to stdout. * - * Object Tracker is not thread-safe at the moment. + * Object Tracker is thread-safe. **/ #ifndef MISC_OBJECT_TRACKER_H #define MISC_OBJECT_TRACKER_H @@ -47,10 +47,11 @@ namespace Anvil { /* Callback issued when a new Anvil object is instantiated * - * @param callback_arg ObjectTrackerOnObjectRegisteredCallbackArg structure instance + * @param callback_arg OnObjectRegisteredCallbackArgument structure instance **/ OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, + /* Callback issued when an existing Anvil object instance is about to go out of scope. * * This callback IS issued BEFORE a corresponding Vulkan handle is destroyed. @@ -58,36 +59,24 @@ namespace Anvil * This callback MAY be issued FROM WITHIN the object's destructor, implying all WEAK POINTERS pointing * to the wrapper instance will have been expired at the time of the callback. * - * @param callback_arg ObjectTrackerOnObjectAboutToBeUnregisteredCallbackArg structure instance + * @param callback_arg OnObjectAboutToBeUnregisteredCallbackArgument structure instance **/ OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, - OBJECT_TRACKER_CALLBACK_ID_COUNT, - } ObjectTrackerCallbackID; - - typedef struct ObjectTrackerOnObjectRegisteredCallbackArg - { - void* object_raw_ptr; - ObjectType object_type; - - ObjectTrackerOnObjectRegisteredCallbackArg() - { - object_raw_ptr = nullptr; - object_type = OBJECT_TYPE_UNKNOWN; - } - - ObjectTrackerOnObjectRegisteredCallbackArg(const ObjectType& in_object_type, - void* in_object_raw_ptr) - { - anvil_assert(in_object_raw_ptr != nullptr); - - object_raw_ptr = in_object_raw_ptr; - object_type = in_object_type; - } - } ObjectTrackerOnObjectRegisteredCallbackArg; + /* Specialized case of OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED. + * + * Uses the same callback argument. + */ + OBJECT_TRACKER_CALLBACK_ID_ON_DEVICE_OBJECT_ABOUT_TO_BE_UNREGISTERED, - typedef ObjectTrackerOnObjectRegisteredCallbackArg ObjectTrackerOnObjectAboutToBeUnregisteredCallbackArg; + /* Specialized case of OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED. + * + * Uses the same callback argument. + */ + OBJECT_TRACKER_CALLBACK_ID_ON_PIPELINE_LAYOUT_OBJECT_ABOUT_TO_BE_UNREGISTERED, + OBJECT_TRACKER_CALLBACK_ID_COUNT, + } ObjectTrackerCallbackID; class ObjectTracker : public CallbacksSupportProvider { @@ -111,8 +100,8 @@ namespace Anvil void check_for_leaks() const; /** Retrieves an alive object of user-specified type at given index. */ - const void* get_object_at_index(ObjectType in_object_type, - uint32_t in_alloc_index) const; + void* get_object_at_index(ObjectType in_object_type, + uint32_t in_alloc_index) const; /** Registers a new object of the specified type. * @@ -140,8 +129,8 @@ namespace Anvil typedef struct ObjectAllocation { - uint32_t n_allocation; - const void* object_ptr; + uint32_t n_allocation; + void* object_ptr; /** Dummy constructor. Should only be used by STL */ ObjectAllocation() @@ -155,8 +144,8 @@ namespace Anvil * @param in_n_allocation Index of the memory allocation. * @param in_object_ptr Pointer to the object. */ - ObjectAllocation(uint32_t in_n_allocation, - const void* in_object_ptr) + ObjectAllocation(uint32_t in_n_allocation, + void* in_object_ptr) { n_allocation = in_n_allocation; object_ptr = in_object_ptr; @@ -179,8 +168,9 @@ namespace Anvil const char* get_object_type_name(ObjectType in_object_type) const; /* Private members */ - ObjectAllocations m_object_allocations [OBJECT_TYPE_COUNT]; - uint32_t m_n_objects_allocated_array[OBJECT_TYPE_COUNT]; + mutable std::mutex m_cs; + ObjectAllocations m_object_allocations [OBJECT_TYPE_COUNT]; + uint32_t m_n_objects_allocated_array[OBJECT_TYPE_COUNT]; }; }; /* namespace Anvil */ diff --git a/include/misc/shader_module_cache.h b/include/misc/shader_module_cache.h index 53fa30b6..6ec82d08 100644 --- a/include/misc/shader_module_cache.h +++ b/include/misc/shader_module_cache.h @@ -136,7 +136,8 @@ namespace Anvil ShaderModuleCache(); - void cache(std::shared_ptr in_shader_module_ptr); + void cache (std::shared_ptr in_shader_module_ptr); + void update_subscriptions(bool in_should_init); size_t get_hash(const char* in_spirv_blob, uint32_t in_n_spirv_blob_bytes, @@ -147,10 +148,8 @@ namespace Anvil const std::string& in_te_entrypoint_name, const std::string& in_vs_entrypoint_name) const; - static void on_object_about_to_be_released(void* in_callback_arg, - void* in_shader_module_cache_raw_ptr); - static void on_object_registered (void* in_callback_arg, - void* in_shader_module_cache_raw_ptr); + void on_object_about_to_be_released(CallbackArgument* in_callback_arg_ptr); + void on_object_registered (CallbackArgument* in_callback_arg_ptr); /* Private variables */ std::mutex m_cs; diff --git a/include/misc/types.h b/include/misc/types.h index 64cf8111..d4ec02c8 100644 --- a/include/misc/types.h +++ b/include/misc/types.h @@ -22,13 +22,15 @@ #ifndef MISC_TYPES_H #define MISC_TYPES_H +#include +#include #include #include #include #include #include "config.h" - +#include "misc/debug.h" /* Disable some of the warnings we cannot work around because they are caused * by external dependencies (ie. Vulkan header) @@ -523,10 +525,10 @@ namespace Anvil class BaseDevice; class Buffer; class BufferView; + struct CallbackArgument; class CommandBufferBase; class CommandPool; class ComputePipelineManager; - class DAGRenderer; class DescriptorPool; class DescriptorSet; class DescriptorSetGroup; @@ -534,6 +536,7 @@ namespace Anvil class Event; class Fence; class Framebuffer; + class GLSLShaderToSPIRVGenerator; class GraphicsPipelineManager; class Image; class ImageView; @@ -1560,7 +1563,7 @@ namespace Anvil OBJECT_TYPE_SHADER_MODULE, OBJECT_TYPE_SWAPCHAIN, - /* For DOT serialization, we also need a handful of fake object types. */ + OBJECT_TYPE_GLSL_SHADER_TO_SPIRV_GENERATOR, OBJECT_TYPE_GRAPHICS_PIPELINE, /* Always last */ @@ -1905,8 +1908,12 @@ namespace Anvil uint32_t* out_opt_n_queue_family_indices_ptr); /** Returns an access mask which has all the access bits, relevant to the user-specified image layout, - * enabled. */ - VkAccessFlags get_access_mask_from_image_layout(VkImageLayout in_layout); + * enabled. + * + * The access mask can be further restricted to the specified queue family type. + */ + VkAccessFlags get_access_mask_from_image_layout(VkImageLayout in_layout, + Anvil::QueueFamilyType in_queue_family_type = Anvil::QUEUE_FAMILY_TYPE_UNDEFINED); /** Converts a pair of VkMemoryPropertyFlags and VkMemoryHeapFlags bitfields to a corresponding Anvil::MemoryFeatureFlags * enum. @@ -2055,6 +2062,22 @@ namespace Anvil */ const char* get_raw_string(VkSampleCountFlagBits in_sample_count); + /** Converts the specified Anvil::ShaderStage value to a raw string + * + * @param in_shader_stage Input value. + * + * @return Non-NULL value if successful, NULL otherwise. + */ + const char* get_raw_string(Anvil::ShaderStage in_shader_stage); + + /** Converts the specified VkShaderStageFlagBits value to a raw string + * + * @param in_shader_stage Input value. + * + * @return Non-NULL value if successful, NULL otherwise. + */ + const char* get_raw_string(VkShaderStageFlagBits in_shader_stage); + /** Converts the specified VkSharingMode value to a raw string * * @param in_sharing_mode Input value. @@ -2071,6 +2094,9 @@ namespace Anvil */ const char* get_raw_string(VkStencilOp in_stencil_op); + /* Returns Vulkan equivalent of @param in_shader_stage */ + VkShaderStageFlagBits get_shader_stage_flag_bits_from_shader_stage(Anvil::ShaderStage in_shader_stage); + /** Converts an Anvil::MemoryFeatureFlags value to a pair of corresponding Vulkan enum values. * * @param in_mem_feature_flags Anvil memory feature flags to use for conversion. diff --git a/include/misc/window.h b/include/misc/window.h index d2601a40..f2d877f0 100644 --- a/include/misc/window.h +++ b/include/misc/window.h @@ -36,40 +36,20 @@ namespace Anvil { /** Prototype of a function, which renders frame contents & presents it */ - typedef void (*PFNPRESENTCALLBACKPROC)(void* in_user_arg); - - /* Structure passed as a WINDOW_CALLBACK_ID_KEYPRESS_RELEASED call-back argument */ - typedef struct KeypressReleasedCallbackData - { - KeyID released_key_id; - Window* window_ptr; - - /** Constructor. - * - * @param in_command_buffer_ptr Command buffer instance the command is being recorded for. - * @param in_command_details_ptr Structure holding all arguments to be passed to the vkCmdBeginRenderPass() call. - **/ - explicit KeypressReleasedCallbackData(Window* in_window_ptr, - KeyID in_released_key_id) - :released_key_id(in_released_key_id), - window_ptr (in_window_ptr) - { - /* Stub */ - } - } KeypressReleasedCallbackData; + typedef std::function PresentCallbackFunction;; /* Enumerates available window call-back types.*/ enum WindowCallbackID { /* Call-back issued right before OS is requested to close the window. * - * callback_arg: pointer to the Window instance + * callback_arg: Pointer to OnWindowAboutToCloseCallbackArgument instance. */ WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, /* Call-back issued when the user releases a pressed key. * - * callback_arg: pointer to a KeypressReleasedCallbackData instance. + * callback_arg: pointer to a OnKeypressReleasedCallbackArgument instance. **/ WINDOW_CALLBACK_ID_KEYPRESS_RELEASED, @@ -128,20 +108,21 @@ namespace Anvil * A window instance should be created in the same thread, from which the run() function * is going to be invoked. * - * @param in_title Name to use for the window's title bar. - * @param in_width Window's width. Note that this value should not exceed screen's width. - * @param in_height Window's height. Note that this value should not exceed screen's height. - * @param in_present_callback_func_ptr Call-back to use in order to render & present the updated frame contents. - * Must not be nullptr. - * @param in_present_callback_func_user_arg Argument to pass to the @param in_present_callback_func_ptr call-back. May - * be nullptr. + * @param in_title Name to use for the window's title bar. + * @param in_width Window's width. Note that this value should not exceed screen's width. + * @param in_height Window's height. Note that this value should not exceed screen's height. + * @param in_closable Tells if the user should be able to close the button. Depending on the OS, + * this may translate to greyed out close button or close button clicks simply + * being ignored. + * @param in_present_callback_func Call-back to use in order to render & present the updated frame contents. + * Must not be nullptr. * **/ - Window(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + Window(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + PresentCallbackFunction in_present_callback_func); /** Closes the window and unblocks the thread executing the message pump. */ virtual void close() { /* Stub */ } @@ -199,18 +180,18 @@ namespace Anvil protected: /* protected variables */ - PFNPRESENTCALLBACKPROC m_present_callback_func_ptr; - void* m_present_callback_func_user_arg; + PresentCallbackFunction m_present_callback_func; - unsigned int m_height; - std::string m_title; - unsigned int m_width; - bool m_window_should_close; - bool m_window_close_finished; + bool m_closable; + unsigned int m_height; + std::string m_title; + unsigned int m_width; + volatile bool m_window_should_close; + volatile bool m_window_close_finished; /* Window handle */ - WindowHandle m_window; - bool m_window_owned; + WindowHandle m_window; + bool m_window_owned; /* protected functions */ virtual ~Window(); @@ -223,4 +204,4 @@ namespace Anvil }; }; /* namespace Anvil */ -#endif /* MISC_WINDOW_H */ \ No newline at end of file +#endif /* MISC_WINDOW_H */ diff --git a/include/misc/window_factory.h b/include/misc/window_factory.h index 78553725..0c858b95 100644 --- a/include/misc/window_factory.h +++ b/include/misc/window_factory.h @@ -48,22 +48,23 @@ namespace Anvil /* Creates a Window wrapper instance by opening a new system window. * - * @param in_platform Window platform to use. See WindowPlatform documentation - * for more details. - * @param in_title Title to use for the new window. - * @param in_width Width of the new window. - * @param in_height Height of the new window. - * @param in_present_callback_func_ptr Callback function to use for rendering frame contents. - * @param in_present_callback_func_user_arg User argument to pass with the callback function invocation. + * @param in_platform Window platform to use. See WindowPlatform documentation + * for more details. + * @param in_title Title to use for the new window. + * @param in_width Width of the new window. + * @param in_height Height of the new window. + * @param in_closable Should the "close button" of the window be accesible to the user? Depending on the OS, + * this may translate to the button being greyed out or not reacting to the user's requests. + * @param in_present_callback_func Callback function to use for rendering frame contents. * * @return A new Window wrapper instance if successful, null otherwise. **/ - static std::shared_ptr create_window(WindowPlatform in_platform, - const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + static std::shared_ptr create_window(WindowPlatform in_platform, + const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func); /* Creates a Window wrapper instance using app-managed window handle. * diff --git a/include/misc/window_win3264.h b/include/misc/window_win3264.h index 7b11a845..d161e360 100644 --- a/include/misc/window_win3264.h +++ b/include/misc/window_win3264.h @@ -40,21 +40,21 @@ namespace Anvil * * NOTE: This function resets that last system error assigned to the calling thread. * - * @param in_title Title to use for the window. - * @param in_width New window's width. Must not be 0. - * @param in_height New window's height. Must not be 0. - * @param in_present_callback_func_ptr Func pointer to a function which is going to render frame contents to - * the swapchain image. Must not be null. - * @param in_present_callback_func_user_arg User-specific argument to be passed with @param in_present_callback_func_ptr - * invocation. May be null. + * @param in_title Title to use for the window. + * @param in_width New window's width. Must not be 0. + * @param in_height New window's height. Must not be 0. + * @param in_closable Determines if window's close button should be greyed out, prohibiting + * the user from being able to destroy the window on their own. + * @param in_present_callback_func Func pointer to a function which is going to render frame contents to + * the swapchain image. Must not be null. * * @return New Anvil::Window instance if successful, or null otherwise. */ - static std::shared_ptr create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + static std::shared_ptr create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func); /* Creates a window wrapper instance from an existing window handle. * @@ -98,17 +98,16 @@ namespace Anvil private: /* Private functions */ - WindowWin3264(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); - WindowWin3264(HWND in_handle, - const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + WindowWin3264(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func); + WindowWin3264(HWND in_handle, + const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func); /** Creates a new system window and prepares it for usage. */ bool init(); diff --git a/include/misc/window_xcb.h b/include/misc/window_xcb.h index 307d0df6..019af2f6 100644 --- a/include/misc/window_xcb.h +++ b/include/misc/window_xcb.h @@ -35,11 +35,11 @@ namespace Anvil { public: /* Public functions */ - static std::shared_ptr create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); + static std::shared_ptr create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func); static std::shared_ptr create(xcb_connection_t* in_connection_ptr, WindowHandle in_window_handle); @@ -68,13 +68,13 @@ namespace Anvil } private: - WindowXcb(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg); - WindowXcb(xcb_connection_t* in_connection_ptr, - WindowHandle in_window_handle); + WindowXcb(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func); + WindowXcb(xcb_connection_t* in_connection_ptr, + WindowHandle in_window_handle); /** Creates a new system window and prepares it for usage. */ bool init(); diff --git a/include/wrappers/buffer.h b/include/wrappers/buffer.h index bf79719d..aa8c316b 100644 --- a/include/wrappers/buffer.h +++ b/include/wrappers/buffer.h @@ -40,21 +40,6 @@ namespace Anvil { - typedef struct BufferCallbackIsAllocPendingQueryData - { - explicit BufferCallbackIsAllocPendingQueryData(std::shared_ptr in_buffer_ptr) - :buffer_ptr(in_buffer_ptr), - result (false) - { - /* Stub */ - } - - BufferCallbackIsAllocPendingQueryData& operator=(const BufferCallbackIsAllocPendingQueryData&) = delete; - - const std::shared_ptr buffer_ptr; - bool result; - } BufferCallbackIsAllocPendingQueryData; - /* Enumerates available buffer call-back types.*/ enum BufferCallbackID { @@ -67,7 +52,7 @@ namespace Anvil * This call-back is needed for memory allocator to support implicit bake operations * for sparse images. * - * callback_arg: BufferCallbackIsAllocPendingQueryData* + * callback_arg: Pointer to IsBufferMemoryAllocPendingQueryCallbackArgument instance. **/ BUFFER_CALLBACK_ID_IS_ALLOC_PENDING, @@ -76,7 +61,7 @@ namespace Anvil * * This call-back is needed by memory allocator in order to support implicit bake operations. * - * callback_arg: Calling back buffer instance; + * callback_arg: Pointer to OnMemoryBlockNeededForBufferCallbackArgument instance. **/ BUFFER_CALLBACK_ID_MEMORY_BLOCK_NEEDED, diff --git a/include/wrappers/command_buffer.h b/include/wrappers/command_buffer.h index ce1a78ff..cde8a545 100644 --- a/include/wrappers/command_buffer.h +++ b/include/wrappers/command_buffer.h @@ -37,6 +37,7 @@ #include "misc/callbacks.h" #include "misc/debug_marker.h" +#include "misc/io.h" #include "misc/types.h" #ifdef _DEBUG @@ -288,26 +289,6 @@ namespace Anvil } } PipelineBarrierCommand; - /* Structure passed as a COMMAND_BUFFER_CALLBACK_ID_PIPELINE_BARRIER_COMMAND_RECORDED call-back argument */ - typedef struct PipelineBarrierCommandRecordedCallbackData - { - CommandBufferBase* command_buffer_ptr; - const PipelineBarrierCommand* command_details_ptr; - - /** Constructor. - * - * @param in_command_buffer_ptr Command buffer instance the command is being recorded for. - * @param in_command_details_ptr Structure holding all arguments to be passed to the vkCmdPipelineBarrier() call. - **/ - explicit PipelineBarrierCommandRecordedCallbackData(CommandBufferBase* in_command_buffer_ptr, - const PipelineBarrierCommand* in_command_details_ptr) - :command_buffer_ptr (in_command_buffer_ptr), - command_details_ptr(in_command_details_ptr) - { - /* Stub */ - } - } PipelineBarrierCommandRecordedCallbackData; - /** Implements base functionality of a command buffer object, such as common command registration * support or validation. Also encapsulates command wrapper structure declarations. * diff --git a/include/wrappers/descriptor_pool.h b/include/wrappers/descriptor_pool.h index 3fe073fb..7098034c 100644 --- a/include/wrappers/descriptor_pool.h +++ b/include/wrappers/descriptor_pool.h @@ -39,7 +39,7 @@ namespace Anvil { /* Notification sent out whenever pool is reset. * - * Callback arg: originating DescriptorPool instance + * Callback arg: Pointer to OnDescriptorPoolResetCallbackArgument instance. */ DESCRIPTOR_POOL_CALLBACK_ID_POOL_RESET, diff --git a/include/wrappers/descriptor_set.h b/include/wrappers/descriptor_set.h index 166f6d38..7ade5c53 100644 --- a/include/wrappers/descriptor_set.h +++ b/include/wrappers/descriptor_set.h @@ -880,10 +880,8 @@ namespace Anvil DescriptorSet (const DescriptorSet&); DescriptorSet& operator=(const DescriptorSet&); - static void on_binding_added_to_layout(void* in_layout_raw_ptr, - void* in_ds_raw_ptr); - static void on_parent_pool_reset (void* in_pool_raw_ptr, - void* in_ds_raw_ptr); + void on_binding_added_to_layout(); + void on_parent_pool_reset (); void alloc_bindings(); diff --git a/include/wrappers/descriptor_set_layout.h b/include/wrappers/descriptor_set_layout.h index ac98707a..a90e37b1 100644 --- a/include/wrappers/descriptor_set_layout.h +++ b/include/wrappers/descriptor_set_layout.h @@ -42,7 +42,7 @@ namespace Anvil { /* Notification fired whenever a new binding is added to the layout. * - * callback argument: pointer to the originating DescriptorSetLayout instance + * callback argument: pointer to OnNewBindingAddedToDescriptorSetLayoutCallbackArgument instance. **/ DESCRIPTOR_SET_LAYOUT_CALLBACK_ID_BINDING_ADDED, diff --git a/include/wrappers/device.h b/include/wrappers/device.h index 36d119b4..08bbca1a 100644 --- a/include/wrappers/device.h +++ b/include/wrappers/device.h @@ -296,6 +296,13 @@ namespace Anvil VkImageTiling in_tiling, std::vector& out_result) const = 0; + + /** Returns surface capabilities, as reported for physical device(s) which have been used to instantiate + * this logical device instance. + **/ + virtual bool get_physical_device_surface_capabilities(std::shared_ptr in_surface_ptr, + VkSurfaceCapabilitiesKHR* out_result_ptr) const = 0; + /** Returns a pipeline cache, created specifically for this device. * * @return As per description @@ -717,6 +724,10 @@ namespace Anvil VkImageTiling in_tiling, std::vector& out_result) const override; + /** See documentation in BaseDevice for more details */ + bool get_physical_device_surface_capabilities(std::shared_ptr in_surface_ptr, + VkSurfaceCapabilitiesKHR* out_result_ptr) const override; + /** See documentation in BaseDevice for more details */ const Anvil::QueueFamilyInfo* get_queue_family_info(uint32_t in_queue_family_index) const override; diff --git a/include/wrappers/framebuffer.h b/include/wrappers/framebuffer.h index 9725b9d9..f3c6e032 100644 --- a/include/wrappers/framebuffer.h +++ b/include/wrappers/framebuffer.h @@ -191,8 +191,7 @@ namespace Anvil Framebuffer& operator=(const Framebuffer&); Framebuffer (const Framebuffer&); - static void on_renderpass_changed(void* in_raw_renderpass_ptr, - void* in_raw_framebuffer_ptr); + void on_renderpass_changed(Anvil::CallbackArgument* in_callback_argument_ptr); /* Private members */ FramebufferAttachments m_attachments; diff --git a/include/wrappers/graphics_pipeline_manager.h b/include/wrappers/graphics_pipeline_manager.h index 83a61e15..62f14cc2 100644 --- a/include/wrappers/graphics_pipeline_manager.h +++ b/include/wrappers/graphics_pipeline_manager.h @@ -97,9 +97,8 @@ namespace Anvil typedef uint32_t DynamicStateBitfield; /* Prototype for a call-back function, invoked right after vkCreateGraphicsPipelines() call returns. **/ - typedef void (*PFNPIPELINEPOSTBAKECALLBACKPROC)(std::weak_ptr in_device_ptr, - GraphicsPipelineID in_pipeline_id, - void* in_user_arg); + typedef std::function in_device_ptr, + GraphicsPipelineID in_pipeline_id)> PipelinePostBakeFunction; /* Prototype for a call-back function, invoked before a Vulkan graphics pipeline is created. * @@ -107,10 +106,9 @@ namespace Anvil * Anvil::GraphicsPipelineManager will not adjust its internal state to sync with user-modified * fields. **/ - typedef void (*PFNPIPELINEPREBAKECALLBACKPROC)(std::weak_ptr in_device_ptr, - GraphicsPipelineID in_pipeline_id, - VkGraphicsPipelineCreateInfo* in_graphics_pipeline_create_info_ptr, - void* in_user_arg); + typedef std::function in_device_ptr, + GraphicsPipelineID in_pipeline_id, + VkGraphicsPipelineCreateInfo* in_graphics_pipeline_create_info_ptr)> PipelinePreBakeFunction; /* Public functions */ @@ -863,15 +861,13 @@ namespace Anvil * * This call overwrites any previous set_pipeline_post_bake_callback() calls. * - * @param in_graphics_pipeline_id ID of the graphics pipeline to set the call-back for. - * @param in_pfn_pipeline_pre_bake_proc Function to call back. Must not be nullptr. - * @param in_user_arg User argument to pass with the call-back. May be nullptr. + * @param in_graphics_pipeline_id ID of the graphics pipeline to set the call-back for. + * @param in_pipeline_post_bake_function Function to call back. Must not be nullptr. * * @return true if successful, false otherwise. **/ - bool set_pipeline_post_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, - PFNPIPELINEPOSTBAKECALLBACKPROC in_pfn_pipeline_post_bake_proc, - void* in_user_arg); + bool set_pipeline_post_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, + PipelinePostBakeFunction in_pipeline_post_bake_function); /** Sets a call-back, which GFX pipeline manager will invoke right before a vkCreateGraphicsPipeline() call is made. * This allows the callee to adjust the VkGraphicsPipelineCreateInfo instance, eg. by modifying pNext to user-defined @@ -887,9 +883,8 @@ namespace Anvil * * @return true if successful, false otherwise. **/ - bool set_pipeline_pre_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, - PFNPIPELINEPREBAKECALLBACKPROC in_pfn_pipeline_pre_bake_proc, - void* in_user_arg); + bool set_pipeline_pre_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, + PipelinePreBakeFunction in_pfn_pipeline_pre_bake_function); /** Copies graphics state from @param in_source_pipeline_id to @param in_target_pipeline_id, leaving * the originally assigned renderpass, as well as the subpass ID, unaffected. @@ -1478,10 +1473,8 @@ namespace Anvil VkCullModeFlagsVariable (cull_mode); VkSampleCountFlagsVariable(sample_count); - PFNPIPELINEPOSTBAKECALLBACKPROC pfn_pipeline_postbake_callback_proc; - PFNPIPELINEPREBAKECALLBACKPROC pfn_pipeline_prebake_callback_proc; - void* pipeline_postbake_callback_user_arg; - void* pipeline_prebake_callback_user_arg; + PipelinePostBakeFunction post_bake_function; + PipelinePreBakeFunction pre_bake_function; std::shared_ptr renderpass_ptr; SubPassID subpass_id; @@ -1523,11 +1516,6 @@ namespace Anvil sample_shading_enabled = false; stencil_test_enabled = false; - pfn_pipeline_postbake_callback_proc = nullptr; - pfn_pipeline_prebake_callback_proc = nullptr; - pipeline_postbake_callback_user_arg = nullptr; - pipeline_prebake_callback_user_arg = nullptr; - renderpass_ptr = in_renderpass_ptr; subpass_id = in_subpass_id; @@ -1637,10 +1625,8 @@ namespace Anvil subpass_attachment_blending_properties = in.subpass_attachment_blending_properties; viewports = in.viewports; - pfn_pipeline_postbake_callback_proc = in.pfn_pipeline_postbake_callback_proc; - pfn_pipeline_prebake_callback_proc = in.pfn_pipeline_prebake_callback_proc; - pipeline_postbake_callback_user_arg = in.pipeline_postbake_callback_user_arg; - pipeline_prebake_callback_user_arg = in.pipeline_prebake_callback_user_arg; + post_bake_function = in.post_bake_function; + pre_bake_function = in.pre_bake_function; memcpy(blend_constant, in.blend_constant, diff --git a/include/wrappers/image.h b/include/wrappers/image.h index 72247dcd..11489911 100644 --- a/include/wrappers/image.h +++ b/include/wrappers/image.h @@ -36,21 +36,6 @@ namespace Anvil { - typedef struct ImageCallbackIsAllocPendingQueryData - { - explicit ImageCallbackIsAllocPendingQueryData(std::shared_ptr in_image_ptr) - :image_ptr(in_image_ptr), - result (false) - { - /* Stub */ - } - - ImageCallbackIsAllocPendingQueryData& operator=(const ImageCallbackIsAllocPendingQueryData&) = delete; - - const std::shared_ptr image_ptr; - bool result; - } ImageCallbackIsAllocPendingQueryData; - /* Enumerates available image call-back types. */ enum ImageCallbackID { @@ -63,7 +48,7 @@ namespace Anvil * This call-back is needed for memory allocator to support implicit bake operations * for sparse images. * - * callback_arg: ImageCallbackIsAllocPendingQueryData* + * callback_arg: Pointer to IsImageMemoryAllocPendingQueryCallbackArgument instance. **/ IMAGE_CALLBACK_ID_IS_ALLOC_PENDING, @@ -72,7 +57,7 @@ namespace Anvil * * This call-back is needed for memory allocator to support implicit bake operations. * - * callback_arg: Calling back image instance; + * callback_arg: Pointer to OnMemoryBlockNeededForImageCallbackArgument instance. **/ IMAGE_CALLBACK_ID_MEMORY_BLOCK_NEEDED, @@ -92,21 +77,34 @@ namespace Anvil * * This is a blocking call. * - * @param in_queue_ptr Queue to use for the transition. The specified queue must support pipeline barrier - * command. Must not be null. - * @param in_src_access_mask Source access mask to use for the transition. - * @param in_src_layout Image layout to transfer from. - * @param in_dst_access_mask Destination access mask to use for the transition. - * @param in_dst_layout Image layout to transfer to. - * @param in_subresource_range Subresource range to use for the transfer operation. - * + * @param in_queue_ptr Queue to use for the transition. The specified queue must support pipeline barrier + * command. Must not be null. + * @param in_src_access_mask Source access mask to use for the transition. + * @param in_src_layout Image layout to transfer from. + * @param in_dst_access_mask Destination access mask to use for the transition. + * @param in_dst_layout Image layout to transfer to. + * @param in_subresource_range Subresource range to use for the transfer operation. + * @param in_opt_n_wait_semaphores Number of wait semaphores specified at @param in_opt_wait_semaphore_ptrs. + * May be 0. + * @param in_opt_wait_dst_stage_mask_ptrs A raw array of wait destination stage masks, to be used at submission time. May be null if + * @param in_opt_n_wait_semaphores is 0. + * @param in_opt_wait_semaphore_ptrs A raw array of semaphores to wait on before proceeding with submission of a cmd buffer + * which changes the layout of the image. May be null if @param in_opt_n_wait_semaphores is 0. + * @param in_opt_n_set_semaphores Number of set semaphores specified at @param in_opt_set_semaphore_ptrs. May be 0. + * @param in_opt_set_semaphore_ptrs A raw array of semaphores to set upon finished execution of the image layout transfer command buffer. + * May be null if @param in_opt_n_set_semaphores is 0. */ - void change_image_layout(std::shared_ptr in_queue_ptr, - VkAccessFlags in_src_access_mask, - VkImageLayout in_src_layout, - VkAccessFlags in_dst_access_mask, - VkImageLayout in_dst_layout, - const VkImageSubresourceRange& in_subresource_range); + void change_image_layout(std::shared_ptr in_queue_ptr, + VkAccessFlags in_src_access_mask, + VkImageLayout in_src_layout, + VkAccessFlags in_dst_access_mask, + VkImageLayout in_dst_layout, + const VkImageSubresourceRange& in_subresource_range, + const uint32_t in_opt_n_wait_semaphores = 0, + const VkPipelineStageFlags* in_opt_wait_dst_stage_mask_ptrs = nullptr, + const std::shared_ptr* in_opt_wait_semaphore_ptrs = nullptr, + const uint32_t in_opt_n_set_semaphores = 0, + const std::shared_ptr* in_opt_set_semaphore_ptrs = nullptr); /** Initializes a new non-sparse Image instance *without* a memory backing. A memory region should be bound * to the object by calling Image::set_memory() before using the object for any operations. diff --git a/include/wrappers/instance.h b/include/wrappers/instance.h index 2837f8da..23768f1e 100644 --- a/include/wrappers/instance.h +++ b/include/wrappers/instance.h @@ -36,11 +36,10 @@ namespace Anvil { /** Debug call-back function prototype */ - typedef VkBool32 (*PFNINSTANCEDEBUGCALLBACKPROC)(VkDebugReportFlagsEXT in_message_flags, - VkDebugReportObjectTypeEXT in_object_type, - const char* in_layer_prefix, - const char* in_message, - void* in_user_arg); + typedef std::function< VkBool32(VkDebugReportFlagsEXT in_message_flags, + VkDebugReportObjectTypeEXT in_object_type, + const char* in_layer_prefix, + const char* in_message)> DebugCallbackFunction; class Instance : public std::enable_shared_from_this { @@ -63,21 +62,17 @@ namespace Anvil * destroyed correctly. * * - * @param in_app_name Name of the application, to be passed in VkCreateInstanceInfo - * structure. - * @param in_engine_name Name of the engine, to be passed in VkCreateInstanceInfo - * structure. - * @param in_opt_pfn_validation_proc If not nullptr, the specified handled will be called whenever - * a call-back from any of the validation layers is received. - * Ignored otherwise. - * @param in_validation_proc_user_arg If @param opt_pfn_validation_proc is not nullptr, this argument - * will be passed to @param opt_pfn_validation_proc every time - * a debug callback is received. Ignored otherwise. + * @param in_app_name Name of the application, to be passed in VkCreateInstanceInfo + * structure. + * @param in_engine_name Name of the engine, to be passed in VkCreateInstanceInfo + * structure. + * @param in_opt_validation_callback_function If not nullptr, the specified function will be called whenever + * a call-back from any of the validation layers is received. + * Ignored otherwise. **/ - static std::shared_ptr create(const std::string& in_app_name, - const std::string& in_engine_name, - PFNINSTANCEDEBUGCALLBACKPROC in_opt_pfn_validation_callback_proc, - void* in_validation_proc_user_arg); + static std::shared_ptr create(const std::string& in_app_name, + const std::string& in_engine_name, + DebugCallbackFunction in_opt_validation_callback_proc); void destroy(); @@ -157,17 +152,16 @@ namespace Anvil /** Tells if validation support has been requested for this Vulkan Instance wrapper */ bool is_validation_enabled() const { - return m_pfn_validation_callback_proc != nullptr; + return m_validation_callback_function != nullptr; } private: /* Private functions */ /** Private constructor. Please use create() function instead. */ - Instance(const std::string& in_app_name, - const std::string& in_engine_name, - PFNINSTANCEDEBUGCALLBACKPROC in_opt_pfn_validation_callback_proc, - void* in_validation_proc_user_arg); + Instance(const std::string& in_app_name, + const std::string& in_engine_name, + DebugCallbackFunction in_opt_validation_callback_function); Instance& operator=(const Instance&); Instance (const Instance&); @@ -197,9 +191,9 @@ namespace Anvil /* DebugReport extension function pointers and data */ VkDebugReportCallbackEXT m_debug_callback_data; - ExtensionEXTDebugReportEntrypoints m_ext_debug_report_entrypoints; - ExtensionKHRGetPhysicalDeviceProperties2 m_khr_get_physical_device_properties2_entrypoints; - ExtensionKHRSurfaceEntrypoints m_khr_surface_entrypoints; + ExtensionEXTDebugReportEntrypoints m_ext_debug_report_entrypoints; + ExtensionKHRGetPhysicalDeviceProperties2 m_khr_get_physical_device_properties2_entrypoints; + ExtensionKHRSurfaceEntrypoints m_khr_surface_entrypoints; #ifdef _WIN32 #if defined(ANVIL_INCLUDE_WIN3264_WINDOW_SYSTEM_SUPPORT) @@ -211,10 +205,9 @@ namespace Anvil #endif #endif - const std::string m_app_name; - const std::string m_engine_name; - PFNINSTANCEDEBUGCALLBACKPROC m_pfn_validation_callback_proc; - void* m_validation_proc_user_arg; + const std::string m_app_name; + const std::string m_engine_name; + DebugCallbackFunction m_validation_callback_function; std::vector m_enabled_extensions; Anvil::Layer m_global_layer; diff --git a/include/wrappers/memory_block.h b/include/wrappers/memory_block.h index eeb2742e..2c1b385b 100644 --- a/include/wrappers/memory_block.h +++ b/include/wrappers/memory_block.h @@ -42,8 +42,7 @@ namespace Anvil { /** "About to be deleted" call-back function prototype. */ - typedef void (*PFNMEMORYBLOCKDESTRUCTIONCALLBACKPROC)(Anvil::MemoryBlock* in_memory_block_ptr, - void* in_user_arg); + typedef std::function OnMemoryBlockReleaseCallbackFunction; /** Wrapper class for memory objects. Please see header for more details */ class MemoryBlock : public std::enable_shared_from_this @@ -86,15 +85,14 @@ namespace Anvil * * TODO */ - static std::shared_ptr create_derived_with_custom_delete_proc(std::weak_ptr in_device_ptr, - VkDeviceMemory in_memory, - uint32_t in_allowed_memory_bits, - Anvil::MemoryFeatureFlags in_memory_features, - uint32_t in_memory_type_index, - VkDeviceSize in_size, - VkDeviceSize in_start_offset, - PFNMEMORYBLOCKDESTRUCTIONCALLBACKPROC in_pfn_destroy_memory_block_proc, - void* in_destroy_memory_block_proc_user_arg); + static std::shared_ptr create_derived_with_custom_delete_proc(std::weak_ptr in_device_ptr, + VkDeviceMemory in_memory, + uint32_t in_allowed_memory_bits, + Anvil::MemoryFeatureFlags in_memory_features, + uint32_t in_memory_type_index, + VkDeviceSize in_size, + VkDeviceSize in_start_offset, + OnMemoryBlockReleaseCallbackFunction in_on_release_callback_function); /** Releases the Vulkan counterpart and unregisters the wrapper instance from the object tracker */ virtual ~MemoryBlock(); @@ -249,15 +247,14 @@ namespace Anvil VkDeviceSize in_size); /** Please see create_derived_with_custom_delete_proc() for documentation */ - MemoryBlock(std::weak_ptr in_device_ptr, - VkDeviceMemory in_memory, - uint32_t in_allowed_memory_bits, - Anvil::MemoryFeatureFlags in_memory_features, - uint32_t in_memory_type_index, - VkDeviceSize in_size, - VkDeviceSize in_start_offset, - PFNMEMORYBLOCKDESTRUCTIONCALLBACKPROC in_pfn_destroy_memory_block_proc, - void* in_destroy_memory_block_proc_user_arg); + MemoryBlock(std::weak_ptr in_device_ptr, + VkDeviceMemory in_memory, + uint32_t in_allowed_memory_bits, + Anvil::MemoryFeatureFlags in_memory_features, + uint32_t in_memory_type_index, + VkDeviceSize in_size, + VkDeviceSize in_start_offset, + OnMemoryBlockReleaseCallbackFunction in_on_release_callback_function); MemoryBlock (const MemoryBlock&); MemoryBlock& operator=(const MemoryBlock&); @@ -265,17 +262,13 @@ namespace Anvil void close_gpu_memory_access (); uint32_t get_device_memory_type_index(uint32_t in_memory_type_bits, Anvil::MemoryFeatureFlags in_memory_features); - bool open_gpu_memory_access (VkDeviceSize in_start_offset, - VkDeviceSize in_size); + bool open_gpu_memory_access (); /* Private members */ - void* m_destroy_memory_block_proc_user_arg; - PFNMEMORYBLOCKDESTRUCTIONCALLBACKPROC m_pfn_destroy_memory_block_proc; + OnMemoryBlockReleaseCallbackFunction m_on_release_callback_function; - void* m_gpu_data_ptr; - bool m_gpu_data_user_mapped; - VkDeviceSize m_gpu_data_user_size; - VkDeviceSize m_gpu_data_user_start_offset; + std::atomic m_gpu_data_map_count; /* Only set for root memory blocks */ + void* m_gpu_data_ptr; /* Only set for root memory blocks */ uint32_t m_allowed_memory_bits; std::weak_ptr m_device_ptr; diff --git a/include/wrappers/pipeline_layout.h b/include/wrappers/pipeline_layout.h index b006b87a..1a755248 100644 --- a/include/wrappers/pipeline_layout.h +++ b/include/wrappers/pipeline_layout.h @@ -41,20 +41,8 @@ namespace Anvil typedef std::vector PushConstantRanges; - typedef enum - { - /* Notification fired when a pipeline layout instance is about to be deleted. - * - * callback_arg: originating PipelineLayout instance ptr. - */ - PIPELINE_LAYOUT_CALLBACK_ID_OBJECT_ABOUT_TO_BE_DELETED, - - PIPELINE_LAYOUT_CALLBACK_ID_COUNT - } PipelineLayoutCallbackID; - /** Vulkan Pipeline Layout wrapper */ - class PipelineLayout : public CallbacksSupportProvider, - public DebugMarkerSupportProvider + class PipelineLayout : public DebugMarkerSupportProvider { public: /* Public functions */ diff --git a/include/wrappers/pipeline_layout_manager.h b/include/wrappers/pipeline_layout_manager.h index 9dcbbf63..eb2f3e2e 100644 --- a/include/wrappers/pipeline_layout_manager.h +++ b/include/wrappers/pipeline_layout_manager.h @@ -97,8 +97,8 @@ namespace Anvil **/ static std::shared_ptr create(std::weak_ptr in_device_ptr); - static void on_pipeline_layout_dropped(void* in_callback_arg, - void* in_user_arg); + void on_pipeline_layout_dropped(); + void update_subscriptions (bool in_should_init); /* Private members */ std::weak_ptr m_device_ptr; diff --git a/include/wrappers/queue.h b/include/wrappers/queue.h index dc709923..4e1d05dc 100644 --- a/include/wrappers/queue.h +++ b/include/wrappers/queue.h @@ -41,7 +41,7 @@ namespace Anvil { /* Notification fired right after vkQueuePresentKHR() has been issued for a swapchain. * - * callback_arg: originating Queue instance ptr. + * callback_arg: Pointer to PresentRequestIssuedCallbackArgument instance. */ QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, @@ -95,6 +95,12 @@ namespace Anvil return m_queue_family_index; } + /** Retrieves index of the queue */ + uint32_t get_queue_index() const + { + return m_queue_index; + } + /** Presents the specified swapchain image using this queue. This queue must support presentation * for the swapchain's rendering surface in order for this call to succeed. * @@ -278,6 +284,7 @@ namespace Anvil VkQueue m_queue; uint32_t m_queue_family_index; uint32_t m_queue_index; + std::shared_ptr m_submit_fence_ptr; bool m_supports_sparse_bindings; }; }; /* namespace Anvil */ diff --git a/include/wrappers/render_pass.h b/include/wrappers/render_pass.h index 64dbc6fe..13be594c 100644 --- a/include/wrappers/render_pass.h +++ b/include/wrappers/render_pass.h @@ -41,7 +41,7 @@ namespace Anvil { /* Call-back issued whenever the originating renderpass becomes dirty * - * callback_arg: source RenderPass instance + * callback_arg: Pointer to OnRenderPassBakeNeededCallbackArgument instance. */ RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, diff --git a/include/wrappers/shader_module.h b/include/wrappers/shader_module.h index e16199e8..167d645f 100644 --- a/include/wrappers/shader_module.h +++ b/include/wrappers/shader_module.h @@ -106,6 +106,26 @@ namespace Anvil in_opt_te_entrypoint_name.c_str(), in_opt_vs_entrypoint_name.c_str() ); } + static std::shared_ptr create_from_spirv_blob(std::weak_ptr in_device_ptr, + const uint32_t* in_spirv_blob, + uint32_t in_n_spirv_blob_uint32s, + const std::string& in_opt_cs_entrypoint_name, + const std::string& in_opt_fs_entrypoint_name, + const std::string& in_opt_gs_entrypoint_name, + const std::string& in_opt_tc_entrypoint_name, + const std::string& in_opt_te_entrypoint_name, + const std::string& in_opt_vs_entrypoint_name) + { + return create_from_spirv_blob(in_device_ptr, + reinterpret_cast(in_spirv_blob), + in_n_spirv_blob_uint32s * sizeof(uint32_t), + in_opt_cs_entrypoint_name.c_str(), + in_opt_fs_entrypoint_name.c_str(), + in_opt_gs_entrypoint_name.c_str(), + in_opt_tc_entrypoint_name.c_str(), + in_opt_te_entrypoint_name.c_str(), + in_opt_vs_entrypoint_name.c_str() ); + } /** Destructor. Releases internally maintained Vulkan shader module instance. */ virtual ~ShaderModule(); @@ -239,8 +259,7 @@ namespace Anvil bool init_from_spirv_blob(const char* in_spirv_blob, uint32_t in_n_spirv_blob_bytes); - static void on_object_about_to_be_released(void* in_callback_arg, - void* in_shader_module_raw_ptr); + void on_object_about_to_be_released(void* in_callback_arg); /* Private variables */ std::string m_cs_entrypoint_name; diff --git a/include/wrappers/swapchain.h b/include/wrappers/swapchain.h index 794b200d..36c51036 100644 --- a/include/wrappers/swapchain.h +++ b/include/wrappers/swapchain.h @@ -223,16 +223,14 @@ namespace Anvil void destroy_swapchain(); void init (); - static void on_parent_window_about_to_close(void* in_window_ptr, - void* in_swapchain_raw_ptr); - static void on_present_request_issued (void* in_queue_raw_ptr, - void* in_swapchain_raw_ptr); + void on_parent_window_about_to_close(); + void on_present_request_issued (); /* Private variables */ bool m_destroy_swapchain_before_parent_window_closes; std::weak_ptr m_device_ptr; VkSwapchainCreateFlagsKHR m_flags; - std::vector > m_image_available_fence_ptrs; + std::shared_ptr m_image_available_fence_ptr; VkFormat m_image_format; std::vector > m_image_ptrs; VkFormat m_image_view_format; diff --git a/src/misc/debug.cpp b/src/misc/debug.cpp index b2a346c1..827bf48e 100644 --- a/src/misc/debug.cpp +++ b/src/misc/debug.cpp @@ -31,7 +31,10 @@ static void default_assertion_failure_handler(const char* in_filename, const char* in_message); -Anvil::PFNASSERTIONFAILEDCALLBACKPROC g_anvil_assertion_check_failed_func_ptr = default_assertion_failure_handler; +static Anvil::AssertionFailedCallbackFunction g_anvil_assertion_check_failed_func = std::bind(default_assertion_failure_handler, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3); /** Please see header for specification */ @@ -63,13 +66,13 @@ void Anvil::on_assertion_failed(const char* in_filename, } #endif - g_anvil_assertion_check_failed_func_ptr(in_filename, - in_line, - in_message); + g_anvil_assertion_check_failed_func(in_filename, + in_line, + in_message); } /** Please see header for specification */ -void Anvil::set_assertion_failure_handler(Anvil::PFNASSERTIONFAILEDCALLBACKPROC in_new_callback_func_ptr) +void Anvil::set_assertion_failure_handler(Anvil::AssertionFailedCallbackFunction in_new_callback_func) { - g_anvil_assertion_check_failed_func_ptr = in_new_callback_func_ptr; + g_anvil_assertion_check_failed_func = in_new_callback_func; } \ No newline at end of file diff --git a/src/misc/dummy_window.cpp b/src/misc/dummy_window.cpp index 44c28b30..005730bf 100644 --- a/src/misc/dummy_window.cpp +++ b/src/misc/dummy_window.cpp @@ -31,11 +31,10 @@ #include "miniz/miniz.c" /** Please see header for specification */ -std::shared_ptr Anvil::DummyWindow::create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +std::shared_ptr Anvil::DummyWindow::create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func) { std::shared_ptr result_ptr; @@ -43,8 +42,7 @@ std::shared_ptr Anvil::DummyWindow::create(const std::string& new Anvil::DummyWindow(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_present_callback_func) ); if (result_ptr) @@ -59,16 +57,15 @@ std::shared_ptr Anvil::DummyWindow::create(const std::string& } /** Please see header for specification */ -Anvil::DummyWindow::DummyWindow(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +Anvil::DummyWindow::DummyWindow(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func) : Window(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + false, /* in_closable */ + in_present_callback_func) { m_window_owned = true; } @@ -95,7 +92,10 @@ void Anvil::DummyWindow::run() while (running && !m_window_should_close) { - m_present_callback_func_ptr(m_present_callback_func_user_arg); + if (m_present_callback_func) + { + m_present_callback_func(); + } running = !m_window_should_close; } @@ -105,11 +105,10 @@ void Anvil::DummyWindow::run() /** Please see header for specification */ -std::shared_ptr Anvil::DummyWindowWithPNGSnapshots::create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +std::shared_ptr Anvil::DummyWindowWithPNGSnapshots::create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func) { std::shared_ptr result_ptr; @@ -117,8 +116,7 @@ std::shared_ptr Anvil::DummyWindowWithPNGSnapshots::create(const new Anvil::DummyWindowWithPNGSnapshots(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_present_callback_func) ); if (result_ptr) @@ -133,16 +131,14 @@ std::shared_ptr Anvil::DummyWindowWithPNGSnapshots::create(const } /** Please see header for specification */ -Anvil::DummyWindowWithPNGSnapshots::DummyWindowWithPNGSnapshots(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +Anvil::DummyWindowWithPNGSnapshots::DummyWindowWithPNGSnapshots(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + PresentCallbackFunction in_present_callback_func) :DummyWindow(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_present_callback_func) { m_height = in_height; m_n_frames_presented = 0; @@ -353,7 +349,7 @@ void Anvil::DummyWindowWithPNGSnapshots::run() while (running && !m_window_should_close) { - m_present_callback_func_ptr(m_present_callback_func_user_arg); + m_present_callback_func(); store_swapchain_frame(); diff --git a/src/misc/formats.cpp b/src/misc/formats.cpp index bf3b2199..bca190e0 100644 --- a/src/misc/formats.cpp +++ b/src/misc/formats.cpp @@ -319,8 +319,9 @@ bool Anvil::Formats::get_format_aspects(VkFormat in_form out_aspects_ptr->push_back(VK_IMAGE_ASPECT_COLOR_BIT); } - if (format_layout == Anvil::COMPONENT_LAYOUT_D || - format_layout == Anvil::COMPONENT_LAYOUT_DS) + if (format_layout == Anvil::COMPONENT_LAYOUT_D || + format_layout == Anvil::COMPONENT_LAYOUT_DS || + format_layout == Anvil::COMPONENT_LAYOUT_XD) { out_aspects_ptr->push_back(VK_IMAGE_ASPECT_DEPTH_BIT); } diff --git a/src/misc/glsl_to_spirv.cpp b/src/misc/glsl_to_spirv.cpp index e43860e2..1d60cb7e 100644 --- a/src/misc/glsl_to_spirv.cpp +++ b/src/misc/glsl_to_spirv.cpp @@ -235,19 +235,33 @@ Anvil::GLSLShaderToSPIRVGenerator::GLSLShaderToSPIRVGenerator(std::weak_ptrunregister_object(Anvil::OBJECT_TYPE_GLSL_SHADER_TO_SPIRV_GENERATOR, + this); + m_spirv_blob.clear(); } @@ -322,55 +336,53 @@ bool Anvil::GLSLShaderToSPIRVGenerator::add_pragma(std::string in_pragma_name, } /* Please see header for specification */ -bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() +bool Anvil::GLSLShaderToSPIRVGenerator::bake_glsl_source_code() { std::string final_glsl_source_string; - bool glsl_filename_is_temporary = false; - std::string glsl_filename_with_path; const uint32_t n_definition_values = static_cast(m_definition_values.size() ); const uint32_t n_extension_behaviors = static_cast(m_extension_behaviors.size() ); const uint32_t n_pragmas = static_cast(m_pragmas.size() ); bool result = false; - ANVIL_REDUNDANT_VARIABLE(glsl_filename_is_temporary); + anvil_assert(m_glsl_source_code_dirty); + switch (m_mode) { - switch (m_mode) + case MODE_LOAD_SOURCE_FROM_FILE: { - case MODE_LOAD_SOURCE_FROM_FILE: - { - char* glsl_source = nullptr; + char* glsl_source = nullptr; - Anvil::IO::read_file(m_data, - true, /* is_text_file */ - &glsl_source, - nullptr); /* out_opt_size_ptr */ + Anvil::IO::read_file(m_data, + true, /* is_text_file */ + &glsl_source, + nullptr); /* out_opt_size_ptr */ - if (glsl_source == nullptr) - { - anvil_assert(glsl_source != nullptr); + if (glsl_source == nullptr) + { + anvil_assert(glsl_source != nullptr); - goto end; - } + goto end; + } - final_glsl_source_string = std::string(glsl_source); + final_glsl_source_string = std::string(glsl_source); - delete [] glsl_source; - break; - } + delete [] glsl_source; + break; + } - case MODE_USE_SPECIFIED_SOURCE: - { - final_glsl_source_string = m_data; + case MODE_USE_SPECIFIED_SOURCE: + { + final_glsl_source_string = m_data; - break; - } + break; + } - default: - { - /* Unrecognized mode specified for a GLSLShaderToSPIRVGenerator instance. */ - anvil_assert_fail(); - } + default: + { + /* Unrecognized mode specified for a GLSLShaderToSPIRVGenerator instance. */ + anvil_assert_fail(); + + goto end; } } @@ -429,16 +441,39 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() } } + /* Cache the GLSL source code used for the conversion */ + m_glsl_source_code = final_glsl_source_string; + + /* All done */ + m_glsl_source_code_dirty = false; + result = true; + +end: + return result; +} + +/* Please see header for specification */ +bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() +{ + bool glsl_filename_is_temporary = false; + std::string glsl_filename_with_path; + bool result = false; + + ANVIL_REDUNDANT_VARIABLE(glsl_filename_is_temporary); + + if (m_glsl_source_code_dirty) + { + bake_glsl_source_code(); + + anvil_assert(!m_glsl_source_code_dirty); + } + if (m_mode == MODE_LOAD_SOURCE_FROM_FILE) { glsl_filename_is_temporary = false; glsl_filename_with_path = m_data; } - /* Cache the GLSL source code used for the conversion */ - anvil_assert(m_final_glsl_source_code.size() == 0); - m_final_glsl_source_code = final_glsl_source_string; - /* Form a temporary file name we will use to write the modified GLSL shader to. */ #ifndef ANVIL_LINK_WITH_GLSLANG { @@ -461,7 +496,7 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() /* Write down the file to a temporary location */ Anvil::IO::write_text_file(glsl_filename_with_path, - final_glsl_source_string); + m_glsl_source_code); glsl_filename_is_temporary = true; } @@ -491,7 +526,7 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() break; } - if (shader_module_ptr->get_glsl_source_code() == final_glsl_source_string) + if (shader_module_ptr->get_glsl_source_code() == m_glsl_source_code) { const auto reference_spirv_blob = shader_module_ptr->get_spirv_blob(); const auto reference_spirv_blob_size_in_bytes = reference_spirv_blob.size() * sizeof(reference_spirv_blob.at(0) ); @@ -516,7 +551,7 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() if (m_spirv_blob.size() == 0) { /* Need to bake a brand new SPIR-V blob */ - result = bake_spirv_blob_by_calling_glslang(final_glsl_source_string.c_str() ); + result = bake_spirv_blob_by_calling_glslang(m_glsl_source_code.c_str() ); } } #else @@ -527,7 +562,6 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() } #endif -end: return result; } @@ -549,7 +583,17 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() std::vector spirv_blob; anvil_assert(new_program_ptr != nullptr && - new_shader_ptr != nullptr); + new_shader_ptr != nullptr); + + /* If this assertion check explodes, you're trying to build a SPIR-V blob with a generator, which has + * been initialized with a null device instance. This is illegal. + */ + OnGLSLToSPIRVConversionAboutToBeStartedCallbackArgument callback_arg(this); + + anvil_assert(m_limits_ptr != nullptr); + + callback(GLSL_SHADER_TO_SPIRV_GENERATOR_CALLBACK_ID_CONVERSION_ABOUT_TO_START, + &callback_arg); if (new_program_ptr != nullptr && new_shader_ptr != nullptr) @@ -560,7 +604,7 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() new_shader_ptr->setStrings(&in_body, 1); - result = new_shader_ptr->parse(m_limits.get_resource_ptr(), + result = new_shader_ptr->parse(m_limits_ptr->get_resource_ptr(), 110, /* defaultVersion */ false, /* forwardCompatible */ (EShMessages) (EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules) ); @@ -675,10 +719,14 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob_by_spawning_glslang_process(const std::string& in_glsl_filename_with_path, const std::string& in_spirv_filename_with_path) { + auto callback_arg = OnGLSLToSPIRVConversionAboutToBeStartedCallbackArgument(this); std::string glslangvalidator_params; bool result = false; size_t spirv_file_size = 0; + callback(GLSL_SHADER_TO_SPIRV_GENERATOR_CALLBACK_ID_CONVERSION_ABOUT_TO_START, + &callback_arg); + #ifdef _WIN32 { /* Launch glslangvalidator and wait until it finishes doing the job */ @@ -806,7 +854,7 @@ bool Anvil::GLSLShaderToSPIRVGenerator::bake_spirv_blob() #endif /* Please see header for specification */ -std::shared_ptr Anvil::GLSLShaderToSPIRVGenerator::create(std::weak_ptr in_device_ptr, +std::shared_ptr Anvil::GLSLShaderToSPIRVGenerator::create(std::weak_ptr in_opt_device_ptr, const Mode& in_mode, std::string in_data, ShaderStage in_shader_stage) @@ -814,12 +862,15 @@ std::shared_ptr Anvil::GLSLShaderToSPIRVGener std::shared_ptr result_ptr; result_ptr.reset( - new Anvil::GLSLShaderToSPIRVGenerator(in_device_ptr, + new Anvil::GLSLShaderToSPIRVGenerator(in_opt_device_ptr, in_mode, in_data, in_shader_stage) ); + Anvil::ObjectTracker::get()->register_object(Anvil::OBJECT_TYPE_GLSL_SHADER_TO_SPIRV_GENERATOR, + result_ptr.get() ); + return result_ptr; } diff --git a/src/misc/io.cpp b/src/misc/io.cpp index cde13205..5dd4a251 100644 --- a/src/misc/io.cpp +++ b/src/misc/io.cpp @@ -503,7 +503,7 @@ bool Anvil::IO::read_file(std::string in_filename, if (fseek(file_handle, in_start_offset, - SEEK_END) != 0) + SEEK_SET) != 0) { goto end; } diff --git a/src/misc/memalloc_backends/backend_vma.cpp b/src/misc/memalloc_backends/backend_vma.cpp index 2d70bea8..00405d6a 100644 --- a/src/misc/memalloc_backends/backend_vma.cpp +++ b/src/misc/memalloc_backends/backend_vma.cpp @@ -162,13 +162,14 @@ bool Anvil::MemoryAllocatorBackends::VMA::bake(Anvil::MemoryAllocator::Items& in */ for (auto& current_item_ptr : in_items) { - VkMemoryRequirements memory_requirements_vk; - VmaMemoryRequirements memory_requirements_vma; - std::shared_ptr new_memory_block_ptr; - VkMemoryHeapFlags required_mem_heap_flags = 0; - VkMemoryPropertyFlags required_mem_property_flags = 0; - uint32_t result_mem_type_index = UINT32_MAX; - VkMappedMemoryRange result_mem_range; + VkMemoryRequirements memory_requirements_vk; + VmaMemoryRequirements memory_requirements_vma; + std::shared_ptr new_memory_block_ptr; + Anvil::OnMemoryBlockReleaseCallbackFunction release_callback_function; + VkMemoryHeapFlags required_mem_heap_flags = 0; + VkMemoryPropertyFlags required_mem_property_flags = 0; + uint32_t result_mem_type_index = UINT32_MAX; + VkMappedMemoryRange result_mem_range; Anvil::Utils::get_vk_property_flags_from_memory_feature_flags(current_item_ptr->alloc_memory_required_features, &required_mem_property_flags, @@ -204,6 +205,12 @@ bool Anvil::MemoryAllocatorBackends::VMA::bake(Anvil::MemoryAllocator::Items& in anvil_assert(result_mem_range.sType == VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE); /* Bake the block and stash it */ + release_callback_function = std::bind( + &VMAAllocator::on_vma_alloced_mem_block_gone_out_of_scope, + m_vma_allocator_ptr, + std::placeholders::_1 + ); + new_memory_block_ptr = Anvil::MemoryBlock::create_derived_with_custom_delete_proc(m_device_ptr, result_mem_range.memory, memory_requirements_vk.memoryTypeBits, @@ -211,9 +218,7 @@ bool Anvil::MemoryAllocatorBackends::VMA::bake(Anvil::MemoryAllocator::Items& in result_mem_type_index, memory_requirements_vk.size, result_mem_range.offset, - VMAAllocator::on_vma_alloced_mem_block_gone_out_of_scope, - m_vma_allocator_ptr.get() - ); + release_callback_function); if (new_memory_block_ptr == nullptr) { @@ -279,13 +284,9 @@ void Anvil::MemoryAllocatorBackends::VMA::VMAAllocator::on_new_vma_mem_block_all } /** Please see header for specification */ -void Anvil::MemoryAllocatorBackends::VMA::VMAAllocator::on_vma_alloced_mem_block_gone_out_of_scope(Anvil::MemoryBlock* in_memory_block_ptr, - void* in_user_arg) +void Anvil::MemoryAllocatorBackends::VMA::VMAAllocator::on_vma_alloced_mem_block_gone_out_of_scope(Anvil::MemoryBlock* in_memory_block_ptr) { VkMappedMemoryRange mem_range; - VMAAllocator* vma_allocator_ptr = reinterpret_cast(in_user_arg); - - anvil_assert(vma_allocator_ptr != nullptr); /* Only physically deallocate those memory blocks that are not derivatives of another memory blocks! */ if (in_memory_block_ptr->get_parent_memory_block() == nullptr) @@ -296,17 +297,17 @@ void Anvil::MemoryAllocatorBackends::VMA::VMAAllocator::on_vma_alloced_mem_block mem_range.size = in_memory_block_ptr->get_size(); mem_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - vmaFreeMemory(vma_allocator_ptr->get_handle(), + vmaFreeMemory(get_handle(), &mem_range); /* Remove one cached pointer to the VMA wrapper class instance. This means that VMA instance * is going to be destroyed in case the vector's size reaches zero! */ - anvil_assert(vma_allocator_ptr->m_refcount_helper.size() >= 1); + anvil_assert(m_refcount_helper.size() >= 1); - vma_allocator_ptr->m_refcount_helper.pop_back(); + m_refcount_helper.pop_back(); - /* WARNING: vma_allocator_ptr is potentially nullptr from this point onward!: */ + /* WARNING: *this is potentially out of scope from this point onward!: */ } } diff --git a/src/misc/memory_allocator.cpp b/src/misc/memory_allocator.cpp index f5749314..243f1f64 100644 --- a/src/misc/memory_allocator.cpp +++ b/src/misc/memory_allocator.cpp @@ -224,16 +224,25 @@ Anvil::MemoryAllocator::Item::~Item() /* Please see header for specification */ void Anvil::MemoryAllocator::Item::register_for_callbacks() { + auto on_implicit_bake_needed_callback_func = std::bind(&Anvil::MemoryAllocator::on_implicit_bake_needed, + memory_allocator_ptr.get() ); + auto on_is_alloc_pending_for_buffer_query_callback_func = std::bind(&Anvil::MemoryAllocator::on_is_alloc_pending_for_buffer_query, + memory_allocator_ptr.get(), + std::placeholders::_1); + auto on_is_alloc_pending_for_image_query_callback_func = std::bind(&Anvil::MemoryAllocator::on_is_alloc_pending_for_image_query, + memory_allocator_ptr.get(), + std::placeholders::_1); + if (buffer_ptr != nullptr) { /* Sign up for "is alloc pending" callback in order to support sparsely bound/sparse buffers */ if (!buffer_ptr->is_callback_registered(BUFFER_CALLBACK_ID_IS_ALLOC_PENDING, - on_is_alloc_pending_for_buffer_query, - memory_allocator_ptr.get() )) + on_is_alloc_pending_for_buffer_query_callback_func, + buffer_ptr.get() )) { buffer_ptr->register_for_callbacks(BUFFER_CALLBACK_ID_IS_ALLOC_PENDING, - on_is_alloc_pending_for_buffer_query, - memory_allocator_ptr.get() ); + on_is_alloc_pending_for_buffer_query_callback_func, + buffer_ptr.get() ); buffer_has_is_alloc_pending_callback_registered = true; } @@ -244,12 +253,12 @@ void Anvil::MemoryAllocator::Item::register_for_callbacks() /* Sign up for "memory needed" callback so that we can trigger an implicit bake operation */ if (!buffer_ptr->is_callback_registered(BUFFER_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - on_implicit_bake_needed, - memory_allocator_ptr.get() )) + on_implicit_bake_needed_callback_func, + buffer_ptr.get() )) { buffer_ptr->register_for_callbacks(BUFFER_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - on_implicit_bake_needed, - memory_allocator_ptr.get() ); + on_implicit_bake_needed_callback_func, + buffer_ptr.get() ); buffer_has_memory_block_needed_callback_registered = true; } @@ -263,12 +272,12 @@ void Anvil::MemoryAllocator::Item::register_for_callbacks() { /* Sign up for "is alloc pending" callback in order to support sparse images */ if (!image_ptr->is_callback_registered(IMAGE_CALLBACK_ID_IS_ALLOC_PENDING, - on_is_alloc_pending_for_image_query, - memory_allocator_ptr.get() )) + on_is_alloc_pending_for_image_query_callback_func, + image_ptr.get() )) { image_ptr->register_for_callbacks(IMAGE_CALLBACK_ID_IS_ALLOC_PENDING, - on_is_alloc_pending_for_image_query, - memory_allocator_ptr.get() ); + on_is_alloc_pending_for_image_query_callback_func, + image_ptr.get() ); image_has_is_alloc_pending_callback_registered = true; } @@ -279,12 +288,12 @@ void Anvil::MemoryAllocator::Item::register_for_callbacks() /* Sign up for "memory needed" callback so that we can trigger an implicit bake operation */ if (!image_ptr->is_callback_registered(IMAGE_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - on_implicit_bake_needed, - memory_allocator_ptr.get() )) + on_implicit_bake_needed_callback_func, + image_ptr.get() )) { image_ptr->register_for_callbacks(IMAGE_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - on_implicit_bake_needed, - memory_allocator_ptr.get() ); + on_implicit_bake_needed_callback_func, + image_ptr.get() ); image_has_memory_block_needed_callback_registered = true; } @@ -299,20 +308,29 @@ void Anvil::MemoryAllocator::Item::register_for_callbacks() /* Please see header for specification */ void Anvil::MemoryAllocator::Item::unregister_from_callbacks() { + auto on_implicit_bake_needed_callback_func = std::bind(&Anvil::MemoryAllocator::on_implicit_bake_needed, + memory_allocator_ptr.get() ); + auto on_is_alloc_pending_for_buffer_query_callback_func = std::bind(&Anvil::MemoryAllocator::on_is_alloc_pending_for_buffer_query, + memory_allocator_ptr.get(), + std::placeholders::_1); + auto on_is_alloc_pending_for_image_query_callback_func = std::bind(&Anvil::MemoryAllocator::on_is_alloc_pending_for_image_query, + memory_allocator_ptr.get(), + std::placeholders::_1); + if (buffer_ptr != nullptr) { if (buffer_has_is_alloc_pending_callback_registered) { buffer_ptr->unregister_from_callbacks(BUFFER_CALLBACK_ID_IS_ALLOC_PENDING, - on_is_alloc_pending_for_buffer_query, - memory_allocator_ptr.get() ); + on_is_alloc_pending_for_buffer_query_callback_func, + buffer_ptr.get() ); } if (buffer_has_memory_block_needed_callback_registered) { buffer_ptr->unregister_from_callbacks(BUFFER_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - on_implicit_bake_needed, - memory_allocator_ptr.get() ); + on_implicit_bake_needed_callback_func, + buffer_ptr.get() ); } } @@ -321,15 +339,15 @@ void Anvil::MemoryAllocator::Item::unregister_from_callbacks() if (image_has_is_alloc_pending_callback_registered) { image_ptr->unregister_from_callbacks(IMAGE_CALLBACK_ID_IS_ALLOC_PENDING, - on_is_alloc_pending_for_image_query, - memory_allocator_ptr.get() ); + on_is_alloc_pending_for_image_query_callback_func, + image_ptr.get() ); } if (image_has_memory_block_needed_callback_registered) { image_ptr->unregister_from_callbacks(IMAGE_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - on_implicit_bake_needed, - memory_allocator_ptr.get() ); + on_implicit_bake_needed_callback_func, + image_ptr.get() ); } } } @@ -338,11 +356,10 @@ void Anvil::MemoryAllocator::Item::unregister_from_callbacks() /* Please see header for specification */ Anvil::MemoryAllocator::MemoryAllocator(std::weak_ptr in_device_ptr, std::shared_ptr in_backend_ptr) - :m_backend_ptr (in_backend_ptr), - m_device_ptr (in_device_ptr), - m_pfn_post_bake_callback_ptr (nullptr), - m_post_bake_callback_user_arg(nullptr) + :m_backend_ptr(in_backend_ptr), + m_device_ptr (in_device_ptr) { + /* Stub */ } /* Please see header for specification */ @@ -803,6 +820,7 @@ bool Anvil::MemoryAllocator::bake() anvil_assert(m_items.size() > 0); result = m_backend_ptr->bake(m_items); + anvil_assert(result); /* Prepare a sparse memory binding structure, if we're going to need one */ for (auto item_iterator = m_items.begin(); @@ -954,6 +972,46 @@ bool Anvil::MemoryAllocator::bake() UINT64_MAX); } + /* If the user does not keep the memory allocator around and all items are assigned memory backing, + * the m_items.erase() call we do close to the end of this func may invoke destruction of this object. + * There's a post-alloc call-back that we still need to do after all items are traversed, so, in order + * to prevent the premature destruction of the allocator, cache a shared ptr to this instance, so that + * the allocator only goes out of scope when this function leaves. + */ + this_ptr = shared_from_this(); + + for (uint32_t n_item = 0; + n_item < m_items.size(); + ++n_item + ) + { + auto item_iterator = m_items.begin() + n_item; + auto item_ptr = *item_iterator; + + if (item_ptr->is_baked) + { + decltype(m_per_object_pending_alloc_status)::iterator alloc_status_map_iterator; + + switch (item_ptr->type) + { + case ITEM_TYPE_BUFFER: alloc_status_map_iterator = m_per_object_pending_alloc_status.find(item_ptr->buffer_ptr.get() ); break; + case ITEM_TYPE_IMAGE_WHOLE: /* fall-through */ + case ITEM_TYPE_SPARSE_IMAGE_MIPTAIL: /* fall-through */ + case ITEM_TYPE_SPARSE_IMAGE_SUBRESOURCE: alloc_status_map_iterator = m_per_object_pending_alloc_status.find(item_ptr->image_ptr.get() ); break; + + default: + { + anvil_assert_fail(); + } + } + + if (alloc_status_map_iterator != m_per_object_pending_alloc_status.end() ) + { + m_per_object_pending_alloc_status.erase(alloc_status_map_iterator); + } + } + } + /* Perform post-alloc fill actions */ for (const auto& current_item_ptr : m_items) { @@ -1014,55 +1072,11 @@ bool Anvil::MemoryAllocator::bake() } } - /* If the user does not keep the memory allocator around and all items are assigned memory backing, - * the m_items.erase() call we do close to the end of this func may invoke destruction of this object. - * There's a post-alloc call-back that we still need to do after all items are traversed, so, in order - * to prevent the premature destruction of the allocator, cache a shared ptr to this instance, so that - * the allocator only goes out of scope when this function leaves. - */ - this_ptr = shared_from_this(); - - for (uint32_t n_item = 0; - n_item < m_items.size(); - ) - { - auto item_iterator = m_items.begin() + n_item; - auto item_ptr = *item_iterator; - - if (item_ptr->is_baked) - { - decltype(m_per_object_pending_alloc_status)::iterator alloc_status_map_iterator; + m_items.clear(); - switch (item_ptr->type) - { - case ITEM_TYPE_BUFFER: alloc_status_map_iterator = m_per_object_pending_alloc_status.find(item_ptr->buffer_ptr.get() ); break; - case ITEM_TYPE_IMAGE_WHOLE: /* fall-through */ - case ITEM_TYPE_SPARSE_IMAGE_MIPTAIL: /* fall-through */ - case ITEM_TYPE_SPARSE_IMAGE_SUBRESOURCE: alloc_status_map_iterator = m_per_object_pending_alloc_status.find(item_ptr->image_ptr.get() ); break; - - default: - { - anvil_assert_fail(); - } - } - - if (alloc_status_map_iterator != m_per_object_pending_alloc_status.end() ) - { - m_per_object_pending_alloc_status.erase(alloc_status_map_iterator); - } - - m_items.erase(item_iterator); - } - else - { - ++n_item; - } - } - - if (m_pfn_post_bake_callback_ptr != nullptr) + if (m_post_bake_callback_function != nullptr) { - m_pfn_post_bake_callback_ptr(this, - m_post_bake_callback_user_arg); + m_post_bake_callback_function(this); } end: @@ -1156,56 +1170,45 @@ bool Anvil::MemoryAllocator::is_alloc_supported(uint32_t in_mem } /* Please see header for specification */ -void Anvil::MemoryAllocator::on_is_alloc_pending_for_buffer_query(void* in_callback_arg, - void* in_user_arg) +void Anvil::MemoryAllocator::on_is_alloc_pending_for_buffer_query(CallbackArgument* in_callback_arg_ptr) { - MemoryAllocator* allocator_ptr = reinterpret_cast (in_user_arg); - BufferCallbackIsAllocPendingQueryData* query_ptr = reinterpret_cast(in_callback_arg); - auto alloc_status_map_iterator = allocator_ptr->m_per_object_pending_alloc_status.find (query_ptr->buffer_ptr.get() ); + IsBufferMemoryAllocPendingQueryCallbackArgument* query_ptr = dynamic_cast(in_callback_arg_ptr); + auto alloc_status_map_iterator = m_per_object_pending_alloc_status.find (query_ptr->buffer_ptr.get() ); - if (alloc_status_map_iterator != allocator_ptr->m_per_object_pending_alloc_status.end() ) + if (alloc_status_map_iterator != m_per_object_pending_alloc_status.end() ) { query_ptr->result = true; } } /* Please see header for specification */ -void Anvil::MemoryAllocator::on_is_alloc_pending_for_image_query(void* in_callback_arg, - void* in_user_arg) +void Anvil::MemoryAllocator::on_is_alloc_pending_for_image_query(CallbackArgument* in_callback_arg_ptr) { - MemoryAllocator* allocator_ptr = reinterpret_cast (in_user_arg); - ImageCallbackIsAllocPendingQueryData* query_ptr = reinterpret_cast(in_callback_arg); - auto alloc_status_map_iterator = allocator_ptr->m_per_object_pending_alloc_status.find(query_ptr->image_ptr.get() ); + IsImageMemoryAllocPendingQueryCallbackArgument* query_ptr = dynamic_cast(in_callback_arg_ptr); + auto alloc_status_map_iterator = m_per_object_pending_alloc_status.find (query_ptr->image_ptr.get() ); - if (alloc_status_map_iterator != allocator_ptr->m_per_object_pending_alloc_status.end() ) + if (alloc_status_map_iterator != m_per_object_pending_alloc_status.end() ) { query_ptr->result = true; } } /* Please see header for specification */ -void Anvil::MemoryAllocator::on_implicit_bake_needed(void* in_callback_arg, - void* in_user_arg) +void Anvil::MemoryAllocator::on_implicit_bake_needed() { - MemoryAllocator* allocator_ptr = reinterpret_cast(in_user_arg); - - ANVIL_REDUNDANT_ARGUMENT(in_callback_arg); - /* Sanity checks */ - anvil_assert(allocator_ptr->m_items.size() >= 1); + anvil_assert(m_items.size() >= 1); - allocator_ptr->bake(); + bake(); } /* Please see header for specification */ -void Anvil::MemoryAllocator::set_post_bake_callback(PFNMEMORYALLOCATORBAKECALLBACKPROC pfn_post_bake_callback, - void* callback_user_arg) +void Anvil::MemoryAllocator::set_post_bake_callback(MemoryAllocatorBakeCallbackFunction in_post_bake_callback_function) { - anvil_assert(m_pfn_post_bake_callback_ptr == nullptr); + anvil_assert(m_post_bake_callback_function == nullptr); - if (m_pfn_post_bake_callback_ptr == nullptr) + if (m_post_bake_callback_function == nullptr) { - m_pfn_post_bake_callback_ptr = pfn_post_bake_callback; - m_post_bake_callback_user_arg = callback_user_arg; + m_post_bake_callback_function = in_post_bake_callback_function; } } diff --git a/src/misc/object_tracker.cpp b/src/misc/object_tracker.cpp index d98ec8a9..932885d0 100644 --- a/src/misc/object_tracker.cpp +++ b/src/misc/object_tracker.cpp @@ -62,6 +62,8 @@ Anvil::ObjectTracker* Anvil::ObjectTracker::get() /* Please see header for specification */ void Anvil::ObjectTracker::check_for_leaks() const { + std::unique_lock lock(m_cs); + for (ObjectType current_object_type = OBJECT_TYPE_FIRST; current_object_type < OBJECT_TYPE_COUNT; current_object_type = static_cast(current_object_type + 1)) @@ -131,7 +133,7 @@ const char* Anvil::ObjectTracker::get_object_type_name(ObjectType in_object_type "Shader Module", "Swapchain", - /* Fake types: */ + "GLSL shader -> SPIR-V generator", "Graphics Pipeline (fake)" }; @@ -142,10 +144,11 @@ const char* Anvil::ObjectTracker::get_object_type_name(ObjectType in_object_type } /* Please see header for specification */ -const void* Anvil::ObjectTracker::get_object_at_index(ObjectType in_object_type, - uint32_t in_alloc_index) const +void* Anvil::ObjectTracker::get_object_at_index(ObjectType in_object_type, + uint32_t in_alloc_index) const { - const void* result = nullptr; + std::unique_lock lock (m_cs); + void* result(nullptr); anvil_assert(in_object_type < OBJECT_TYPE_COUNT); @@ -164,39 +167,59 @@ void Anvil::ObjectTracker::register_object(ObjectType in_object_type, anvil_assert(in_object_ptr != nullptr); anvil_assert(in_object_type < OBJECT_TYPE_COUNT); - m_object_allocations[in_object_type].push_back(ObjectAllocation(m_n_objects_allocated_array[in_object_type]++, - in_object_ptr) ); + { + std::unique_lock lock(m_cs); + + m_object_allocations[in_object_type].push_back(ObjectAllocation(m_n_objects_allocated_array[in_object_type]++, + in_object_ptr) ); + } /* Notify any observers about the new object */ - ObjectTrackerOnObjectRegisteredCallbackArg callback_arg(in_object_type, - in_object_ptr); + OnObjectRegisteredCallbackArgument callback_arg(in_object_type, + in_object_ptr); - callback(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, - &callback_arg); + callback_safe(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, + &callback_arg); } /* Please see header for specification */ void Anvil::ObjectTracker::unregister_object(ObjectType in_object_type, void* in_object_ptr) { - ObjectTrackerOnObjectAboutToBeUnregisteredCallbackArg callback_arg (in_object_type, - in_object_ptr); - auto object_allocation_iterator(std::find(m_object_allocations[in_object_type].begin(), - m_object_allocations[in_object_type].end(), - in_object_ptr) ); + OnObjectAboutToBeUnregisteredCallbackArgument callback_arg(in_object_type, + in_object_ptr); - if (object_allocation_iterator == m_object_allocations[in_object_type].end() ) { - anvil_assert_fail(); + std::unique_lock lock (m_cs); + auto object_allocation_iterator(std::find(m_object_allocations[in_object_type].begin(), + m_object_allocations[in_object_type].end(), + in_object_ptr) ); + + if (object_allocation_iterator == m_object_allocations[in_object_type].end() ) + { + anvil_assert_fail(); - goto end; + goto end; + } + + m_object_allocations[in_object_type].erase(object_allocation_iterator); } - m_object_allocations[in_object_type].erase(object_allocation_iterator); + /* Notify any observers about the event. */ + if (in_object_type == OBJECT_TYPE_DEVICE) + { + callback_safe(OBJECT_TRACKER_CALLBACK_ID_ON_DEVICE_OBJECT_ABOUT_TO_BE_UNREGISTERED, + &callback_arg); + } + else + if (in_object_type == OBJECT_TYPE_PIPELINE_LAYOUT) + { + callback_safe(OBJECT_TRACKER_CALLBACK_ID_ON_PIPELINE_LAYOUT_OBJECT_ABOUT_TO_BE_UNREGISTERED, + &callback_arg); + } - /* Notify any observers about the event */ - callback(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, - &callback_arg); + callback_safe(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, + &callback_arg); end: ; diff --git a/src/misc/shader_module_cache.cpp b/src/misc/shader_module_cache.cpp index a278cedb..017746c8 100644 --- a/src/misc/shader_module_cache.cpp +++ b/src/misc/shader_module_cache.cpp @@ -27,7 +27,7 @@ /** Please see header for documentation */ Anvil::ShaderModuleCache::ShaderModuleCache() { - /* Stub */ + update_subscriptions(true); } /** Please see header for documentation */ @@ -35,14 +35,7 @@ Anvil::ShaderModuleCache::~ShaderModuleCache() { std::unique_lock lock(m_cs); { - auto object_tracker_ptr = Anvil::ObjectTracker::get(); - - object_tracker_ptr->unregister_from_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, - on_object_about_to_be_released, - this); - object_tracker_ptr->unregister_from_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, - on_object_registered, - this); + update_subscriptions(false); } } @@ -130,22 +123,12 @@ void Anvil::ShaderModuleCache::cache(std::shared_ptr in_sha std::shared_ptr Anvil::ShaderModuleCache::create() { - auto object_tracker_ptr = Anvil::ObjectTracker::get(); std::shared_ptr result_ptr; result_ptr.reset( new Anvil::ShaderModuleCache() ); - /* Sign up for object creation / release notifications. We're going to need this in order to cache shader module instances - * which are created by the app. */ - object_tracker_ptr->register_for_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, - on_object_about_to_be_released, - result_ptr.get() ); - object_tracker_ptr->register_for_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, - on_object_registered, - result_ptr.get() ); - return result_ptr; } @@ -237,15 +220,11 @@ size_t Anvil::ShaderModuleCache::get_hash(const char* in_spirv_blob, } /** TODO */ -void Anvil::ShaderModuleCache::on_object_about_to_be_released(void* in_callback_arg, - void* in_shader_module_cache_raw_ptr) +void Anvil::ShaderModuleCache::on_object_about_to_be_released(CallbackArgument* in_callback_arg_ptr) { - const Anvil::ObjectTrackerOnObjectAboutToBeUnregisteredCallbackArg* callback_arg_ptr = static_cast(in_callback_arg); - Anvil::ShaderModuleCache* shader_module_cache_ptr = static_cast (in_shader_module_cache_raw_ptr); + const Anvil::OnObjectAboutToBeUnregisteredCallbackArgument* callback_arg_ptr = dynamic_cast(in_callback_arg_ptr); - anvil_assert (callback_arg_ptr != nullptr); - anvil_assert (shader_module_cache_ptr != nullptr); - ANVIL_REDUNDANT_VARIABLE(shader_module_cache_ptr); + anvil_assert(callback_arg_ptr != nullptr); if (callback_arg_ptr->object_type == OBJECT_TYPE_SHADER_MODULE) { @@ -259,19 +238,47 @@ void Anvil::ShaderModuleCache::on_object_about_to_be_released(void* in_callback_ } /** TODO */ -void Anvil::ShaderModuleCache::on_object_registered(void* in_callback_arg, - void* in_shader_module_cache_raw_ptr) +void Anvil::ShaderModuleCache::on_object_registered(CallbackArgument* in_callback_arg_ptr) { - const Anvil::ObjectTrackerOnObjectRegisteredCallbackArg* callback_arg_ptr = static_cast(in_callback_arg); - Anvil::ShaderModuleCache* shader_module_cache_ptr = static_cast (in_shader_module_cache_raw_ptr); + const auto callback_arg_ptr = dynamic_cast(in_callback_arg_ptr); - anvil_assert(callback_arg_ptr != nullptr); - anvil_assert(shader_module_cache_ptr != nullptr); + anvil_assert(callback_arg_ptr != nullptr); if (callback_arg_ptr->object_type == OBJECT_TYPE_SHADER_MODULE) { auto shader_module_ptr = static_cast(callback_arg_ptr->object_raw_ptr); - shader_module_cache_ptr->cache(shader_module_ptr->shared_from_this() ); + cache(shader_module_ptr->shared_from_this() ); + } +} + +void Anvil::ShaderModuleCache::update_subscriptions(bool in_should_init) +{ + auto object_tracker_ptr = Anvil::ObjectTracker::get(); + + auto on_object_about_to_be_released_func = std::bind(&ShaderModuleCache::on_object_about_to_be_released, + this, + std::placeholders::_1); + auto on_object_registered_func = std::bind(&ShaderModuleCache::on_object_registered, + this, + std::placeholders::_1); + + if (in_should_init) + { + object_tracker_ptr->register_for_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, + on_object_about_to_be_released_func, + this); + object_tracker_ptr->register_for_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, + on_object_registered_func, + this); + } + else + { + object_tracker_ptr->unregister_from_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, + on_object_about_to_be_released_func, + this); + object_tracker_ptr->unregister_from_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_REGISTERED, + on_object_registered_func, + this); } -} \ No newline at end of file +} diff --git a/src/misc/types.cpp b/src/misc/types.cpp index 66665ddb..daba6c09 100644 --- a/src/misc/types.cpp +++ b/src/misc/types.cpp @@ -1738,7 +1738,8 @@ void Anvil::Utils::convert_queue_family_bits_to_family_indices(std::weak_ptr Anvil::WindowFactory::create_window(WindowPlatform in_platform, - const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +std::shared_ptr Anvil::WindowFactory::create_window(WindowPlatform in_platform, + const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + PresentCallbackFunction in_present_callback_func) { std::shared_ptr result_ptr; @@ -38,8 +38,7 @@ std::shared_ptr Anvil::WindowFactory::create_window(WindowPlatfor result_ptr = Anvil::DummyWindow::create(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg); + in_present_callback_func); break; } @@ -49,8 +48,7 @@ std::shared_ptr Anvil::WindowFactory::create_window(WindowPlatfor result_ptr = Anvil::DummyWindowWithPNGSnapshots::create(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg); + in_present_callback_func); break; } @@ -63,8 +61,8 @@ std::shared_ptr Anvil::WindowFactory::create_window(WindowPlatfor result_ptr = Anvil::WindowWin3264::create(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg); + in_closable, + in_present_callback_func); break; } @@ -76,8 +74,8 @@ std::shared_ptr Anvil::WindowFactory::create_window(WindowPlatfor result_ptr = Anvil::WindowXcb::create(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg); + in_closable, + in_present_callback_func); break; } diff --git a/src/misc/window_win3264.cpp b/src/misc/window_win3264.cpp index 127191b2..f27ddac6 100644 --- a/src/misc/window_win3264.cpp +++ b/src/misc/window_win3264.cpp @@ -21,55 +21,55 @@ // #include "misc/window_win3264.h" +#include #define WM_DESTROY_WINDOW (WM_USER + 1) /* See create() for documentation */ -Anvil::WindowWin3264::WindowWin3264(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +Anvil::WindowWin3264::WindowWin3264(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func) :Window(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_closable, + in_present_callback_func) { m_window_owned = true; } /* See create() for documentation */ -Anvil::WindowWin3264::WindowWin3264(HWND in_handle, - const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +Anvil::WindowWin3264::WindowWin3264(HWND in_handle, + const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + Anvil::PresentCallbackFunction in_present_callback_func) :Window(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + true, /* in_closable */ + in_present_callback_func) { m_window = in_handle; m_window_owned = false; } /** Please see header for specification */ -std::shared_ptr Anvil::WindowWin3264::create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +std::shared_ptr Anvil::WindowWin3264::create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func) { std::shared_ptr result_ptr( new Anvil::WindowWin3264(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_closable, + in_present_callback_func) ); if (result_ptr) @@ -130,8 +130,7 @@ std::shared_ptr Anvil::WindowWin3264::create(HWND in_window_handl std::string(&window_title.at(0) ), window_size[0], window_size[1], - nullptr, /* present_callback_func_ptr */ - nullptr) /* present_callback_func_user_arg */ + nullptr) /* present_callback_func_ptr */ ); if (result_ptr) @@ -166,20 +165,23 @@ void Anvil::WindowWin3264::close() /** Creates a new system window and prepares it for usage. */ bool Anvil::WindowWin3264::init() { - bool result = false; + static volatile uint32_t n_windows_spawned = 0; + bool result = false; + const char* window_class_name = (m_closable) ? "Anvil window (closable)" + : "Anvil window (non-closable)"; if (m_window_owned) { - const uint32_t window_size[2] = + std::stringstream class_name_sstream; + HINSTANCE instance = ::GetModuleHandle(nullptr); + WNDCLASSEX window_class; + RECT window_rect; + const uint32_t window_size[2] = { m_width, m_height }; - static const char* class_name = "Anvil window class"; - HINSTANCE instance = ::GetModuleHandle(nullptr); - WNDCLASSEX window_class; - RECT window_rect; // Initialize the window class structure: window_class.cbSize = sizeof(WNDCLASSEX); @@ -194,11 +196,16 @@ bool Anvil::WindowWin3264::init() window_class.hCursor = ::LoadCursor(nullptr, /* hInstance */ IDC_ARROW); window_class.lpszMenuName = nullptr; - window_class.lpszClassName = class_name; + window_class.lpszClassName = window_class_name; window_class.hIconSm = ::LoadIcon(nullptr, /* hInstance */ IDI_WINLOGO); - /* Register window class. If more than one window is instantiated, this call will fail + if (!m_closable) + { + window_class.style |= CS_NOCLOSE; + } + + /* Register window class. If more than one window is instantiated, this call may fail * but we don't really care. **/ ::RegisterClassEx(&window_class); @@ -220,7 +227,7 @@ bool Anvil::WindowWin3264::init() /* NOTE: Anvil currently does not support automatic swapchain resizing so make sure the window is not scalable. */ m_window = ::CreateWindowEx(0, /* dwExStyle */ - class_name, + window_class_name, m_title.c_str(), (WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU) ^ WS_THICKFRAME, 0, /* X */ @@ -286,10 +293,13 @@ LRESULT CALLBACK Anvil::WindowWin3264::msg_callback_pfn_proc(HWND in_window_ha return 0; } + case WM_CLOSE: case WM_DESTROY_WINDOW: { + OnWindowAboutToCloseCallbackArgument callback_argument(window_ptr); + window_ptr->callback(WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, - window_ptr); + &callback_argument); ::DestroyWindow(window_ptr->m_window); @@ -298,8 +308,8 @@ LRESULT CALLBACK Anvil::WindowWin3264::msg_callback_pfn_proc(HWND in_window_ha case WM_KEYUP: { - KeypressReleasedCallbackData callback_data(window_ptr, - static_cast(LOWORD(in_param_wide) & 0xFF) ); + OnKeypressReleasedCallbackArgument callback_data(window_ptr, + static_cast(LOWORD(in_param_wide) & 0xFF) ); window_ptr->callback(WINDOW_CALLBACK_ID_KEYPRESS_RELEASED, &callback_data); @@ -338,6 +348,13 @@ void Anvil::WindowWin3264::run() 0, PM_REMOVE) ) { + if (msg.message == WM_QUIT) + { + done = 1; + + break; + } + ::TranslateMessage(&msg); ::DispatchMessage (&msg); } @@ -346,8 +363,11 @@ void Anvil::WindowWin3264::run() { done = 1; } - - m_present_callback_func_ptr(m_present_callback_func_user_arg); + else + if (m_present_callback_func != nullptr) + { + m_present_callback_func(); + } } m_window_close_finished = true; diff --git a/src/misc/window_xcb.cpp b/src/misc/window_xcb.cpp index a5e27686..8784e764 100644 --- a/src/misc/window_xcb.cpp +++ b/src/misc/window_xcb.cpp @@ -40,11 +40,11 @@ typedef struct /** Please see header for specification */ -std::shared_ptr Anvil::WindowXcb::create(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +std::shared_ptr Anvil::WindowXcb::create(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func) { std::shared_ptr result_ptr; @@ -52,8 +52,8 @@ std::shared_ptr Anvil::WindowXcb::create(const std::string& i new Anvil::WindowXcb(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_closable, + in_present_callback_func) ); if (result_ptr) @@ -89,16 +89,16 @@ std::shared_ptr Anvil::WindowXcb::create(xcb_connection_t* in_con } /** Please see header for specification */ -Anvil::WindowXcb::WindowXcb(const std::string& in_title, - unsigned int in_width, - unsigned int in_height, - PFNPRESENTCALLBACKPROC in_present_callback_func_ptr, - void* in_present_callback_func_user_arg) +Anvil::WindowXcb::WindowXcb(const std::string& in_title, + unsigned int in_width, + unsigned int in_height, + bool in_closable, + Anvil::PresentCallbackFunction in_present_callback_func) :Window(in_title, in_width, in_height, - in_present_callback_func_ptr, - in_present_callback_func_user_arg) + in_closable, + in_present_callback_func) { m_connection_ptr = nullptr; m_window_owned = true; @@ -108,10 +108,10 @@ Anvil::WindowXcb::WindowXcb(const std::string& in_title, Anvil::WindowXcb::WindowXcb(xcb_connection_t* in_connection_ptr, WindowHandle in_window_handle) :Window("", - 0, /* width */ - 0, /* height */ - nullptr, /* present_callback_func_ptr */ - nullptr) /* present_callback_func_user_arg */ + 0, /* in_width */ + 0, /* in_height */ + true, /* in_closable */ + nullptr) /* in_present_callback_func */ { /* NOTE: Window title/size info is extracted at init time */ m_connection_ptr = in_connection_ptr; @@ -142,8 +142,10 @@ void Anvil::WindowXcb::close() if (!m_window_should_close) { + OnWindowAboutToCloseCallbackArgument callback_argument(this); + callback(WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, - this); + &callback_argument); m_window_should_close = true; @@ -365,7 +367,8 @@ void Anvil::WindowXcb::run() { case XCB_CLIENT_MESSAGE: { - if (reinterpret_cast(event_ptr)->data.data32[0] == m_atom_wm_delete_window_ptr->atom) + if (reinterpret_cast(event_ptr)->data.data32[0] == m_atom_wm_delete_window_ptr->atom && + m_closable) { running = false; } @@ -382,11 +385,11 @@ void Anvil::WindowXcb::run() const_cast(key_ptr), 0); - KeypressReleasedCallbackData callback_data(this, - static_cast(sym)); + OnKeypressReleasedCallbackArgument callback_argument(this, + static_cast(sym)); - this->callback(WINDOW_CALLBACK_ID_KEYPRESS_RELEASED, - &callback_data); + callback(WINDOW_CALLBACK_ID_KEYPRESS_RELEASED, + &callback_argument); break; } @@ -400,7 +403,10 @@ void Anvil::WindowXcb::run() case XCB_EXPOSE: { - m_present_callback_func_ptr(m_present_callback_func_user_arg); + if (m_present_callback_func != nullptr) + { + m_present_callback_func(); + } running = !m_window_should_close; break; @@ -416,7 +422,10 @@ void Anvil::WindowXcb::run() } else { - m_present_callback_func_ptr(m_present_callback_func_user_arg); + if (m_present_callback_func != nullptr) + { + m_present_callback_func(); + } running = !m_window_should_close; } diff --git a/src/misc/xcb_loader.cpp b/src/misc/xcb_loader.cpp index 6daabbed..7d207ca8 100644 --- a/src/misc/xcb_loader.cpp +++ b/src/misc/xcb_loader.cpp @@ -60,8 +60,8 @@ Result XCBLoader::init() if (m_initialized == false) { - // resolve symbols from libxcb-keysyms.so - m_library_handles[XCB_LOADER_LIBRARIES_XCB_KEYSYMS] = dlopen("libxcb-keysyms.so", + // resolve symbols from libxcb-keysyms.so.1 + m_library_handles[XCB_LOADER_LIBRARIES_XCB_KEYSYMS] = dlopen("libxcb-keysyms.so.1", RTLD_LAZY); if (m_library_handles[XCB_LOADER_LIBRARIES_XCB_KEYSYMS] == nullptr) @@ -76,8 +76,8 @@ Result XCBLoader::init() "xcb_key_release_lookup_keysym") ); } - // resolve symbols from libxcb.so - m_library_handles[XCB_LOADER_LIBRARIES_XCB] = dlopen("libxcb.so", + // resolve symbols from libxcb.so.1 + m_library_handles[XCB_LOADER_LIBRARIES_XCB] = dlopen("libxcb.so.1", RTLD_LAZY); if (m_library_handles[XCB_LOADER_LIBRARIES_XCB] == nullptr) diff --git a/src/wrappers/buffer.cpp b/src/wrappers/buffer.cpp index 042f4d52..b9780725 100644 --- a/src/wrappers/buffer.cpp +++ b/src/wrappers/buffer.cpp @@ -436,7 +436,7 @@ std::shared_ptr Anvil::Buffer::get_memory_block(uint32_t in_ if (m_is_sparse) { - BufferCallbackIsAllocPendingQueryData callback_arg(shared_from_this() ); + IsBufferMemoryAllocPendingQueryCallbackArgument callback_arg(shared_from_this() ); callback(BUFFER_CALLBACK_ID_IS_ALLOC_PENDING, &callback_arg); @@ -450,10 +450,12 @@ std::shared_ptr Anvil::Buffer::get_memory_block(uint32_t in_ if (is_callback_needed) { + OnMemoryBlockNeededForBufferCallbackArgument callback_argument(shared_from_this() ); + anvil_assert(m_parent_buffer_ptr == nullptr); callback_safe(BUFFER_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - nullptr); + &callback_argument); } if (m_is_sparse) @@ -523,7 +525,7 @@ bool Anvil::Buffer::read(VkDeviceSize in_start_offset, m_device_ptr, in_size, staging_buffer_queue_fam_bits, - VK_SHARING_MODE_EXCLUSIVE, + VK_SHARING_MODE_CONCURRENT, VK_BUFFER_USAGE_TRANSFER_DST_BIT, MEMORY_FEATURE_FLAG_MAPPABLE, nullptr); @@ -727,13 +729,6 @@ bool Anvil::Buffer::write(VkDeviceSize in_start_offset, else { /* We can use any queue from the list of queue fams this buffer is compatible, in order to perform the copy op. */ - if ((m_queue_families & Anvil::QUEUE_FAMILY_DMA_BIT) != 0) - { - queue_ptr = base_device_locked_ptr->get_transfer_queue(0); - staging_buffer_queue_fam_bits = Anvil::QUEUE_FAMILY_DMA_BIT; - staging_buffer_queue_fam_type = Anvil::QUEUE_FAMILY_TYPE_TRANSFER; - } - else if ((m_queue_families & Anvil::QUEUE_FAMILY_GRAPHICS_BIT) != 0) { queue_ptr = base_device_locked_ptr->get_universal_queue(0); @@ -741,6 +736,13 @@ bool Anvil::Buffer::write(VkDeviceSize in_start_offset, staging_buffer_queue_fam_type = Anvil::QUEUE_FAMILY_TYPE_UNIVERSAL; } else + if ((m_queue_families & Anvil::QUEUE_FAMILY_DMA_BIT) != 0) + { + queue_ptr = base_device_locked_ptr->get_transfer_queue(0); + staging_buffer_queue_fam_bits = Anvil::QUEUE_FAMILY_DMA_BIT; + staging_buffer_queue_fam_type = Anvil::QUEUE_FAMILY_TYPE_TRANSFER; + } + else { anvil_assert((m_queue_families & Anvil::QUEUE_FAMILY_COMPUTE_BIT) != 0) @@ -763,7 +765,7 @@ bool Anvil::Buffer::write(VkDeviceSize in_start_offset, m_device_ptr, in_size, staging_buffer_queue_fam_bits, - VK_SHARING_MODE_EXCLUSIVE, + VK_SHARING_MODE_CONCURRENT, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, Anvil::MEMORY_FEATURE_FLAG_MAPPABLE, in_data); @@ -778,16 +780,32 @@ bool Anvil::Buffer::write(VkDeviceSize in_start_offset, copy_cmdbuf_ptr->start_recording(true, /* one_time_submit */ false); /* simultaneous_use_allowed */ { - VkBufferCopy copy_region; + BufferBarrier buffer_barrier(VK_ACCESS_HOST_WRITE_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED, + staging_buffer_ptr, + 0, /* in_offset */ + staging_buffer_ptr->get_size() ); + VkBufferCopy copy_region; copy_region.dstOffset = in_start_offset; copy_region.size = in_size; copy_region.srcOffset = 0; - copy_cmdbuf_ptr->record_copy_buffer(staging_buffer_ptr, - shared_from_this(), - 1, /* in_region_count */ - ©_region); + copy_cmdbuf_ptr->record_pipeline_barrier(VK_PIPELINE_STAGE_HOST_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_FALSE, /* in_by_region */ + 0, /* in_memory_barrier_count */ + nullptr, /* in_memory_barriers_ptr */ + 1, /* in_buffer_memory_barrier_count */ + &buffer_barrier, + 0, /* in_image_memory_barrier_count */ + nullptr); /* in_image_memory_barriers_ptr */ + copy_cmdbuf_ptr->record_copy_buffer (staging_buffer_ptr, + shared_from_this(), + 1, /* in_region_count */ + ©_region); } copy_cmdbuf_ptr->stop_recording(); diff --git a/src/wrappers/command_buffer.cpp b/src/wrappers/command_buffer.cpp index 214ef2fd..44a9afbe 100644 --- a/src/wrappers/command_buffer.cpp +++ b/src/wrappers/command_buffer.cpp @@ -1373,7 +1373,7 @@ bool Anvil::CommandBufferBase::record_bind_descriptor_sets(VkPipelineBindPoint const uint32_t* in_dynamic_offset_ptrs) { /* Note: Command supported inside and outside the renderpass. */ - VkDescriptorSet dss_vk[16]; + VkDescriptorSet dss_vk[100]; bool result = false; anvil_assert(in_set_count < sizeof(dss_vk) / sizeof(dss_vk[0]) ); @@ -1512,7 +1512,7 @@ bool Anvil::CommandBufferBase::record_bind_vertex_buffers(uint32_t const VkDeviceSize* in_offset_ptrs) { /* Note: Command supported inside and outside the renderpass. */ - VkBuffer buffers[16]; + VkBuffer buffers[100]; bool result = false; anvil_assert(in_binding_count < sizeof(buffers) / sizeof(buffers[0]) ); @@ -2647,9 +2647,9 @@ bool Anvil::CommandBufferBase::record_pipeline_barrier(VkPipelineStageFlags const ImageBarrier* const in_image_memory_barriers_ptr) { /* NOTE: The command can be executed both inside and outside a renderpass */ - VkBufferMemoryBarrier buffer_barriers_vk[16]; - VkImageMemoryBarrier image_barriers_vk [16]; - VkMemoryBarrier memory_barriers_vk[16]; + VkBufferMemoryBarrier buffer_barriers_vk[100]; + VkImageMemoryBarrier image_barriers_vk [100]; + VkMemoryBarrier memory_barriers_vk[100]; bool result = false; if (!m_recording_in_progress) @@ -2678,17 +2678,17 @@ bool Anvil::CommandBufferBase::record_pipeline_barrier(VkPipelineStageFlags if (get_n_of_callback_subscribers(COMMAND_BUFFER_CALLBACK_ID_PIPELINE_BARRIER_COMMAND_RECORDED) > 0) { - PipelineBarrierCommand command_data(in_src_stage_mask, - in_dst_stage_mask, - in_by_region, - in_memory_barrier_count, - in_memory_barriers_ptr, - in_buffer_memory_barrier_count, - in_buffer_memory_barriers_ptr, - in_image_memory_barrier_count, - in_image_memory_barriers_ptr); - PipelineBarrierCommandRecordedCallbackData callback_data(this, - &command_data); + PipelineBarrierCommand command_data(in_src_stage_mask, + in_dst_stage_mask, + in_by_region, + in_memory_barrier_count, + in_memory_barriers_ptr, + in_buffer_memory_barrier_count, + in_buffer_memory_barriers_ptr, + in_image_memory_barrier_count, + in_image_memory_barriers_ptr); + OnPipelineBarrierCommandRecordedCallbackData callback_data(this, + &command_data); callback(COMMAND_BUFFER_CALLBACK_ID_PIPELINE_BARRIER_COMMAND_RECORDED, &callback_data); @@ -3322,10 +3322,10 @@ bool Anvil::CommandBufferBase::record_wait_events(uint32_t { /* NOTE: The command can be executed both inside and outside a renderpass */ - VkEvent events [16]; - VkBufferMemoryBarrier buffer_barriers_vk[16]; - VkImageMemoryBarrier image_barriers_vk [16]; - VkMemoryBarrier memory_barriers_vk[16]; + VkEvent events [100]; + VkBufferMemoryBarrier buffer_barriers_vk[100]; + VkImageMemoryBarrier image_barriers_vk [100]; + VkMemoryBarrier memory_barriers_vk[100]; bool result = false; anvil_assert(in_event_count > 0); /* as per spec - easy to miss */ @@ -3649,7 +3649,7 @@ bool Anvil::PrimaryCommandBuffer::record_execute_commands(uint32_t std::shared_ptr* in_cmd_buffer_ptrs) { /* NOTE: The command can be executed both inside and outside a renderpass */ - VkCommandBuffer cmd_buffers[16]; + VkCommandBuffer cmd_buffers[100]; bool result = false; anvil_assert(in_cmd_buffers_count < sizeof(cmd_buffers) / sizeof(cmd_buffers[0]) ); @@ -3817,9 +3817,6 @@ bool Anvil::SecondaryCommandBuffer::start_recording(bool bool result = false; VkResult result_vk; - anvil_assert((in_occlusion_query_used_by_primary_command_buffer && in_required_occlusion_query_support_scope == OCCLUSION_QUERY_SUPPORT_SCOPE_NOT_REQUIRED) || - !in_occlusion_query_used_by_primary_command_buffer); - if (m_recording_in_progress) { anvil_assert(!m_recording_in_progress); @@ -3828,11 +3825,12 @@ bool Anvil::SecondaryCommandBuffer::start_recording(bool } command_buffer_inheritance_info.framebuffer = (in_framebuffer_ptr != nullptr) ? in_framebuffer_ptr->get_framebuffer(in_render_pass_ptr) : VK_NULL_HANDLE; - command_buffer_inheritance_info.occlusionQueryEnable = (!in_occlusion_query_used_by_primary_command_buffer) ? VK_TRUE : VK_FALSE; + command_buffer_inheritance_info.occlusionQueryEnable = (in_occlusion_query_used_by_primary_command_buffer) ? VK_TRUE : VK_FALSE; command_buffer_inheritance_info.pipelineStatistics = in_required_pipeline_statistics_scope; command_buffer_inheritance_info.pNext = nullptr; - command_buffer_inheritance_info.queryFlags = (in_required_occlusion_query_support_scope == OCCLUSION_QUERY_SUPPORT_SCOPE_REQUIRED_PRECISE) ? VK_QUERY_CONTROL_PRECISE_BIT : 0u; - command_buffer_inheritance_info.renderPass = (in_render_pass_ptr != nullptr) ? in_render_pass_ptr->get_render_pass() : VK_NULL_HANDLE; + command_buffer_inheritance_info.queryFlags = (in_occlusion_query_used_by_primary_command_buffer && + in_required_occlusion_query_support_scope == OCCLUSION_QUERY_SUPPORT_SCOPE_REQUIRED_PRECISE) ? VK_QUERY_CONTROL_PRECISE_BIT : 0u; + command_buffer_inheritance_info.renderPass = (in_render_pass_ptr != nullptr) ? in_render_pass_ptr->get_render_pass() : VK_NULL_HANDLE; command_buffer_inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; command_buffer_inheritance_info.subpass = in_subpass_id; diff --git a/src/wrappers/descriptor_pool.cpp b/src/wrappers/descriptor_pool.cpp index 1a5cf077..fe1526ef 100644 --- a/src/wrappers/descriptor_pool.cpp +++ b/src/wrappers/descriptor_pool.cpp @@ -247,8 +247,10 @@ bool Anvil::DescriptorPool::reset() { /* Alloced descriptor sets went out of scope. Send out a call-back, so that descriptor set * wrapper instances can mark themselves as unusable */ + OnDescriptorPoolResetCallbackArgument callback_argument(this); + callback(DESCRIPTOR_POOL_CALLBACK_ID_POOL_RESET, - this); + &callback_argument); } } else diff --git a/src/wrappers/descriptor_set.cpp b/src/wrappers/descriptor_set.cpp index 575c2a71..ec2caa94 100644 --- a/src/wrappers/descriptor_set.cpp +++ b/src/wrappers/descriptor_set.cpp @@ -261,12 +261,19 @@ Anvil::DescriptorSet::DescriptorSet(std::weak_ptr { alloc_bindings(); - in_layout_ptr->register_for_callbacks (Anvil::DESCRIPTOR_SET_LAYOUT_CALLBACK_ID_BINDING_ADDED, - on_binding_added_to_layout, - this); - m_parent_pool_ptr->register_for_callbacks(Anvil::DESCRIPTOR_POOL_CALLBACK_ID_POOL_RESET, - on_parent_pool_reset, - this); + in_layout_ptr->register_for_callbacks( + Anvil::DESCRIPTOR_SET_LAYOUT_CALLBACK_ID_BINDING_ADDED, + std::bind(&DescriptorSet::on_binding_added_to_layout, + this), + this + ); + + m_parent_pool_ptr->register_for_callbacks( + Anvil::DESCRIPTOR_POOL_CALLBACK_ID_POOL_RESET, + std::bind(&DescriptorSet::on_parent_pool_reset, + this), + this + ); Anvil::ObjectTracker::get()->register_object(Anvil::OBJECT_TYPE_DESCRIPTOR_SET, this); @@ -758,42 +765,26 @@ bool Anvil::DescriptorSet::get_storage_texel_buffer_binding_properties(uint32_t * This will resize a number of internally managed vectors. * * @param layout_raw_ptr Ignored. - * @param ds_raw_ptr Pointer to a DescriptorSet instance which uses the modified layout as the parent. - * Never nullptr. * **/ -void Anvil::DescriptorSet::on_binding_added_to_layout(void* in_layout_raw_ptr, - void* in_ds_raw_ptr) +void Anvil::DescriptorSet::on_binding_added_to_layout() { - Anvil::DescriptorSet* ds_ptr = static_cast(in_ds_raw_ptr); - - ANVIL_REDUNDANT_ARGUMENT(in_layout_raw_ptr); - - ds_ptr->alloc_bindings(); + alloc_bindings(); } /** Called back whenever parent descriptor pool is reset. * * Resets m_descriptor_set back to VK_NULL_HANDLE and marks the descriptor set as unusable. * - * @param pool_raw_ptr Ignored. - * @param ds_raw_ptr Affected DescriptorSet instance. Never nullptr. - * **/ -void Anvil::DescriptorSet::on_parent_pool_reset(void* in_pool_raw_ptr, - void* in_ds_raw_ptr) +void Anvil::DescriptorSet::on_parent_pool_reset() { - Anvil::DescriptorSet* ds_ptr = static_cast(in_ds_raw_ptr); - - ANVIL_REDUNDANT_ARGUMENT(in_ds_raw_ptr); - ANVIL_REDUNDANT_ARGUMENT(in_pool_raw_ptr); - /* This descriptor set instance is no longer usable. * * To restore functionality, a new Vulkan DS handle should be assigned to this instance * by calling set_new_vk_handle() */ - ds_ptr->m_descriptor_set = VK_NULL_HANDLE; - ds_ptr->m_unusable = true; + m_descriptor_set = VK_NULL_HANDLE; + m_unusable = true; } /** Please see header for specification */ diff --git a/src/wrappers/descriptor_set_layout.cpp b/src/wrappers/descriptor_set_layout.cpp index d42438ea..6f8a5e9e 100644 --- a/src/wrappers/descriptor_set_layout.cpp +++ b/src/wrappers/descriptor_set_layout.cpp @@ -93,8 +93,13 @@ bool Anvil::DescriptorSetLayout::add_binding(uint32_t in_stage_flags, in_immutable_sampler_ptrs); - callback(DESCRIPTOR_SET_LAYOUT_CALLBACK_ID_BINDING_ADDED, - this); + { + OnNewBindingAddedToDescriptorSetLayoutCallbackArgument callback_argument(this); + + callback(DESCRIPTOR_SET_LAYOUT_CALLBACK_ID_BINDING_ADDED, + &callback_argument); + + } m_dirty = true; result = true; diff --git a/src/wrappers/device.cpp b/src/wrappers/device.cpp index 21a19a0b..ea0599da 100644 --- a/src/wrappers/device.cpp +++ b/src/wrappers/device.cpp @@ -95,7 +95,8 @@ void Anvil::BaseDevice::destroy() m_pipeline_layout_manager_ptr = nullptr; /* Proceed with device-specific instances */ - m_queue_fams.clear(); + m_queue_fams.clear (); + m_sparse_binding_queues.clear(); for (Anvil::QueueFamilyType queue_family_type = Anvil::QUEUE_FAMILY_TYPE_FIRST; queue_family_type < Anvil::QUEUE_FAMILY_TYPE_COUNT + 1; @@ -956,6 +957,15 @@ bool Anvil::SGPUDevice::get_physical_device_sparse_image_format_properties(VkFor return true; } +/* Please see header for specification */ +bool Anvil::SGPUDevice::get_physical_device_surface_capabilities(std::shared_ptr in_surface_ptr, + VkSurfaceCapabilitiesKHR* out_result_ptr) const +{ + return (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_parent_physical_device_ptr.lock()->get_physical_device(), + in_surface_ptr->get_surface(), + out_result_ptr) == VK_SUCCESS); +} + /* Please see header for specification */ void Anvil::SGPUDevice::get_queue_family_indices(DeviceQueueFamilyInfo* out_device_queue_family_info_ptr) const { diff --git a/src/wrappers/framebuffer.cpp b/src/wrappers/framebuffer.cpp index dafc47b8..12ee1a6b 100644 --- a/src/wrappers/framebuffer.cpp +++ b/src/wrappers/framebuffer.cpp @@ -113,9 +113,13 @@ Anvil::Framebuffer::~Framebuffer() nullptr /* pAllocator */); /* Carry on and release the renderpass the framebuffer had been baked for */ - fb_iterator->first->unregister_from_callbacks(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, - on_renderpass_changed, - this); + fb_iterator->first->unregister_from_callbacks( + RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, + std::bind(&Framebuffer::on_renderpass_changed, + this, + std::placeholders::_1), + this + ); } m_baked_framebuffers.clear(); @@ -267,9 +271,13 @@ bool Anvil::Framebuffer::bake(std::shared_ptr in_render_pass_ } /* If the render pass is ever changed, make sure we re-bake the framebuffer when needed */ - in_render_pass_ptr->register_for_callbacks(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, - &on_renderpass_changed, - this); + in_render_pass_ptr->register_for_callbacks( + RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, + std::bind(&Framebuffer::on_renderpass_changed, + this, + std::placeholders::_1), + this + ); /* All done */ result = true; @@ -386,20 +394,16 @@ void Anvil::Framebuffer::get_size(uint32_t* out_framebuffer_width_ptr, * * Marks the framebuffer as dirty, forcing the framebuffer to be rebaked next time it is used. * - * @param in_raw_renderpass_ptr RenderPass instance which has invoked the call-back. Never nullptr. - * @param in_raw_framebuffer_ptr Framebuffer instance this call-back is fired against. Never nullptr. - * **/ -void Anvil::Framebuffer::on_renderpass_changed(void* in_raw_renderpass_ptr, - void* in_raw_framebuffer_ptr) +void Anvil::Framebuffer::on_renderpass_changed(CallbackArgument* in_callback_argument_ptr) { - Framebuffer* framebuffer_ptr = reinterpret_cast(in_raw_framebuffer_ptr); - std::shared_ptr renderpass_ptr = std::shared_ptr (reinterpret_cast(in_raw_renderpass_ptr), - Anvil::NullDeleter() ); + auto callback_argument_ptr = dynamic_cast(in_callback_argument_ptr); + auto renderpass_ptr = std::shared_ptr (callback_argument_ptr->renderpass_ptr, + Anvil::NullDeleter() ); - auto baked_fb_iterator = framebuffer_ptr->m_baked_framebuffers.find(renderpass_ptr); + auto baked_fb_iterator = m_baked_framebuffers.find(renderpass_ptr); - if (baked_fb_iterator == framebuffer_ptr->m_baked_framebuffers.end() ) + if (baked_fb_iterator == m_baked_framebuffers.end() ) { anvil_assert_fail(); diff --git a/src/wrappers/graphics_pipeline_manager.cpp b/src/wrappers/graphics_pipeline_manager.cpp index ae40e739..e658396a 100644 --- a/src/wrappers/graphics_pipeline_manager.cpp +++ b/src/wrappers/graphics_pipeline_manager.cpp @@ -969,12 +969,11 @@ bool Anvil::GraphicsPipelineManager::bake() graphics_pipeline_create_info.flags |= ((current_pipeline_ptr->allow_derivatives) ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT : 0) | ((current_pipeline_ptr->disable_optimizations) ? VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT : 0); - if (current_pipeline_config_ptr->pfn_pipeline_prebake_callback_proc != nullptr) + if (current_pipeline_config_ptr->pre_bake_function != nullptr) { - current_pipeline_config_ptr->pfn_pipeline_prebake_callback_proc(m_device_ptr, - current_pipeline_id, - &graphics_pipeline_create_info, - current_pipeline_config_ptr->pipeline_prebake_callback_user_arg); + current_pipeline_config_ptr->pre_bake_function(m_device_ptr, + current_pipeline_id, + &graphics_pipeline_create_info); } /* Stash the descriptor for now. We will issue one expensive vkCreateGraphicsPipelines() call after all pipeline objects @@ -1036,11 +1035,10 @@ bool Anvil::GraphicsPipelineManager::bake() continue; } - if (m_pipeline_configurations[bake_item_iterator->pipeline_id]->pfn_pipeline_postbake_callback_proc != nullptr) + if (m_pipeline_configurations[bake_item_iterator->pipeline_id]->post_bake_function != nullptr) { - m_pipeline_configurations[bake_item_iterator->pipeline_id]->pfn_pipeline_postbake_callback_proc(m_device_ptr, - bake_item_iterator->pipeline_id, - m_pipeline_configurations[bake_item_iterator->pipeline_id]->pipeline_postbake_callback_user_arg); + m_pipeline_configurations[bake_item_iterator->pipeline_id]->post_bake_function(m_device_ptr, + bake_item_iterator->pipeline_id); } } @@ -2646,9 +2644,8 @@ void Anvil::GraphicsPipelineManager::set_multisampling_properties(GraphicsPipeli } /* Please see header for specification */ -bool Anvil::GraphicsPipelineManager::set_pipeline_post_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, - PFNPIPELINEPOSTBAKECALLBACKPROC in_pfn_pipeline_post_bake_proc, - void* in_user_arg) +bool Anvil::GraphicsPipelineManager::set_pipeline_post_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, + PipelinePostBakeFunction in_pipeline_post_bake_function) { bool result = false; @@ -2669,18 +2666,16 @@ bool Anvil::GraphicsPipelineManager::set_pipeline_post_bake_callback(GraphicsPip pipeline_config_ptr = pipeline_config_iterator->second; } - pipeline_config_ptr->pfn_pipeline_postbake_callback_proc = in_pfn_pipeline_post_bake_proc; - pipeline_config_ptr->pipeline_postbake_callback_user_arg = in_user_arg; + pipeline_config_ptr->post_bake_function = in_pipeline_post_bake_function; + result = true; - result = true; end: return result; } /* Please see header for specification */ -bool Anvil::GraphicsPipelineManager::set_pipeline_pre_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, - PFNPIPELINEPREBAKECALLBACKPROC in_pfn_pipeline_pre_bake_proc, - void* in_user_arg) +bool Anvil::GraphicsPipelineManager::set_pipeline_pre_bake_callback(GraphicsPipelineID in_graphics_pipeline_id, + PipelinePreBakeFunction in_pfn_pipeline_pre_bake_function) { bool result = false; @@ -2701,10 +2696,8 @@ bool Anvil::GraphicsPipelineManager::set_pipeline_pre_bake_callback(GraphicsPipe pipeline_config_ptr = pipeline_config_iterator->second; } - pipeline_config_ptr->pfn_pipeline_prebake_callback_proc = in_pfn_pipeline_pre_bake_proc; - pipeline_config_ptr->pipeline_prebake_callback_user_arg = in_user_arg; - - result = true; + pipeline_config_ptr->pre_bake_function = in_pfn_pipeline_pre_bake_function; + result = true; end: return result; } diff --git a/src/wrappers/image.cpp b/src/wrappers/image.cpp index 43212940..52a813bd 100644 --- a/src/wrappers/image.cpp +++ b/src/wrappers/image.cpp @@ -261,12 +261,17 @@ Anvil::Image::Image(std::weak_ptr in_device_ptr, } /** Please see header for specification */ -void Anvil::Image::change_image_layout(std::shared_ptr in_queue_ptr, - VkAccessFlags in_src_access_mask, - VkImageLayout in_src_layout, - VkAccessFlags in_dst_access_mask, - VkImageLayout in_dst_layout, - const VkImageSubresourceRange& in_subresource_range) +void Anvil::Image::change_image_layout(std::shared_ptr in_queue_ptr, + VkAccessFlags in_src_access_mask, + VkImageLayout in_src_layout, + VkAccessFlags in_dst_access_mask, + VkImageLayout in_dst_layout, + const VkImageSubresourceRange& in_subresource_range, + const uint32_t in_opt_n_wait_semaphores, + const VkPipelineStageFlags* in_opt_wait_dst_stage_mask_ptrs, + const std::shared_ptr* in_opt_wait_semaphore_ptrs, + const uint32_t in_opt_n_set_semaphores, + const std::shared_ptr* in_opt_set_semaphore_ptrs) { std::shared_ptr device_locked_ptr (m_device_ptr); Anvil::QueueFamilyType in_queue_family_type (Anvil::QUEUE_FAMILY_TYPE_UNDEFINED); @@ -307,8 +312,13 @@ void Anvil::Image::change_image_layout(std::shared_ptr in_queue_p } transition_command_buffer_ptr->stop_recording(); - in_queue_ptr->submit_command_buffer(transition_command_buffer_ptr, - true /* should_block */); + in_queue_ptr->submit_command_buffer_with_signal_wait_semaphores(transition_command_buffer_ptr, + in_opt_n_set_semaphores, + in_opt_set_semaphore_ptrs, + in_opt_n_wait_semaphores, + in_opt_wait_semaphore_ptrs, + in_opt_wait_dst_stage_mask_ptrs, + true /* should_block */); } /** Please see header for specification */ @@ -654,7 +664,7 @@ std::shared_ptr Anvil::Image::get_memory_block() if (m_is_sparse) { - ImageCallbackIsAllocPendingQueryData callback_arg(shared_from_this() ); + IsImageMemoryAllocPendingQueryCallbackArgument callback_arg(shared_from_this() ); callback(IMAGE_CALLBACK_ID_IS_ALLOC_PENDING, &callback_arg); @@ -669,8 +679,10 @@ std::shared_ptr Anvil::Image::get_memory_block() if (is_callback_needed) { + OnMemoryBlockNeededForImageCallbackArgument callback_argument(shared_from_this() ); + callback_safe(IMAGE_CALLBACK_ID_MEMORY_BLOCK_NEEDED, - this); + &callback_argument); } return m_memory_block_ptr; @@ -1365,8 +1377,8 @@ VkImageSubresourceRange Anvil::Image::get_subresource_range() const result.baseArrayLayer = 0; result.baseMipLevel = 0; - result.layerCount = m_n_layers; - result.levelCount = m_n_mipmaps; + result.layerCount = VK_REMAINING_ARRAY_LAYERS; + result.levelCount = VK_REMAINING_MIP_LEVELS; return result; } diff --git a/src/wrappers/instance.cpp b/src/wrappers/instance.cpp index 6ff991ca..5fa9178c 100644 --- a/src/wrappers/instance.cpp +++ b/src/wrappers/instance.cpp @@ -27,16 +27,14 @@ #include "wrappers/physical_device.h" /** Please see header for specification */ -Anvil::Instance::Instance(const std::string& in_app_name, - const std::string& in_engine_name, - PFNINSTANCEDEBUGCALLBACKPROC in_opt_pfn_validation_callback_proc, - void* in_validation_proc_user_arg) +Anvil::Instance::Instance(const std::string& in_app_name, + const std::string& in_engine_name, + DebugCallbackFunction in_opt_validation_callback_function) :m_app_name (in_app_name), m_debug_callback_data (0), m_engine_name (in_engine_name), m_global_layer (""), - m_pfn_validation_callback_proc(in_opt_pfn_validation_callback_proc), - m_validation_proc_user_arg (in_validation_proc_user_arg) + m_validation_callback_function(in_opt_validation_callback_function) { Anvil::ObjectTracker::get()->register_object(Anvil::OBJECT_TYPE_INSTANCE, this); @@ -60,10 +58,9 @@ Anvil::Instance::~Instance() } /** Please see header for specification */ -std::shared_ptr Anvil::Instance::create(const std::string& in_app_name, - const std::string& in_engine_name, - PFNINSTANCEDEBUGCALLBACKPROC in_opt_pfn_validation_callback_proc, - void* in_validation_proc_user_arg) +std::shared_ptr Anvil::Instance::create(const std::string& in_app_name, + const std::string& in_engine_name, + DebugCallbackFunction in_opt_validation_callback_proc) { std::shared_ptr new_instance_ptr; @@ -71,8 +68,7 @@ std::shared_ptr Anvil::Instance::create(const std::string& new Instance( in_app_name, in_engine_name, - in_opt_pfn_validation_callback_proc, - in_validation_proc_user_arg) + in_opt_validation_callback_proc) ); new_instance_ptr->init(); @@ -100,11 +96,10 @@ VkBool32 VKAPI_PTR Anvil::Instance::debug_callback_pfn_proc(VkDebugReportFlagsEX ANVIL_REDUNDANT_ARGUMENT(in_msg_code); ANVIL_REDUNDANT_ARGUMENT(in_user_data); - return instance_ptr->m_pfn_validation_callback_proc(in_message_flags, + return instance_ptr->m_validation_callback_function(in_message_flags, in_object_type, in_layer_prefix_ptr, - in_message_ptr, - instance_ptr->m_validation_proc_user_arg); + in_message_ptr); } /** Please see header for specification */ @@ -123,6 +118,8 @@ void Anvil::Instance::destroy() { m_physical_devices.back()->destroy(); } + + m_shader_module_cache_ptr.reset(); } /** Enumerates and caches all layers supported by the Vulkan Instance. */ @@ -349,7 +346,7 @@ void Anvil::Instance::init() #endif }; - if (m_pfn_validation_callback_proc != nullptr) + if (m_validation_callback_function != nullptr) { for (uint32_t n_extension = 0; n_extension < sizeof(desired_extensions_with_validation) / sizeof(desired_extensions_with_validation[0]); @@ -399,7 +396,7 @@ void Anvil::Instance::init() /* If validation is enabled and this is a layer which issues debug call-backs, cache it, so that * we can request for it at vkCreateInstance() call time */ - if (m_pfn_validation_callback_proc != nullptr && + if (m_validation_callback_function != nullptr && std::find(layer_extensions.begin(), layer_extensions.end(), VK_EXT_DEBUG_REPORT_EXTENSION_NAME) != layer_extensions.end() ) @@ -440,7 +437,7 @@ void Anvil::Instance::init() /* Continue initializing */ init_func_pointers(); - if (m_pfn_validation_callback_proc != nullptr) + if (m_validation_callback_function != nullptr) { init_debug_callbacks(); } diff --git a/src/wrappers/memory_block.cpp b/src/wrappers/memory_block.cpp index 620650da..0c7260ee 100644 --- a/src/wrappers/memory_block.cpp +++ b/src/wrappers/memory_block.cpp @@ -29,21 +29,19 @@ #include "wrappers/physical_device.h" /* Please see header for specification */ -Anvil::MemoryBlock::MemoryBlock(std::weak_ptr in_device_ptr, - uint32_t in_allowed_memory_bits, - VkDeviceSize in_size, - Anvil::MemoryFeatureFlags in_memory_features) - :m_allowed_memory_bits (in_allowed_memory_bits), - m_device_ptr (in_device_ptr), - m_destroy_memory_block_proc_user_arg(nullptr), - m_gpu_data_ptr (nullptr), - m_gpu_data_user_mapped (false), - m_memory (VK_NULL_HANDLE), - m_memory_features (in_memory_features), - m_parent_memory_block_ptr (nullptr), - m_pfn_destroy_memory_block_proc (nullptr), - m_size (in_size), - m_start_offset (0) +Anvil::MemoryBlock::MemoryBlock(std::weak_ptr in_device_ptr, + uint32_t in_allowed_memory_bits, + VkDeviceSize in_size, + Anvil::MemoryFeatureFlags in_memory_features) + :m_allowed_memory_bits (in_allowed_memory_bits), + m_device_ptr (in_device_ptr), + m_gpu_data_map_count (0), + m_gpu_data_ptr (nullptr), + m_memory (VK_NULL_HANDLE), + m_memory_features (in_memory_features), + m_parent_memory_block_ptr(nullptr), + m_size (in_size), + m_start_offset (0) { /* Register the object */ Anvil::ObjectTracker::get()->register_object(Anvil::OBJECT_TYPE_MEMORY_BLOCK, @@ -58,18 +56,17 @@ Anvil::MemoryBlock::MemoryBlock(std::shared_ptr in_parent_memory_bl anvil_assert(in_parent_memory_block_ptr != nullptr); anvil_assert(in_parent_memory_block_ptr->m_gpu_data_ptr == nullptr); - m_allowed_memory_bits = in_parent_memory_block_ptr->m_allowed_memory_bits; - m_destroy_memory_block_proc_user_arg = in_parent_memory_block_ptr->m_destroy_memory_block_proc_user_arg; - m_device_ptr = in_parent_memory_block_ptr->m_device_ptr; - m_gpu_data_ptr = nullptr; - m_gpu_data_user_mapped = false; - m_memory_features = in_parent_memory_block_ptr->m_memory_features; - m_memory = VK_NULL_HANDLE; - m_memory_type_index = UINT32_MAX; - m_parent_memory_block_ptr = in_parent_memory_block_ptr; - m_pfn_destroy_memory_block_proc = in_parent_memory_block_ptr->m_pfn_destroy_memory_block_proc; - m_size = in_size; - m_start_offset = in_start_offset + m_parent_memory_block_ptr->m_start_offset; + m_allowed_memory_bits = in_parent_memory_block_ptr->m_allowed_memory_bits; + m_device_ptr = in_parent_memory_block_ptr->m_device_ptr; + m_gpu_data_map_count = UINT32_MAX; + m_gpu_data_ptr = nullptr; + m_memory_features = in_parent_memory_block_ptr->m_memory_features; + m_memory = VK_NULL_HANDLE; + m_memory_type_index = UINT32_MAX; + m_on_release_callback_function = in_parent_memory_block_ptr->m_on_release_callback_function; + m_parent_memory_block_ptr = in_parent_memory_block_ptr; + m_size = in_size; + m_start_offset = in_start_offset + m_parent_memory_block_ptr->m_start_offset; anvil_assert(m_start_offset >= m_parent_memory_block_ptr->m_start_offset); anvil_assert(m_start_offset + m_size <= m_parent_memory_block_ptr->m_start_offset + m_parent_memory_block_ptr->m_size); @@ -80,30 +77,28 @@ Anvil::MemoryBlock::MemoryBlock(std::shared_ptr in_parent_memory_bl } /* Please see header for specification */ -Anvil::MemoryBlock::MemoryBlock(std::weak_ptr in_device_ptr, - VkDeviceMemory in_memory, - uint32_t in_allowed_memory_bits, - Anvil::MemoryFeatureFlags in_memory_features, - uint32_t in_memory_type_index, - VkDeviceSize in_size, - VkDeviceSize in_start_offset, - PFNMEMORYBLOCKDESTRUCTIONCALLBACKPROC in_pfn_destroy_memory_block_proc, - void* in_destroy_memory_block_proc_user_arg) +Anvil::MemoryBlock::MemoryBlock(std::weak_ptr in_device_ptr, + VkDeviceMemory in_memory, + uint32_t in_allowed_memory_bits, + Anvil::MemoryFeatureFlags in_memory_features, + uint32_t in_memory_type_index, + VkDeviceSize in_size, + VkDeviceSize in_start_offset, + OnMemoryBlockReleaseCallbackFunction in_on_release_callback_function) { - anvil_assert(in_pfn_destroy_memory_block_proc != nullptr); - - m_allowed_memory_bits = in_allowed_memory_bits; - m_destroy_memory_block_proc_user_arg = in_destroy_memory_block_proc_user_arg; - m_device_ptr = in_device_ptr; - m_gpu_data_ptr = nullptr; - m_gpu_data_user_mapped = false; - m_memory_features = in_memory_features; - m_memory = in_memory; - m_memory_type_index = in_memory_type_index; - m_parent_memory_block_ptr = nullptr; - m_pfn_destroy_memory_block_proc = in_pfn_destroy_memory_block_proc; - m_size = in_size; - m_start_offset = in_start_offset; + anvil_assert(in_on_release_callback_function != nullptr); + + m_allowed_memory_bits = in_allowed_memory_bits; + m_device_ptr = in_device_ptr; + m_gpu_data_map_count = 0; + m_gpu_data_ptr = nullptr; + m_memory_features = in_memory_features; + m_memory = in_memory; + m_memory_type_index = in_memory_type_index; + m_parent_memory_block_ptr = nullptr; + m_on_release_callback_function = in_on_release_callback_function; + m_size = in_size; + m_start_offset = in_start_offset; /* Register the object */ Anvil::ObjectTracker::get()->register_object(Anvil::OBJECT_TYPE_MEMORY_BLOCK, @@ -113,12 +108,14 @@ Anvil::MemoryBlock::MemoryBlock(std::weak_ptr in_device_ /** Releases the underlying Vulkan memory object. */ Anvil::MemoryBlock::~MemoryBlock() { - anvil_assert(!m_gpu_data_user_mapped); + if (m_parent_memory_block_ptr == nullptr) + { + anvil_assert(m_gpu_data_map_count.load() == 0); + } - if (m_pfn_destroy_memory_block_proc != nullptr) + if (m_on_release_callback_function != nullptr) { - m_pfn_destroy_memory_block_proc(this, - m_destroy_memory_block_proc_user_arg); + m_on_release_callback_function(this); } /* Unregister the object */ @@ -127,7 +124,7 @@ Anvil::MemoryBlock::~MemoryBlock() if (m_memory != VK_NULL_HANDLE) { - if (m_pfn_destroy_memory_block_proc == nullptr) + if (m_on_release_callback_function == nullptr) { std::shared_ptr device_locked_ptr(m_device_ptr); @@ -144,14 +141,23 @@ Anvil::MemoryBlock::~MemoryBlock() void Anvil::MemoryBlock::close_gpu_memory_access() { std::shared_ptr device_locked_ptr(m_device_ptr); - VkDeviceMemory memory ((m_parent_memory_block_ptr != nullptr) ? m_parent_memory_block_ptr->m_memory : m_memory); - anvil_assert(m_gpu_data_ptr != nullptr); + if (m_parent_memory_block_ptr != nullptr) + { + m_parent_memory_block_ptr->close_gpu_memory_access(); + } + else + { + anvil_assert(m_gpu_data_ptr != nullptr); - vkUnmapMemory(device_locked_ptr->get_device_vk(), - memory); + if (m_gpu_data_map_count.fetch_sub(1) == 1) + { + vkUnmapMemory(device_locked_ptr->get_device_vk(), + m_memory); - m_gpu_data_ptr = nullptr; + m_gpu_data_ptr = nullptr; + } + } } /* Please see header for specification */ @@ -202,15 +208,14 @@ std::shared_ptr Anvil::MemoryBlock::create_derived(std::shar } /* Please see header for specification */ -std::shared_ptr Anvil::MemoryBlock::create_derived_with_custom_delete_proc(std::weak_ptr in_device_ptr, - VkDeviceMemory in_memory, - uint32_t in_allowed_memory_bits, - Anvil::MemoryFeatureFlags in_memory_features, - uint32_t in_memory_type_index, - VkDeviceSize in_size, - VkDeviceSize in_start_offset, - PFNMEMORYBLOCKDESTRUCTIONCALLBACKPROC in_pfn_destroy_memory_block_proc, - void* in_destroy_memory_block_proc_user_arg) +std::shared_ptr Anvil::MemoryBlock::create_derived_with_custom_delete_proc(std::weak_ptr in_device_ptr, + VkDeviceMemory in_memory, + uint32_t in_allowed_memory_bits, + Anvil::MemoryFeatureFlags in_memory_features, + uint32_t in_memory_type_index, + VkDeviceSize in_size, + VkDeviceSize in_start_offset, + OnMemoryBlockReleaseCallbackFunction in_on_release_callback_function) { std::shared_ptr result_ptr; @@ -222,8 +227,7 @@ std::shared_ptr Anvil::MemoryBlock::create_derived_with_cust in_memory_type_index, in_size, in_start_offset, - in_pfn_destroy_memory_block_proc, - in_destroy_memory_block_proc_user_arg) + in_on_release_callback_function) ); return result_ptr; @@ -355,52 +359,49 @@ bool Anvil::MemoryBlock::map(VkDeviceSize in_start_offset, bool result = false; /* Sanity checks */ - if (m_gpu_data_user_mapped) + if (m_parent_memory_block_ptr != nullptr) { - anvil_assert(!m_gpu_data_user_mapped); - - goto end; + result = m_parent_memory_block_ptr->map(m_start_offset + in_start_offset, + in_size, + out_opt_data_ptr); } + else + { + /* Map whole memory block into process space. Necessary since deriving memory blocks may + * need to carve out subregions. */ + if (!open_gpu_memory_access() ) + { + goto end; + } - result = open_gpu_memory_access(in_start_offset, - in_size); + if ((m_memory_features & Anvil::MEMORY_FEATURE_FLAG_HOST_COHERENT) == 0) + { + /* Make sure the mapped region is invalidated before letting the user read from it */ + std::shared_ptr device_locked_ptr (m_device_ptr); + VkMappedMemoryRange mapped_memory_range; + VkResult result_vk (VK_ERROR_INITIALIZATION_FAILED); - if (!result) - { - goto end; - } + ANVIL_REDUNDANT_VARIABLE(result_vk); - if ((m_memory_features & Anvil::MEMORY_FEATURE_FLAG_HOST_COHERENT) == 0) - { - /* Make sure the mapped region is invalidated before letting the user read from it */ - std::shared_ptr device_locked_ptr (m_device_ptr); - VkMappedMemoryRange mapped_memory_range; - VkResult result_vk (VK_ERROR_INITIALIZATION_FAILED); - - ANVIL_REDUNDANT_VARIABLE(result_vk); - - mapped_memory_range.memory = get_memory(); - mapped_memory_range.offset = m_start_offset + in_start_offset; - mapped_memory_range.pNext = nullptr; - mapped_memory_range.size = in_size; - mapped_memory_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - - result_vk = vkInvalidateMappedMemoryRanges(device_locked_ptr->get_device_vk(), - 1, /* memRangeCount */ - &mapped_memory_range); - anvil_assert_vk_call_succeeded(result_vk); - } + mapped_memory_range.memory = get_memory(); + mapped_memory_range.offset = m_start_offset + in_start_offset; + mapped_memory_range.pNext = nullptr; + mapped_memory_range.size = in_size; + mapped_memory_range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - m_gpu_data_user_mapped = true; - m_gpu_data_user_size = in_size; - m_gpu_data_user_start_offset = in_start_offset; + result_vk = vkInvalidateMappedMemoryRanges(device_locked_ptr->get_device_vk(), + 1, /* memRangeCount */ + &mapped_memory_range); + anvil_assert_vk_call_succeeded(result_vk); + } - if (out_opt_data_ptr != nullptr) - { - *out_opt_data_ptr = m_gpu_data_ptr; - } + if (out_opt_data_ptr != nullptr) + { + *out_opt_data_ptr = static_cast(m_gpu_data_ptr) + m_start_offset + in_start_offset; + } - result = true; + result = true; + } end: return result; } @@ -411,24 +412,17 @@ bool Anvil::MemoryBlock::map(VkDeviceSize in_start_offset, * Once the mapped region is no longer needed, a close_gpu_memory_access() call must be made to * unmap the object from process space. * - * @param in_start_offset Start offset of the region to be mapped. Must be smaller than the size - * of the underlying buffer object, or else an assertion failure will occur. - * @param in_size Size of the region to be mapped. (size + start_offset) must not be larger - * than the size of the underlying buffer object, or else an assertion failure - * will occur. - * * @return true if the call was successful, false otherwise. - * */ -bool Anvil::MemoryBlock::open_gpu_memory_access(VkDeviceSize in_start_offset, - VkDeviceSize in_size) + **/ +bool Anvil::MemoryBlock::open_gpu_memory_access() { - std::shared_ptr device_locked_ptr(m_device_ptr); - VkDeviceMemory memory (VK_NULL_HANDLE); - std::shared_ptr memory_block_ptr ((m_parent_memory_block_ptr != nullptr) ? m_parent_memory_block_ptr : shared_from_this() ); - bool result (false); - VkResult result_vk; + std::shared_ptr device_locked_ptr(m_device_ptr); + bool result (false); + VkResult result_vk; /* Sanity checks */ + anvil_assert(m_parent_memory_block_ptr == nullptr); + if ((m_memory_features & Anvil::MEMORY_FEATURE_FLAG_MAPPABLE) == 0) { anvil_assert((m_memory_features & Anvil::MEMORY_FEATURE_FLAG_MAPPABLE) != 0); @@ -436,25 +430,23 @@ bool Anvil::MemoryBlock::open_gpu_memory_access(VkDeviceSize in_start_offset, goto end; } - if (!(m_start_offset + m_size >= in_start_offset + in_size)) + if (m_gpu_data_map_count.fetch_add(1) == 0) { - anvil_assert(m_start_offset + m_size >= in_start_offset + in_size); + /* Map the memory region into process space */ + result_vk = vkMapMemory(device_locked_ptr->get_device_vk(), + m_memory, + 0, /* offset */ + m_size, + 0, /* flags */ + (void**) &m_gpu_data_ptr); - goto end; + anvil_assert_vk_call_succeeded(result_vk); + result = is_vk_call_successful(result_vk); + } + else + { + result = true; } - - /* Map the memory region into process space */ - memory = memory_block_ptr->m_memory; - - result_vk = vkMapMemory(device_locked_ptr->get_device_vk(), - memory, - in_start_offset, - in_size, - 0, /* flags */ - (void**) &m_gpu_data_ptr); - - anvil_assert_vk_call_succeeded(result_vk); - result = is_vk_call_successful(result_vk); end: return result; @@ -466,8 +458,7 @@ bool Anvil::MemoryBlock::read(VkDeviceSize in_start_offset, void* out_result_ptr) { std::shared_ptr device_locked_ptr(m_device_ptr); - VkDeviceSize memcpy_offset = 0; - bool result = false; + bool result (false); anvil_assert(in_size > 0); anvil_assert(in_start_offset + in_size <= m_size); @@ -481,30 +472,10 @@ bool Anvil::MemoryBlock::read(VkDeviceSize in_start_offset, } else { - /* If a user's memory buffer mapping is active, make sure the requested region is completely covered - * by the mapped region. - * If not, just map the specified region, issue the read op, and then close the mapping. - */ - if (m_gpu_data_user_mapped) + if (!open_gpu_memory_access() ) { - const bool no_full_overlap = !(in_start_offset + in_size < m_gpu_data_user_start_offset + m_gpu_data_user_size || - in_start_offset > m_gpu_data_user_start_offset); - - if (no_full_overlap) - { - anvil_assert(!no_full_overlap); - - goto end; - } + anvil_assert_fail(); - anvil_assert(in_start_offset >= m_gpu_data_user_start_offset); - - memcpy_offset = in_start_offset - m_gpu_data_user_start_offset; - } - else - if (!open_gpu_memory_access(in_start_offset, - in_size) ) - { goto end; } @@ -513,6 +484,7 @@ bool Anvil::MemoryBlock::read(VkDeviceSize in_start_offset, VkMappedMemoryRange mapped_memory_range; VkResult result_vk (VK_ERROR_INITIALIZATION_FAILED); + anvil_assert (m_start_offset == 0); ANVIL_REDUNDANT_VARIABLE(result_vk); mapped_memory_range.memory = m_memory; @@ -528,13 +500,10 @@ bool Anvil::MemoryBlock::read(VkDeviceSize in_start_offset, } memcpy(out_result_ptr, - (char*) m_gpu_data_ptr + static_cast(memcpy_offset), + static_cast(m_gpu_data_ptr) + static_cast(in_start_offset), static_cast(in_size)); - if (!m_gpu_data_user_mapped) - { - close_gpu_memory_access(); - } + close_gpu_memory_access(); result = true; } @@ -548,21 +517,26 @@ bool Anvil::MemoryBlock::unmap() { bool result = false; - /* Sanity checks */ - if (!m_gpu_data_user_mapped) + if (m_parent_memory_block_ptr != nullptr) { - anvil_assert(m_gpu_data_user_mapped); + result = m_parent_memory_block_ptr->unmap(); goto end; } + else + { + /* Sanity checks */ + if (m_gpu_data_ptr == nullptr) + { + anvil_assert(m_gpu_data_ptr != nullptr); - close_gpu_memory_access(); + goto end; + } - m_gpu_data_user_mapped = false; - m_gpu_data_user_size = 0; - m_gpu_data_user_start_offset = UINT64_MAX; + close_gpu_memory_access(); - result = true; + result = true; + } end: return result; } @@ -573,8 +547,7 @@ bool Anvil::MemoryBlock::write(VkDeviceSize in_start_offset, const void* in_data) { std::shared_ptr device_locked_ptr(m_device_ptr); - VkDeviceSize memcpy_offset = 0; - bool result = false; + bool result (false); anvil_assert(in_size > 0); anvil_assert(in_start_offset + in_size <= in_start_offset + m_size); @@ -588,34 +561,12 @@ bool Anvil::MemoryBlock::write(VkDeviceSize in_start_offset, } else { - /* If a user's memory buffer mapping is active, make sure the requested region is completely covered - * by the mapped region. - * If not, just map the specified region, issue the read op, and then close the mapping. - */ - if (m_gpu_data_user_mapped) - { - const bool no_full_overlap = !(in_start_offset + in_size <= m_gpu_data_user_start_offset + m_gpu_data_user_size || - in_start_offset > m_gpu_data_user_start_offset); - - if (no_full_overlap) - { - anvil_assert(!no_full_overlap); - - goto end; - } - - anvil_assert(in_start_offset >= m_gpu_data_user_start_offset); - - memcpy_offset = in_start_offset - m_gpu_data_user_start_offset; - } - else - if (!open_gpu_memory_access(in_start_offset, - in_size) ) + if (!open_gpu_memory_access() ) { goto end; } - memcpy((char*) m_gpu_data_ptr + static_cast(memcpy_offset), + memcpy(static_cast(m_gpu_data_ptr) + static_cast(in_start_offset), in_data, static_cast(in_size)); @@ -638,10 +589,7 @@ bool Anvil::MemoryBlock::write(VkDeviceSize in_start_offset, anvil_assert_vk_call_succeeded(result_vk); } - if (!m_gpu_data_user_mapped) - { - close_gpu_memory_access(); - } + close_gpu_memory_access(); result = true; } diff --git a/src/wrappers/pipeline_layout.cpp b/src/wrappers/pipeline_layout.cpp index c49400d3..12673304 100644 --- a/src/wrappers/pipeline_layout.cpp +++ b/src/wrappers/pipeline_layout.cpp @@ -30,8 +30,7 @@ /** Please see header for specification */ Anvil::PipelineLayout::PipelineLayout(std::weak_ptr in_device_ptr) - :CallbacksSupportProvider (PIPELINE_LAYOUT_CALLBACK_ID_COUNT), - DebugMarkerSupportProvider(in_device_ptr, + :DebugMarkerSupportProvider(in_device_ptr, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT) { @@ -51,8 +50,7 @@ Anvil::PipelineLayout::PipelineLayout(std::weak_ptr std::shared_ptr in_dsg_ptr, const Anvil::PushConstantRanges& in_push_constant_ranges, bool in_is_immutable) - :CallbacksSupportProvider (PIPELINE_LAYOUT_CALLBACK_ID_COUNT), - DebugMarkerSupportProvider(in_device_ptr, + :DebugMarkerSupportProvider(in_device_ptr, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT) { m_device_ptr = in_device_ptr; @@ -72,9 +70,6 @@ Anvil::PipelineLayout::PipelineLayout(std::weak_ptr /** Please see header for specification */ Anvil::PipelineLayout::~PipelineLayout() { - callback(PIPELINE_LAYOUT_CALLBACK_ID_OBJECT_ABOUT_TO_BE_DELETED, - this); - m_dsg_ptr = nullptr; Anvil::ObjectTracker::get()->unregister_object(Anvil::OBJECT_TYPE_PIPELINE_LAYOUT, diff --git a/src/wrappers/pipeline_layout_manager.cpp b/src/wrappers/pipeline_layout_manager.cpp index 5f66cc6d..2c7d2359 100644 --- a/src/wrappers/pipeline_layout_manager.cpp +++ b/src/wrappers/pipeline_layout_manager.cpp @@ -33,6 +33,8 @@ Anvil::PipelineLayoutManager::PipelineLayoutManager(std::weak_ptrregister_object(Anvil::OBJECT_TYPE_PIPELINE_LAYOUT_MANAGER, this); @@ -41,6 +43,8 @@ Anvil::PipelineLayoutManager::PipelineLayoutManager(std::weak_ptrunregister_object(Anvil::OBJECT_TYPE_PIPELINE_LAYOUT_MANAGER, this); @@ -114,10 +118,6 @@ bool Anvil::PipelineLayoutManager::get_layout(std::shared_ptrregister_for_callbacks(PIPELINE_LAYOUT_CALLBACK_ID_OBJECT_ABOUT_TO_BE_DELETED, - on_pipeline_layout_dropped, - this); - if (result) { const PipelineLayoutID pipeline_layout_id = new_layout_ptr->get_id(); @@ -149,24 +149,20 @@ std::shared_ptr Anvil::PipelineLayoutManager::get_layout_ } /** Called back whenever a pipeline layout is released **/ -void Anvil::PipelineLayoutManager::on_pipeline_layout_dropped(void* in_callback_arg, - void* in_user_arg) +void Anvil::PipelineLayoutManager::on_pipeline_layout_dropped() { - PipelineLayouts::iterator layout_iterator; - Anvil::PipelineLayoutManager* layout_manager_ptr = static_cast(in_user_arg); - - ANVIL_REDUNDANT_ARGUMENT(in_callback_arg); + PipelineLayouts::iterator layout_iterator; /* Are we the last standing layout user? */ - for (layout_iterator = layout_manager_ptr->m_pipeline_layouts.begin(); - layout_iterator != layout_manager_ptr->m_pipeline_layouts.end(); + for (layout_iterator = m_pipeline_layouts.begin(); + layout_iterator != m_pipeline_layouts.end(); ) { if (layout_iterator->second.expired() ) { - layout_manager_ptr->m_pipeline_layouts.erase(layout_iterator); + m_pipeline_layouts.erase(layout_iterator); - layout_iterator = layout_manager_ptr->m_pipeline_layouts.begin(); + layout_iterator = m_pipeline_layouts.begin(); } else { @@ -179,4 +175,25 @@ void Anvil::PipelineLayoutManager::on_pipeline_layout_dropped(void* in_callback_ Anvil::PipelineLayoutID Anvil::PipelineLayoutManager::reserve_pipeline_layout_id() { return m_pipeline_layouts_created++; -} \ No newline at end of file +} + +void Anvil::PipelineLayoutManager::update_subscriptions(bool in_should_init) +{ + const auto callback_func = std::bind(&PipelineLayoutManager::on_pipeline_layout_dropped, + this); + void* callback_owner = this; + auto object_tracker_ptr = Anvil::ObjectTracker::get(); + + if (in_should_init) + { + object_tracker_ptr->register_for_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_PIPELINE_LAYOUT_OBJECT_ABOUT_TO_BE_UNREGISTERED, + callback_func, + callback_owner); + } + else + { + object_tracker_ptr->unregister_from_callbacks(OBJECT_TRACKER_CALLBACK_ID_ON_PIPELINE_LAYOUT_OBJECT_ABOUT_TO_BE_UNREGISTERED, + callback_func, + callback_owner); + } +} diff --git a/src/wrappers/queue.cpp b/src/wrappers/queue.cpp index 950be89c..c8a8688b 100644 --- a/src/wrappers/queue.cpp +++ b/src/wrappers/queue.cpp @@ -62,6 +62,10 @@ Anvil::Queue::Queue(std::weak_ptr in_device_ptr, /* Determine whether the queue supports sparse bindings */ m_supports_sparse_bindings = !!(device_locked_ptr->get_queue_family_info(in_queue_family_index)->flags & VK_QUEUE_SPARSE_BINDING_BIT); + /* Cache a fence that may be optionally used for submissions */ + m_submit_fence_ptr = Anvil::Fence::create(m_device_ptr, + false /* create_signalled */); + /* OK, register the wrapper instance and leave */ Anvil::ObjectTracker::get()->register_object(Anvil::OBJECT_TYPE_QUEUE, this); @@ -70,7 +74,7 @@ Anvil::Queue::Queue(std::weak_ptr in_device_ptr, /** Please see header for specification */ Anvil::Queue::~Queue() { - /* Queues are indestructible. Nothing to do here. */ + m_submit_fence_ptr.reset(); Anvil::ObjectTracker::get()->unregister_object(Anvil::OBJECT_TYPE_QUEUE, this); @@ -259,6 +263,16 @@ VkResult Anvil::Queue::present(std::shared_ptr in_swapchain_p &dst_stage_mask, true); /* should_block */ + for (uint32_t n_presentation = 0; + n_presentation < 1; + ++n_presentation) + { + OnPresentRequestIssuedCallbackArgument callback_argument(in_swapchain_ptr.get() ); + + CallbacksSupportProvider::callback(QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, + &callback_argument); + } + result = VK_SUCCESS; goto end; } @@ -283,8 +297,8 @@ VkResult Anvil::Queue::present(std::shared_ptr in_swapchain_p image_presentation_info.swapchainCount = 1; image_presentation_info.waitSemaphoreCount = in_n_wait_semaphores; - result = swapchain_entrypoints.vkQueuePresentKHR(m_queue, - &image_presentation_info); + result = swapchain_entrypoints.vkQueuePresentKHR(m_queue, + &image_presentation_info); anvil_assert_vk_call_succeeded(result); @@ -342,10 +356,14 @@ VkResult Anvil::Queue::present(std::shared_ptr in_swapchain_p anvil_assert(presentation_results[0] == VK_SUCCESS); } } - } - CallbacksSupportProvider::callback(QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, - in_swapchain_ptr.get() ); + { + OnPresentRequestIssuedCallbackArgument callback_argument(in_swapchain_ptr.get() ); + + CallbacksSupportProvider::callback(QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, + &callback_argument); + } + } } end: @@ -381,8 +399,9 @@ void Anvil::Queue::submit_command_buffers(uint32_t if (in_opt_fence_ptr == nullptr && in_should_block) { - in_opt_fence_ptr = Anvil::Fence::create(m_device_ptr, - false /* create_signalled */); + m_submit_fence_ptr->reset(); + + in_opt_fence_ptr = m_submit_fence_ptr; } for (uint32_t n_command_buffer = 0; diff --git a/src/wrappers/render_pass.cpp b/src/wrappers/render_pass.cpp index 620ba2f5..688b5b7b 100644 --- a/src/wrappers/render_pass.cpp +++ b/src/wrappers/render_pass.cpp @@ -114,8 +114,12 @@ bool Anvil::RenderPass::add_color_attachment(VkFormat in_format, result = true; /* Notify the subscribers about the event */ - callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, - this); + { + OnRenderPassBakeNeededCallbackArgument callback_argument(this); + + callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, + &callback_argument); + } end: return result; @@ -165,8 +169,12 @@ bool Anvil::RenderPass::add_dependency(SubPass* in_destination_subpa m_dirty = true; /* Notify the subscribers about the event */ - callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, - this); + { + OnRenderPassBakeNeededCallbackArgument callback_argument(this); + + callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, + &callback_argument); + } } return true; @@ -446,8 +454,12 @@ bool Anvil::RenderPass::add_subpass_attachment(SubPassID in_subpass result = true; /* Notify the subscribers about the event */ - callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, - this); + { + OnRenderPassBakeNeededCallbackArgument callback_argument(this); + + callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, + &callback_argument); + } end: return result; @@ -1387,8 +1399,12 @@ bool Anvil::RenderPass::set_subpass_graphics_pipeline_id(SubPassID in_s result = true; /* Notify the subscribers about the event */ - callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, - this); + { + OnRenderPassBakeNeededCallbackArgument callback_argument(this); + + callback(RENDER_PASS_CALLBACK_ID_BAKING_NEEDED, + &callback_argument); + } end: return result; diff --git a/src/wrappers/rendering_surface.cpp b/src/wrappers/rendering_surface.cpp index 11402708..89148e3a 100644 --- a/src/wrappers/rendering_surface.cpp +++ b/src/wrappers/rendering_surface.cpp @@ -317,7 +317,6 @@ bool Anvil::RenderingSurface::init() const bool is_dummy_window_platform(window_platform == WINDOW_PLATFORM_DUMMY || window_platform == WINDOW_PLATFORM_DUMMY_WITH_PNG_SNAPSHOTS); - for (uint32_t n_physical_device = 0; n_physical_device < n_physical_devices; ++n_physical_device) @@ -390,44 +389,37 @@ bool Anvil::RenderingSurface::init() * the logical device to present using the surface we've just spawned and the physical device user has specified? */ const auto& queue_families (device_locked_ptr->get_physical_device_queue_families() ); std::shared_ptr sgpu_device_locked_ptr(std::dynamic_pointer_cast(device_locked_ptr) ); + auto physical_device_locked_ptr = sgpu_device_locked_ptr->get_physical_device().lock(); + auto physical_device_caps_ptr = &m_physical_device_capabilities[0]; - for (uint32_t n_physical_device = 0; - n_physical_device < n_physical_devices; - ++n_physical_device) + switch (m_type) { - std::shared_ptr physical_device_locked_ptr(sgpu_device_locked_ptr->get_physical_device() ); - - auto& result_caps = m_physical_device_capabilities.at(0); - - switch (m_type) + case Anvil::RENDERING_SURFACE_TYPE_GENERAL: { - case Anvil::RENDERING_SURFACE_TYPE_GENERAL: + for (uint32_t n_queue_family = 0; + n_queue_family < static_cast(queue_families.size() ); + ++n_queue_family) { - for (uint32_t n_queue_family = 0; - n_queue_family < static_cast(queue_families.size() ); - ++n_queue_family) + VkBool32 is_presentation_supported = VK_FALSE; + + result = vkGetPhysicalDeviceSurfaceSupportKHR(physical_device_locked_ptr->get_physical_device(), + n_queue_family, + m_surface, + &is_presentation_supported); + + if (is_vk_call_successful(result) && + is_presentation_supported == VK_TRUE) { - VkBool32 is_presentation_supported = VK_FALSE; - - result = vkGetPhysicalDeviceSurfaceSupportKHR(physical_device_locked_ptr->get_physical_device(), - n_queue_family, - m_surface, - &is_presentation_supported); - - if (is_vk_call_successful(result) && - is_presentation_supported == VK_TRUE) - { - result_caps.present_capable_queue_fams.push_back(n_queue_family); - } + physical_device_caps_ptr->present_capable_queue_fams.push_back(n_queue_family); } - - break; } - default: - { - anvil_assert_fail(); - } + break; + } + + default: + { + anvil_assert_fail(); } } } @@ -443,8 +435,8 @@ bool Anvil::RenderingSurface::init() if (sgpu_device_locked_ptr->get_n_universal_queues() > 0) { std::shared_ptr physical_device_locked_ptr = sgpu_device_locked_ptr->get_physical_device().lock(); - auto& result_caps = m_physical_device_capabilities.at (0); - + auto& result_caps = m_physical_device_capabilities[0]; + result_caps.present_capable_queue_fams.push_back(sgpu_device_locked_ptr->get_universal_queue(0)->get_queue_family_index() ); } } diff --git a/src/wrappers/shader_module.cpp b/src/wrappers/shader_module.cpp index 19e3a2ee..1743dac3 100644 --- a/src/wrappers/shader_module.cpp +++ b/src/wrappers/shader_module.cpp @@ -105,9 +105,13 @@ Anvil::ShaderModule::~ShaderModule() destroy(); /* Unregister from any callbacks we have subscribed for */ - object_tracker_ptr->unregister_from_callbacks(Anvil::OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, - on_object_about_to_be_released, - this); + object_tracker_ptr->unregister_from_callbacks( + Anvil::OBJECT_TRACKER_CALLBACK_ID_ON_DEVICE_OBJECT_ABOUT_TO_BE_UNREGISTERED, + std::bind(&ShaderModule::on_object_about_to_be_released, + this, + std::placeholders::_1), + this + ); } /** Please see header for specification */ @@ -262,26 +266,25 @@ bool Anvil::ShaderModule::init_from_spirv_blob(const char* in_spirv_blob, } /* Sign for device destruction notification, in which case we need to destroy the shader module. */ - Anvil::ObjectTracker::get()->register_for_callbacks(Anvil::OBJECT_TRACKER_CALLBACK_ID_ON_OBJECT_ABOUT_TO_BE_UNREGISTERED, - on_object_about_to_be_released, - this); + Anvil::ObjectTracker::get()->register_for_callbacks( + Anvil::OBJECT_TRACKER_CALLBACK_ID_ON_DEVICE_OBJECT_ABOUT_TO_BE_UNREGISTERED, + std::bind(&ShaderModule::on_object_about_to_be_released, + this, + std::placeholders::_1), + this + ); return is_vk_call_successful(result_vk); } /** TODO */ -void Anvil::ShaderModule::on_object_about_to_be_released(void* in_callback_arg, - void* in_shader_module_raw_ptr) +void Anvil::ShaderModule::on_object_about_to_be_released(void* in_callback_arg_ptr) { - const ObjectTrackerOnObjectAboutToBeUnregisteredCallbackArg* callback_arg_ptr = reinterpret_cast(in_callback_arg); - Anvil::ShaderModule* shader_module_ptr = reinterpret_cast (in_shader_module_raw_ptr); + const auto callback_arg_ptr = reinterpret_cast(in_callback_arg_ptr); - if (callback_arg_ptr->object_type == OBJECT_TYPE_DEVICE) + if (m_device_raw_ptr == callback_arg_ptr->object_raw_ptr) { - if (shader_module_ptr->m_device_raw_ptr == callback_arg_ptr->object_raw_ptr) - { - /* Make sure to release the shader module handle before we let the object actually proceed with destruction! */ - shader_module_ptr->destroy(); - } + /* Make sure to release the shader module handle before we let the object actually proceed with destruction! */ + destroy(); } } \ No newline at end of file diff --git a/src/wrappers/swapchain.cpp b/src/wrappers/swapchain.cpp index f26078ad..6f6098f9 100644 --- a/src/wrappers/swapchain.cpp +++ b/src/wrappers/swapchain.cpp @@ -64,17 +64,11 @@ Anvil::Swapchain::Swapchain(std::weak_ptr in_device_p anvil_assert(in_parent_surface_ptr != nullptr); anvil_assert(in_usage_flags != 0); - m_image_available_fence_ptrs.resize(in_n_images); - m_image_ptrs.resize (in_n_images); - m_image_view_ptrs.resize (in_n_images); + m_image_ptrs.resize (in_n_images); + m_image_view_ptrs.resize(in_n_images); - for (uint32_t n_fence = 0; - n_fence < in_n_images; - ++n_fence) - { - m_image_available_fence_ptrs[n_fence] = Anvil::Fence::create(m_device_ptr, - false /* create_signalled */); - } + m_image_available_fence_ptr = Anvil::Fence::create(m_device_ptr, + false /* create_signalled */); init(); @@ -95,20 +89,26 @@ Anvil::Swapchain::~Swapchain() m_parent_surface_ptr = nullptr; } - m_image_ptrs.clear (); - m_image_available_fence_ptrs.clear(); - m_image_view_ptrs.clear (); + m_image_ptrs.clear (); + m_image_available_fence_ptr.reset(); + m_image_view_ptrs.clear (); for (auto queue_ptr : m_observed_queues) { - queue_ptr->unregister_from_callbacks(QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, - on_present_request_issued, - this); /* in_user_arg */ + queue_ptr->unregister_from_callbacks( + QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, + std::bind(&Swapchain::on_present_request_issued, + this), + this + ); } - m_window_ptr->unregister_from_callbacks(WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, - on_parent_window_about_to_close, - this); + m_window_ptr->unregister_from_callbacks( + WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, + std::bind(&Swapchain::on_parent_window_about_to_close, + this), + this + ); } /** Please see header for specification */ @@ -132,9 +132,9 @@ uint32_t Anvil::Swapchain::acquire_image(std::shared_ptr in_op if (in_should_block) { - m_image_available_fence_ptrs.at(m_n_acquire_counter_rounded)->reset(); + m_image_available_fence_ptr->reset(); - fence_handle = m_image_available_fence_ptrs.at(m_n_acquire_counter_rounded)->get_fence(); + fence_handle = m_image_available_fence_ptr->get_fence(); } result_vk = m_khr_swapchain_entrypoints.vkAcquireNextImageKHR(device_locked_ptr->get_device_vk(), @@ -156,25 +156,29 @@ uint32_t Anvil::Swapchain::acquire_image(std::shared_ptr in_op anvil_assert_vk_call_succeeded(result_vk); } - - /* NOTE: Only bump the frame acquisition counter if we're not emulating a Vulkan swapchain */ - m_n_acquire_counter++; - m_n_acquire_counter_rounded = (m_n_acquire_counter_rounded + 1) % m_n_swapchain_images; } else { - /* We need to set the semaphore manually in this scenario */ - device_locked_ptr->get_universal_queue(0)->submit_command_buffer_with_signal_semaphores(nullptr, /* cmd_buffer_ptr */ - 1, /* n_semaphores_to_signal */ - &in_opt_semaphore_ptr, - true); /* should_block */ - } + if (in_should_block) + { + vkDeviceWaitIdle(m_device_ptr.lock()->get_device_vk() ); + } + + if (in_opt_semaphore_ptr != nullptr) + { + /* We need to set the semaphore manually in this scenario */ + device_locked_ptr->get_universal_queue(0)->submit_command_buffer_with_signal_semaphores(nullptr, /* cmd_buffer_ptr */ + 1, /* n_semaphores_to_signal */ + &in_opt_semaphore_ptr, + true); /* should_block */ + } - if (is_offscreen_rendering_enabled) - { result = m_n_acquire_counter_rounded; } + m_n_acquire_counter++; + m_n_acquire_counter_rounded = (m_n_acquire_counter_rounded + 1) % m_n_swapchain_images; + m_last_acquired_image_index = result; return result; @@ -487,9 +491,12 @@ void Anvil::Swapchain::init() for (auto queue_ptr : queues) { - queue_ptr->register_for_callbacks(QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, - on_present_request_issued, - this); /* in_user_arg */ + queue_ptr->register_for_callbacks( + QUEUE_CALLBACK_ID_PRESENT_REQUEST_ISSUED, + std::bind(&Swapchain::on_present_request_issued, + this), + this + ); m_observed_queues.push_back(queue_ptr); } @@ -498,37 +505,25 @@ void Anvil::Swapchain::init() /* Sign up for "about to close the parent window" notifications. Swapchain instance SHOULD be deinitialized * before the window is destroyed, so we're going to act as nice citizens. */ - m_window_ptr->register_for_callbacks(WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, - on_parent_window_about_to_close, - this); + m_window_ptr->register_for_callbacks( + WINDOW_CALLBACK_ID_ABOUT_TO_CLOSE, + std::bind(&Swapchain::on_parent_window_about_to_close, + this), + this + ); } /** TODO */ -void Anvil::Swapchain::on_parent_window_about_to_close(void* in_window_ptr, - void* in_swapchain_raw_ptr) +void Anvil::Swapchain::on_parent_window_about_to_close() { - Anvil::Swapchain* swapchain_ptr = static_cast(in_swapchain_raw_ptr); - - ANVIL_REDUNDANT_ARGUMENT(in_window_ptr); - anvil_assert (swapchain_ptr != nullptr); - - if (swapchain_ptr->m_destroy_swapchain_before_parent_window_closes) + if (m_destroy_swapchain_before_parent_window_closes) { - swapchain_ptr->destroy_swapchain(); + destroy_swapchain(); } } /** TODO */ -void Anvil::Swapchain::on_present_request_issued(void* in_queue_raw_ptr, - void* in_swapchain_raw_ptr) +void Anvil::Swapchain::on_present_request_issued() { - Anvil::Swapchain* swapchain_ptr = static_cast(in_swapchain_raw_ptr); - - ANVIL_REDUNDANT_ARGUMENT(in_queue_raw_ptr); - - if (swapchain_ptr->m_swapchain != VK_NULL_HANDLE) - { - /* Only bump the present counter if a real (ie. non-emulated) swapchain is being used. */ - swapchain_ptr->m_n_present_counter++; - } + m_n_present_counter++; } \ No newline at end of file