mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Debug visualization for the Vulkan memory allocator. Shows some interesting behaviour.
This commit is contained in:
1 parent
2ae2dd7d40
commit
c60c8ed68a
18 files changed
+168
-15
No files matched your search
@@ -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
|
||||
|
||||
@@ -293,6 +293,13 @@ int VulkanDeviceAllocator::ComputeUsagePercent() const {
|
||||
return blockSum == 0 ? 0 : 100 * blocksUsed / blockSum;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> VulkanDeviceAllocator::GetSlabUsage(int slabIndex) const {
|
||||
if (slabIndex < 0 || slabIndex >= (int)slabs_.size())
|
||||
return std::vector<uint8_t>();
|
||||
const Slab &slab = slabs_[slabIndex];
|
||||
return slab.usage;
|
||||
}
|
||||
|
||||
void VulkanDeviceAllocator::Free(VkDeviceMemory deviceMemory, size_t offset) {
|
||||
assert(!destroyed_);
|
||||
|
||||
|
||||
@@ -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<uint8_t> GetSlabUsage(int slab) const;
|
||||
|
||||
private:
|
||||
static const size_t SLAB_GRAIN_SIZE = 1024;
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+3
-1
@@ -256,6 +256,7 @@
|
||||
<ClInclude Include="Software\SoftGpu.h" />
|
||||
<ClInclude Include="Software\TransformUnit.h" />
|
||||
<ClInclude Include="Common\TextureDecoder.h" />
|
||||
<ClInclude Include="Vulkan\DebugVisVulkan.h" />
|
||||
<ClInclude Include="Vulkan\DepalettizeShaderVulkan.h" />
|
||||
<ClInclude Include="Vulkan\DrawEngineVulkan.h" />
|
||||
<ClInclude Include="Vulkan\FragmentShaderGeneratorVulkan.h" />
|
||||
@@ -360,6 +361,7 @@
|
||||
<ClCompile Include="Software\SoftGpu.cpp" />
|
||||
<ClCompile Include="Software\TransformUnit.cpp" />
|
||||
<ClCompile Include="Common\TextureDecoder.cpp" />
|
||||
<ClCompile Include="Vulkan\DebugVisVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\DepalettizeShaderVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\DrawEngineVulkan.cpp" />
|
||||
<ClCompile Include="Vulkan\FragmentShaderGeneratorVulkan.cpp" />
|
||||
@@ -385,4 +387,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -270,6 +270,7 @@
|
||||
<ClInclude Include="D3D11\StateMappingD3D11.h">
|
||||
<Filter>D3D11</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Vulkan\DebugVisVulkan.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Math3D.cpp">
|
||||
@@ -536,5 +537,6 @@
|
||||
<ClCompile Include="Common\StencilCommon.cpp">
|
||||
<Filter>Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\DebugVisVulkan.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -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_Vulkan *>(gpu);
|
||||
VulkanDeviceAllocator *alloc = gpuVulkan->GetTextureCache()->GetAllocator();
|
||||
|
||||
std::vector<Draw::Texture *> texturesToDelete;
|
||||
for (int i = 0; i < alloc->GetSlabCount(); i++) {
|
||||
std::vector<uint8_t> 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<uint8_t> 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();
|
||||
}
|
||||
@@ -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);
|
||||
@@ -78,6 +78,10 @@ public:
|
||||
std::vector<std::string> 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;
|
||||
|
||||
@@ -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<std::string> TextureCacheVulkan::DebugGetSamplerIDs() const {
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
Vulkan2D(VulkanContext *vulkan);
|
||||
~Vulkan2D();
|
||||
|
||||
VulkanContext *GetVulkanContext() const { return vulkan_; }
|
||||
|
||||
void DeviceLost();
|
||||
void DeviceRestore(VulkanContext *vulkan);
|
||||
void Shutdown();
|
||||
|
||||
@@ -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);
|
||||
|
||||
+13
-8
@@ -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() {
|
||||
|
||||
@@ -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 := \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -520,6 +520,7 @@ struct TextureDesc {
|
||||
int depth;
|
||||
int mipLevels;
|
||||
bool generateMips;
|
||||
// Does not take ownership over pointed-to data.
|
||||
std::vector<uint8_t *> 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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user