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();
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);
}

View File

@ -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() {

View File

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

View File

@ -449,6 +449,7 @@ struct Values {
SwitchableSetting<GraphicsAPI> graphics_api{GraphicsAPI::OpenGL, "graphics_api"};
SwitchableSetting<u16> physical_device{0, "physical_device"};
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_shader{true, "use_hw_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)
: 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{

View File

@ -4,6 +4,7 @@
#include <span>
#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<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,
.enabledLayerCount = layer_count,
.ppEnabledLayerNames = layers.data(),

View File

@ -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;
}

View File

@ -601,7 +601,13 @@ void PipelineCache::BindDescriptorSets() {
.descriptorSetCount = DESCRIPTOR_BATCH_SIZE,
.pSetLayouts = layouts.data()};
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();

View File

@ -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;

View File

@ -69,7 +69,7 @@ StreamBuffer::StreamBuffer(const Instance& instance, TaskScheduler& scheduler, u
vk::BufferUsageFlagBits usage, std::span<const vk::Format> 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

View File

@ -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;

View File

@ -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