使用DirectX 11在WPF控件上进行渲染

时间:2012-08-03 11:06:45

标签: wpf directx directx-11 d3dimage

我正在尝试基于WPF创建地图编辑器。目前我正在使用黑客来呈现DirectX内容。我创建了一个WinFormsHost并在WinForms-Panel上呈现。

这一切都是因为DirectX(我使用DirectX 11和Featurelevel 10)想要一个Handle(别名IntPtr)来渲染。我不知道如何在没有句柄的情况下初始化和使用DX设备。

但WPF控件无法处理。所以我发现,有一个名为“D3DImage”的互操作类。但我不明白如何使用它。

我目前的系统是这样的:

内部循环遍历“IGameloopElement”列表。对于每个,它呈现其内容调用“Draw()”。之后,它调用交换链的“Present()”来显示更改。然后它重置设备以将句柄切换到下一个元素(大多数只有一个元素)。

现在,因为D3DImage没有句柄,我该如何渲染它?我只知道我必须使用“Lock()”然后“SetBackBuffer()”,“AddDirtyRect()”然后“Unlock()”。

但是如何在不指定设备句柄的情况下渲染到DirectX11.Texture2D对象上?

我真的输了......我刚刚在codeplex上找到了“DirectX 4 WPF”示例,但这实现了DirectX的所有版本,管理设备本身并且有如此巨大的开销。 我想留在我目前的系统。我自己管理设备。我不希望WPF控件处理它。

循环应调用“Render()”,然后将后备缓冲区纹理传递给WPF控件。

有人能告诉我怎么做吗?我完全陷入困境......

非常感谢:)

[R

2 个答案:

答案 0 :(得分:4)

WPF的D3DImage仅支持Direct3D9 / Direct3D9Ex,它不支持Direct3D 11.您需要使用DXGI Surface Sharing才能使其正常工作。

答案 1 :(得分:2)

另一个答案写道,“D3DImage 仅支持 Direct3D9/Direct3D9Ex”……无论如何,这在过去几年中可能并不完全正确。正如我在评论 here 中总结的那样,关键似乎是带有 DXGI 的 Direct3D11 具有非常特定的互操作兼容模式(D3D11_SHARED_WITHOUT_MUTEX 标志),这使得 {{1} } 可直接用作 ID3D11Texture2D1,无需复制任何位,这恰好(且仅)是 WPF D3DResourceType.IDirect3DSurface9 愿意接受的。

这是对我有用的粗略草图,用于创建一个 D3D11 SampleAllocator,它生成与 WPF 的 Direct3D9 直接兼容的 D3DImage。因为这里显示的所有 .NET 互操作都是我自己设计的,所以这不会是完全准备好运行的代码,可以放入您的项目中,但方法、意图和过程应该很清楚,以便于适应。

1.初级帮手

ID3D11Texture2D1

2. D3D11 设备和上下文实例去某处

static D3D_FEATURE_LEVEL[] levels =
{
    D3D_FEATURE_LEVEL._11_1,
    D3D_FEATURE_LEVEL._11_0,
};

static IMFAttributes GetSampleAllocatorAttribs()
{
    MF.CreateAttributes(out IMFAttributes attr, 6);
    attr.SetUINT32(in MF_SA_D3D11_AWARE, 1U);
    attr.SetUINT32(in MF_SA_D3D11_BINDFLAGS, (uint)D3D11_BIND.RENDER_TARGET);
    attr.SetUINT32(in MF_SA_D3D11_USAGE, (uint)D3D11_USAGE.DEFAULT);
    attr.SetUINT32(in MF_SA_D3D11_SHARED_WITHOUT_MUTEX, (uint)BOOL.TRUE);
    attr.SetUINT32(in MF_SA_BUFFERS_PER_SAMPLE, 1U);
    return attr;
}

static IMFMediaType GetMediaType()
{
    MF.CreateMediaType(out IMFMediaType mt);
    mt.SetUINT64(in MF_MT_FRAME_SIZE, new SIZEU(1920, 1080).ToSwap64());
    mt.SetGUID(in MF_MT_MAJOR_TYPE, in WMMEDIATYPE.Video);
    mt.SetUINT32(in MF_MT_INTERLACE_MODE, (uint)MFVideoInterlaceMode.Progressive);
    mt.SetGUID(in MF_MT_SUBTYPE, in MF_VideoFormat.RGB32);
    return mt;
}

3.接下来是初始化代码

ID3D11Device4 m_d3D11_device;

ID3D11DeviceContext2 m_d3D11_context;

4.根据需要使用样本分配器重复生成纹理

void InitialSetup()
{
    D3D11.CreateDevice(
        null,
        D3D_DRIVER_TYPE.HARDWARE,
        IntPtr.Zero,
        D3D11_CREATE_DEVICE.BGRA_SUPPORT,
        levels,
        levels.Length,
        D3D11.SDK_VERSION,
        out m_d3D11_device,
        out D3D_FEATURE_LEVEL _,
        out m_d3D11_context);

    MF.CreateDXGIDeviceManager(out uint tok, out IMFDXGIDeviceManager m_dxgi);

    m_dxgi.ResetDevice(m_d3D11_device, tok);

    MF.CreateVideoSampleAllocatorEx(
        ref REFGUID<IMFVideoSampleAllocatorEx>.GUID,
        out IMFVideoSampleAllocatorEx sa);

    sa.SetDirectXManager(m_dxgi);

    sa.InitializeSampleAllocatorEx(
        PrerollSampleSink.QueueMax,
        PrerollSampleSink.QueueMax * 2,
        GetSampleAllocatorAttribs(),
        GetMediaType());
}
相关问题