diff --git a/src/graphics/host_gpu/renderer/cache/bufferCache.cpp b/src/graphics/host_gpu/renderer/cache/bufferCache.cpp index 5a6141e37..8123c42ce 100644 --- a/src/graphics/host_gpu/renderer/cache/bufferCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/bufferCache.cpp @@ -9,6 +9,7 @@ #include "graphics/host_gpu/renderer/commandScheduler.h" #include "graphics/host_gpu/renderer/render.h" #include "graphics/host_gpu/renderer/renderContext.h" +#include "graphics/host_gpu/vulkanCommon.h" #include "kernel/memory.h" #include @@ -435,6 +436,9 @@ BufferCache::CachedBuffer& BufferCache::GetOrCreateBuffer(CommandBuffer& command cached->tick_accessed_last = m_gc_tick; cached->buffer = std::make_shared(m_graphics, m_scheduler, MemoryUsage::DeviceLocal, merged.address, AllFlags, merged.size); + SetVulkanObjectNameF(m_graphics.device, cached->buffer->Handle(), + "Kyty.GameBuffer[guest=0x{:016x} size=0x{:x}]", cached->vaddr, + cached->size); for (const auto overlap: overlaps) { const auto& old = *overlap->second; cached->buffer->CopyFrom(command, *old.buffer, 0, old.vaddr - cached->vaddr, old.size); diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index d669e982d..47726ce72 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -34,6 +34,36 @@ constexpr uint64_t NumFramesBeforeRemoval = 32; thread_local const TextureCache* g_locked_cache = nullptr; +[[nodiscard]] const char* BindingTypeName(TextureCache::BindingType type) { + switch (type) { + case TextureCache::BindingType::Texture: return "Texture"; + case TextureCache::BindingType::Storage: return "StorageTexture"; + case TextureCache::BindingType::RenderTarget: return "ColorTarget"; + case TextureCache::BindingType::DepthTarget: return "DepthTarget"; + case TextureCache::BindingType::VideoOut: return "VideoOut"; + } + return "Image"; +} + +void NameImageBinding(GraphicContext& graphics, Image& image, vk::ImageView view, + TextureCache::BindingType type, const ImageViewInfo& view_info) { + const auto* role = BindingTypeName(type); + SetVulkanObjectNameF( + graphics.device, image.backing.image, + "Kyty.{}.Image[guest=0x{:016x} size=0x{:x} extent={}x{}x{} format={} mips={} layers={} " + "samples={}]", + role, image.info.data.address, image.info.data.size, image.info.extent.width, + image.info.extent.height, image.info.extent.depth, + static_cast(image.info.pixel_format), image.info.resources.levels, + image.info.resources.layers, image.info.samples); + SetVulkanObjectNameF( + graphics.device, view, + "Kyty.{}.View[guest=0x{:016x} format={} aspect=0x{:x} mip={}+{} layer={}+{}]", role, + image.info.data.address, static_cast(view_info.format), + static_cast(view_info.aspect), view_info.base_level, + view_info.level_count, view_info.base_layer, view_info.layer_count); +} + class CacheLock final { public: CacheLock(const TextureCache& owner, TrackingSpinLock& lock): m_lock(lock) { @@ -714,7 +744,7 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp cached.info.data.size / cached.info.resources.layers && !requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() && !cached.info.HasMetadata(); - bool recreate = cached.info.resources < requested.resources; + bool recreate = cached.info.resources < requested.resources; switch (binding) { case BindingType::Texture: recreate |= requested.IsDepth() && !cached.info.IsDepth(); @@ -1359,6 +1389,7 @@ vk::ImageView TextureCache::FindTexture(ImageId id, const ImageDesc& desc) { default: EXIT("TextureCache: invalid texture binding\n"); } const auto view = image.FindView(desc.view_info); + NameImageBinding(m_graphics, image, view, desc.type, desc.view_info); RetainImage(m_scheduler.Current(), id); return view; } @@ -1392,6 +1423,7 @@ vk::ImageView TextureCache::FindRenderTarget(ImageId id, const ImageDesc& desc) CommitGpuWrite(image); TrackImageDownloadLocked(id, image); const auto view = image.FindView(desc.view_info); + NameImageBinding(m_graphics, image, view, desc.type, desc.view_info); RetainImage(m_scheduler.Current(), id); return view; } @@ -1431,6 +1463,7 @@ vk::ImageView TextureCache::FindDepthTarget(ImageId id, const ImageDesc& desc) { AssociateStencilLocked(id, desc.info.stencil); } const auto view = image.FindView(desc.view_info); + NameImageBinding(m_graphics, image, view, desc.type, desc.view_info); RetainImage(m_scheduler.Current(), id); return view; } @@ -1957,7 +1990,7 @@ bool TextureCache::TryConsumeDccFill(uint64_t address, uint64_t size, uint32_t f // This dispatch may precede color-target discovery. Retain it in the shared // metadata map, but PendingDcc remains invisible to IsMeta until registration. Returning // false lets the guest dispatch execute and initialize memory while the type is uncertain. - m_surface_metas.emplace(address, MetaDataInfo {.type = MetaDataInfo::Type::PendingDcc, + m_surface_metas.emplace(address, MetaDataInfo {.type = MetaDataInfo::Type::PendingDcc, .clear_mask = dcc_clear_mask, .fill_value = fill_value, .fill_size = size}); diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 64a989b78..d2c8520ee 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -45,6 +45,16 @@ namespace Libs::Graphics { +static const char* ShaderStageResourceName(DescriptorCache::Stage stage) { + switch (stage) { + case DescriptorCache::Stage::Vertex: return "Vertex"; + case DescriptorCache::Stage::Pixel: return "Pixel"; + case DescriptorCache::Stage::Compute: return "Compute"; + case DescriptorCache::Stage::Unknown: return "Unknown"; + } + return "Unknown"; +} + static void BindNullStorageBuffer(RenderContext& context, BufferView& dst) { auto owner = context.GetBufferCache().ObtainNullBuffer(); dst.buffer = owner->Handle(); @@ -82,7 +92,8 @@ static bool IsMultisampledTexture(Prospero::ImageType type) { static BufferView NativeStorageBuffer(RenderContext& context, CommandBuffer& command_buffer, const ShaderBufferResource& descriptor, const ShaderRecompiler::IR::BufferResource& resource, - uint32_t& buffer_offset) { + DescriptorCache::Stage stage, uint32_t slot, + uint32_t& buffer_offset) { BufferView result; buffer_offset = 0; @@ -117,6 +128,11 @@ static BufferView NativeStorageBuffer(RenderContext& context, CommandBuffer& com result.buffer = binding.buffer; result.offset = aligned_offset; result.range = static_cast(size + adjustment); + SetVulkanObjectNameF( + graphics.device, result.buffer, + "Kyty.{}.StorageBuffer[slot={} guest=0x{:016x} size=0x{:x} access={} formatted={}]", + ShaderStageResourceName(stage), slot, address, size, + resource.written ? (resource.read ? "ReadWrite" : "Write") : "Read", resource.formatted); return result; } @@ -124,7 +140,7 @@ static BufferView NativeAddressBuffer(RenderContext& context, CommandBuffer& command_buffer, const ShaderRecompiler::IR::AddressResource& resource, const ShaderRecompiler::IR::ResourceSnapshot::Address& address, - uint32_t& address_offset) { + DescriptorCache::Stage stage, uint32_t slot, uint32_t& address_offset) { BufferView result; address_offset = 0; if (address.binding_base == 0) { @@ -147,17 +163,20 @@ NativeAddressBuffer(RenderContext& context, CommandBuffer& command_buffer, } const auto& graphics = context.GetGraphics(); const auto alignment = graphics.StorageMinAlignment(); - auto binding = + auto binding = context.GetBufferCache().ObtainBuffer(command_buffer, address.binding_base, size); const auto aligned_offset = binding.offset - binding.offset % alignment; const auto adjustment = binding.offset - aligned_offset; const auto max_range = graphics.GetPhysicalDeviceProperties().limits.maxStorageBufferRange; - const auto visible_size = std::min(size, static_cast(max_range - adjustment)); - address_offset = static_cast(adjustment); - result.owner = std::move(binding.owner); - result.buffer = binding.buffer; - result.offset = aligned_offset; - result.range = static_cast(visible_size + adjustment); + const auto visible_size = std::min(size, static_cast(max_range - adjustment)); + address_offset = static_cast(adjustment); + result.owner = std::move(binding.owner); + result.buffer = binding.buffer; + result.offset = aligned_offset; + result.range = static_cast(visible_size + adjustment); + SetVulkanObjectNameF(graphics.device, result.buffer, + "Kyty.{}.AddressBuffer[slot={} guest=0x{:016x} size=0x{:x}]", + ShaderStageResourceName(stage), slot, address.binding_base, visible_size); return result; } @@ -458,10 +477,9 @@ void ValidateStorageTexture(const ShaderRecompiler::IR::ImageResource& resource, const bool raw_sint_storage = format == Prospero::BufferFormat::k32SInt && uint_resource && resource.written && !resource.read && !resource.atomic; const bool format_ok = - raw_sint_storage || - (Prospero::IsSampledTextureFormat(format) && - uint_resource == Prospero::IsUintTextureFormat(format) && - (!resource.atomic || format == Prospero::BufferFormat::k32UInt)); + raw_sint_storage || (Prospero::IsSampledTextureFormat(format) && + uint_resource == Prospero::IsUintTextureFormat(format) && + (!resource.atomic || format == Prospero::BufferFormat::k32UInt)); if (resource_ok && descriptor_ok && encoding_ok && format_ok && size != 0) { return; } @@ -568,8 +586,8 @@ static void PopulateTextureMipLayout(ImageInfo& info) { static ImageViewInfo TextureViewInfo(const ShaderRecompiler::IR::ImageResource& resource, const ShaderTextureResource& descriptor, vk::Format format, - bool shader_conversion, bool storage, - uint32_t view_levels, uint32_t image_layers) { + bool shader_conversion, bool storage, uint32_t view_levels, + uint32_t image_layers) { ImageViewInfo view {}; view.format = format; view.aspect = vk::ImageAspectFlagBits::eColor; @@ -684,10 +702,9 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso const bool shader_conversion = surface_format.conversion_format != Prospero::BufferFormat::kInvalid; const bool sampled_numeric_class = - storage || - (Prospero::IsSampledTextureFormat(format) && - (resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) == - Prospero::IsUintTextureFormat(format)); + storage || (Prospero::IsSampledTextureFormat(format) && + (resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) == + Prospero::IsUintTextureFormat(format)); if (!storage && (resource.kind == ShaderRecompiler::IR::ResourceKind::Image || resource.kind == ShaderRecompiler::IR::ResourceKind::ImageUint) && @@ -752,7 +769,7 @@ RenderExecutor::ResolveTexture(const ShaderRecompiler::IR::ImageResource& reso view_levels, desc.info.resources.layers); desc.type = storage ? TextureCache::BindingType::Storage : TextureCache::BindingType::Texture; - auto id = texture_cache.FindImage(desc, shader_conversion); + auto id = texture_cache.FindImage(desc, shader_conversion); auto* image = &texture_cache.GetImage(id); const bool stencil_association = static_cast(image->depth_id); if (stencil_association) { @@ -910,17 +927,18 @@ void RenderExecutor::RebindBuffers(CommandBuffer& buffer, CopyNativeDescriptor(snapshot.buffers[i], descriptor.fields); uint32_t buffer_offset = 0; resources.buffers.push_back(NativeStorageBuffer(m_context, buffer, descriptor, - program.info.buffers[i], buffer_offset)); + program.info.buffers[i], prepared.stage, i, + buffer_offset)); pack_memory_offset(i, buffer_offset); } resources.addresses.clear(); resources.addresses.reserve(program.info.addresses.size()); for (uint32_t i = 0; i < program.info.addresses.size(); i++) { uint32_t address_offset = 0; - resources.addresses.push_back(NativeAddressBuffer( - m_context, buffer, program.info.addresses[i], snapshot.addresses[i], address_offset)); - pack_memory_offset(static_cast(program.info.buffers.size()) + i, - address_offset); + resources.addresses.push_back( + NativeAddressBuffer(m_context, buffer, program.info.addresses[i], snapshot.addresses[i], + prepared.stage, i, address_offset)); + pack_memory_offset(static_cast(program.info.buffers.size()) + i, address_offset); } } diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index 24dfc091b..a55bee6fd 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -142,18 +142,6 @@ static void LogMrtState(const char* draw_name, const RenderCommandBuffer& buffer (bc0.separate_alpha_blend && (IsDualSourceBlendFactor(bc0.alpha_srcblend) || IsDualSourceBlendFactor(bc0.alpha_destblend))); - for (uint32_t i = 1; i < 8; i++) { - const auto& rt = ctx.GetRenderTarget(i); - if (rt.base.addr != 0 || ps_input_info.target_output_mode[i] != 0 || - ((rt_mask >> (i * 4u)) & 0x0fu) != 0 || ((cb_shader_mask >> (i * 4u)) & 0x0fu) != 0) { - interesting = true; - } - } - - if (!interesting) { - return; - } - auto log_id = g_mrt_state_log_count.fetch_add(1); if (log_id >= 32) { return; @@ -553,8 +541,7 @@ struct DrawCallInfo { }; static bool ResolveDccAttachmentClear(TextureCache& cache, const RenderColorInfo& target, - const ImageViewInfo& view, - vk::ClearColorValue& clear_value) { + const ImageViewInfo& view, vk::ClearColorValue& clear_value) { if (target.desc.info.metadata.kind != ImageMetadataKind::Dcc) { return false; } @@ -641,6 +628,15 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo } target.image_view = cache.FindRenderTarget(target.image_id, target.desc); auto& image = cache.GetImage(target.image_id); + SetVulkanObjectNameF(m_context.GetGraphics().device, image.backing.image, + "Kyty.MRT{}.Image[guest=0x{:016x} size=0x{:x} format={}]", + target.target_slot, image.info.data.address, image.info.data.size, + static_cast(image.info.pixel_format)); + SetVulkanObjectNameF(m_context.GetGraphics().device, target.image_view, + "Kyty.MRT{}.View[guest=0x{:016x} mip={} layer={}+{}]", + target.target_slot, image.info.data.address, + target.desc.view_info.base_level, target.desc.view_info.base_layer, + target.desc.view_info.layer_count); EXIT_IF(image.backing.samples != target.samples || target.image_view == nullptr); if (attachment_samples == 0) { attachment_samples = target.samples; @@ -657,15 +653,15 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo ImageSubresourceRange {view.base_level, view.level_count, view.base_layer, view.layer_count}, buffer.Handle()); - state.width = std::min(state.width, target.extent.width); - state.height = std::min(state.height, target.extent.height); - state.num_layers = std::min(state.num_layers, view.layer_count); - auto& attachment = state.color_attachments[i]; - attachment.image_view = target.image_view; - attachment.image_layout = layout; - attachment.clear_value = target.color_clear_value.uint32; + state.width = std::min(state.width, target.extent.width); + state.height = std::min(state.height, target.extent.height); + state.num_layers = std::min(state.num_layers, view.layer_count); + auto& attachment = state.color_attachments[i]; + attachment.image_view = target.image_view; + attachment.image_layout = layout; + attachment.clear_value = target.color_clear_value.uint32; vk::ClearColorValue metadata_clear_value {}; - const bool metadata_clear = + const bool metadata_clear = ResolveDccAttachmentClear(cache, target, view, metadata_clear_value); if (metadata_clear) { attachment.clear_value = metadata_clear_value.uint32; @@ -690,6 +686,14 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo EXIT("failed to consume HTile clear state\n"); } auto& image = cache.GetImage(depth.image_id); + SetVulkanObjectNameF(m_context.GetGraphics().device, image.backing.image, + "Kyty.DepthTarget.Image[guest=0x{:016x} size=0x{:x} format={}]", + image.info.data.address, image.info.data.size, + static_cast(image.info.pixel_format)); + SetVulkanObjectNameF(m_context.GetGraphics().device, depth.image_view, + "Kyty.DepthTarget.View[guest=0x{:016x} layer={}+{}]", + image.info.data.address, depth.desc.view_info.base_layer, + depth.desc.view_info.layer_count); EXIT_IF(depth.image_view == nullptr || image.backing.samples != depth.samples); if (attachment_samples == 0) { attachment_samples = depth.samples; @@ -862,6 +866,9 @@ static PreparedVertexBuffers AcquireVertexBuffers(RenderCommandBuffer& b Libs::LibKernel::Memory::ClampRangeSize(range.base_address, range.RequestedSize()); range.acquired_end = range.base_address + size; range.binding = cache.ObtainBuffer(buffer, range.base_address, size); + SetVulkanObjectNameF(buffer.GetContext().GetGraphics().device, range.binding.buffer, + "Kyty.VertexBufferRange[guest=0x{:016x} size=0x{:x}]", + range.base_address, size); } // Rebuild slot bindings, offsetting non-empty slots into their acquired merged range. @@ -894,6 +901,10 @@ static PreparedVertexBuffers AcquireVertexBuffers(RenderCommandBuffer& b prepared.buffers[i] = range->binding.buffer; prepared.offsets[i] = range->binding.offset + vertex.addr - range->base_address; + SetVulkanObjectNameF( + buffer.GetContext().GetGraphics().device, prepared.buffers[i], + "Kyty.VertexBuffer[slot={} guest=0x{:016x} size=0x{:x} stride={} records={}]", i, + vertex.addr, size, vertex.stride, vertex.num_records); } if (null_owner != nullptr) { @@ -1104,6 +1115,15 @@ static PreparedIndexBuffer PrepareIndexBuffer(RenderCommandBuffer& buffe prepared.buffer = binding.buffer; prepared.offset = binding.offset; } + if (source.host_data != nullptr) { + SetVulkanObjectNameF(buffer.GetContext().GetGraphics().device, prepared.buffer, + "Kyty.IndexBuffer[guest=transient size=0x{:x} type={}]", source.size, + static_cast(source.type)); + } else { + SetVulkanObjectNameF(buffer.GetContext().GetGraphics().device, prepared.buffer, + "Kyty.IndexBuffer[guest=0x{:016x} size=0x{:x} type={}]", + source.address, source.size, static_cast(source.type)); + } return prepared; } diff --git a/src/graphics/host_gpu/vulkanCommon.h b/src/graphics/host_gpu/vulkanCommon.h index c9b0fa451..bc0fe9227 100644 --- a/src/graphics/host_gpu/vulkanCommon.h +++ b/src/graphics/host_gpu/vulkanCommon.h @@ -10,10 +10,13 @@ #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#include "common/emulatorConfig.h" #include "graphics/guest_gpu/gpu_defs.h" #include +#include #include +#include #include #include #include @@ -29,6 +32,24 @@ std::string VulkanToString(vk::QueueFlags value); vk::Format VulkanFormat(Prospero::BufferFormat guest_format); void RequireVulkanSuccess(vk::Result result, const char* operation); +template +void SetVulkanObjectNameF(vk::Device device, Handle handle, fmt::format_string format, + Args&&... args) { + if (!Config::GraphicsDebugDumpEnabled() || device == nullptr || handle == nullptr || + VULKAN_HPP_DEFAULT_DISPATCHER.vkSetDebugUtilsObjectNameEXT == nullptr) { + return; + } + + const auto name = fmt::format(format, std::forward(args)...); + vk::DebugUtilsObjectNameInfoEXT info {}; + info.sType = vk::StructureType::eDebugUtilsObjectNameInfoEXT; + info.objectType = Handle::objectType; + info.objectHandle = static_cast( + reinterpret_cast(static_cast(handle))); + info.pObjectName = name.c_str(); + (void)device.setDebugUtilsObjectNameEXT(&info); +} + template [[nodiscard]] std::vector EnumerateVulkan(const char* operation, Enumerator&& enumerate) { for (;;) {