NVK 2.0.5 发布构建与三大变更详解:nvidia-macos-driver 的 Vulkan 后端稳定性修复

【免费下载链接】nvidia-macos-driver

Metal driver for NVIDIA GeForce cards on macOS Sequoia

项目地址: https://gitcode.com/gh_mirrors/nv/nvidia-macos-driver
点击查看 免费下载

在 macOS 上为 NVIDIA GeForce 显卡提供 Metal 驱动的 nvidia-macos-driver 项目里,Vulkan 后端(NVK)承担着 Metal 之上最底层的着色器编译与命令提交职责。nvk/2.0.5/README.md 记录的是一次“同源码、换构建配置”的关键发布:它把此前一直以调试构建发布的 Vulkan 驱动改为发布构建,并同时收纳了三处行为修正。本文以该说明为主线,逐条对照 nvk/nvk-macos.patch、构建脚本与插件侧加载逻辑,说明每一处变更在源码中的落点、可观察的日志现象以及排障时可用的开关。

2.0.5 到底改了什么:一次构建配置切换加三处行为修正

原文档给出的核心事实非常集中,可以归纳为四条:

  1. 2.0.4 及之前的 Vulkan 驱动是调试构建,Mesa 的 assert() 处于生效状态;其中一个断言(nvk_descriptor_set.c 中的 desc_index > 0)会让 Safari 与 mediaanalysisd 在所有 GPU 系列上被中止。
  2. 2.0.5 用同一棵源码树改为发布构建(-Dbuildtype=release -Db_ndebug=true),其 C 导出(C exports)与 2.0.4 相同。
  3. 在 2.0.4 所基于的树之上,2.0.0 就已提供的原生着色派发(native-shader dispatch,v2/v3)及其句柄导出,现在正式并入树本身。
  4. 上传队列(upload queue)在 Blackwell 之前会优先选择芯片自己的异步拷贝引擎,而不是把上传退回到图形通道;Blackwell 继续使用 COPY4。此外,写 stencil reference 的着色器不再进入 NAK 的不可达分支,写入被丢弃并给出警告,改用管线的 stencil reference。

注意第 2 条的措辞:C 导出不变。这意味着 2.0.5 不是一次 ABI 变更,而是一次“语义与环境不变、仅编译优化等级与断言开关变化”的发布。这一点直接决定了升级风险的下限——插件侧 dlsym() 解析的符号名没有变化,变化的是“同一个符号在异常输入下是否会把进程 abort 掉”。

Mesa 基线在仓库中以单独文件固定,nvk/MESA_BASE 内容为 17ca6174;docs/HOW-IT-WORKS.md 也明确写道,NVK 是把 Mesa 的 NVIDIA Vulkan 驱动与 NAK 着色器编译器打补丁,使其不依赖 Linux DRM 接口、而是跑在 macOS 的 NVRM 之上(补丁即 nvk/nvk-macos.patch,基线即 17ca6174)。因此本文所有源码结论都以该基线为准。

为什么 assert() 在发布版里是“事故级”问题

Mesa 的 C 代码习惯用 assert() 表达“这里不该发生”。在 -Db_ndebug=true 下,NDEBUG 被定义,assert() 被整体编译掉,表达式不再求值;而在调试构建里,条件不成立会直接 abort()。

对驱动而言这两种语义的差别不是“日志多一句”,而是宿主进程存活与否。原文档点出的路径非常具体:nvk_descriptor_set.c 中的 assert(desc_index > 0) 会让 Safari 和 mediaanalysisd 在每一个 GPU 系列上被中止。也就是说,它不是某个芯片的兼容性问题,而是“某些应用确实会绑定一个没有采样描述符的图像视图”这一合法(或至少是普遍存在)输入,被调试断言当成了内部不变量被破坏。

这一点能解释为什么 2.0.5 选择“同树换构建配置”而不是逐条修断言:断言所保护的不变量在真实应用中并不成立,而发布构建让这类输入经由已有的空描述符路径自然降级,比逐条重写断言更安全、覆盖面更广。

断言处的实际替代逻辑:空图像与空采样器的降级

虽然没有改 ABI,补丁里对这段代码的处理仍值得单独看,因为它揭示了“发布构建下会发生什么”。在 nvk/nvk-macos.patch 中,原先的两条断言被替换为带一次性告警的钳制逻辑:

/* A view with no sampled descriptor (index 0, the null image) used
 * to abort the app here. Index 0 is the null descriptor and reads as
 * zero, so bind that and warn once instead.
 */
uint32_t di = view->planes[plane].sampled.desc_index;
if (di == 0 || di >= (1 << 20)) {
   static bool warned;
   if (!warned) {
      warned = true;
      mesa_logw("nvk: image view plane %u has no sampled descriptor (%u); binding the null image", plane, di);
   }
   di = 0;
}
desc[plane].image_index = di;

关键点有三个:

  • 索引 0 在 NVK 的描述符表里就是空描述符,读取结果为零,因此“绑定空图像”是一个安全的降级,而不是伪造数据。
  • 上界 (1 << 20) 仍然保留为有效范围检查,说明这里同时防的是越界索引,而非仅仅是零值。
  • 告警使用 static bool warned 只打印一次,避免每帧绑定都刷日志——这与项目在别处“限制重复日志”的一贯做法一致。

同一文件的相邻 hunk(nvk/nvk-macos.patch)处理了另一半问题:一个“绑定了纹理但在该槽位没有采样器”的组合图像采样器,会以 sampler == VK_NULL_HANDLE 的形式到达这里,而去读它的 plane_count 会触发故障。补丁把条件收紧为:

if ((descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
     descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
    info && info->sampler != VK_NULL_HANDLE) {

也就是说,采样器索引保持为 0,与空图像视图把图像索引置 0 的处理方式对称。

从源码结构看,这两处改动与“改为发布构建”是互补的:发布构建消除了进程被中止的可能,而这两处代码保证被放行的输入落到一个定义良好的空描述符状态,而不是带着随机索引继续走下去。

原生着色派发与句柄导出:从“外挂”到树内

原文档第 3 条说,2.0.0 就随包提供的 native-shader dispatch(v2/v3)及其句柄导出“现在是树本身的一部分”。这句话在源码里可以拆成两层来理解。

第一层:树内新增的 C 入口

补丁在 src/nouveau/vulkan/ 下新增了一个源文件,并在构建列表里显式登记(nvk/nvk-macos.patch):

'nvmtl_nvk_sass.c',   # nvmtl: dispatch raw sm_120 SASS on NVK's channel

该文件(nvk/nvk-macos.patch)导出的入口签名如下:

__attribute__((visibility("default"))) int
nvmtl_nvk_dispatch_sass_v1(VkCommandBuffer _cmd,
                           const void *sass, uint32_t sass_len,
                           uint32_t num_gprs, uint32_t smem_size, uint32_t num_barriers,
                           const uint64_t *params, uint32_t num_params,
                           const uint32_t block[3], const uint32_t grid[3]);

visibility("default") 是必需的:该 dylib 在 meson 中以 gnu_symbol_visibility : 'hidden' 编译,非默认可见性的符号无法被 dlsym() 找到。

其内部路径(nvk/nvk-macos.patch)依次完成:把 SASS 上传到命令缓冲(nvk_cmd_buffer_upload_alloc,对齐 0x100);构造一个参数常量缓冲(NVMTL_CB0_PARAMS = 0x380 起,最多 16 个 64 位参数);用 struct nak_shader_info + struct nak_qmd_info 调 nak_fill_qmd() 生成 QMD;再发 SEND_PCAS_A / SEND_SIGNALING_PCAS_B(或较新芯片上的 SEND_SIGNALING_PCAS2_B)触发派发。

第二层:插件侧的版本化解析

插件不是按 _v1 解析的。在 plugin/NVMTLSass.m 中,解析目标是 nvmtl_nvk_dispatch_sass_v3:

g_sass_dispatch = (nvmtl_sass_dispatch_v3_fn)dlsym(g_lib, "nvmtl_nvk_dispatch_sass_v3");
if (!g_sass_dispatch || !nvmtl_sass_image_fn() || !nvmtl_sass_sampler_fn())
    why = "the loaded NVK has no direct dispatch entry points";

同时在 plugin/nvmtl_vk.c 中还有一条按 nvmtl_nvk_dispatch_sass_v1 解析的路径,并在缺失时打印 sass dispatch: NVK hook MISSING — this NVK predates it。

这正好对应原文档“v2/v3 及其句柄导出”的表述:入口按版本号演进,插件用符号是否存在来判断对端 NVK 的能力。因此“并入树本身”的实际收益是:插件的探测不再依赖外挂文件,dlsym() 能在标准安装路径 /Library/GPUBundles/nvmtl/libvulkan_nvulkan…(源码中默认值为 /Library/GPUBundles/nvmtl/libvulkan_nouveau.dylib,可由 NVMTL_NVK_DYLIB 覆盖)上稳定命中。

同一批导出里还有哪些“契约”符号

除派发入口外,补丁还导出了一组供插件查询状态的函数,它们共同构成“句柄导出”这一说法:

  • nvmtl_nvk_surface_dirty(VkDevice, surfaceID, plane)(nvk/nvk-macos.patch):通过 nvkmd_nvrm_surface_dirty() 走 NVRM_ESC_SURF_DIRTY,把 surface 脏标记通知到内核侧。
  • nvmtl_nvk_sample_depth_contract_v1 / nvmtl_nvk_sample_depth_image_v1(nvk/nvk-macos.patch):前者回填采样深度契约标志与支持的采样数掩码,后者校验某个 VkImage 是否可以按该契约采样。两者都先检查 vk_object_base->type 与 client_visible,因此传入伪造句柄时会稳定返回 VK_ERROR_UNKNOWN 而不是解引用野指针。
  • nvmtl_nvk_sparse_bind_v1():在补丁快照中是一个返回 1 的桩(nvk/nvk-macos.patch),插件据此判断稀疏绑定能力是否存在。
  • nvmtl_nvk_stage_import(const struct nvmtl_nvk_share *):线程局部暂存一次导入描述(__thread),供紧接其后的导入调用读取。

这些符号还有一个入口:nvk_GetDeviceProcAddr 被改写,对 vkNVMTLGetSampleDepthContractV1 与 vkNVMTLVerifySampleDepthImageV1 两个名字先行拦截并直接返回函数指针,其余名字交回 vk_device_get_proc_addr()(nvk/nvk-macos.patch)。因此同一能力既能被 dlsym() 使用,也能被 Vulkan 的 vkGetDeviceProcAddr 使用。

派发前的硬性拒绝条件

原生派发并非“什么都能发”。插件侧在 plugin/nvmtl_vk.c 中先做三项检查,任一不满足就返回负值,由调用方回落到 SPIR-V 路径:

返回值触发条件含义
-1命令缓冲 / SASS / 长度为空参数不完整
-2nparams > 16超过 NVMTL_SASS_MAX_PARAMS,内核入口参数放不下
-3非 NVIDIA 厂商,或未找到 hook该进程/该 NVK 不支持直发
-4tg[d] 或 threads[d] 为 0网格维度非法
-5threads[d] % tg[d] != 0线程数不是工作组宽度的整数倍,部分尾块由 SPIR-V 路径负责
-6没有绑定表参数槽位无从解析

特别注意 -5:部分工作组尾块被显式排除在直发之外,这是“让 SPIR-V 路径拥有尾部”的设计取舍,避免在 SASS 路径里重复实现一次边界处理。

此外,直发默认对显卡有门槛:nvmtl_sass_enabled() 会检查 nvmtl_sass_device_name_ok(g_name),不满足时日志给出 this GPU is not a GeForce RTX 50 series card;也可用 NVMTL_DIRECT_SASS=0 关闭,日志会写明关闭原因。

上传队列的拷贝引擎选择:COPY4 与“芯片自己的伴生 CE”

这是 2.0.5 中最容易在真机上观察到差异的一条,也是代码注释里保留了最多现场证据的一条。

规则本身

  • Blackwell 之前(Turing、Ampere、Ada)的上传队列,应当优先建立在芯片自己的异步拷贝引擎上,而不是退回图形通道。
  • 具体选择的是“第一个不是图形引擎伴生(partner)的拷贝引擎”,并以 NVB0B5 VERSION_1 的分配参数把该引擎点名给 RM,做法与 NVIDIA 自家驱动一致。
  • Blackwell 继续使用 COPY4。
  • 在 2.0.5 之前,Turing / Ampere / Ada 上的上传会退回到图形通道。

对应实现

上下文创建入口按“是否允许 CE”拆成两层。内层依据 allowCe、引擎类型与 nvrm610_on("CECHAN") 决定是否走纯拷贝引擎通道(nvk/nvk-macos.patch):

ctx->ceOnly = allowCe && engines == NVKMD_ENGINE_COPY && nvrm610_on("CECHAN");
NvU32 engineType = ctx->ceOnly ? NV2080_ENGINE_TYPE_COPY4 : NV2080_ENGINE_TYPE_GRAPHICS;

ceOnly 还影响通道标志:只有持有 ctxshare 或纯 CE 通道时才请求 PRIVILEGED_CHANNEL,失败则重试非特权通道(nvk/nvk-macos.patch)。如果连 COPY4 通道都建不起来,会打印 nvrm: COPY4 channel refused rc 0x%x - graphics channel for the upload queue,并改写 engineType 走图形通道重试。

外层则负责“建不起来就退”的兜底(nvk/nvk-macos.patch):

VkResult r = nvkmd_nvrm_create_exec_ctx_on(_dev, log_obj, engines, true, ctx_out);
if (r != VK_SUCCESS && engines == NVKMD_ENGINE_COPY && nvrm610_on("CECHAN")) {
   if (nvkmd_nvrm_diag_on()) fprintf(stderr, "nvrm: copy-engine queue could not be built on this GPU (VkResult %d) - copy queue on a graphics channel\n", (int)r);
   r = nvkmd_nvrm_create_exec_ctx_on(_dev, log_obj, engines, false, ctx_out);
}

注释记录了两个真实失败样本,这是理解“为什么顺序如此”的关键:

  1. RTX 3060 Ti(GA104):RM 成功创建了 COPY4 通道,随后在该通道上拒绝拷贝对象("bad class 0xc7b5"),导致每次 vkCreateDevice 都失败。因此当 CE 上下文建不起来时,必须能把拷贝队列改到图形通道上——而图形通道在每颗芯片上都能跑。注释同时指出,拷贝引擎的编号与它暴露的 class 因芯片而异,这正是不能写死一个引擎号的原因。
  2. 多屏行为回归:早期尝试把伴生 CE 放到第一次分配调用里,结果改变了 RTX 5060 上的拷贝路径(由 WindowServer 以拷贝填充的第 2 屏先黑后闪)。因此最终的顺序是“原调用先来、伴生 CE 只作重试”,保证已经能工作的卡行为完全不变。

图灵世代为何需要额外一步

图形通道上的拷贝子通道首先按常规方式分配(nvRmApiAlloc(..., cls_copy, NULL))。若被拒绝且不是纯 CE 通道,才去查伴生引擎(nvk/nvk-macos.patch):

NV2080_CTRL_GPU_GET_ENGINE_PARTNERLIST_PARAMS pl = { .engineType = NV2080_ENGINE_TYPE_GRAPHICS,
                                                     .partnershipClassId = pdev->base.dev_info.cls_copy, .runqueue = 0 };
...
const NvU32 ceEngine = (ps == NV_OK && pl.numPartners >= 1) ? pl.partnerList[0] : 0;
if (ceEngine) {
   NVB0B5_ALLOCATION_PARAMETERS ceParams = { .version = NVB0B5_ALLOCATION_PARAMETERS_VERSION_1, .engineType = ceEngine };
   cs = nvRmApiAlloc(&rm, ctx->hChannel, &ctx->subchannels.hCopy, pdev->base.dev_info.cls_copy, &ceParams);
}

注释解释了原因:Ampere 及以后,RM 会自己为 GR 通道上的 CE 对象配对 GR 引擎的伴生 CE(channel_descendant.c 里的 “GRCE case”);Turing 走的是旧路径,CE 引擎必须来自 NVB0B5_ALLOCATION_PARAMETERS(kceGetEngineDescFromAllocParams),参数为 NULL 时 RM 拿不到引擎。而 Ampere 及以后会忽略这些参数。

这一步的日志刻意用 vk_logw() 而不是 fprintf(stderr),注释写明了理由:vk_logw 到达插件的 debug messenger,最终以 nvk-reason: 行写进 nvmtl.log,可被 “Send logs” 收集;而旧的 stderr 行既进不了 nvmtl.log,也进不了内核日志。这也是排查“某张卡的拷贝队列到底有没有起来”时应当先看的行:

nvrm copy-engine retry: class 0x… refused on the graphics channel rc 0x…; partner lookup rc 0x…, N partner(s), engine 0x…; retry rc 0x…

开关与配置文件

nvrm610_on()(nvk/nvk-macos.patch)的取值顺序是环境变量优先,其次配置文件:

  • 环境变量名带前缀:NVRM_610_CECHAN、NVRM_610_TSG、NVRM_610_PREEMPT、NVRM_610_LGPROMO、NVRM_610_ZCULL、NVRM_610_USERMODE、NVRM_610_BOOST。
  • 配置文件为 /Library/GPUBundles/nvmtl/nvrm610.conf,键名不带前缀(如 CECHAN=0),匹配要求行首或换行之后紧跟键名。
  • 命中配置文件时会在 stderr 打印 nvrm: 610 <item>=<char> (nvrm610.conf),读到即为生效证据。
  • 语义是“非 '0' 即开”:未设置时返回真,因此这些能力默认开启,只有显式写 0 才关闭。

这也解释了为什么把 CECHAN 设为 0 能临时禁用纯 CE 通道:ceOnly 变假,上传队列直接建在图形通道上,与 2.0.5 之前的行为一致。

值得一提的是,安装脚本会保留用户在这份配置里手写的条目:它只把形如 NVMTL_/NVK_/NVRM_ 加普通值的行留下来再追加回去(package/install.sh)。这意味着升级不会悄悄丢掉你为排查问题加的开关。

NAK 里的 stencil 写入:丢弃 + 警告 + 回落到管线状态

原文档最后一条记录的是一个编译器侧行为:写 stencil reference 的着色器不再走到 NAK 的不可达分支,写入被丢弃并给出警告,改用管线的 stencil reference;该问题编号为 GH #193。

需要说明证据边界:在 nvk/nvk-macos.patch 中检索 stencil 只能看到图像侧的 stencil_copy_temp 相关逻辑(例如 sample layout 变化时重建临时拷贝,以及“Blackwell 之前不存在独立 depth/stencil”的注释)。编译器侧对 stencil 写入的丢弃处理,在本次检索的补丁快照中未定位到对应 hunk,因此本文只复述原文档记录的可观察行为,不对其具体实现位置下结论。

从工程角度看,这个取舍的方向是明确的:stencil reference 的“写入”本质上是着色器想覆盖管线状态的一个动态值,而在 NAK 的后端路径上该写入无法安全落地。与其在巡视路径上落到 unreachable / panic,不如丢弃该写入并让管线的 stencil reference 生效——这与 2.0.5 的整体基调一致:把“不该发生”的分支变成“降级 + 留下证据”。

构建与发布链路:同树换配置是怎么做的

理解 2.0.5,需要区分“开发构建脚本”和“发布构建”的不同关注点。

仓库内的 build/build263.sh 是重建 NVK 的脚本,它的 meson 配置为 debugoptimized、只开 nouveau Vulkan 驱动、关掉 Gallium/EGL/GLX/LLVM/工具链等一切不需要的东西,最终只构建一个目标:

meson setup "$B" "$S" -Dbuildtype=debugoptimized -Dvulkan-drivers=nouveau -Dgallium-drivers= -Dplatforms= \
  -Degl=disabled -Dglx=disabled -Dglvnd=disabled -Dllvm=disabled -Dmesa-clc=system -Dshared-glapi=disabled \
  -Dvulkan-layers= -Dtools= -Dbuild-tests=false -Dexpat=disabled -Dzstd=disabled -Dlibunwind=disabled \
  -Dlmsensors=disabled -Dvalgrind=disabled -Dxlib-lease=disabled -Dgallium-rusticl=false -Dspirv-tools=disabled
...
nice ninja -C "$B" -k 0 src/nouveau/vulkan/libvulkan_nouveau.dylib

而 2.0.5 的发布构建按原文档是 -Dbuildtype=release -Db_ndebug=true。两者产出的符号集合相同,差别在于 NDEBUG 与优化级别——也就是本文开头强调的那一点。

脚本里还有两道与“发布质量”直接相关的关卡,值得在自建时照做:

  1. 拒绝带 .git 的源码树:[ -e "$S/.git" ] 存在即退出,理由是 mesa 会把 git-<sha> 写进二进制。对可重复构建与体积都有影响。
  2. 拒绝强未定义引用:构建完成后执行
    U=$(nm -m "$B/src/nouveau/vulkan/libvulkan_nouveau.dylib" | grep '(undefined)' | grep -v weak | grep 'dynamically looked up')
    

    非空即失败,并提示 unresolved strong references (dlopen fails in WindowServer)。这条检查的必要性在补丁的 meson 改动里也有对应说明:生成的入口表以弱符号引用全部 Vulkan 入口点,但 Mach-O 的 weak_import 仍要求在链接期有一个定义,因此在 darwin 上必须允许未定义符号(b_lundef=false,做法与 targets/lavapipe/meson.build 相同,nvk/nvk-macos.patch)。允许未定义符号之后,就必须用 nm 复查,否则问题要到 WindowServer 里 dlopen 时才会暴露。

  3. 产出后用 strip -S 去掉调试映射(注释说明:debug-map stabs 会用绝对路径点名每个 .o),再 cp 到输出目录并打印 sha256 前缀与 UUID,便于确认装的是哪个构建。

另外补丁里有一处与 2.0.5 直接相关的隐患修复背景:在 26.3 的 meson.build 里,BVH 构建器的开关从“找到 glslang 就编”改成了显式列表,若不把 with_nouveau_vk 加进去,NVK 这个 dylib 会带五个未解析的 vk_*bvh* / vk_get_as_build_sizes 引用,导致 WindowServer 内 dlopen 失败(nvk/nvk-macos.patch 附近)。这与上面第 2 条属于同一类问题:弱符号容错 + nm 复查才是完整的闭环。

部署位置与运行时观察点

发布产物落在 /Library/GPUBundles/nvmtl/。安装脚本对该目录的处理有两处与 NVK 相关:

  • 用 ditto 而不是 cp -Rp:注释说明 cp 会沿符号链接重新施加文件标志,曾在 nvmtl/libvulkan.dylib 上以 chflags: Too many levels of symbolic links 停下(package/install.sh)。
  • 安装时逐个替换 NVMTLDriver.bundle、NVIDIAShared.bundle、nvmtl,并单独保留 nvrm610.conf 里的用户条目、重建 aircache 与 spvcache 并把属主设为 _windowserver:wheel、权限 0755(package/install.sh)。

运行时若需要确认 NVK 的版本与行为,可以按下列线索定位证据:

现象 / 日志关键字来源含义
nvk: image view plane N has no sampled descriptor (M); binding the null imagenvk_descriptor_set.c 补丁断言点被降级为空描述符,进程继续;每进程只报一次
nvrm copy-engine retry: class 0x… refused on the graphics channel rc 0x…nvkmd_nvrm_create_exec_ctx_on图形通道上的拷贝子通道被拒,走伴生 CE 重试;看末尾 retry rc 判断结果
nvrm: COPY4 channel refused rc 0x… - graphics channel for the upload queue同上纯 CE 通道建不起来,上传队列改走图形通道
nvrm: copy-engine queue could not be built on this GPU (VkResult N) - copy queue on a graphics channel外层兜底纯 CE 上下文整体失败并已回退;仅在诊断模式下出现
nvrm: 610 CECHAN=0 (nvrm610.conf)nvrm610_on配置文件开关被读到并生效
sass dispatch: NVK hook MISSING — this NVK predates it插件 nvmtl_vk.c所加载的 NVK 没有该直发入口,回落 SPIR-V
direct machine code: off (<原因>)插件 NVMTLSass.m直发被关闭,原因包括 NVMTL_DIRECT_SASS=0、Vulkan 未起、显卡不匹配、没有编译好的内核
nvk-diag: slot … CE/GFX … <== ACQUIRE NOT SATISFIED诊断转储提交侧信号量 acquire 未满足;CE/GFX 标记即该上下文是否走拷贝引擎

其中最后一行的 CE/GFX 标记来自上下文结构体的 ceOnly 字段(nvk/nvk-macos.patch),是判断“上传队列究竟落在哪个引擎上”最直接的运行时证据。

升级与回退的实践建议

结合以上源码事实,可以给出几条有依据的操作结论:

  1. 从 2.0.4 升级到 2.0.5,不需要重新适配符号。原文明确写了 C 导出与 2.0.4 相同,插件侧的 dlsym() 名称不变;风险集中在“以前会 abort 的输入现在会降级并继续执行”,因此升级后应关注的是行为差异(是否出现空图像告警、画面是否正确),而不是加载失败。
  2. 上传路径的变化只发生在 Blackwell 之前。如果 Turing / Ampere / Ada 上升级后出现与屏幕填充、窗口刷新相关的新问题,第一件事是看 nvk-reason: 行的 retry rc;需要回到旧行为可写 CECHAN=0 到 /Library/GPUBundles/nvmtl/nvrm610.conf,或临时用环境变量 NVRM_610_CECHAN=0。
  3. 自建发布版时不要省掉 nm 检查。脚本里的未定义强符号检查针对的正是 WindowServer 内 dlopen 失败这一类问题,而 b_lundef=false 恰恰让链接器不再替你挡住它。
  4. 修改 ABI 头文件后必须重建加速器。这一点与 NVK 无直接关系,但 README.md 的构建章节明确要求:nvrm_vram_abi.h 或 nvrm_gpuva_abi.h 变化后两个加速器都要重建,否则加速器能加载但 NVRMFB 会拒绝它的所有 VRAM 请求,桌面停在黑屏。

小结

nvk/2.0.5/README.md 只有十余行,但它描述的三件事在源码里都留下了清晰的落点:发布构建把调试断言从“中止宿主进程”变成“编译期消失”,并配套补齐了空图像 / 空采样器的降级逻辑;原生着色派发与句柄导出从外挂变为树内,以版本化符号让插件按能力探测;上传队列改为优先使用芯片自身的异步拷贝引擎(Blackwell 保持 COPY4),并通过伴生引擎查询、图形通道重试与 vk_logw 证据链把“某些卡建不起来”变成可诊断的状态。再加上 NAK 对 stencil 写入的“丢弃 + 警告 + 回落管线状态”,这几条共同构成了 2.0.5 的稳定性叙事:没有改变 ABI,改变的是异常路径的结局。

深入阅读建议从 nvk/nvk-macos.patch 的上下文创建段与描述符写入段入手,并对照 docs/HOW-IT-WORKS.md 理解 NVK 在整条 Metal → Vulkan → 内核驱动链路中的位置;构建细节参考 build/build263.sh,部署与配置保留逻辑参考 package/install.sh。

【免费下载链接】nvidia-macos-driver

Metal driver for NVIDIA GeForce cards on macOS Sequoia

项目地址: https://gitcode.com/gh_mirrors/nv/nvidia-macos-driver
点击查看 免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值