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

DirectX12加载DDS立方体贴图失败:GPU资源全黑求助

DXR光线追踪应用中DDS立方体贴图上传GPU失败(全黑)问题

问题概述

使用DirectX12 DXR开发光线追踪应用,实现IBL(基于图像的光照)时遇到DDS立方体贴图加载异常:GPU资源的维度、数组大小、格式、Mip层级等参数均正确,但像素数据未成功上传,渲染结果全黑。已验证CPU端加载的纹理数据正常,DirectX12未返回任何错误,NSight Graphics检测显示GPU资源无像素数据。

实现步骤与关键代码

1. Miss着色器根签名创建

ComPtr<ID3D12RootSignature> D3D12HelloTriangle::CreateMissSignature() {
  nv_helpers_dx12::RootSignatureGenerator rsc;
  rsc.AddHeapRangesParameter({ {0, 1, 0, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 3} });
  auto s = GetStaticSamplers();
  return rsc.Generate(m_device.Get(), true, static_cast<UINT>(s.size()), s.data());
}

注:基于NVIDIA光线追踪示例项目,使用nv_helpers_dx12库实现

2. 立方体贴图加载

void D3D12HelloTriangle::CreateCubemapBuffer()
{
  auto tex = std::make_unique<Texture>();
  tex->name = "cubemap";
  tex->filename = L"assets/earth-cubemap.dds"; // DirectXTex提供的示例纹理
  ThrowIfFailed(CreateDDSTextureFromFile12(
    m_device.Get(),
    m_commandList.Get(),
    tex->filename.c_str(),
    tex->resource,
    tex->uploadHeap
  ));
  m_cubemap = std::move(tex);
}

说明:参考DirectXTex的DX12纹理加载实现,Texture结构体封装资源名称、路径及ID3D12Resource指针

3. 着色器资源堆创建(立方体贴图位于第4个槽位)

void D3D12HelloTriangle::CreateShaderResourceHeap() {
  m_srvUavHeap = nv_helpers_dx12::CreateDescriptorHeap(m_device.Get(), 4, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, true);

  D3D12_CPU_DESCRIPTOR_HANDLE srvHandle = m_srvUavHeap->GetCPUDescriptorHandleForHeapStart();

  // 创建输出纹理UAV(槽位0)
  D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
  uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
  m_device->CreateUnorderedAccessView(m_outputResource.Get(), nullptr, &uavDesc, srvHandle);

  srvHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

  // 创建顶层加速结构SRV(槽位1)
  D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
  srvDesc.Format = DXGI_FORMAT_UNKNOWN;
  srvDesc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE;
  srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  srvDesc.RaytracingAccelerationStructure.Location = m_topLevelASBuffers.pResult->GetGPUVirtualAddress();
  m_device->CreateShaderResourceView(nullptr, &srvDesc, srvHandle);

  srvHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

  // 创建相机CBV(槽位2)
  D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
  cbvDesc.BufferLocation = m_cameraBuffer->GetGPUVirtualAddress();
  cbvDesc.SizeInBytes = m_cameraBufferSize;
  m_device->CreateConstantBufferView(&cbvDesc, srvHandle);

  srvHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

  // 创建立方体贴图SRV(槽位3)
  D3D12_SHADER_RESOURCE_VIEW_DESC srvDescCubemap = {};
  srvDescCubemap.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  srvDescCubemap.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
  srvDescCubemap.TextureCube.MostDetailedMip = 0;
  srvDescCubemap.TextureCube.MipLevels = m_cubemap->resource->GetDesc().MipLevels;
  srvDescCubemap.TextureCube.ResourceMinLODClamp = 0.0f;
  srvDescCubemap.Format = m_cubemap->resource->GetDesc().Format;
  m_device->CreateShaderResourceView(m_cubemap->resource.Get(), &srvDescCubemap, srvHandle);
}

4. 着色器绑定表(SBT)创建

void D3D12HelloTriangle::CreateShaderBindingTable() {
  m_sbtHelper.Reset();

  D3D12_GPU_DESCRIPTOR_HANDLE srvUavHeapHandle = m_srvUavHeap->GetGPUDescriptorHandleForHeapStart();

  auto heapPointer = reinterpret_cast<UINT64*>(srvUavHeapHandle.ptr);

  m_sbtHelper.AddRayGenerationProgram(L"RayGen", { heapPointer });

  m_sbtHelper.AddMissProgram(L"Miss", { heapPointer });

  m_sbtHelper.AddHitGroup(L"HitGroup", { (void*)(m_vertexBuffer->GetGPUVirtualAddress()), heapPointer });

  uint32_t sbtSize = m_sbtHelper.ComputeSBTSize();

  m_sbtStorage = nv_helpers_dx12::CreateBuffer(
    m_device.Get(),
    sbtSize,
    D3D12_RESOURCE_FLAG_NONE,
    D3D12_RESOURCE_STATE_GENERIC_READ,
    nv_helpers_dx12::kUploadHeapProps
  );

  if (!m_sbtStorage) {
    throw std::logic_error("Could not allocate the shader binding table");
  }
  m_sbtHelper.Generate(m_sbtStorage.Get(), m_rtStateObjectProps.Get());
}

5. Miss着色器代码

#include "Common.hlsl"

TextureCube gCubemap : register(t0);
SamplerState gsamBilinearWrap : register(s0);

[shader("miss")]
void Miss(inout HitInfo payload : SV_RayPayload)
{
  uint2 launchIndex = DispatchRaysIndex().xy;
  float2 dims = float2(DispatchRaysDimensions().xy);
   
  float3 unitDir = normalize(WorldRayDirection());
  //float ramp = 0.5f * (unitDir.y + 1.0f);
  //float3 color = lerp(float3(.91f, .94f, .99f), float3(.24f, .49f, .79f), ramp); // blue sky-like fade
  
  float4 color = gCubemap.SampleLevel(gsamBilinearWrap, WorldRayDirection(), 0);
  
  payload.colorAndDistance = float4(color.rgb,1e7);
}

排查与解决方向

1. 命令列表提交与资源状态过渡

CreateDDSTextureFromFile12内部会使用传入的m_commandList执行纹理拷贝,但必须确保:

  • 命令列表执行拷贝后已提交到GPU队列,并等待执行完成,否则GPU不会处理拷贝指令
  • 立方体贴图资源在拷贝后已过渡到D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE(光线追踪着色器属于非像素着色器范畴)

可补充以下代码确保拷贝完成:

m_commandList->Close();
ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };
m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);

// 等待GPU完成拷贝
m_fence->Signal(m_commandQueue.Get(), ++m_fenceValue);
m_fence->SetEventOnCompletion(m_fenceValue, m_fenceEvent);
WaitForSingleObject(m_fenceEvent, INFINITE);

2. 根签名与SRV槽位匹配

Miss着色器中gCubemap绑定的是t0(槽位0),但代码中立方体贴图SRV创建在槽位3,这会导致着色器访问的是槽位0的输出UAV而非目标立方体贴图。修改着色器绑定为t3即可:

TextureCube gCubemap : register(t3);

3. 上传堆资源生命周期

CreateDDSTextureFromFile12创建的uploadHeap是临时上传资源,需确保GPU完成拷贝前不被释放。当前代码中tex->uploadHeap被std::move到m_cubemap,只要m_cubemap在拷贝完成前未被销毁即可,可检查代码中是否存在提前释放m_cubemap的逻辑。

4. SRV格式兼容性

确认DDS纹理格式与SRV格式匹配,若使用压缩格式(如BC6H/BC7),需确保设备支持该格式。可尝试使用无压缩格式(如DXGI_FORMAT_R8G8B8A8_UNORM)的立方体贴图测试,排除格式兼容性问题。

5. SBT参数传递正确性

检查nv_helpers_dx12::ShaderBindingTableHelper的AddMissProgram方法是否正确传递根参数。当前传入的heapPointer是堆起始地址,需确认根签名要求的参数传递方式正确,可通过NSight Graphics查看Miss着色器的根参数绑定是否指向正确的SRV。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:44:53