diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index e5d88a743..654de16f7 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -455,6 +455,8 @@ void Config::ReadDebuggingValues() {
qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
ReadBasicSetting(Settings::values.use_gdbstub);
ReadBasicSetting(Settings::values.gdbstub_port);
+ ReadBasicSetting(Settings::values.renderer_debug);
+ ReadBasicSetting(Settings::values.dump_command_buffers);
qt_config->beginGroup(QStringLiteral("LLE"));
for (const auto& service_module : Service::service_module_map) {
@@ -624,7 +626,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.texture_filter_name);
if (global) {
- ReadBasicSetting(Settings::values.renderer_debug);
ReadBasicSetting(Settings::values.use_shader_jit);
}
@@ -968,6 +969,8 @@ void Config::SaveDebuggingValues() {
qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
WriteBasicSetting(Settings::values.use_gdbstub);
WriteBasicSetting(Settings::values.gdbstub_port);
+ WriteBasicSetting(Settings::values.renderer_debug);
+ WriteBasicSetting(Settings::values.dump_command_buffers);
qt_config->beginGroup(QStringLiteral("LLE"));
for (const auto& service_module : Settings::values.lle_modules) {
@@ -1102,7 +1105,6 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.texture_filter_name);
if (global) {
- WriteBasicSetting(Settings::values.renderer_debug);
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
true);
}
diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp
index 475d6ab70..48a829afb 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.GetValue()));
ui->toggle_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue());
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.GetValue());
+ ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers.GetValue());
}
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/common/settings.h b/src/common/settings.h
index fb5fd9408..efd9a1520 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -449,6 +449,7 @@ struct Values {
SwitchableSetting graphics_api{GraphicsAPI::OpenGL, "graphics_api"};
SwitchableSetting physical_device{0, "physical_device"};
Setting renderer_debug{false, "renderer_debug"};
+ Setting dump_command_buffers{false, "dump_command_buffers"};
SwitchableSetting use_hw_renderer{true, "use_hw_renderer"};
SwitchableSetting use_hw_shader{true, "use_hw_shader"};
SwitchableSetting separable_shader{false, "use_separable_shader"};
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 91cf17953..d25ac17d4 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -183,8 +183,7 @@ static std::array MakeOrthographicMatrix(float width, float height
}
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