You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#调用FSR的ffxQuery获取版本ID异常问题求助

问题排查与解决方案

核心问题出在C#与C++互操作时的结构体内存布局、调用约定或指针处理不匹配,以下是具体排查步骤和修正代码:

常见错误点及修正

1. 结构体内存布局未显式指定

C#默认的结构体布局可能与C++的顺序布局不一致,导致VersionId字段偏移错误,读取到无效值。

修正后的结构体定义:

public enum FfxQueryType
{
    FFX_QUERY_VERSION_COUNT = 0,
    FFX_QUERY_VERSION_INFO = 1
}

// 强制顺序布局,与C++结构体对齐
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct FfxQueryVersionInfo
{
    public uint VersionId; // 对应C++的uint32_t,必须用无符号整数
    public IntPtr VersionName; // 对应C++的const char*,用IntPtr手动转字符串
}

2. 函数调用约定不匹配

AMD FSR的ffxQuery函数默认使用__cdecl调用约定,若C#未指定,会导致栈不平衡、参数传递错误。

修正后的委托定义:

// 显式指定Cdecl调用约定,与C++函数匹配
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint FfxQueryDelegate(FfxQueryType queryType, IntPtr data, uint dataSize);

3. 内存分配与指针处理错误

获取版本信息时,需为结构体数组分配足够内存,且正确遍历每个结构体的内存地址。

完整调用代码:

using System;
using System.Runtime.InteropServices;

class FsrVersionReader
{
    // P/Invoke 动态加载DLL的函数
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool FreeLibrary(IntPtr hModule);

    public enum FfxQueryType
    {
        FFX_QUERY_VERSION_COUNT = 0,
        FFX_QUERY_VERSION_INFO = 1
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct FfxQueryVersionInfo
    {
        public uint VersionId;
        public IntPtr VersionName;
    }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    private delegate uint FfxQueryDelegate(FfxQueryType queryType, IntPtr data, uint dataSize);

    public static void ReadFsrVersions(string dllPath)
    {
        IntPtr dllHandle = LoadLibrary(dllPath);
        if (dllHandle == IntPtr.Zero)
        {
            Console.WriteLine("Failed to load DLL");
            return;
        }

        try
        {
            IntPtr ffxQueryPtr = GetProcAddress(dllHandle, "ffxQuery");
            if (ffxQueryPtr == IntPtr.Zero)
            {
                Console.WriteLine("Failed to get ffxQuery address");
                return;
            }

            FfxQueryDelegate ffxQuery = Marshal.GetDelegateForFunctionPointer<FfxQueryDelegate>(ffxQueryPtr);

            // 获取版本数量
            uint versionCount = ffxQuery(FfxQueryType.FFX_QUERY_VERSION_COUNT, IntPtr.Zero, 0);
            Console.WriteLine($"Version count: {versionCount}");

            if (versionCount == 0)
                return;

            // 分配内存存储版本信息数组
            uint structSize = (uint)Marshal.SizeOf(typeof(FfxQueryVersionInfo));
            IntPtr versionInfoPtr = Marshal.AllocHGlobal((int)(structSize * versionCount));

            try
            {
                // 获取版本信息
                uint result = ffxQuery(FfxQueryType.FFX_QUERY_VERSION_INFO, versionInfoPtr, structSize * versionCount);
                if (result != versionCount)
                {
                    Console.WriteLine("Failed to retrieve all version info");
                    return;
                }

                // 遍历并输出每个版本
                for (int i = 0; i < versionCount; i++)
                {
                    IntPtr currentPtr = IntPtr.Add(versionInfoPtr, (int)(structSize * i));
                    FfxQueryVersionInfo info = Marshal.PtrToStructure<FfxQueryVersionInfo>(currentPtr);
                    string versionName = Marshal.PtrToStringAnsi(info.VersionName);
                    Console.WriteLine($"Version {i+1}: ID = {info.VersionId}, Name = {versionName}");
                }
            }
            finally
            {
                Marshal.FreeHGlobal(versionInfoPtr);
            }
        }
        finally
        {
            FreeLibrary(dllHandle);
        }
    }

    // 测试调用
    static void Main()
    {
        ReadFsrVersions("amd_fidelityfx_dx12.dll");
    }
}

额外排查步骤

  1. 验证函数名:用VS的dumpbin /exports amd_fidelityfx_dx12.dll命令查看DLL导出表,确认ffxQuery的名字是否正确(若存在 mangled 名称,需替换为实际导出名)。
  2. 检查结构体大小:对比C++中sizeof(FfxQueryVersionInfo)与C#中Marshal.SizeOf(typeof(FfxQueryVersionInfo))的返回值,确保一致(64位系统应为16字节,32位为8字节)。
  3. 调试内存:在调试器中查看versionInfoPtr指向的内存,确认是否有非0的VersionId数值(FSR 3.1.3的ID通常为0x03010300或类似编码值)。

内容的提问来源于stack exchange,提问作者Brad Moore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:13:13