Files
NX2navi/runtime/vk_rec.h
chrg6 a8c6e992ee Draw task and mesh programs through compute passes when the mesh fallback is on.
A mesh draw becomes its record (the workgroup count, copied on the GPU for an indirect draw), the task dispatch, a
scan that lists the mesh workgroups the tasks started, the mesh dispatch, and an instanced indirect draw with a
generated vertex stage and the program's fragment stage. The compute modules bind the resources of the task and mesh
stages, and their pipelines are made on a thread of their own while the program's draws are skipped.

The indirect mesh ring and the texture pool marks are released at a probe's shutdown.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 05:58:42 -05:00

170 lines
15 KiB
C

// The recorder thread (vk_rec.c): the Vulkan calls the replay makes into its command buffer are made by a thread of
// their own. vk_sync.c brackets each part of a submission with rec_begin (after vkBeginCommandBuffer) and rec_end
// (before vkEndCommandBuffer). In between, every vkCmd* on that command buffer copies its arguments into a packet of a
// ring, in call order, and the recorder makes the real call in that order; calls into any other command buffer (uploads,
// the window, probes) are made at once. A call the ring has no packet for (a structure with a pNext chain) waits for
// the recorder to empty the ring and is then made at once on the calling thread. rec_end returns once the recorder made
// every call. vk_sync.c ends a part through rec_end_cb: the recorder makes the last calls into a part it recorded,
// vkEndCommandBuffer included; submitting and the command pool stay on the submitting thread.
//
// Every vkCmd* the runtime calls through vk.h goes through the rc_* wrappers below (the macros at the end); the
// extension commands called through function pointers have rec_* wrappers of their own. NX2NAVI_VK_RECORDER=0 makes every
// call at once (the same calls in the same order), =ab switches it with the A/B blocks (rt_ab), per submission part.
//
// A recorder thread makes the Vulkan calls: the driver's work behind the commands depends on nothing the replay decides next.
#pragma once
void rec_begin(VkCommandBuffer cb, uint64_t fence); // the submitting thread, sub_lock held; fence: the part's value
void rec_end(void); // waits for the recorder; no-op when rec_begin did not start it
// The end of part cb: the breadcrumb crumb (0: none, vk_crumbs.c), then vkEndCommandBuffer, both made by the recorder
// when it records cb, and the wait for it (1); otherwise rec_end and the breadcrumb, and the caller ends cb (0).
int rec_end_cb(VkCommandBuffer cb, int crumb, uint64_t n);
void rec_drain(void); // waits until the recorder made every call queued so far
void rec_wait_totals(uint64_t *full_ns, uint64_t *drain_ns); // producer time spent on a full ring and in drains
void rec_stats_log(void); // NX2NAVI_TRACE=perf: packets, bytes, drains and waits since the last call
// NX2NAVI_REC_CHECK=1 (debug, recorder on): vk_memory.c reports each object it defers (destroy 0, stamped tl) or destroys
// (destroy 1) with the value the GPU reached (gpu); a packet of the part being recorded that still names it is logged
// as a hazard when the object can go before the part ran. rec_check_log: the counts by kind and packet, at exit.
enum { REC_IMAGE, REC_VIEW, REC_BUFFER, REC_KINDS };
void rec_check_handle(int kind, uint64_t handle, int destroy, uint64_t tl, uint64_t gpu);
void rec_check_log(void);
// Extension commands called through device function pointers.
void rec_push_tpl(PFN_vkCmdPushDescriptorSetWithTemplateKHR fn, VkCommandBuffer cb, VkDescriptorUpdateTemplate tpl,
VkPipelineLayout layout, uint32_t set, const void *data, uint32_t bytes); // data: bytes read by tpl
void rec_push(PFN_vkCmdPushDescriptorSetKHR fn, VkCommandBuffer cb, VkPipelineBindPoint bp, VkPipelineLayout layout,
uint32_t set, uint32_t n, const VkWriteDescriptorSet *w);
void rec_vertex_input(PFN_vkCmdSetVertexInputEXT fn, VkCommandBuffer cb, uint32_t nb,
const VkVertexInputBindingDescription2EXT *b, uint32_t na,
const VkVertexInputAttributeDescription2EXT *a);
void rec_bool(PFN_vkCmdSetDepthClampEnableEXT fn, VkCommandBuffer cb, VkBool32 v); // also alpha to coverage
void rec_polygon_mode(PFN_vkCmdSetPolygonModeEXT fn, VkCommandBuffer cb, VkPolygonMode m);
void rec_blend_enable(PFN_vkCmdSetColorBlendEnableEXT fn, VkCommandBuffer cb, uint32_t first, uint32_t n, const VkBool32 *v);
void rec_blend_equation(PFN_vkCmdSetColorBlendEquationEXT fn, VkCommandBuffer cb, uint32_t first, uint32_t n,
const VkColorBlendEquationEXT *v);
void rec_write_mask(PFN_vkCmdSetColorWriteMaskEXT fn, VkCommandBuffer cb, uint32_t first, uint32_t n,
const VkColorComponentFlags *v);
void rec_draw_mesh(PFN_vkCmdDrawMeshTasksEXT fn, VkCommandBuffer cb, uint32_t x, uint32_t y, uint32_t z);
void rec_shading_rate(PFN_vkCmdSetFragmentShadingRateKHR fn, VkCommandBuffer cb, uint32_t size); // size x size pixels per fragment
void rec_draw_mesh_ind(PFN_vkCmdDrawMeshTasksIndirectEXT fn, VkCommandBuffer cb, VkBuffer b, VkDeviceSize o, uint32_t n,
uint32_t stride);
// A pass mark (vk_crumbs.c vk_pass_mark_cmd: a buffer marker and a checkpoint), in order with the commands around it.
void rec_pass_mark(VkCommandBuffer cb, uint32_t id, int end);
#define REC_CMDS(X) \
X(BeginQuery, (VkCommandBuffer cb, VkQueryPool p, uint32_t q, VkQueryControlFlags f), (cb, p, q, f)) \
X(BeginRendering, (VkCommandBuffer cb, const VkRenderingInfo *ri), (cb, ri)) \
X(BindDescriptorSets, (VkCommandBuffer cb, VkPipelineBindPoint bp, VkPipelineLayout l, uint32_t first, uint32_t n, \
const VkDescriptorSet *s, uint32_t nd, const uint32_t *d), (cb, bp, l, first, n, s, nd, d)) \
X(BindIndexBuffer, (VkCommandBuffer cb, VkBuffer b, VkDeviceSize o, VkIndexType t), (cb, b, o, t)) \
X(BindPipeline, (VkCommandBuffer cb, VkPipelineBindPoint bp, VkPipeline p), (cb, bp, p)) \
X(BindVertexBuffers2, (VkCommandBuffer cb, uint32_t first, uint32_t n, const VkBuffer *b, const VkDeviceSize *o, \
const VkDeviceSize *sz, const VkDeviceSize *st), (cb, first, n, b, o, sz, st)) \
X(BlitImage, (VkCommandBuffer cb, VkImage s, VkImageLayout sl, VkImage d, VkImageLayout dl, uint32_t n, \
const VkImageBlit *r, VkFilter f), (cb, s, sl, d, dl, n, r, f)) \
X(ClearAttachments, (VkCommandBuffer cb, uint32_t na, const VkClearAttachment *a, uint32_t nr, const VkClearRect *r), \
(cb, na, a, nr, r)) \
X(ClearColorImage, (VkCommandBuffer cb, VkImage i, VkImageLayout l, const VkClearColorValue *c, uint32_t n, \
const VkImageSubresourceRange *r), (cb, i, l, c, n, r)) \
X(ClearDepthStencilImage, (VkCommandBuffer cb, VkImage i, VkImageLayout l, const VkClearDepthStencilValue *c, \
uint32_t n, const VkImageSubresourceRange *r), (cb, i, l, c, n, r)) \
X(CopyBuffer, (VkCommandBuffer cb, VkBuffer s, VkBuffer d, uint32_t n, const VkBufferCopy *r), (cb, s, d, n, r)) \
X(CopyBufferToImage, (VkCommandBuffer cb, VkBuffer s, VkImage d, VkImageLayout dl, uint32_t n, \
const VkBufferImageCopy *r), (cb, s, d, dl, n, r)) \
X(CopyImage, (VkCommandBuffer cb, VkImage s, VkImageLayout sl, VkImage d, VkImageLayout dl, uint32_t n, \
const VkImageCopy *r), (cb, s, sl, d, dl, n, r)) \
X(CopyImageToBuffer, (VkCommandBuffer cb, VkImage s, VkImageLayout sl, VkBuffer d, uint32_t n, \
const VkBufferImageCopy *r), (cb, s, sl, d, n, r)) \
X(Dispatch, (VkCommandBuffer cb, uint32_t x, uint32_t y, uint32_t z), (cb, x, y, z)) \
X(DispatchIndirect, (VkCommandBuffer cb, VkBuffer b, VkDeviceSize o), (cb, b, o)) \
X(Draw, (VkCommandBuffer cb, uint32_t n, uint32_t i, uint32_t f, uint32_t fi), (cb, n, i, f, fi)) \
X(DrawIndexed, (VkCommandBuffer cb, uint32_t n, uint32_t i, uint32_t f, int32_t v, uint32_t fi), (cb, n, i, f, v, fi)) \
X(DrawIndexedIndirect, (VkCommandBuffer cb, VkBuffer b, VkDeviceSize o, uint32_t n, uint32_t s), (cb, b, o, n, s)) \
X(DrawIndirect, (VkCommandBuffer cb, VkBuffer b, VkDeviceSize o, uint32_t n, uint32_t s), (cb, b, o, n, s)) \
X(EndQuery, (VkCommandBuffer cb, VkQueryPool p, uint32_t q), (cb, p, q)) \
X(EndRendering, (VkCommandBuffer cb), (cb)) \
X(FillBuffer, (VkCommandBuffer cb, VkBuffer b, VkDeviceSize o, VkDeviceSize n, uint32_t v), (cb, b, o, n, v)) \
X(PipelineBarrier2, (VkCommandBuffer cb, const VkDependencyInfo *di), (cb, di)) \
X(ExecuteCommands, (VkCommandBuffer cb, uint32_t n, const VkCommandBuffer *c), (cb, n, c)) \
X(PushConstants, (VkCommandBuffer cb, VkPipelineLayout l, VkShaderStageFlags st, uint32_t o, uint32_t n, \
const void *v), (cb, l, st, o, n, v)) \
X(ResetQueryPool, (VkCommandBuffer cb, VkQueryPool p, uint32_t f, uint32_t n), (cb, p, f, n)) \
X(ResolveImage, (VkCommandBuffer cb, VkImage s, VkImageLayout sl, VkImage d, VkImageLayout dl, uint32_t n, \
const VkImageResolve *r), (cb, s, sl, d, dl, n, r)) \
X(SetBlendConstants, (VkCommandBuffer cb, const float c[4]), (cb, c)) \
X(SetCullMode, (VkCommandBuffer cb, VkCullModeFlags m), (cb, m)) \
X(SetDepthBias, (VkCommandBuffer cb, float c, float cl, float s), (cb, c, cl, s)) \
X(SetDepthBiasEnable, (VkCommandBuffer cb, VkBool32 v), (cb, v)) \
X(SetDepthCompareOp, (VkCommandBuffer cb, VkCompareOp v), (cb, v)) \
X(SetDepthTestEnable, (VkCommandBuffer cb, VkBool32 v), (cb, v)) \
X(SetDepthWriteEnable, (VkCommandBuffer cb, VkBool32 v), (cb, v)) \
X(SetFrontFace, (VkCommandBuffer cb, VkFrontFace v), (cb, v)) \
X(SetPrimitiveRestartEnable, (VkCommandBuffer cb, VkBool32 v), (cb, v)) \
X(SetPrimitiveTopology, (VkCommandBuffer cb, VkPrimitiveTopology v), (cb, v)) \
X(SetRasterizerDiscardEnable, (VkCommandBuffer cb, VkBool32 v), (cb, v)) \
X(SetScissorWithCount, (VkCommandBuffer cb, uint32_t n, const VkRect2D *r), (cb, n, r)) \
X(SetStencilCompareMask, (VkCommandBuffer cb, VkStencilFaceFlags f, uint32_t v), (cb, f, v)) \
X(SetStencilOp, (VkCommandBuffer cb, VkStencilFaceFlags f, VkStencilOp a, VkStencilOp b, VkStencilOp c, \
VkCompareOp d), (cb, f, a, b, c, d)) \
X(SetStencilReference, (VkCommandBuffer cb, VkStencilFaceFlags f, uint32_t v), (cb, f, v)) \
X(SetStencilTestEnable, (VkCommandBuffer cb, VkBool32 v), (cb, v)) \
X(SetStencilWriteMask, (VkCommandBuffer cb, VkStencilFaceFlags f, uint32_t v), (cb, f, v)) \
X(SetViewportWithCount, (VkCommandBuffer cb, uint32_t n, const VkViewport *v), (cb, n, v)) \
X(WriteTimestamp, (VkCommandBuffer cb, VkPipelineStageFlagBits s, VkQueryPool p, uint32_t q), (cb, s, p, q)) \
X(WriteTimestamp2, (VkCommandBuffer cb, VkPipelineStageFlags2 s, VkQueryPool p, uint32_t q), (cb, s, p, q))
#define REC_DECL(name, params, args) void rc_vkCmd##name params;
REC_CMDS(REC_DECL)
#undef REC_DECL
#ifndef VK_REC_IMPL
#define vkCmdBeginQuery rc_vkCmdBeginQuery
#define vkCmdBeginRendering rc_vkCmdBeginRendering
#define vkCmdBindDescriptorSets rc_vkCmdBindDescriptorSets
#define vkCmdBindIndexBuffer rc_vkCmdBindIndexBuffer
#define vkCmdBindPipeline rc_vkCmdBindPipeline
#define vkCmdBindVertexBuffers2 rc_vkCmdBindVertexBuffers2
#define vkCmdBlitImage rc_vkCmdBlitImage
#define vkCmdExecuteCommands rc_vkCmdExecuteCommands
#define vkCmdClearAttachments rc_vkCmdClearAttachments
#define vkCmdClearColorImage rc_vkCmdClearColorImage
#define vkCmdClearDepthStencilImage rc_vkCmdClearDepthStencilImage
#define vkCmdCopyBuffer rc_vkCmdCopyBuffer
#define vkCmdCopyBufferToImage rc_vkCmdCopyBufferToImage
#define vkCmdCopyImage rc_vkCmdCopyImage
#define vkCmdCopyImageToBuffer rc_vkCmdCopyImageToBuffer
#define vkCmdDispatch rc_vkCmdDispatch
#define vkCmdDispatchIndirect rc_vkCmdDispatchIndirect
#define vkCmdDraw rc_vkCmdDraw
#define vkCmdDrawIndexed rc_vkCmdDrawIndexed
#define vkCmdDrawIndexedIndirect rc_vkCmdDrawIndexedIndirect
#define vkCmdDrawIndirect rc_vkCmdDrawIndirect
#define vkCmdEndQuery rc_vkCmdEndQuery
#define vkCmdEndRendering rc_vkCmdEndRendering
#define vkCmdFillBuffer rc_vkCmdFillBuffer
#define vkCmdPipelineBarrier2 rc_vkCmdPipelineBarrier2
#define vkCmdPushConstants rc_vkCmdPushConstants
#define vkCmdResetQueryPool rc_vkCmdResetQueryPool
#define vkCmdResolveImage rc_vkCmdResolveImage
#define vkCmdSetBlendConstants rc_vkCmdSetBlendConstants
#define vkCmdSetCullMode rc_vkCmdSetCullMode
#define vkCmdSetDepthBias rc_vkCmdSetDepthBias
#define vkCmdSetDepthBiasEnable rc_vkCmdSetDepthBiasEnable
#define vkCmdSetDepthCompareOp rc_vkCmdSetDepthCompareOp
#define vkCmdSetDepthTestEnable rc_vkCmdSetDepthTestEnable
#define vkCmdSetDepthWriteEnable rc_vkCmdSetDepthWriteEnable
#define vkCmdSetFrontFace rc_vkCmdSetFrontFace
#define vkCmdSetPrimitiveRestartEnable rc_vkCmdSetPrimitiveRestartEnable
#define vkCmdSetPrimitiveTopology rc_vkCmdSetPrimitiveTopology
#define vkCmdSetRasterizerDiscardEnable rc_vkCmdSetRasterizerDiscardEnable
#define vkCmdSetScissorWithCount rc_vkCmdSetScissorWithCount
#define vkCmdSetStencilCompareMask rc_vkCmdSetStencilCompareMask
#define vkCmdSetStencilOp rc_vkCmdSetStencilOp
#define vkCmdSetStencilReference rc_vkCmdSetStencilReference
#define vkCmdSetStencilTestEnable rc_vkCmdSetStencilTestEnable
#define vkCmdSetStencilWriteMask rc_vkCmdSetStencilWriteMask
#define vkCmdSetViewportWithCount rc_vkCmdSetViewportWithCount
#define vkCmdWriteTimestamp rc_vkCmdWriteTimestamp
#define vkCmdWriteTimestamp2 rc_vkCmdWriteTimestamp2
#endif