从 FSR 3.0 迁移到 FSR 3.1
FSR 3.1 的新 API 在几个方面改变了应用程序与 FSR 的交互方式
- 上采样和帧生成已分离。
- 不再支持自定义后端。
- 后端与效果上下文一起创建,其生命周期绑定在一起。
- 所有调用都使用 ABI 稳定的结构,支持未来的扩展。
有关新 API 的更详细信息,请参阅 FidelityFX API 简介。
API 设置
将您的构建系统设置为包含 ffx-api/include 中的头文件,并链接到 amd_fidelityfx_dx12 或 amd_fidelityfx_vk 库之一。
在源文件中,包含 C API 的 ffx_api/ffx_api.h 或 C++ 便利工具的 ffx_api/ffx_api.hpp。
对于上采样,包含 ffx_api/ffx_fsr_upscale.h(或 .hpp),对于帧生成,包含 ffx_api/ffx_fg.h(或 .hpp)。
对于后端创建和帧生成交换链,您还需要 ffx_api/dx12/ffx_api_dx12.h 或 ffx_api/vk/ffx_api_vk.h(或 .hpp)之一。
创建上下文
不要调用 ffxFsr3ContextCreate,而是调用 ffxCreateContext。
ffxCreateContextDescFsrUpscale 接受 FfxFsr3ContextDescription 的一部分参数,不同之处在于标志现在以 FFX_FSR_ 开头,而不是 FFX_FSR3_。
必须在 ffxCreateContextDescFsrUpscale 的 header 的 pNext 字段中传递后端创建描述。这可以是 ffxCreateBackendDX12Desc 或 ffxCreateBackendVKDesc。
每个结构体的 header 上的 type 字段必须设置为关联的类型 ID。在 C 头文件中,这些与其关联的类型相邻。在使用 C++ 命名空间类型时,结构体类型由构造函数初始化。
对于帧生成,必须单独创建一个上下文,以及一个用于帧生成交换链(特定于后端)的上下文。
对于内存分配,可以传递一组回调。如果设置为 NULL,则使用系统 malloc 和 free。
查询 FSR 信息
ffxFsr3GetUpscaleRatioFromQualityMode、ffxFsr3GetRenderResolutionFromQualityMode、ffxFsr3GetJitterPhaseCount 和 ffxFsr3GetJitterOffset 函数被替换为传递给 ffxQuery 函数的结构体。这些查询函数中的指针参数在新 API 中是结构体成员。
配置 FSR
ffxFsr3ConfigureFrameGeneration 被 ffxConfigure 函数替换,并使用帧生成上下文。配置结构体几乎相同。添加了一个新的可选回调上下文。有关详细信息,请参阅比较表。
调度 FSR
所有调度都使用 ffxDispatch 函数完成。
资源通过新的 FfxApiResource 结构体传递,该结构体与 FfxResource 非常相似,但具有更好的平台稳定性。对于 DirectX,可以使用辅助函数 ffxApiGetResourceDX12 来填充资源描述。
使用帧生成时,每帧都必须调用新的准备调度。这可以放在与上采样调度相同的位置,并接受上采样资源的子集。
对比
以下部分显示了 FSR 3.0 代码模式及其 FSR 3.1 等效项。
上下文名称
FSR 3.0
FfxFsr3Context fsr3Context;FSR 3.1 / FFX API C
ffxContext upscalingContext, framegenContext;FFX API C++
ffx::Context upscalingContext, framegenContext;上下文创建(仅限上采样)
FSR 3.0
FfxFsr3ContextDescription fsr3ContextDesc = {0};// create backend interface ...// fill fsr3ContextDesc ...fsr3ContextDesc.flags |= FFX_FSR3_ENABLE_UPSCALING_ONLY;ffxFsr3ContextCreate(&fsr3Context, &fsr3ContextDesc);FSR 3.1 / FFX API C
ffxCreateContextDescFsrUpscale fsrContextDesc = {0};fsrContextDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FSR_UPSCALE;// fill fsrContextDesc ...// backend interface desc ...fsrContextDesc.header.pNext = &backendDesc.header;ffxCreateContext(&upscalingContext, &fsrContextDesc.header, NULL);FFX API C++
ffx::CreateContextDescFsrUpscale fsrContextDesc{};// fill fsrContextDesc ...// backend interface desc ...ffx::CreateContext(&upscalingContext, nullptr, fsrContextDesc, backendDesc);DX12 后端创建
FSR 3.0
FfxFsr3ContextDescription fsr3ContextDesc = {0};// create backend interface (DX12)size_t scratchBufferSize = ffxGetScratchMemorySizeDX12(1);void* scratchBuffer = malloc(scrathBufferSize);memset(scratchBuffer, 0, scrathBufferSize);errorCode = ffxGetInterfaceDX12(&fsr3ContextDesc.backendInterfaceUpscaling, ffxGetDeviceDX12(dx12Device), scratchBuffer, scratchBufferSize, 1);assert(errorCode == FFX_OK);FSR 3.1 / FFX API C
ffxCreateContextDescFsrUpscale fsrContextDesc = {0};// fill fsrContextDesc ...// backend interface desc (dx12)ffxCreateBackendDX12Desc backendDesc = {0};backendDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12;backendDesc.device = dx12Device;fsrContextDesc.header.pNext = &backendDesc.header;// create context and backendffxCreateContext(&upscalingContext, &fsrContextDesc.header, NULL);FFX API C++
ffx::CreateContextDescFsrUpscale fsrContextDesc{};// fill fsrContextDesc ...// backend interface desc (dx12)ffx::CreateBackendDX12Desc backendDesc{};backendDesc.device = dx12Device;ffx::CreateContext(&upscalingContext, nullptr, fsrContextDesc, backendDesc);上下文创建(上采样 + 帧生成)
FSR 3.0
FfxFsr3ContextDescription fsr3ContextDesc = {0};// create backend interface (x3) ...// fill fsr3ContextDesc ...ffxFsr3ContextCreate(&fsr3Context, &fsr3ContextDesc);FSR 3.1 / FFX API C
ffxCreateContextDescFsrUpscale fsrContextDesc = {0};fsrContextDesc.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_FSR_UPSCALE;// fill fsrContextDesc ...// backend interface desc ...fsrContextDesc.header.pNext = &backendDesc.header;ffxCreateContext(&upscalingContext, &fsrContextDesc.header, NULL);ffxCreateContextDescFsrFrameGeneneration fgContextDesc = {0};// fill fgContextDesc ...// backend interface desc ...fgContextDesc.header.pNext = &backendDesc.header;ffxCreateContext(&frameGenContext, &fgContextDesc.header, NULL);FFX API C++
ffx::CreateContextDescFsrUpscale fsrContextDesc{};// fill fsrContextDesc ...// backend interface desc ...ffx::CreateContext(&upscalingContext, nullptr, fsrContextDesc, backendDesc);ffx::CreateContextDescFsrFrameGen fgContextDesc{};// fill fgContextDesc ...// backend interface desc ...ffx::CreateContext(&frameGenContext, nullptr, fgContextDesc, backendDesc);查询上采样比例 / 渲染分辨率
FSR 3.0
float upscaleRatio = ffxFsr3GetUpscaleRatioFromQualityMode(FFX_FSR3_QUALITY_MODE_BALANCED);<!-- -->uint32_t renderWidth, renderHeight;ffxFsr3GetRenderResolutionFromQualityMode(&renderWidth, &renderHeight, displayWidth, displayHeight, FFX_FSR3_QUALITY_MODE_BALANCED);FSR 3.1 / FFX API C
float upscaleRatio;struct ffxQueryDescFsrGetUpscaleRatioFromQualityMode queryDesc1 = {0};queryDesc1.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETUPSCALERATIOFROMQUALITYMODE;queryDesc1.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED;queryDesc1.pOutUpscaleRatio = &upscaleRatio;ffxQuery(&fsrContext, &queryDesc1.header);<!-- -->uint32_t renderWidth, renderHeight;struct ffxQueryDescFsrGetRenderResolutionFromQualityMode queryDesc2 = {0};queryDesc2.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETRENDERRESOLUTIONFROMQUALITYMODE;queryDesc2.displayWidth = displayWidth;queryDesc2.displayHeight = displayHeight;queryDesc2.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED;queryDesc2.pOutRenderWidth = &renderWidth;queryDesc2.pOutRenderHeight = &renderHeight;ffxQuery(&fsrContext, &queryDesc2.header);FFX API C++
float upscaleRatio;ffx::QueryDescFsrGetUpscaleRatioFromQualityMode queryDesc1{};queryDesc1.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED;queryDesc1.pOutUpscaleRatio = &upscaleRatio;ffx::Query(fsrContext, queryDesc1);<!-- -->uint32_t renderWidth, renderHeight;ffx::QueryDescFsrGetRenderResolutionFromQualityMode queryDesc2{};queryDesc2.displayWidth = displayWidth;queryDesc2.displayHeight = displayHeight;queryDesc2.qualityMode = FFX_FSR_QUALITY_MODE_BALANCED;queryDesc2.pOutRenderWidth = &renderWidth;queryDesc2.pOutRenderHeight = &renderHeight;ffx::Query(fsrContext, queryDesc2);查询抖动计数 / 偏移量
FSR 3.0
int32_t jitterCount = ffxFsr3GetJitterPhaseCount(renderWidth, displayWidth);<!-- -->float jitterX, jitterY;ffxFsr3GetJitterOffset(&jitterX, &jitterY, jitterIndex, jitterCount);FSR 3.1 / FFX API C
int32_t jitterCount;struct ffxQueryDescFsrGetJitterPhaseCount queryDesc1 = {0};queryDesc1.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETJITTERPHASECOUNT;queryDesc1.renderWidth = renderWidth;queryDesc1.displayWidth = displayWidth;queryDesc1.pOutPhaseCount = &jitterCount;ffxQuery(&fsrContext, &queryDesc1.header);<!-- -->float jitterX, jitterY;struct ffxQueryDescFsrGetJitterOffset queryDesc2 = {0};queryDesc2.header.type = FFX_API_QUERY_DESC_TYPE_FSR_GETJITTEROFFSET;queryDesc2.index = jitterIndex;queryDesc2.phaseCount = jitterCount;queryDesc2.pOutX = &jitterX;queryDesc2.pOutY = &jitterY;ffxQuery(&fsrContext, &queryDesc2.header);FFX API C++
int32_t jitterCount;ffx::QueryDescFsrGetJitterPhaseCount queryDesc1{};queryDesc1.renderWidth = renderWidth;queryDesc1.displayWidth = displayWidth;queryDesc1.pOutPhaseCount = &jitterCount;ffx::Query(fsrContext, queryDesc1);<!-- -->float jitterX, jitterY;ffxQueryDescFsrGetJitterOffset queryDesc2{};queryDesc2.index = jitterIndex;queryDesc2.phaseCount = jitterCount;queryDesc2.pOutX = &jitterX;queryDesc2.pOutY = &jitterY;ffx::Query(fsrContext, queryDesc2);配置帧生成
FSR 3.0
FfxFrameGenerationConfig config = {0};// fill config ...ffxFsr3ConfigureFrameGeneration(&fsr3Context, &config);FSR 3.1 / FFX API C
struct ffxConfigureDescFrameGeneration config = {0};config.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION;// fill config ...ffxConfigure(&fsrContext, &config);FFX API C++
ffx::ConfigureDescFrameGeneration config{};// fill config ...ffxConfigure(fsrContext, config);呈现回调
FSR 3.0
FfxErrorCode myPresentCallback(const FfxPresentCallbackDescription* params, void* userCtx) // note: pre-3.1 does not have user context pointer{ // pre-presentation work, e.g. UI return FFX_OK;}<!-- -->// ...FfxFrameGenerationConfig config;config.presentCallback = myPresentCallback;config.presentCallbackContext = &myEngineContext;FSR 3.1 / FFX API C
ffxReturnCode_t myPresentCallback(struct ffxCallbackDescFrameGenerationPresent* params, void* pUserCtx){ // pre-presentation work, e.g. UI return FFX_API_RETURN_OK;}<!-- -->// ...struct ffxConfigureDescFrameGeneration config;config.presentCallback = myPresentCallback;config.presentCallbackUserContext = &myEngineContext;FFX API C++
extern "C" ffxReturnCode_t myPresentCallback(ffxCallbackDescFrameGenerationPresent* params, void* pUserCtx){ // pre-presentation work, e.g. UI return FFX_API_RETURN_OK;}<!-- -->// ...ffx::ConfigureDescFrameGeneration config;config.presentCallback = myPresentCallback;config.presentCallbackUserContext = &myEngineContext;调度上采样(无 FG)
FSR 3.0
// (context created with UPSCALING_ONLY flag)FfxFsr3DispatchUpscaleDescription params = {0};// fill params ...ffxFsr3ContextDispatchUpscale(&fsr3Context, ¶ms);FSR 3.1 / FFX API C
struct ffxDispatchDescFsrUpscale params = {0};params.header.type = FFX_API_DISPATCH_DESC_TYPE_FSR_UPSCALE;// fill params ...ffxDispatch(&fsrContext, ¶ms);FFX API C++
ffx::DispatchDescFsrUpscale params{};// fill params ...ffx::Dispatch(fsrContext, params);调度上采样和 FG 准备
FSR 3.0
// dispatch upscaling and prepare resources for frame generationFfxFsr3DispatchUpscaleDescription params = {0};// fill params ...ffxFsr3ContextDispatchUpscale(&fsr3Context, ¶ms);FSR 3.1 / FFX API C
struct ffxDispatchDescFsrUpscale upscaleParams = {0};upscaleParams.header.type = FFX_API_DISPATCH_DESC_TYPE_FSR_UPSCALE;struct ffxDispatchDescFrameGenerationPrepare frameGenParams = {0};frameGenParams.header.type = FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION_PREPARE;// fill both structs with params ...ffxDispatch(&fsrContext, &upscaleParams);ffxDispatch(&fgContext, &frameGenParams);FFX API C++
ffx::DispatchDescFsrUpscale upscaleParams{};ffx::DispatchDescFrameGenerationPrepare frameGenParams{};// fill both structs with params ...ffx::Dispatch(fsrContext, upscaleParams);ffx::Dispatch(fgContext, frameGenParams);调度帧生成(无回调模式)
FSR 3.0
FfxFrameGenerationDispatchDescription fgDesc = {0};ffxGetFrameinterpolationCommandlistDX12(ffxSwapChain, fgDesc.commandList);fgDesc.outputs[0] = ffxGetFrameinterpolationTextureDX12(ffxSwapChain);// other parameters ...ffxFsr3DispatchFrameGeneration(&fgDesc);FSR 3.1 / FFX API C
struct ffxDispatchDescFrameGeneration dispatchFg = {0};dispatchFg.header.type = FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION;<!-- -->struct ffxQueryDescFrameGenerationSwapChainInterpolationCommandListDX12 queryCmdList = {0};queryCmdList.header.type = FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_INTERPOLATIONCOMMANDLIST_DX12;queryCmdList.pOutCommandList = &dispatchFg.commandList;ffxQuery(&swapChainContext, &queryCmdList);<!-- -->struct ffxQueryDescFrameGenerationSwapChainInterpolationTextureDX12 queryFiTexture{};queryFiTexture.header.type = FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_INTERPOLATIONTEXTURE_DX12;queryFiTexture.pOutTexture = &dispatchFg.outputs[0];ffxQuery(&swapChainContext, &queryFiTexture);<!-- -->// other parameters ...ffxDispatch(&fgContext, &dispatchFg);FFX API C++
ffx::DispatchDescFrameGeneration dispatchFg{};<!-- -->ffx::QueryDescFrameGenerationSwapChainInterpolationCommandListDX12 queryCmdList{};queryCmdList.pOutCommandList = &dispatchFg.commandList;ffx::Query(swapChainContext, queryCmdList);<!-- -->ffx::QueryDescFrameGenerationSwapChainInterpolationTextureDX12 queryFiTexture{};queryFiTexture.pOutTexture = &dispatchFg.outputs[0];ffx::Query(swapChainContext, queryFiTexture);<!-- -->// other parameters ...ffx::Dispatch(fgContext, dispatchFg);销毁上下文和后端
FSR 3.0
ffxFsr3ContextDestroy(&fsr3Context);// for each backend interface:free(backendInterface.scratchBuffer);FSR 3.1 / FFX API C
ffxDestroyContext(&fsrContext, NULL);FFX API C++
ffx::DestroyContext(fsrContext, nullptr);