mirror of
https://github.com/simple64/simple64.git
synced 2026-11-01 20:21:52 +01:00
update parallel rdp
This commit is contained in:
1 parent
e6ebcd840f
commit
abfe7e2d30
13 files changed
+244
-101
No files matched your search
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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 *) {}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user