diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index abf4072a23..7d483f11ad 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -694,6 +694,14 @@ VkResult VulkanContext::InitDebugUtilsCallback() { return res; } +void VulkanContext::SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name) { + VkDebugUtilsObjectNameInfoEXT info{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; + info.pObjectName = name; + info.objectHandle = handle; + info.objectType = type; + vkSetDebugUtilsObjectNameEXT(device_, &info); +} + VkResult VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2) { winsys_ = winsys; winsysData1_ = data1; @@ -1383,7 +1391,7 @@ void VulkanDeleteList::PerformDeletes(VkDevice device) { } void VulkanContext::GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation) { - if (DeviceExtensions().KHR_dedicated_allocation) { + if (Extensions().KHR_dedicated_allocation) { VkImageMemoryRequirementsInfo2KHR memReqInfo2{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR}; memReqInfo2.image = image; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index db61f2e5b1..7c9174f38f 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -167,6 +167,14 @@ public: void BeginFrame(); void EndFrame(); + // Simple workaround for the casting warning. + template + void SetDebugName(T handle, VkObjectType type, const char *name) { + if (extensionsLookup_.EXT_debug_utils) { + SetDebugNameImpl((uint64_t)handle, type, name); + } + } + bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex); VkPhysicalDevice GetPhysicalDevice(int n) const { @@ -267,13 +275,15 @@ public: MAX_INFLIGHT_FRAMES = 3, }; - const VulkanDeviceExtensions &DeviceExtensions() { return extensionsLookup_; } + const VulkanExtensions &Extensions() { return extensionsLookup_; } void GetImageMemoryRequirements(VkImage image, VkMemoryRequirements *mem_reqs, bool *dedicatedAllocation); private: bool ChooseQueue(); + void SetDebugNameImpl(uint64_t handle, VkObjectType type, const char *name); + VkResult InitDebugUtilsCallback(); // A layer can expose extensions, keep track of those extensions here. @@ -307,7 +317,7 @@ private: std::vector device_extensions_enabled_; std::vector device_extension_properties_; - VulkanDeviceExtensions extensionsLookup_{}; + VulkanExtensions extensionsLookup_{}; std::vector physical_devices_; diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index d6f3f53877..247df10ff9 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -71,6 +71,9 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all return false; } + // Apply the tag + vulkan_ ->SetDebugName(image_, VK_OBJECT_TYPE_IMAGE, tag_.c_str()); + VkMemoryRequirements mem_reqs{}; bool dedicatedAllocation = false; vulkan_->GetImageMemoryRequirements(image_, &mem_reqs, &dedicatedAllocation); @@ -161,6 +164,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *all return true; } +// TODO: Batch these. void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) { VkBufferImageCopy copy_region{}; copy_region.bufferOffset = offset; diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 43298ec9c4..59b3fb5bd3 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -489,7 +489,7 @@ bool VulkanLoad() { } } -void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions) { +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions) { // OK, let's use the above functions to get the rest. LOAD_INSTANCE_FUNC(instance, vkDestroyInstance); LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices); @@ -554,7 +554,7 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio // On some implementations, loading functions (that have Device as their first parameter) via vkGetDeviceProcAddr may // increase performance - but then these function pointers will only work on that specific device. Thus, this loader is not very // good for multi-device - not likely we'll ever try that anyway though. -void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions) { +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions) { WLOG("Vulkan device functions loaded."); LOAD_DEVICE_FUNC(device, vkQueueSubmit); diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index e9c7f96156..c91ad6296c 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -215,7 +215,7 @@ extern PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; extern PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; // For fast extension-enabled checks. -struct VulkanDeviceExtensions { +struct VulkanExtensions { bool EXT_debug_utils; bool KHR_maintenance1; // required for KHR_create_renderpass2 bool KHR_maintenance2; @@ -236,6 +236,6 @@ bool VulkanMayBeAvailable(); void VulkanSetAvailable(bool available); bool VulkanLoad(); -void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensions &enabledExtensions); -void VulkanLoadDeviceFunctions(VkDevice device, const VulkanDeviceExtensions &enabledExtensions); +void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanExtensions &enabledExtensions); +void VulkanLoadDeviceFunctions(VkDevice device, const VulkanExtensions &enabledExtensions); void VulkanFree(); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 5be05dfded..556e2519ee 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1060,7 +1060,9 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } shaderManager_->DirtyLastShader(); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); + char name[256]; + snprintf(name, sizeof(name), "%08x_%08x", vfb->fb_address, vfb->z_address); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, name }); if (old.fbo) { INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %d x %d x %d", vfb->fb_address, w, h, vfb->format); if (vfb->fbo) { @@ -1329,7 +1331,9 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd vfb->usageFlags = FB_USAGE_RENDERTARGET; SetColorUpdated(vfb, 0); textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth }); + char name[64]; + snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, name }); vfbs_.push_back(vfb); u32 byteSize = ColorBufferByteSize(vfb); @@ -1417,7 +1421,9 @@ bool FramebufferManagerCommon::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb } } - nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, false, (Draw::FBColorDepth)nvfb->colorDepth }); + char name[64]; + snprintf(name, sizeof(name), "download_temp"); + nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, false, (Draw::FBColorDepth)nvfb->colorDepth, name }); if (!nvfb->fbo) { ERROR_LOG(FRAMEBUF, "Error creating GL FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); return false; @@ -1744,7 +1750,8 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u textureCache_->ForgetLastTexture(); bool z_stencil = reason == TempFBO::STENCIL; - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, depth }); + const char *name = "temp_fbo"; + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, depth, name }); if (!fbo) return fbo; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 09bf2c2009..9ef488ffda 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -317,7 +317,7 @@ bool PresentationCommon::AllocateFramebuffer(int w, int h) { } // No depth/stencil for post processing - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, Draw::FBO_8888 }); + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, Draw::FBO_8888, "presentation" }); if (!fbo) { return false; } diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 8631e4cdea..d15f68988a 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -859,7 +859,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { } char texName[128]{}; - snprintf(texName, sizeof(texName), "Texture%08x", entry->addr); + snprintf(texName, sizeof(texName), "texture_%08x_%s", entry->addr, GeTextureFormatToString((GETextureFormat)entry->format)); image->SetTag(texName); bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, imageLayout, usage, mapping); diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 32c9684db0..e1c2db94f0 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -789,7 +789,7 @@ void GameInfoCache::SetupTexture(std::shared_ptr &info, Draw::DrawCont using namespace Draw; if (tex.data.size()) { if (!tex.texture) { - tex.texture = CreateTextureFromFileData(thin3d, (const uint8_t *)tex.data.data(), (int)tex.data.size(), ImageFileType::DETECT); + tex.texture = CreateTextureFromFileData(thin3d, (const uint8_t *)tex.data.data(), (int)tex.data.size(), ImageFileType::DETECT, false, info->GetTitle().c_str()); if (tex.texture) { tex.timeLoaded = time_now_d(); } else { diff --git a/UI/Store.cpp b/UI/Store.cpp index 780a7f4c99..f52a1ae916 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -139,7 +139,7 @@ void HttpImageFileView::Draw(UIContext &dc) { } if (!textureData_.empty()) { - texture_ = CreateTextureFromFileData(dc.GetDrawContext(), (const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT); + texture_ = CreateTextureFromFileData(dc.GetDrawContext(), (const uint8_t *)(textureData_.data()), (int)textureData_.size(), DETECT, false, "store_icon"); if (!texture_) textureFailed_ = true; textureData_.clear(); diff --git a/UI/TextureUtil.cpp b/UI/TextureUtil.cpp index b79459f769..0d05bbc448 100644 --- a/UI/TextureUtil.cpp +++ b/UI/TextureUtil.cpp @@ -92,7 +92,7 @@ static bool LoadTextureLevels(const uint8_t *data, size_t size, ImageFileType ty return *num_levels > 0; } -bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips) { +bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips, const char *name) { generateMips_ = generateMips; using namespace Draw; @@ -131,7 +131,7 @@ bool ManagedTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, Imag desc.depth = 1; desc.mipLevels = generateMips ? potentialLevels : num_levels; desc.generateMips = generateMips && potentialLevels > num_levels; - desc.tag = "LoadedFileData"; + desc.tag = name; for (int i = 0; i < num_levels; i++) { desc.initData.push_back(image[i]); } @@ -152,7 +152,7 @@ bool ManagedTexture::LoadFromFile(const std::string &filename, ImageFileType typ ELOG("Failed to read file '%s'", filename.c_str()); return false; } - bool retval = LoadFromFileData(buffer, fileSize, type, generateMips); + bool retval = LoadFromFileData(buffer, fileSize, type, generateMips, filename.c_str()); if (retval) { filename_ = filename; } else { @@ -202,11 +202,11 @@ Draw::Texture *ManagedTexture::GetTexture() { } // TODO: Remove the code duplication between this and LoadFromFileData -std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type, bool generateMips) { +std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType type, bool generateMips, const char *name) { if (!draw) return std::unique_ptr(); ManagedTexture *mtex = new ManagedTexture(draw); - if (mtex->LoadFromFileData(data, size, type, generateMips)) { + if (mtex->LoadFromFileData(data, size, type, generateMips, name)) { return std::unique_ptr(mtex); } else { // Best to return a null pointer if we fail! diff --git a/UI/TextureUtil.h b/UI/TextureUtil.h index 6a93f4809b..d5ebca8a5c 100644 --- a/UI/TextureUtil.h +++ b/UI/TextureUtil.h @@ -23,7 +23,7 @@ public: } bool LoadFromFile(const std::string &filename, ImageFileType type = ImageFileType::DETECT, bool generateMips = false); - bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type = ImageFileType::DETECT, bool generateMips = false); + bool LoadFromFileData(const uint8_t *data, size_t dataSize, ImageFileType type, bool generateMips, const char *name); Draw::Texture *GetTexture(); // For immediate use, don't store. int Width() const { return texture_->Width(); } int Height() const { return texture_->Height(); } @@ -39,8 +39,8 @@ private: bool loadPending_ = false; }; -std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips = false); -std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips = false); +std::unique_ptr CreateTextureFromFile(Draw::DrawContext *draw, const char *filename, ImageFileType fileType, bool generateMips); +std::unique_ptr CreateTextureFromFileData(Draw::DrawContext *draw, const uint8_t *data, int size, ImageFileType fileType, bool generateMips, const char *name); class GameIconView : public UI::InertView { public: diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 088af77b01..c1e2d34f00 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -447,7 +447,7 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector &st } } - bool emitLabels = vulkan_->DeviceExtensions().EXT_debug_utils; + bool emitLabels = vulkan_->Extensions().EXT_debug_utils; for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index a595bfe29a..a56a357cc7 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -718,6 +718,8 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { if (res != VK_SUCCESS) return false; + vulkan_->SetDebugName(depth_.image, VK_OBJECT_TYPE_IMAGE, "BackbufferDepth"); + bool dedicatedAllocation = false; VkMemoryRequirements mem_reqs; vulkan_->GetImageMemoryRequirements(depth_.image, &mem_reqs, &dedicatedAllocation); diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 3bc5a344e7..6113132980 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -11,6 +11,7 @@ #include #include "base/display.h" +#include "base/stringutil.h" #include "Common/Vulkan/VulkanContext.h" #include "math/dataconv.h" #include "math/math_util.h" @@ -30,7 +31,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height) : vulkan_(vk) { + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag) : vulkan_(vk) { width = _width; height = _height; @@ -50,6 +51,11 @@ public: fbci.layers = 1; vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf); + if (vk->Extensions().EXT_debug_utils) { + vk->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_color_%s", tag).c_str()); + vk->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_depth_%s", tag).c_str()); + vk->SetDebugName(framebuf, VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag).c_str()); + } } ~VKRFramebuffer() { diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 2ead85c2e4..ced1d8df67 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -311,6 +311,7 @@ struct FramebufferDesc { int numColorAttachments; bool z_stencil; FBColorDepth colorDepth; + const char *tag; // For graphics debuggers }; // Binary compatible with D3D11 viewport. @@ -536,8 +537,8 @@ struct TextureDesc { int depth; int mipLevels; bool generateMips; - // Optional, for tracking memory usage. - std::string tag; + // Optional, for tracking memory usage and graphcis debuggers. + const char *tag; // Does not take ownership over pointed-to data. std::vector initData; TextureCallback initDataCallback; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index a0b3a5f1d4..7c033aeed3 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -714,7 +714,9 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur height_ = desc.height; depth_ = desc.depth; vkTex_ = new VulkanTexture(vulkan_); - vkTex_->SetTag(desc.tag); + if (desc.tag) { + vkTex_->SetTag(desc.tag); + } VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); int bytesPerPixel = bpp / 8; @@ -1462,7 +1464,7 @@ private: Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) { VkCommandBuffer cmd = renderManager_.GetInitCmd(); - VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetFramebufferRenderPass(), desc.width, desc.height); + VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetFramebufferRenderPass(), desc.width, desc.height, desc.tag); return new VKFramebuffer(vkrfb); }