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

D3D11on12中无法从封装的普通ID3D12Resource查询IDXGISurface

问题:D3D11On12封装普通D3D12资源时QueryInterface获取IDXGISurface失败

在D2D结合D3D11On12的场景中,调用ID3D11On12Device::CreateWrappedResource、ID3D11Texture2D::QueryInterface<IDXGISurface>、ID2D1DeviceContext::CreateBitmapFromDxgiSurface三个函数时,封装交换链缓冲区可正常通过QueryInterface获取IDXGISurface,但封装普通ID3D12Resource时会返回错误0x80004002 : 'No such interface supported'。


官方示例代码片段

ThrowIfFailed(m_d3d11On12Device->CreateWrappedResource(
            m_renderTargets[n].Get(),
            &d3d11Flags,
            D3D12_RESOURCE_STATE_RENDER_TARGET,
            D3D12_RESOURCE_STATE_PRESENT,
            IID_PPV_ARGS(&m_wrappedBackBuffers[n])
            ));

// Create a render target for D2D to draw directly to this back buffer.
ComPtr<IDXGISurface> surface;
ThrowIfFailed(m_wrappedBackBuffers[n].As(&surface));
ThrowIfFailed(m_d2dDeviceContext->CreateBitmapFromDxgiSurface(
    surface.Get(),
    &bitmapProperties,
    &m_d2dRenderTargets[n]
    ));

我的代码片段

winrt::com_ptr<ID2D1Bitmap1> d2dBitmap;
winrt::com_ptr<ID3D11Resource> d3d11Resource;

auto desc = d3dx12::CD3DX12_RESOURCE_DESC::Tex2D(
    DXGI_FORMAT_R8G8B8A8_UNORM, text_metrics.width, 53);
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;

winrt::com_ptr<ID3D12Resource> d3d12Resource;
auto heapProperties = d3dx12::CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
winrt::check_hresult(resources.D3D12Device().CreateCommittedResource(
    &heapProperties,
    D3D12_HEAP_FLAG_NONE,
    &desc,
    D3D12_RESOURCE_STATE_COMMON,
    nullptr,
    IID_PPV_ARGS(d3d12Resource.put())));

D3D11_RESOURCE_FLAGS d3d11Flags = { D3D11_BIND_RENDER_TARGET };
winrt::check_hresult(
m_d3d11On12Device->CreateWrappedResource(
    d3d12Resource.get(),
    &d3d11Flags,
    D3D12_RESOURCE_STATE_RENDER_TARGET,
    D3D12_RESOURCE_STATE_RENDER_TARGET,
    IID_PPV_ARGS(d3d11Resource.put())
));

auto tex2d = d3d11Resource.as<ID3D11Texture2D>(); // good!
auto surface2 = tex2d.as<IDXGISurface>(); //0x80004002 : 'No such interface supported'.
auto surface = d3d11Resource.as<IDXGISurface>(); //0x80004002 : 'No such interface supported'.

错误原因

  • 交换链缓冲区是DXGI直接管理的资源,天然支持IDXGISurface接口;而手动创建的普通D3D12资源并非DXGI表面类型,因此Wrapped后的D3D11纹理不会直接暴露IDXGISurface接口,直接调用QueryInterface会失败。
  • 你的D3D12资源初始状态为D3D12_RESOURCE_STATE_COMMON,但CreateWrappedResource中传入的BeforeState是D3D12_RESOURCE_STATE_RENDER_TARGET,存在状态不匹配的隐患,虽未直接导致当前错误,但可能引发后续问题。

解决方案

1. 修正IDXGISurface的获取方式

不要直接从ID3D11Texture2D查询IDXGISurface,而是先将D3D11资源转换为IDXGIResource,再通过GetSurface方法获取表面:

auto tex2d = d3d11Resource.as<ID3D11Texture2D>();

// 替换原QueryInterface逻辑
winrt::com_ptr<IDXGIResource> dxgiResource;
winrt::check_hresult(tex2d.as(&dxgiResource));

winrt::com_ptr<IDXGISurface> surface;
// 参数0表示获取第0个Mip层级的表面
winrt::check_hresult(dxgiResource->GetSurface(0, IID_PPV_ARGS(surface.put())));

2. 修复D3D12资源状态不匹配问题

创建D3D12资源后,先将其从COMMON状态转换为RENDER_TARGET状态,再执行CreateWrappedResource:

// 创建D3D12资源后添加状态转换屏障
D3D12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
    d3d12Resource.get(),
    D3D12_RESOURCE_STATE_COMMON,
    D3D12_RESOURCE_STATE_RENDER_TARGET
);
resources.CommandList()->ResourceBarrier(1, &barrier);

// 提交命令列表并等待执行完成(需根据你的命令队列逻辑实现)
resources.CommandList()->Close();
ID3D12CommandList* lists[] = { resources.CommandList().get() };
resources.CommandQueue()->ExecuteCommandLists(_countof(lists), lists);

// 等待GPU完成状态转换
winrt::com_ptr<ID3D12Fence> fence;
winrt::check_hresult(resources.D3D12Device()->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence.put())));
uint64_t fenceValue = 1;
resources.CommandQueue()->Signal(fence.get(), fenceValue);
if (fence->GetCompletedValue() < fenceValue)
{
    HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    winrt::check_hresult(fence->SetEventOnCompletion(fenceValue, fenceEvent));
    WaitForSingleObject(fenceEvent, INFINITE);
    CloseHandle(fenceEvent);
}

3. 确保D3D11On12设备创建时包含必要标志

创建D3D11On12设备时,必须指定D3D11_CREATE_DEVICE_BGRA_SUPPORT标志,这是D2D与D3D11互操作的前提:

D3D11_DEVICE_CREATION_FLAGS d3d11Flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
winrt::check_hresult(D3D11On12CreateDevice(
    d3d12Device.get(),
    d3d11Flags,
    nullptr,
    0,
    reinterpret_cast<IUnknown**>(&d3d12CommandQueue),
    1,
    0,
    m_d3d11Device.put(),
    m_d3d11DeviceContext.put(),
    nullptr
));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 06:57:06