Direct3D 12 中使用 Stream Output 的细节研究

本文详细探讨了Direct3D 12中Stream Output(SO)的使用,特别关注了BufferFilledSize和T-Buffer的问题。在BufferFilledSize部分,介绍了其创建、使用和对GPU指示数据位置的重要性。在T-Buffer部分,分析了导致模型消失的原因,指出NumElements参数理解错误是关键。通过深入研究和调试,揭示了解决这些问题的关键所在。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、前言:

二、坑1: BufferFilledSize

1.BufferFilledSize 的创建

2.BufferFilledSize 的使用

3.总结 BufferFilledSize

三、坑2:T-Buffer 和 NumElements

1.T-Buffer 问题的表象

2.T-Buffer 问题的分析

3.T-Buffer 问题的原因

四、尾声


一、前言:

        一直在做骨骼动画,其中 Skinning 的部分使用 D3D12 的 Stream Output,经过一段“苦难”的探索终于成功了,其中遇到了一些坑,这些坑看似很小很不起眼,但是各个致命,没搞明白就无法运行或出错,在此和大家分享一下。

注:以下 Stream Output 简称为 SO。

二、坑1: BufferFilledSize

        关于什么是 BufferFilledSize 请具体参看 MSDN 上相关的文档说明。简单的描述一下就是这是用来告诉 GPU 当前 SO 到哪里。

1.BufferFilledSize 的创建

(1) BufferFilledSize 的大小要求是 8 个字节(unsigned long long) 。

(2) 它可以创建在任何 Heap 是 Default 的 Buffer 中,Upload/Readback Heap 是不可以的。也就是说它既可以创建在 Output 的 Buffer 中也可以专门为它单开一个 Buffer。

(3) 一个 Mesh 中需要经过 SO 操作的每一个流都需要一个 BufferFilledSize 。比如说如果有 Position/Normal/Binormal/Tanget 这 4 个流需要 SO ,那么就需要准备 4

首先,您需要了解以下几个概念: - `ID3D11VideoDevice`:Direct3D 11视频设备接口,用于创建视频编解码器和视频处理器。 - `ID3D11VideoProcessor`:Direct3D 11视频处理器接口,用于对视频进行处理,如缩放、旋转、色彩空间转换等。 - `ID3D11VideoProcessorEnumerator`:Direct3D 11视频处理器枚举接口,用于枚举支持的视频处理器和视频处理器特性。 - `DXVAHD_VPCAPS`:视频处理器能力结构体,用于描述视频处理器的特性。 接下来是 `GetVideoProcessBltState` 的示例代码: ```c++ // 获得 D3D 设备和设备上下文 ID3D11Device* pD3DDevice = ...; ID3D11DeviceContext* pD3DDeviceContext = ...; // 创建视频设备 ID3D11VideoDevice* pVideoDevice = nullptr; HRESULT hr = pD3DDevice->QueryInterface(__uuidof(ID3D11VideoDevice), (void**)&pVideoDevice); if (FAILED(hr)) { // 处理错误 } // 创建视频处理器枚举器 ID3D11VideoProcessorEnumerator* pVideoProcessorEnumerator = nullptr; DXVAHDDDI_CONTENT_DESC contentDesc = {}; contentDesc.InputFrameFormat = DXVAHDDDI_FRAME_FORMAT_PROGRESSIVE; contentDesc.InputWidth = 1920; contentDesc.InputHeight = 1080; contentDesc.OutputFrameRate.Numerator = 1; contentDesc.OutputFrameRate.Denominator = 1; contentDesc.OutputWidth = 1920; contentDesc.OutputHeight = 1080; contentDesc.Usage = DXVAHDDDI_FILTER_BRIGHTNESS | DXVAHDDDI_FILTER_CONTRAST | DXVAHDDDI_FILTER_HUE | DXVAHDDDI_FILTER_SATURATION; hr = pVideoDevice->CreateVideoProcessorEnumerator(&contentDesc, &pVideoProcessorEnumerator); if (FAILED(hr)) { // 处理错误 } // 创建视频处理器 ID3D11VideoProcessor* pVideoProcessor = nullptr; DXVAHD_STREAM_STATE_STREAM_DATA streamData = {}; streamData.Enable = TRUE; streamData.OutputIndex = 0; streamData.Transform.AffineMatrix.e11 = 1.0f; streamData.Transform.AffineMatrix.e22 = 1.0f; streamData.Transform.AffineMatrix.e33 = 1.0f; streamData.Transform.AffineMatrix.e44 = 1.0f; hr = pVideoDevice->CreateVideoProcessor(pVideoProcessorEnumerator, 0, &pVideoProcessor); if (FAILED(hr)) { // 处理错误 } // 获取视频处理器能力 DXVAHD_VPCAPS videoProcessorCaps = {}; hr = pVideoProcessorEnumerator->GetVideoProcessorCaps(&videoProcessorCaps); if (FAILED(hr)) { // 处理错误 } // 获取视频处理器状态 DXVAHD_STREAM_STATE_BRIGHTNESS stateBrightness = {}; DXVAHD_STREAM_STATE_CONTRAST stateContrast = {}; DXVAHD_STREAM_STATE_HUE stateHue = {}; DXVAHD_STREAM_STATE_SATURATION stateSaturation = {}; UINT numData = 4; DXVAHD_STREAM_DATA streamDataArray[4] = { { &stateBrightness, sizeof(stateBrightness), 0 }, { &stateContrast, sizeof(stateContrast), 0 }, { &stateHue, sizeof(stateHue), 0 }, { &stateSaturation, sizeof(stateSaturation), 0 } }; hr = pVideoProcessor->GetVideoProcessBltState(DXVAHD_STREAM_STATE_BRIGHTNESS | DXVAHD_STREAM_STATE_CONTRAST | DXVAHD_STREAM_STATE_HUE | DXVAHD_STREAM_STATE_SATURATION, numData, streamDataArray); if (FAILED(hr)) { // 处理错误 } // 释放资源 pVideoProcessor->Release(); pVideoProcessorEnumerator->Release(); pVideoDevice->Release(); ``` 在这段代码中,我们首先创建了一个视频设备 `ID3D11VideoDevice`,然后创建了一个视频处理器枚举器 `ID3D11VideoProcessorEnumerator`,用于枚举支持的视频处理器和视频处理器特性。接着,我们创建一个视频处理器 `ID3D11VideoProcessor`,并使用 `GetVideoProcessorCaps` 获取视频处理器能力结构体 `DXVAHD_VPCAPS`。最后,我们通过 `GetVideoProcessBltState` 获取视频处理器状态,包括亮度、对比度、色调和饱和度等。 需要注意的是,这段示例代码中省略了一些错误处理代码,实际使用时需要根据需要添加。另外,这里使用的是 DirectX 11 中的视频处理接口,如果您使用的是其他版本的 DirectX,可能需要做一些调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值