Add ABI v2 external-handle plumbing for FSR3 bridge dispatch

This commit is contained in:
Kelsi 2026-03-09 01:31:01 -07:00
parent e25253a6e8
commit 61cb2df400
7 changed files with 158 additions and 1 deletions

View file

@ -462,6 +462,14 @@ bool AmdFsr3Runtime::dispatchUpscale(const AmdFsr3RuntimeDispatchDesc& desc) {
wrapperDesc.cameraFar = desc.cameraFar;
wrapperDesc.cameraFovYRadians = desc.cameraFovYRadians;
wrapperDesc.reset = desc.reset ? 1u : 0u;
wrapperDesc.externalFlags = desc.externalFlags;
wrapperDesc.colorMemoryHandle = desc.colorMemoryHandle;
wrapperDesc.depthMemoryHandle = desc.depthMemoryHandle;
wrapperDesc.motionVectorMemoryHandle = desc.motionVectorMemoryHandle;
wrapperDesc.outputMemoryHandle = desc.outputMemoryHandle;
wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle;
wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle;
wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle;
const bool ok = fns_->wrapperDispatchUpscale(static_cast<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0;
if (!ok) {
lastError_ = "wrapper upscale dispatch failed";
@ -570,6 +578,14 @@ bool AmdFsr3Runtime::dispatchFrameGeneration(const AmdFsr3RuntimeDispatchDesc& d
wrapperDesc.cameraFar = desc.cameraFar;
wrapperDesc.cameraFovYRadians = desc.cameraFovYRadians;
wrapperDesc.reset = desc.reset ? 1u : 0u;
wrapperDesc.externalFlags = desc.externalFlags;
wrapperDesc.colorMemoryHandle = desc.colorMemoryHandle;
wrapperDesc.depthMemoryHandle = desc.depthMemoryHandle;
wrapperDesc.motionVectorMemoryHandle = desc.motionVectorMemoryHandle;
wrapperDesc.outputMemoryHandle = desc.outputMemoryHandle;
wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle;
wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle;
wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle;
const bool ok = fns_->wrapperDispatchFramegen(static_cast<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0;
if (!ok) {
lastError_ = "wrapper frame generation dispatch failed";

View file

@ -657,6 +657,20 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W
if (!dispatchDesc->commandBuffer || !dispatchDesc->colorImage || !dispatchDesc->depthImage ||
!dispatchDesc->motionVectorImage || !dispatchDesc->outputImage) return -1;
WrapperContext* ctx = reinterpret_cast<WrapperContext*>(context);
#if defined(_WIN32)
if (ctx->backend == WrapperBackend::Dx12Bridge) {
const uint32_t requiredMask =
WOWEE_FSR3_WRAPPER_EXTERNAL_COLOR_MEMORY |
WOWEE_FSR3_WRAPPER_EXTERNAL_DEPTH_MEMORY |
WOWEE_FSR3_WRAPPER_EXTERNAL_MOTION_MEMORY |
WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY;
if ((dispatchDesc->externalFlags & requiredMask) != requiredMask ||
dispatchDesc->colorMemoryHandle == 0 || dispatchDesc->depthMemoryHandle == 0 ||
dispatchDesc->motionVectorMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0) {
return -1;
}
}
#endif
FfxResourceDescription colorDesc = makeResourceDescription(
dispatchDesc->colorFormat, dispatchDesc->renderWidth, dispatchDesc->renderHeight, FFX_RESOURCE_USAGE_READ_ONLY);
@ -712,6 +726,17 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3
if (!dispatchDesc->commandBuffer || !dispatchDesc->outputImage || !dispatchDesc->frameGenOutputImage) return -1;
WrapperContext* ctx = reinterpret_cast<WrapperContext*>(context);
if (!ctx->frameGenerationReady || !ctx->fns.fsr3DispatchFrameGeneration) return -1;
#if defined(_WIN32)
if (ctx->backend == WrapperBackend::Dx12Bridge) {
const uint32_t requiredMask =
WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY |
WOWEE_FSR3_WRAPPER_EXTERNAL_FRAMEGEN_OUTPUT_MEMORY;
if ((dispatchDesc->externalFlags & requiredMask) != requiredMask ||
dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->frameGenOutputMemoryHandle == 0) {
return -1;
}
}
#endif
FfxResourceDescription presentDesc = makeResourceDescription(
dispatchDesc->outputFormat, dispatchDesc->outputWidth, dispatchDesc->outputHeight, FFX_RESOURCE_USAGE_READ_ONLY);

View file

@ -72,6 +72,9 @@
#include <unordered_set>
#include <set>
#include <future>
#if defined(_WIN32)
#include <windows.h>
#endif
namespace wowee {
namespace rendering {
@ -110,6 +113,29 @@ static int envIntOrDefault(const char* key, int defaultValue) {
return static_cast<int>(n);
}
#if defined(_WIN32)
static uint64_t exportImageMemoryHandleWin32(VkDevice device, PFN_vkGetDeviceProcAddr getDeviceProcAddr,
VmaAllocator allocator, const AllocatedImage& image) {
if (!device || !getDeviceProcAddr || !allocator || !image.allocation) return 0;
auto getMemHandle = reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(
getDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR"));
if (!getMemHandle) return 0;
VmaAllocationInfo allocInfo{};
vmaGetAllocationInfo(allocator, image.allocation, &allocInfo);
if (allocInfo.deviceMemory == VK_NULL_HANDLE) return 0;
VkMemoryGetWin32HandleInfoKHR handleInfo{};
handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR;
handleInfo.memory = allocInfo.deviceMemory;
handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
HANDLE outHandle = nullptr;
if (getMemHandle(device, &handleInfo, &outHandle) != VK_SUCCESS || !outHandle) return 0;
return reinterpret_cast<uint64_t>(outHandle);
}
#endif
static std::vector<std::string> parseEmoteCommands(const std::string& raw) {
std::vector<std::string> out;
std::string cur;
@ -4488,6 +4514,53 @@ void Renderer::dispatchAmdFsr3Framegen() {
fgDispatch.cameraFovYRadians = camera ? glm::radians(camera->getFovDegrees()) : 1.0f;
fgDispatch.reset = fsr2_.needsHistoryReset;
#if defined(_WIN32)
std::vector<HANDLE> exportedHandles;
auto trackHandle = [&](uint64_t h) {
if (!h) return;
HANDLE raw = reinterpret_cast<HANDLE>(h);
exportedHandles.push_back(raw);
};
auto cleanupExportedHandles = [&]() {
for (HANDLE h : exportedHandles) {
if (h) CloseHandle(h);
}
exportedHandles.clear();
};
fgDispatch.externalFlags = 0;
fgDispatch.colorMemoryHandle = exportImageMemoryHandleWin32(
device, vkGetDeviceProcAddr, alloc, fsr2_.sceneColor);
if (fgDispatch.colorMemoryHandle) {
fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_COLOR_MEMORY;
trackHandle(fgDispatch.colorMemoryHandle);
}
fgDispatch.depthMemoryHandle = exportImageMemoryHandleWin32(
device, vkGetDeviceProcAddr, alloc, fsr2_.sceneDepth);
if (fgDispatch.depthMemoryHandle) {
fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_DEPTH_MEMORY;
trackHandle(fgDispatch.depthMemoryHandle);
}
fgDispatch.motionVectorMemoryHandle = exportImageMemoryHandleWin32(
device, vkGetDeviceProcAddr, alloc, fsr2_.motionVectors);
if (fgDispatch.motionVectorMemoryHandle) {
fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_MOTION_MEMORY;
trackHandle(fgDispatch.motionVectorMemoryHandle);
}
fgDispatch.outputMemoryHandle = exportImageMemoryHandleWin32(
device, vkGetDeviceProcAddr, alloc, fsr2_.history[fsr2_.currentHistory]);
if (fgDispatch.outputMemoryHandle) {
fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY;
trackHandle(fgDispatch.outputMemoryHandle);
}
fgDispatch.frameGenOutputMemoryHandle = exportImageMemoryHandleWin32(
device, vkGetDeviceProcAddr, alloc, fsr2_.framegenOutput);
if (fgDispatch.frameGenOutputMemoryHandle) {
fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_FRAMEGEN_OUTPUT_MEMORY;
trackHandle(fgDispatch.frameGenOutputMemoryHandle);
}
#endif
if (!fsr2_.amdFsr3Runtime->dispatchUpscale(fgDispatch)) {
static bool warnedRuntimeDispatch = false;
if (!warnedRuntimeDispatch) {
@ -4497,6 +4570,9 @@ void Renderer::dispatchAmdFsr3Framegen() {
fsr2_.amdFsr3RuntimeLastError = fsr2_.amdFsr3Runtime->lastError();
fsr2_.amdFsr3FallbackCount++;
fsr2_.amdFsr3FramegenRuntimeActive = false;
#if defined(_WIN32)
cleanupExportedHandles();
#endif
return;
}
fsr2_.amdFsr3RuntimeLastError.clear();
@ -4504,10 +4580,16 @@ void Renderer::dispatchAmdFsr3Framegen() {
if (!fsr2_.amdFsr3FramegenEnabled) {
fsr2_.amdFsr3FramegenRuntimeActive = false;
#if defined(_WIN32)
cleanupExportedHandles();
#endif
return;
}
if (!fsr2_.amdFsr3Runtime->isFrameGenerationReady()) {
fsr2_.amdFsr3FramegenRuntimeActive = false;
#if defined(_WIN32)
cleanupExportedHandles();
#endif
return;
}
if (!fsr2_.amdFsr3Runtime->dispatchFrameGeneration(fgDispatch)) {
@ -4519,12 +4601,18 @@ void Renderer::dispatchAmdFsr3Framegen() {
fsr2_.amdFsr3RuntimeLastError = fsr2_.amdFsr3Runtime->lastError();
fsr2_.amdFsr3FallbackCount++;
fsr2_.amdFsr3FramegenRuntimeActive = false;
#if defined(_WIN32)
cleanupExportedHandles();
#endif
return;
}
fsr2_.amdFsr3RuntimeLastError.clear();
fsr2_.amdFsr3FramegenDispatchCount++;
fsr2_.framegenOutputValid = true;
fsr2_.amdFsr3FramegenRuntimeActive = true;
#if defined(_WIN32)
cleanupExportedHandles();
#endif
#else
fsr2_.amdFsr3FramegenRuntimeActive = false;
#endif