Video Core: debug tools (#412)
* video_core: better use of rdoc markers * renderer_vulkan: added gpu assisted validation * renderer_vulkan: make nv_checkpoints operational * video_core: unified Vulkan objects names
This commit is contained in:
parent
3e2d4d6b79
commit
ace39957ef
|
@ -25,7 +25,9 @@ static bool shouldDumpPM4 = false;
|
|||
static u32 vblankDivider = 1;
|
||||
static bool vkValidation = false;
|
||||
static bool vkValidationSync = false;
|
||||
static bool vkValidationGpu = false;
|
||||
static bool rdocEnable = false;
|
||||
static bool rdocMarkersEnable = false;
|
||||
// Gui
|
||||
std::string settings_install_dir = "";
|
||||
u32 main_window_geometry_x = 400;
|
||||
|
@ -102,6 +104,10 @@ bool isRdocEnabled() {
|
|||
return rdocEnable;
|
||||
}
|
||||
|
||||
bool isMarkersEnabled() {
|
||||
return rdocMarkersEnable;
|
||||
}
|
||||
|
||||
u32 vblankDiv() {
|
||||
return vblankDivider;
|
||||
}
|
||||
|
@ -114,6 +120,10 @@ bool vkValidationSyncEnabled() {
|
|||
return vkValidationSync;
|
||||
}
|
||||
|
||||
bool vkValidationGpuEnabled() {
|
||||
return vkValidationGpu;
|
||||
}
|
||||
|
||||
void setScreenWidth(u32 width) {
|
||||
screenWidth = width;
|
||||
}
|
||||
|
@ -319,7 +329,9 @@ void load(const std::filesystem::path& path) {
|
|||
gpuId = toml::find_or<int>(vk, "gpuId", -1);
|
||||
vkValidation = toml::find_or<bool>(vk, "validation", false);
|
||||
vkValidationSync = toml::find_or<bool>(vk, "validation_sync", false);
|
||||
vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", true);
|
||||
rdocEnable = toml::find_or<bool>(vk, "rdocEnable", false);
|
||||
rdocMarkersEnable = toml::find_or<bool>(vk, "rdocMarkersEnable", false);
|
||||
}
|
||||
|
||||
if (data.contains("Debug")) {
|
||||
|
@ -394,7 +406,9 @@ void save(const std::filesystem::path& path) {
|
|||
data["Vulkan"]["gpuId"] = gpuId;
|
||||
data["Vulkan"]["validation"] = vkValidation;
|
||||
data["Vulkan"]["validation_sync"] = vkValidationSync;
|
||||
data["Vulkan"]["validation_gpu"] = vkValidationGpu;
|
||||
data["Vulkan"]["rdocEnable"] = rdocEnable;
|
||||
data["Vulkan"]["rdocMarkersEnable"] = rdocMarkersEnable;
|
||||
data["Debug"]["DebugDump"] = isDebugDump;
|
||||
data["LLE"]["libc"] = isLibc;
|
||||
data["GUI"]["theme"] = mw_themes;
|
||||
|
|
|
@ -27,6 +27,7 @@ bool nullGpu();
|
|||
bool dumpShaders();
|
||||
bool dumpPM4();
|
||||
bool isRdocEnabled();
|
||||
bool isMarkersEnabled();
|
||||
u32 vblankDiv();
|
||||
|
||||
void setDebugDump(bool enable);
|
||||
|
@ -50,6 +51,7 @@ void setRdocEnabled(bool enable);
|
|||
|
||||
bool vkValidationEnabled();
|
||||
bool vkValidationSyncEnabled();
|
||||
bool vkValidationGpuEnabled();
|
||||
|
||||
// Gui
|
||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||
|
|
|
@ -180,6 +180,17 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||
Platform::IrqC::Instance()->Signal(Platform::InterruptId::GfxFlip);
|
||||
break;
|
||||
}
|
||||
case PM4CmdNop::PayloadType::DebugMarkerPush: {
|
||||
const auto marker_sz = nop->header.count.Value() * 2;
|
||||
const std::string_view label{reinterpret_cast<const char*>(&nop->data_block[1]),
|
||||
marker_sz};
|
||||
rasterizer->ScopeMarkerBegin(label);
|
||||
break;
|
||||
}
|
||||
case PM4CmdNop::PayloadType::DebugMarkerPop: {
|
||||
rasterizer->ScopeMarkerEnd();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -295,8 +306,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||
regs.num_indices = draw_index->index_count;
|
||||
regs.draw_initiator = draw_index->draw_initiator;
|
||||
if (rasterizer) {
|
||||
rasterizer->ScopeMarkerBegin(
|
||||
fmt::format("dcb:{}:DrawIndex2", reinterpret_cast<const void*>(dcb.data())));
|
||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:DrawIndex2", cmd_address));
|
||||
rasterizer->Breadcrumb(u64(cmd_address));
|
||||
rasterizer->Draw(true);
|
||||
rasterizer->ScopeMarkerEnd();
|
||||
}
|
||||
|
@ -308,8 +320,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||
regs.num_indices = draw_index_off->index_count;
|
||||
regs.draw_initiator = draw_index_off->draw_initiator;
|
||||
if (rasterizer) {
|
||||
rasterizer->ScopeMarkerBegin(fmt::format(
|
||||
"dcb:{}:DrawIndexOffset2", reinterpret_cast<const void*>(dcb.data())));
|
||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:DrawIndexOffset2", cmd_address));
|
||||
rasterizer->Breadcrumb(u64(cmd_address));
|
||||
rasterizer->Draw(true, draw_index_off->index_offset);
|
||||
rasterizer->ScopeMarkerEnd();
|
||||
}
|
||||
|
@ -320,8 +333,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||
regs.num_indices = draw_index->index_count;
|
||||
regs.draw_initiator = draw_index->draw_initiator;
|
||||
if (rasterizer) {
|
||||
rasterizer->ScopeMarkerBegin(
|
||||
fmt::format("dcb:{}:DrawIndexAuto", reinterpret_cast<const void*>(dcb.data())));
|
||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:DrawIndexAuto", cmd_address));
|
||||
rasterizer->Breadcrumb(u64(cmd_address));
|
||||
rasterizer->Draw(false);
|
||||
rasterizer->ScopeMarkerEnd();
|
||||
}
|
||||
|
@ -334,8 +348,9 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||
rasterizer->ScopeMarkerBegin(
|
||||
fmt::format("dcb:{}:Dispatch", reinterpret_cast<const void*>(dcb.data())));
|
||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||
rasterizer->ScopeMarkerBegin(fmt::format("dcb:{}:Dispatch", cmd_address));
|
||||
rasterizer->Breadcrumb(u64(cmd_address));
|
||||
rasterizer->DispatchDirect();
|
||||
rasterizer->ScopeMarkerEnd();
|
||||
}
|
||||
|
@ -486,8 +501,9 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
|||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||
rasterizer->ScopeMarkerBegin(fmt::format(
|
||||
"acb[{}]:{}:Dispatch", vqid, reinterpret_cast<const void*>(acb.data())));
|
||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||
rasterizer->ScopeMarkerBegin(fmt::format("acb[{}]:{}:Dispatch", vqid, cmd_address));
|
||||
rasterizer->Breadcrumb(u64(cmd_address));
|
||||
rasterizer->DispatchDirect();
|
||||
rasterizer->ScopeMarkerEnd();
|
||||
}
|
||||
|
|
|
@ -106,10 +106,8 @@ Buffer::Buffer(const Vulkan::Instance& instance_, MemoryUsage usage_, VAddr cpu_
|
|||
VmaAllocationInfo alloc_info{};
|
||||
buffer.Create(buffer_ci, usage, &alloc_info);
|
||||
|
||||
if (instance->HasDebuggingToolAttached()) {
|
||||
const auto device = instance->GetDevice();
|
||||
Vulkan::SetObjectName(device, Handle(), "Buffer {:#x} {} KiB", cpu_addr, size_bytes / 1024);
|
||||
}
|
||||
const auto device = instance->GetDevice();
|
||||
Vulkan::SetObjectName(device, Handle(), "Buffer {:#x}:{:#x}", cpu_addr, size_bytes);
|
||||
|
||||
// Map it if it is host visible.
|
||||
VkMemoryPropertyFlags property_flags{};
|
||||
|
@ -152,10 +150,8 @@ StreamBuffer::StreamBuffer(const Vulkan::Instance& instance, Vulkan::Scheduler&
|
|||
ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
|
||||
ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
|
||||
const auto device = instance.GetDevice();
|
||||
if (instance.HasDebuggingToolAttached()) {
|
||||
Vulkan::SetObjectName(device, Handle(), "StreamBuffer({}): {} KiB", BufferTypeName(usage),
|
||||
size_bytes / 1024);
|
||||
}
|
||||
Vulkan::SetObjectName(device, Handle(), "StreamBuffer({}):{:#x}", BufferTypeName(usage),
|
||||
size_bytes);
|
||||
}
|
||||
|
||||
std::pair<u8*, u64> StreamBuffer::Map(u64 size, u64 alignment) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <fmt/ranges.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "sdl_window.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
@ -213,6 +214,13 @@ bool Instance::CreateDevice() {
|
|||
add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
|
||||
add_extension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
|
||||
add_extension(VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME);
|
||||
const bool has_sync2 = add_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
|
||||
|
||||
if (has_sync2) {
|
||||
has_nv_checkpoints = Config::isMarkersEnabled()
|
||||
? add_extension(VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME)
|
||||
: false;
|
||||
}
|
||||
|
||||
const auto family_properties = physical_device.getQueueFamilyProperties();
|
||||
if (family_properties.empty()) {
|
||||
|
@ -308,6 +316,9 @@ bool Instance::CreateDevice() {
|
|||
vk::PhysicalDeviceRobustness2FeaturesEXT{
|
||||
.nullDescriptor = true,
|
||||
},
|
||||
vk::PhysicalDeviceSynchronization2Features{
|
||||
.synchronization2 = has_sync2,
|
||||
},
|
||||
};
|
||||
|
||||
if (!color_write_en) {
|
||||
|
|
|
@ -88,6 +88,10 @@ public:
|
|||
return profiler_context;
|
||||
}
|
||||
|
||||
bool HasNvCheckpoints() const {
|
||||
return has_nv_checkpoints;
|
||||
}
|
||||
|
||||
/// Returns true when a known debugging tool is attached.
|
||||
bool HasDebuggingToolAttached() const {
|
||||
return has_renderdoc || has_nsight_graphics;
|
||||
|
@ -259,6 +263,7 @@ private:
|
|||
bool debug_utils_supported{};
|
||||
bool has_nsight_graphics{};
|
||||
bool has_renderdoc{};
|
||||
bool has_nv_checkpoints{};
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -221,12 +221,61 @@ vk::UniqueInstance CreateInstance(vk::DynamicLoader& dl, Frontend::WindowSystemT
|
|||
|
||||
vk::Bool32 enable_sync =
|
||||
enable_validation && Config::vkValidationSyncEnabled() ? vk::True : vk::False;
|
||||
vk::LayerSettingEXT layer_set = {
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "validate_sync",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_sync,
|
||||
vk::Bool32 enable_gpuav =
|
||||
enable_validation && Config::vkValidationSyncEnabled() ? vk::True : vk::False;
|
||||
const char* gpuav_mode = enable_validation && Config::vkValidationGpuEnabled()
|
||||
? "GPU_BASED_GPU_ASSISTED"
|
||||
: "GPU_BASED_NONE";
|
||||
const std::array layer_setings = {
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "validate_sync",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_sync,
|
||||
},
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "sync_queue_submit",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_sync,
|
||||
},
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "validate_gpu_based",
|
||||
.type = vk::LayerSettingTypeEXT::eString,
|
||||
.valueCount = 1,
|
||||
.pValues = &gpuav_mode,
|
||||
},
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "gpuav_reserve_binding_slot",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_gpuav,
|
||||
},
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "gpuav_descriptor_checks",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_gpuav,
|
||||
},
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "gpuav_validate_indirect_buffer",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_gpuav,
|
||||
},
|
||||
vk::LayerSettingEXT{
|
||||
.pLayerName = VALIDATION_LAYER_NAME,
|
||||
.pSettingName = "gpuav_buffer_copies",
|
||||
.type = vk::LayerSettingTypeEXT::eBool32,
|
||||
.valueCount = 1,
|
||||
.pValues = &enable_gpuav,
|
||||
},
|
||||
};
|
||||
|
||||
vk::StructureChain<vk::InstanceCreateInfo, vk::LayerSettingsCreateInfoEXT> instance_ci_chain = {
|
||||
|
@ -238,8 +287,8 @@ vk::UniqueInstance CreateInstance(vk::DynamicLoader& dl, Frontend::WindowSystemT
|
|||
.ppEnabledExtensionNames = extensions.data(),
|
||||
},
|
||||
vk::LayerSettingsCreateInfoEXT{
|
||||
.settingCount = 1,
|
||||
.pSettings = &layer_set,
|
||||
.settingCount = layer_setings.size(),
|
||||
.pSettings = layer_setings.data(),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -230,16 +230,42 @@ void Rasterizer::UpdateDepthStencilState() {
|
|||
cmdbuf.setDepthBoundsTestEnable(depth.depth_bounds_enable);
|
||||
}
|
||||
|
||||
void Rasterizer::ScopeMarkerBegin(const std::string& str) {
|
||||
void Rasterizer::ScopeMarkerBegin(const std::string_view& str) {
|
||||
if (!Config::isMarkersEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
|
||||
.pLabelName = str.c_str(),
|
||||
.pLabelName = str.data(),
|
||||
});
|
||||
}
|
||||
|
||||
void Rasterizer::ScopeMarkerEnd() {
|
||||
if (!Config::isMarkersEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.endDebugUtilsLabelEXT();
|
||||
}
|
||||
|
||||
void Rasterizer::ScopedMarkerInsert(const std::string_view& str) {
|
||||
if (!Config::isMarkersEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.insertDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
|
||||
.pLabelName = str.data(),
|
||||
});
|
||||
}
|
||||
|
||||
void Rasterizer::Breadcrumb(u64 id) {
|
||||
if (!instance.HasNvCheckpoints()) {
|
||||
return;
|
||||
}
|
||||
scheduler.CommandBuffer().setCheckpointNV(id);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -35,8 +35,10 @@ public:
|
|||
|
||||
void DispatchDirect();
|
||||
|
||||
void ScopeMarkerBegin(const std::string& str);
|
||||
void ScopeMarkerBegin(const std::string_view& str);
|
||||
void ScopeMarkerEnd();
|
||||
void ScopedMarkerInsert(const std::string_view& str);
|
||||
void Breadcrumb(u64 id);
|
||||
|
||||
void InvalidateMemory(VAddr addr, u64 size);
|
||||
void MapMemory(VAddr addr, u64 size);
|
||||
|
|
|
@ -158,6 +158,13 @@ void Scheduler::SubmitExecution(SubmitInfo& info) {
|
|||
try {
|
||||
instance.GetGraphicsQueue().submit(submit_info, info.fence);
|
||||
} catch (vk::DeviceLostError& err) {
|
||||
if (instance.HasNvCheckpoints()) {
|
||||
const auto checkpoint_data = instance.GetGraphicsQueue().getCheckpointData2NV();
|
||||
for (const auto& cp : checkpoint_data) {
|
||||
LOG_CRITICAL(Render_Vulkan, "{}: {:#x}", vk::to_string(cp.stage),
|
||||
reinterpret_cast<u64>(cp.pCheckpointMarker));
|
||||
}
|
||||
}
|
||||
UNREACHABLE_MSG("Device lost during submit: {}", err.what());
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
|
@ -154,6 +155,9 @@ Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
|
|||
};
|
||||
|
||||
image.Create(image_ci);
|
||||
|
||||
Vulkan::SetObjectName(instance->GetDevice(), (vk::Image)image, "Image {:#x}:{:#x}",
|
||||
info.guest_address, info.guest_size_bytes);
|
||||
}
|
||||
|
||||
void Image::Transit(vk::ImageLayout dst_layout, vk::Flags<vk::AccessFlagBits> dst_mask,
|
||||
|
|
Loading…
Reference in New Issue