locum 0.1.6

Captures everything a Direct3D 11 game draws in a frame, to look at, query, change and replay: d3d11.dll and dxgi.dll beside the game that watch every call on its way to the real runtime.
Documentation
// A top-level build's instances given as an array of pointers, gathered on the GPU (locum::d3d12::gather). Shader
// model 5.0, for Direct3D 12.
//
// `records` reads the pointers locum copied right after the build (u0) and writes, for pointer `i`, a record of
// locum's command signature (u1): the pointer as a root SRV, `i` as the root constant, and a dispatch of one group, or
// of none for a null pointer. It also writes the pointers as read (u2) and clears each stamp (u3). ExecuteIndirect
// then runs `copy` once per record: the instance the pointer points at, 64 bytes, into place `i` of the instances
// (u0), and `i + 1` into stamp `i` (u3), which says the record ran.

// The root signature of both: the instance a pointer points at, the constant (`count` for `records`, `i` for
// `copy`), and four buffers. A command signature sets root parameters in increasing order: the SRV, then the constant.
#define ROOT "SRV(t0), RootConstants(num32BitConstants = 1, b0), UAV(u0), UAV(u1), UAV(u2), UAV(u3)"

cbuffer Gather : register(b0)
{
    uint k;
};

ByteAddressBuffer instance : register(t0);
RWByteAddressBuffer first : register(u0);
RWByteAddressBuffer records_out : register(u1);
RWByteAddressBuffer pointers_out : register(u2);
RWByteAddressBuffer stamps : register(u3);

// The bytes of one record: the root SRV's address, the constant, and the dispatch's three group counts.
#define RECORD 24

[numthreads(64, 1, 1)]
void records(uint3 id : SV_DispatchThreadID)
{
    uint i = id.x;
    if (i >= k)
    {
        return;
    }
    uint2 p = first.Load2(i * 8);
    pointers_out.Store2(i * 8, p);
    stamps.Store(i * 4, 0);
    records_out.Store2(i * RECORD, p);
    records_out.Store(i * RECORD + 8, i);
    records_out.Store3(i * RECORD + 12, uint3((p.x | p.y) != 0 ? 1 : 0, 1, 1));
}

[numthreads(16, 1, 1)]
void copy(uint3 t : SV_GroupThreadID)
{
    first.Store(k * 64 + t.x * 4, instance.Load(t.x * 4));
    if (t.x == 0)
    {
        stamps.Store(k * 4, k + 1);
    }
}