mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
graphics: add --gpu-assisted-validation and report fatal VkResults (#268)
* graphics: report the VkResult when a submit or fence wait fails * graphics: add a --gpu-assisted-validation flag * graphics: imply Vulkan validation for GPU-assisted validation --------- Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -93,6 +93,10 @@ bool SpirvDebugPrintfEnabled() {
|
|||||||
return g_config->spirv_debug_printf_enabled;
|
return g_config->spirv_debug_printf_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GpuAssistedValidationEnabled() {
|
||||||
|
return g_config->gpu_assisted_validation_enabled && g_config->vulkan_validation_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderDocEnabled() {
|
bool RenderDocEnabled() {
|
||||||
return g_config->renderdoc_enabled;
|
return g_config->renderdoc_enabled;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ struct ConfigOptions {
|
|||||||
std::filesystem::path printf_output_file = "_kyty.txt";
|
std::filesystem::path printf_output_file = "_kyty.txt";
|
||||||
ProfilerDirection profiler_direction = ProfilerDirection::None;
|
ProfilerDirection profiler_direction = ProfilerDirection::None;
|
||||||
bool spirv_debug_printf_enabled = false;
|
bool spirv_debug_printf_enabled = false;
|
||||||
|
bool gpu_assisted_validation_enabled = false;
|
||||||
bool renderdoc_enabled = false;
|
bool renderdoc_enabled = false;
|
||||||
bool readback_linear_images = false;
|
bool readback_linear_images = false;
|
||||||
bool playgo_hack_enabled = false;
|
bool playgo_hack_enabled = false;
|
||||||
@@ -84,6 +85,8 @@ ProfilerDirection GetProfilerDirection();
|
|||||||
|
|
||||||
bool SpirvDebugPrintfEnabled();
|
bool SpirvDebugPrintfEnabled();
|
||||||
|
|
||||||
|
bool GpuAssistedValidationEnabled();
|
||||||
|
|
||||||
bool RenderDocEnabled();
|
bool RenderDocEnabled();
|
||||||
bool ReadbackLinearImagesEnabled();
|
bool ReadbackLinearImagesEnabled();
|
||||||
bool PlayGoHackEnabled();
|
bool PlayGoHackEnabled();
|
||||||
|
|||||||
@@ -17,10 +17,29 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
namespace Libs::Graphics {
|
namespace Libs::Graphics {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void ReportVulkanFatal(const char* what, vk::Result result, uint32_t slot, uint64_t submit_seq,
|
||||||
|
uint32_t debug_op, uint64_t debug_submit, uint32_t arg0, uint32_t arg1,
|
||||||
|
uint32_t arg2, uint32_t arg3, uint64_t arg4) {
|
||||||
|
LOGF("%s failed: %s (%d), slot=%u submit_seq=%" PRIu64 " debug_op=%u debug_submit=%" PRIu64
|
||||||
|
" args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
||||||
|
what, VulkanToString(result).c_str(), static_cast<int>(result), slot, submit_seq, debug_op,
|
||||||
|
debug_submit, arg0, arg1, arg2, arg3, arg4);
|
||||||
|
std::printf("%s failed: %s (%d), slot=%u submit_seq=%" PRIu64 " debug_op=%u debug_submit=%" PRIu64
|
||||||
|
" args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
||||||
|
what, VulkanToString(result).c_str(), static_cast<int>(result), slot, submit_seq,
|
||||||
|
debug_op, debug_submit, arg0, arg1, arg2, arg3, arg4);
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
FenceResourceRetainer::~FenceResourceRetainer() {
|
FenceResourceRetainer::~FenceResourceRetainer() {
|
||||||
if (!m_resources.empty()) {
|
if (!m_resources.empty()) {
|
||||||
EXIT("fence resource retainer destroyed before release\n");
|
EXIT("fence resource retainer destroyed before release\n");
|
||||||
@@ -169,8 +188,9 @@ void CommandBuffer::Execute(const SubmitInfo& submit) {
|
|||||||
|
|
||||||
auto result = graphics.device.resetFences(1, &fence);
|
auto result = graphics.device.resetFences(1, &fence);
|
||||||
if (result != vk::Result::eSuccess) {
|
if (result != vk::Result::eSuccess) {
|
||||||
LOGF("vkResetFences failed before submit: %s (%d)\n", VulkanToString(result).c_str(),
|
ReportVulkanFatal("vkResetFences (before submit)", result, m_slot->id, m_submit_seq,
|
||||||
static_cast<int>(result));
|
m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2,
|
||||||
|
m_debug_arg3, m_debug_arg4);
|
||||||
}
|
}
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
|
|
||||||
@@ -192,10 +212,8 @@ void CommandBuffer::Execute(const SubmitInfo& submit) {
|
|||||||
m_fence_waited = false;
|
m_fence_waited = false;
|
||||||
|
|
||||||
if (result != vk::Result::eSuccess) {
|
if (result != vk::Result::eSuccess) {
|
||||||
LOGF("vkQueueSubmit failed: %s (%d), slot=%u submit_seq=%" PRIu64
|
ReportVulkanFatal("vkQueueSubmit", result, m_slot->id, m_submit_seq, m_debug_op,
|
||||||
" debug_op=%u debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2, m_debug_arg3,
|
||||||
VulkanToString(result).c_str(), static_cast<int>(result), m_slot->id, m_submit_seq,
|
|
||||||
m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2, m_debug_arg3,
|
|
||||||
m_debug_arg4);
|
m_debug_arg4);
|
||||||
}
|
}
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
@@ -213,10 +231,8 @@ void CommandBuffer::WaitForFenceOnly() {
|
|||||||
auto device = m_graphics.device;
|
auto device = m_graphics.device;
|
||||||
auto result = device.waitForFences(1, &m_slot->fence, VK_TRUE, UINT64_MAX);
|
auto result = device.waitForFences(1, &m_slot->fence, VK_TRUE, UINT64_MAX);
|
||||||
if (result != vk::Result::eSuccess) {
|
if (result != vk::Result::eSuccess) {
|
||||||
LOGF("vkWaitForFences failed: %s (%d), slot=%u submit_seq=%" PRIu64
|
ReportVulkanFatal("vkWaitForFences", result, m_slot->id, m_submit_seq, m_debug_op,
|
||||||
" debug_op=%u debug_submit=%" PRIu64 " args=%u,%u,%u,%u,0x%016" PRIx64 "\n",
|
m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2, m_debug_arg3,
|
||||||
VulkanToString(result).c_str(), static_cast<int>(result), m_slot->id, m_submit_seq,
|
|
||||||
m_debug_op, m_debug_submit_id, m_debug_arg0, m_debug_arg1, m_debug_arg2, m_debug_arg3,
|
|
||||||
m_debug_arg4);
|
m_debug_arg4);
|
||||||
}
|
}
|
||||||
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess);
|
||||||
|
|||||||
@@ -554,6 +554,14 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, const V
|
|||||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.depthBiasClamp != VK_TRUE);
|
EXIT_NOT_IMPLEMENTED(supported_features2.features.depthBiasClamp != VK_TRUE);
|
||||||
features12.timelineSemaphore = VK_TRUE;
|
features12.timelineSemaphore = VK_TRUE;
|
||||||
|
|
||||||
|
if (Config::GpuAssistedValidationEnabled()) {
|
||||||
|
if (supported_features12.bufferDeviceAddress != VK_TRUE) {
|
||||||
|
EXIT("--gpu-assisted-validation requires bufferDeviceAddress, unsupported by this "
|
||||||
|
"device\n");
|
||||||
|
}
|
||||||
|
features12.bufferDeviceAddress = VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
vk::PhysicalDeviceFeatures device_features {};
|
vk::PhysicalDeviceFeatures device_features {};
|
||||||
device_features.fragmentStoresAndAtomics = VK_TRUE;
|
device_features.fragmentStoresAndAtomics = VK_TRUE;
|
||||||
device_features.samplerAnisotropy = VK_TRUE;
|
device_features.samplerAnisotropy = VK_TRUE;
|
||||||
@@ -571,6 +579,9 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, const V
|
|||||||
graphics.sample_rate_shading_enabled = true;
|
graphics.sample_rate_shading_enabled = true;
|
||||||
device_features.vertexPipelineStoresAndAtomics =
|
device_features.vertexPipelineStoresAndAtomics =
|
||||||
supported_features2.features.vertexPipelineStoresAndAtomics;
|
supported_features2.features.vertexPipelineStoresAndAtomics;
|
||||||
|
if (Config::GpuAssistedValidationEnabled()) {
|
||||||
|
device_features.shaderInt64 = supported_features2.features.shaderInt64;
|
||||||
|
}
|
||||||
|
|
||||||
if (graphics.subgroup_size_control_enabled &&
|
if (graphics.subgroup_size_control_enabled &&
|
||||||
supported_features13.subgroupSizeControl == VK_TRUE) {
|
supported_features13.subgroupSizeControl == VK_TRUE) {
|
||||||
@@ -833,23 +844,26 @@ void WindowContext::CreateVulkan() {
|
|||||||
app_info.engineVersion = 1;
|
app_info.engineVersion = 1;
|
||||||
app_info.apiVersion = VULKAN_TARGET_API_VERSION; // NOLINT
|
app_info.apiVersion = VULKAN_TARGET_API_VERSION; // NOLINT
|
||||||
|
|
||||||
vk::ValidationFeatureEnableEXT enabled_features[] = {
|
if (Config::SpirvDebugPrintfEnabled() && Config::GpuAssistedValidationEnabled()) {
|
||||||
|
EXIT("--spirv-debug-printf and --gpu-assisted-validation are mutually exclusive\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ValidationFeatureEnableEXT enabled_features[3] = {};
|
||||||
|
uint32_t enabled_features_count = 0;
|
||||||
#ifdef KYTY_ENABLE_BEST_PRACTICES
|
#ifdef KYTY_ENABLE_BEST_PRACTICES
|
||||||
vk::ValidationFeatureEnableEXT::eBestPractices,
|
enabled_features[enabled_features_count++] = vk::ValidationFeatureEnableEXT::eBestPractices;
|
||||||
#endif
|
#endif
|
||||||
#ifdef KYTY_ENABLE_DEBUG_PRINTF
|
#ifdef KYTY_ENABLE_DEBUG_PRINTF
|
||||||
vk::ValidationFeatureEnableEXT::eDebugPrintf,
|
if (Config::SpirvDebugPrintfEnabled()) {
|
||||||
#endif
|
enabled_features[enabled_features_count++] = vk::ValidationFeatureEnableEXT::eDebugPrintf;
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t enabled_features_count =
|
|
||||||
sizeof(enabled_features) / sizeof(vk::ValidationFeatureEnableEXT);
|
|
||||||
|
|
||||||
#ifdef KYTY_ENABLE_DEBUG_PRINTF
|
|
||||||
if (!Config::SpirvDebugPrintfEnabled()) {
|
|
||||||
enabled_features_count--;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (Config::GpuAssistedValidationEnabled()) {
|
||||||
|
enabled_features[enabled_features_count++] = vk::ValidationFeatureEnableEXT::eGpuAssisted;
|
||||||
|
LOGF("Vulkan GPU-assisted validation is enabled; expect a large slowdown\n");
|
||||||
|
std::printf("Vulkan GPU-assisted validation is enabled; expect a large slowdown\n");
|
||||||
|
std::fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
vk::ValidationFeaturesEXT validation_features {};
|
vk::ValidationFeaturesEXT validation_features {};
|
||||||
validation_features.sType = vk::StructureType::eValidationFeaturesEXT;
|
validation_features.sType = vk::StructureType::eValidationFeaturesEXT;
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ static void PrintUsage() {
|
|||||||
::printf(" --vblank-frequency <num> Virtual vblank frequency. Default: 60.\n");
|
::printf(" --vblank-frequency <num> Virtual vblank frequency. Default: 60.\n");
|
||||||
::printf(" --console-language <0-29> Console language. Default: 1 (English US).\n");
|
::printf(" --console-language <0-29> Console language. Default: 1 (English US).\n");
|
||||||
::printf(" --vulkan-validation <true|false> Enable Vulkan validation.\n");
|
::printf(" --vulkan-validation <true|false> Enable Vulkan validation.\n");
|
||||||
|
::printf(" --gpu-assisted-validation <t|f> Bounds-check shader accesses on the GPU.\n"
|
||||||
|
" Implies --vulkan-validation; very slow.\n");
|
||||||
::printf(" --shader-validation <true|false> Enable shader validation.\n");
|
::printf(" --shader-validation <true|false> Enable shader validation.\n");
|
||||||
::printf(" --shader-optimization-type <value> None, Size, or Performance.\n");
|
::printf(" --shader-optimization-type <value> None, Size, or Performance.\n");
|
||||||
::printf(" --shader-log-direction <value> Silent, Console, or File.\n");
|
::printf(" --shader-log-direction <value> Silent, Console, or File.\n");
|
||||||
@@ -213,6 +215,11 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
|||||||
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (arg == "--gpu-assisted-validation") {
|
||||||
|
if (!ParseBool(value, options.config.gpu_assisted_validation_enabled)) {
|
||||||
|
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (arg == "--shader-validation") {
|
} else if (arg == "--shader-validation") {
|
||||||
if (!ParseBool(value, options.config.shader_validation_enabled)) {
|
if (!ParseBool(value, options.config.shader_validation_enabled)) {
|
||||||
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
::printf("invalid boolean for %s: %s\n", arg.c_str(), value.c_str());
|
||||||
@@ -277,6 +284,10 @@ static bool ParseArgs(int argc, char* argv[], RunOptions& options, bool& show_he
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.config.gpu_assisted_validation_enabled) {
|
||||||
|
options.config.vulkan_validation_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
return show_help || (!options.app0_dir.empty() && !options.elf.empty());
|
return show_help || (!options.app0_dir.empty() && !options.elf.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user