3.3 子资源、布局与拷贝操作


文档摘要

3.3 子资源、布局与拷贝操作 本节摘要:图像内部是 mip 层与数组层构成的子资源矩阵,每个子资源在任一时刻处于一种确定的布局——谁可以读、谁可以写、数据怎么排布。本节讲清这个坐标系统,演示从暂存缓冲到完整 mipmap 链的搬运与布局迁移全流程,并给出三种拷贝工具的分工表。 深夜排查一桩怪案:纹理上传后画面是歪的,每行错开几个像素。最终定位到 vkCmdCopyBufferToImage 少填了缓冲内行距——源数据有行对齐填充,而拷贝命令默认按紧密排布读。这类案件的主战场就是本节:子资源坐标、布局语义与拷贝参数,三者错任何一处,症状都会很诡异。

3.3 子资源、布局与拷贝操作

本节摘要:图像内部是 mip 层与数组层构成的子资源矩阵,每个子资源在任一时刻处于一种确定的布局——谁可以读、谁可以写、数据怎么排布。本节讲清这个坐标系统,演示从暂存缓冲到完整 mipmap 链的搬运与布局迁移全流程,并给出三种拷贝工具的分工表。

深夜排查一桩怪案:纹理上传后画面是歪的,每行错开几个像素。最终定位到 vkCmdCopyBufferToImage 少填了缓冲内行距——源数据有行对齐填充,而拷贝命令默认按紧密排布读。这类案件的主战场就是本节:子资源坐标、布局语义与拷贝参数,三者错任何一处,症状都会很诡异。

一、子资源:图像内部的坐标系

一张图像在 Vulkan 里不是一个整体,而是子资源(subresource)的矩阵:mip 维度乘数组层维度,深度与模板还各占一个面(aspect)。寻址一个子资源要报全四个坐标:aspectMask、mipLevel、baseArrayLayer、layerCount。这个坐标系贯穿拷贝、屏障、视图——3.2 节视图里的 subresourceRange 就是它在取景,本节的屏障与拷贝命令用的还是它。

拷贝参数因此比缓冲拷贝多出几项。vkCmdCopyBufferToImage 里,bufferOffset 定位数据起点,bufferRowLength 与 bufferImageHeight 描述源数据的「包装方式」(零表示紧密排布),imageSubresource 与 imageOffset、imageExtent 定位目标区域。开头那桩歪纹理案,答案就是 bufferRowLength:源 DDS 数据按 256 字节对齐每行,填上行距后画面复原。

二、布局:为什么数据要「换姿势」

布局回答的问题是:这块子资源现在以什么排布存在、准备好被谁访问。OPTIMAL 系列是驱动为特定访问优化的物理排布,各有专攻——TRANSFER_SRC_OPTIMAL 当拷贝源最快,SHADER_READ_ONLY_OPTIMAL 供采样器读,COLOR_ATTACHMENT_OPTIMAL 供渲染写入,PRESENT_SRC_KHR 供展示引擎上台。 GENERAL 是万用但通常最慢的兜底。UNDEFINED 表示内容不保证存在——注意它不是「没意义」而是「可以牺牲」,进入它的屏障有权丢弃数据。

布局迁移靠屏障完成(vkCmdPipelineBarrier,完整语义在第 6 章),本节先掌握标准套路。整条生命周期可以画成一台状态机:

两个高频误区写在这里。其一,渲染目标图像每帧都要「从 READ 回到 ATTACHMENT 写入再回 READ」,迁移是常态而非异常——渲染通道的场景里它被隐式接管(第 4 章)。其二,UNDEFINED 只在「旧内容可丢」时进入;「保留内容换布局」必须从具体布局迁出,典型如深度缓冲的读写往复。

三、实操:从暂存到完整 mipmap 链

把一张 256 见方的纹理从主机内存送进设备本地堆并生成整条 mip 链,是本章各概念的总装车间。流程分四拍:提交进暂存、拷入第零层、逐层缩小搬迁、最终转成可采样。

// 拍一:暂存缓冲已按 3.1 方案A 填好。拷入图像第零层 cmdBuf.begin(); VkBufferImageCopy region = {}; region.bufferOffset = 0; region.bufferRowLength = 0; // 暂存按紧密排布摆放 region.bufferImageHeight = 0; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.mipLevel = 0; region.imageSubresource.layerCount = 1; region.imageExtent = {256, 256, 1}; vkCmdPipelineBarrier(cmd, // 目标转为拷贝目的 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &toTransferDst); vkCmdCopyBufferToImage(cmd, stagingBuffer, texImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region); // 拍二到拍四:逐级 blit 缩小,源读目的写,循环推进 int32_t w = 256, h = 256; for (uint32_t i = 1; i < mipLevels; ++i) { barrierFor(texImage, i - 1, TRANSFER_DST_OPTIMAL, TRANSFER_SRC_OPTIMAL); vkCmdPipelineBarrier(cmd, ..., 1, &barrier); // 上一级转为拷贝源 VkImageBlit blit = {}; blit.srcSubresource = {COLOR_BIT, i - 1, 0, 1}; blit.srcOffsets[1] = {w, h, 1}; blit.dstSubresource = {COLOR_BIT, i, 0, 1}; blit.dstOffsets[1] = {w > 1 ? w / 2 : 1, h > 1 ? h / 2 : 1, 1}; vkCmdBlitImage(cmd, texImage, TRANSFER_SRC_OPTIMAL, texImage, TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); w /= 2; h /= 2; } // 收尾:全部 mip 转为着色器可读 barrierAllMips(TRANSFER_DST_OPTIMAL, SHADER_READ_ONLY_OPTIMAL); cmdBuf.end();

同一张图像自己拷给自己(blit 的源与目的相同)是完全合法的操作,前提是每层的布局迁移屏障把读写次序写清楚——屏障里的 subresourceRange 必须精确到层,笼统的全图屏障会打断并行性。粘贴这段代码到工程时注意:省略号处的屏障结构体与过滤阶段掩码要按第 6 章的规则填全。

四、三种搬运工具的分工

拷贝家族不止一个成员,选错工具的代价是画质或性能。

工具 能力 适用 禁忌
vkCmdCopyBuffer 纯字节搬运 暂存到正式缓冲、缓冲间搬移 无格式概念
vkCmdCopyBufferToImage 字节进图像 纹理上传主通道 源排布要对齐说明
vkCmdCopyImage 图像对图像 同格式整搬 跨格式受限
vkCmdBlitImage 缩放加格式转换 mipmap 生成、尺寸归一 质量与开销高于拷贝
vkCmdCopyQueryPoolResults 查询结果入缓冲 统计回读 属第 8 章话题

经验规则:能 Copy 就不 Blit,缩放或格式转换才升级到 Blit;线性过滤的质量不满足时考虑专用降采样着色器——那是计算管线(第 5 章)的活。

五、案例:上传时间线的完整推演

背景:加载界面要把两百余张 UI 纹理与角色贴图送进显存,首帧黑屏等待近两秒,且期间无法渲染进度条。

操作:按本节流程重排时间线。上传帧里,每张纹理走「暂存写入、拷贝、逐级 blit」的命令序列,但所有纹理共享一条大型暂存缓冲分块复用,命令缓冲在加载线程预录制;上传队列与渲染队列并行(2.3 节的多柜台),进度条由渲染队列持续呈现,加载完成时用信号量交接。

结果:黑屏消失,进度条全程流动;总体加载时间略增(并行开销),但感知时间大幅下降。暂存缓冲复用把分配次数压到个位数,3.1 节的子分配思想在这里再次兑现。

解读:拷贝操作的工程价值不在单次调用,而在时间线编排——「什么时候搬、搬的时候谁在渲染、搬完怎么交接」。布局迁移屏障是这条时间线的道岔,扳错了轻则黑帧重则数据损坏。

变式:流式加载(游戏运行中边玩边换资源)是本案例的加强版:暂存分帧复用、拷贝插入渲染间隙、旧资源等栅栏确认无人使用后再回收——回收时机的判定要等第 6 章的栅栏语义讲完才完整。

六、要点回顾

  • 子资源四坐标:面、mip 层、起始层、层数,贯穿拷贝、屏障、视图三处寻址。
  • 布局即访问合同:每种 OPTIMAL 布局服务一类访问者,迁移靠屏障,进 UNDEFINED 意味着可弃内容。
  • mipmap 四拍流程:暂存就绪、拷入第零层、逐级 blit、全链转可采样,屏障精确到层。
  • 工具分工:Copy 走直运、Blit 管缩放与转格式,能直运不绕路。
  • 时间线编排:上传的价值在于与渲染并行,交接靠同步原语,回收靠完成确认。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U