4

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

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

但是 WPF 控件没有句柄。所以我刚刚发现,有一个名为“D3DImage”的互操作类。但我不明白如何使用它。

我当前的系统是这样工作的:

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

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

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

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

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

谁能告诉我该怎么做?我完全卡住了...

非常感谢 :)

R

4

2 回答 2

4

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

于 2014-10-01T18:43:13.200 回答
3

另一个答案写道,“D3DImage仅支持Direct3D9/Direct3D9Ex ”……这在过去几年中可能并不完全正确。正如我在此处的评论中总结的那样,关键似乎是带有DXGI的Direct3D11具有非常特定的互操作兼容性模式(D3D11_SHARED_WITHOUT_MUTEX标志),它可以ID3D11Texture2D1直接用作D3DResourceType.IDirect3DSurface9) WPFD3DImage愿意接受什么。

这是对我有用的粗略草图,它创建了一个D3D11 SampleAllocator,它产生ID3D11Texture2D1的内容与 WPF 的 Direct3D9 直接兼容。因为这里显示的所有 .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;
}
于 2021-02-02T03:17:13.813 回答