pub const MODEL_HISTORY: &str = "// Previous-frame model snapshot for the G-buffer pre-pass\'s motion vectors.\n// One thread per cull record: copies this frame\'s model matrix out of the\n// bindless object buffer into the frame\'s slot of the model-history ring, which\n// the NEXT frame\'s pre-pass reads as its previous-frame transform.\n//\n// The snapshot lives on the GPU because the object buffer already carries every\n// model the pre-pass needs: a host-built parallel table would write the same\n// 64 bytes per record a second time, once per backend.\n//\n// Records are indexed exactly as the object buffer indexes them (static prefix,\n// instances, runtime reserve, skinned tail), so a record\'s history entry is only\n// meaningful while that record keeps its occupant. A record whose occupant\n// changed carries `DRAW_NO_HISTORY` in its draw args and the pre-pass falls back\n// to the current model, which is what makes the copy unconditional here.\n//\n// Single source for every backend. Metal and DXIL assign the same slots from\n// declaration order (params 0, objects 1, history 2), matching the hand-assigned\n// host bindings on all three; Vulkan binds set 0 bindings 0-2.\n\n{OBJECT_COMMON}\n\n// Matches `ModelHistoryParams` in render/uniforms/geometry.rs (16 B).\nstruct ModelHistoryParams\n{\n uint record_count;\n uint _pad0;\n uint _pad1;\n uint _pad2;\n};\n\n[[vk::binding(0, 0)]]\nConstantBuffer<ModelHistoryParams> params;\n\n[[vk::binding(1, 0)]]\nStructuredBuffer<GpuObjectData> objects;\n\n[[vk::binding(2, 0)]]\nRWStructuredBuffer<float4x4> history;\n\n[shader(\"compute\")]\n[numthreads(64, 1, 1)]\nvoid model_history_kernel(uint3 tid : SV_DispatchThreadID)\n{\n uint i = tid.x;\n if (i >= params.record_count)\n {\n return;\n }\n history[i] = objects[i].model;\n}\n";Expand description
model_history.slang.