HansKristian-Work/vkd3d-proton

GitHub: HansKristian-Work/vkd3d-proton

基于 Vulkan 实现 Direct3D 12 API 的翻译层,为 Proton 提供高性能的 Windows 游戏兼容支持。

Stars: 2709 | Forks: 278

# vkd3d-proton vkd3d-proton 是 VKD3D 的一个分支,旨在基于 Vulkan 实现完整的 Direct3D 12 API。 该项目为 [Proton](https://github.com/ValveSoftware/Proton) 中的 Direct3D 12 支持提供开发支持。 ## 上游 原始项目可在 [WineHQ](https://gitlab.winehq.org/wine/vkd3d) 获取。 ## 优先级 性能和游戏兼容性是我们的重要目标,为此甚至不惜牺牲对旧版驱动和系统的兼容性。 为了提升游戏性能和兼容性,我们积极地利用了现代 Vulkan 扩展和特性。 建议您尽可能使用能够获取的最新驱动,以获得最佳体验。 向后兼容 vkd3d 独立 API 并非本项目的目标。 ## 驱动 为了能以合理的性能实现 D3D12,对驱动有一些硬性要求。 - Vulkan 1.3 - 描述符索引,且除了 UniformBuffer 之外的所有类型,至少具有 1000000 个 UpdateAfterBind 描述符。 基本上必须支持 `VkPhysicalDeviceDescriptorIndexingFeatures` 中的所有特性。 - 此外,还需要以下设备特性: - `samplerMirrorClampToEdge` - `shaderDrawParameters` - `VK_EXT_robustness2` - `VK_KHR_push_descriptor` 为了获得最优或正确的行为,一些值得注意的扩展**应该**得到支持。 这些扩展以后很可能会变为强制要求。 - `VK_EXT_image_view_min_lod` 同样强烈建议支持 `VK_EXT_mutable_descriptor_type`(或供应商 `VALVE` 别名)和 `VK_EXT_descriptor_buffer`,但并非强制要求。 ### AMD (RADV) 对于 AMD,RADV 是推荐的驱动程序,也是在 AMD GPU 上进行最多测试的驱动。 目前的最低要求是 Mesa 22.0。 注意:对于较旧的 Mesa 版本,请使用 v2.6 版本。 ### NVIDIA [Vulkan beta 驱动](https://developer.nvidia.com/vulkan-driver) 通常包含我们在让游戏运行过程中发现的最新驱动修复。 始终首选最新的驱动程序(稳定版、beta 版或 Vulkan beta 轨道)。 如果您遇到问题,请始终尝试最新的驱动。 至少需要 535 系列驱动,该系列修复了大量 bug。 ### Intel 我们尚未针对 Intel GPU 进行任何测试。 ## 克隆仓库 要克隆仓库,您应该运行: ``` git clone --recursive https://github.com/HansKristian-Work/vkd3d-proton ``` 以拉取构建所需的所有子模块。 ## 构建 vkd3d-proton ### 要求: - [wine](https://www.winehq.org/)(用于提供 `widl`)[用于本地构建] - 在 Windows 上,可以将其替换为 [Strawberry Perl](http://strawberryperl.com/),因为它附带了 `widl` 并且易于查找和安装——尽管将来可能会移除这一依赖。 - [Meson](http://mesonbuild.com/) 构建系统(至少 0.49 版本) - [glslang](https://github.com/KhronosGroup/glslang) 编译器 - [Mingw-w64](http://mingw-w64.org/) 编译器、头文件和工具(至少 7.0 版本)[用于默认的 d3d12.dll 交叉编译] ### 构建: #### 简单方式 在 vkd3d-proton 目录中,运行: ``` ./package-release.sh master /your/target/directory --no-package ``` 这将在 `/your/target/directory` 中创建一个 `vkd3d-master` 文件夹,其中包含 vkd3d-proton 的 32 位和 64 位版本,可以按照上述发布版本的说明进行设置。 如果您想进行本地构建(即构建 `libvkd3d-proton.so`),请向构建脚本传递 `--native` 参数。此选项将使其使用您系统的编译器进行构建。 为了保留构建目录以供开发使用,请向脚本传递 `--dev-build` 参数。此选项隐含了 `--no-package`。在对源代码进行更改之后,您可以执行以下操作来重新构建 vkd3d-proton: ``` # 对于 32-bit,更改为 build.86 ninja -C /your/target/directory/build.64 install ``` #### 手动编译(交叉编译 d3d12.dll,默认) ``` # 64-bit build。 meson --cross-file build-win64.txt --buildtype release --prefix /your/vkd3d-proton/directory build.64 ninja -C build.64 install # 32-bit build meson --cross-file build-win32.txt --buildtype release --prefix /your/vkd3d-proton/directory build.86 ninja -C build.86 install ``` #### 手动编译(本地构建) ``` # 64-bit build。 meson --buildtype release --prefix /your/vkd3d-proton/directory build.64 ninja -C build.64 install # 32-bit build CC="gcc -m32" CXX="g++ -m32" \ PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig" \ meson --buildtype release --prefix /your/vkd3d-proton/directory build.86 ninja -C build.86 install ``` #### 针对 aarch64 的交叉编译构建 首先,使用 Steam 的运行时环境设置一个 distrobox。 ``` distrobox create --image registry.gitlab.steamos.cloud/steamrt/steamrt4/sdk/arm64-on-amd64 --name aarch64 distrobox enter aarch64 # Inside container sudo apt install mingw-w64-tools meson setup build-aarch64 \ --buildtype release \ --cross-file /usr/share/meson/cross/aarch64-linux-gnu-gcc.txt \ --cross-file ./build-widl.txt \ -Denable_extras=true \ -Denable_tests=true \ --prefix /tmp/vkd3d-proton-aarch64 ninja -C build-aarch64 install cp build-aarch64/tests/d3d12 /tmp/vkd3d-proton-aarch64/bin ``` ## 使用 vkd3d-proton 使用 vkd3d-proton 的预期方式是作为原生 Win32 DLL(d3d12.dll 和 d3d12core.dll)。 它们作为 D3D12 的直接替代品,可在 Wine(Proton 或原生版本)或 Windows 上使用。 vkd3d-proton 本身不提供必要的 DXGI 组件。 相反,DXVK(2.1+)和 vkd3d-proton 共享一个 DXGI 实现。 ### 关于在 Windows 上使用 vkd3d-proton 的说明 原生 Windows 使用主要与开发人员测试目的相关。 不要指望在 Windows 7 或 8.1 上运行的游戏会奇迹般地使用 vkd3d-proton, 因为许多游戏只有在 Windows 10 上运行时才会尝试加载 d3d12.dll。 ### 原生 Linux 构建 可以构建原生的 Linux 二进制文件,但其目的并不是与上游 Wine 兼容。 目前,原生选项主要与开发目的相关。 ## 环境变量 vkd3d-proton 使用的大多数环境变量都是出于调试目的。这些 环境变量不被视为 API 的一部分,可能会在 vkd3d-proton 的未来版本中被更改或移除。 一些调试变量是元素列表。元素之间必须用逗号或分号分隔。 - `VKD3D_CONFIG` - 用于更改 vkd3d-proton 行为的选项列表。 - `vk_debug` - 启用 Vulkan 调试扩展并加载验证层。 - `skip_application_workarounds` - 跳过所有应用程序的变通方案。 用于调试目的。 - `nodxr` - 禁用 DXR 支持。 - `dxr` - DXR 通常会自动启用。此配置强制其启用,即使在被认为不安全的情况下也是如此。 - `dxr12` - 如果 `VK_EXT_opacity_micromap` 可用,则启用对 DXR 1.2 的实验性支持。 - `force_static_cbv` - NVIDIA 上不安全的速度提升 hack。可能会也可能不会带来显著的性能提升。 - `single_queue` - 不使用异步计算或传输队列。 - `no_upload_hvv` - 阻止任何尝试将主机可见 VRAM(大容量/可调整大小的 BAR)用于 UPLOAD 堆的操作。 在某些关键情况下可能会释放出至关重要的 VRAM,代价是降低 GPU 性能。 无论哪种情况,都会保留一部分 VRAM 用于可调整大小的 BAR 分配, 因此即使在低显存显卡上这也不应成为真正的问题。 - `force_host_cached` - 强制所有主机可见分配为 CACHED,这极大地加速了捕获。 - `no_invariant_position` - 避免针对不变位置使用变通方案。该变通方案默认启用。 - `VKD3D_DEBUG` - 控制 vkd3d-proton 生成的日志消息的调试级别。接受以下值:none、err、info、fixme、warn、trace。 - `VKD3D_SHADER_DEBUG` - 控制着色器编译器生成的日志消息的调试级别。有关可接受的值,请参见 `VKD3D_DEBUG`。 - `VKD3D_LOG_FILE` - 如果设置,将 `VKD3D_DEBUG` 的日志输出重定向到文件。 - `VKD3D_VULKAN_DEVICE` - 从零开始的设备索引。用于强制选择特定的 Vulkan 设备。 - `VKD3D_FILTER_DEVICE_NAME` - 跳过不包含此子字符串的设备。 - `VKD3D_DISABLE_EXTENSIONS` - 即使可用,vkd3d-proton 也不应使用的 Vulkan 扩展列表。 - `VKD3D_TEST_DEBUG` - 在测试中启用额外的调试消息。设置为 0、1 或 2。 - `VKD3D_TEST_MATCH` - 匹配字符串。只有名称与该字符串完全匹配的测试才会运行,例如 `VKD3D_TEST_FILTER=clear_render_target` 将只匹配名为 'clear_render_target' 的测试。 对调试或开发新测试很有用。 - `VKD3D_TEST_FILTER` - 过滤字符串。只有名称与过滤字符串匹配的测试才会运行,例如 `VKD3D_TEST_FILTER=clear_render` 将匹配名为 'clear_render_target' 或 'target_clear_render' 的测试。 对调试或开发新测试很有用。 - `VKD3D_TEST_EXCLUDE` - 排除名称包含在该字符串中的测试,例如 `VKD3D_TEST_EXCLUDE=test_root_signature_priority,test_conservative_rasterization_dxil`。 - `VKD3D_TEST_PLATFORM` - 可设置为 "wine"、"windows" 或 "other"。测试平台控制测试中 todo()、todo_if()、bug_if() 和 broken() 条件的行为。 - `VKD3D_TEST_BUG` - 设置为 0 以禁用测试中的 bug_if() 条件。 - `VKD3D_PROFILE_PATH` - 如果在构建中启用了性能分析,将向 `${VKD3D_PROFILE_PATH}.${pid}` 输出分析数据块。 - `VKD3D_SWAPCHAIN_PRESENT_MODE` - 接受一个 Vulkan 呈现模式名称。如果支持,强制使用指定的呈现模式。目前接受 `IMMEDIATE`、`MAILBOX`、`FIFO`、`FIFO_RELAXED`、`FIFO_LATEST_READY`。 ### 帧率限制 `VKD3D_FRAME_RATE` 环境变量可用于限制帧率。值为 `0` 时解除帧率限制,而任何正值都会将渲染限制为给定的每秒帧数。 ## 着色器缓存 默认情况下,vkd3d-proton 管理自己的驱动缓存。 此缓存旨在缓存 DXBC/DXIL -> SPIR-V 的转换。 这减少了卡顿(当管线在最后一刻创建且应用程序依赖热驱动缓存时) 和加载时间(当应用程序做足了预先加载 PSO 的正确步骤时)。 其行为设计接近于 DXVK 状态缓存。 #### 默认行为 `vkd3d-proton.cache`(以及 `vkd3d-proton.cache.write`)被放置在当前工作目录中。 通常,这是在 Steam 中运行时的游戏安装文件夹。 #### 自定义目录 `VKD3D_SHADER_CACHE_PATH=/path/to/directory` 覆盖放置 `vkd3d-proton.cache` 的目录。 #### 禁用缓存 `VKD3D_SHADER_CACHE_PATH=0` 禁用内部缓存,任何缓存都必须由应用程序显式管理。 ### ID3D12PipelineLibrary 的行为 当使用显式着色器缓存时,对应用程序管理的管线库的需求大大降低, 并且应用程序与之交互的缓存是一个虚拟缓存。 如果 vkd3d-proton 的着色器缓存被禁用,ID3D12PipelineLibrary 将存储完整缓存所需的所有相关内容, 即 SPIR-V 和 PSO 驱动缓存 blob。 `VKD3D_CONFIG=pipeline_library_app_cache` 是 `VKD3D_SHADER_CACHE_PATH=0` 的替代方案,如果将来应用程序管理缓存比 vkd3d-proton 自动管理得更好,它可以根据应用程序配置自动启用。 ## CPU 分析(开发) 向 Meson 传递 `-Denable_profiling=true` 以启用带性能分析的构建。使用带性能分析的构建时,需使用 `VKD3D_PROFILE_PATH` 环境变量。 性能分析会转储出一个二进制数据块,可以使用 `programs/vkd3d-profile.py` 进行分析。 性能分析是一个简易系统,记录迭代次数和花费的总时钟周期(ns)。 它可以很方便地检测您正在优化的代码部分。 ## 高级着色器调试 这些功能仅供 vkd3d-proton 开发人员使用。对于任何内置的 RenderDoc 相关功能, 请向 Meson 传递 `-Denable_renderdoc=true`。 - `VKD3D_SHADER_DUMP_PATH` - 转储着色器字节码的路径。 字节码以 `$hash.{spv,dxbc,dxil}` 格式转储。 - `VKD3D_SHADER_OVERRIDE` - 可找到覆盖着色器的路径。 如果应用程序正在使用 `$hash` 创建管线,并且 `$VKD3D_SHADER_OVERRIDE/$hash.spv` 存在, 将转而使用该 SPIR-V 文件。 - `VKD3D_AUTO_CAPTURE_SHADER` - 如果将其设置为着色器哈希值,并且启用了 RenderDoc 层, vkd3d-proton 将在遇到特定着色器时自动进行捕获。 - `VKD3D_AUTO_CAPTURE_COUNTS` - 逗号分隔的索引列表。这可用于控制要捕获哪些队列提交。 例如,使用 `VKD3D_AUTO_CAPTURE_COUNTS=0,4,10` 可捕获第 0 次(首次提交)、第 4 次和第 10 次作为候选的提交。 如果 `VKD3D_AUTO_CAPTURE_COUNTS` 为 `-1`,则整个应用程序运行时可以变成一个大型捕获。 这仅用于捕获诸如测试套件之类的内容, 或者具有有限运行时间的微型应用程序,以便更容易调试跨提交的工作。 如果仅设置了 `VKD3D_AUTO_CAPTURE_COUNTS`,则任何队列提交都会被视为捕获候选。 如果仅 `VKD3D_AUTO_CAPTURE_SHADER`,则 `VKD3D_AUTO_CAPTURE_COUNTS` 被视为等于 `"0"`,即仅在首次遇到目标着色器时进行捕获。 如果两者都设置了,则仅当提交包含目标着色器的使用时,捕获计数器才会递增并予以考虑。 ### 面包屑调试 (Breadcrumbs debugging) 对于调试 GPU 挂起,了解崩溃发生的位置非常有用。 如果构建启用了跟踪功能(非发布版本),则也会启用面包屑支持。 `VKD3D_CONFIG=breadcrumbs` 将使用 `VK_AMD_buffer_marker` 或 `VK_NV_device_checkpoints` 检测命令列表。 在 GPU 设备丢失或超时时,崩溃转储将被写入日志。 为了在 RADV 上获得最佳结果,请使用 `RADV_DEBUG=syncshaders`。日志将打印当时正在执行的命令列表的摘要形式, 并尝试缩小可能导致崩溃的命令范围。 ### 着色器日志 可以记录替换着色器的输出,本质上是一个自定义的着色器 printf。要启用此功能,必须支持 `VK_KHR_buffer_device_address`。 首先,例如使用 `VKD3D_SHADER_DEBUG_RING_SIZE_LOG2=28` 在主机内存中设置一个 256 MiB 的环形缓冲区。 由于此缓冲区是在主机内存中分配的,您可以随意将其设置得尽可能大,因为它不会消耗 VRAM。 一个工作线程将读取传入的数据并将其记录下来。未来有可能在这里发出更多结构化的信息。 实现此功能而不是使用验证层 printf 系统的主要原因是运行时性能, 并且避免了因引入增加锁等操作的验证层而意外掩盖任何 bug。 如果 `debugPrintEXT` 更适合您的调试场景,同样可以使用它。 通过这种着色器替换方案,我们能够尽可能无干扰地添加着色器日志。 ``` # 在充满 override shaders 的文件夹内,使用以下命令 build 所有内容: make -C /path/to/include/shader-debug M=$PWD ``` 然后,该着色器可以包含 `#include "debug_channel.h"` 并使用下面的各种函数。 ``` void DEBUG_CHANNEL_INIT(uvec3 ID); ``` 在您替换的着色器中的某处使用。这应该使用 `gl_GlobalInvocationID` 或类似的方法进行初始化。 此 ID 将显示在日志中。对于每个调用 `DEBUG_CHANNEL_INIT` 的子组,都会生成一个实例计数器。 这允许您将多条源自相同实例计数器的消息关联起来,该计数器会与 ID 一起记录。 一个调用可以通过实例 + `DEBUG_CHANNEL_INIT` id 唯一标识。 `DEBUG_CHANNEL_INIT` 可以从非均匀控制流中调用,因为它不使用 `barrier()` 或类似结构。 因此,它也可以在顶点和片段着色器中使用。 ``` void DEBUG_CHANNEL_MSG(); void DEBUG_CHANNEL_MSG(uint v0); void DEBUG_CHANNEL_MSG(uint v0, uint v1, ...); // Up to 4 components, can be expanded as needed up to 16. void DEBUG_CHANNEL_MSG(int v0); void DEBUG_CHANNEL_MSG(int v0, int v1, ...); // Up to 4 components, ... void DEBUG_CHANNEL_MSG(float v0); void DEBUG_CHANNEL_MSG(float v0, float v1, ...); // Up to 4 components, ... ``` 这些函数用于记录日志,格式为 uint 类型使用 `#%x`,int 类型使用 `%d`,float 类型使用 `%f`。 ## 描述符调试 如果在构建时启用了 `-Denable_descriptor_qa=true`,您可以将 `VKD3D_DESCRIPTOR_QA_LOG` 环境变量设置为一个文件。 所有描述符的更新和复制都会被记录下来,以便将描述符与 GPU 崩溃转储关联起来。默认情况下不启用 `enable_descriptor_qa`,因为它在极其热门的代码路径中增加了一些直接开销。 ### GPU 辅助调试 如果在启用 `-Denable_descriptor_qa=true` 的构建中设置了 `VKD3D_CONFIG=descriptor_qa_checks`,所有着色器都将被注入代码以检查无效访问。在日志中,您将看到此信息以确保该功能已启用。 ``` 932:info:vkd3d_descriptor_debug_init_once: Enabling descriptor QA checks! ``` 主要动机是紧密的集成和高性能。 GPU 辅助调试可以以远超可玩速度的帧率运行。 #### 描述符堆索引越界 ``` ============ Fault type: HEAP_OUT_OF_RANGE Fault type: MISMATCH_DESCRIPTOR_TYPE CBV_SRV_UAV heap cookie: 1800 Shader hash and instruction: edbaf1b5ed344467 (1) Accessed resource/view cookie: 0 Shader desired descriptor type: 8 (STORAGE_BUFFER) Found descriptor type in heap: 0 (NONE) Failed heap index: 1024000 ========== ``` 指令 `(1)` 也会被报告, 并且可以通过相关着色器的反汇编来准确定位哪里出了问题。 使用 `VKD3D_SHADER_DUMP_PATH=/my/folder` 转储所有着色器, 并运行 `spirv-cross -V /my/folder/edbaf1b5ed344467.spv`。 (注意:转储前请清空该文件夹,现有文件不会被覆盖)。 可以通过查看最后一个参数来识别出错的指令,例如: ``` uint fixup_index = descriptor_qa_check(heap_index, descriptor_type, 1u /* instruction ID */); ``` #### 不匹配的描述符类型 ``` ============ Fault type: MISMATCH_DESCRIPTOR_TYPE CBV_SRV_UAV heap cookie: 1800 // Refer to VKD3D_DESCRIPTOR_QA_LOG Shader hash and instruction: edbaf1b5ed344467 (1) Accessed resource/view cookie: 1802 // Refer to VKD3D_DESCRIPTOR_QA_LOG Shader desired descriptor type: 8 (STORAGE_BUFFER) Found descriptor type in heap: 1 (SAMPLED_IMAGE) Failed heap index: 1025 ========== ``` #### 访问已销毁的资源 ``` ============ Fault type: DESTROYED_RESOURCE CBV_SRV_UAV heap cookie: 1800 Shader hash and instruction: edbaf1b5ed344467 (2) Accessed resource/view cookie: 1806 Shader desired descriptor type: 1 (SAMPLED_IMAGE) Found descriptor type in heap: 1 (SAMPLED_IMAGE) Failed heap index: 1029 ========== ``` ### 使用 RADV 转储调试描述符崩溃(硬核终极噩梦模式) 当您陷入绝对绝望的境地时,还有一种方法可以调试 GPU 挂起。 首先,安装 [umr](https://gitlab.freedesktop.org/tomstdenis/umr) 并将该二进制文件设置为 setuid。 `ACO_DEBUG=force-waitcnt RADV_DEBUG=hang VKD3D_DESCRIPTOR_QA_LOG=/somewhere/desc.txt %command%` 也可以使用 `RADV_DEBUG=hang,umr`,但在 Wine 内部会发生一些奇怪的事情,导致 UMR 转储并不总是成功。 相反,当 GPU 挂起时,可以通过 SSH shell 手动调用 umr。 ``` #!/bin/bash mkdir -p "$HOME/umr-dump" # 对于 Navi,较旧的 GPU 可能有不同的 rings。参见 RADV 源码。 umr -R gfx_0.0.0 > "$HOME/umr-dump/ring.txt" 2>&1 umr -O halt_waves -wa gfx_0.0.0 > "$HOME/umr-dump/halt-waves-1.txt" 2>&1 umr -O bits,halt_waves -wa gfx_0.0.0 > "$HOME/umr-dump/halt-waves-2.txt" 2>&1 ``` RADV 会在 `~/radv_dumps*` 中放置一个文件夹,而 UMR 脚本会将 wave 转储放置在 `~/umr-dump` 中。 首先,我们可以研究 wave 转储以查看崩溃发生的位置,例如: ``` pgm[6@0x800120e26c00 + 0x584 ] = 0xf0001108 image_load v47, v[4:5], s[48:55] dmask:0x1 dim:SQ_RSRC_IMG_2D unorm pgm[6@0x800120e26c00 + 0x588 ] = 0x000c2f04 ;; pgm[6@0x800120e26c00 + 0x58c ] = 0xbf8c3f70 s_waitcnt vmcnt(0) * pgm[6@0x800120e26c00 + 0x590 ] = 0x930118c0 s_mul_i32 s1, 64, s24 pgm[6@0x800120e26c00 + 0x594 ] = 0xf40c0c09 s_load_dwordx8 s[48:55], s[18:19], s1 pgm[6@0x800120e26c00 + 0x598 ] = 0x02000000 ;; ``` excp: 256 是一个内存错误(至少在 5700xt 上是如此)。 ``` TRAPSTS[50000100]: excp: 256 | illegal_inst: 0 | buffer_oob: 0 | excp_cycle: 0 | excp_wave64hi: 0 | xnack_error: 1 | dp_rate: 2 | excp_group_mask: 0 | ``` 我们可以检查所有的 VGPR 和所有的 SGPR,这里是针对图像描述符的。 ``` [ 48.. 51] = { 0130a000, c0500080, 810dc1df, 93b00204 } [ 52.. 55] = { 00000000, 00400000, 002b0000, 800130c8 } ``` 解码 VA(虚拟地址)并研究 `bo_history.log`。RADV 中有一个脚本可让您查询 VA 的历史记录。 这使我们能够验证相关 VA 在某个时刻已被释放。 在撰写本文时,还没有简单的方法可以解码原始的描述符 blob,但当您足够绝望时,您可以手动完成 :| 在 `pipeline.log` 中,我们有完整的 SPIR-V(带有指向源 DXIL/DXBC 的 OpSource 引用) 以及崩溃管线的反汇编。在这里我们可以研究代码以弄清楚读取了哪个描述符。 ``` // s7 is the descriptor heap index, s1 is the offset (64 bytes per image descriptor), // s[18:19] is the descriptor heap. s_mul_i32 s1, 64, s7 ; 930107c0 s_load_dwordx8 s[48:55], s[18:19], s1 ; f40c0c09 02000000 s_waitcnt lgkmcnt(0) ; bf8cc07f image_load v47, v[4:5], s[48:55] dmask:0x1 dim:SQ_RSRC_IMG_2D unorm ; f0001108 000c2f04 ``` ``` [ 4.. 7] = { 03200020, ffff8000, 0000002b, 00000103 } ``` 即描述符索引 #259。基于此,我们可以检查描述符 QA 日志,并验证应用程序确实执行了无效操作,进而导致了 GPU 挂起。
标签:3D图形渲染, AMD RADV, Direct3D 12, DirectX 12兼容, Linux游戏, Mesa驱动, NVIDIA驱动, Proton, Steam Deck, UML, VKD3D, VKD3D-Proton, Vulkan, Wine, 兼容性层, 图形API转换, 客户端加密, 开源图形驱动, 技术栈:Vulkan 1.3, 游戏兼容层, 游戏移植, 翻译层, 跨平台游戏, 预握手