From abfe7e2d305f88848e82b1fadedfd9cd8809fcf2 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Sun, 3 Jul 2022 09:28:24 -0600 Subject: [PATCH] update parallel rdp --- parallel-rdp-standalone/COMMIT | 2 +- .../vulkan/command_buffer.cpp | 78 +++++++++------ .../vulkan/command_buffer.hpp | 14 +-- parallel-rdp-standalone/vulkan/context.cpp | 3 +- parallel-rdp-standalone/vulkan/context.hpp | 5 +- .../vulkan/descriptor_set.cpp | 5 + .../vulkan/descriptor_set.hpp | 2 + parallel-rdp-standalone/vulkan/device.hpp | 4 +- .../vulkan/device_fossilize.cpp | 35 ++++++- parallel-rdp-standalone/vulkan/shader.cpp | 12 +-- parallel-rdp-standalone/vulkan/shader.hpp | 14 ++- parallel-rdp-standalone/vulkan/wsi.cpp | 97 +++++++++++++------ parallel-rdp-standalone/vulkan/wsi.hpp | 74 +++++++++++--- 13 files changed, 244 insertions(+), 101 deletions(-) diff --git a/parallel-rdp-standalone/COMMIT b/parallel-rdp-standalone/COMMIT index 61765a9..f4f2ea7 100644 --- a/parallel-rdp-standalone/COMMIT +++ b/parallel-rdp-standalone/COMMIT @@ -1 +1 @@ -4137ff0771ca473b7610a1c8ea307d7a5141aee4 +a691960e8d4f72fea6a384fd89881cbdb8a78a0b diff --git a/parallel-rdp-standalone/vulkan/command_buffer.cpp b/parallel-rdp-standalone/vulkan/command_buffer.cpp index a8dbf4b..e732709 100644 --- a/parallel-rdp-standalone/vulkan/command_buffer.cpp +++ b/parallel-rdp-standalone/vulkan/command_buffer.cpp @@ -475,7 +475,7 @@ void CommandBuffer::begin_context() dirty = ~0u; dirty_sets = ~0u; dirty_vbos = ~0u; - current_pipeline = VK_NULL_HANDLE; + current_pipeline = {}; current_pipeline_layout = VK_NULL_HANDLE; current_layout = nullptr; pipeline_state.program = nullptr; @@ -721,14 +721,14 @@ void CommandBuffer::end_render_pass() begin_compute(); } -VkPipeline CommandBuffer::build_compute_pipeline(Device *device, const DeferredPipelineCompile &compile, bool synchronous) +Pipeline CommandBuffer::build_compute_pipeline(Device *device, const DeferredPipelineCompile &compile, bool synchronous) { // If we don't have pipeline creation cache control feature, // we must assume compilation can be synchronous. if (!synchronous && !device->get_device_features().pipeline_creation_cache_control_features.pipelineCreationCacheControl) { - return VK_NULL_HANDLE; + return {}; } auto &shader = *compile.program->get_shader(ShaderStage::Compute); @@ -775,7 +775,7 @@ VkPipeline CommandBuffer::build_compute_pipeline(Device *device, const DeferredP compile.static_state.state.subgroup_maximum_size_log2)) { LOGE("Subgroup size configuration not supported.\n"); - return VK_NULL_HANDLE; + return {}; } auto &features = device->get_device_features(); @@ -821,11 +821,11 @@ VkPipeline CommandBuffer::build_compute_pipeline(Device *device, const DeferredP { if (vr < 0) LOGE("Failed to create compute pipeline!\n"); - return VK_NULL_HANDLE; + return {}; } - auto returned_pipeline = compile.program->add_pipeline(compile.hash, compute_pipeline); - if (returned_pipeline != compute_pipeline) + auto returned_pipeline = compile.program->add_pipeline(compile.hash, { compute_pipeline, 0 }); + if (returned_pipeline.pipeline != compute_pipeline) table.vkDestroyPipeline(device->get_device(), compute_pipeline, nullptr); return returned_pipeline; } @@ -849,14 +849,14 @@ void CommandBuffer::extract_pipeline_state(DeferredPipelineCompile &compile) con } } -VkPipeline CommandBuffer::build_graphics_pipeline(Device *device, const DeferredPipelineCompile &compile, bool synchronous) +Pipeline CommandBuffer::build_graphics_pipeline(Device *device, const DeferredPipelineCompile &compile, bool synchronous) { // If we don't have pipeline creation cache control feature, // we must assume compilation can be synchronous. if (!synchronous && !device->get_device_features().pipeline_creation_cache_control_features.pipelineCreationCacheControl) { - return VK_NULL_HANDLE; + return {}; } // Viewport state @@ -872,13 +872,20 @@ VkPipeline CommandBuffer::build_graphics_pipeline(Device *device, const Deferred }; dyn.pDynamicStates = states; + uint32_t dynamic_mask = COMMAND_BUFFER_DIRTY_VIEWPORT_BIT | COMMAND_BUFFER_DIRTY_SCISSOR_BIT; + if (compile.static_state.state.depth_bias_enable) + { states[dyn.dynamicStateCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS; + dynamic_mask |= COMMAND_BUFFER_DIRTY_DEPTH_BIAS_BIT; + } + if (compile.static_state.state.stencil_test) { states[dyn.dynamicStateCount++] = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK; states[dyn.dynamicStateCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; states[dyn.dynamicStateCount++] = VK_DYNAMIC_STATE_STENCIL_WRITE_MASK; + dynamic_mask |= COMMAND_BUFFER_DIRTY_STENCIL_REFERENCE_BIT; } // Blend state @@ -992,7 +999,7 @@ VkPipeline CommandBuffer::build_graphics_pipeline(Device *device, const Deferred else { LOGE("Conservative rasterization is not supported on this device.\n"); - return VK_NULL_HANDLE; + return {}; } } @@ -1072,11 +1079,11 @@ VkPipeline CommandBuffer::build_graphics_pipeline(Device *device, const Deferred { if (res < 0) LOGE("Failed to create graphics pipeline!\n"); - return VK_NULL_HANDLE; + return {}; } - auto returned_pipeline = compile.program->add_pipeline(compile.hash, pipeline); - if (returned_pipeline != pipeline) + auto returned_pipeline = compile.program->add_pipeline(compile.hash, { pipeline, dynamic_mask }); + if (returned_pipeline.pipeline != pipeline) table.vkDestroyPipeline(device->get_device(), pipeline, nullptr); return returned_pipeline; } @@ -1085,9 +1092,9 @@ bool CommandBuffer::flush_compute_pipeline(bool synchronous) { update_hash_compute_pipeline(pipeline_state); current_pipeline = pipeline_state.program->get_pipeline(pipeline_state.hash); - if (current_pipeline == VK_NULL_HANDLE) + if (current_pipeline.pipeline == VK_NULL_HANDLE) current_pipeline = build_compute_pipeline(device, pipeline_state, synchronous); - return current_pipeline != VK_NULL_HANDLE; + return current_pipeline.pipeline != VK_NULL_HANDLE; } void CommandBuffer::update_hash_compute_pipeline(DeferredPipelineCompile &compile) @@ -1172,9 +1179,19 @@ bool CommandBuffer::flush_graphics_pipeline(bool synchronous) { update_hash_graphics_pipeline(pipeline_state, active_vbos); current_pipeline = pipeline_state.program->get_pipeline(pipeline_state.hash); - if (current_pipeline == VK_NULL_HANDLE) + if (current_pipeline.pipeline == VK_NULL_HANDLE) current_pipeline = build_graphics_pipeline(device, pipeline_state, synchronous); - return current_pipeline != VK_NULL_HANDLE; + return current_pipeline.pipeline != VK_NULL_HANDLE; +} + +void CommandBuffer::bind_pipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline, uint32_t active_dynamic_state) +{ + table.vkCmdBindPipeline(cmd, bind_point, pipeline); + + // If some dynamic state is static in the pipeline it clobbers the dynamic state. + // As a performance optimization don't clobber everything. + uint32_t static_state_clobber = ~active_dynamic_state & COMMAND_BUFFER_DYNAMIC_BITS; + set_dirty(static_state_clobber); } bool CommandBuffer::flush_compute_state(bool synchronous) @@ -1183,20 +1200,20 @@ bool CommandBuffer::flush_compute_state(bool synchronous) return false; VK_ASSERT(current_layout); - if (current_pipeline == VK_NULL_HANDLE) + if (current_pipeline.pipeline == VK_NULL_HANDLE) set_dirty(COMMAND_BUFFER_DIRTY_PIPELINE_BIT); if (get_and_clear(COMMAND_BUFFER_DIRTY_STATIC_STATE_BIT | COMMAND_BUFFER_DIRTY_PIPELINE_BIT)) { - VkPipeline old_pipe = current_pipeline; + VkPipeline old_pipe = current_pipeline.pipeline; if (!flush_compute_pipeline(synchronous)) return false; - if (old_pipe != current_pipeline) - table.vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, current_pipeline); + if (old_pipe != current_pipeline.pipeline) + bind_pipeline(VK_PIPELINE_BIND_POINT_COMPUTE, current_pipeline.pipeline, current_pipeline.dynamic_mask); } - if (current_pipeline == VK_NULL_HANDLE) + if (current_pipeline.pipeline == VK_NULL_HANDLE) return false; flush_descriptor_sets(); @@ -1222,25 +1239,22 @@ bool CommandBuffer::flush_render_state(bool synchronous) return false; VK_ASSERT(current_layout); - if (current_pipeline == VK_NULL_HANDLE) + if (current_pipeline.pipeline == VK_NULL_HANDLE) set_dirty(COMMAND_BUFFER_DIRTY_PIPELINE_BIT); // We've invalidated pipeline state, update the VkPipeline. if (get_and_clear(COMMAND_BUFFER_DIRTY_STATIC_STATE_BIT | COMMAND_BUFFER_DIRTY_PIPELINE_BIT | COMMAND_BUFFER_DIRTY_STATIC_VERTEX_BIT)) { - VkPipeline old_pipe = current_pipeline; + VkPipeline old_pipe = current_pipeline.pipeline; if (!flush_graphics_pipeline(synchronous)) return false; - if (old_pipe != current_pipeline) - { - table.vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, current_pipeline); - set_dirty(COMMAND_BUFFER_DYNAMIC_BITS); - } + if (old_pipe != current_pipeline.pipeline) + bind_pipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, current_pipeline.pipeline, current_pipeline.dynamic_mask); } - if (current_pipeline == VK_NULL_HANDLE) + if (current_pipeline.pipeline == VK_NULL_HANDLE) return false; flush_descriptor_sets(); @@ -1468,9 +1482,9 @@ void CommandBuffer::set_program(Program *program) return; pipeline_state.program = program; - current_pipeline = VK_NULL_HANDLE; + current_pipeline = {}; - set_dirty(COMMAND_BUFFER_DIRTY_PIPELINE_BIT | COMMAND_BUFFER_DYNAMIC_BITS); + set_dirty(COMMAND_BUFFER_DIRTY_PIPELINE_BIT); if (!program) return; diff --git a/parallel-rdp-standalone/vulkan/command_buffer.hpp b/parallel-rdp-standalone/vulkan/command_buffer.hpp index fb332c2..26fd030 100644 --- a/parallel-rdp-standalone/vulkan/command_buffer.hpp +++ b/parallel-rdp-standalone/vulkan/command_buffer.hpp @@ -168,7 +168,7 @@ using CommandBufferSaveStateFlags = uint32_t; struct CommandBufferSavedState { - CommandBufferSaveStateFlags flags = 0; + CommandBufferSaveStateFlags flags; ResourceBindings bindings; VkViewport viewport; VkRect2D scissor; @@ -675,10 +675,10 @@ public: void end_debug_channel(); void extract_pipeline_state(DeferredPipelineCompile &compile) const; - static VkPipeline build_graphics_pipeline(Device *device, const DeferredPipelineCompile &compile, - bool synchronous = true); - static VkPipeline build_compute_pipeline(Device *device, const DeferredPipelineCompile &compile, - bool synchronous = true); + static Pipeline build_graphics_pipeline(Device *device, const DeferredPipelineCompile &compile, + bool synchronous = true); + static Pipeline build_compute_pipeline(Device *device, const DeferredPipelineCompile &compile, + bool synchronous = true); bool flush_pipeline_state_without_blocking(); @@ -701,7 +701,7 @@ private: VkDescriptorSet bindless_sets[VULKAN_NUM_DESCRIPTOR_SETS] = {}; VkDescriptorSet allocated_sets[VULKAN_NUM_DESCRIPTOR_SETS] = {}; - VkPipeline current_pipeline = VK_NULL_HANDLE; + Pipeline current_pipeline = {}; VkPipelineLayout current_pipeline_layout = VK_NULL_HANDLE; PipelineLayout *current_layout = nullptr; VkSubpassContents current_contents = VK_SUBPASS_CONTENTS_INLINE; @@ -771,6 +771,8 @@ private: Vulkan::BufferHandle debug_channel_buffer; DebugChannelInterface *debug_channel_interface = nullptr; + void bind_pipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline, uint32_t active_dynamic_state); + static void update_hash_graphics_pipeline(DeferredPipelineCompile &compile, uint32_t &active_vbos); static void update_hash_compute_pipeline(DeferredPipelineCompile &compile); }; diff --git a/parallel-rdp-standalone/vulkan/context.cpp b/parallel-rdp-standalone/vulkan/context.cpp index d7eb09f..5aa3837 100644 --- a/parallel-rdp-standalone/vulkan/context.cpp +++ b/parallel-rdp-standalone/vulkan/context.cpp @@ -432,7 +432,8 @@ bool Context::create_instance(const char **instance_ext, uint32_t instance_ext_c debug_info.pUserData = this; // For some reason, this segfaults Android, sigh ... We get relevant output in logcat anyways. - vkCreateDebugUtilsMessengerEXT(instance, &debug_info, nullptr, &debug_messenger); + if (vkCreateDebugUtilsMessengerEXT) + vkCreateDebugUtilsMessengerEXT(instance, &debug_info, nullptr, &debug_messenger); } #endif diff --git a/parallel-rdp-standalone/vulkan/context.hpp b/parallel-rdp-standalone/vulkan/context.hpp index c8f2ed0..d7deefe 100644 --- a/parallel-rdp-standalone/vulkan/context.hpp +++ b/parallel-rdp-standalone/vulkan/context.hpp @@ -135,8 +135,9 @@ struct QueueInfo }; class Context + : public Util::IntrusivePtrEnabled, HandleCounter> #ifdef GRANITE_VULKAN_FOSSILIZE - : public Fossilize::DeviceQueryInterface + , public Fossilize::DeviceQueryInterface #endif { public: @@ -289,4 +290,6 @@ private: bool descriptor_set_layout_is_supported(const VkDescriptorSetLayoutCreateInfo *set_layout) override; #endif }; + +using ContextHandle = Util::IntrusivePtr; } diff --git a/parallel-rdp-standalone/vulkan/descriptor_set.cpp b/parallel-rdp-standalone/vulkan/descriptor_set.cpp index 3f09940..d3324da 100644 --- a/parallel-rdp-standalone/vulkan/descriptor_set.cpp +++ b/parallel-rdp-standalone/vulkan/descriptor_set.cpp @@ -429,6 +429,11 @@ void BindlessAllocator::begin() views.clear(); } +void BindlessAllocator::reset() +{ + descriptor_pool.reset(); +} + unsigned BindlessAllocator::get_next_offset() const { return unsigned(views.size()); diff --git a/parallel-rdp-standalone/vulkan/descriptor_set.hpp b/parallel-rdp-standalone/vulkan/descriptor_set.hpp index 11c727d..efc0cc0 100644 --- a/parallel-rdp-standalone/vulkan/descriptor_set.hpp +++ b/parallel-rdp-standalone/vulkan/descriptor_set.hpp @@ -174,6 +174,8 @@ public: unsigned get_next_offset() const; + void reset(); + private: BindlessDescriptorPoolHandle descriptor_pool; unsigned max_sets_per_pool = 0; diff --git a/parallel-rdp-standalone/vulkan/device.hpp b/parallel-rdp-standalone/vulkan/device.hpp index 1c081e2..5f123e0 100644 --- a/parallel-rdp-standalone/vulkan/device.hpp +++ b/parallel-rdp-standalone/vulkan/device.hpp @@ -164,8 +164,9 @@ private: } class Device + : public Util::IntrusivePtrEnabled, HandleCounter> #ifdef GRANITE_VULKAN_FOSSILIZE - : public Fossilize::StateCreatorInterface + , public Fossilize::StateCreatorInterface #endif { public: @@ -848,4 +849,5 @@ CommandBufferHandle request_command_buffer_with_ownership_transfer( const OwnershipTransferInfo &info, const Vulkan::Semaphore &semaphore); +using DeviceHandle = Util::IntrusivePtr; } diff --git a/parallel-rdp-standalone/vulkan/device_fossilize.cpp b/parallel-rdp-standalone/vulkan/device_fossilize.cpp index 7c459dc..389d4de 100644 --- a/parallel-rdp-standalone/vulkan/device_fossilize.cpp +++ b/parallel-rdp-standalone/vulkan/device_fossilize.cpp @@ -134,11 +134,42 @@ VkPipeline Device::fossilize_create_graphics_pipeline(Fossilize::Hash hash, VkGr LOGI("Replaying graphics pipeline.\n"); #endif + uint32_t dynamic_state = 0; + if (info.pDynamicState) + { + for (uint32_t i = 0; i < info.pDynamicState->dynamicStateCount; i++) + { + switch (info.pDynamicState->pDynamicStates[i]) + { + case VK_DYNAMIC_STATE_VIEWPORT: + dynamic_state |= COMMAND_BUFFER_DIRTY_VIEWPORT_BIT; + break; + + case VK_DYNAMIC_STATE_SCISSOR: + dynamic_state |= COMMAND_BUFFER_DIRTY_SCISSOR_BIT; + break; + + case VK_DYNAMIC_STATE_DEPTH_BIAS: + dynamic_state |= COMMAND_BUFFER_DIRTY_DEPTH_BIAS_BIT; + break; + + case VK_DYNAMIC_STATE_STENCIL_REFERENCE: + case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: + case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: + dynamic_state |= COMMAND_BUFFER_DIRTY_STENCIL_REFERENCE_BIT; + break; + + default: + break; + } + } + } + VkPipeline pipeline = VK_NULL_HANDLE; VkResult res = table->vkCreateGraphicsPipelines(device, pipeline_cache, 1, &info, nullptr, &pipeline); if (res != VK_SUCCESS) LOGE("Failed to create graphics pipeline!\n"); - return ret->add_pipeline(hash, pipeline); + return ret->add_pipeline(hash, { pipeline, dynamic_state }).pipeline; } VkPipeline Device::fossilize_create_compute_pipeline(Fossilize::Hash hash, VkComputePipelineCreateInfo &info) @@ -162,7 +193,7 @@ VkPipeline Device::fossilize_create_compute_pipeline(Fossilize::Hash hash, VkCom VkResult res = table->vkCreateComputePipelines(device, pipeline_cache, 1, &info, nullptr, &pipeline); if (res != VK_SUCCESS) LOGE("Failed to create compute pipeline!\n"); - return ret->add_pipeline(hash, pipeline); + return ret->add_pipeline(hash, { pipeline, 0 }).pipeline; } bool Device::enqueue_create_graphics_pipeline(Fossilize::Hash hash, diff --git a/parallel-rdp-standalone/vulkan/shader.cpp b/parallel-rdp-standalone/vulkan/shader.cpp index 2cc6cd0..1f792e3 100644 --- a/parallel-rdp-standalone/vulkan/shader.cpp +++ b/parallel-rdp-standalone/vulkan/shader.cpp @@ -600,23 +600,23 @@ Program::Program(Device *device_, Shader *compute_shader) device->bake_program(*this); } -VkPipeline Program::get_pipeline(Hash hash) const +Pipeline Program::get_pipeline(Hash hash) const { auto *ret = pipelines.find(hash); - return ret ? ret->get() : VK_NULL_HANDLE; + return ret ? ret->get() : Pipeline{}; } -VkPipeline Program::add_pipeline(Hash hash, VkPipeline pipeline) +Pipeline Program::add_pipeline(Hash hash, const Pipeline &pipeline) { return pipelines.emplace_yield(hash, pipeline)->get(); } -void Program::destroy_pipeline(VkPipeline pipeline) +void Program::destroy_pipeline(const Pipeline &pipeline) { if (internal_sync) - device->destroy_pipeline_nolock(pipeline); + device->destroy_pipeline_nolock(pipeline.pipeline); else - device->destroy_pipeline(pipeline); + device->destroy_pipeline(pipeline.pipeline); } void Program::promote_read_write_to_read_only() diff --git a/parallel-rdp-standalone/vulkan/shader.hpp b/parallel-rdp-standalone/vulkan/shader.hpp index 6fcd2f7..a441507 100644 --- a/parallel-rdp-standalone/vulkan/shader.hpp +++ b/parallel-rdp-standalone/vulkan/shader.hpp @@ -179,6 +179,12 @@ private: ImmutableSamplerBank immutable_sampler_bank; }; +struct Pipeline +{ + VkPipeline pipeline; + uint32_t dynamic_mask; +}; + class Program : public HashedObject, public InternalSyncEnabled { public: @@ -201,8 +207,8 @@ public: return layout; } - VkPipeline get_pipeline(Util::Hash hash) const; - VkPipeline add_pipeline(Util::Hash hash, VkPipeline pipeline); + Pipeline get_pipeline(Util::Hash hash) const; + Pipeline add_pipeline(Util::Hash hash, const Pipeline &pipeline); void promote_read_write_to_read_only(); @@ -211,7 +217,7 @@ private: Device *device; Shader *shaders[Util::ecast(ShaderStage::Count)] = {}; PipelineLayout *layout = nullptr; - VulkanCache> pipelines; - void destroy_pipeline(VkPipeline pipeline); + VulkanCache> pipelines; + void destroy_pipeline(const Pipeline &pipeline); }; } diff --git a/parallel-rdp-standalone/vulkan/wsi.cpp b/parallel-rdp-standalone/vulkan/wsi.cpp index 1b010a3..aec526e 100644 --- a/parallel-rdp-standalone/vulkan/wsi.cpp +++ b/parallel-rdp-standalone/vulkan/wsi.cpp @@ -104,21 +104,18 @@ float WSI::get_estimated_video_latency() } } -bool WSI::init_external_context(std::unique_ptr fresh_context) +bool WSI::init_from_existing_context(ContextHandle existing_context) { - context = move(fresh_context); - - // Need to have a dummy swapchain in place before we issue create device events. - device.reset(new Device); - device->set_context(*context); - device->init_external_swapchain({ ImageHandle(nullptr) }); - platform->event_device_created(device.get()); + VK_ASSERT(platform); + context = std::move(existing_context); table = &context->get_device_table(); return true; } bool WSI::init_external_swapchain(std::vector swapchain_images_) { + VK_ASSERT(context); + VK_ASSERT(device); swapchain_width = platform->get_surface_width(); swapchain_height = platform->get_surface_height(); swapchain_aspect_ratio = platform->get_aspect_ratio(); @@ -150,26 +147,28 @@ void WSI::set_platform(WSIPlatform *platform_) platform = platform_; } -bool WSI::init(unsigned num_thread_indices, const Context::SystemHandles &system_handles) +bool WSI::init_device() { - auto instance_ext = platform->get_instance_extensions(); - auto device_ext = platform->get_device_extensions(); - context.reset(new Context); - - context->set_application_info(platform->get_application_info()); - context->set_num_thread_indices(num_thread_indices); - context->set_system_handles(system_handles); - if (!context->init_instance_and_device(instance_ext.data(), instance_ext.size(), device_ext.data(), device_ext.size())) - { - LOGE("Failed to create Vulkan device.\n"); - return false; - } - - device.reset(new Device); + VK_ASSERT(context); + device = Util::make_handle(); device->set_context(*context); - table = &context->get_device_table(); - platform->event_device_created(device.get()); + return true; +} + +bool WSI::init_device(DeviceHandle device_handle) +{ + VK_ASSERT(context); + device = std::move(device_handle); + platform->event_device_created(device.get()); + return true; +} + +bool WSI::init_surface_swapchain() +{ + VK_ASSERT(surface == VK_NULL_HANDLE); + VK_ASSERT(context); + VK_ASSERT(device); surface = platform->create_surface(context->get_instance(), context->get_gpu()); if (surface == VK_NULL_HANDLE) @@ -189,8 +188,8 @@ bool WSI::init(unsigned num_thread_indices, const Context::SystemHandles &system { if (index != VK_QUEUE_FAMILY_IGNORED) { - if (vkGetPhysicalDeviceSurfaceSupportKHR(context->get_gpu(), index, surface, &supported) == VK_SUCCESS && - supported) + if (vkGetPhysicalDeviceSurfaceSupportKHR(context->get_gpu(), index, surface, &supported) == + VK_SUCCESS && supported) { queue_present_support |= 1u << index; } @@ -218,7 +217,39 @@ bool WSI::init(unsigned num_thread_indices, const Context::SystemHandles &system return true; } -void WSI::init_surface_and_swapchain(VkSurfaceKHR new_surface) +bool WSI::init_simple(unsigned num_thread_indices, const Context::SystemHandles &system_handles) +{ + if (!init_context_from_platform(num_thread_indices, system_handles)) + return false; + if (!init_device()) + return false; + if (!init_surface_swapchain()) + return false; + return true; +} + +bool WSI::init_context_from_platform(unsigned num_thread_indices, const Context::SystemHandles &system_handles) +{ + VK_ASSERT(platform); + auto instance_ext = platform->get_instance_extensions(); + auto device_ext = platform->get_device_extensions(); + auto new_context = Util::make_handle(); + + new_context->set_application_info(platform->get_application_info()); + new_context->set_num_thread_indices(num_thread_indices); + new_context->set_system_handles(system_handles); + if (!new_context->init_instance_and_device( + instance_ext.data(), instance_ext.size(), + device_ext.data(), device_ext.size())) + { + LOGE("Failed to create Vulkan device.\n"); + return false; + } + + return init_from_existing_context(std::move(new_context)); +} + +void WSI::reinit_surface_and_swapchain(VkSurfaceKHR new_surface) { LOGI("init_surface_and_swapchain()\n"); if (new_surface != VK_NULL_HANDLE) @@ -445,8 +476,7 @@ bool WSI::end_frame() { // If we didn't render into the swapchain this frame, we will return a blank semaphore. external_release = device->consume_release_semaphore(); - if (external_release && !external_release->is_signalled()) - abort(); + VK_ASSERT(!external_release || external_release->is_signalled()); frame_is_external = false; } else @@ -633,7 +663,7 @@ void WSI::set_backbuffer_srgb(bool enable) } } -void WSI::deinit_external() +void WSI::teardown() { if (platform) platform->release_resources(); @@ -645,7 +675,10 @@ void WSI::deinit_external() } if (surface != VK_NULL_HANDLE) + { vkDestroySurfaceKHR(context->get_instance(), surface, nullptr); + surface = VK_NULL_HANDLE; + } if (platform) platform->event_device_destroyed(); @@ -1174,7 +1207,7 @@ VkSurfaceTransformFlagBitsKHR WSI::get_current_prerotate() const WSI::~WSI() { - deinit_external(); + teardown(); } void WSIPlatform::event_device_created(Device *) {} diff --git a/parallel-rdp-standalone/vulkan/wsi.hpp b/parallel-rdp-standalone/vulkan/wsi.hpp index f3c4fa3..6f72840 100644 --- a/parallel-rdp-standalone/vulkan/wsi.hpp +++ b/parallel-rdp-standalone/vulkan/wsi.hpp @@ -27,7 +27,6 @@ #include "vulkan_headers.hpp" #include "timer.hpp" #include "wsi_timing.hpp" -#include #include #include #include @@ -74,14 +73,14 @@ public: return float(get_surface_width()) / float(get_surface_height()); } - virtual bool alive(Vulkan::WSI &wsi) = 0; + virtual bool alive(WSI &wsi) = 0; virtual void poll_input() = 0; virtual bool has_external_swapchain() { return false; } - virtual void block_until_wsi_forward_progress(Vulkan::WSI &wsi) + virtual void block_until_wsi_forward_progress(WSI &wsi) { get_frame_timer().enter_idle(); while (!resize && alive(wsi)) @@ -158,10 +157,33 @@ public: return srgb_backbuffer_enable; } - bool init(unsigned num_thread_indices, const Context::SystemHandles &system_handles); - bool init_external_context(std::unique_ptr context); - bool init_external_swapchain(std::vector external_images); - void deinit_external(); + // First, we need a Util::IntrinsivePtr. + // This holds the instance and device. + + // The simple approach. WSI internally creates the context with instance + device. + // Required information about extensions etc, is pulled from the platform. + bool init_context_from_platform(unsigned num_thread_indices, const Context::SystemHandles &system_handles); + + // If you have your own VkInstance and/or VkDevice, you must create your own Vulkan::Context with + // the appropriate init() call. Based on the platform you use, you must make sure to enable the + // required extensions. + bool init_from_existing_context(ContextHandle context); + + // Then we initialize the Vulkan::Device. Either lets WSI create its own device or reuse an existing handle. + // A device provided here must have been bound to the context. + bool init_device(); + bool init_device(DeviceHandle device); + + // Called after we have a device and context. + // Either we can use a swapchain based on VkSurfaceKHR, or we can supply our own images + // to create a virtual swapchain. + // init_surface_swapchain() is called once. + // Here we create the surface and perform creation of the first swapchain. + bool init_surface_swapchain(); + bool init_external_swapchain(std::vector external_images); + + // Calls init_context_from_platform -> init_device -> init_surface_swapchain in succession. + bool init_simple(unsigned num_thread_indices, const Context::SystemHandles &system_handles); ~WSI(); @@ -175,10 +197,29 @@ public: return *device; } + // Acquires a frame from swapchain, also calls poll_input() after acquire + // since acquire tends to block. bool begin_frame(); + // Presents and iterates frame context. + // Present is skipped if swapchain resource was not touched. + // The normal app loop is something like begin_frame() -> submit work -> end_frame(). bool end_frame(); - void set_external_frame(unsigned index, Vulkan::Semaphore acquire_semaphore, double frame_time); - Vulkan::Semaphore consume_external_release_semaphore(); + + // For external swapchains we don't have a normal acquire -> present cycle. + // - set_external_frame() + // - index replaces the acquire next image index. + // - acquire_semaphore replaces semaphore from acquire next image. + // - frame_time controls the frame time passed down. + // - begin_frame() + // - submit work + // - end_frame() + // - consume_external_release_semaphore() + // - Returns the release semaphore that can passed to the equivalent of QueuePresentKHR. + void set_external_frame(unsigned index, Semaphore acquire_semaphore, double frame_time); + Semaphore consume_external_release_semaphore(); + + // Equivalent to calling destructor. + void teardown(); WSIPlatform &get_platform() { @@ -186,8 +227,11 @@ public: return *platform; } + // For Android. Used in response to APP_CMD_{INIT,TERM}_WINDOW once + // we have a proper swapchain going. + // We have to completely drain swapchain before the window is terminated on Android. void deinit_surface_and_swapchain(); - void init_surface_and_swapchain(VkSurfaceKHR new_surface); + void reinit_surface_and_swapchain(VkSurfaceKHR new_surface); float get_estimated_video_latency(); void set_window_title(const std::string &title); @@ -205,12 +249,12 @@ public: private: void update_framebuffer(unsigned width, unsigned height); - std::unique_ptr context; + ContextHandle context; VkSurfaceKHR surface = VK_NULL_HANDLE; VkSwapchainKHR swapchain = VK_NULL_HANDLE; std::vector swapchain_images; std::vector release_semaphores; - std::unique_ptr device; + DeviceHandle device; const VolkDeviceTable *table = nullptr; unsigned swapchain_width = 0; @@ -237,11 +281,11 @@ private: WSIPlatform *platform = nullptr; - std::vector external_swapchain_images; + std::vector external_swapchain_images; unsigned external_frame_index = 0; - Vulkan::Semaphore external_acquire; - Vulkan::Semaphore external_release; + Semaphore external_acquire; + Semaphore external_release; bool frame_is_external = false; bool using_display_timing = false; bool srgb_backbuffer_enable = true;