diff --git a/include/rendering/amd_fsr3_wrapper_abi.h b/include/rendering/amd_fsr3_wrapper_abi.h index 2eb0366c..24518757 100644 --- a/include/rendering/amd_fsr3_wrapper_abi.h +++ b/include/rendering/amd_fsr3_wrapper_abi.h @@ -87,6 +87,7 @@ int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3WrapperContext context, int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3WrapperContext context, const WoweeFsr3WrapperDispatchDesc* dispatchDesc); void wowee_fsr3_wrapper_shutdown(WoweeFsr3WrapperContext context); +const char* wowee_fsr3_wrapper_get_last_error(WoweeFsr3WrapperContext context); #ifdef __cplusplus } diff --git a/src/rendering/amd_fsr3_runtime.cpp b/src/rendering/amd_fsr3_runtime.cpp index 42b93e1c..f358581d 100644 --- a/src/rendering/amd_fsr3_runtime.cpp +++ b/src/rendering/amd_fsr3_runtime.cpp @@ -32,6 +32,7 @@ struct AmdFsr3Runtime::RuntimeFns { int32_t (*wrapperDispatchUpscale)(WoweeFsr3WrapperContext, const WoweeFsr3WrapperDispatchDesc*) = nullptr; int32_t (*wrapperDispatchFramegen)(WoweeFsr3WrapperContext, const WoweeFsr3WrapperDispatchDesc*) = nullptr; void (*wrapperShutdown)(WoweeFsr3WrapperContext) = nullptr; + const char* (*wrapperGetLastError)(WoweeFsr3WrapperContext) = nullptr; decltype(&ffxGetScratchMemorySizeVK) getScratchMemorySizeVK = nullptr; decltype(&ffxGetDeviceVK) getDeviceVK = nullptr; @@ -238,6 +239,7 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { fns_->wrapperDispatchUpscale = reinterpret_castwrapperDispatchUpscale)>(resolveSym("wowee_fsr3_wrapper_dispatch_upscale")); fns_->wrapperDispatchFramegen = reinterpret_castwrapperDispatchFramegen)>(resolveSym("wowee_fsr3_wrapper_dispatch_framegen")); fns_->wrapperShutdown = reinterpret_castwrapperShutdown)>(resolveSym("wowee_fsr3_wrapper_shutdown")); + fns_->wrapperGetLastError = reinterpret_castwrapperGetLastError)>(resolveSym("wowee_fsr3_wrapper_get_last_error")); if (!fns_->wrapperGetAbiVersion || !fns_->wrapperInitialize || !fns_->wrapperDispatchUpscale || !fns_->wrapperShutdown) { @@ -472,7 +474,12 @@ bool AmdFsr3Runtime::dispatchUpscale(const AmdFsr3RuntimeDispatchDesc& desc) { wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle; const bool ok = fns_->wrapperDispatchUpscale(static_cast(wrapperContext_), &wrapperDesc) == 0; if (!ok) { - lastError_ = "wrapper upscale dispatch failed"; + if (fns_->wrapperGetLastError) { + const char* err = fns_->wrapperGetLastError(static_cast(wrapperContext_)); + lastError_ = (err && *err) ? err : "wrapper upscale dispatch failed"; + } else { + lastError_ = "wrapper upscale dispatch failed"; + } } else { lastError_.clear(); } @@ -588,7 +595,12 @@ bool AmdFsr3Runtime::dispatchFrameGeneration(const AmdFsr3RuntimeDispatchDesc& d wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle; const bool ok = fns_->wrapperDispatchFramegen(static_cast(wrapperContext_), &wrapperDesc) == 0; if (!ok) { - lastError_ = "wrapper frame generation dispatch failed"; + if (fns_->wrapperGetLastError) { + const char* err = fns_->wrapperGetLastError(static_cast(wrapperContext_)); + lastError_ = (err && *err) ? err : "wrapper frame generation dispatch failed"; + } else { + lastError_ = "wrapper frame generation dispatch failed"; + } } else { lastError_.clear(); } diff --git a/src/rendering/amd_fsr3_wrapper_impl.cpp b/src/rendering/amd_fsr3_wrapper_impl.cpp index 7f972af0..74e61156 100644 --- a/src/rendering/amd_fsr3_wrapper_impl.cpp +++ b/src/rendering/amd_fsr3_wrapper_impl.cpp @@ -229,8 +229,14 @@ struct WrapperContext { size_t scratchBufferSize = 0; void* fsr3ContextStorage = nullptr; bool frameGenerationReady = false; + std::string lastError{}; }; +void setContextError(WrapperContext* ctx, const char* message) { + if (!ctx) return; + ctx->lastError = (message && *message) ? message : "unknown wrapper error"; +} + void closeLibrary(void* handle) { if (!handle) return; #if defined(_WIN32) @@ -655,7 +661,10 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W if (!context || !dispatchDesc) return -1; if (dispatchDesc->structSize < sizeof(WoweeFsr3WrapperDispatchDesc)) return -1; if (!dispatchDesc->commandBuffer || !dispatchDesc->colorImage || !dispatchDesc->depthImage || - !dispatchDesc->motionVectorImage || !dispatchDesc->outputImage) return -1; + !dispatchDesc->motionVectorImage || !dispatchDesc->outputImage) { + setContextError(reinterpret_cast(context), "invalid dispatch resources for upscale"); + return -1; + } WrapperContext* ctx = reinterpret_cast(context); #if defined(_WIN32) if (ctx->backend == WrapperBackend::Dx12Bridge) { @@ -670,6 +679,25 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W dispatchDesc->colorMemoryHandle == 0 || dispatchDesc->depthMemoryHandle == 0 || dispatchDesc->motionVectorMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0) { + setContextError(ctx, "dx12_bridge dispatch missing required external handles for upscale"); + return -1; + } + + ID3D12Device* d3d12Device = nullptr; + if (D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&d3d12Device)) == S_OK && d3d12Device) { + ID3D12Resource* sharedOutputResource = nullptr; + HRESULT hrOpen = d3d12Device->OpenSharedHandle( + reinterpret_cast(dispatchDesc->outputMemoryHandle), + IID_PPV_ARGS(&sharedOutputResource)); + if (FAILED(hrOpen) || !sharedOutputResource) { + setContextError(ctx, "dx12_bridge failed to open shared output memory handle as D3D12 resource"); + d3d12Device->Release(); + return -1; + } + sharedOutputResource->Release(); + d3d12Device->Release(); + } else { + setContextError(ctx, "dx12_bridge failed to create D3D12 device for shared-handle import"); return -1; } } @@ -713,7 +741,13 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3W dispatch.cameraFovAngleVertical = dispatchDesc->cameraFovYRadians; dispatch.viewSpaceToMetersFactor = 1.0f; - return (ctx->fns.fsr3ContextDispatchUpscale(reinterpret_cast(ctx->fsr3ContextStorage), &dispatch) == FFX_OK) ? 0 : -1; + const bool ok = (ctx->fns.fsr3ContextDispatchUpscale(reinterpret_cast(ctx->fsr3ContextStorage), &dispatch) == FFX_OK); + if (!ok) { + setContextError(ctx, "ffxFsr3ContextDispatchUpscale failed"); + return -1; + } + ctx->lastError.clear(); + return 0; #endif } @@ -726,9 +760,15 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3 #else if (!context || !dispatchDesc) return -1; if (dispatchDesc->structSize < sizeof(WoweeFsr3WrapperDispatchDesc)) return -1; - if (!dispatchDesc->commandBuffer || !dispatchDesc->outputImage || !dispatchDesc->frameGenOutputImage) return -1; + if (!dispatchDesc->commandBuffer || !dispatchDesc->outputImage || !dispatchDesc->frameGenOutputImage) { + setContextError(reinterpret_cast(context), "invalid dispatch resources for frame generation"); + return -1; + } WrapperContext* ctx = reinterpret_cast(context); - if (!ctx->frameGenerationReady || !ctx->fns.fsr3DispatchFrameGeneration) return -1; + if (!ctx->frameGenerationReady || !ctx->fns.fsr3DispatchFrameGeneration) { + setContextError(ctx, "frame generation backend is not ready"); + return -1; + } #if defined(_WIN32) if (ctx->backend == WrapperBackend::Dx12Bridge) { const uint32_t requiredMask = @@ -739,6 +779,7 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3 if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->frameGenOutputMemoryHandle == 0 || dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0) { + setContextError(ctx, "dx12_bridge dispatch missing required external handles for frame generation"); return -1; } } @@ -761,7 +802,13 @@ WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3 fgDispatch.minMaxLuminance[0] = 0.0f; fgDispatch.minMaxLuminance[1] = 1.0f; - return (ctx->fns.fsr3DispatchFrameGeneration(&fgDispatch) == FFX_OK) ? 0 : -1; + const bool ok = (ctx->fns.fsr3DispatchFrameGeneration(&fgDispatch) == FFX_OK); + if (!ok) { + setContextError(ctx, "ffxFsr3DispatchFrameGeneration failed"); + return -1; + } + ctx->lastError.clear(); + return 0; #endif } @@ -773,3 +820,14 @@ WOWEE_FSR3_WRAPPER_EXPORT void wowee_fsr3_wrapper_shutdown(WoweeFsr3WrapperConte (void)context; #endif } + +WOWEE_FSR3_WRAPPER_EXPORT const char* wowee_fsr3_wrapper_get_last_error(WoweeFsr3WrapperContext context) { +#if WOWEE_HAS_AMD_FSR3_FRAMEGEN + WrapperContext* ctx = reinterpret_cast(context); + if (!ctx) return "invalid wrapper context"; + return ctx->lastError.c_str(); +#else + (void)context; + return "wrapper built without WOWEE_HAS_AMD_FSR3_FRAMEGEN"; +#endif +}