diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 79e670fb4..dc763e22f 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -331,6 +331,8 @@ void Config::ReadDebuggingValues() { qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool(); Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt(); + Settings::values.renderer_debug = ReadSetting(QStringLiteral("renderer_debug"), false).toBool(); + Settings::values.dump_command_buffers = ReadSetting(QStringLiteral("dump_command_buffers"), false).toBool(); qt_config->beginGroup(QStringLiteral("LLE")); for (const auto& service_module : Service::service_module_map) { @@ -486,7 +488,6 @@ void Config::ReadRendererValues() { ReadSetting(QStringLiteral("graphics_api"), static_cast(Settings::GraphicsAPI::OpenGL)) .toUInt()); Settings::values.physical_device = ReadSetting(QStringLiteral("physical_device"), 0).toUInt(); - Settings::values.renderer_debug = ReadSetting(QStringLiteral("renderer_debug"), false).toBool(); Settings::values.use_hw_renderer = ReadSetting(QStringLiteral("use_hw_renderer"), true).toBool(); Settings::values.use_hw_shader = ReadSetting(QStringLiteral("use_hw_shader"), true).toBool(); @@ -891,6 +892,8 @@ void Config::SaveDebuggingValues() { qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false); WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689); + WriteSetting(QStringLiteral("renderer_debug"), Settings::values.renderer_debug, false); + WriteSetting(QStringLiteral("dump_command_buffers"), Settings::values.dump_command_buffers, false); qt_config->beginGroup(QStringLiteral("LLE")); for (const auto& service_module : Settings::values.lle_modules) { @@ -1002,7 +1005,6 @@ void Config::SaveRendererValues() { WriteSetting(QStringLiteral("graphics_api"), static_cast(Settings::values.graphics_api), static_cast(Settings::GraphicsAPI::OpenGL)); WriteSetting(QStringLiteral("physical_device"), Settings::values.physical_device, 0); - WriteSetting(QStringLiteral("renderer_debug"), Settings::values.renderer_debug, false); WriteSetting(QStringLiteral("use_hw_renderer"), Settings::values.use_hw_renderer, true); WriteSetting(QStringLiteral("use_hw_shader"), Settings::values.use_hw_shader, true); #ifdef __APPLE__ diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp index 5066adba2..1cd0e2bd5 100644 --- a/src/citra_qt/configuration/configure_debug.cpp +++ b/src/citra_qt/configuration/configure_debug.cpp @@ -26,6 +26,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent) const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); ui->toggle_cpu_jit->setEnabled(!is_powered_on); ui->toggle_renderer_debug->setEnabled(!is_powered_on); + ui->toggle_dump_command_buffers->setEnabled(!is_powered_on); } ConfigureDebug::~ConfigureDebug() = default; @@ -39,6 +40,7 @@ void ConfigureDebug::SetConfiguration() { ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit); ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug); + ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers); } void ConfigureDebug::ApplyConfiguration() { @@ -52,6 +54,7 @@ void ConfigureDebug::ApplyConfiguration() { Log::SetGlobalFilter(filter); Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked(); + Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked(); } void ConfigureDebug::RetranslateUI() { diff --git a/src/citra_qt/configuration/configure_debug.ui b/src/citra_qt/configuration/configure_debug.ui index 9edcfacaa..fbac8fecc 100644 --- a/src/citra_qt/configuration/configure_debug.ui +++ b/src/citra_qt/configuration/configure_debug.ui @@ -6,8 +6,8 @@ 0 0 - 443 - 300 + 454 + 356 @@ -132,6 +132,13 @@ + + + + Dump command buffers + + + diff --git a/src/core/settings.h b/src/core/settings.h index fb0f7f44b..6dd10502d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -167,6 +167,7 @@ struct Values { GraphicsAPI graphics_api; u16 physical_device; bool renderer_debug; + bool dump_command_buffers; bool use_hw_renderer; bool use_hw_shader; bool separable_shader; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index b60e5ea92..461001bdb 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -154,8 +154,7 @@ struct ScreenRectVertex { constexpr u32 VERTEX_BUFFER_SIZE = sizeof(ScreenRectVertex) * 8192; RendererVulkan::RendererVulkan(Frontend::EmuWindow& window) - : RendererBase{window}, instance{window, Settings::values.physical_device, - Settings::values.renderer_debug}, + : RendererBase{window}, instance{window, Settings::values.physical_device}, scheduler{instance, *this}, renderpass_cache{instance, scheduler}, runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache}, vertex_buffer{ diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 38d8d5488..cffc64787 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -4,6 +4,7 @@ #include #include "common/assert.h" +#include "core/settings.h" #include "core/frontend/emu_window.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_platform.h" @@ -66,7 +67,7 @@ Instance::Instance() { physical_devices = instance.enumeratePhysicalDevices(); } -Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index, bool enable_validation) { +Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index) { auto window_info = window.GetWindowInfo(); // Fetch instance independant function pointers @@ -90,8 +91,16 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index, bool .engineVersion = VK_MAKE_VERSION(1, 0, 0), .apiVersion = available_version}; - const std::array layers = {"VK_LAYER_KHRONOS_validation"}; - const u32 layer_count = enable_validation ? 1u : 0u; + u32 layer_count = 0; + std::array layers; + + if (Settings::values.renderer_debug) { + layers[layer_count++] = "VK_LAYER_KHRONOS_validation"; + } + if (Settings::values.dump_command_buffers) { + layers[layer_count++] = "VK_LAYER_LUNARG_api_dump"; + } + const vk::InstanceCreateInfo instance_info = {.pApplicationInfo = &application_info, .enabledLayerCount = layer_count, .ppEnabledLayerNames = layers.data(), diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index c5f970a32..9cf70003f 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -32,7 +32,7 @@ struct FormatTraits { class Instance { public: Instance(); ///< Portable constructor used to query physical devices - Instance(Frontend::EmuWindow& window, u32 physical_device_index, bool enable_validation); + Instance(Frontend::EmuWindow& window, u32 physical_device_index); ~Instance(); /// Returns the FormatTraits struct for the provided pixel format @@ -87,6 +87,7 @@ public: /// Returns true when VK_KHR_timeline_semaphore is supported bool IsTimelineSemaphoreSupported() const { + return false; return timeline_semaphores; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 0b67ca685..68a5a7c97 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -601,7 +601,13 @@ void PipelineCache::BindDescriptorSets() { .descriptorSetCount = DESCRIPTOR_BATCH_SIZE, .pSetLayouts = layouts.data()}; - batch = device.allocateDescriptorSets(alloc_info); + try { + batch = device.allocateDescriptorSets(alloc_info); + } catch (vk::OutOfPoolMemoryError& err) { + LOG_CRITICAL(Render_Vulkan, "Run out of pool memory for layout {}: {}", + i, err.what()); + UNREACHABLE(); + } } vk::DescriptorSet set = batch.back(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 9f11525a2..14271634b 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -95,7 +95,7 @@ constexpr VertexLayout RasterizerVulkan::HardwareVertex::GetVertexLayout() { return layout; } -constexpr u32 VERTEX_BUFFER_SIZE = 256 * 1024 * 1024; +constexpr u32 VERTEX_BUFFER_SIZE = 64 * 1024 * 1024; constexpr u32 INDEX_BUFFER_SIZE = 8 * 1024 * 1024; constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024; constexpr u32 TEXTURE_BUFFER_SIZE = 16 * 1024 * 1024; diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp index e70767259..fc5c5e7a3 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp @@ -69,7 +69,7 @@ StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u vk::BufferUsageFlagBits usage, std::span view_formats) : instance{instance}, scheduler{scheduler}, staging{instance, size, vk::BufferUsageFlagBits::eTransferSrc}, - usage{usage}, total_size{size} { + usage{usage}, total_size{size * SCHEDULER_COMMAND_COUNT} { const vk::BufferCreateInfo buffer_info = { .size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst}; @@ -98,7 +98,7 @@ StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u } view_count = view_formats.size(); - bucket_size = size / SCHEDULER_COMMAND_COUNT; + bucket_size = size; } StreamBuffer::~StreamBuffer() { @@ -177,9 +177,4 @@ void StreamBuffer::Flush() { buckets[next_bucket].invalid = true; } -u32 StreamBuffer::GetBufferOffset() const { - const u32 current_bucket = scheduler.GetCurrentSlotIndex(); - return current_bucket * bucket_size + buckets[current_bucket].offset; -} - } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h index 87c4955ec..f4038ecb4 100644 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.h +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h @@ -48,9 +48,6 @@ public: /// Flushes staging memory to the GPU buffer void Flush(); - /// Returns the current buffer offset - u32 GetBufferOffset() const; - /// Returns the Vulkan buffer handle vk::Buffer GetHandle() const { return buffer; diff --git a/src/video_core/renderer_vulkan/vk_task_scheduler.cpp b/src/video_core/renderer_vulkan/vk_task_scheduler.cpp index fe62169c8..38310dd03 100644 --- a/src/video_core/renderer_vulkan/vk_task_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_task_scheduler.cpp @@ -33,7 +33,6 @@ TaskScheduler::TaskScheduler(const Instance& instance, RendererVulkan& renderer) vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eUniformBufferDynamic, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eSampledImage, 2048}, - vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler, 512}, vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 2048}, vk::DescriptorPoolSize{vk::DescriptorType::eUniformTexelBuffer, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eStorageImage, 1024}}; @@ -91,7 +90,7 @@ void TaskScheduler::Synchronize(u32 slot) { const auto& command = commands[slot]; vk::Device device = instance.GetDevice(); - u32 completed_counter = GetFenceCounter(); + const u64 completed_counter = GetFenceCounter(); if (command.fence_counter > completed_counter) { if (instance.IsTimelineSemaphoreSupported()) { const vk::SemaphoreWaitInfo wait_info = { @@ -134,6 +133,16 @@ void TaskScheduler::Submit(SubmitMode mode) { command_buffers[command_buffer_count++] = command.render_command_buffer; + const auto QueueSubmit = [this](const vk::SubmitInfo& info, vk::Fence fence) { + try { + vk::Queue queue = instance.GetGraphicsQueue(); + queue.submit(info, fence); + } catch (vk::DeviceLostError& err) { + LOG_CRITICAL(Render_Vulkan, "Device lost during submit: {}", err.what()); + UNREACHABLE(); + } + }; + const bool swapchain_sync = True(mode & SubmitMode::SwapchainSynced); if (instance.IsTimelineSemaphoreSupported()) { const u32 wait_semaphore_count = swapchain_sync ? 2u : 1u; @@ -166,9 +175,7 @@ void TaskScheduler::Submit(SubmitMode mode) { .pSignalSemaphores = signal_semaphores.data(), }; - vk::Queue queue = instance.GetGraphicsQueue(); - queue.submit(submit_info); - + QueueSubmit(submit_info, command.fence); } else { const u32 signal_semaphore_count = swapchain_sync ? 1u : 0u; const u32 wait_semaphore_count = swapchain_sync ? 1u : 0u; @@ -185,8 +192,7 @@ void TaskScheduler::Submit(SubmitMode mode) { .pSignalSemaphores = &command.present_ready, }; - vk::Queue queue = instance.GetGraphicsQueue(); - queue.submit(submit_info, command.fence); + QueueSubmit(submit_info, command.fence); } // Block host until the GPU catches up