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

如何使用DirectX 11.1直接渲染YUV I420数据?

DirectX 11.1 渲染 YUV I420 数据的实现方案

核心思路

DirectX 11.1 没有原生支持直接渲染 YUV I420 格式,常规做法是将 Y、U、V 三个分量作为独立纹理传入着色器,在像素着色器中完成 YUV 到 RGB 的转换计算。

具体实现步骤

1. 创建对应 Y/U/V 平面的纹理资源

YUV I420 是平面格式:Y 平面尺寸为宽×高,U、V 平面尺寸均为**(宽/2)×(高/2)**。

  • 为每个平面创建 ID3D11Texture2D,指定纹理格式为 DXGI_FORMAT_R8_UNORM(单通道8位无符号)
  • 同步创建对应的 ID3D11ShaderResourceView(SRV),供着色器访问纹理数据

示例代码片段:

// 创建Y平面纹理
D3D11_TEXTURE2D_DESC yTexDesc{};
yTexDesc.Width = width;
yTexDesc.Height = height;
yTexDesc.MipLevels = 1;
yTexDesc.ArraySize = 1;
yTexDesc.Format = DXGI_FORMAT_R8_UNORM;
yTexDesc.SampleDesc.Count = 1;
yTexDesc.Usage = D3D11_USAGE_DYNAMIC;
yTexDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
yTexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

ID3D11Texture2D* pYTexture = nullptr;
pDevice->CreateTexture2D(&yTexDesc, nullptr, &pYTexture);

// 创建Y平面SRV
D3D11_SHADER_RESOURCE_VIEW_DESC ySrvDesc{};
ySrvDesc.Format = yTexDesc.Format;
ySrvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
ySrvDesc.Texture2D.MipLevels = 1;

ID3D11ShaderResourceView* pYSrv = nullptr;
pDevice->CreateShaderResourceView(pYTexture, &ySrvDesc, &pYSrv);

U、V 平面的创建逻辑一致,仅需将 Width 设为 width/2、Height 设为 height/2。

2. 更新纹理数据

每次获取新的 YUV 数据时,通过 Map 和 Unmap 操作更新三个纹理的内容:

// 更新Y平面数据
D3D11_MAPPED_SUBRESOURCE mappedY;
pContext->Map(pYTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedY);
memcpy(mappedY.pData, yData, width * height);
pContext->Unmap(pYTexture, 0);

// 更新U平面数据
D3D11_MAPPED_SUBRESOURCE mappedU;
pContext->Map(pUTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedU);
memcpy(mappedU.pData, uData, (width/2)*(height/2));
pContext->Unmap(pUTexture, 0);

// V平面更新逻辑与U平面一致

3. 编写着色器完成YUV转RGB

在像素着色器中采样三个纹理的 Y、U、V 值,使用标准转换公式计算 RGB。注意 U、V 需双线性采样(分辨率为 Y 平面的一半)。

HLSL 像素着色器示例:

Texture2D<float> YTexture : register(t0);
Texture2D<float> UTexture : register(t1);
Texture2D<float> VTexture : register(t2);
SamplerState BilinearSampler : register(s0);

float4 PS(float4 pos : SV_POSITION, float2 uv : TEXCOORD0) : SV_TARGET
{
    float y = YTexture.Sample(BilinearSampler, uv).r;
    float u = UTexture.Sample(BilinearSampler, uv).r - 0.5f;
    float v = VTexture.Sample(BilinearSampler, uv).r - 0.5f;

    // BT.601 转换公式(如需BT.709可替换对应系数)
    float r = y + 1.402f * v;
    float g = y - 0.344f * u - 0.714f * v;
    float b = y + 1.772f * u;

    return float4(r, g, b, 1.0f);
}

顶点着色器只需传递 UV 坐标,与你之前渲染 RGB 的顶点着色器逻辑一致。

4. 绑定资源并渲染

渲染前将三个 SRV 和采样器绑定到着色器资源槽:

pContext->PSSetShaderResources(0, 1, &pYSrv);
pContext->PSSetShaderResources(1, 1, &pUSrv);
pContext->PSSetShaderResources(2, 1, &pVSrv);
pContext->PSSetSamplers(0, 1, &BilinearSampler);

后续绘制流程(如绘制全屏四边形)与你之前渲染 RGB 的流程完全相同。

额外优化点

  • 若硬件支持,可尝试使用 DXGI_FORMAT_YUV420P 相关纹理格式,减少手动转换开销,但需确认显卡兼容性
  • 可将 YUV 转 RGB 计算放到计算着色器中提前完成并缓存为 RGB 纹理,但实时像素着色器转换通常更高效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:57:35