update parallel rdp

This commit is contained in:
Logan McNaughton committed 2022-07-03 09:28:24 -06:00
1 parent e6ebcd840f
commit abfe7e2d30
13 files changed
+244 -101

No files matched your search

+1 -1
View File
@@ -1 +1 @@
4137ff0771ca473b7610a1c8ea307d7a5141aee4
a691960e8d4f72fea6a384fd89881cbdb8a78a0b
@@ -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;
@@ -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);
};
+2 -1
View File
@@ -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
+4 -1
View File
@@ -135,8 +135,9 @@ struct QueueInfo
};
class Context
: public Util::IntrusivePtrEnabled<Context, std::default_delete<Context>, 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<Context>;
}
@@ -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());
@@ -174,6 +174,8 @@ public:
unsigned get_next_offset() const;
void reset();
private:
BindlessDescriptorPoolHandle descriptor_pool;
unsigned max_sets_per_pool = 0;
+3 -1
View File
@@ -164,8 +164,9 @@ private:
}
class Device
: public Util::IntrusivePtrEnabled<Device, std::default_delete<Device>, 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<Device>;
}
@@ -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,
+6 -6
View File
@@ -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()
+10 -4
View File
@@ -179,6 +179,12 @@ private:
ImmutableSamplerBank immutable_sampler_bank;
};
struct Pipeline
{
VkPipeline pipeline;
uint32_t dynamic_mask;
};
class Program : public HashedObject<Program>, 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<Util::IntrusivePODWrapper<VkPipeline>> pipelines;
void destroy_pipeline(VkPipeline pipeline);
VulkanCache<Util::IntrusivePODWrapper<Pipeline>> pipelines;
void destroy_pipeline(const Pipeline &pipeline);
};
}
+65 -32
View File
@@ -104,21 +104,18 @@ float WSI::get_estimated_video_latency()
}
}
bool WSI::init_external_context(std::unique_ptr<Context> 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<ImageHandle> 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>();
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<Context>();
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 *) {}
+59 -15
View File
@@ -27,7 +27,6 @@
#include "vulkan_headers.hpp"
#include "timer.hpp"
#include "wsi_timing.hpp"
#include <memory>
#include <vector>
#include <thread>
#include <chrono>
@@ -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<Vulkan::Context> context);
bool init_external_swapchain(std::vector<Vulkan::ImageHandle> external_images);
void deinit_external();
// First, we need a Util::IntrinsivePtr<Vulkan::Context>.
// 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<ImageHandle> 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> context;
ContextHandle context;
VkSurfaceKHR surface = VK_NULL_HANDLE;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
std::vector<VkImage> swapchain_images;
std::vector<Semaphore> release_semaphores;
std::unique_ptr<Device> device;
DeviceHandle device;
const VolkDeviceTable *table = nullptr;
unsigned swapchain_width = 0;
@@ -237,11 +281,11 @@ private:
WSIPlatform *platform = nullptr;
std::vector<Vulkan::ImageHandle> external_swapchain_images;
std::vector<ImageHandle> 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;