diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a1ae75c2d..9e2dedf410 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1188,6 +1188,8 @@ set(GPU_GLES set(GPU_VULKAN GPU/Vulkan/DepalettizeShaderVulkan.cpp GPU/Vulkan/DepalettizeShaderVulkan.h + GPU/Vulkan/DebugVisVulkan.cpp + GPU/Vulkan/DebugVisVulkan.h GPU/Vulkan/DrawEngineVulkan.cpp GPU/Vulkan/DrawEngineVulkan.h GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index d19467847e..0950bc8596 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -293,6 +293,13 @@ int VulkanDeviceAllocator::ComputeUsagePercent() const { return blockSum == 0 ? 0 : 100 * blocksUsed / blockSum; } +std::vector VulkanDeviceAllocator::GetSlabUsage(int slabIndex) const { + if (slabIndex < 0 || slabIndex >= (int)slabs_.size()) + return std::vector(); + const Slab &slab = slabs_[slabIndex]; + return slab.usage; +} + void VulkanDeviceAllocator::Free(VkDeviceMemory deviceMemory, size_t offset) { assert(!destroyed_); diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h index 5541f0d628..1a74cbceb0 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/Vulkan/VulkanMemory.h @@ -146,11 +146,12 @@ public: static const size_t ALLOCATE_FAILED = -1; - int GetBlockCount() const { return (int)slabs_.size(); } + int GetSlabCount() const { return (int)slabs_.size(); } int GetMinSlabSize() const { return (int)minSlabSize_; } int GetMaxSlabSize() const { return (int)maxSlabSize_; } int ComputeUsagePercent() const; + std::vector GetSlabUsage(int slab) const; private: static const size_t SLAB_GRAIN_SIZE = 1024; diff --git a/Core/Config.cpp b/Core/Config.cpp index d35c3bc3e9..8fae1b0f60 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -789,6 +789,7 @@ static ConfigSetting debuggerSettings[] = { ConfigSetting("DisplayStatusBar", &g_Config.bDisplayStatusBar, true), ConfigSetting("ShowBottomTabTitles",&g_Config.bShowBottomTabTitles,true), ConfigSetting("ShowDeveloperMenu", &g_Config.bShowDeveloperMenu, false), + ConfigSetting("ShowAllocatorDebug", &g_Config.bShowAllocatorDebug, false, false), ConfigSetting("SkipDeadbeefFilling", &g_Config.bSkipDeadbeefFilling, false), ConfigSetting("FuncHashMap", &g_Config.bFuncHashMap, false), diff --git a/Core/Config.h b/Core/Config.h index 12534e3e6d..78af006d04 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -447,6 +447,7 @@ public: bool bDisplayStatusBar; bool bShowBottomTabTitles; bool bShowDeveloperMenu; + bool bShowAllocatorDebug; // Double edged sword: much easier debugging, but not accurate. bool bSkipDeadbeefFilling; bool bFuncHashMap; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index dc3d6f11d9..96fd523c37 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -256,6 +256,7 @@ + @@ -360,6 +361,7 @@ + @@ -385,4 +387,4 @@ - + \ No newline at end of file diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index ad9211a28c..ddc5b0ff12 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -270,6 +270,7 @@ D3D11 + @@ -536,5 +537,6 @@ Common + - + \ No newline at end of file diff --git a/GPU/Vulkan/DebugVisVulkan.cpp b/GPU/Vulkan/DebugVisVulkan.cpp new file mode 100644 index 0000000000..b095a4595f --- /dev/null +++ b/GPU/Vulkan/DebugVisVulkan.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2016- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "DebugVisVulkan.h" +#include "Common/Vulkan/VulkanMemory.h" +#include "Common/Vulkan/VulkanImage.h" +#include "GPU/Vulkan/GPU_Vulkan.h" +#include "GPU/Vulkan/VulkanUtil.h" +#include "gfx_es2/draw_buffer.h" +#include "thin3d/thin3d.h" +#include "ui/ui_context.h" +#include "ui/view.h" + +void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu) { + if (!gpu) { + return; + } + using namespace Draw; + const int padding = 10; + const int columnWidth = 256; + const int starty = padding * 8; + int x = padding; + int y = starty; + int w = columnWidth; // We will double this when actually drawing to make the pixels visible. + ui->End(); + + ui->Begin(); + + GPU_Vulkan *gpuVulkan = static_cast(gpu); + VulkanDeviceAllocator *alloc = gpuVulkan->GetTextureCache()->GetAllocator(); + + std::vector texturesToDelete; + for (int i = 0; i < alloc->GetSlabCount(); i++) { + std::vector usage = alloc->GetSlabUsage(i); + int h = ((int)usage.size() + w - 1) / w; + + if (y + h + padding > ui->GetBounds().h) { + y = starty; + x += columnWidth + padding; + } + + std::vector initData(w * h * 4); + uint32_t *wideData = (uint32_t *)initData.data(); + + // Convert to nice colors. If we really wanted to save on memory, we could use a 16-bit texture... + for (int j = 0; j < usage.size(); j++) { + switch (usage[j]) { + case 0: wideData[j] = 0xFF333333; break; + case 1: wideData[j] = 0xFF33FF33; break; + case 2: wideData[j] = 0xFF3333FF; break; + default: wideData[j] = 0xFFFF00FF; break; // Magenta - if you see this, need to add more cases. + } + } + + Draw::TextureDesc desc{}; + desc.width = w; + desc.height = h; + desc.depth = 1; + desc.format = Draw::DataFormat::R8G8B8A8_UNORM; + desc.mipLevels = 1; + desc.type = Draw::TextureType::LINEAR2D; + desc.initData.push_back(initData.data()); + + Draw::DrawContext *draw = ui->GetDrawContext(); + Draw::Texture *tex = draw->CreateTexture(desc); + + UI::Drawable white(0xFFFFFFFF); + draw->BindTexture(0, tex); + ui->Draw()->Rect(x, y, w, h, 0xFFFFFFFF); + ui->Flush(); + texturesToDelete.push_back(tex); + + y += h + padding; + } + ui->Flush(); + + for (auto iter : texturesToDelete) + iter->Release(); +} diff --git a/GPU/Vulkan/DebugVisVulkan.h b/GPU/Vulkan/DebugVisVulkan.h new file mode 100644 index 0000000000..9c0590bab4 --- /dev/null +++ b/GPU/Vulkan/DebugVisVulkan.h @@ -0,0 +1,26 @@ +// Copyright (c) 2016- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include "thin3d/thin3d.h" + +class GPUInterface; +class UIContext; + +// gpu MUST be an instance of GPU_Vulkan. If not, will definitely crash. +void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu); diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index caeb71b6e1..fcbbf4145d 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -78,6 +78,10 @@ public: std::vector DebugGetShaderIDs(DebugShaderType shader) override; std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override; + TextureCacheVulkan *GetTextureCache() { + return textureCacheVulkan_; + } + protected: void FastRunLoop(DisplayList &list) override; void FinishDeferred() override; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 4b844b192b..fd7aaa6bc0 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -845,7 +845,7 @@ bool TextureCacheVulkan::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int leve void TextureCacheVulkan::GetStats(char *ptr, size_t size) { snprintf(ptr, size, "Alloc: %d slabs\nSlab min/max: %d/%d\nAlloc usage: %d%%", - allocator_->GetBlockCount(), allocator_->GetMinSlabSize(), allocator_->GetMaxSlabSize(), allocator_->ComputeUsagePercent()); + allocator_->GetSlabCount(), allocator_->GetMinSlabSize(), allocator_->GetMaxSlabSize(), allocator_->ComputeUsagePercent()); } std::vector TextureCacheVulkan::DebugGetSamplerIDs() const { diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index 32b0421e4b..69c3e5357a 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -54,6 +54,8 @@ public: Vulkan2D(VulkanContext *vulkan); ~Vulkan2D(); + VulkanContext *GetVulkanContext() const { return vulkan_; } + void DeviceLost(); void DeviceRestore(VulkanContext *vulkan); void Shutdown(); diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 45870eda72..7597dd7087 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -70,6 +70,7 @@ void DevMenu::CreatePopupContents(UI::ViewGroup *parent) { items->Add(new Choice(sy->T("Developer Tools")))->OnClick.Handle(this, &DevMenu::OnDeveloperTools); items->Add(new Choice(dev->T("Jit Compare")))->OnClick.Handle(this, &DevMenu::OnJitCompare); items->Add(new Choice(dev->T("Shader Viewer")))->OnClick.Handle(this, &DevMenu::OnShaderView); + items->Add(new CheckBox(&g_Config.bShowAllocatorDebug, dev->T("Allocator Viewer"))); items->Add(new Choice(dev->T("Toggle Freeze")))->OnClick.Handle(this, &DevMenu::OnFreezeFrame); items->Add(new Choice(dev->T("Dump Frame GPU Commands")))->OnClick.Handle(this, &DevMenu::OnDumpFrame); items->Add(new Choice(dev->T("Toggle Audio Debug")))->OnClick.Handle(this, &DevMenu::OnToggleAudioDebug); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 439aaf3444..5aad74ca76 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -50,6 +50,7 @@ #include "GPU/GPUState.h" #include "GPU/GPUInterface.h" #include "GPU/GLES/FramebufferManagerGLES.h" +#include "GPU/Vulkan/DebugVisVulkan.h" #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceSas.h" @@ -1179,9 +1180,10 @@ void EmuScreen::renderUI() { using namespace Draw; DrawContext *thin3d = screenManager()->getDrawContext(); + UIContext *ctx = screenManager()->getUIContext(); // This sets up some important states but not the viewport. - screenManager()->getUIContext()->Begin(); + ctx->Begin(); Viewport viewport; viewport.TopLeftX = 0; @@ -1192,11 +1194,10 @@ void EmuScreen::renderUI() { viewport.MinDepth = 0.0; thin3d->SetViewports(1, &viewport); - DrawBuffer *draw2d = screenManager()->getUIContext()->Draw(); - + DrawBuffer *draw2d = ctx->Draw(); if (root_) { - UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_); - root_->Draw(*screenManager()->getUIContext()); + UI::LayoutViewHierarchy(*ctx, root_); + root_->Draw(*ctx); } if (g_Config.bShowDebugStats && !invalid_) { @@ -1208,16 +1209,20 @@ void EmuScreen::renderUI() { } if (g_Config.iShowFPSCounter && !invalid_) { - DrawFPS(draw2d, screenManager()->getUIContext()->GetBounds()); + DrawFPS(draw2d, ctx->GetBounds()); + } + + if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowAllocatorDebug) { + DrawAllocatorVis(ctx, gpu); } #ifdef USE_PROFILER if (g_Config.bShowFrameProfiler && !invalid_) { - DrawProfile(*screenManager()->getUIContext()); + DrawProfile(*ctx); } #endif - screenManager()->getUIContext()->End(); + ctx->End(); } void EmuScreen::autoLoad() { diff --git a/android/jni/Android.mk b/android/jni/Android.mk index ecd4352c45..76e874f288 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -142,7 +142,8 @@ VULKAN_FILES := \ $(SRC)/GPU/Vulkan/TextureScalerVulkan.cpp \ $(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \ $(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp \ - $(SRC)/GPU/Vulkan/VulkanUtil.cpp + $(SRC)/GPU/Vulkan/VulkanUtil.cpp \ + $(SRC)/GPU/Vulkan/DebugVisVulkan.cpp #endif SPIRV_CROSS_FILES := \ diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index b074e3b4f9..322738d44f 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -219,6 +219,10 @@ public: splitSubmit_ = split; } + VulkanContext *GetVulkanContext() { + return vulkan_; + } + private: bool InitBackbufferFramebuffers(int width, int height); bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering. diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index b401a6268f..9c993727d2 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -520,6 +520,7 @@ struct TextureDesc { int depth; int mipLevels; bool generateMips; + // Does not take ownership over pointed-to data. std::vector initData; }; @@ -564,6 +565,7 @@ public: // Resources virtual Buffer *CreateBuffer(size_t size, uint32_t usageFlags) = 0; + // Does not take ownership over pointed-to initData. After this returns, can dispose of it. virtual Texture *CreateTexture(const TextureDesc &desc) = 0; // On some hardware, you might get a 24-bit depth buffer even though you only wanted a 16-bit one. virtual Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) = 0; diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 2dac9803fa..ce89f21498 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -652,8 +652,7 @@ enum class TextureState { bool VKTexture::Create(VkCommandBuffer cmd, const TextureDesc &desc, VulkanDeviceAllocator *alloc) { // Zero-sized textures not allowed. - if (desc.width * desc.height * desc.depth == 0) - return false; + assert(desc.width * desc.height * desc.depth > 0); format_ = desc.format; mipLevels_ = desc.mipLevels; width_ = desc.width;