renderer_vulkan: Catch and log more runtime errors

* Also add the ability to enable command buffer dumping which is very useful
This commit is contained in:
emufan4568
2022-10-16 13:09:51 +03:00
committed by GPUCode
parent 558062efd7
commit 2b37997a95
12 changed files with 55 additions and 29 deletions

View File

@ -455,6 +455,8 @@ void Config::ReadDebuggingValues() {
qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
ReadBasicSetting(Settings::values.use_gdbstub); ReadBasicSetting(Settings::values.use_gdbstub);
ReadBasicSetting(Settings::values.gdbstub_port); ReadBasicSetting(Settings::values.gdbstub_port);
ReadBasicSetting(Settings::values.renderer_debug);
ReadBasicSetting(Settings::values.dump_command_buffers);
qt_config->beginGroup(QStringLiteral("LLE")); qt_config->beginGroup(QStringLiteral("LLE"));
for (const auto& service_module : Service::service_module_map) { for (const auto& service_module : Service::service_module_map) {
@ -624,7 +626,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.texture_filter_name); ReadGlobalSetting(Settings::values.texture_filter_name);
if (global) { if (global) {
ReadBasicSetting(Settings::values.renderer_debug);
ReadBasicSetting(Settings::values.use_shader_jit); 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); qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
WriteBasicSetting(Settings::values.use_gdbstub); WriteBasicSetting(Settings::values.use_gdbstub);
WriteBasicSetting(Settings::values.gdbstub_port); WriteBasicSetting(Settings::values.gdbstub_port);
WriteBasicSetting(Settings::values.renderer_debug);
WriteBasicSetting(Settings::values.dump_command_buffers);
qt_config->beginGroup(QStringLiteral("LLE")); qt_config->beginGroup(QStringLiteral("LLE"));
for (const auto& service_module : Settings::values.lle_modules) { for (const auto& service_module : Settings::values.lle_modules) {
@ -1102,7 +1105,6 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.texture_filter_name); WriteGlobalSetting(Settings::values.texture_filter_name);
if (global) { if (global) {
WriteBasicSetting(Settings::values.renderer_debug);
WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(), WriteSetting(QStringLiteral("use_shader_jit"), Settings::values.use_shader_jit.GetValue(),
true); true);
} }

View File

@ -26,6 +26,7 @@ ConfigureDebug::ConfigureDebug(QWidget* parent)
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn(); const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
ui->toggle_cpu_jit->setEnabled(!is_powered_on); ui->toggle_cpu_jit->setEnabled(!is_powered_on);
ui->toggle_renderer_debug->setEnabled(!is_powered_on); ui->toggle_renderer_debug->setEnabled(!is_powered_on);
ui->toggle_dump_command_buffers->setEnabled(!is_powered_on);
} }
ConfigureDebug::~ConfigureDebug() = default; ConfigureDebug::~ConfigureDebug() = default;
@ -39,6 +40,7 @@ void ConfigureDebug::SetConfiguration() {
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter.GetValue())); 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_cpu_jit->setChecked(Settings::values.use_cpu_jit.GetValue());
ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.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() { void ConfigureDebug::ApplyConfiguration() {
@ -52,6 +54,7 @@ void ConfigureDebug::ApplyConfiguration() {
Log::SetGlobalFilter(filter); Log::SetGlobalFilter(filter);
Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked(); Settings::values.use_cpu_jit = ui->toggle_cpu_jit->isChecked();
Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked(); Settings::values.renderer_debug = ui->toggle_renderer_debug->isChecked();
Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked();
} }
void ConfigureDebug::RetranslateUI() { void ConfigureDebug::RetranslateUI() {

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>443</width> <width>454</width>
<height>300</height> <height>356</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -132,6 +132,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="toggle_dump_command_buffers">
<property name="text">
<string>Dump command buffers</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -449,6 +449,7 @@ struct Values {
SwitchableSetting<GraphicsAPI> graphics_api{GraphicsAPI::OpenGL, "graphics_api"}; SwitchableSetting<GraphicsAPI> graphics_api{GraphicsAPI::OpenGL, "graphics_api"};
SwitchableSetting<u16> physical_device{0, "physical_device"}; SwitchableSetting<u16> physical_device{0, "physical_device"};
Setting<bool> renderer_debug{false, "renderer_debug"}; Setting<bool> renderer_debug{false, "renderer_debug"};
Setting<bool> dump_command_buffers{false, "dump_command_buffers"};
SwitchableSetting<bool> use_hw_renderer{true, "use_hw_renderer"}; SwitchableSetting<bool> use_hw_renderer{true, "use_hw_renderer"};
SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"}; SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
SwitchableSetting<bool> separable_shader{false, "use_separable_shader"}; SwitchableSetting<bool> separable_shader{false, "use_separable_shader"};

View File

@ -183,8 +183,7 @@ static std::array<float, 3 * 2> MakeOrthographicMatrix(float width, float height
} }
RendererVulkan::RendererVulkan(Frontend::EmuWindow& window) RendererVulkan::RendererVulkan(Frontend::EmuWindow& window)
: RendererBase{window}, instance{window, Settings::values.physical_device, : RendererBase{window}, instance{window, Settings::values.physical_device},
Settings::values.renderer_debug},
scheduler{instance, *this}, renderpass_cache{instance, scheduler}, scheduler{instance, *this}, renderpass_cache{instance, scheduler},
runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache}, runtime{instance, scheduler, renderpass_cache}, swapchain{instance, renderpass_cache},
vertex_buffer{ vertex_buffer{

View File

@ -4,6 +4,7 @@
#include <span> #include <span>
#include "common/assert.h" #include "common/assert.h"
#include "core/settings.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_platform.h" #include "video_core/renderer_vulkan/vk_platform.h"
@ -66,7 +67,7 @@ Instance::Instance() {
physical_devices = instance.enumeratePhysicalDevices(); 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(); auto window_info = window.GetWindowInfo();
// Fetch instance independant function pointers // 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), .engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = available_version}; .apiVersion = available_version};
const std::array layers = {"VK_LAYER_KHRONOS_validation"}; u32 layer_count = 0;
const u32 layer_count = enable_validation ? 1u : 0u; std::array<const char*, 2> 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, const vk::InstanceCreateInfo instance_info = {.pApplicationInfo = &application_info,
.enabledLayerCount = layer_count, .enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(), .ppEnabledLayerNames = layers.data(),

View File

@ -32,7 +32,7 @@ struct FormatTraits {
class Instance { class Instance {
public: public:
Instance(); ///< Portable constructor used to query physical devices 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(); ~Instance();
/// Returns the FormatTraits struct for the provided pixel format /// Returns the FormatTraits struct for the provided pixel format
@ -87,6 +87,7 @@ public:
/// Returns true when VK_KHR_timeline_semaphore is supported /// Returns true when VK_KHR_timeline_semaphore is supported
bool IsTimelineSemaphoreSupported() const { bool IsTimelineSemaphoreSupported() const {
return false;
return timeline_semaphores; return timeline_semaphores;
} }

View File

@ -601,7 +601,13 @@ void PipelineCache::BindDescriptorSets() {
.descriptorSetCount = DESCRIPTOR_BATCH_SIZE, .descriptorSetCount = DESCRIPTOR_BATCH_SIZE,
.pSetLayouts = layouts.data()}; .pSetLayouts = layouts.data()};
try {
batch = device.allocateDescriptorSets(alloc_info); 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(); vk::DescriptorSet set = batch.back();

View File

@ -95,7 +95,7 @@ constexpr VertexLayout RasterizerVulkan::HardwareVertex::GetVertexLayout() {
return layout; 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 INDEX_BUFFER_SIZE = 8 * 1024 * 1024;
constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024; constexpr u32 UNIFORM_BUFFER_SIZE = 16 * 1024 * 1024;
constexpr u32 TEXTURE_BUFFER_SIZE = 16 * 1024 * 1024; constexpr u32 TEXTURE_BUFFER_SIZE = 16 * 1024 * 1024;

View File

@ -69,7 +69,7 @@ StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u
vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats) vk::BufferUsageFlagBits usage, std::span<const vk::Format> view_formats)
: instance{instance}, scheduler{scheduler}, staging{instance, size, : instance{instance}, scheduler{scheduler}, staging{instance, size,
vk::BufferUsageFlagBits::eTransferSrc}, vk::BufferUsageFlagBits::eTransferSrc},
usage{usage}, total_size{size} { usage{usage}, total_size{size * SCHEDULER_COMMAND_COUNT} {
const vk::BufferCreateInfo buffer_info = { const vk::BufferCreateInfo buffer_info = {
.size = total_size, .usage = usage | vk::BufferUsageFlagBits::eTransferDst}; .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(); view_count = view_formats.size();
bucket_size = size / SCHEDULER_COMMAND_COUNT; bucket_size = size;
} }
StreamBuffer::~StreamBuffer() { StreamBuffer::~StreamBuffer() {
@ -177,9 +177,4 @@ void StreamBuffer::Flush() {
buckets[next_bucket].invalid = true; 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 } // namespace Vulkan

View File

@ -48,9 +48,6 @@ public:
/// Flushes staging memory to the GPU buffer /// Flushes staging memory to the GPU buffer
void Flush(); void Flush();
/// Returns the current buffer offset
u32 GetBufferOffset() const;
/// Returns the Vulkan buffer handle /// Returns the Vulkan buffer handle
vk::Buffer GetHandle() const { vk::Buffer GetHandle() const {
return buffer; return buffer;

View File

@ -33,7 +33,6 @@ TaskScheduler::TaskScheduler(const Instance& instance, RendererVulkan& renderer)
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eUniformBuffer, 1024},
vk::DescriptorPoolSize{vk::DescriptorType::eUniformBufferDynamic, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eUniformBufferDynamic, 1024},
vk::DescriptorPoolSize{vk::DescriptorType::eSampledImage, 2048}, vk::DescriptorPoolSize{vk::DescriptorType::eSampledImage, 2048},
vk::DescriptorPoolSize{vk::DescriptorType::eCombinedImageSampler, 512},
vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 2048}, vk::DescriptorPoolSize{vk::DescriptorType::eSampler, 2048},
vk::DescriptorPoolSize{vk::DescriptorType::eUniformTexelBuffer, 1024}, vk::DescriptorPoolSize{vk::DescriptorType::eUniformTexelBuffer, 1024},
vk::DescriptorPoolSize{vk::DescriptorType::eStorageImage, 1024}}; vk::DescriptorPoolSize{vk::DescriptorType::eStorageImage, 1024}};
@ -91,7 +90,7 @@ void TaskScheduler::Synchronize(u32 slot) {
const auto& command = commands[slot]; const auto& command = commands[slot];
vk::Device device = instance.GetDevice(); vk::Device device = instance.GetDevice();
u32 completed_counter = GetFenceCounter(); const u64 completed_counter = GetFenceCounter();
if (command.fence_counter > completed_counter) { if (command.fence_counter > completed_counter) {
if (instance.IsTimelineSemaphoreSupported()) { if (instance.IsTimelineSemaphoreSupported()) {
const vk::SemaphoreWaitInfo wait_info = { const vk::SemaphoreWaitInfo wait_info = {
@ -134,6 +133,16 @@ void TaskScheduler::Submit(SubmitMode mode) {
command_buffers[command_buffer_count++] = command.render_command_buffer; 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); const bool swapchain_sync = True(mode & SubmitMode::SwapchainSynced);
if (instance.IsTimelineSemaphoreSupported()) { if (instance.IsTimelineSemaphoreSupported()) {
const u32 wait_semaphore_count = swapchain_sync ? 2u : 1u; const u32 wait_semaphore_count = swapchain_sync ? 2u : 1u;
@ -166,9 +175,7 @@ void TaskScheduler::Submit(SubmitMode mode) {
.pSignalSemaphores = signal_semaphores.data(), .pSignalSemaphores = signal_semaphores.data(),
}; };
vk::Queue queue = instance.GetGraphicsQueue(); QueueSubmit(submit_info, command.fence);
queue.submit(submit_info);
} else { } else {
const u32 signal_semaphore_count = swapchain_sync ? 1u : 0u; const u32 signal_semaphore_count = swapchain_sync ? 1u : 0u;
const u32 wait_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, .pSignalSemaphores = &command.present_ready,
}; };
vk::Queue queue = instance.GetGraphicsQueue(); QueueSubmit(submit_info, command.fence);
queue.submit(submit_info, command.fence);
} }
// Block host until the GPU catches up // Block host until the GPU catches up