update parallel rdp

This commit is contained in:
Logan McNaughton
2022-12-20 09:32:55 -05:00
parent 06a962d607
commit 08a78f6073
46 changed files with 1896 additions and 631 deletions
+140 -86
View File
@@ -20,7 +20,11 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define NOMINMAX
#include "device.hpp"
#ifdef GRANITE_VULKAN_FOSSILIZE
#include "device_fossilize.hpp"
#endif
#include "format.hpp"
#include "timeline_trace_file.hpp"
#include "type_to_string.hpp"
@@ -39,28 +43,19 @@
#include "string_helpers.hpp"
#endif
#ifdef GRANITE_VULKAN_MT
#include "thread_id.hpp"
static unsigned get_thread_index()
{
return Util::get_current_thread_index();
}
#define LOCK() std::lock_guard<std::mutex> holder__{lock.lock}
#define LOCK_MEMORY() std::lock_guard<std::mutex> holder__{lock.memory_lock}
#define LOCK() std::lock_guard<std::mutex> _holder_##__COUNTER__{lock.lock}
#define LOCK_MEMORY() std::lock_guard<std::mutex> _holder_##__COUNTER__{lock.memory_lock}
#define LOCK_CACHE() ::Util::RWSpinLockReadHolder _holder_##__COUNTER__{lock.read_only_cache}
#define DRAIN_FRAME_LOCK() \
std::unique_lock<std::mutex> holder__{lock.lock}; \
lock.cond.wait(holder__, [&]() { \
std::unique_lock<std::mutex> _holder{lock.lock}; \
lock.cond.wait(_holder, [&]() { \
return lock.counter == 0; \
})
#else
#define LOCK() ((void)0)
#define LOCK_MEMORY() ((void)0)
#define DRAIN_FRAME_LOCK() VK_ASSERT(lock.counter == 0)
static unsigned get_thread_index()
{
return 0;
}
#endif
using namespace Util;
@@ -96,9 +91,7 @@ Device::Device()
, texture_manager(this)
#endif
{
#ifdef GRANITE_VULKAN_MT
cookie.store(0);
#endif
}
Semaphore Device::request_semaphore(VkSemaphoreTypeKHR type, VkSemaphore vk_semaphore, bool transfer_ownership)
@@ -386,6 +379,7 @@ Shader *Device::request_shader(const uint32_t *data, size_t size,
const ImmutableSamplerBank *sampler_bank)
{
auto hash = Shader::hash(data, size, sampler_bank);
LOCK_CACHE();
auto *ret = shaders.find(hash);
if (!ret)
ret = shaders.emplace_yield(hash, hash, this, data, size, layout, sampler_bank);
@@ -394,6 +388,7 @@ Shader *Device::request_shader(const uint32_t *data, size_t size,
Shader *Device::request_shader_by_hash(Hash hash)
{
LOCK_CACHE();
return shaders.find(hash);
}
@@ -405,6 +400,7 @@ Program *Device::request_program(Vulkan::Shader *compute_shader)
Util::Hasher hasher;
hasher.u64(compute_shader->get_hash());
LOCK_CACHE();
auto hash = hasher.get();
auto *ret = programs.find(hash);
if (!ret)
@@ -433,6 +429,7 @@ Program *Device::request_program(Shader *vertex, Shader *fragment)
hasher.u64(fragment->get_hash());
auto hash = hasher.get();
LOCK_CACHE();
auto *ret = programs.find(hash);
if (!ret)
@@ -490,6 +487,7 @@ DescriptorSetAllocator *Device::request_descriptor_set_allocator(const Descripto
});
auto hash = h.get();
LOCK_CACHE();
auto *ret = descriptor_set_allocators.find(hash);
if (!ret)
ret = descriptor_set_allocators.emplace_yield(hash, hash, this, layout, stages_for_bindings, immutable_samplers_);
@@ -827,11 +825,10 @@ void Device::init_workarounds()
void Device::set_context(const Context &context)
{
ctx = &context;
table = &context.get_device_table();
#ifdef GRANITE_VULKAN_MT
register_thread_index(0);
#endif
instance = context.get_instance();
gpu = context.get_gpu();
device = context.get_device();
@@ -850,7 +847,6 @@ void Device::set_context(const Context &context)
init_pipeline_cache();
init_timeline_semaphores();
init_bindless();
init_frame_contexts(2); // By default, regular double buffer between CPU and GPU.
@@ -894,36 +890,39 @@ void Device::set_context(const Context &context)
queue_data[i].performance_query_pool.init_device(this, queue_info.family_indices[i]);
}
#ifdef GRANITE_VULKAN_FILESYSTEM
init_shader_manager_cache();
#endif
#ifdef GRANITE_VULKAN_FOSSILIZE
init_pipeline_state(context.get_feature_filter());
#endif
if (system_handles.timeline_trace_file)
init_calibrated_timestamps();
}
void Device::init_bindless()
void Device::begin_shader_caches()
{
if (!ext.supports_descriptor_indexing)
if (!ctx)
{
LOGE("No context. Forgot Device::set_context()?\n");
return;
}
DescriptorSetLayout layout;
layout.array_size[0] = DescriptorSetLayout::UNSIZED_ARRAY;
for (unsigned i = 1; i < VULKAN_NUM_BINDINGS; i++)
layout.array_size[i] = 1;
layout.separate_image_mask = 1;
uint32_t stages_for_sets[VULKAN_NUM_BINDINGS] = { VK_SHADER_STAGE_ALL };
bindless_sampled_image_allocator_integer = request_descriptor_set_allocator(layout, stages_for_sets, nullptr);
layout.fp_mask = 1;
bindless_sampled_image_allocator_fp = request_descriptor_set_allocator(layout, stages_for_sets, nullptr);
#ifdef GRANITE_VULKAN_FOSSILIZE
init_pipeline_state(ctx->get_feature_filter(), ctx->get_physical_device_features(),
ctx->get_application_info());
#elif defined(GRANITE_VULKAN_FILESYSTEM)
// Fossilize init will deal with init_shader_manager_cache()
init_shader_manager_cache();
#endif
}
#ifndef GRANITE_VULKAN_FOSSILIZE
unsigned Device::query_initialization_progress(InitializationStage) const
{
// If we don't have Fossilize, everything is considered done up front.
return 100;
}
void Device::wait_shader_caches()
{
}
#endif
void Device::init_timeline_semaphores()
{
if (!ext.timeline_semaphore_features.timelineSemaphore)
@@ -1271,6 +1270,13 @@ void Device::submit_empty_inner(QueueIndices physical_type, InternalFence *fence
collect_wait_semaphores(data, wait_semaphores);
composer.add_wait_submissions(wait_semaphores);
for (auto consume : frame().consumed_semaphores)
{
composer.add_wait_semaphore(consume, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
frame().recycled_semaphores.push_back(consume);
}
frame().consumed_semaphores.clear();
emit_queue_signals(composer, external_semaphore,
timeline_semaphore, timeline_value,
fence, semaphore_count, semaphores);
@@ -1590,6 +1596,19 @@ void Helper::BatchComposer::add_wait_semaphore(SemaphoreHolder &sem, VkPipelineS
wait_counts[submit_index].push_back(is_timeline ? sem.get_timeline_value() : 0);
}
void Helper::BatchComposer::add_wait_semaphore(VkSemaphore sem, VkPipelineStageFlags stage)
{
if (!cmds[submit_index].empty() || !signals[submit_index].empty())
begin_batch();
if (split_binary_timeline_semaphores && has_timeline_semaphore_in_batch(submit_index))
begin_batch();
waits[submit_index].push_back(sem);
wait_stages[submit_index].push_back(stage);
wait_counts[submit_index].push_back(0);
}
void Device::emit_queue_signals(Helper::BatchComposer &composer,
SemaphoreHolder *external_semaphore,
VkSemaphore sem, uint64_t timeline, InternalFence *fence,
@@ -1758,6 +1777,13 @@ void Device::submit_queue(QueueIndices physical_type, InternalFence *fence,
if (fence)
fence->fence = cleared_fence;
for (auto consume : frame().consumed_semaphores)
{
composer.add_wait_semaphore(consume, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
frame().recycled_semaphores.push_back(consume);
}
frame().consumed_semaphores.clear();
emit_queue_signals(composer, external_semaphore, timeline_semaphore, timeline_value,
fence, semaphore_count, semaphores);
@@ -1850,7 +1876,9 @@ void Device::end_frame_nolock()
for (auto &i : queue_flush_order)
{
if (queue_data[i].need_fence || !frame().submissions[i].empty())
if (queue_data[i].need_fence ||
!frame().submissions[i].empty() ||
!frame().consumed_semaphores.empty())
{
submit_queue(i, &fence);
if (fence.fence != VK_NULL_HANDLE)
@@ -1908,9 +1936,7 @@ CommandBufferHandle Device::request_profiled_command_buffer_for_thread(unsigned
CommandBufferHandle Device::request_command_buffer_nolock(unsigned thread_index, CommandBuffer::Type type, bool profiled)
{
#ifndef GRANITE_VULKAN_MT
VK_ASSERT(thread_index == 0);
#endif
auto physical_type = get_physical_queue_type(type);
auto &pool = frame().cmd_pools[physical_type][thread_index];
auto cmd = pool.request_command_buffer();
@@ -2019,14 +2045,14 @@ bool Device::swapchain_touched() const
Device::~Device()
{
wait_idle();
managers.timestamps.log_simple();
wsi.acquire.reset();
wsi.release.reset();
wsi.swapchain.clear();
wait_idle();
managers.timestamps.log_simple();
if (pipeline_cache != VK_NULL_HANDLE)
{
flush_pipeline_cache();
@@ -2126,7 +2152,6 @@ void Device::init_swapchain(const std::vector<VkImage> &swapchain_images, unsign
{
DRAIN_FRAME_LOCK();
wsi.swapchain.clear();
wait_idle_nolock();
auto info = ImageCreateInfo::render_target(width, height, format);
info.usage = usage;
@@ -2256,6 +2281,12 @@ void Device::destroy_semaphore(VkSemaphore semaphore)
destroy_semaphore_nolock(semaphore);
}
void Device::consume_semaphore(VkSemaphore semaphore)
{
LOCK();
consume_semaphore_nolock(semaphore);
}
void Device::recycle_semaphore(VkSemaphore semaphore)
{
LOCK();
@@ -2304,6 +2335,12 @@ void Device::destroy_semaphore_nolock(VkSemaphore semaphore)
frame().destroyed_semaphores.push_back(semaphore);
}
void Device::consume_semaphore_nolock(VkSemaphore semaphore)
{
VK_ASSERT(!exists(frame().consumed_semaphores, semaphore));
frame().consumed_semaphores.push_back(semaphore);
}
void Device::recycle_semaphore_nolock(VkSemaphore semaphore)
{
VK_ASSERT(!exists(frame().recycled_semaphores, semaphore));
@@ -2415,15 +2452,10 @@ void Device::wait_idle_nolock()
framebuffer_allocator.clear();
transient_allocator.clear();
#ifdef GRANITE_VULKAN_MT
for (auto &allocator : descriptor_set_allocators.get_read_only())
allocator.clear();
for (auto &allocator : descriptor_set_allocators.get_read_write())
allocator.clear();
#else
for (auto &allocator : descriptor_set_allocators)
allocator.clear();
#endif
for (auto &frame : per_frame)
{
@@ -2441,20 +2473,25 @@ void Device::wait_idle_nolock()
void Device::promote_read_write_caches_to_read_only()
{
#ifdef GRANITE_VULKAN_MT
pipeline_layouts.move_to_read_only();
descriptor_set_allocators.move_to_read_only();
shaders.move_to_read_only();
programs.move_to_read_only();
for (auto &program : programs.get_read_only())
program.promote_read_write_to_read_only();
render_passes.move_to_read_only();
immutable_samplers.move_to_read_only();
immutable_ycbcr_conversions.move_to_read_only();
// Components which could potentially call into these must hold global reader locks.
// - A CommandBuffer holds a read lock for its lifetime.
// - Fossilize replay in the background also holds lock.
if (lock.read_only_cache.try_lock_write())
{
pipeline_layouts.move_to_read_only();
descriptor_set_allocators.move_to_read_only();
shaders.move_to_read_only();
programs.move_to_read_only();
for (auto &program : programs.get_read_only())
program.promote_read_write_to_read_only();
render_passes.move_to_read_only();
immutable_samplers.move_to_read_only();
immutable_ycbcr_conversions.move_to_read_only();
#ifdef GRANITE_VULKAN_FILESYSTEM
shader_manager.promote_read_write_caches_to_read_only();
#endif
shader_manager.promote_read_write_caches_to_read_only();
#endif
lock.read_only_cache.unlock_write();
}
}
void Device::next_frame_context()
@@ -2474,21 +2511,18 @@ void Device::next_frame_context()
framebuffer_allocator.begin_frame();
transient_allocator.begin_frame();
#ifdef GRANITE_VULKAN_MT
for (auto &allocator : descriptor_set_allocators.get_read_only())
allocator.begin_frame();
for (auto &allocator : descriptor_set_allocators.get_read_write())
allocator.begin_frame();
#else
for (auto &allocator : descriptor_set_allocators)
allocator.begin_frame();
#endif
VK_ASSERT(!per_frame.empty());
frame_context_index++;
if (frame_context_index >= per_frame.size())
frame_context_index = 0;
promote_read_write_caches_to_read_only();
frame().begin();
recalibrate_timestamps();
frame_context_begin_ts = write_calibrated_timestamp_nolock();
@@ -2678,9 +2712,7 @@ void Device::decrement_frame_counter_nolock()
{
VK_ASSERT(lock.counter > 0);
lock.counter--;
#ifdef GRANITE_VULKAN_MT
lock.cond.notify_all();
#endif
}
void Device::PerFrame::trim_command_pools()
@@ -2794,12 +2826,11 @@ void Device::PerFrame::begin()
managers.semaphore.recycle(semaphore);
for (auto &event : recycled_events)
managers.event.recycle(event);
VK_ASSERT(consumed_semaphores.empty());
if (!allocations.empty())
{
#ifdef GRANITE_VULKAN_MT
std::lock_guard<std::mutex> holder{device.lock.memory_lock};
#endif
for (auto &alloc : allocations)
alloc.free_immediate(managers.memory);
}
@@ -3417,11 +3448,17 @@ InitialImageBuffer Device::create_image_staging_buffer(const TextureFormatLayout
buffer_info.domain = BufferDomain::Host;
buffer_info.size = layout.get_required_size();
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
result.buffer = create_buffer(buffer_info, nullptr);
{
GRANITE_SCOPED_TIMELINE_EVENT_FILE(system_handles.timeline_trace_file, "allocate-image-staging-buffer");
result.buffer = create_buffer(buffer_info, nullptr);
}
set_name(*result.buffer, "image-upload-staging-buffer");
auto *mapped = static_cast<uint8_t *>(map_host_buffer(*result.buffer, MEMORY_ACCESS_WRITE_BIT));
memcpy(mapped, layout.data(), layout.get_required_size());
{
GRANITE_SCOPED_TIMELINE_EVENT_FILE(system_handles.timeline_trace_file, "copy-image-staging-buffer");
memcpy(mapped, layout.data(), layout.get_required_size());
}
unmap_host_buffer(*result.buffer, MEMORY_ACCESS_WRITE_BIT);
layout.build_buffer_image_copies(result.blits);
@@ -3462,7 +3499,10 @@ InitialImageBuffer Device::create_image_staging_buffer(const ImageCreateInfo &in
buffer_info.domain = BufferDomain::Host;
buffer_info.size = layout.get_required_size();
buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
result.buffer = create_buffer(buffer_info, nullptr);
{
GRANITE_SCOPED_TIMELINE_EVENT_FILE(system_handles.timeline_trace_file, "allocate-image-staging-buffer");
result.buffer = create_buffer(buffer_info, nullptr);
}
set_name(*result.buffer, "image-upload-staging-buffer");
// And now, do the actual copy.
@@ -3471,6 +3511,7 @@ InitialImageBuffer Device::create_image_staging_buffer(const ImageCreateInfo &in
layout.set_buffer(mapped, layout.get_required_size());
GRANITE_SCOPED_TIMELINE_EVENT_FILE(system_handles.timeline_trace_file, "copy-image-staging-buffer");
for (unsigned level = 0; level < copy_levels; level++)
{
const auto &mip_info = layout.get_mip_info(level);
@@ -4158,6 +4199,7 @@ const ImmutableSampler *Device::request_immutable_sampler(const SamplerCreateInf
else
h.u32(0);
LOCK_CACHE();
auto *sampler = immutable_samplers.find(h.get());
if (!sampler)
sampler = immutable_samplers.emplace_yield(h.get(), h.get(), this, sampler_info, ycbcr);
@@ -4180,6 +4222,7 @@ const ImmutableYcbcrConversion *Device::request_immutable_ycbcr_conversion(
h.u32(info.ycbcrModel);
h.u32(info.ycbcrRange);
LOCK_CACHE();
auto *sampler = immutable_ycbcr_conversions.find(h.get());
if (!sampler)
sampler = immutable_ycbcr_conversions.emplace_yield(h.get(), h.get(), this, info);
@@ -4201,22 +4244,29 @@ BindlessDescriptorPoolHandle Device::create_bindless_descriptor_pool(BindlessRes
if (!ext.supports_descriptor_indexing)
return BindlessDescriptorPoolHandle{nullptr};
DescriptorSetAllocator *allocator = nullptr;
DescriptorSetLayout layout;
const uint32_t stages_for_sets[VULKAN_NUM_BINDINGS] = { VK_SHADER_STAGE_ALL };
layout.array_size[0] = DescriptorSetLayout::UNSIZED_ARRAY;
for (unsigned i = 1; i < VULKAN_NUM_BINDINGS; i++)
layout.array_size[i] = 1;
switch (type)
{
case BindlessResourceType::ImageFP:
allocator = bindless_sampled_image_allocator_fp;
layout.separate_image_mask = 1;
layout.fp_mask = 1;
break;
case BindlessResourceType::ImageInt:
allocator = bindless_sampled_image_allocator_integer;
layout.separate_image_mask = 1;
break;
default:
break;
return BindlessDescriptorPoolHandle{nullptr};
}
auto *allocator = request_descriptor_set_allocator(layout, stages_for_sets, nullptr);
VkDescriptorPool pool = VK_NULL_HANDLE;
if (allocator)
pool = allocator->allocate_bindless_pool(num_sets, num_descriptors);
@@ -4670,12 +4720,7 @@ VkFormat Device::get_default_depth_format() const
uint64_t Device::allocate_cookie()
{
// Reserve lower bits for "special purposes".
#ifdef GRANITE_VULKAN_MT
return cookie.fetch_add(16, std::memory_order_relaxed) + 16;
#else
cookie += 16;
return cookie;
#endif
}
const RenderPass &Device::request_render_pass(const RenderPassInfo &info, bool compatible)
@@ -5048,6 +5093,15 @@ TextureManager &Device::get_texture_manager()
ShaderManager &Device::get_shader_manager()
{
#ifdef GRANITE_VULKAN_FOSSILIZE
if (query_initialization_progress(InitializationStage::ShaderModules) < 100)
{
LOGW("Querying shader manager before completion of module initialization.\n"
"Application should not hit this case.\n"
"Blocking until completion ... Try using DeviceShaderModuleReadyEvent or PipelineReadyEvent instead.\n");
block_until_shader_module_ready();
}
#endif
return shader_manager;
}
#endif