mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
121 lines
3.4 KiB
C++
121 lines
3.4 KiB
C++
#include <stdarg.h>
|
|
|
|
#include "VulkanProfiler.h"
|
|
#include "VulkanContext.h"
|
|
|
|
using namespace PPSSPP_VK;
|
|
|
|
void VulkanProfiler::Init(VulkanContext *vulkan) {
|
|
vulkan_ = vulkan;
|
|
|
|
int graphicsQueueFamilyIndex = vulkan_->GetGraphicsQueueFamilyIndex();
|
|
_assert_(graphicsQueueFamilyIndex >= 0);
|
|
|
|
if (queryPool_) {
|
|
vulkan->Delete().QueueDeleteQueryPool(queryPool_);
|
|
}
|
|
|
|
validBits_ = vulkan_->GetQueueFamilyProperties(graphicsQueueFamilyIndex).timestampValidBits;
|
|
|
|
if (validBits_) {
|
|
VkQueryPoolCreateInfo ci{ VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO };
|
|
ci.queryCount = MAX_QUERY_COUNT;
|
|
ci.queryType = VK_QUERY_TYPE_TIMESTAMP;
|
|
vkCreateQueryPool(vulkan->GetDevice(), &ci, nullptr, &queryPool_);
|
|
}
|
|
}
|
|
|
|
void VulkanProfiler::Shutdown() {
|
|
if (queryPool_) {
|
|
vulkan_->Delete().QueueDeleteQueryPool(queryPool_);
|
|
}
|
|
}
|
|
|
|
void VulkanProfiler::BeginFrame(VulkanContext *vulkan, VkCommandBuffer firstCommandBuf) {
|
|
if (!validBits_) {
|
|
return;
|
|
}
|
|
|
|
vulkan_ = vulkan;
|
|
|
|
// Check for old queries belonging to this frame context that we can log out - these are now
|
|
// guaranteed to be done.
|
|
if (numQueries_ > 0) {
|
|
std::vector<uint64_t> results(numQueries_);
|
|
vkGetQueryPoolResults(vulkan->GetDevice(), queryPool_, 0, numQueries_, sizeof(uint64_t) * numQueries_, results.data(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT);
|
|
|
|
double timestampConversionFactor = (double)vulkan_->GetPhysicalDeviceProperties().properties.limits.timestampPeriod * (1.0 / 1000000.0);
|
|
uint64_t timestampDiffMask = validBits_ == 64 ? 0xFFFFFFFFFFFFFFFFULL : ((1ULL << validBits_) - 1);
|
|
|
|
static const char * const indent[4] = { "", " ", " ", " " };
|
|
|
|
if (!scopes_.empty()) {
|
|
INFO_LOG(G3D, "Profiling events this frame:");
|
|
}
|
|
|
|
// Log it all out.
|
|
for (auto &scope : scopes_) {
|
|
if (scope.endQueryId == -1) {
|
|
WARN_LOG(G3D, "Unclosed scope: %s", scope.name);
|
|
continue;
|
|
}
|
|
uint64_t startTime = results[scope.startQueryId];
|
|
uint64_t endTime = results[scope.endQueryId];
|
|
|
|
uint64_t delta = (endTime - startTime) & timestampDiffMask;
|
|
|
|
double milliseconds = (double)delta * timestampConversionFactor;
|
|
|
|
INFO_LOG(G3D, "%s%s (%0.3f ms)", indent[scope.level & 3], scope.name, milliseconds);
|
|
}
|
|
|
|
scopes_.clear();
|
|
scopeStack_.clear();
|
|
}
|
|
|
|
// Only need to reset all on the first frame.
|
|
if (firstFrame_) {
|
|
numQueries_ = MAX_QUERY_COUNT;
|
|
firstFrame_ = false;
|
|
}
|
|
if (numQueries_ > 0) {
|
|
vkCmdResetQueryPool(firstCommandBuf, queryPool_, 0, numQueries_);
|
|
}
|
|
numQueries_ = 0;
|
|
}
|
|
|
|
void VulkanProfiler::Begin(VkCommandBuffer cmdBuf, VkPipelineStageFlagBits stageFlags, const char *fmt, ...) {
|
|
if (!validBits_ || (enabledPtr_ && !*enabledPtr_) || numQueries_ >= MAX_QUERY_COUNT - 1) {
|
|
return;
|
|
}
|
|
|
|
ProfilerScope scope;
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsnprintf(scope.name, sizeof(scope.name), fmt, args);
|
|
va_end(args);
|
|
scope.startQueryId = numQueries_;
|
|
scope.endQueryId = -1;
|
|
scope.level = (int)scopeStack_.size();
|
|
|
|
scopeStack_.push_back(scopes_.size());
|
|
scopes_.push_back(scope);
|
|
|
|
vkCmdWriteTimestamp(cmdBuf, stageFlags, queryPool_, numQueries_);
|
|
numQueries_++;
|
|
}
|
|
|
|
void VulkanProfiler::End(VkCommandBuffer cmdBuf, VkPipelineStageFlagBits stageFlags) {
|
|
if (!validBits_ || (enabledPtr_ && !*enabledPtr_) || numQueries_ >= MAX_QUERY_COUNT - 1) {
|
|
return;
|
|
}
|
|
|
|
size_t scopeId = scopeStack_.back();
|
|
scopeStack_.pop_back();
|
|
|
|
ProfilerScope &scope = scopes_[scopeId];
|
|
scope.endQueryId = numQueries_;
|
|
|
|
vkCmdWriteTimestamp(cmdBuf, stageFlags, queryPool_, numQueries_);
|
|
numQueries_++;
|
|
}
|