Cache D3D12 recording lookups without retaining game resources

This commit is contained in:
Codex committed 2026-10-01 20:23:08 +03:00
1 parent 73ee2e5ecc
commit 74aad12938
10 files changed
+267 -12

No files matched your search

+2
View File
@@ -53,6 +53,8 @@ command-list split/replay, submitted state publication and suffix completion.
The recording interval measures NGX calls on the recording thread, not Present. The recording interval measures NGX calls on the recording thread, not Present.
`-ProfileKernels` enables synchronizing HIP-event kernel profiling and changes `-ProfileKernels` enables synchronizing HIP-event kernel profiling and changes
frame scheduling; use it separately from a production FPS measurement. frame scheduling; use it separately from a production FPS measurement.
`-ProfileCommandHooks` samples one in 64 D3D12 interceptions to distinguish
tracking/lock waits from driver calls. It is disabled in ordinary runs.
The runner drains stdout/stderr concurrently as raw bytes; the earlier The runner drains stdout/stderr concurrently as raw bytes; the earlier
line-oriented PowerShell collector imposed large per-frame delays. The optional line-oriented PowerShell collector imposed large per-frame delays. The optional
ZLUDA kernel profiler is for diagnostics only. Measurements and reproduction ZLUDA kernel profiler is for diagnostics only. Measurements and reproduction
+34
View File
@@ -138,5 +138,39 @@ The installer accepts them with `-LocalTextureKernels` only after validation,
checking the exact DLL identity, object and manifest hashes. M retains its checking the exact DLL identity, object and manifest hashes. M retains its
independently validated FP16-equivalent baseline. independently validated FP16-equivalent baseline.
The following no-debugger K/4K run completes 9982 frames and 9982 finite GPU
scans. Kernel event profiling is disabled; the validated private output tail
executes natively. The user reports 43-47 FPS. Mean NGX recording interval is
21.867 ms. No backend failure, CPU image copy or previous-frame output occurs.
Random one-in-64 hook samples then identify contention in the shared routing
table used by every intercepted D3D12 command. Per-thread weak lookup caches
now bypass that table on repeated calls to a list. Table mutations invalidate
cache generations; Reset/address reuse cannot route to a previous suffix, and
thread caches do not retain game resources. The per-list and submission locks
remain. A GPU regression resets and re-splits the exact same list with changed
root constants twice per iteration, checking both prefix and suffix results.
| Sampled command-hook access | Shared table | Per-thread weak cache |
| --- | ---: | ---: |
| Busiest recording thread, mean us/call | 0.203 | 0.066 |
| Estimated access + capture across threads, ms/s | 977.528 | 233.606 |
The latter estimate includes lock waits summed across concurrently running
threads, not CPU execution time or serial frame latency. The two game runs
have different thread populations (31 versus 29); there is no identical frame
trace. Generated forwarding methods have separate driver/capture markers;
special-case hooks contribute access samples but lack those body markers.
With the cache, 4770 complete K/4K frames and finite GPU scans pass, with zero
backend failures, CPU image copies or previous-frame output. Median NGX
recording interval is 19.473 ms. The user reports 49-51 FPS and 53% GPU usage
in the previously measured scene. These user readings are separate from the
sampled hook estimates and do not establish isolated WMMA utilization.
All sixteen CTest gates pass, including 64 same-object Reset/split checks in
each physical command-backend test and the software indirect-root regression.
Use `-ProfileCommandHooks -ProfileStages` to collect samples; the sampler is
disabled for ordinary play.
References: [HIP events](https://rocmdocs.amd.com/projects/HIP/en/develop/doxygen/html/group___event.html), References: [HIP events](https://rocmdocs.amd.com/projects/HIP/en/develop/doxygen/html/group___event.html),
[HIP occupancy API](https://rocm.docs.amd.com/projects/HIP/en/latest/doxygen/html/group___occupancy.html). [HIP occupancy API](https://rocm.docs.amd.com/projects/HIP/en/latest/doxygen/html/group___occupancy.html).
+21
View File
@@ -54,6 +54,27 @@ public ZIPs exclude these objects. Install/restore with private overrides
restores sentinel DLL/config byte-exactly, without duplicate slash/backslash restores sentinel DLL/config byte-exactly, without duplicate slash/backslash
manifest paths. manifest paths.
Production K/4K with private output stores completes 9982 frames and 9982
finite GPU scans; the user reports 43-47 FPS. Random per-hook CPU sampling
then localizes contention to the shared command-list routing map. A per-thread
weak lookup cache bypasses that mutex for repeated calls, invalidating on map
mutations to preserve Reset/final Release/address reuse. Queue and per-list
synchronization remain. The regression resets/re-splits the same object twice
per iteration with different root constants and verifies both GPU outputs.
All sixteen CTest gates pass. The cached game run completes 4770 K/4K frames
and 4770 finite GPU scans, zero failures/CPU image copies/aged outputs. The user
reports 49-51 FPS and 53% GPU usage. Aggregated sampled access/capture time
falls from 977.528 to 233.606 ms/s across threads; it includes parallel lock
waits and must not be treated as serial frame time. Median recording interval
is 19.473 ms. `-ProfileCommandHooks` is optional and off during ordinary play.
Detailed scope and timings are in [windows-performance.md](windows-performance.md).
Post-cache full-pipeline checks also pass: three K/4K HDR frames and four M
512x288 frames match their previously validated controls with max absolute and
relative RGB error 0, all RGBA finite. Public archive validation checks all 63
entries and their SHA256 against package.json; NVIDIA DLLs and private texture
objects are absent. `package-windows-game.ps1 -ArchivePath <zip>` archives only
the staged manifest, including on Windows PowerShell 5.1.
Performance diagnostics (2026-10-01): the separate ZLUDA `b0161a4` runtime Performance diagnostics (2026-10-01): the separate ZLUDA `b0161a4` runtime
passes 32 PTX launches in each context and all four native K/M frames with passes 32 PTX launches in each context and all four native K/M frames with
bit-exact RGB against their controls. All thirteen exported patches (0002 bit-exact RGB against their controls. All thirteen exported patches (0002
+20 -1
View File
@@ -1,7 +1,8 @@
[CmdletBinding()] [CmdletBinding()]
param( param(
[string]$PackageRoot, [string]$DiagnosticRoot, [string]$OptiScalerRoot, [string]$PackageRoot, [string]$DiagnosticRoot, [string]$OptiScalerRoot,
[string]$ZludaRoot, [string]$HipRoot, [string]$KernelKRoot, [string]$KernelMRoot [string]$ZludaRoot, [string]$HipRoot, [string]$KernelKRoot, [string]$KernelMRoot,
[string]$ArchivePath
) )
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..')) $repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
@@ -76,3 +77,21 @@ if (Get-ChildItem -LiteralPath $PackageRoot -Recurse -File | Where-Object { $_.N
throw 'Proprietary NVIDIA binaries must not be in the package.' throw 'Proprietary NVIDIA binaries must not be in the package.'
} }
Write-Host "Windows game development package: $PackageRoot (NVIDIA DLLs excluded)" Write-Host "Windows game development package: $PackageRoot (NVIDIA DLLs excluded)"
if ($ArchivePath) {
$ArchivePath=[IO.Path]::GetFullPath($ArchivePath)
if ($ArchivePath.StartsWith($PackageRoot+'\',[StringComparison]::OrdinalIgnoreCase)) { throw 'Place the ZIP outside the package directory.' }
Add-Type -AssemblyName System.IO.Compression,System.IO.Compression.FileSystem
New-Item -ItemType Directory -Force (Split-Path $ArchivePath) | Out-Null
$stream=[IO.File]::Open($ArchivePath,[IO.FileMode]::Create,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None)
$archive=$null
try {
$archive=[IO.Compression.ZipArchive]::new($stream,[IO.Compression.ZipArchiveMode]::Create)
# Never archive caches, results, private texture outputs or a local DLL
# merely because it happens to be somewhere under PackageRoot.
foreach ($relative in @($stagedFiles)+@('package.json')) {
[void][IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive,
(Join-Path $PackageRoot $relative),$relative.Replace('\','/'),[IO.Compression.CompressionLevel]::Optimal)
}
} finally { if ($archive) { $archive.Dispose() }; $stream.Dispose() }
Write-Host "Public package archive: $ArchivePath"
}
+3 -1
View File
@@ -11,6 +11,7 @@ param(
[switch]$ValidateOutput, [switch]$ValidateOutput,
[switch]$ProfileStages, [switch]$ProfileStages,
[switch]$ProfileKernels, [switch]$ProfileKernels,
[switch]$ProfileCommandHooks,
[switch]$VerboseRuntime, [switch]$VerboseRuntime,
[switch]$CaptureExceptions, [switch]$CaptureExceptions,
[string[]]$GameArguments = @('-dx12'), [string[]]$GameArguments = @('-dx12'),
@@ -176,6 +177,7 @@ $settings = @{
D4R_VALIDATE_OUTPUT=$(if ($ValidateOutput) { '1' } else { $null }); D4R_VALIDATE_OUTPUT=$(if ($ValidateOutput) { '1' } else { $null });
D4R_PROFILE_STAGES=$(if ($ProfileStages) { '1' } else { $null }); D4R_PROFILE_STAGES=$(if ($ProfileStages) { '1' } else { $null });
D4R_ZLUDA_PROFILE=$(if ($ProfileKernels) { '1' } else { $null }); D4R_ZLUDA_PROFILE=$(if ($ProfileKernels) { '1' } else { $null });
D4R_PROFILE_COMMAND_HOOKS=$(if ($ProfileCommandHooks) { '1' } else { $null });
D4R_DIAG_DIR=$OutputDirectory; ZLUDA_LOG_DIR=(Join-Path $OutputDirectory 'zluda-trace'); D4R_DIAG_DIR=$OutputDirectory; ZLUDA_LOG_DIR=(Join-Path $OutputDirectory 'zluda-trace');
ZLUDA_CACHE_DIR=$CacheDirectory; PATH=((GamePath 'd4r/hip/bin') + ';' + (GamePath 'd4r/zluda') + ';' + $env:PATH) ZLUDA_CACHE_DIR=$CacheDirectory; PATH=((GamePath 'd4r/hip/bin') + ';' + (GamePath 'd4r/zluda') + ';' + $env:PATH)
} }
@@ -258,7 +260,7 @@ try {
outputGpuChecks=$checks.Count; nonfiniteOutputs=$nonfinite; kernels=$kernels; outputGpuChecks=$checks.Count; nonfiniteOutputs=$nonfinite; kernels=$kernels;
previousFrameOutputs=@($frames | Where-Object { $_.Groups[2].Value -ne '0' }).Count; previousFrameOutputs=@($frames | Where-Object { $_.Groups[2].Value -ne '0' }).Count;
cpuImageCopyFrames=@($frames | Where-Object { $_.Groups[1].Value -ne '0' }).Count; cpuImageCopyFrames=@($frames | Where-Object { $_.Groups[1].Value -ne '0' }).Count;
failures=([regex]::Matches($stderr, 'D4R_WINDOWS_FAILURE|D4R_COMMAND_FAILURE')).Count} | failures=([regex]::Matches($stderr, 'D4R_[A-Z0-9_]*FAILURE\b')).Count} |
ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8 ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Compress-Archive -LiteralPath $OutputDirectory -DestinationPath ($OutputDirectory + '.zip') -Force Compress-Archive -LiteralPath $OutputDirectory -DestinationPath ($OutputDirectory + '.zip') -Force
Write-Host "Game diagnostic bundle: $OutputDirectory.zip" Write-Host "Game diagnostic bundle: $OutputDirectory.zip"
+70 -5
View File
@@ -60,28 +60,93 @@ struct Recording {
explicit Recording(ID3D12GraphicsCommandList* list) : original(list) {} explicit Recording(ID3D12GraphicsCommandList* list) : original(list) {}
}; };
std::unordered_map<ID3D12GraphicsCommandList*, std::shared_ptr<Recording>> recordings; std::unordered_map<ID3D12GraphicsCommandList*, std::shared_ptr<Recording>> recordings;
std::atomic<uint64_t> recording_generation{0};
struct RecordingCache {
ID3D12GraphicsCommandList* list = nullptr;
uint64_t generation = 0;
// A thread's last lookup must not retain suffix lists, allocators or game
// resources after Reset/final Release. Address reuse also needs a new
// generation, even if the old Recording is alive in a submit callback.
std::weak_ptr<Recording> value;
};
thread_local RecordingCache recording_cache;
std::shared_ptr<Recording> get_recording(ID3D12GraphicsCommandList* self, bool create = true) { std::shared_ptr<Recording> get_recording(ID3D12GraphicsCommandList* self, bool create = true) {
if (internal) return {}; if (internal) return {};
const auto generation = recording_generation.load(std::memory_order_acquire);
if (recording_cache.list == self && recording_cache.generation == generation) {
if (auto value = recording_cache.value.lock()) return value;
}
std::lock_guard<std::mutex> lock(map_mutex); std::lock_guard<std::mutex> lock(map_mutex);
auto found = recordings.find(self); auto found = recordings.find(self);
if (found != recordings.end()) return found->second; std::shared_ptr<Recording> value;
if (found != recordings.end()) value = found->second;
else {
if (!create) return {}; if (!create) return {};
auto value = std::make_shared<Recording>(self); value = std::make_shared<Recording>(self);
recordings.emplace(self, value); return value; recordings.emplace(self, value);
recording_generation.fetch_add(1, std::memory_order_release);
}
recording_cache.list = self;
recording_cache.value = value;
recording_cache.generation = recording_generation.load(std::memory_order_relaxed);
return value;
} }
void forget(ID3D12GraphicsCommandList* self) { void forget(ID3D12GraphicsCommandList* self) {
std::shared_ptr<Recording> released; std::shared_ptr<Recording> released;
{ std::lock_guard<std::mutex> lock(map_mutex); { std::lock_guard<std::mutex> lock(map_mutex);
auto it = recordings.find(self); auto it = recordings.find(self);
if (it != recordings.end()) { released = std::move(it->second); recordings.erase(it); } } if (it != recordings.end()) {
released = std::move(it->second); recordings.erase(it);
recording_generation.fetch_add(1, std::memory_order_release);
} }
// Release retained COM objects without holding the map mutex. // Release retained COM objects without holding the map mutex.
} }
struct HookSample {
uint32_t random = GetCurrentThreadId() | 1u;
uint64_t calls = 0, samples = 0, marked = 0;
double access_ms = 0, capture_ms = 0, driver_ms = 0;
Clock::time_point since = Clock::now();
bool choose() {
++calls; random ^= random << 13; random ^= random >> 17; random ^= random << 5;
return !(random & 63u);
}
void flush() {
const double elapsed = milliseconds(since);
if (elapsed < 2000) return;
std::printf("D4R_COMMAND_HOOK_SAMPLE thread=%lu period_ms=%.3f calls=%llu samples=%llu marked=%llu access_sum_ms=%.6f capture_sum_ms=%.6f driver_sum_ms=%.6f sampling=64\n",
GetCurrentThreadId(), elapsed, (unsigned long long)calls, (unsigned long long)samples,
(unsigned long long)marked, access_ms, capture_ms, driver_ms);
calls = samples = marked = 0; access_ms = capture_ms = driver_ms = 0; since = Clock::now();
}
};
thread_local HookSample hook_sample;
bool sample_hooks() { static const bool enabled = std::getenv("D4R_PROFILE_COMMAND_HOOKS") != nullptr; return enabled; }
struct Access { struct Access {
std::shared_ptr<Recording> recording; std::shared_ptr<Recording> recording;
std::unique_lock<std::recursive_mutex> lock; std::unique_lock<std::recursive_mutex> lock;
ID3D12GraphicsCommandList* self; ID3D12GraphicsCommandList* self;
explicit Access(ID3D12GraphicsCommandList* list) : recording(get_recording(list)), self(list) { bool sampled = false;
Clock::time_point begin{}, acquired{}, driver{};
explicit Access(ID3D12GraphicsCommandList* list) : self(list) {
sampled = !internal && sample_hooks() && hook_sample.choose();
if (sampled) begin = Clock::now();
recording = get_recording(list);
if (recording) lock = std::unique_lock<std::recursive_mutex>(recording->mutex); if (recording) lock = std::unique_lock<std::recursive_mutex>(recording->mutex);
if (sampled) acquired = Clock::now();
}
void driver_call() {
if (sampled) driver = Clock::now();
}
~Access() {
if (!sampled) return;
++hook_sample.samples;
hook_sample.access_ms += std::chrono::duration<double, std::milli>(acquired - begin).count();
if (driver != Clock::time_point{}) {
++hook_sample.marked;
hook_sample.capture_ms += std::chrono::duration<double, std::milli>(driver - acquired).count();
hook_sample.driver_ms += milliseconds(driver);
}
hook_sample.flush();
} }
ID3D12GraphicsCommandList* target() const { ID3D12GraphicsCommandList* target() const {
return recording && recording->current ? recording->current.Get() : self; return recording && recording->current ? recording->current.Get() : self;
@@ -16,6 +16,7 @@ using Fn_DrawInstanced = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* sel
static Fn_DrawInstanced original_DrawInstanced = nullptr; static Fn_DrawInstanced original_DrawInstanced = nullptr;
static void STDMETHODCALLTYPE hook_DrawInstanced(ID3D12GraphicsCommandList* self, UINT vertex_count_per_instance, UINT instance_count, UINT start_vertex_location, UINT start_instance_location) { static void STDMETHODCALLTYPE hook_DrawInstanced(ID3D12GraphicsCommandList* self, UINT vertex_count_per_instance, UINT instance_count, UINT start_vertex_location, UINT start_instance_location) {
Access access(self); Access access(self);
access.driver_call();
return original_DrawInstanced(access.target(), vertex_count_per_instance, instance_count, start_vertex_location, start_instance_location); return original_DrawInstanced(access.target(), vertex_count_per_instance, instance_count, start_vertex_location, start_instance_location);
} }
@@ -23,6 +24,7 @@ using Fn_DrawIndexedInstanced = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandLi
static Fn_DrawIndexedInstanced original_DrawIndexedInstanced = nullptr; static Fn_DrawIndexedInstanced original_DrawIndexedInstanced = nullptr;
static void STDMETHODCALLTYPE hook_DrawIndexedInstanced(ID3D12GraphicsCommandList* self, UINT index_count_per_instance, UINT instance_count, UINT start_vertex_location, INT base_vertex_location, UINT start_instance_location) { static void STDMETHODCALLTYPE hook_DrawIndexedInstanced(ID3D12GraphicsCommandList* self, UINT index_count_per_instance, UINT instance_count, UINT start_vertex_location, INT base_vertex_location, UINT start_instance_location) {
Access access(self); Access access(self);
access.driver_call();
return original_DrawIndexedInstanced(access.target(), index_count_per_instance, instance_count, start_vertex_location, base_vertex_location, start_instance_location); return original_DrawIndexedInstanced(access.target(), index_count_per_instance, instance_count, start_vertex_location, base_vertex_location, start_instance_location);
} }
@@ -30,6 +32,7 @@ using Fn_Dispatch = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UI
static Fn_Dispatch original_Dispatch = nullptr; static Fn_Dispatch original_Dispatch = nullptr;
static void STDMETHODCALLTYPE hook_Dispatch(ID3D12GraphicsCommandList* self, UINT x, UINT u, UINT z) { static void STDMETHODCALLTYPE hook_Dispatch(ID3D12GraphicsCommandList* self, UINT x, UINT u, UINT z) {
Access access(self); Access access(self);
access.driver_call();
return original_Dispatch(access.target(), x, u, z); return original_Dispatch(access.target(), x, u, z);
} }
@@ -37,6 +40,7 @@ using Fn_CopyBufferRegion = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList*
static Fn_CopyBufferRegion original_CopyBufferRegion = nullptr; static Fn_CopyBufferRegion original_CopyBufferRegion = nullptr;
static void STDMETHODCALLTYPE hook_CopyBufferRegion(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT64 byte_count) { static void STDMETHODCALLTYPE hook_CopyBufferRegion(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT64 byte_count) {
Access access(self); Access access(self);
access.driver_call();
return original_CopyBufferRegion(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, byte_count); return original_CopyBufferRegion(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, byte_count);
} }
@@ -44,6 +48,7 @@ using Fn_CopyTextureRegion = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList*
static Fn_CopyTextureRegion original_CopyTextureRegion = nullptr; static Fn_CopyTextureRegion original_CopyTextureRegion = nullptr;
static void STDMETHODCALLTYPE hook_CopyTextureRegion(ID3D12GraphicsCommandList* self, const D3D12_TEXTURE_COPY_LOCATION *dst, UINT dst_x, UINT dst_y, UINT dst_z, const D3D12_TEXTURE_COPY_LOCATION *src, const D3D12_BOX *src_box) { static void STDMETHODCALLTYPE hook_CopyTextureRegion(ID3D12GraphicsCommandList* self, const D3D12_TEXTURE_COPY_LOCATION *dst, UINT dst_x, UINT dst_y, UINT dst_z, const D3D12_TEXTURE_COPY_LOCATION *src, const D3D12_BOX *src_box) {
Access access(self); Access access(self);
access.driver_call();
return original_CopyTextureRegion(access.target(), dst, dst_x, dst_y, dst_z, src, src_box); return original_CopyTextureRegion(access.target(), dst, dst_x, dst_y, dst_z, src, src_box);
} }
@@ -51,6 +56,7 @@ using Fn_CopyResource = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self
static Fn_CopyResource original_CopyResource = nullptr; static Fn_CopyResource original_CopyResource = nullptr;
static void STDMETHODCALLTYPE hook_CopyResource(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, ID3D12Resource *src_resource) { static void STDMETHODCALLTYPE hook_CopyResource(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, ID3D12Resource *src_resource) {
Access access(self); Access access(self);
access.driver_call();
return original_CopyResource(access.target(), dst_resource, src_resource); return original_CopyResource(access.target(), dst_resource, src_resource);
} }
@@ -58,6 +64,7 @@ using Fn_CopyTiles = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, I
static Fn_CopyTiles original_CopyTiles = nullptr; static Fn_CopyTiles original_CopyTiles = nullptr;
static void STDMETHODCALLTYPE hook_CopyTiles(ID3D12GraphicsCommandList* self, ID3D12Resource *tiled_resource, const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate, const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer, UINT64 buffer_offset, D3D12_TILE_COPY_FLAGS flags) { static void STDMETHODCALLTYPE hook_CopyTiles(ID3D12GraphicsCommandList* self, ID3D12Resource *tiled_resource, const D3D12_TILED_RESOURCE_COORDINATE *tile_region_start_coordinate, const D3D12_TILE_REGION_SIZE *tile_region_size, ID3D12Resource *buffer, UINT64 buffer_offset, D3D12_TILE_COPY_FLAGS flags) {
Access access(self); Access access(self);
access.driver_call();
return original_CopyTiles(access.target(), tiled_resource, tile_region_start_coordinate, tile_region_size, buffer, buffer_offset, flags); return original_CopyTiles(access.target(), tiled_resource, tile_region_start_coordinate, tile_region_size, buffer, buffer_offset, flags);
} }
@@ -65,6 +72,7 @@ using Fn_ResolveSubresource = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList
static Fn_ResolveSubresource original_ResolveSubresource = nullptr; static Fn_ResolveSubresource original_ResolveSubresource = nullptr;
static void STDMETHODCALLTYPE hook_ResolveSubresource(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, UINT dst_sub_resource, ID3D12Resource *src_resource, UINT src_sub_resource, DXGI_FORMAT format) { static void STDMETHODCALLTYPE hook_ResolveSubresource(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, UINT dst_sub_resource, ID3D12Resource *src_resource, UINT src_sub_resource, DXGI_FORMAT format) {
Access access(self); Access access(self);
access.driver_call();
return original_ResolveSubresource(access.target(), dst_resource, dst_sub_resource, src_resource, src_sub_resource, format); return original_ResolveSubresource(access.target(), dst_resource, dst_sub_resource, src_resource, src_sub_resource, format);
} }
@@ -75,6 +83,7 @@ static void STDMETHODCALLTYPE hook_IASetPrimitiveTopology(ID3D12GraphicsCommandL
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_IASetPrimitiveTopology(target, primitive_topology); original_IASetPrimitiveTopology(target, primitive_topology);
}); });
access.driver_call();
return original_IASetPrimitiveTopology(access.target(), primitive_topology); return original_IASetPrimitiveTopology(access.target(), primitive_topology);
} }
@@ -86,6 +95,7 @@ static void STDMETHODCALLTYPE hook_RSSetViewports(ID3D12GraphicsCommandList* sel
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetViewports(target, viewport_count, values_pointer(saved_viewports)); original_RSSetViewports(target, viewport_count, values_pointer(saved_viewports));
}); });
access.driver_call();
return original_RSSetViewports(access.target(), viewport_count, viewports); return original_RSSetViewports(access.target(), viewport_count, viewports);
} }
@@ -97,6 +107,7 @@ static void STDMETHODCALLTYPE hook_RSSetScissorRects(ID3D12GraphicsCommandList*
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetScissorRects(target, rect_count, values_pointer(saved_rects)); original_RSSetScissorRects(target, rect_count, values_pointer(saved_rects));
}); });
access.driver_call();
return original_RSSetScissorRects(access.target(), rect_count, rects); return original_RSSetScissorRects(access.target(), rect_count, rects);
} }
@@ -108,6 +119,7 @@ static void STDMETHODCALLTYPE hook_OMSetBlendFactor(ID3D12GraphicsCommandList* s
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetBlendFactor(target, values_pointer(saved_blend_factor)); original_OMSetBlendFactor(target, values_pointer(saved_blend_factor));
}); });
access.driver_call();
return original_OMSetBlendFactor(access.target(), blend_factor); return original_OMSetBlendFactor(access.target(), blend_factor);
} }
@@ -118,6 +130,7 @@ static void STDMETHODCALLTYPE hook_OMSetStencilRef(ID3D12GraphicsCommandList* se
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetStencilRef(target, stencil_ref); original_OMSetStencilRef(target, stencil_ref);
}); });
access.driver_call();
return original_OMSetStencilRef(access.target(), stencil_ref); return original_OMSetStencilRef(access.target(), stencil_ref);
} }
@@ -129,6 +142,7 @@ static void STDMETHODCALLTYPE hook_SetPipelineState(ID3D12GraphicsCommandList* s
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetPipelineState(target, saved_pipeline_state.Get()); original_SetPipelineState(target, saved_pipeline_state.Get());
}); });
access.driver_call();
return original_SetPipelineState(access.target(), pipeline_state); return original_SetPipelineState(access.target(), pipeline_state);
} }
@@ -148,6 +162,7 @@ static void STDMETHODCALLTYPE hook_SetDescriptorHeaps(ID3D12GraphicsCommandList*
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetDescriptorHeaps(target, heap_count, saved_heaps.raw.data()); original_SetDescriptorHeaps(target, heap_count, saved_heaps.raw.data());
}); });
access.driver_call();
return original_SetDescriptorHeaps(access.target(), heap_count, heaps); return original_SetDescriptorHeaps(access.target(), heap_count, heaps);
} }
@@ -159,6 +174,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRootSignature(ID3D12GraphicsCommand
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootSignature(target, saved_root_signature.Get()); original_SetComputeRootSignature(target, saved_root_signature.Get());
}); });
access.driver_call();
return original_SetComputeRootSignature(access.target(), root_signature); return original_SetComputeRootSignature(access.target(), root_signature);
} }
@@ -170,6 +186,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRootSignature(ID3D12GraphicsComman
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootSignature(target, saved_root_signature.Get()); original_SetGraphicsRootSignature(target, saved_root_signature.Get());
}); });
access.driver_call();
return original_SetGraphicsRootSignature(access.target(), root_signature); return original_SetGraphicsRootSignature(access.target(), root_signature);
} }
@@ -180,6 +197,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRootDescriptorTable(ID3D12GraphicsC
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootDescriptorTable(target, root_parameter_index, base_descriptor); original_SetComputeRootDescriptorTable(target, root_parameter_index, base_descriptor);
}); });
access.driver_call();
return original_SetComputeRootDescriptorTable(access.target(), root_parameter_index, base_descriptor); return original_SetComputeRootDescriptorTable(access.target(), root_parameter_index, base_descriptor);
} }
@@ -190,6 +208,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRootDescriptorTable(ID3D12Graphics
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootDescriptorTable(target, root_parameter_index, base_descriptor); original_SetGraphicsRootDescriptorTable(target, root_parameter_index, base_descriptor);
}); });
access.driver_call();
return original_SetGraphicsRootDescriptorTable(access.target(), root_parameter_index, base_descriptor); return original_SetGraphicsRootDescriptorTable(access.target(), root_parameter_index, base_descriptor);
} }
@@ -200,6 +219,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRoot32BitConstant(ID3D12GraphicsCom
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRoot32BitConstant(target, root_parameter_index, data, dst_offset); original_SetComputeRoot32BitConstant(target, root_parameter_index, data, dst_offset);
}); });
access.driver_call();
return original_SetComputeRoot32BitConstant(access.target(), root_parameter_index, data, dst_offset); return original_SetComputeRoot32BitConstant(access.target(), root_parameter_index, data, dst_offset);
} }
@@ -210,6 +230,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRoot32BitConstant(ID3D12GraphicsCo
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRoot32BitConstant(target, root_parameter_index, data, dst_offset); original_SetGraphicsRoot32BitConstant(target, root_parameter_index, data, dst_offset);
}); });
access.driver_call();
return original_SetGraphicsRoot32BitConstant(access.target(), root_parameter_index, data, dst_offset); return original_SetGraphicsRoot32BitConstant(access.target(), root_parameter_index, data, dst_offset);
} }
@@ -221,6 +242,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRoot32BitConstants(ID3D12GraphicsCo
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRoot32BitConstants(target, root_parameter_index, constant_count, values_pointer(saved_data), dst_offset); original_SetComputeRoot32BitConstants(target, root_parameter_index, constant_count, values_pointer(saved_data), dst_offset);
}); });
access.driver_call();
return original_SetComputeRoot32BitConstants(access.target(), root_parameter_index, constant_count, data, dst_offset); return original_SetComputeRoot32BitConstants(access.target(), root_parameter_index, constant_count, data, dst_offset);
} }
@@ -232,6 +254,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRoot32BitConstants(ID3D12GraphicsC
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRoot32BitConstants(target, root_parameter_index, constant_count, values_pointer(saved_data), dst_offset); original_SetGraphicsRoot32BitConstants(target, root_parameter_index, constant_count, values_pointer(saved_data), dst_offset);
}); });
access.driver_call();
return original_SetGraphicsRoot32BitConstants(access.target(), root_parameter_index, constant_count, data, dst_offset); return original_SetGraphicsRoot32BitConstants(access.target(), root_parameter_index, constant_count, data, dst_offset);
} }
@@ -242,6 +265,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRootConstantBufferView(ID3D12Graphi
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootConstantBufferView(target, root_parameter_index, address); original_SetComputeRootConstantBufferView(target, root_parameter_index, address);
}); });
access.driver_call();
return original_SetComputeRootConstantBufferView(access.target(), root_parameter_index, address); return original_SetComputeRootConstantBufferView(access.target(), root_parameter_index, address);
} }
@@ -252,6 +276,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRootConstantBufferView(ID3D12Graph
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootConstantBufferView(target, root_parameter_index, address); original_SetGraphicsRootConstantBufferView(target, root_parameter_index, address);
}); });
access.driver_call();
return original_SetGraphicsRootConstantBufferView(access.target(), root_parameter_index, address); return original_SetGraphicsRootConstantBufferView(access.target(), root_parameter_index, address);
} }
@@ -262,6 +287,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRootShaderResourceView(ID3D12Graphi
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootShaderResourceView(target, root_parameter_index, address); original_SetComputeRootShaderResourceView(target, root_parameter_index, address);
}); });
access.driver_call();
return original_SetComputeRootShaderResourceView(access.target(), root_parameter_index, address); return original_SetComputeRootShaderResourceView(access.target(), root_parameter_index, address);
} }
@@ -272,6 +298,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRootShaderResourceView(ID3D12Graph
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootShaderResourceView(target, root_parameter_index, address); original_SetGraphicsRootShaderResourceView(target, root_parameter_index, address);
}); });
access.driver_call();
return original_SetGraphicsRootShaderResourceView(access.target(), root_parameter_index, address); return original_SetGraphicsRootShaderResourceView(access.target(), root_parameter_index, address);
} }
@@ -282,6 +309,7 @@ static void STDMETHODCALLTYPE hook_SetComputeRootUnorderedAccessView(ID3D12Graph
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootUnorderedAccessView(target, root_parameter_index, address); original_SetComputeRootUnorderedAccessView(target, root_parameter_index, address);
}); });
access.driver_call();
return original_SetComputeRootUnorderedAccessView(access.target(), root_parameter_index, address); return original_SetComputeRootUnorderedAccessView(access.target(), root_parameter_index, address);
} }
@@ -292,6 +320,7 @@ static void STDMETHODCALLTYPE hook_SetGraphicsRootUnorderedAccessView(ID3D12Grap
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootUnorderedAccessView(target, root_parameter_index, address); original_SetGraphicsRootUnorderedAccessView(target, root_parameter_index, address);
}); });
access.driver_call();
return original_SetGraphicsRootUnorderedAccessView(access.target(), root_parameter_index, address); return original_SetGraphicsRootUnorderedAccessView(access.target(), root_parameter_index, address);
} }
@@ -303,6 +332,7 @@ static void STDMETHODCALLTYPE hook_IASetIndexBuffer(ID3D12GraphicsCommandList* s
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_IASetIndexBuffer(target, values_pointer(saved_view)); original_IASetIndexBuffer(target, values_pointer(saved_view));
}); });
access.driver_call();
return original_IASetIndexBuffer(access.target(), view); return original_IASetIndexBuffer(access.target(), view);
} }
@@ -314,6 +344,7 @@ static void STDMETHODCALLTYPE hook_IASetVertexBuffers(ID3D12GraphicsCommandList*
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_IASetVertexBuffers(target, start_slot, view_count, values_pointer(saved_views)); original_IASetVertexBuffers(target, start_slot, view_count, values_pointer(saved_views));
}); });
access.driver_call();
return original_IASetVertexBuffers(access.target(), start_slot, view_count, views); return original_IASetVertexBuffers(access.target(), start_slot, view_count, views);
} }
@@ -325,6 +356,7 @@ static void STDMETHODCALLTYPE hook_SOSetTargets(ID3D12GraphicsCommandList* self,
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SOSetTargets(target, start_slot, view_count, values_pointer(saved_views)); original_SOSetTargets(target, start_slot, view_count, values_pointer(saved_views));
}); });
access.driver_call();
return original_SOSetTargets(access.target(), start_slot, view_count, views); return original_SOSetTargets(access.target(), start_slot, view_count, views);
} }
@@ -337,6 +369,7 @@ static void STDMETHODCALLTYPE hook_OMSetRenderTargets(ID3D12GraphicsCommandList*
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetRenderTargets(target, render_target_descriptor_count, values_pointer(saved_render_target_descriptors), single_descriptor_handle, values_pointer(saved_depth_stencil_descriptor)); original_OMSetRenderTargets(target, render_target_descriptor_count, values_pointer(saved_render_target_descriptors), single_descriptor_handle, values_pointer(saved_depth_stencil_descriptor));
}); });
access.driver_call();
return original_OMSetRenderTargets(access.target(), render_target_descriptor_count, render_target_descriptors, single_descriptor_handle, depth_stencil_descriptor); return original_OMSetRenderTargets(access.target(), render_target_descriptor_count, render_target_descriptors, single_descriptor_handle, depth_stencil_descriptor);
} }
@@ -344,6 +377,7 @@ using Fn_ClearDepthStencilView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandL
static Fn_ClearDepthStencilView original_ClearDepthStencilView = nullptr; static Fn_ClearDepthStencilView original_ClearDepthStencilView = nullptr;
static void STDMETHODCALLTYPE hook_ClearDepthStencilView(ID3D12GraphicsCommandList* self, D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags, FLOAT depth, UINT8 stencil, UINT rect_count, const D3D12_RECT *rects) { static void STDMETHODCALLTYPE hook_ClearDepthStencilView(ID3D12GraphicsCommandList* self, D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags, FLOAT depth, UINT8 stencil, UINT rect_count, const D3D12_RECT *rects) {
Access access(self); Access access(self);
access.driver_call();
return original_ClearDepthStencilView(access.target(), dsv, flags, depth, stencil, rect_count, rects); return original_ClearDepthStencilView(access.target(), dsv, flags, depth, stencil, rect_count, rects);
} }
@@ -351,6 +385,7 @@ using Fn_ClearRenderTargetView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandL
static Fn_ClearRenderTargetView original_ClearRenderTargetView = nullptr; static Fn_ClearRenderTargetView original_ClearRenderTargetView = nullptr;
static void STDMETHODCALLTYPE hook_ClearRenderTargetView(ID3D12GraphicsCommandList* self, D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4], UINT rect_count, const D3D12_RECT *rects) { static void STDMETHODCALLTYPE hook_ClearRenderTargetView(ID3D12GraphicsCommandList* self, D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4], UINT rect_count, const D3D12_RECT *rects) {
Access access(self); Access access(self);
access.driver_call();
return original_ClearRenderTargetView(access.target(), rtv, color, rect_count, rects); return original_ClearRenderTargetView(access.target(), rtv, color, rect_count, rects);
} }
@@ -358,6 +393,7 @@ using Fn_ClearUnorderedAccessViewUint = void(STDMETHODCALLTYPE*)(ID3D12GraphicsC
static Fn_ClearUnorderedAccessViewUint original_ClearUnorderedAccessViewUint = nullptr; static Fn_ClearUnorderedAccessViewUint original_ClearUnorderedAccessViewUint = nullptr;
static void STDMETHODCALLTYPE hook_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList* self, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, const UINT values[4], UINT rect_count, const D3D12_RECT *rects) { static void STDMETHODCALLTYPE hook_ClearUnorderedAccessViewUint(ID3D12GraphicsCommandList* self, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, const UINT values[4], UINT rect_count, const D3D12_RECT *rects) {
Access access(self); Access access(self);
access.driver_call();
return original_ClearUnorderedAccessViewUint(access.target(), gpu_handle, cpu_handle, resource, values, rect_count, rects); return original_ClearUnorderedAccessViewUint(access.target(), gpu_handle, cpu_handle, resource, values, rect_count, rects);
} }
@@ -365,6 +401,7 @@ using Fn_ClearUnorderedAccessViewFloat = void(STDMETHODCALLTYPE*)(ID3D12Graphics
static Fn_ClearUnorderedAccessViewFloat original_ClearUnorderedAccessViewFloat = nullptr; static Fn_ClearUnorderedAccessViewFloat original_ClearUnorderedAccessViewFloat = nullptr;
static void STDMETHODCALLTYPE hook_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList* self, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, const float values[4], UINT rect_count, const D3D12_RECT *rects) { static void STDMETHODCALLTYPE hook_ClearUnorderedAccessViewFloat(ID3D12GraphicsCommandList* self, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, ID3D12Resource *resource, const float values[4], UINT rect_count, const D3D12_RECT *rects) {
Access access(self); Access access(self);
access.driver_call();
return original_ClearUnorderedAccessViewFloat(access.target(), gpu_handle, cpu_handle, resource, values, rect_count, rects); return original_ClearUnorderedAccessViewFloat(access.target(), gpu_handle, cpu_handle, resource, values, rect_count, rects);
} }
@@ -372,6 +409,7 @@ using Fn_DiscardResource = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* s
static Fn_DiscardResource original_DiscardResource = nullptr; static Fn_DiscardResource original_DiscardResource = nullptr;
static void STDMETHODCALLTYPE hook_DiscardResource(ID3D12GraphicsCommandList* self, ID3D12Resource *resource, const D3D12_DISCARD_REGION *region) { static void STDMETHODCALLTYPE hook_DiscardResource(ID3D12GraphicsCommandList* self, ID3D12Resource *resource, const D3D12_DISCARD_REGION *region) {
Access access(self); Access access(self);
access.driver_call();
return original_DiscardResource(access.target(), resource, region); return original_DiscardResource(access.target(), resource, region);
} }
@@ -387,6 +425,7 @@ using Fn_ResolveQueryData = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList*
static Fn_ResolveQueryData original_ResolveQueryData = nullptr; static Fn_ResolveQueryData original_ResolveQueryData = nullptr;
static void STDMETHODCALLTYPE hook_ResolveQueryData(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count, ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset) { static void STDMETHODCALLTYPE hook_ResolveQueryData(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count, ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset) {
Access access(self); Access access(self);
access.driver_call();
return original_ResolveQueryData(access.target(), heap, type, start_index, query_count, dst_buffer, aligned_dst_buffer_offset); return original_ResolveQueryData(access.target(), heap, type, start_index, query_count, dst_buffer, aligned_dst_buffer_offset);
} }
@@ -398,6 +437,7 @@ using Fn_SetMarker = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, U
static Fn_SetMarker original_SetMarker = nullptr; static Fn_SetMarker original_SetMarker = nullptr;
static void STDMETHODCALLTYPE hook_SetMarker(ID3D12GraphicsCommandList* self, UINT metadata, const void *data, UINT size) { static void STDMETHODCALLTYPE hook_SetMarker(ID3D12GraphicsCommandList* self, UINT metadata, const void *data, UINT size) {
Access access(self); Access access(self);
access.driver_call();
return original_SetMarker(access.target(), metadata, data, size); return original_SetMarker(access.target(), metadata, data, size);
} }
@@ -417,6 +457,7 @@ using Fn_AtomicCopyBufferUINT = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandLi
static Fn_AtomicCopyBufferUINT original_AtomicCopyBufferUINT = nullptr; static Fn_AtomicCopyBufferUINT original_AtomicCopyBufferUINT = nullptr;
static void STDMETHODCALLTYPE hook_AtomicCopyBufferUINT(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT dependent_resource_count, ID3D12Resource *const *dependent_resources, const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) { static void STDMETHODCALLTYPE hook_AtomicCopyBufferUINT(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT dependent_resource_count, ID3D12Resource *const *dependent_resources, const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) {
Access access(self); Access access(self);
access.driver_call();
return original_AtomicCopyBufferUINT(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, dependent_resource_count, dependent_resources, dependent_sub_resource_ranges); return original_AtomicCopyBufferUINT(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, dependent_resource_count, dependent_resources, dependent_sub_resource_ranges);
} }
@@ -424,6 +465,7 @@ using Fn_AtomicCopyBufferUINT64 = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommand
static Fn_AtomicCopyBufferUINT64 original_AtomicCopyBufferUINT64 = nullptr; static Fn_AtomicCopyBufferUINT64 original_AtomicCopyBufferUINT64 = nullptr;
static void STDMETHODCALLTYPE hook_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT dependent_resource_count, ID3D12Resource *const *dependent_resources, const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) { static void STDMETHODCALLTYPE hook_AtomicCopyBufferUINT64(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT dependent_resource_count, ID3D12Resource *const *dependent_resources, const D3D12_SUBRESOURCE_RANGE_UINT64 *dependent_sub_resource_ranges) {
Access access(self); Access access(self);
access.driver_call();
return original_AtomicCopyBufferUINT64(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, dependent_resource_count, dependent_resources, dependent_sub_resource_ranges); return original_AtomicCopyBufferUINT64(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, dependent_resource_count, dependent_resources, dependent_sub_resource_ranges);
} }
@@ -434,6 +476,7 @@ static void STDMETHODCALLTYPE hook_OMSetDepthBounds(ID3D12GraphicsCommandList* s
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetDepthBounds(target, min, max); original_OMSetDepthBounds(target, min, max);
}); });
access.driver_call();
return original_OMSetDepthBounds(access.target(), min, max); return original_OMSetDepthBounds(access.target(), min, max);
} }
@@ -445,6 +488,7 @@ static void STDMETHODCALLTYPE hook_SetSamplePositions(ID3D12GraphicsCommandList*
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetSamplePositions(target, sample_count, pixel_count, values_pointer(saved_sample_positions)); original_SetSamplePositions(target, sample_count, pixel_count, values_pointer(saved_sample_positions));
}); });
access.driver_call();
return original_SetSamplePositions(access.target(), sample_count, pixel_count, sample_positions); return original_SetSamplePositions(access.target(), sample_count, pixel_count, sample_positions);
} }
@@ -452,6 +496,7 @@ using Fn_ResolveSubresourceRegion = void(STDMETHODCALLTYPE*)(ID3D12GraphicsComma
static Fn_ResolveSubresourceRegion original_ResolveSubresourceRegion = nullptr; static Fn_ResolveSubresourceRegion original_ResolveSubresourceRegion = nullptr;
static void STDMETHODCALLTYPE hook_ResolveSubresourceRegion(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, UINT dst_sub_resource_idx, UINT dst_x, UINT dst_y, ID3D12Resource *src_resource, UINT src_sub_resource_idx, D3D12_RECT *src_rect, DXGI_FORMAT format, D3D12_RESOLVE_MODE mode) { static void STDMETHODCALLTYPE hook_ResolveSubresourceRegion(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, UINT dst_sub_resource_idx, UINT dst_x, UINT dst_y, ID3D12Resource *src_resource, UINT src_sub_resource_idx, D3D12_RECT *src_rect, DXGI_FORMAT format, D3D12_RESOLVE_MODE mode) {
Access access(self); Access access(self);
access.driver_call();
return original_ResolveSubresourceRegion(access.target(), dst_resource, dst_sub_resource_idx, dst_x, dst_y, src_resource, src_sub_resource_idx, src_rect, format, mode); return original_ResolveSubresourceRegion(access.target(), dst_resource, dst_sub_resource_idx, dst_x, dst_y, src_resource, src_sub_resource_idx, src_rect, format, mode);
} }
@@ -462,6 +507,7 @@ static void STDMETHODCALLTYPE hook_SetViewInstanceMask(ID3D12GraphicsCommandList
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetViewInstanceMask(target, mask); original_SetViewInstanceMask(target, mask);
}); });
access.driver_call();
return original_SetViewInstanceMask(access.target(), mask); return original_SetViewInstanceMask(access.target(), mask);
} }
@@ -469,6 +515,7 @@ using Fn_WriteBufferImmediate = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandLi
static Fn_WriteBufferImmediate original_WriteBufferImmediate = nullptr; static Fn_WriteBufferImmediate original_WriteBufferImmediate = nullptr;
static void STDMETHODCALLTYPE hook_WriteBufferImmediate(ID3D12GraphicsCommandList* self, UINT count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters, const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes) { static void STDMETHODCALLTYPE hook_WriteBufferImmediate(ID3D12GraphicsCommandList* self, UINT count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters, const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes) {
Access access(self); Access access(self);
access.driver_call();
return original_WriteBufferImmediate(access.target(), count, parameters, modes); return original_WriteBufferImmediate(access.target(), count, parameters, modes);
} }
@@ -480,6 +527,7 @@ static void STDMETHODCALLTYPE hook_SetProtectedResourceSession(ID3D12GraphicsCom
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetProtectedResourceSession(target, saved_protected_resource_session.Get()); original_SetProtectedResourceSession(target, saved_protected_resource_session.Get());
}); });
access.driver_call();
return original_SetProtectedResourceSession(access.target(), protected_resource_session); return original_SetProtectedResourceSession(access.target(), protected_resource_session);
} }
@@ -495,6 +543,7 @@ using Fn_InitializeMetaCommand = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandL
static Fn_InitializeMetaCommand original_InitializeMetaCommand = nullptr; static Fn_InitializeMetaCommand original_InitializeMetaCommand = nullptr;
static void STDMETHODCALLTYPE hook_InitializeMetaCommand(ID3D12GraphicsCommandList* self, ID3D12MetaCommand *meta_command, const void *initialization_parameters_data, SIZE_T initialization_parameters_data_size_in_bytes) { static void STDMETHODCALLTYPE hook_InitializeMetaCommand(ID3D12GraphicsCommandList* self, ID3D12MetaCommand *meta_command, const void *initialization_parameters_data, SIZE_T initialization_parameters_data_size_in_bytes) {
Access access(self); Access access(self);
access.driver_call();
return original_InitializeMetaCommand(access.target(), meta_command, initialization_parameters_data, initialization_parameters_data_size_in_bytes); return original_InitializeMetaCommand(access.target(), meta_command, initialization_parameters_data, initialization_parameters_data_size_in_bytes);
} }
@@ -502,6 +551,7 @@ using Fn_ExecuteMetaCommand = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList
static Fn_ExecuteMetaCommand original_ExecuteMetaCommand = nullptr; static Fn_ExecuteMetaCommand original_ExecuteMetaCommand = nullptr;
static void STDMETHODCALLTYPE hook_ExecuteMetaCommand(ID3D12GraphicsCommandList* self, ID3D12MetaCommand *meta_command, const void *execution_parameters_data, SIZE_T execution_parameters_data_size_in_bytes) { static void STDMETHODCALLTYPE hook_ExecuteMetaCommand(ID3D12GraphicsCommandList* self, ID3D12MetaCommand *meta_command, const void *execution_parameters_data, SIZE_T execution_parameters_data_size_in_bytes) {
Access access(self); Access access(self);
access.driver_call();
return original_ExecuteMetaCommand(access.target(), meta_command, execution_parameters_data, execution_parameters_data_size_in_bytes); return original_ExecuteMetaCommand(access.target(), meta_command, execution_parameters_data, execution_parameters_data_size_in_bytes);
} }
@@ -509,6 +559,7 @@ using Fn_BuildRaytracingAccelerationStructure = void(STDMETHODCALLTYPE*)(ID3D12G
static Fn_BuildRaytracingAccelerationStructure original_BuildRaytracingAccelerationStructure = nullptr; static Fn_BuildRaytracingAccelerationStructure original_BuildRaytracingAccelerationStructure = nullptr;
static void STDMETHODCALLTYPE hook_BuildRaytracingAccelerationStructure(ID3D12GraphicsCommandList* self, const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *desc, UINT postbuild_info_descs_count, const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *postbuild_info_descs) { static void STDMETHODCALLTYPE hook_BuildRaytracingAccelerationStructure(ID3D12GraphicsCommandList* self, const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC *desc, UINT postbuild_info_descs_count, const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *postbuild_info_descs) {
Access access(self); Access access(self);
access.driver_call();
return original_BuildRaytracingAccelerationStructure(access.target(), desc, postbuild_info_descs_count, postbuild_info_descs); return original_BuildRaytracingAccelerationStructure(access.target(), desc, postbuild_info_descs_count, postbuild_info_descs);
} }
@@ -516,6 +567,7 @@ using Fn_EmitRaytracingAccelerationStructurePostbuildInfo = void(STDMETHODCALLTY
static Fn_EmitRaytracingAccelerationStructurePostbuildInfo original_EmitRaytracingAccelerationStructurePostbuildInfo = nullptr; static Fn_EmitRaytracingAccelerationStructurePostbuildInfo original_EmitRaytracingAccelerationStructurePostbuildInfo = nullptr;
static void STDMETHODCALLTYPE hook_EmitRaytracingAccelerationStructurePostbuildInfo(ID3D12GraphicsCommandList* self, const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *desc, UINT src_acceleration_structures_count, const D3D12_GPU_VIRTUAL_ADDRESS *src_acceleration_structure_data) { static void STDMETHODCALLTYPE hook_EmitRaytracingAccelerationStructurePostbuildInfo(ID3D12GraphicsCommandList* self, const D3D12_RAYTRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO_DESC *desc, UINT src_acceleration_structures_count, const D3D12_GPU_VIRTUAL_ADDRESS *src_acceleration_structure_data) {
Access access(self); Access access(self);
access.driver_call();
return original_EmitRaytracingAccelerationStructurePostbuildInfo(access.target(), desc, src_acceleration_structures_count, src_acceleration_structure_data); return original_EmitRaytracingAccelerationStructurePostbuildInfo(access.target(), desc, src_acceleration_structures_count, src_acceleration_structure_data);
} }
@@ -523,6 +575,7 @@ using Fn_CopyRaytracingAccelerationStructure = void(STDMETHODCALLTYPE*)(ID3D12Gr
static Fn_CopyRaytracingAccelerationStructure original_CopyRaytracingAccelerationStructure = nullptr; static Fn_CopyRaytracingAccelerationStructure original_CopyRaytracingAccelerationStructure = nullptr;
static void STDMETHODCALLTYPE hook_CopyRaytracingAccelerationStructure(ID3D12GraphicsCommandList* self, D3D12_GPU_VIRTUAL_ADDRESS dst_acceleration_structure_data, D3D12_GPU_VIRTUAL_ADDRESS src_acceleration_structure_data, D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE mode) { static void STDMETHODCALLTYPE hook_CopyRaytracingAccelerationStructure(ID3D12GraphicsCommandList* self, D3D12_GPU_VIRTUAL_ADDRESS dst_acceleration_structure_data, D3D12_GPU_VIRTUAL_ADDRESS src_acceleration_structure_data, D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE mode) {
Access access(self); Access access(self);
access.driver_call();
return original_CopyRaytracingAccelerationStructure(access.target(), dst_acceleration_structure_data, src_acceleration_structure_data, mode); return original_CopyRaytracingAccelerationStructure(access.target(), dst_acceleration_structure_data, src_acceleration_structure_data, mode);
} }
@@ -534,6 +587,7 @@ static void STDMETHODCALLTYPE hook_SetPipelineState1(ID3D12GraphicsCommandList*
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetPipelineState1(target, saved_state_object.Get()); original_SetPipelineState1(target, saved_state_object.Get());
}); });
access.driver_call();
return original_SetPipelineState1(access.target(), state_object); return original_SetPipelineState1(access.target(), state_object);
} }
@@ -541,6 +595,7 @@ using Fn_DispatchRays = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self
static Fn_DispatchRays original_DispatchRays = nullptr; static Fn_DispatchRays original_DispatchRays = nullptr;
static void STDMETHODCALLTYPE hook_DispatchRays(ID3D12GraphicsCommandList* self, const D3D12_DISPATCH_RAYS_DESC *desc) { static void STDMETHODCALLTYPE hook_DispatchRays(ID3D12GraphicsCommandList* self, const D3D12_DISPATCH_RAYS_DESC *desc) {
Access access(self); Access access(self);
access.driver_call();
return original_DispatchRays(access.target(), desc); return original_DispatchRays(access.target(), desc);
} }
@@ -552,6 +607,7 @@ static void STDMETHODCALLTYPE hook_RSSetShadingRate(ID3D12GraphicsCommandList* s
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetShadingRate(target, base_shading_rate, values_pointer(saved_combiners)); original_RSSetShadingRate(target, base_shading_rate, values_pointer(saved_combiners));
}); });
access.driver_call();
return original_RSSetShadingRate(access.target(), base_shading_rate, combiners); return original_RSSetShadingRate(access.target(), base_shading_rate, combiners);
} }
@@ -563,6 +619,7 @@ static void STDMETHODCALLTYPE hook_RSSetShadingRateImage(ID3D12GraphicsCommandLi
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetShadingRateImage(target, saved_shading_rate_image.Get()); original_RSSetShadingRateImage(target, saved_shading_rate_image.Get());
}); });
access.driver_call();
return original_RSSetShadingRateImage(access.target(), shading_rate_image); return original_RSSetShadingRateImage(access.target(), shading_rate_image);
} }
@@ -570,6 +627,7 @@ using Fn_DispatchMesh = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self
static Fn_DispatchMesh original_DispatchMesh = nullptr; static Fn_DispatchMesh original_DispatchMesh = nullptr;
static void STDMETHODCALLTYPE hook_DispatchMesh(ID3D12GraphicsCommandList* self, UINT thread_group_count_x, UINT thread_group_count_y, UINT thread_group_count_z) { static void STDMETHODCALLTYPE hook_DispatchMesh(ID3D12GraphicsCommandList* self, UINT thread_group_count_x, UINT thread_group_count_y, UINT thread_group_count_z) {
Access access(self); Access access(self);
access.driver_call();
return original_DispatchMesh(access.target(), thread_group_count_x, thread_group_count_y, thread_group_count_z); return original_DispatchMesh(access.target(), thread_group_count_x, thread_group_count_y, thread_group_count_z);
} }
@@ -584,6 +642,7 @@ static void STDMETHODCALLTYPE hook_OMSetFrontAndBackStencilRef(ID3D12GraphicsCom
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) {
original_OMSetFrontAndBackStencilRef(target, front_stencil, back_stencil); original_OMSetFrontAndBackStencilRef(target, front_stencil, back_stencil);
}); });
access.driver_call();
original_OMSetFrontAndBackStencilRef(access.target(), front_stencil, back_stencil); original_OMSetFrontAndBackStencilRef(access.target(), front_stencil, back_stencil);
} }
@@ -594,6 +653,7 @@ static void STDMETHODCALLTYPE hook_RSSetDepthBias(ID3D12GraphicsCommandList* sel
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) {
original_RSSetDepthBias(target, depth_bias, clamp, slope); original_RSSetDepthBias(target, depth_bias, clamp, slope);
}); });
access.driver_call();
original_RSSetDepthBias(access.target(), depth_bias, clamp, slope); original_RSSetDepthBias(access.target(), depth_bias, clamp, slope);
} }
@@ -604,6 +664,7 @@ static void STDMETHODCALLTYPE hook_IASetIndexBufferStripCutValue(ID3D12GraphicsC
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) { if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) {
original_IASetIndexBufferStripCutValue(target, value); original_IASetIndexBufferStripCutValue(target, value);
}); });
access.driver_call();
original_IASetIndexBufferStripCutValue(access.target(), value); original_IASetIndexBufferStripCutValue(access.target(), value);
} }
@@ -615,6 +676,7 @@ using Fn_DispatchGraph = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* sel
static Fn_DispatchGraph original_DispatchGraph = nullptr; static Fn_DispatchGraph original_DispatchGraph = nullptr;
static void STDMETHODCALLTYPE hook_DispatchGraph(ID3D12GraphicsCommandList* self, const void* desc) { static void STDMETHODCALLTYPE hook_DispatchGraph(ID3D12GraphicsCommandList* self, const void* desc) {
Access access(self); Access access(self);
access.driver_call();
original_DispatchGraph(access.target(), desc); original_DispatchGraph(access.target(), desc);
} }
+30 -3
View File
@@ -82,6 +82,7 @@ struct Callback {
ID3D12Resource* readback; ID3D12Resource* readback;
uint32_t expected_seed = seed; uint32_t expected_seed = seed;
bool prefix_verified = false; bool prefix_verified = false;
uint32_t expected_multiplier = 17, expected_addend = 10;
}; };
void WINAPI boundary(ID3D12CommandQueue* queue, void* context) { void WINAPI boundary(ID3D12CommandQueue* queue, void* context) {
auto& callback = *static_cast<Callback*>(context); auto& callback = *static_cast<Callback*>(context);
@@ -93,7 +94,8 @@ void WINAPI boundary(ID3D12CommandQueue* queue, void* context) {
list.list->CopyResource(callback.input, callback.replacement); list.list->CopyResource(callback.input, callback.replacement);
transition(list.list.Get(), callback.input, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); transition(list.list.Get(), callback.input, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
list.submit(callback.device, queue); list.submit(callback.device, queue);
callback.prefix_verified = verify(callback.readback, 17, 10, callback.expected_seed); callback.prefix_verified = verify(callback.readback, callback.expected_multiplier,
callback.expected_addend, callback.expected_seed);
} }
} }
@@ -263,13 +265,38 @@ int main(int argc, char** argv) {
ID3D12CommandList* batch[] = {a.list.Get(), b.list.Get(), c.list.Get()}; ID3D12CommandList* batch[] = {a.list.Get(), b.list.Get(), c.list.Get()};
queue->ExecuteCommandLists(no_hooks ? 2 : 3, batch + (no_hooks ? 1 : 0)); drain(device.Get(), queue.Get()); queue->ExecuteCommandLists(no_hooks ? 2 : 3, batch + (no_hooks ? 1 : 0)); drain(device.Get(), queue.Get());
if (!callback.prefix_verified || !verify(readback.Get(), 25, 100, expected_seed)) throw std::runtime_error("Queue order or suffix root state mismatch"); if (!callback.prefix_verified || !verify(readback.Get(), 25, 100, expected_seed)) throw std::runtime_error("Queue order or suffix root state mismatch");
if (!no_hooks) for (unsigned reuse = 0; reuse < 2; ++reuse) {
// Populate the same thread's routing cache with a split
// list, Reset that exact COM object, then split again with
// different root state. A cached previous Recording would
// keep targeting the old suffix or replay the old Seed.
dx(b.allocator->Reset(), "Reset reused allocator");
dx(b.list->Reset(b.allocator.Get(), initial_pso ? pso.Get() : nullptr), "Reset reused logical list");
b.list->SetComputeRootSignature(root.Get());
if (!initial_pso) b.list->SetPipelineState(pso.Get());
b.list->SetComputeRootUnorderedAccessView(0, output->GetGPUVirtualAddress());
b.list->SetComputeRootShaderResourceView(1, input->GetGPUVirtualAddress());
callback.expected_seed = seed + iteration + reuse + 1;
callback.expected_multiplier = 25; callback.expected_addend = 100;
callback.prefix_verified = false;
b.list->SetComputeRoot32BitConstant(2, callback.expected_seed, 0);
b.list->Dispatch(count / 64, 1, 1);
if (record(b.list.Get(), boundary, &callback) != 1) throw std::runtime_error("Record reused split failed");
b.list->Dispatch(count / 64, 1, 1);
transition(b.list.Get(), output.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
b.list->CopyResource(readback.Get(), output.Get());
transition(b.list.Get(), output.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
b.submit(device.Get(), queue.Get());
if (!callback.prefix_verified || !verify(readback.Get(), 25, 100, callback.expected_seed))
throw std::runtime_error("Reset reused logical list retained stale routing/root state");
}
} }
if (live() != 0) throw std::runtime_error("D3D12 recording metadata leaked after command-list Release"); if (live() != 0) throw std::runtime_error("D3D12 recording metadata leaked after command-list Release");
} }
const bool warp = std::getenv("D4R_COMMAND_PROBE_WARP") != nullptr; const bool warp = std::getenv("D4R_COMMAND_PROBE_WARP") != nullptr;
std::printf("PASS D3D12_COMMAND_BACKEND adapter=%s architecture=%s backend=%u iterations=%u batch_order=1 root_state=1 deep_copy=1 indirect=%u indirect_reset=%u live_recordings=0 frame_age=0\n", std::printf("PASS D3D12_COMMAND_BACKEND adapter=%s architecture=%s backend=%u iterations=%u batch_order=1 root_state=1 deep_copy=1 indirect=%u indirect_reset=%u reset_reuse=%u live_recordings=0 frame_age=0\n",
warp ? "WARP" : "AMD", warp ? "software" : no_hip ? "not_queried" : "gfx1201", !no_hooks, warp ? "WARP" : "AMD", warp ? "software" : no_hip ? "not_queried" : "gfx1201", !no_hooks,
args.iterations, indirect_enabled, root_indirect); args.iterations, indirect_enabled, root_indirect, no_hooks ? 0 : 2 * args.iterations);
return 0; return 0;
} catch (const std::exception& failure) { } catch (const std::exception& failure) {
std::fprintf(stderr, "FAIL D3D12_COMMAND_BACKEND %s\n", failure.what()); std::fprintf(stderr, "FAIL D3D12_COMMAND_BACKEND %s\n", failure.what());
+2 -2
View File
@@ -95,7 +95,7 @@ def generate(source):
captured.append(argument) captured.append(argument)
lines += [' if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {', lines += [' if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {',
f' original_{name}(' + ', '.join(['target'] + captured) + ');', ' });'] f' original_{name}(' + ', '.join(['target'] + captured) + ');', ' });']
lines += [f' return original_{name}({call});', '}'] lines += [' access.driver_call();', f' return original_{name}({call});', '}']
registrations.append(f' attach_method(table[{slot}], reinterpret_cast<void*>(hook_{name}), reinterpret_cast<void**>(&original_{name}), "{name}");') registrations.append(f' attach_method(table[{slot}], reinterpret_cast<void*>(hook_{name}), reinterpret_cast<void**>(&original_{name}), "{name}");')
registrations[-1] = f' if (version >= {version})' + registrations[-1][3:] registrations[-1] = f' if (version >= {version})' + registrations[-1][3:]
slot += 1 slot += 1
@@ -112,7 +112,7 @@ def generate(source):
if name != 'DispatchGraph': if name != 'DispatchGraph':
lines += [' if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) {', lines += [' if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) {',
f' original_{name}(' + ', '.join(['target'] + names) + ');', ' });'] f' original_{name}(' + ', '.join(['target'] + names) + ');', ' });']
lines += [f' original_{name}(' + ', '.join(['access.target()'] + names) + ');', '}'] lines += [' access.driver_call();', f' original_{name}(' + ', '.join(['access.target()'] + names) + ');', '}']
registrations.append(f' if (version >= {version}) attach_method(table[{slot}], reinterpret_cast<void*>(hook_{name}), reinterpret_cast<void**>(&original_{name}), "{name}");') registrations.append(f' if (version >= {version}) attach_method(table[{slot}], reinterpret_cast<void*>(hook_{name}), reinterpret_cast<void**>(&original_{name}), "{name}");')
slot += 1 slot += 1
lines.append('') lines.append('')
+23
View File
@@ -41,6 +41,7 @@ def report(directory, metadata_directory=None):
stages = collections.defaultdict(list) stages = collections.defaultdict(list)
commands = collections.defaultdict(list) commands = collections.defaultdict(list)
kernels = collections.defaultdict(list) kernels = collections.defaultdict(list)
hook_threads = collections.defaultdict(list)
for path in sorted(directory.glob('*.log')): for path in sorted(directory.glob('*.log')):
text = path.read_text(encoding='utf-8-sig', errors='replace') text = path.read_text(encoding='utf-8-sig', errors='replace')
for name, value in re.findall(r'D4R_STAGE name=(\S+) cpu_ms=([0-9.]+)', text): for name, value in re.findall(r'D4R_STAGE name=(\S+) cpu_ms=([0-9.]+)', text):
@@ -51,18 +52,37 @@ def report(directory, metadata_directory=None):
if name != 'interval_ms' or number > 0: if name != 'interval_ms' or number > 0:
commands[kind.lower() + '.' + name].append(number) commands[kind.lower() + '.' + name].append(number)
for line in text.splitlines(): for line in text.splitlines():
if line.startswith('D4R_COMMAND_HOOK_SAMPLE '):
fields = dict(re.findall(r'(\w+)=(\S+)', line))
if all(name in fields for name in ('thread', 'period_ms', 'calls', 'samples', 'marked',
'access_sum_ms', 'capture_sum_ms', 'driver_sum_ms')):
hook_threads[fields['thread']].append(fields)
if not line.startswith('D4R_KERNEL_PROFILE '): if not line.startswith('D4R_KERNEL_PROFILE '):
continue continue
fields = dict(re.findall(r'(\w+)=("[^"]+"|\S+)', line)) fields = dict(re.findall(r'(\w+)=("[^"]+"|\S+)', line))
kernels[(fields['kernel'].strip('"'), fields['backend'], fields['phase'])].append(fields) kernels[(fields['kernel'].strip('"'), fields['backend'], fields['phase'])].append(fields)
result = dict(cpuStages={name: stats(values) for name, values in stages.items()}, result = dict(cpuStages={name: stats(values) for name, values in stages.items()},
commandStages={name: stats(values) for name, values in commands.items()}, commandStages={name: stats(values) for name, values in commands.items()},
commandHookSamples=[],
kernels=[], notes=[ kernels=[], notes=[
'CPU stage times include waits and host work; they are not isolated GPU timings.', 'CPU stage times include waits and host work; they are not isolated GPU timings.',
'Command record intervals are between NGX recording calls on one thread, not Present/FPS.', 'Command record intervals are between NGX recording calls on one thread, not Present/FPS.',
'Hook estimates use random one-in-64 samples; driver timing covers generated forwarding methods only.',
'Hook access includes lock waits; summing threads does not measure serial frame latency or CPU execution time.',
'HIP-event profiling synchronizes every sampled launch and changes scheduling.', 'HIP-event profiling synchronizes every sampled launch and changes scheduling.',
'Occupancy is an API prediction, not a measured hardware counter.', 'Occupancy is an API prediction, not a measured hardware counter.',
'Bandwidth and WMMA utilization require additional supported hardware tooling.']) 'Bandwidth and WMMA utilization require additional supported hardware tooling.'])
for thread, rows in hook_threads.items():
sums = {name: sum(float(row[name]) for row in rows) for name in
('period_ms', 'calls', 'samples', 'marked', 'access_sum_ms', 'capture_sum_ms', 'driver_sum_ms')}
if not sums['samples'] or not sums['period_ms']:
continue
scale = sums['calls'] / sums['samples']
estimate = scale * (sums['access_sum_ms'] + sums['capture_sum_ms'])
result['commandHookSamples'].append(dict(thread=int(thread), periods=len(rows), **sums,
accessMeanUs=1000 * sums['access_sum_ms'] / sums['samples'],
captureMeanUsPerSample=1000 * sums['capture_sum_ms'] / sums['samples'],
estimatedAccessCaptureMs=estimate, estimatedAccessCaptureMsPerSecond=1000 * estimate / sums['period_ms']))
for (name, backend, phase), rows in kernels.items(): for (name, backend, phase), rows in kernels.items():
item = dict(kernel=name, backend=backend, phase=phase, item = dict(kernel=name, backend=backend, phase=phase,
gpuMs=stats([float(row['gpu_ms']) for row in rows]), gpuMs=stats([float(row['gpu_ms']) for row in rows]),
@@ -93,6 +113,9 @@ def main():
print(f"CPU {name}: n={row['samples']} mean={row['mean']:.3f} ms median={row['median']:.3f} ms p95={row['p95']:.3f} ms") print(f"CPU {name}: n={row['samples']} mean={row['mean']:.3f} ms median={row['median']:.3f} ms p95={row['p95']:.3f} ms")
for name, row in result['commandStages'].items(): for name, row in result['commandStages'].items():
print(f"COMMAND {name}: n={row['samples']} mean={row['mean']:.3f} ms median={row['median']:.3f} ms p95={row['p95']:.3f} ms") print(f"COMMAND {name}: n={row['samples']} mean={row['mean']:.3f} ms median={row['median']:.3f} ms p95={row['p95']:.3f} ms")
for row in result['commandHookSamples']:
print(f"HOOK thread={row['thread']} samples={int(row['samples'])} access={row['accessMeanUs']:.3f} us "
f"capture={row['captureMeanUsPerSample']:.3f} us estimated_cpu={row['estimatedAccessCaptureMsPerSecond']:.3f} ms/s")
for row in result['kernels']: for row in result['kernels']:
times = row['gpuMs'] times = row['gpuMs']
print(f"GPU {row['kernel']} {row['backend']} {row['phase']}: n={times['samples']} mean={times['mean']:.6f} ms total={times['total']:.3f} ms") print(f"GPU {row['kernel']} {row['backend']} {row['phase']}: n={times['samples']} mean={times['mean']:.6f} ms total={times['total']:.3f} ms")