perf(agc): resolve the recorder's query and fold entry points once
Every occlusion counter dump the recorder handles on the GPU ends the batch's occlusion query, copies the pending results, folds them with a compute dispatch, then resets and begins a new query. Each of those commands was resolved through vkGetDeviceProcAddr, a loader name lookup, on every call: seven lookups per dump on the graphics worker, and a title dumps the counter twice per occlusion query. The mesh argument and timing paths resolved their bind, push, dispatch and reset per call too. They join the entry points the recorder already resolves in its constructor: vkCmdBeginQuery, vkCmdEndQuery, vkCmdResetQueryPool, vkCmdCopyQueryPoolResults, vkCmdBindPipeline, vkCmdPushConstants and vkCmdDispatch. The same functions are called with the same arguments; APS5_NO_PROC_TABLE=1 still resolves every call.
This commit is contained in:
parent
b0c2e05ba0
commit
2b388e0b0e
|
|
@ -641,6 +641,13 @@ private:
|
|||
PFN_vkEndCommandBuffer endCommandBuffer = nullptr;
|
||||
PFN_vkQueueSubmit queueSubmit = nullptr;
|
||||
PFN_vkCmdPipelineBarrier cmdPipelineBarrier = nullptr;
|
||||
PFN_vkCmdBeginQuery cmdBeginQuery = nullptr;
|
||||
PFN_vkCmdEndQuery cmdEndQuery = nullptr;
|
||||
PFN_vkCmdResetQueryPool cmdResetQueryPool = nullptr;
|
||||
PFN_vkCmdCopyQueryPoolResults cmdCopyQueryPoolResults = nullptr;
|
||||
PFN_vkCmdBindPipeline cmdBindPipeline = nullptr;
|
||||
PFN_vkCmdPushConstants cmdPushConstants = nullptr;
|
||||
PFN_vkCmdDispatch cmdDispatch = nullptr;
|
||||
template<typename TFunction>
|
||||
TFunction function(TFunction resolved, const char* name) const {
|
||||
return resolved != nullptr ? resolved : context.Function<TFunction>(name);
|
||||
|
|
|
|||
|
|
@ -1074,6 +1074,13 @@ Recorder::Recorder(const Context& context, bool timelineSemaphores) : context(co
|
|||
endCommandBuffer = context.Function<PFN_vkEndCommandBuffer>("vkEndCommandBuffer");
|
||||
queueSubmit = context.Function<PFN_vkQueueSubmit>("vkQueueSubmit");
|
||||
cmdPipelineBarrier = context.Function<PFN_vkCmdPipelineBarrier>("vkCmdPipelineBarrier");
|
||||
cmdBeginQuery = context.Function<PFN_vkCmdBeginQuery>("vkCmdBeginQuery");
|
||||
cmdEndQuery = context.Function<PFN_vkCmdEndQuery>("vkCmdEndQuery");
|
||||
cmdResetQueryPool = context.Function<PFN_vkCmdResetQueryPool>("vkCmdResetQueryPool");
|
||||
cmdCopyQueryPoolResults = context.Function<PFN_vkCmdCopyQueryPoolResults>("vkCmdCopyQueryPoolResults");
|
||||
cmdBindPipeline = context.Function<PFN_vkCmdBindPipeline>("vkCmdBindPipeline");
|
||||
cmdPushConstants = context.Function<PFN_vkCmdPushConstants>("vkCmdPushConstants");
|
||||
cmdDispatch = context.Function<PFN_vkCmdDispatch>("vkCmdDispatch");
|
||||
}
|
||||
if (!timelineSemaphores) return;
|
||||
// The timeline starts at 0 and every Submit signals its serial (1, 2, ...): a value that only
|
||||
|
|
@ -1837,7 +1844,7 @@ std::uint32_t Recorder::beginTiming(std::uint64_t key) {
|
|||
return NoTiming;
|
||||
}
|
||||
}
|
||||
context.Function<PFN_vkCmdResetQueryPool>("vkCmdResetQueryPool")(commands, open->queries, 0, queryCount);
|
||||
function(cmdResetQueryPool, "vkCmdResetQueryPool")(commands, open->queries, 0, queryCount);
|
||||
}
|
||||
if (open->timedKeys.size() >= queryCount / 2) {
|
||||
timingDropped.fetch_add(1, std::memory_order_relaxed);
|
||||
|
|
@ -1926,7 +1933,7 @@ bool Recorder::gpuSampleCounter() {
|
|||
|
||||
void Recorder::endSamples(Batch& batch) {
|
||||
if (!batch.sampleActive) return;
|
||||
context.Function<PFN_vkCmdEndQuery>("vkCmdEndQuery")(batch.commands, batch.samples, 0);
|
||||
function(cmdEndQuery, "vkCmdEndQuery")(batch.commands, batch.samples, 0);
|
||||
batch.sampleActive = false;
|
||||
if (sampleCounterState > 0 && batch.samplesDrawn) pendingSamples.push_back({batch.samplePool, batch.samples});
|
||||
batch.samplesDrawn = false;
|
||||
|
|
@ -1934,10 +1941,10 @@ void Recorder::endSamples(Batch& batch) {
|
|||
|
||||
void Recorder::foldSamples(Batch& batch, VkDeviceAddress target) {
|
||||
const auto commands = batch.commands;
|
||||
const auto copy = context.Function<PFN_vkCmdCopyQueryPoolResults>("vkCmdCopyQueryPoolResults");
|
||||
const auto bind = context.Function<PFN_vkCmdBindPipeline>("vkCmdBindPipeline");
|
||||
const auto push = context.Function<PFN_vkCmdPushConstants>("vkCmdPushConstants");
|
||||
const auto dispatch = context.Function<PFN_vkCmdDispatch>("vkCmdDispatch");
|
||||
const auto copy = function(cmdCopyQueryPoolResults, "vkCmdCopyQueryPoolResults");
|
||||
const auto bind = function(cmdBindPipeline, "vkCmdBindPipeline");
|
||||
const auto push = function(cmdPushConstants, "vkCmdPushConstants");
|
||||
const auto dispatch = function(cmdDispatch, "vkCmdDispatch");
|
||||
std::size_t done = 0;
|
||||
do {
|
||||
const auto count = static_cast<std::uint32_t>(std::min<std::size_t>(SampleFoldCapacity, pendingSamples.size() - done));
|
||||
|
|
@ -2011,15 +2018,15 @@ bool Recorder::RecordMeshArguments(VkCommandBuffer commands, VkDeviceAddress rec
|
|||
}
|
||||
if (meshArgumentState < 0) return false;
|
||||
recordBarrier(commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
context.Function<PFN_vkCmdBindPipeline>("vkCmdBindPipeline")(commands, VK_PIPELINE_BIND_POINT_COMPUTE, meshArgumentPipeline);
|
||||
function(cmdBindPipeline, "vkCmdBindPipeline")(commands, VK_PIPELINE_BIND_POINT_COMPUTE, meshArgumentPipeline);
|
||||
struct {
|
||||
VkDeviceAddress record;
|
||||
VkDeviceAddress arguments;
|
||||
std::array<std::uint32_t, 8> rules;
|
||||
} parameters{record, arguments, {rules[0], rules[1], rules[2], rules[3], rules[4], rules[5], rules[6], 0u}};
|
||||
static_assert(sizeof(parameters) == PushBytes);
|
||||
context.Function<PFN_vkCmdPushConstants>("vkCmdPushConstants")(commands, meshArgumentLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, PushBytes, ¶meters);
|
||||
context.Function<PFN_vkCmdDispatch>("vkCmdDispatch")(commands, 1, 1, 1);
|
||||
function(cmdPushConstants, "vkCmdPushConstants")(commands, meshArgumentLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, PushBytes, ¶meters);
|
||||
function(cmdDispatch, "vkCmdDispatch")(commands, 1, 1, 1);
|
||||
recordBarrier(commands, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
CountBarriers(CommandClass::Draw, 2);
|
||||
return true;
|
||||
|
|
@ -2049,8 +2056,8 @@ void Recorder::beginSamples(Batch& batch) {
|
|||
throw;
|
||||
}
|
||||
}
|
||||
context.Function<PFN_vkCmdResetQueryPool>("vkCmdResetQueryPool")(batch.commands, batch.samples, 0, 1);
|
||||
context.Function<PFN_vkCmdBeginQuery>("vkCmdBeginQuery")(batch.commands, batch.samples, 0, context.occlusionQueryPrecise ? VK_QUERY_CONTROL_PRECISE_BIT : 0u);
|
||||
function(cmdResetQueryPool, "vkCmdResetQueryPool")(batch.commands, batch.samples, 0, 1);
|
||||
function(cmdBeginQuery, "vkCmdBeginQuery")(batch.commands, batch.samples, 0, context.occlusionQueryPrecise ? VK_QUERY_CONTROL_PRECISE_BIT : 0u);
|
||||
batch.sampleActive = true;
|
||||
batch.samplesDrawn = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue