Merge pull request #12266 from hrydgard/vulkan-gpu-profiling-2

Vulkan: Further improvements to GPU profiling
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2019-08-21 18:49:00 +02:00
commit 16f4f525e7
5 files changed
+49 -16

No files matched your search

+1
View File
@@ -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();
}
+39 -1
View File
@@ -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);
+3 -1
View File
@@ -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();
+5 -11
View File
@@ -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) {
+1 -3
View File
@@ -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;