mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-14 10:09:32 +01:00
Merge pull request #12266 from hrydgard/vulkan-gpu-profiling-2
Vulkan: Further improvements to GPU profiling
This commit is contained in:
5 files changed
+49
-16
No files matched your search
@@ -116,6 +116,7 @@ void DrawProfilerVis(UIContext *ui, GPUInterface *gpu) {
|
||||
std::string text = gpuVulkan->GetGpuProfileString();
|
||||
|
||||
Draw::DrawContext *draw = ui->GetDrawContext();
|
||||
ui->SetFontScale(0.4f, 0.4f);
|
||||
ui->DrawTextShadow(text.c_str(), 10, 50, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
|
||||
ui->Flush();
|
||||
}
|
||||
@@ -374,7 +374,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) {
|
||||
return pass;
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps) {
|
||||
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps, VkQueryPool queryPool, std::vector<std::string> *timestampDescriptions) {
|
||||
// Optimizes renderpasses, then sequences them.
|
||||
// Planned optimizations:
|
||||
// * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes
|
||||
@@ -461,6 +461,11 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &st
|
||||
case VKRStepType::RENDER_SKIP:
|
||||
break;
|
||||
}
|
||||
|
||||
if (queryPool) {
|
||||
vkCmdWriteTimestamp(cmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, (uint32_t)timestampDescriptions->size());
|
||||
timestampDescriptions->push_back(StepToString(step));
|
||||
}
|
||||
}
|
||||
|
||||
// Deleting all in one go should be easier on the instruction cache than deleting
|
||||
@@ -695,10 +700,43 @@ void VulkanQueueRunner::ApplySonicHack(std::vector<VKRStep *> &steps) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string VulkanQueueRunner::StepToString(const VKRStep &step) const {
|
||||
char buffer[256];
|
||||
switch (step.stepType) {
|
||||
case VKRStepType::RENDER:
|
||||
{
|
||||
int w = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth();
|
||||
int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight();
|
||||
snprintf(buffer, sizeof(buffer), "RenderPass (draws: %d, %dx%d, fb: %p, )", step.render.numDraws, w, h, step.render.framebuffer);
|
||||
break;
|
||||
}
|
||||
case VKRStepType::COPY:
|
||||
snprintf(buffer, sizeof(buffer), "Copy (%dx%d)", step.copy.srcRect.extent.width, step.copy.srcRect.extent.height);
|
||||
break;
|
||||
case VKRStepType::BLIT:
|
||||
snprintf(buffer, sizeof(buffer), "Blit (%dx%d->%dx%d)", step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height);
|
||||
break;
|
||||
case VKRStepType::READBACK:
|
||||
snprintf(buffer, sizeof(buffer), "Readback (%dx%d)", step.readback.srcRect.extent.width, step.readback.srcRect.extent.height);
|
||||
break;
|
||||
case VKRStepType::READBACK_IMAGE:
|
||||
snprintf(buffer, sizeof(buffer), "ReadbackImage");
|
||||
break;
|
||||
case VKRStepType::RENDER_SKIP:
|
||||
snprintf(buffer, sizeof(buffer), "(SKIPPED RenderPass)");
|
||||
break;
|
||||
default:
|
||||
buffer[0] = 0;
|
||||
break;
|
||||
}
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps) {
|
||||
ILOG("=======================================");
|
||||
for (size_t i = 0; i < steps.size(); i++) {
|
||||
const VKRStep &step = *steps[i];
|
||||
ILOG("%s", StepToString(step).c_str());
|
||||
switch (step.stepType) {
|
||||
case VKRStepType::RENDER:
|
||||
LogRenderPass(step);
|
||||
|
||||
@@ -163,9 +163,11 @@ public:
|
||||
}
|
||||
|
||||
// RunSteps can modify steps but will leave it in a valid state.
|
||||
void RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps);
|
||||
void RunSteps(VkCommandBuffer cmd, std::vector<VKRStep *> &steps, VkQueryPool queryPool, std::vector<std::string> *timestampDescriptions);
|
||||
void LogSteps(const std::vector<VKRStep *> &steps);
|
||||
|
||||
std::string StepToString(const VKRStep &step) const;
|
||||
|
||||
void CreateDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
|
||||
|
||||
@@ -350,12 +350,12 @@ void VulkanRenderManager::ThreadFunc() {
|
||||
}
|
||||
|
||||
void VulkanRenderManager::BeginFrame(bool enableProfiling) {
|
||||
gpuProfilingEnabled_ = enableProfiling;
|
||||
VLOG("BeginFrame");
|
||||
VkDevice device = vulkan_->GetDevice();
|
||||
|
||||
int curFrame = vulkan_->GetCurFrame();
|
||||
FrameData &frameData = frameData_[curFrame];
|
||||
frameData.profilingEnabled_ = enableProfiling;
|
||||
|
||||
// Make sure the very last command buffer from the frame before the previous has been fully executed.
|
||||
if (useThread_) {
|
||||
@@ -373,7 +373,7 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling) {
|
||||
|
||||
uint64_t queryResults[MAX_TIMESTAMP_QUERIES];
|
||||
|
||||
if (gpuProfilingEnabled_) {
|
||||
if (frameData.profilingEnabled_) {
|
||||
// Pull the profiling results from last time and produce a summary!
|
||||
if (!frameData.timestampDescriptions.empty()) {
|
||||
int numQueries = (int)frameData.timestampDescriptions.size();
|
||||
@@ -416,7 +416,7 @@ void VulkanRenderManager::BeginFrame(bool enableProfiling) {
|
||||
insideFrame_ = true;
|
||||
|
||||
frameData.timestampDescriptions.clear();
|
||||
if (gpuProfilingEnabled_) {
|
||||
if (frameData_->profilingEnabled_) {
|
||||
// For various reasons, we need to always use an init cmd buffer in this case to perform the vkCmdResetQueryPool,
|
||||
// unless we want to limit ourselves to only measure the main cmd buffer.
|
||||
// Reserve the first two queries for initCmd.
|
||||
@@ -954,7 +954,7 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) {
|
||||
void VulkanRenderManager::Submit(int frame, bool triggerFence) {
|
||||
FrameData &frameData = frameData_[frame];
|
||||
if (frameData.hasInitCommands) {
|
||||
if (gpuProfilingEnabled_ && triggerFence) {
|
||||
if (frameData.profilingEnabled_ && triggerFence) {
|
||||
// Pre-allocated query ID 1.
|
||||
vkCmdWriteTimestamp(frameData.initCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.timestampQueryPool_, 1);
|
||||
}
|
||||
@@ -962,12 +962,6 @@ void VulkanRenderManager::Submit(int frame, bool triggerFence) {
|
||||
_assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (init)! result=%s", VulkanResultToString(res));
|
||||
}
|
||||
|
||||
if (gpuProfilingEnabled_) {
|
||||
int numQueries = (int)frameData.timestampDescriptions.size();
|
||||
vkCmdWriteTimestamp(frameData.mainCmd, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, frameData.timestampQueryPool_, numQueries);
|
||||
frameData.timestampDescriptions.push_back("mainCmd");
|
||||
}
|
||||
|
||||
VkResult res = vkEndCommandBuffer(frameData.mainCmd);
|
||||
_assert_msg_(G3D, res == VK_SUCCESS, "vkEndCommandBuffer failed (main)! result=%s", VulkanResultToString(res));
|
||||
|
||||
@@ -1063,7 +1057,7 @@ void VulkanRenderManager::Run(int frame) {
|
||||
auto &stepsOnThread = frameData_[frame].steps;
|
||||
VkCommandBuffer cmd = frameData.mainCmd;
|
||||
// queueRunner_.LogSteps(stepsOnThread);
|
||||
queueRunner_.RunSteps(cmd, stepsOnThread);
|
||||
queueRunner_.RunSteps(cmd, stepsOnThread, frameData.profilingEnabled_ ? frameData.timestampQueryPool_ : VK_NULL_HANDLE, &frameData.timestampDescriptions);
|
||||
stepsOnThread.clear();
|
||||
|
||||
switch (frameData.type) {
|
||||
|
||||
@@ -291,6 +291,7 @@ private:
|
||||
|
||||
// Profiling.
|
||||
VkQueryPool timestampQueryPool_ = VK_NULL_HANDLE;
|
||||
bool profilingEnabled_;
|
||||
std::vector<std::string> timestampDescriptions;
|
||||
std::string profileSummary;
|
||||
};
|
||||
@@ -301,9 +302,6 @@ private:
|
||||
MAX_TIMESTAMP_QUERIES = 256,
|
||||
};
|
||||
|
||||
// Global state
|
||||
bool gpuProfilingEnabled_ = false;
|
||||
|
||||
// Submission time state
|
||||
int curWidth_ = -1;
|
||||
int curHeight_ = -1;
|
||||
|
||||
Reference in new issue
Block a user