Execute Windows DLSS K and M at recorded D3D12 command-list boundaries

This commit is contained in:
Codex committed 2026-09-30 22:21:06 +03:00
1 parent b8d801ae4c
commit 63607298ea
12 files changed
+1421 -15

No files matched your search

+320
View File
@@ -0,0 +1,320 @@
#include "d3d12_command_hooks.h"
#include <MinHook.h>
#include <atomic>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <vector>
namespace d4r::win::commands {
namespace {
thread_local bool internal = false;
std::mutex map_mutex, installation_mutex, error_mutex;
std::string last_error;
bool installed = false;
struct Event { UINT metadata; std::vector<uint8_t> data; };
using State = std::function<void(ID3D12GraphicsCommandList*)>;
struct Segment {
// The application's original list is a weak pointer; holding it in its
// own routing map would prevent final Release and leak the entire feature.
ID3D12GraphicsCommandList* list = nullptr;
ComPtr<ID3D12GraphicsCommandList> owner;
ComPtr<ID3D12CommandAllocator> allocator;
Boundary boundary;
};
struct Recording {
std::recursive_mutex mutex;
ID3D12GraphicsCommandList* original;
ComPtr<ID3D12GraphicsCommandList> current;
ComPtr<ID3D12CommandAllocator> current_allocator;
std::vector<Segment> segments;
std::vector<State> state;
std::vector<Event> events;
std::unordered_map<ID3D12Resource*, D3D12_RESOURCE_STATES> resource_states;
unsigned active_queries = 0;
bool render_pass = false, predication = false, indirect_state_unknown = false, closed = false;
explicit Recording(ID3D12GraphicsCommandList* list) : original(list) {}
};
std::unordered_map<ID3D12GraphicsCommandList*, std::shared_ptr<Recording>> recordings;
std::shared_ptr<Recording> get_recording(ID3D12GraphicsCommandList* self, bool create = true) {
if (internal) return {};
std::lock_guard<std::mutex> lock(map_mutex);
auto found = recordings.find(self);
if (found != recordings.end()) return found->second;
if (!create) return {};
auto value = std::make_shared<Recording>(self);
recordings.emplace(self, value); return value;
}
void forget(ID3D12GraphicsCommandList* self) {
std::shared_ptr<Recording> released;
{ std::lock_guard<std::mutex> lock(map_mutex);
auto it = recordings.find(self);
if (it != recordings.end()) { released = std::move(it->second); recordings.erase(it); } }
// Release retained COM objects without holding the map mutex.
}
struct Access {
std::shared_ptr<Recording> recording;
std::unique_lock<std::recursive_mutex> lock;
ID3D12GraphicsCommandList* self;
explicit Access(ID3D12GraphicsCommandList* list) : recording(get_recording(list)), self(list) {
if (recording) lock = std::unique_lock<std::recursive_mutex>(recording->mutex);
}
ID3D12GraphicsCommandList* target() const {
return recording && recording->current ? recording->current.Get() : self;
}
};
template<class T> ComPtr<T> retain(T* pointer) { return ComPtr<T>(pointer); }
template<class T> std::vector<T> copy_values(const T* pointer, size_t count) {
return pointer ? std::vector<T>(pointer, pointer + count) : std::vector<T>();
}
template<class T> T* values_pointer(std::vector<T>& values) { return values.empty() ? nullptr : values.data(); }
template<class T> struct RetainedArray { std::vector<ComPtr<T>> owners; std::vector<T*> raw; };
template<class T> RetainedArray<T> retain_values(T* const* pointer, size_t count) {
RetainedArray<T> result;
for (size_t i = 0; pointer && i < count; ++i) { result.owners.emplace_back(pointer[i]); result.raw.push_back(pointer[i]); }
return result;
}
struct Hook { void* target; void* replacement; };
std::vector<Hook> attached;
void attach_method(void* target, void* replacement, void** original, const char* name) {
for (const auto& hook : attached) if (hook.target == target)
throw std::runtime_error(std::string("Shared D3D12 implementation needs an explicit alias adapter: ") + name);
const auto result = MH_CreateHook(target, replacement, original);
if (result != MH_OK) throw std::runtime_error(std::string("Cannot intercept D3D12 ") + name + ": " + MH_StatusToString(result));
attached.push_back({target, replacement});
std::printf("D4R_D3D12_HOOK method=%s\n", name);
}
#include "d3d12_command_hooks.generated.h"
using ReleaseFn = ULONG(STDMETHODCALLTYPE*)(IUnknown*);
ReleaseFn original_release = nullptr;
ULONG STDMETHODCALLTYPE hook_release(IUnknown* self) {
const ULONG count = original_release(self);
if (!count) forget(reinterpret_cast<ID3D12GraphicsCommandList*>(self));
return count;
}
HRESULT STDMETHODCALLTYPE hook_Close(ID3D12GraphicsCommandList* self) {
Access access(self);
const auto result = original_Close(access.target());
if (SUCCEEDED(result) && access.recording) access.recording->closed = true;
return result;
}
HRESULT STDMETHODCALLTYPE hook_Reset(ID3D12GraphicsCommandList* self, ID3D12CommandAllocator* allocator, ID3D12PipelineState* initial_state) {
if (internal) return original_Reset(self, allocator, initial_state);
forget(self);
const auto result = original_Reset(self, allocator, initial_state);
if (SUCCEEDED(result)) {
auto recording = get_recording(self);
auto pipeline = retain(initial_state);
recording->state.emplace_back([pipeline](ID3D12GraphicsCommandList* target) {
if (pipeline) original_SetPipelineState(target, pipeline.Get());
});
}
return result;
}
void STDMETHODCALLTYPE hook_ClearState(ID3D12GraphicsCommandList* self, ID3D12PipelineState* pipeline_state) {
Access access(self);
if (access.recording) {
access.recording->state.clear(); access.recording->indirect_state_unknown = false;
auto pipeline = retain(pipeline_state);
access.recording->state.emplace_back([pipeline](ID3D12GraphicsCommandList* target) { original_ClearState(target, pipeline.Get()); });
}
original_ClearState(access.target(), pipeline_state);
}
void STDMETHODCALLTYPE hook_ResourceBarrier(ID3D12GraphicsCommandList* self, UINT barrier_count, const D3D12_RESOURCE_BARRIER* barriers) {
Access access(self);
if (access.recording) for (UINT i = 0; i < barrier_count; ++i)
if (barriers[i].Type == D3D12_RESOURCE_BARRIER_TYPE_TRANSITION && barriers[i].Flags != D3D12_RESOURCE_BARRIER_FLAG_BEGIN_ONLY)
access.recording->resource_states[barriers[i].Transition.pResource] = barriers[i].Transition.StateAfter;
original_ResourceBarrier(access.target(), barrier_count, barriers);
}
void STDMETHODCALLTYPE hook_Barrier(ID3D12GraphicsCommandList* self, UINT32 barrier_groups_count, const D3D12_BARRIER_GROUP* barrier_groups) {
Access access(self);
original_Barrier(access.target(), barrier_groups_count, barrier_groups);
// Enhanced layout-to-legacy conversion is an explicit subsequent gate.
}
void STDMETHODCALLTYPE hook_BeginEvent(ID3D12GraphicsCommandList* self, UINT metadata, const void* data, UINT size) {
Access access(self);
if (access.recording) access.recording->events.push_back({metadata, copy_values(static_cast<const uint8_t*>(data), size)});
original_BeginEvent(access.target(), metadata, data, size);
}
void STDMETHODCALLTYPE hook_EndEvent(ID3D12GraphicsCommandList* self) {
Access access(self);
if (access.recording && !access.recording->events.empty()) access.recording->events.pop_back();
original_EndEvent(access.target());
}
void STDMETHODCALLTYPE hook_BeginRenderPass(ID3D12GraphicsCommandList* self, UINT render_target_count,
const D3D12_RENDER_PASS_RENDER_TARGET_DESC* render_targets, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* depth_stencil, D3D12_RENDER_PASS_FLAGS flags) {
Access access(self); if (access.recording) access.recording->render_pass = true;
original_BeginRenderPass(access.target(), render_target_count, render_targets, depth_stencil, flags);
}
void STDMETHODCALLTYPE hook_EndRenderPass(ID3D12GraphicsCommandList* self) {
Access access(self); if (access.recording) access.recording->render_pass = false;
original_EndRenderPass(access.target());
}
void STDMETHODCALLTYPE hook_BeginQuery(ID3D12GraphicsCommandList* self, ID3D12QueryHeap* heap, D3D12_QUERY_TYPE type, UINT index) {
Access access(self); if (access.recording) ++access.recording->active_queries;
original_BeginQuery(access.target(), heap, type, index);
}
void STDMETHODCALLTYPE hook_EndQuery(ID3D12GraphicsCommandList* self, ID3D12QueryHeap* heap, D3D12_QUERY_TYPE type, UINT index) {
Access access(self); if (access.recording && access.recording->active_queries) --access.recording->active_queries;
original_EndQuery(access.target(), heap, type, index);
}
void STDMETHODCALLTYPE hook_SetPredication(ID3D12GraphicsCommandList* self, ID3D12Resource* buffer, UINT64 aligned_buffer_offset, D3D12_PREDICATION_OP operation) {
Access access(self);
if (access.recording) {
access.recording->predication = buffer != nullptr;
auto retained = retain(buffer);
access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) { original_SetPredication(target, retained.Get(), aligned_buffer_offset, operation); });
}
original_SetPredication(access.target(), buffer, aligned_buffer_offset, operation);
}
void STDMETHODCALLTYPE hook_ExecuteBundle(ID3D12GraphicsCommandList* self, ID3D12GraphicsCommandList* command_list) {
Access access(self);
auto bundle = get_recording(command_list, false);
if (access.recording && bundle) {
std::lock_guard<std::recursive_mutex> lock(bundle->mutex);
access.recording->state.insert(access.recording->state.end(), bundle->state.begin(), bundle->state.end());
access.recording->indirect_state_unknown |= bundle->indirect_state_unknown;
} else if (access.recording) access.recording->indirect_state_unknown = true;
original_ExecuteBundle(access.target(), command_list);
}
void STDMETHODCALLTYPE hook_ExecuteIndirect(ID3D12GraphicsCommandList* self, ID3D12CommandSignature* command_signature,
UINT max_command_count, ID3D12Resource* arg_buffer, UINT64 arg_buffer_offset, ID3D12Resource* count_buffer, UINT64 count_buffer_offset) {
Access access(self);
if (access.recording) access.recording->indirect_state_unknown = true;
original_ExecuteIndirect(access.target(), command_signature, max_command_count, arg_buffer, arg_buffer_offset, count_buffer, count_buffer_offset);
}
using ExecuteFn = void(STDMETHODCALLTYPE*)(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*);
ExecuteFn original_execute = nullptr;
void complete(ID3D12CommandQueue* queue) {
ComPtr<ID3D12Device> device; dx(queue->GetDevice(IID_PPV_ARGS(device.GetAddressOf())), "Queue device(submit drain)");
ComPtr<ID3D12Fence> fence; dx(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())), "Queue fence(submit drain)");
Handle event; event.value = CreateEventW(nullptr, FALSE, FALSE, nullptr);
if (!event.value) throw std::runtime_error("CreateEvent(submit drain)");
dx(queue->Signal(fence.Get(), 1), "Queue Signal(submit drain)");
if (fence->GetCompletedValue() < 1) {
dx(fence->SetEventOnCompletion(1, event.value), "Queue event(submit drain)");
if (WaitForSingleObject(event.value, 30000) != WAIT_OBJECT_0) throw std::runtime_error("GPU submit boundary timed out");
}
}
void STDMETHODCALLTYPE hook_execute(ID3D12CommandQueue* queue, UINT count, ID3D12CommandList* const* lists) {
if (internal) { original_execute(queue, count, lists); return; }
std::vector<std::shared_ptr<Recording>> owners;
std::vector<ID3D12CommandList*> pending;
InternalScope scope;
auto flush = [&] { if (!pending.empty()) { original_execute(queue, UINT(pending.size()), pending.data()); pending.clear(); } };
bool boundaries = false;
try {
for (UINT i = 0; i < count; ++i) {
std::shared_ptr<Recording> recording;
{ std::lock_guard<std::mutex> lock(map_mutex);
auto found = recordings.find(static_cast<ID3D12GraphicsCommandList*>(lists[i]));
if (found != recordings.end()) recording = found->second; }
if (!recording || recording->segments.empty()) { pending.push_back(lists[i]); continue; }
std::lock_guard<std::recursive_mutex> lock(recording->mutex);
if (!recording->closed) throw std::runtime_error("Logical command list submitted before Close");
owners.push_back(recording); boundaries = true;
for (const auto& segment : recording->segments) {
pending.push_back(segment.list); flush();
segment.boundary(queue);
}
pending.push_back(recording->current.Get());
}
flush();
if (boundaries) complete(queue);
} catch (const std::exception& failure) {
{ std::lock_guard<std::mutex> lock(error_mutex); last_error = failure.what(); }
std::fprintf(stderr, "D4R_D3D12_SUBMIT_FAILURE %s\n", failure.what());
try { complete(queue); } catch (...) {}
// Do not submit a consumer suffix after a failed DLSS boundary.
}
}
}
InternalScope::InternalScope() : previous(internal) { internal = true; }
InternalScope::~InternalScope() { internal = previous; }
std::string error() { std::lock_guard<std::mutex> lock(error_mutex); return last_error; }
size_t live_recordings() { std::lock_guard<std::mutex> lock(map_mutex); return recordings.size(); }
D3D12_RESOURCE_STATES resource_state(ID3D12GraphicsCommandList* list, ID3D12Resource* resource, D3D12_RESOURCE_STATES fallback) {
auto recording = get_recording(list, false);
if (!recording) return fallback;
std::lock_guard<std::recursive_mutex> lock(recording->mutex);
auto found = recording->resource_states.find(resource);
return found == recording->resource_states.end() ? fallback : found->second;
}
void install(ID3D12Device* device) {
std::lock_guard<std::mutex> lock(installation_mutex);
if (installed) return;
InternalScope scope;
// An application may unload its NGX handle while native D3D12 objects are
// still alive. Public method callbacks must remain callable until exit.
HMODULE owner = nullptr;
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN,
reinterpret_cast<LPCWSTR>(&install), &owner)) throw std::runtime_error("Cannot retain the D3D12 callback module");
const auto init = MH_Initialize();
if (init != MH_OK && init != MH_ERROR_ALREADY_INITIALIZED) throw std::runtime_error(MH_StatusToString(init));
ComPtr<ID3D12CommandAllocator> allocator; ComPtr<ID3D12GraphicsCommandList> list;
dx(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(allocator.GetAddressOf())), "Create hook allocator");
dx(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, allocator.Get(), nullptr, IID_PPV_ARGS(list.GetAddressOf())), "Create hook command list");
try {
// The public COM interface inherits one ordered method table.
unsigned version = 0;
ComPtr<IUnknown> newest;
const GUID* ids[] = {&IID_ID3D12GraphicsCommandList, &IID_ID3D12GraphicsCommandList1, &IID_ID3D12GraphicsCommandList2,
&IID_ID3D12GraphicsCommandList3, &IID_ID3D12GraphicsCommandList4, &IID_ID3D12GraphicsCommandList5,
&IID_ID3D12GraphicsCommandList6, &IID_ID3D12GraphicsCommandList7};
for (unsigned n = 0; n < 8; ++n) if (SUCCEEDED(list->QueryInterface(*ids[n], reinterpret_cast<void**>(newest.ReleaseAndGetAddressOf())))) version = n;
auto table = *reinterpret_cast<void***>(list.Get());
attach_recording_methods(table, version);
attach_method(table[2], reinterpret_cast<void*>(hook_release), reinterpret_cast<void**>(&original_release), "Release");
D3D12_COMMAND_QUEUE_DESC desc{}; desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ComPtr<ID3D12CommandQueue> queue; dx(device->CreateCommandQueue(&desc, IID_PPV_ARGS(queue.GetAddressOf())), "Create hook queue");
auto queueTable = *reinterpret_cast<void***>(queue.Get());
// Queue inherits IUnknown, Object, DeviceChild; UpdateTileMappings,
// CopyTileMappings precede ExecuteCommandLists in the public SDK.
attach_method(queueTable[10], reinterpret_cast<void*>(hook_execute), reinterpret_cast<void**>(&original_execute), "ExecuteCommandLists");
for (const auto& hook : attached) {
const auto result = MH_QueueEnableHook(hook.target);
if (result != MH_OK) throw std::runtime_error(MH_StatusToString(result));
}
const auto result = MH_ApplyQueued();
if (result != MH_OK) throw std::runtime_error(MH_StatusToString(result));
installed = true;
std::printf("D4R_D3D12_COMMAND_BACKEND installed=1 interface=%u hooks=%zu frame_age=0\n", version, attached.size());
} catch (...) {
for (const auto& hook : attached) { (void)MH_DisableHook(hook.target); (void)MH_RemoveHook(hook.target); }
attached.clear(); throw;
}
}
void record_boundary(ID3D12GraphicsCommandList* list, Boundary callback) {
if (!installed || !list || !callback) throw std::runtime_error("D3D12 command backend is not initialized");
if (!error().empty()) throw std::runtime_error(error());
if (list->GetType() != D3D12_COMMAND_LIST_TYPE_DIRECT) throw std::runtime_error("DLSS requires a direct command list");
Access access(list);
auto& recording = *access.recording;
if (recording.closed || recording.render_pass || recording.active_queries || recording.predication || recording.indirect_state_unknown)
throw std::runtime_error("Cannot split a closed list or an active render/query/predication/unknown indirect state scope");
// Construct/replay the suffix before modifying the original list so an
// allocation failure leaves the caller's recording intact.
InternalScope scope;
ComPtr<ID3D12Device> device; dx(list->GetDevice(IID_PPV_ARGS(device.GetAddressOf())), "Boundary device");
Segment segment; segment.list = access.target(); segment.owner = recording.current;
segment.allocator = recording.current_allocator; segment.boundary = std::move(callback);
ComPtr<ID3D12CommandAllocator> nextAllocator; ComPtr<ID3D12GraphicsCommandList> next;
dx(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(nextAllocator.GetAddressOf())), "Suffix allocator");
dx(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, nextAllocator.Get(), nullptr, IID_PPV_ARGS(next.GetAddressOf())), "Suffix command list");
for (auto& state : recording.state) state(next.Get());
recording.segments.reserve(recording.segments.size() + 1);
for (const auto& event : recording.events) original_BeginEvent(next.Get(), event.metadata, event.data.data(), UINT(event.data.size()));
for (size_t n = 0; n < recording.events.size(); ++n) original_EndEvent(segment.list);
dx(original_Close(segment.list), "Close boundary prefix");
// Each suffix owns an independent allocator until GPU completion/reset.
recording.segments.push_back(std::move(segment));
recording.current_allocator = std::move(nextAllocator);
recording.current = std::move(next);
std::printf("D4R_D3D12_RECORD boundary=%zu state_calls=%zu frame_age=0\n", recording.segments.size(), recording.state.size());
}
}
@@ -0,0 +1,653 @@
// Generated by generate_d3d12_hooks.py from the public SDK. Do not edit.
using Fn_Close = HRESULT(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self);
static Fn_Close original_Close = nullptr;
static HRESULT STDMETHODCALLTYPE hook_Close(ID3D12GraphicsCommandList* self);
using Fn_Reset = HRESULT(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12CommandAllocator *allocator, ID3D12PipelineState *initial_state);
static Fn_Reset original_Reset = nullptr;
static HRESULT STDMETHODCALLTYPE hook_Reset(ID3D12GraphicsCommandList* self, ID3D12CommandAllocator *allocator, ID3D12PipelineState *initial_state);
using Fn_ClearState = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12PipelineState *pipeline_state);
static Fn_ClearState original_ClearState = nullptr;
static void STDMETHODCALLTYPE hook_ClearState(ID3D12GraphicsCommandList* self, ID3D12PipelineState *pipeline_state);
using Fn_DrawInstanced = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT vertex_count_per_instance, UINT instance_count, UINT start_vertex_location, UINT start_instance_location);
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) {
Access access(self);
return original_DrawInstanced(access.target(), vertex_count_per_instance, instance_count, start_vertex_location, start_instance_location);
}
using Fn_DrawIndexedInstanced = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT index_count_per_instance, UINT instance_count, UINT start_vertex_location, INT base_vertex_location, UINT start_instance_location);
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) {
Access access(self);
return original_DrawIndexedInstanced(access.target(), index_count_per_instance, instance_count, start_vertex_location, base_vertex_location, start_instance_location);
}
using Fn_Dispatch = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT x, UINT u, UINT z);
static Fn_Dispatch original_Dispatch = nullptr;
static void STDMETHODCALLTYPE hook_Dispatch(ID3D12GraphicsCommandList* self, UINT x, UINT u, UINT z) {
Access access(self);
return original_Dispatch(access.target(), x, u, z);
}
using Fn_CopyBufferRegion = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_buffer, UINT64 dst_offset, ID3D12Resource *src_buffer, UINT64 src_offset, UINT64 byte_count);
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) {
Access access(self);
return original_CopyBufferRegion(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, byte_count);
}
using Fn_CopyTextureRegion = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_CopyTextureRegion(access.target(), dst, dst_x, dst_y, dst_z, src, src_box);
}
using Fn_CopyResource = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, ID3D12Resource *src_resource);
static Fn_CopyResource original_CopyResource = nullptr;
static void STDMETHODCALLTYPE hook_CopyResource(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, ID3D12Resource *src_resource) {
Access access(self);
return original_CopyResource(access.target(), dst_resource, src_resource);
}
using Fn_CopyTiles = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_CopyTiles(access.target(), tiled_resource, tile_region_start_coordinate, tile_region_size, buffer, buffer_offset, flags);
}
using Fn_ResolveSubresource = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12Resource *dst_resource, UINT dst_sub_resource, ID3D12Resource *src_resource, UINT src_sub_resource, DXGI_FORMAT format);
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) {
Access access(self);
return original_ResolveSubresource(access.target(), dst_resource, dst_sub_resource, src_resource, src_sub_resource, format);
}
using Fn_IASetPrimitiveTopology = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, D3D12_PRIMITIVE_TOPOLOGY primitive_topology);
static Fn_IASetPrimitiveTopology original_IASetPrimitiveTopology = nullptr;
static void STDMETHODCALLTYPE hook_IASetPrimitiveTopology(ID3D12GraphicsCommandList* self, D3D12_PRIMITIVE_TOPOLOGY primitive_topology) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_IASetPrimitiveTopology(target, primitive_topology);
});
return original_IASetPrimitiveTopology(access.target(), primitive_topology);
}
using Fn_RSSetViewports = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT viewport_count, const D3D12_VIEWPORT *viewports);
static Fn_RSSetViewports original_RSSetViewports = nullptr;
static void STDMETHODCALLTYPE hook_RSSetViewports(ID3D12GraphicsCommandList* self, UINT viewport_count, const D3D12_VIEWPORT *viewports) {
Access access(self);
auto saved_viewports = copy_values(viewports, viewport_count);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetViewports(target, viewport_count, values_pointer(saved_viewports));
});
return original_RSSetViewports(access.target(), viewport_count, viewports);
}
using Fn_RSSetScissorRects = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT rect_count, const D3D12_RECT *rects);
static Fn_RSSetScissorRects original_RSSetScissorRects = nullptr;
static void STDMETHODCALLTYPE hook_RSSetScissorRects(ID3D12GraphicsCommandList* self, UINT rect_count, const D3D12_RECT *rects) {
Access access(self);
auto saved_rects = copy_values(rects, rect_count);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetScissorRects(target, rect_count, values_pointer(saved_rects));
});
return original_RSSetScissorRects(access.target(), rect_count, rects);
}
using Fn_OMSetBlendFactor = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, const FLOAT blend_factor[4]);
static Fn_OMSetBlendFactor original_OMSetBlendFactor = nullptr;
static void STDMETHODCALLTYPE hook_OMSetBlendFactor(ID3D12GraphicsCommandList* self, const FLOAT blend_factor[4]) {
Access access(self);
auto saved_blend_factor = copy_values(blend_factor, 4);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetBlendFactor(target, values_pointer(saved_blend_factor));
});
return original_OMSetBlendFactor(access.target(), blend_factor);
}
using Fn_OMSetStencilRef = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT stencil_ref);
static Fn_OMSetStencilRef original_OMSetStencilRef = nullptr;
static void STDMETHODCALLTYPE hook_OMSetStencilRef(ID3D12GraphicsCommandList* self, UINT stencil_ref) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetStencilRef(target, stencil_ref);
});
return original_OMSetStencilRef(access.target(), stencil_ref);
}
using Fn_SetPipelineState = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12PipelineState *pipeline_state);
static Fn_SetPipelineState original_SetPipelineState = nullptr;
static void STDMETHODCALLTYPE hook_SetPipelineState(ID3D12GraphicsCommandList* self, ID3D12PipelineState *pipeline_state) {
Access access(self);
auto saved_pipeline_state = retain(pipeline_state);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetPipelineState(target, saved_pipeline_state.Get());
});
return original_SetPipelineState(access.target(), pipeline_state);
}
using Fn_ResourceBarrier = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers);
static Fn_ResourceBarrier original_ResourceBarrier = nullptr;
static void STDMETHODCALLTYPE hook_ResourceBarrier(ID3D12GraphicsCommandList* self, UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers);
using Fn_ExecuteBundle = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12GraphicsCommandList *command_list);
static Fn_ExecuteBundle original_ExecuteBundle = nullptr;
static void STDMETHODCALLTYPE hook_ExecuteBundle(ID3D12GraphicsCommandList* self, ID3D12GraphicsCommandList *command_list);
using Fn_SetDescriptorHeaps = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT heap_count, ID3D12DescriptorHeap *const *heaps);
static Fn_SetDescriptorHeaps original_SetDescriptorHeaps = nullptr;
static void STDMETHODCALLTYPE hook_SetDescriptorHeaps(ID3D12GraphicsCommandList* self, UINT heap_count, ID3D12DescriptorHeap *const *heaps) {
Access access(self);
auto saved_heaps = retain_values(heaps, heap_count);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetDescriptorHeaps(target, heap_count, saved_heaps.raw.data());
});
return original_SetDescriptorHeaps(access.target(), heap_count, heaps);
}
using Fn_SetComputeRootSignature = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12RootSignature *root_signature);
static Fn_SetComputeRootSignature original_SetComputeRootSignature = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRootSignature(ID3D12GraphicsCommandList* self, ID3D12RootSignature *root_signature) {
Access access(self);
auto saved_root_signature = retain(root_signature);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootSignature(target, saved_root_signature.Get());
});
return original_SetComputeRootSignature(access.target(), root_signature);
}
using Fn_SetGraphicsRootSignature = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12RootSignature *root_signature);
static Fn_SetGraphicsRootSignature original_SetGraphicsRootSignature = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRootSignature(ID3D12GraphicsCommandList* self, ID3D12RootSignature *root_signature) {
Access access(self);
auto saved_root_signature = retain(root_signature);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootSignature(target, saved_root_signature.Get());
});
return original_SetGraphicsRootSignature(access.target(), root_signature);
}
using Fn_SetComputeRootDescriptorTable = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
static Fn_SetComputeRootDescriptorTable original_SetComputeRootDescriptorTable = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRootDescriptorTable(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootDescriptorTable(target, root_parameter_index, base_descriptor);
});
return original_SetComputeRootDescriptorTable(access.target(), root_parameter_index, base_descriptor);
}
using Fn_SetGraphicsRootDescriptorTable = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor);
static Fn_SetGraphicsRootDescriptorTable original_SetGraphicsRootDescriptorTable = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_DESCRIPTOR_HANDLE base_descriptor) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootDescriptorTable(target, root_parameter_index, base_descriptor);
});
return original_SetGraphicsRootDescriptorTable(access.target(), root_parameter_index, base_descriptor);
}
using Fn_SetComputeRoot32BitConstant = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT data, UINT dst_offset);
static Fn_SetComputeRoot32BitConstant original_SetComputeRoot32BitConstant = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRoot32BitConstant(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT data, UINT dst_offset) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRoot32BitConstant(target, root_parameter_index, data, dst_offset);
});
return original_SetComputeRoot32BitConstant(access.target(), root_parameter_index, data, dst_offset);
}
using Fn_SetGraphicsRoot32BitConstant = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT data, UINT dst_offset);
static Fn_SetGraphicsRoot32BitConstant original_SetGraphicsRoot32BitConstant = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRoot32BitConstant(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT data, UINT dst_offset) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRoot32BitConstant(target, root_parameter_index, data, dst_offset);
});
return original_SetGraphicsRoot32BitConstant(access.target(), root_parameter_index, data, dst_offset);
}
using Fn_SetComputeRoot32BitConstants = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset);
static Fn_SetComputeRoot32BitConstants original_SetComputeRoot32BitConstants = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRoot32BitConstants(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset) {
Access access(self);
auto saved_data = copy_values(static_cast<const UINT*>(data), constant_count);
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);
});
return original_SetComputeRoot32BitConstants(access.target(), root_parameter_index, constant_count, data, dst_offset);
}
using Fn_SetGraphicsRoot32BitConstants = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset);
static Fn_SetGraphicsRoot32BitConstants original_SetGraphicsRoot32BitConstants = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRoot32BitConstants(ID3D12GraphicsCommandList* self, UINT root_parameter_index, UINT constant_count, const void *data, UINT dst_offset) {
Access access(self);
auto saved_data = copy_values(static_cast<const UINT*>(data), constant_count);
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);
});
return original_SetGraphicsRoot32BitConstants(access.target(), root_parameter_index, constant_count, data, dst_offset);
}
using Fn_SetComputeRootConstantBufferView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
static Fn_SetComputeRootConstantBufferView original_SetComputeRootConstantBufferView = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRootConstantBufferView(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootConstantBufferView(target, root_parameter_index, address);
});
return original_SetComputeRootConstantBufferView(access.target(), root_parameter_index, address);
}
using Fn_SetGraphicsRootConstantBufferView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
static Fn_SetGraphicsRootConstantBufferView original_SetGraphicsRootConstantBufferView = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRootConstantBufferView(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootConstantBufferView(target, root_parameter_index, address);
});
return original_SetGraphicsRootConstantBufferView(access.target(), root_parameter_index, address);
}
using Fn_SetComputeRootShaderResourceView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
static Fn_SetComputeRootShaderResourceView original_SetComputeRootShaderResourceView = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRootShaderResourceView(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootShaderResourceView(target, root_parameter_index, address);
});
return original_SetComputeRootShaderResourceView(access.target(), root_parameter_index, address);
}
using Fn_SetGraphicsRootShaderResourceView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
static Fn_SetGraphicsRootShaderResourceView original_SetGraphicsRootShaderResourceView = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRootShaderResourceView(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootShaderResourceView(target, root_parameter_index, address);
});
return original_SetGraphicsRootShaderResourceView(access.target(), root_parameter_index, address);
}
using Fn_SetComputeRootUnorderedAccessView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
static Fn_SetComputeRootUnorderedAccessView original_SetComputeRootUnorderedAccessView = nullptr;
static void STDMETHODCALLTYPE hook_SetComputeRootUnorderedAccessView(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetComputeRootUnorderedAccessView(target, root_parameter_index, address);
});
return original_SetComputeRootUnorderedAccessView(access.target(), root_parameter_index, address);
}
using Fn_SetGraphicsRootUnorderedAccessView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address);
static Fn_SetGraphicsRootUnorderedAccessView original_SetGraphicsRootUnorderedAccessView = nullptr;
static void STDMETHODCALLTYPE hook_SetGraphicsRootUnorderedAccessView(ID3D12GraphicsCommandList* self, UINT root_parameter_index, D3D12_GPU_VIRTUAL_ADDRESS address) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetGraphicsRootUnorderedAccessView(target, root_parameter_index, address);
});
return original_SetGraphicsRootUnorderedAccessView(access.target(), root_parameter_index, address);
}
using Fn_IASetIndexBuffer = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, const D3D12_INDEX_BUFFER_VIEW *view);
static Fn_IASetIndexBuffer original_IASetIndexBuffer = nullptr;
static void STDMETHODCALLTYPE hook_IASetIndexBuffer(ID3D12GraphicsCommandList* self, const D3D12_INDEX_BUFFER_VIEW *view) {
Access access(self);
auto saved_view = copy_values(view, 1);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_IASetIndexBuffer(target, values_pointer(saved_view));
});
return original_IASetIndexBuffer(access.target(), view);
}
using Fn_IASetVertexBuffers = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT start_slot, UINT view_count, const D3D12_VERTEX_BUFFER_VIEW *views);
static Fn_IASetVertexBuffers original_IASetVertexBuffers = nullptr;
static void STDMETHODCALLTYPE hook_IASetVertexBuffers(ID3D12GraphicsCommandList* self, UINT start_slot, UINT view_count, const D3D12_VERTEX_BUFFER_VIEW *views) {
Access access(self);
auto saved_views = copy_values(views, view_count);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_IASetVertexBuffers(target, start_slot, view_count, values_pointer(saved_views));
});
return original_IASetVertexBuffers(access.target(), start_slot, view_count, views);
}
using Fn_SOSetTargets = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT start_slot, UINT view_count, const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views);
static Fn_SOSetTargets original_SOSetTargets = nullptr;
static void STDMETHODCALLTYPE hook_SOSetTargets(ID3D12GraphicsCommandList* self, UINT start_slot, UINT view_count, const D3D12_STREAM_OUTPUT_BUFFER_VIEW *views) {
Access access(self);
auto saved_views = copy_values(views, view_count);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SOSetTargets(target, start_slot, view_count, values_pointer(saved_views));
});
return original_SOSetTargets(access.target(), start_slot, view_count, views);
}
using Fn_OMSetRenderTargets = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, WINBOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor);
static Fn_OMSetRenderTargets original_OMSetRenderTargets = nullptr;
static void STDMETHODCALLTYPE hook_OMSetRenderTargets(ID3D12GraphicsCommandList* self, UINT render_target_descriptor_count, const D3D12_CPU_DESCRIPTOR_HANDLE *render_target_descriptors, WINBOOL single_descriptor_handle, const D3D12_CPU_DESCRIPTOR_HANDLE *depth_stencil_descriptor) {
Access access(self);
auto saved_render_target_descriptors = copy_values(render_target_descriptors, (single_descriptor_handle ? 1 : render_target_descriptor_count));
auto saved_depth_stencil_descriptor = copy_values(depth_stencil_descriptor, 1);
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));
});
return original_OMSetRenderTargets(access.target(), render_target_descriptor_count, render_target_descriptors, single_descriptor_handle, depth_stencil_descriptor);
}
using Fn_ClearDepthStencilView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, D3D12_CPU_DESCRIPTOR_HANDLE dsv, D3D12_CLEAR_FLAGS flags, FLOAT depth, UINT8 stencil, UINT rect_count, const D3D12_RECT *rects);
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) {
Access access(self);
return original_ClearDepthStencilView(access.target(), dsv, flags, depth, stencil, rect_count, rects);
}
using Fn_ClearRenderTargetView = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, D3D12_CPU_DESCRIPTOR_HANDLE rtv, const FLOAT color[4], UINT rect_count, const D3D12_RECT *rects);
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) {
Access access(self);
return original_ClearRenderTargetView(access.target(), rtv, color, rect_count, rects);
}
using Fn_ClearUnorderedAccessViewUint = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_ClearUnorderedAccessViewUint(access.target(), gpu_handle, cpu_handle, resource, values, rect_count, rects);
}
using Fn_ClearUnorderedAccessViewFloat = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_ClearUnorderedAccessViewFloat(access.target(), gpu_handle, cpu_handle, resource, values, rect_count, rects);
}
using Fn_DiscardResource = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12Resource *resource, const D3D12_DISCARD_REGION *region);
static Fn_DiscardResource original_DiscardResource = nullptr;
static void STDMETHODCALLTYPE hook_DiscardResource(ID3D12GraphicsCommandList* self, ID3D12Resource *resource, const D3D12_DISCARD_REGION *region) {
Access access(self);
return original_DiscardResource(access.target(), resource, region);
}
using Fn_BeginQuery = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index);
static Fn_BeginQuery original_BeginQuery = nullptr;
static void STDMETHODCALLTYPE hook_BeginQuery(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index);
using Fn_EndQuery = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index);
static Fn_EndQuery original_EndQuery = nullptr;
static void STDMETHODCALLTYPE hook_EndQuery(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT index);
using Fn_ResolveQueryData = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12QueryHeap *heap, D3D12_QUERY_TYPE type, UINT start_index, UINT query_count, ID3D12Resource *dst_buffer, UINT64 aligned_dst_buffer_offset);
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) {
Access access(self);
return original_ResolveQueryData(access.target(), heap, type, start_index, query_count, dst_buffer, aligned_dst_buffer_offset);
}
using Fn_SetPredication = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12Resource *buffer, UINT64 aligned_buffer_offset, D3D12_PREDICATION_OP operation);
static Fn_SetPredication original_SetPredication = nullptr;
static void STDMETHODCALLTYPE hook_SetPredication(ID3D12GraphicsCommandList* self, ID3D12Resource *buffer, UINT64 aligned_buffer_offset, D3D12_PREDICATION_OP operation);
using Fn_SetMarker = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT metadata, const void *data, UINT size);
static Fn_SetMarker original_SetMarker = nullptr;
static void STDMETHODCALLTYPE hook_SetMarker(ID3D12GraphicsCommandList* self, UINT metadata, const void *data, UINT size) {
Access access(self);
return original_SetMarker(access.target(), metadata, data, size);
}
using Fn_BeginEvent = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT metadata, const void *data, UINT size);
static Fn_BeginEvent original_BeginEvent = nullptr;
static void STDMETHODCALLTYPE hook_BeginEvent(ID3D12GraphicsCommandList* self, UINT metadata, const void *data, UINT size);
using Fn_EndEvent = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self);
static Fn_EndEvent original_EndEvent = nullptr;
static void STDMETHODCALLTYPE hook_EndEvent(ID3D12GraphicsCommandList* self);
using Fn_ExecuteIndirect = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12CommandSignature *command_signature, UINT max_command_count, ID3D12Resource *arg_buffer, UINT64 arg_buffer_offset, ID3D12Resource *count_buffer, UINT64 count_buffer_offset);
static Fn_ExecuteIndirect original_ExecuteIndirect = nullptr;
static void STDMETHODCALLTYPE hook_ExecuteIndirect(ID3D12GraphicsCommandList* self, ID3D12CommandSignature *command_signature, UINT max_command_count, ID3D12Resource *arg_buffer, UINT64 arg_buffer_offset, ID3D12Resource *count_buffer, UINT64 count_buffer_offset);
using Fn_AtomicCopyBufferUINT = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_AtomicCopyBufferUINT(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, dependent_resource_count, dependent_resources, dependent_sub_resource_ranges);
}
using Fn_AtomicCopyBufferUINT64 = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_AtomicCopyBufferUINT64(access.target(), dst_buffer, dst_offset, src_buffer, src_offset, dependent_resource_count, dependent_resources, dependent_sub_resource_ranges);
}
using Fn_OMSetDepthBounds = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, FLOAT min, FLOAT max);
static Fn_OMSetDepthBounds original_OMSetDepthBounds = nullptr;
static void STDMETHODCALLTYPE hook_OMSetDepthBounds(ID3D12GraphicsCommandList* self, FLOAT min, FLOAT max) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_OMSetDepthBounds(target, min, max);
});
return original_OMSetDepthBounds(access.target(), min, max);
}
using Fn_SetSamplePositions = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT sample_count, UINT pixel_count, D3D12_SAMPLE_POSITION *sample_positions);
static Fn_SetSamplePositions original_SetSamplePositions = nullptr;
static void STDMETHODCALLTYPE hook_SetSamplePositions(ID3D12GraphicsCommandList* self, UINT sample_count, UINT pixel_count, D3D12_SAMPLE_POSITION *sample_positions) {
Access access(self);
auto saved_sample_positions = copy_values(sample_positions, sample_count * pixel_count);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetSamplePositions(target, sample_count, pixel_count, values_pointer(saved_sample_positions));
});
return original_SetSamplePositions(access.target(), sample_count, pixel_count, sample_positions);
}
using Fn_ResolveSubresourceRegion = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
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);
}
using Fn_SetViewInstanceMask = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT mask);
static Fn_SetViewInstanceMask original_SetViewInstanceMask = nullptr;
static void STDMETHODCALLTYPE hook_SetViewInstanceMask(ID3D12GraphicsCommandList* self, UINT mask) {
Access access(self);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetViewInstanceMask(target, mask);
});
return original_SetViewInstanceMask(access.target(), mask);
}
using Fn_WriteBufferImmediate = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT count, const D3D12_WRITEBUFFERIMMEDIATE_PARAMETER *parameters, const D3D12_WRITEBUFFERIMMEDIATE_MODE *modes);
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) {
Access access(self);
return original_WriteBufferImmediate(access.target(), count, parameters, modes);
}
using Fn_SetProtectedResourceSession = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12ProtectedResourceSession *protected_resource_session);
static Fn_SetProtectedResourceSession original_SetProtectedResourceSession = nullptr;
static void STDMETHODCALLTYPE hook_SetProtectedResourceSession(ID3D12GraphicsCommandList* self, ID3D12ProtectedResourceSession *protected_resource_session) {
Access access(self);
auto saved_protected_resource_session = retain(protected_resource_session);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetProtectedResourceSession(target, saved_protected_resource_session.Get());
});
return original_SetProtectedResourceSession(access.target(), protected_resource_session);
}
using Fn_BeginRenderPass = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT render_targets_count, const D3D12_RENDER_PASS_RENDER_TARGET_DESC *render_targets, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC *depth_stencil, D3D12_RENDER_PASS_FLAGS flags);
static Fn_BeginRenderPass original_BeginRenderPass = nullptr;
static void STDMETHODCALLTYPE hook_BeginRenderPass(ID3D12GraphicsCommandList* self, UINT render_targets_count, const D3D12_RENDER_PASS_RENDER_TARGET_DESC *render_targets, const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC *depth_stencil, D3D12_RENDER_PASS_FLAGS flags);
using Fn_EndRenderPass = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self);
static Fn_EndRenderPass original_EndRenderPass = nullptr;
static void STDMETHODCALLTYPE hook_EndRenderPass(ID3D12GraphicsCommandList* self);
using Fn_InitializeMetaCommand = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12MetaCommand *meta_command, const void *initialization_parameters_data, SIZE_T initialization_parameters_data_size_in_bytes);
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) {
Access access(self);
return original_InitializeMetaCommand(access.target(), meta_command, initialization_parameters_data, initialization_parameters_data_size_in_bytes);
}
using Fn_ExecuteMetaCommand = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12MetaCommand *meta_command, const void *execution_parameters_data, SIZE_T execution_parameters_data_size_in_bytes);
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) {
Access access(self);
return original_ExecuteMetaCommand(access.target(), meta_command, execution_parameters_data, execution_parameters_data_size_in_bytes);
}
using Fn_BuildRaytracingAccelerationStructure = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_BuildRaytracingAccelerationStructure(access.target(), desc, postbuild_info_descs_count, postbuild_info_descs);
}
using Fn_EmitRaytracingAccelerationStructurePostbuildInfo = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_EmitRaytracingAccelerationStructurePostbuildInfo(access.target(), desc, src_acceleration_structures_count, src_acceleration_structure_data);
}
using Fn_CopyRaytracingAccelerationStructure = void(STDMETHODCALLTYPE*)(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 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) {
Access access(self);
return original_CopyRaytracingAccelerationStructure(access.target(), dst_acceleration_structure_data, src_acceleration_structure_data, mode);
}
using Fn_SetPipelineState1 = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12StateObject *state_object);
static Fn_SetPipelineState1 original_SetPipelineState1 = nullptr;
static void STDMETHODCALLTYPE hook_SetPipelineState1(ID3D12GraphicsCommandList* self, ID3D12StateObject *state_object) {
Access access(self);
auto saved_state_object = retain(state_object);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_SetPipelineState1(target, saved_state_object.Get());
});
return original_SetPipelineState1(access.target(), state_object);
}
using Fn_DispatchRays = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, const D3D12_DISPATCH_RAYS_DESC *desc);
static Fn_DispatchRays original_DispatchRays = nullptr;
static void STDMETHODCALLTYPE hook_DispatchRays(ID3D12GraphicsCommandList* self, const D3D12_DISPATCH_RAYS_DESC *desc) {
Access access(self);
return original_DispatchRays(access.target(), desc);
}
using Fn_RSSetShadingRate = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, D3D12_SHADING_RATE base_shading_rate, const D3D12_SHADING_RATE_COMBINER *combiners);
static Fn_RSSetShadingRate original_RSSetShadingRate = nullptr;
static void STDMETHODCALLTYPE hook_RSSetShadingRate(ID3D12GraphicsCommandList* self, D3D12_SHADING_RATE base_shading_rate, const D3D12_SHADING_RATE_COMBINER *combiners) {
Access access(self);
auto saved_combiners = copy_values(combiners, 2);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetShadingRate(target, base_shading_rate, values_pointer(saved_combiners));
});
return original_RSSetShadingRate(access.target(), base_shading_rate, combiners);
}
using Fn_RSSetShadingRateImage = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, ID3D12Resource *shading_rate_image);
static Fn_RSSetShadingRateImage original_RSSetShadingRateImage = nullptr;
static void STDMETHODCALLTYPE hook_RSSetShadingRateImage(ID3D12GraphicsCommandList* self, ID3D12Resource *shading_rate_image) {
Access access(self);
auto saved_shading_rate_image = retain(shading_rate_image);
if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {
original_RSSetShadingRateImage(target, saved_shading_rate_image.Get());
});
return original_RSSetShadingRateImage(access.target(), shading_rate_image);
}
using Fn_DispatchMesh = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT thread_group_count_x, UINT thread_group_count_y, UINT thread_group_count_z);
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) {
Access access(self);
return original_DispatchMesh(access.target(), thread_group_count_x, thread_group_count_y, thread_group_count_z);
}
using Fn_Barrier = void(STDMETHODCALLTYPE*)(ID3D12GraphicsCommandList* self, UINT32 barrier_groups_count, const D3D12_BARRIER_GROUP *barrier_groups);
static Fn_Barrier original_Barrier = nullptr;
static void STDMETHODCALLTYPE hook_Barrier(ID3D12GraphicsCommandList* self, UINT32 barrier_groups_count, const D3D12_BARRIER_GROUP *barrier_groups);
static void attach_recording_methods(void** table, unsigned version) {
if (version >= 0) attach_method(table[9], reinterpret_cast<void*>(hook_Close), reinterpret_cast<void**>(&original_Close), "Close");
if (version >= 0) attach_method(table[10], reinterpret_cast<void*>(hook_Reset), reinterpret_cast<void**>(&original_Reset), "Reset");
if (version >= 0) attach_method(table[11], reinterpret_cast<void*>(hook_ClearState), reinterpret_cast<void**>(&original_ClearState), "ClearState");
if (version >= 0) attach_method(table[12], reinterpret_cast<void*>(hook_DrawInstanced), reinterpret_cast<void**>(&original_DrawInstanced), "DrawInstanced");
if (version >= 0) attach_method(table[13], reinterpret_cast<void*>(hook_DrawIndexedInstanced), reinterpret_cast<void**>(&original_DrawIndexedInstanced), "DrawIndexedInstanced");
if (version >= 0) attach_method(table[14], reinterpret_cast<void*>(hook_Dispatch), reinterpret_cast<void**>(&original_Dispatch), "Dispatch");
if (version >= 0) attach_method(table[15], reinterpret_cast<void*>(hook_CopyBufferRegion), reinterpret_cast<void**>(&original_CopyBufferRegion), "CopyBufferRegion");
if (version >= 0) attach_method(table[16], reinterpret_cast<void*>(hook_CopyTextureRegion), reinterpret_cast<void**>(&original_CopyTextureRegion), "CopyTextureRegion");
if (version >= 0) attach_method(table[17], reinterpret_cast<void*>(hook_CopyResource), reinterpret_cast<void**>(&original_CopyResource), "CopyResource");
if (version >= 0) attach_method(table[18], reinterpret_cast<void*>(hook_CopyTiles), reinterpret_cast<void**>(&original_CopyTiles), "CopyTiles");
if (version >= 0) attach_method(table[19], reinterpret_cast<void*>(hook_ResolveSubresource), reinterpret_cast<void**>(&original_ResolveSubresource), "ResolveSubresource");
if (version >= 0) attach_method(table[20], reinterpret_cast<void*>(hook_IASetPrimitiveTopology), reinterpret_cast<void**>(&original_IASetPrimitiveTopology), "IASetPrimitiveTopology");
if (version >= 0) attach_method(table[21], reinterpret_cast<void*>(hook_RSSetViewports), reinterpret_cast<void**>(&original_RSSetViewports), "RSSetViewports");
if (version >= 0) attach_method(table[22], reinterpret_cast<void*>(hook_RSSetScissorRects), reinterpret_cast<void**>(&original_RSSetScissorRects), "RSSetScissorRects");
if (version >= 0) attach_method(table[23], reinterpret_cast<void*>(hook_OMSetBlendFactor), reinterpret_cast<void**>(&original_OMSetBlendFactor), "OMSetBlendFactor");
if (version >= 0) attach_method(table[24], reinterpret_cast<void*>(hook_OMSetStencilRef), reinterpret_cast<void**>(&original_OMSetStencilRef), "OMSetStencilRef");
if (version >= 0) attach_method(table[25], reinterpret_cast<void*>(hook_SetPipelineState), reinterpret_cast<void**>(&original_SetPipelineState), "SetPipelineState");
if (version >= 0) attach_method(table[26], reinterpret_cast<void*>(hook_ResourceBarrier), reinterpret_cast<void**>(&original_ResourceBarrier), "ResourceBarrier");
if (version >= 0) attach_method(table[27], reinterpret_cast<void*>(hook_ExecuteBundle), reinterpret_cast<void**>(&original_ExecuteBundle), "ExecuteBundle");
if (version >= 0) attach_method(table[28], reinterpret_cast<void*>(hook_SetDescriptorHeaps), reinterpret_cast<void**>(&original_SetDescriptorHeaps), "SetDescriptorHeaps");
if (version >= 0) attach_method(table[29], reinterpret_cast<void*>(hook_SetComputeRootSignature), reinterpret_cast<void**>(&original_SetComputeRootSignature), "SetComputeRootSignature");
if (version >= 0) attach_method(table[30], reinterpret_cast<void*>(hook_SetGraphicsRootSignature), reinterpret_cast<void**>(&original_SetGraphicsRootSignature), "SetGraphicsRootSignature");
if (version >= 0) attach_method(table[31], reinterpret_cast<void*>(hook_SetComputeRootDescriptorTable), reinterpret_cast<void**>(&original_SetComputeRootDescriptorTable), "SetComputeRootDescriptorTable");
if (version >= 0) attach_method(table[32], reinterpret_cast<void*>(hook_SetGraphicsRootDescriptorTable), reinterpret_cast<void**>(&original_SetGraphicsRootDescriptorTable), "SetGraphicsRootDescriptorTable");
if (version >= 0) attach_method(table[33], reinterpret_cast<void*>(hook_SetComputeRoot32BitConstant), reinterpret_cast<void**>(&original_SetComputeRoot32BitConstant), "SetComputeRoot32BitConstant");
if (version >= 0) attach_method(table[34], reinterpret_cast<void*>(hook_SetGraphicsRoot32BitConstant), reinterpret_cast<void**>(&original_SetGraphicsRoot32BitConstant), "SetGraphicsRoot32BitConstant");
if (version >= 0) attach_method(table[35], reinterpret_cast<void*>(hook_SetComputeRoot32BitConstants), reinterpret_cast<void**>(&original_SetComputeRoot32BitConstants), "SetComputeRoot32BitConstants");
if (version >= 0) attach_method(table[36], reinterpret_cast<void*>(hook_SetGraphicsRoot32BitConstants), reinterpret_cast<void**>(&original_SetGraphicsRoot32BitConstants), "SetGraphicsRoot32BitConstants");
if (version >= 0) attach_method(table[37], reinterpret_cast<void*>(hook_SetComputeRootConstantBufferView), reinterpret_cast<void**>(&original_SetComputeRootConstantBufferView), "SetComputeRootConstantBufferView");
if (version >= 0) attach_method(table[38], reinterpret_cast<void*>(hook_SetGraphicsRootConstantBufferView), reinterpret_cast<void**>(&original_SetGraphicsRootConstantBufferView), "SetGraphicsRootConstantBufferView");
if (version >= 0) attach_method(table[39], reinterpret_cast<void*>(hook_SetComputeRootShaderResourceView), reinterpret_cast<void**>(&original_SetComputeRootShaderResourceView), "SetComputeRootShaderResourceView");
if (version >= 0) attach_method(table[40], reinterpret_cast<void*>(hook_SetGraphicsRootShaderResourceView), reinterpret_cast<void**>(&original_SetGraphicsRootShaderResourceView), "SetGraphicsRootShaderResourceView");
if (version >= 0) attach_method(table[41], reinterpret_cast<void*>(hook_SetComputeRootUnorderedAccessView), reinterpret_cast<void**>(&original_SetComputeRootUnorderedAccessView), "SetComputeRootUnorderedAccessView");
if (version >= 0) attach_method(table[42], reinterpret_cast<void*>(hook_SetGraphicsRootUnorderedAccessView), reinterpret_cast<void**>(&original_SetGraphicsRootUnorderedAccessView), "SetGraphicsRootUnorderedAccessView");
if (version >= 0) attach_method(table[43], reinterpret_cast<void*>(hook_IASetIndexBuffer), reinterpret_cast<void**>(&original_IASetIndexBuffer), "IASetIndexBuffer");
if (version >= 0) attach_method(table[44], reinterpret_cast<void*>(hook_IASetVertexBuffers), reinterpret_cast<void**>(&original_IASetVertexBuffers), "IASetVertexBuffers");
if (version >= 0) attach_method(table[45], reinterpret_cast<void*>(hook_SOSetTargets), reinterpret_cast<void**>(&original_SOSetTargets), "SOSetTargets");
if (version >= 0) attach_method(table[46], reinterpret_cast<void*>(hook_OMSetRenderTargets), reinterpret_cast<void**>(&original_OMSetRenderTargets), "OMSetRenderTargets");
if (version >= 0) attach_method(table[47], reinterpret_cast<void*>(hook_ClearDepthStencilView), reinterpret_cast<void**>(&original_ClearDepthStencilView), "ClearDepthStencilView");
if (version >= 0) attach_method(table[48], reinterpret_cast<void*>(hook_ClearRenderTargetView), reinterpret_cast<void**>(&original_ClearRenderTargetView), "ClearRenderTargetView");
if (version >= 0) attach_method(table[49], reinterpret_cast<void*>(hook_ClearUnorderedAccessViewUint), reinterpret_cast<void**>(&original_ClearUnorderedAccessViewUint), "ClearUnorderedAccessViewUint");
if (version >= 0) attach_method(table[50], reinterpret_cast<void*>(hook_ClearUnorderedAccessViewFloat), reinterpret_cast<void**>(&original_ClearUnorderedAccessViewFloat), "ClearUnorderedAccessViewFloat");
if (version >= 0) attach_method(table[51], reinterpret_cast<void*>(hook_DiscardResource), reinterpret_cast<void**>(&original_DiscardResource), "DiscardResource");
if (version >= 0) attach_method(table[52], reinterpret_cast<void*>(hook_BeginQuery), reinterpret_cast<void**>(&original_BeginQuery), "BeginQuery");
if (version >= 0) attach_method(table[53], reinterpret_cast<void*>(hook_EndQuery), reinterpret_cast<void**>(&original_EndQuery), "EndQuery");
if (version >= 0) attach_method(table[54], reinterpret_cast<void*>(hook_ResolveQueryData), reinterpret_cast<void**>(&original_ResolveQueryData), "ResolveQueryData");
if (version >= 0) attach_method(table[55], reinterpret_cast<void*>(hook_SetPredication), reinterpret_cast<void**>(&original_SetPredication), "SetPredication");
if (version >= 0) attach_method(table[56], reinterpret_cast<void*>(hook_SetMarker), reinterpret_cast<void**>(&original_SetMarker), "SetMarker");
if (version >= 0) attach_method(table[57], reinterpret_cast<void*>(hook_BeginEvent), reinterpret_cast<void**>(&original_BeginEvent), "BeginEvent");
if (version >= 0) attach_method(table[58], reinterpret_cast<void*>(hook_EndEvent), reinterpret_cast<void**>(&original_EndEvent), "EndEvent");
if (version >= 0) attach_method(table[59], reinterpret_cast<void*>(hook_ExecuteIndirect), reinterpret_cast<void**>(&original_ExecuteIndirect), "ExecuteIndirect");
if (version >= 1) attach_method(table[60], reinterpret_cast<void*>(hook_AtomicCopyBufferUINT), reinterpret_cast<void**>(&original_AtomicCopyBufferUINT), "AtomicCopyBufferUINT");
if (version >= 1) attach_method(table[61], reinterpret_cast<void*>(hook_AtomicCopyBufferUINT64), reinterpret_cast<void**>(&original_AtomicCopyBufferUINT64), "AtomicCopyBufferUINT64");
if (version >= 1) attach_method(table[62], reinterpret_cast<void*>(hook_OMSetDepthBounds), reinterpret_cast<void**>(&original_OMSetDepthBounds), "OMSetDepthBounds");
if (version >= 1) attach_method(table[63], reinterpret_cast<void*>(hook_SetSamplePositions), reinterpret_cast<void**>(&original_SetSamplePositions), "SetSamplePositions");
if (version >= 1) attach_method(table[64], reinterpret_cast<void*>(hook_ResolveSubresourceRegion), reinterpret_cast<void**>(&original_ResolveSubresourceRegion), "ResolveSubresourceRegion");
if (version >= 1) attach_method(table[65], reinterpret_cast<void*>(hook_SetViewInstanceMask), reinterpret_cast<void**>(&original_SetViewInstanceMask), "SetViewInstanceMask");
if (version >= 2) attach_method(table[66], reinterpret_cast<void*>(hook_WriteBufferImmediate), reinterpret_cast<void**>(&original_WriteBufferImmediate), "WriteBufferImmediate");
if (version >= 3) attach_method(table[67], reinterpret_cast<void*>(hook_SetProtectedResourceSession), reinterpret_cast<void**>(&original_SetProtectedResourceSession), "SetProtectedResourceSession");
if (version >= 4) attach_method(table[68], reinterpret_cast<void*>(hook_BeginRenderPass), reinterpret_cast<void**>(&original_BeginRenderPass), "BeginRenderPass");
if (version >= 4) attach_method(table[69], reinterpret_cast<void*>(hook_EndRenderPass), reinterpret_cast<void**>(&original_EndRenderPass), "EndRenderPass");
if (version >= 4) attach_method(table[70], reinterpret_cast<void*>(hook_InitializeMetaCommand), reinterpret_cast<void**>(&original_InitializeMetaCommand), "InitializeMetaCommand");
if (version >= 4) attach_method(table[71], reinterpret_cast<void*>(hook_ExecuteMetaCommand), reinterpret_cast<void**>(&original_ExecuteMetaCommand), "ExecuteMetaCommand");
if (version >= 4) attach_method(table[72], reinterpret_cast<void*>(hook_BuildRaytracingAccelerationStructure), reinterpret_cast<void**>(&original_BuildRaytracingAccelerationStructure), "BuildRaytracingAccelerationStructure");
if (version >= 4) attach_method(table[73], reinterpret_cast<void*>(hook_EmitRaytracingAccelerationStructurePostbuildInfo), reinterpret_cast<void**>(&original_EmitRaytracingAccelerationStructurePostbuildInfo), "EmitRaytracingAccelerationStructurePostbuildInfo");
if (version >= 4) attach_method(table[74], reinterpret_cast<void*>(hook_CopyRaytracingAccelerationStructure), reinterpret_cast<void**>(&original_CopyRaytracingAccelerationStructure), "CopyRaytracingAccelerationStructure");
if (version >= 4) attach_method(table[75], reinterpret_cast<void*>(hook_SetPipelineState1), reinterpret_cast<void**>(&original_SetPipelineState1), "SetPipelineState1");
if (version >= 4) attach_method(table[76], reinterpret_cast<void*>(hook_DispatchRays), reinterpret_cast<void**>(&original_DispatchRays), "DispatchRays");
if (version >= 5) attach_method(table[77], reinterpret_cast<void*>(hook_RSSetShadingRate), reinterpret_cast<void**>(&original_RSSetShadingRate), "RSSetShadingRate");
if (version >= 5) attach_method(table[78], reinterpret_cast<void*>(hook_RSSetShadingRateImage), reinterpret_cast<void**>(&original_RSSetShadingRateImage), "RSSetShadingRateImage");
if (version >= 6) attach_method(table[79], reinterpret_cast<void*>(hook_DispatchMesh), reinterpret_cast<void**>(&original_DispatchMesh), "DispatchMesh");
if (version >= 7) attach_method(table[80], reinterpret_cast<void*>(hook_Barrier), reinterpret_cast<void**>(&original_Barrier), "Barrier");
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "d3d12_external.h"
#include <functional>
#include <string>
namespace d4r::win::commands {
// Intercept only documented D3D12 COM methods on this device's runtime.
// A boundary becomes prefix -> callback -> suffix at ExecuteCommandLists,
// preserving preceding lists in the caller's batch and current-frame output.
using Boundary = std::function<void(ID3D12CommandQueue*)>;
void install(ID3D12Device* device);
void record_boundary(ID3D12GraphicsCommandList* list, Boundary callback);
std::string error();
size_t live_recordings();
D3D12_RESOURCE_STATES resource_state(ID3D12GraphicsCommandList* list, ID3D12Resource* resource, D3D12_RESOURCE_STATES fallback);
// Internal copies and callback submissions must bypass logical list routing.
struct InternalScope {
bool previous;
InternalScope();
~InternalScope();
};
}
+163
View File
@@ -0,0 +1,163 @@
#include "d3d12_external.h"
#include <dxgi1_6.h>
#include <d3dcompiler.h>
#include <array>
using namespace d4r::diag;
using namespace d4r::win;
namespace {
constexpr unsigned count = 256, bytes = count * sizeof(uint32_t), seed = 0x12345;
void drain(ID3D12Device* device, ID3D12CommandQueue* queue) {
ComPtr<ID3D12Fence> fence; dx(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.GetAddressOf())), "Probe fence");
Handle event; event.value = CreateEventW(nullptr, FALSE, FALSE, nullptr);
if (!event.value) throw std::runtime_error("Probe event");
dx(queue->Signal(fence.Get(), 1), "Probe signal");
if (fence->GetCompletedValue() < 1) {
dx(fence->SetEventOnCompletion(1, event.value), "Probe fence event");
if (WaitForSingleObject(event.value, 30000) != WAIT_OBJECT_0) throw std::runtime_error("Probe GPU timeout");
}
}
struct NativeList {
ComPtr<ID3D12CommandAllocator> allocator;
ComPtr<ID3D12GraphicsCommandList> list;
explicit NativeList(ID3D12Device* device) {
dx(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(allocator.GetAddressOf())), "Probe allocator");
dx(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, allocator.Get(), nullptr, IID_PPV_ARGS(list.GetAddressOf())), "Probe command list");
}
void submit(ID3D12Device* device, ID3D12CommandQueue* queue) {
dx(list->Close(), "Close probe list"); ID3D12CommandList* lists[] = {list.Get()};
queue->ExecuteCommandLists(1, lists); drain(device, queue);
}
};
ComPtr<ID3D12Resource> output_buffer(ID3D12Device* device) {
D3D12_HEAP_PROPERTIES heap{}; heap.Type = D3D12_HEAP_TYPE_DEFAULT; heap.CreationNodeMask = heap.VisibleNodeMask = 1;
D3D12_RESOURCE_DESC desc{}; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Width = bytes;
desc.Height = desc.DepthOrArraySize = desc.MipLevels = desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
ComPtr<ID3D12Resource> result;
dx(device->CreateCommittedResource(&heap, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
nullptr, IID_PPV_ARGS(result.GetAddressOf())), "Probe UAV");
return result;
}
void upload(ID3D12Resource* buffer, uint32_t multiplier, uint32_t addend) {
void* data = nullptr; D3D12_RANGE noRead{}; dx(buffer->Map(0, &noRead, &data), "Probe upload map");
auto* values = static_cast<uint32_t*>(data);
for (unsigned i = 0; i < count; ++i) values[i] = i * multiplier + addend;
buffer->Unmap(0, nullptr);
}
bool verify(ID3D12Resource* buffer, uint32_t multiplier, uint32_t addend) {
void* data = nullptr; D3D12_RANGE range{0, bytes}; dx(buffer->Map(0, &range, &data), "Probe verification map");
const auto* values = static_cast<const uint32_t*>(data);
bool passed = true;
for (unsigned i = 0; i < count; ++i) if (values[i] != i * multiplier + addend + seed) {
std::fprintf(stderr, "COMMAND_DIFFERENT index=%u expected=%u actual=%u\n", i, i * multiplier + addend + seed, values[i]);
passed = false; break;
}
D3D12_RANGE noWrite{}; buffer->Unmap(0, &noWrite); return passed;
}
struct Callback {
ID3D12Device* device;
ID3D12Resource* input;
ID3D12Resource* output;
ID3D12Resource* replacement;
ID3D12Resource* readback;
bool prefix_verified = false;
};
void WINAPI boundary(ID3D12CommandQueue* queue, void* context) {
auto& callback = *static_cast<Callback*>(context);
NativeList list(callback.device);
transition(list.list.Get(), callback.output, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
list.list->CopyResource(callback.readback, callback.output);
transition(list.list.Get(), callback.output, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
transition(list.list.Get(), callback.input, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST);
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);
list.submit(callback.device, queue);
callback.prefix_verified = verify(callback.readback, 17, 10);
}
}
int main(int argc, char** argv) {
start();
try {
Args args(argc, argv);
if (args.module.empty()) throw std::runtime_error("--module d4r_nvngx.dll is required; NVIDIA DLLs are not needed");
HipApi hip(args.hip_root); hipDeviceProp_t props{}; hip.select_gfx1201(args.device, props);
ComPtr<IDXGIFactory4> factory; dx(CreateDXGIFactory1(IID_PPV_ARGS(factory.GetAddressOf())), "Probe DXGI");
ComPtr<IDXGIAdapter1> adapter;
for (UINT i = 0; ; ++i) {
dx(factory->EnumAdapters1(i, adapter.ReleaseAndGetAddressOf()), "Probe adapter");
DXGI_ADAPTER_DESC1 desc{}; dx(adapter->GetDesc1(&desc), "Probe adapter desc");
if (!std::memcmp(&desc.AdapterLuid, props.luid, sizeof(LUID))) break;
}
ComPtr<ID3D12Device> device;
dx(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(device.GetAddressOf())), "Probe D3D12");
ComPtr<ID3D12CommandQueue> queue;
D3D12_COMMAND_QUEUE_DESC qd{}; qd.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
dx(device->CreateCommandQueue(&qd, IID_PPV_ARGS(queue.GetAddressOf())), "Probe queue");
wchar_t system[32768]{}; if (!GetSystemDirectoryW(system, 32768)) throw std::runtime_error("System directory");
Library compiler(std::filesystem::path(system) / L"d3dcompiler_47.dll");
auto compile = compiler.symbol<decltype(&D3DCompile)>("D3DCompile");
static constexpr char shader[] = "RWStructuredBuffer<uint> Output : register(u0); StructuredBuffer<uint> Input : register(t0); cbuffer Constants : register(b0) { uint Seed; }; [numthreads(64,1,1)] void main(uint3 t:SV_DispatchThreadID) { Output[t.x] = Input[t.x] + Seed; }";
ComPtr<ID3DBlob> code, errors;
dx(compile(shader, sizeof(shader)-1, nullptr, nullptr, nullptr, "main", "cs_5_1", D3DCOMPILE_OPTIMIZATION_LEVEL3,
0, code.GetAddressOf(), errors.GetAddressOf()), "Probe HLSL");
D3D12_ROOT_PARAMETER roots[3]{};
roots[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; roots[0].Descriptor.ShaderRegister = 0;
roots[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV; roots[1].Descriptor.ShaderRegister = 0;
roots[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; roots[2].Constants.Num32BitValues = 1;
D3D12_ROOT_SIGNATURE_DESC signature{}; signature.NumParameters = 3; signature.pParameters = roots;
ComPtr<ID3DBlob> serialized;
dx(D3D12SerializeRootSignature(&signature, D3D_ROOT_SIGNATURE_VERSION_1, serialized.GetAddressOf(), errors.ReleaseAndGetAddressOf()), "Probe root signature serialize");
ComPtr<ID3D12RootSignature> root;
dx(device->CreateRootSignature(0, serialized->GetBufferPointer(), serialized->GetBufferSize(), IID_PPV_ARGS(root.GetAddressOf())), "Probe root signature");
D3D12_COMPUTE_PIPELINE_STATE_DESC pipeline{};
pipeline.pRootSignature = root.Get(); pipeline.CS = {code->GetBufferPointer(), code->GetBufferSize()};
ComPtr<ID3D12PipelineState> pso; dx(device->CreateComputePipelineState(&pipeline, IID_PPV_ARGS(pso.GetAddressOf())), "Probe PSO");
Library shim(wide(args.module));
using Install = unsigned(*)(ID3D12Device*);
using Record = unsigned(*)(ID3D12GraphicsCommandList*, void(WINAPI*)(ID3D12CommandQueue*, void*), void*);
using Live = unsigned long long(*)();
if (shim.symbol<Install>("d4r_D3D12_InstallCommandBackend")(device.Get()) != 1) throw std::runtime_error("Command backend installation failed");
auto record = shim.symbol<Record>("d4r_D3D12_RecordDiagnosticBoundary");
auto live = shim.symbol<Live>("d4r_D3D12_LiveRecordings");
for (unsigned iteration = 0; iteration < args.iterations; ++iteration) {
auto input = make_buffer(device.Get(), bytes, D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
auto output = output_buffer(device.Get());
auto first = make_buffer(device.Get(), bytes, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ);
auto second = make_buffer(device.Get(), bytes, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ);
auto readback = make_buffer(device.Get(), bytes, D3D12_HEAP_TYPE_READBACK, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
auto prefix = make_buffer(device.Get(), bytes, D3D12_HEAP_TYPE_READBACK, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
upload(first.Get(), 17, 10); upload(second.Get(), 25, 100);
{
NativeList a(device.Get()), b(device.Get()), c(device.Get());
a.list->CopyResource(input.Get(), first.Get());
transition(a.list.Get(), input.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
dx(a.list->Close(), "Close predecessor A");
b.list->SetComputeRootSignature(root.Get()); b.list->SetPipelineState(pso.Get());
b.list->SetComputeRootUnorderedAccessView(0, output->GetGPUVirtualAddress());
b.list->SetComputeRootShaderResourceView(1, input->GetGPUVirtualAddress());
uint32_t temporary = seed;
b.list->SetComputeRoot32BitConstants(2, 1, &temporary, 0);
temporary = 0xdeadbeef; // Deep-copy check: replay must retain Seed.
b.list->Dispatch(count / 64, 1, 1);
Callback callback{device.Get(), input.Get(), output.Get(), second.Get(), prefix.Get()};
if (record(b.list.Get(), boundary, &callback) != 1) throw std::runtime_error("Record split failed");
b.list->Dispatch(count / 64, 1, 1); // No rebinding after the split.
dx(b.list->Close(), "Close logical list B");
transition(c.list.Get(), output.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
c.list->CopyResource(readback.Get(), output.Get());
transition(c.list.Get(), output.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
dx(c.list->Close(), "Close consumer C");
ID3D12CommandList* batch[] = {a.list.Get(), b.list.Get(), c.list.Get()};
queue->ExecuteCommandLists(3, batch); drain(device.Get(), queue.Get());
if (!callback.prefix_verified || !verify(readback.Get(), 25, 100)) throw std::runtime_error("Queue order or suffix root state mismatch");
}
if (live() != 0) throw std::runtime_error("D3D12 recording metadata leaked after command-list Release");
}
std::printf("PASS D3D12_COMMAND_BACKEND architecture=gfx1201 iterations=%u batch_order=1 root_state=1 deep_copy=1 live_recordings=0 frame_age=0\n", args.iterations);
return 0;
} catch (const std::exception& failure) {
std::fprintf(stderr, "FAIL D3D12_COMMAND_BACKEND %s\n", failure.what()); loaded_modules(); return 4;
}
}
+34 -5
View File
@@ -16,6 +16,8 @@ int main(int argc, char** argv) {
if (!diagDir && args.interop_mode != "images") throw std::runtime_error("Set D4R_DIAG_DIR");
const std::filesystem::path directory(diagDir ? wide(diagDir) : std::filesystem::current_path().wstring());
std::filesystem::create_directories(directory);
const bool commandBackend = args.interop_mode == "command-list";
if (commandBackend && _putenv_s("D4R_D3D12_COMMAND_BACKEND", "1")) throw std::runtime_error("Cannot enable command backend");
for (const auto& pair : {std::make_pair("D4R_HIP_ROOT", args.hip_root),
std::make_pair("D4R_NVCUDA_DLL", args.cuda_dll), std::make_pair("D4R_NVAPI_DLL", args.nvapi_dll),
std::make_pair("D4R_NGX_CORE", args.ngx_core), std::make_pair("D4R_DLSS_DLL", args.dlss_dll)})
@@ -93,7 +95,7 @@ int main(int argc, char** argv) {
i == 3 ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
}
dx(list->Close(), "Close(synthetic producers)"); ID3D12CommandList* producer[] = {list.Get()};
queue->ExecuteCommandLists(1, producer); drain();
if (!commandBackend) { queue->ExecuteCommandLists(1, producer); drain(); }
if (args.interop_mode == "images") {
CudaApi cuda(args.cuda_dll); cuda.check(cuda.cuInit(0), "cuInit(image interop)");
CUdevice ordinal = 0; CUcontext context = nullptr;
@@ -164,17 +166,43 @@ int main(int argc, char** argv) {
for (unsigned i = 0; i < 5; ++i) d4r_ngx_set_d3d12_resource(parameters, names[i], textures[i].image.Get());
d4r_ngx_set_int(parameters, "Disable.Watermark", 1);
auto readback = make_buffer(device.Get(), textures[3].bytes, D3D12_HEAP_TYPE_READBACK, D3D12_HEAP_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST);
ComPtr<ID3D12GraphicsCommandList> predecessor;
ComPtr<ID3D12CommandAllocator> predecessorAllocator;
if (commandBackend) {
// Keep initial synthetic producers unsubmitted until the first
// batch, before the list which contains the NGX evaluation.
predecessor = list; predecessorAllocator = allocator;
dx(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(allocator.ReleaseAndGetAddressOf())), "Create game-style allocator");
dx(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, allocator.Get(), nullptr,
IID_PPV_ARGS(list.ReleaseAndGetAddressOf())), "Create game-style command list");
dx(list->Close(), "Close initial game-style list");
}
for (unsigned frame = 0; frame < args.iterations; ++frame) {
d4r_ngx_set_int(parameters, "Reset", frame == 0 ? 1 : 0);
check(shim.symbol<Evaluate>("d4r_D3D12_EvaluateAtBoundary")(queue.Get(), handle, parameters), "D3D12 same-frame Evaluate");
dx(allocator->Reset(), "Reset(harness allocator)"); dx(list->Reset(allocator.Get(), nullptr), "Reset(harness list)");
if (commandBackend) {
dx(allocator->Reset(), "Reset(game-style allocator)"); dx(list->Reset(allocator.Get(), nullptr), "Reset(game-style list)");
using RecordedEvaluate = unsigned(*)(ID3D12GraphicsCommandList*, void*, void*, void*);
check(shim.symbol<RecordedEvaluate>("NVSDK_NGX_D3D12_EvaluateFeature")(list.Get(), handle, parameters, nullptr), "D3D12 recorded same-frame Evaluate");
// The caller may reuse/mutate its parameter object as soon as
// Evaluate returns. The queued snapshot must remain immutable.
d4r_ngx_set_d3d12_resource(parameters, "Color", nullptr);
d4r_ngx_set_int(parameters, "Reset", 0);
} else {
check(shim.symbol<Evaluate>("d4r_D3D12_EvaluateAtBoundary")(queue.Get(), handle, parameters), "D3D12 same-frame Evaluate");
dx(allocator->Reset(), "Reset(harness allocator)"); dx(list->Reset(allocator.Get(), nullptr), "Reset(harness list)");
}
transition(list.Get(), textures[3].image.Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
D3D12_TEXTURE_COPY_LOCATION src{}, dst{};
src.pResource = textures[3].image.Get(); src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dst.pResource = readback.Get(); dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dst.PlacedFootprint = textures[3].footprint;
list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
transition(list.Get(), textures[3].image.Get(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
dx(list->Close(), "Close(verification)"); ID3D12CommandList* verify[] = {list.Get()}; queue->ExecuteCommandLists(1, verify); drain();
dx(list->Close(), "Close(verification)");
if (commandBackend && frame == 0) {
ID3D12CommandList* batch[] = {predecessor.Get(), list.Get()}; queue->ExecuteCommandLists(2, batch);
} else { ID3D12CommandList* verify[] = {list.Get()}; queue->ExecuteCommandLists(1, verify); }
drain();
if (commandBackend) d4r_ngx_set_d3d12_resource(parameters, "Color", textures[0].image.Get());
void* raw = nullptr; D3D12_RANGE range{0, size_t(textures[3].bytes)};
dx(readback->Map(0, &range, &raw), "Map(verification only)");
std::vector<uint16_t> pixels(size_t(outWidth) * outHeight * 4);
@@ -193,7 +221,8 @@ int main(int argc, char** argv) {
if (variance < 1e-6) throw std::runtime_error("D3D12 output lost the synthetic pattern");
}
loaded_modules();
std::printf("PASS D3D12_DLSS architecture=gfx1201 preset=%u frames=%u fast_path_cpu_copies=0 frame_age=0 queue_integration=explicit_harness\n", args.preset, args.iterations);
std::printf("PASS D3D12_DLSS architecture=gfx1201 preset=%u frames=%u fast_path_cpu_copies=0 frame_age=0 queue_integration=%s\n",
args.preset, args.iterations, commandBackend ? "recorded_command_list" : "explicit_harness");
return 0;
} catch (const std::exception& error) { std::fprintf(stderr, "FAIL D3D12_DLSS %s\n", error.what()); loaded_modules(); return 4; }
}
+40 -4
View File
@@ -44,6 +44,8 @@ API unsigned NVSDK_NGX_D3D12_Init_Ext(unsigned long long app, const wchar_t* dat
std::lock_guard<std::mutex> lock(apiMutex);
return call([&] {
if (!runtime) runtime = std::make_shared<d4r::win::Runtime>(device, app, data, sdk);
if (const char* backend = std::getenv("D4R_D3D12_COMMAND_BACKEND"); backend && std::string(backend) == "1")
d4r::win::commands::install(device);
return 1u;
});
}
@@ -84,10 +86,33 @@ API unsigned d4r_D3D12_EvaluateAtBoundary(ID3D12CommandQueue* queue, Handle* han
auto it = features.find(handle); if (it == features.end() || !p) return invalid; feature = it->second; }
return call([&] { feature->evaluate_boundary(queue, p); return 1u; });
}
API unsigned NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCommandList*, const Handle*, void*, void*) {
// Explicitly refuse an unsubmitted game list until queue integration exists.
std::fprintf(stderr, "D4R_WINDOWS_FAILURE command-list queue backend pending; no frame-age fallback\n");
return failure;
API unsigned NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCommandList* list, const Handle* handle, void* p, void*) {
std::shared_ptr<d4r::win::Feature> feature;
{ std::lock_guard<std::mutex> lock(apiMutex);
auto it = features.find(const_cast<Handle*>(handle));
if (it == features.end() || !p || !list) return invalid; feature = it->second; }
return call([&] {
struct Snapshot {
void* parameters = d4r_ngx_parameters_create();
std::vector<d4r::win::ComPtr<ID3D12Resource>> resources;
~Snapshot() { if (parameters) d4r_ngx_parameters_destroy(parameters); }
};
auto snapshot = std::make_shared<Snapshot>();
if (!snapshot->parameters) return failure;
d4r::ngx::copy_create(p, snapshot->parameters); d4r::ngx::copy_frame(p, snapshot->parameters);
const char* names[] = {"Color", "Depth", "MotionVectors", "Output", "ExposureTexture"};
const char* states[] = {"D4R.Color.State", "D4R.Depth.State", "D4R.Motion.State", "D4R.Output.State", "D4R.Exposure.State"};
for (unsigned i = 0; i < 5; ++i) {
ID3D12Resource* resource = nullptr; (void)d4r_ngx_get_d3d12_resource(p, names[i], &resource);
snapshot->resources.emplace_back(resource);
d4r_ngx_set_d3d12_resource(snapshot->parameters, names[i], resource);
const auto state = d4r::win::commands::resource_state(list, resource, D3D12_RESOURCE_STATES(
d4r::ngx::uint_value(p, states[i], i == 3 ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)));
d4r_ngx_set_uint(snapshot->parameters, states[i], unsigned(state));
}
d4r::win::commands::record_boundary(list, [feature, snapshot](ID3D12CommandQueue* queue) { feature->evaluate_boundary(queue, snapshot->parameters); });
return 1u;
});
}
API unsigned NVSDK_NGX_D3D12_EvaluateFeature_C(ID3D12GraphicsCommandList* list, const Handle* handle, void* p, void* callback) {
return NVSDK_NGX_D3D12_EvaluateFeature(list, handle, p, callback);
@@ -109,3 +134,14 @@ API unsigned NVSDK_NGX_D3D12_Shutdown() {
});
}
API unsigned NVSDK_NGX_D3D12_Shutdown1(ID3D12Device*) { return NVSDK_NGX_D3D12_Shutdown(); }
// Public diagnostics exercise queue/list integration without NVIDIA binaries.
API unsigned d4r_D3D12_InstallCommandBackend(ID3D12Device* device) {
return call([&] { d4r::win::commands::install(device); return 1u; });
}
using DiagnosticBoundary = void(WINAPI*)(ID3D12CommandQueue*, void*);
API unsigned d4r_D3D12_RecordDiagnosticBoundary(ID3D12GraphicsCommandList* list, DiagnosticBoundary callback, void* context) {
if (!callback) return invalid;
return call([&] { d4r::win::commands::record_boundary(list, [=](ID3D12CommandQueue* queue) { callback(queue, context); }); return 1u; });
}
API unsigned long long d4r_D3D12_LiveRecordings() { return d4r::win::commands::live_recordings(); }
+101
View File
@@ -0,0 +1,101 @@
"""Generate typed command forwarding from public MinGW D3D12 SDK declarations.
Run with --header <SDK/include/d3d12.h> --output d3d12_command_hooks.generated.h.
Every recording method through CommandList7 is forwarded. State setters copy
their host arguments; COM object arguments retain a reference. SDK slot numbers
are derived from the public interface inheritance, never a driver binary.
"""
import argparse
import pathlib
import re
POINTER_COUNTS = {
'RSSetViewports': {'viewports': 'viewport_count'},
'RSSetScissorRects': {'rects': 'rect_count'},
'OMSetBlendFactor': {'blend_factor': '4'},
'SetDescriptorHeaps': {'heaps': 'heap_count'},
'SetComputeRoot32BitConstants': {'data': 'constant_count'},
'SetGraphicsRoot32BitConstants': {'data': 'constant_count'},
'IASetIndexBuffer': {'view': '1'},
'IASetVertexBuffers': {'views': 'view_count'},
'SOSetTargets': {'views': 'view_count'},
'OMSetRenderTargets': {'render_target_descriptors': '(single_descriptor_handle ? 1 : render_target_descriptor_count)', 'depth_stencil_descriptor': '1'},
'SetSamplePositions': {'sample_positions': 'sample_count * pixel_count'},
'RSSetShadingRate': {'combiners': '2'},
}
SPECIAL = {'Close', 'Reset', 'ClearState', 'ResourceBarrier', 'Barrier',
'BeginEvent', 'EndEvent', 'BeginRenderPass', 'EndRenderPass',
'BeginQuery', 'EndQuery', 'ExecuteBundle', 'ExecuteIndirect', 'SetPredication'}
def generate(source):
classes = []
for match in re.finditer(r'\n(ID3D12GraphicsCommandList\d*) : public \w+\s*\{(.*?)\n\};', source, re.S):
name, body = match.groups()
methods = re.findall(r'virtual\s+(.*?)\s+STDMETHODCALLTYPE\s+(\w+)\s*\((.*?)\)\s*= 0;', body, re.S)
classes.append((int(name[len('ID3D12GraphicsCommandList'):] or '0'), name, methods))
if [version for version, _, _ in sorted(classes)] != list(range(8)):
raise RuntimeError('Expected exactly the public CommandList0..7 interfaces; review a changed SDK')
lines = ['// Generated by generate_d3d12_hooks.py from the public SDK. Do not edit.', '']
registrations = []
slot = 9 # IUnknown(3), ID3D12Object(4), DeviceChild(1), CommandList(1).
for version, interface, methods in sorted(classes):
for result, name, arguments in methods:
result = ' '.join(result.split())
arguments = ' '.join(arguments.split())
declarations = [arg.strip() for arg in arguments.split(',')] if arguments else []
names = []
for declaration in declarations:
match = re.search(r'(\w+)\s*(?:\[\d+\])?$', declaration)
if not match:
raise RuntimeError(f'Unparsed SDK argument: {name}: {declaration}')
names.append(match[1])
signature = ', '.join(['ID3D12GraphicsCommandList* self'] + declarations)
call = ', '.join(['access.target()'] + names)
lines.append(f'using Fn_{name} = {result}(STDMETHODCALLTYPE*)({signature});')
lines.append(f'static Fn_{name} original_{name} = nullptr;')
if name in SPECIAL:
lines.append(f'static {result} STDMETHODCALLTYPE hook_{name}({signature});')
else:
lines += [f'static {result} STDMETHODCALLTYPE hook_{name}({signature}) {{', ' Access access(self);']
stateful = name.startswith(('Set', 'IASet', 'RSSet', 'OMSet', 'SOSet')) and name != 'SetMarker'
if stateful:
captured = []
for declaration, argument in zip(declarations, names):
pointer = '*' in declaration or '[' in declaration
if pointer and 'ID3D12' in declaration:
if declaration.count('*') > 1:
count = POINTER_COUNTS.get(name, {}).get(argument)
if count is None:
raise RuntimeError(f'No COM array copy rule: {name}: {declaration}')
lines.append(f' auto saved_{argument} = retain_values({argument}, {count});')
captured.append(f'saved_{argument}.raw.data()')
else:
lines.append(f' auto saved_{argument} = retain({argument});')
captured.append(f'saved_{argument}.Get()')
elif pointer:
count = POINTER_COUNTS.get(name, {}).get(argument)
if count is None:
raise RuntimeError(f'No deep-copy rule for {name}: {declaration}')
value = f'static_cast<const UINT*>({argument})' if argument == 'data' else argument
lines.append(f' auto saved_{argument} = copy_values({value}, {count});')
captured.append(f'values_pointer(saved_{argument})')
else:
captured.append(argument)
lines += [' if (access.recording) access.recording->state.emplace_back([=](ID3D12GraphicsCommandList* target) mutable {',
f' original_{name}(' + ', '.join(['target'] + captured) + ');', ' });']
lines += [f' return original_{name}({call});', '}']
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:]
slot += 1
lines.append('')
lines += ['static void attach_recording_methods(void** table, unsigned version) {'] + registrations + ['}', '']
return '\n'.join(lines)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--header', type=pathlib.Path, required=True)
parser.add_argument('--output', type=pathlib.Path, required=True)
args = parser.parse_args()
args.output.write_text(generate(args.header.read_text()), encoding='utf-8')
+2
View File
@@ -2,6 +2,7 @@
#include "d3d12_external.h"
#include "cuda_image_api.h"
#include "ngx_parameters.h"
#include "d3d12_command_hooks.h"
#include <chrono>
#include <memory>
#include <mutex>
@@ -160,6 +161,7 @@ public:
// Explicit harness boundary: all earlier producers must already be queued.
// The forthcoming command-list backend calls the same stages at queue submit.
void evaluate_boundary(ID3D12CommandQueue* queue, void* parameters) {
commands::InternalScope internal;
std::lock_guard<std::mutex> lock(rt_->mutex);
if (!queue) throw std::runtime_error("Null D3D12 queue");
if (queue_ && queue_.Get() != queue) throw std::runtime_error("A feature cannot switch queues without an explicit drain");