Add ABI v3 fence-value sync for DX12 bridge dispatch

This commit is contained in:
Kelsi 2026-03-09 01:58:45 -07:00
parent 2bd9575419
commit 1c7908f02d
7 changed files with 29 additions and 7 deletions

View file

@ -218,7 +218,7 @@ make -j$(nproc)
- Set to `0` to skip adapter/device preflight. - Set to `0` to skip adapter/device preflight.
- Bridge preflight also checks Vulkan Win32 interop funcs/extensions before enabling DX12 path. - Bridge preflight also checks Vulkan Win32 interop funcs/extensions before enabling DX12 path.
- Path B wrapper libraries must export the clean wrapper ABI (`include/rendering/amd_fsr3_wrapper_abi.h`): - Path B wrapper libraries must export the clean wrapper ABI (`include/rendering/amd_fsr3_wrapper_abi.h`):
- ABI version is currently `2` (dispatch includes external-memory/semaphore handle fields for bridge interop plumbing). - ABI version is currently `3` (dispatch includes external-memory/semaphore handles plus acquire/release fence values for bridge sync).
- `wowee_fsr3_wrapper_get_abi_version` - `wowee_fsr3_wrapper_get_abi_version`
- `wowee_fsr3_wrapper_initialize` - `wowee_fsr3_wrapper_initialize`
- `wowee_fsr3_wrapper_dispatch_upscale` - `wowee_fsr3_wrapper_dispatch_upscale`

View file

@ -67,7 +67,7 @@ Runtime note:
- required device extensions: `VK_KHR_external_memory`, `VK_KHR_external_memory_win32`, `VK_KHR_external_semaphore`, `VK_KHR_external_semaphore_win32` - required device extensions: `VK_KHR_external_memory`, `VK_KHR_external_memory_win32`, `VK_KHR_external_semaphore`, `VK_KHR_external_semaphore_win32`
- Path B wrapper ABI contract is declared in: - Path B wrapper ABI contract is declared in:
- `include/rendering/amd_fsr3_wrapper_abi.h` - `include/rendering/amd_fsr3_wrapper_abi.h`
- Current wrapper ABI version: `2` (adds external memory and semaphore handle fields in dispatch payload for bridge interop). - Current wrapper ABI version: `3` (dispatch payload carries external memory/semaphore handles and acquire/release fence values for bridge synchronization).
- Required wrapper exports: - Required wrapper exports:
- `wowee_fsr3_wrapper_get_abi_version` - `wowee_fsr3_wrapper_get_abi_version`
- `wowee_fsr3_wrapper_initialize` - `wowee_fsr3_wrapper_initialize`

View file

@ -52,6 +52,8 @@ struct AmdFsr3RuntimeDispatchDesc {
uint64_t frameGenOutputMemoryHandle = 0; uint64_t frameGenOutputMemoryHandle = 0;
uint64_t acquireSemaphoreHandle = 0; uint64_t acquireSemaphoreHandle = 0;
uint64_t releaseSemaphoreHandle = 0; uint64_t releaseSemaphoreHandle = 0;
uint64_t acquireSemaphoreValue = 0;
uint64_t releaseSemaphoreValue = 0;
}; };
class AmdFsr3Runtime { class AmdFsr3Runtime {

View file

@ -7,7 +7,7 @@
extern "C" { extern "C" {
#endif #endif
#define WOWEE_FSR3_WRAPPER_ABI_VERSION 2u #define WOWEE_FSR3_WRAPPER_ABI_VERSION 3u
typedef void* WoweeFsr3WrapperContext; typedef void* WoweeFsr3WrapperContext;
@ -58,6 +58,8 @@ typedef struct WoweeFsr3WrapperDispatchDesc {
uint64_t frameGenOutputMemoryHandle; uint64_t frameGenOutputMemoryHandle;
uint64_t acquireSemaphoreHandle; uint64_t acquireSemaphoreHandle;
uint64_t releaseSemaphoreHandle; uint64_t releaseSemaphoreHandle;
uint64_t acquireSemaphoreValue;
uint64_t releaseSemaphoreValue;
} WoweeFsr3WrapperDispatchDesc; } WoweeFsr3WrapperDispatchDesc;
enum { enum {

View file

@ -472,6 +472,8 @@ bool AmdFsr3Runtime::dispatchUpscale(const AmdFsr3RuntimeDispatchDesc& desc) {
wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle; wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle;
wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle; wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle;
wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle; wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle;
wrapperDesc.acquireSemaphoreValue = desc.acquireSemaphoreValue;
wrapperDesc.releaseSemaphoreValue = desc.releaseSemaphoreValue;
const bool ok = fns_->wrapperDispatchUpscale(static_cast<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0; const bool ok = fns_->wrapperDispatchUpscale(static_cast<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0;
if (!ok) { if (!ok) {
if (fns_->wrapperGetLastError) { if (fns_->wrapperGetLastError) {
@ -593,6 +595,8 @@ bool AmdFsr3Runtime::dispatchFrameGeneration(const AmdFsr3RuntimeDispatchDesc& d
wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle; wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle;
wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle; wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle;
wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle; wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle;
wrapperDesc.acquireSemaphoreValue = desc.acquireSemaphoreValue;
wrapperDesc.releaseSemaphoreValue = desc.releaseSemaphoreValue;
const bool ok = fns_->wrapperDispatchFramegen(static_cast<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0; const bool ok = fns_->wrapperDispatchFramegen(static_cast<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0;
if (!ok) { if (!ok) {
if (fns_->wrapperGetLastError) { if (fns_->wrapperGetLastError) {

View file

@ -846,7 +846,8 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W
if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || if ((dispatchDesc->externalFlags & requiredMask) != requiredMask ||
dispatchDesc->colorMemoryHandle == 0 || dispatchDesc->depthMemoryHandle == 0 || dispatchDesc->colorMemoryHandle == 0 || dispatchDesc->depthMemoryHandle == 0 ||
dispatchDesc->motionVectorMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->motionVectorMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0 ||
dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0) { dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0 ||
dispatchDesc->acquireSemaphoreValue == 0 || dispatchDesc->releaseSemaphoreValue == 0) {
setContextError(ctx, "dx12_bridge dispatch missing required external handles for upscale"); setContextError(ctx, "dx12_bridge dispatch missing required external handles for upscale");
return -1; return -1;
} }
@ -959,6 +960,11 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W
setContextError(ctx, "dx12_bridge failed to close command list after upscale dispatch"); setContextError(ctx, "dx12_bridge failed to close command list after upscale dispatch");
return -1; return -1;
} }
if (acquireFence && ctx->dx12Queue->Wait(acquireFence, dispatchDesc->acquireSemaphoreValue) != S_OK) {
cleanupDx12Imports();
setContextError(ctx, "dx12_bridge failed to wait on shared acquire fence before upscale dispatch");
return -1;
}
ID3D12CommandList* lists[] = {ctx->dx12CommandList}; ID3D12CommandList* lists[] = {ctx->dx12CommandList};
ctx->dx12Queue->ExecuteCommandLists(1, lists); ctx->dx12Queue->ExecuteCommandLists(1, lists);
const uint64_t waitValue = ctx->dx12FenceValue++; const uint64_t waitValue = ctx->dx12FenceValue++;
@ -971,7 +977,7 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W
ctx->dx12Fence->SetEventOnCompletion(waitValue, ctx->dx12FenceEvent); ctx->dx12Fence->SetEventOnCompletion(waitValue, ctx->dx12FenceEvent);
WaitForSingleObject(ctx->dx12FenceEvent, INFINITE); WaitForSingleObject(ctx->dx12FenceEvent, INFINITE);
} }
if (releaseFence && ctx->dx12Queue->Signal(releaseFence, waitValue) != S_OK) { if (releaseFence && ctx->dx12Queue->Signal(releaseFence, dispatchDesc->releaseSemaphoreValue) != S_OK) {
cleanupDx12Imports(); cleanupDx12Imports();
setContextError(ctx, "dx12_bridge failed to signal shared release fence after upscale dispatch"); setContextError(ctx, "dx12_bridge failed to signal shared release fence after upscale dispatch");
return -1; return -1;
@ -1015,7 +1021,8 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3
WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE;
if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || if ((dispatchDesc->externalFlags & requiredMask) != requiredMask ||
dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->frameGenOutputMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->frameGenOutputMemoryHandle == 0 ||
dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0) { dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0 ||
dispatchDesc->acquireSemaphoreValue == 0 || dispatchDesc->releaseSemaphoreValue == 0) {
setContextError(ctx, "dx12_bridge dispatch missing required external handles for frame generation"); setContextError(ctx, "dx12_bridge dispatch missing required external handles for frame generation");
return -1; return -1;
} }
@ -1097,6 +1104,11 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3
setContextError(ctx, "dx12_bridge failed to close command list after frame generation dispatch"); setContextError(ctx, "dx12_bridge failed to close command list after frame generation dispatch");
return -1; return -1;
} }
if (acquireFence && ctx->dx12Queue->Wait(acquireFence, dispatchDesc->acquireSemaphoreValue) != S_OK) {
cleanupDx12Imports();
setContextError(ctx, "dx12_bridge failed to wait on shared acquire fence before frame generation dispatch");
return -1;
}
ID3D12CommandList* lists[] = {ctx->dx12CommandList}; ID3D12CommandList* lists[] = {ctx->dx12CommandList};
ctx->dx12Queue->ExecuteCommandLists(1, lists); ctx->dx12Queue->ExecuteCommandLists(1, lists);
const uint64_t waitValue = ctx->dx12FenceValue++; const uint64_t waitValue = ctx->dx12FenceValue++;
@ -1109,7 +1121,7 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3
ctx->dx12Fence->SetEventOnCompletion(waitValue, ctx->dx12FenceEvent); ctx->dx12Fence->SetEventOnCompletion(waitValue, ctx->dx12FenceEvent);
WaitForSingleObject(ctx->dx12FenceEvent, INFINITE); WaitForSingleObject(ctx->dx12FenceEvent, INFINITE);
} }
if (releaseFence && ctx->dx12Queue->Signal(releaseFence, waitValue) != S_OK) { if (releaseFence && ctx->dx12Queue->Signal(releaseFence, dispatchDesc->releaseSemaphoreValue) != S_OK) {
cleanupDx12Imports(); cleanupDx12Imports();
setContextError(ctx, "dx12_bridge failed to signal shared release fence after frame generation dispatch"); setContextError(ctx, "dx12_bridge failed to signal shared release fence after frame generation dispatch");
return -1; return -1;

View file

@ -4606,6 +4606,8 @@ void Renderer::dispatchAmdFsr3Framegen() {
fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE;
trackHandle(fgDispatch.releaseSemaphoreHandle); trackHandle(fgDispatch.releaseSemaphoreHandle);
} }
fgDispatch.acquireSemaphoreValue = 1;
fgDispatch.releaseSemaphoreValue = 1;
#endif #endif
if (!fsr2_.amdFsr3Runtime->dispatchUpscale(fgDispatch)) { if (!fsr2_.amdFsr3Runtime->dispatchUpscale(fgDispatch)) {