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

4
我正在尝试基于WPF创建一个地图编辑器。目前我正在使用一种hack方法来渲染DirectX内容。我创建了一个WinFormsHost并在WinForms-Panel上进行渲染。
所有这些都是因为DirectX(我正在使用具有Featurelevel 10的DirectX 11)需要句柄(别名IntPtr)来进行渲染。我不知道如何在没有句柄的情况下初始化和使用DX设备。
但是WPF控件没有句柄。所以我刚刚发现了一个名为“D3DImage”的interop类。但我不知道如何使用它。
我的当前系统工作方式如下:
内部循环遍历“IGameloopElement”列表。对于每个元素,它调用“Draw()”来呈现其内容。之后,它调用交换链的“Present()”以显示更改。然后,它将设备重置为切换到下一个元素的句柄(大多数情况下只有一个元素)。
现在,因为D3DImage没有句柄,我该如何在其上进行渲染?我只知道我必须使用“Lock()”,然后“SetBackBuffer()”,“AddDirtyRect()”,然后“Unlock()”。
但是如果不指定设备的句柄,我该如何在DirectX11.Texture2D对象上进行渲染?
我真的迷失了...我刚在codeplex上找到了“DirectX 4 WPF”示例,但这个示例实现了所有版本的DirectX,自己管理设备,并具有如此巨大的开销。我想保持我的现有系统。我正在自己管理设备。我不希望WPF控件来处理它。
循环应该只调用“Render()”,然后将后备缓冲区纹理传递给WPF控件。
是否有人能告诉我如何做到这一点?我完全被卡住了...
非常感谢:)
R

这是什么编程语言?我对你的问题有一个相当好的想法,但我需要知道你使用的编程语言,以便了解你如何管理DirectX资源。 - Alex
这是C#。我已经改用另一种方法了,它是SharpDX示例中使用的方法。虽然在将鼠标移动到UI上时有时会闪烁,但它运行得相当不错。你有什么解决方案? - SharpShade
所以,如果我正确理解了你的问题,你有一个Texture2D句柄值(或者可以获取一个),一个D3DImage类,并且你想要将所有数据渲染到D3DImage中。如果是这种情况,将所有内容渲染到纹理中,锁定D3DImage,调用D3DImage.SetBackBuffer()时指定该纹理的句柄,然后将整个表面设置为脏矩形并解锁它。我不确定这个解决方案是否适用于你的目的,因为似乎D3DImage只支持D3D9,但我可能在这方面弄错了。 - Alex
嗯,听起来就像SDX示例展示的那样。渲染到它,锁定它,标记为脏数据,解锁。似乎没有其他方法,但还是谢谢你的帮助 :) 这种方式肯定有效(因为我已经在使用它了 - 问题有点老 :D) - SharpShade
2个回答

4

WPF的D3DImage只支持Direct3D9/Direct3D9Ex,不支持Direct3D 11。您需要使用DXGI Surface Sharing来使其正常工作。


这个问题已经在两年前被问过了 ;) 我已经解决了,不过还是谢谢你的回答 ;) - SharpShade

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

这是我使用的创建与WPF的Direct3D9直接兼容的ID3D11Texture2D1D3D11 SampleAllocator的大致概述。由于此处显示的所有.NET互操作都是我自己设计的,因此这不是适用于项目的完全可运行代码,但方法、意图和程序应清晰易懂,易于调整。

1. 初步辅助器

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;
}

2. D3D11设备和上下文实例放在哪里

ID3D11Device4 m_d3D11_device;

ID3D11DeviceContext2 m_d3D11_context;

3. 初始化代码紧随其后

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());
}

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

ID3D11Texture2D1 CreateTexture2D(SIZEU sz)
{
    var vp = new D3D11_VIEWPORT
    {
        TopLeftX = 0f,
        TopLeftY = 0f,
        Width = sz.Width,
        Height = sz.Height,
        MinDepth = 0f,
        MaxDepth = 1f,
    };

    m_d3D11_context.RSSetViewports(1, ref vp);

    var desc = new D3D11_TEXTURE2D_DESC1
    {
        SIZEU = sz,
        MipLevels = 1,
        ArraySize = 1,
        Format = DXGI_FORMAT.B8G8R8X8_UNORM,
        SampleDesc = new DXGI_SAMPLE_DESC { Count = 1, Quality = 0 },
        Usage = D3D11_USAGE.DEFAULT,
        BindFlags = D3D11_BIND.RENDER_TARGET | D3D11_BIND.SHADER_RESOURCE,
        CPUAccessFlags = D3D11_CPU_ACCESS.NOT_REQUESTED,
        MiscFlags = D3D11_RESOURCE_MISC.SHARED,
        TextureLayout = D3D11_TEXTURE_LAYOUT.UNDEFINED,
    };

    m_d3D11_device.CreateTexture2D1(ref desc, IntPtr.Zero, out ID3D11Texture2D1 tex2D);
    return tex2D;
}

感谢你的补充,可能会对一些人有所帮助。至于我,目前已经不再从事那个项目了,所以我无法真正地去验证那个东西。但是我正在好奇地关注Avalonia的发展,因为他们在Windows上使用SharpDX,并且可能会首先采用基于DX11/12的渲染引擎。或者也许MAUI会带来一些好东西,我们拭目以待。 - SharpShade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接