繁体   English   中英

C ++中的DirectX11引擎和C#中的接口

[英]DirectX11 Engine in C++ and Interface in C#

我有用C ++编写的DirectX11 Engine,带有CLR的C ++包装器和C#中的接口。

1) 我很好奇这个结构中的瓶颈在哪里,我想知道是否有更有效的方法让我在WinForms控件中托管DirectX11渲染。

2) 有没有办法在WinForms控件的所有者以外的线程上呈现? 我怀疑它,但我想我会问。

3) 有没有办法渲染多个帧而不通过每个帧上的包装层但保持应用程序响应?

我已经将这个设置与SlimDX进行了比较,实际上只是清除屏幕并且没有进行任何其他API调用时,FPS稍微变慢了。 SlimDX~3000 FPS,我的引擎~2000 FPS。 这不是什么大问题,但我想知道这33%的差异来自哪里,因为它可能会在以后比较20 fps到30时产生影响。

我将介绍当前的设置并尽可能多地描述。 我相信一路上人们会要求更多信息,我会根据需要进行更新。

我的WinForms GraphicsPanel控件如下。 它将系统消息传递给包装层。

public class GraphicsPanel : Control
{
    EngineWrapper Engine;

    public GraphicsPanel()
    {
        this.SetStyle(ControlStyles.Selectable, true);
        this.SetStyle(ControlStyles.UserMouse, true);
        this.SetStyle(ControlStyles.UserPaint, true);
        this.TabStop = true;
    }
    public void SetEngine(EngineWrapper Engine)
    {
        this.Engine = Engine;

        Application.Idle += OnApplicationIdle;
    }

    ~GraphicsPanel()
    {
        System.Windows.Forms.Application.Idle -= OnApplicationIdle;
    }
    void PassMessage(Message m)
    {
        Engine.ProcessWindowMessage(m.Msg, m.WParam, m.LParam);
    }
    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        PassMessage(m);
    }
    private void OnApplicationIdle(object sender, EventArgs e)
    {
        while (AppStillIdle)
            if (Engine != null)
                Engine.ProcessWindowMessage(0, IntPtr.Zero, IntPtr.Zero);
    }
    public bool AppStillIdle
    {
        get
        {
            NativeMethods.PeekMsg msg;
            return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
        }
    }
    internal class NativeMethods
    {
        private NativeMethods() { }

        [StructLayout(LayoutKind.Sequential)]
        public struct PeekMsg
        {
            public IntPtr hWnd;
            public Message msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public System.Drawing.Point p;
        }

        [System.Security.SuppressUnmanagedCodeSecurity]
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool PeekMessage(out PeekMsg msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
    }
}

Engine Wrapper中,我有这个函数将消息从WinForms控件传递到本机C ++层。

void EngineWrapper::ProcessWindowMessage(int msg, System::IntPtr wParam, System::IntPtr lParam)
{
    m_Engine->ProcessWindowMessage(msg, (void*)wParam, (void*)lParam);
}

最后, Native C ++ Engine按如下方式处理消息:

void Input::ProcessWindowMessage(int msg, void* wParam, void* lParam)
{
    if (msg == 0 || msg == WM_PAINT)
    {
        DrawFrame();
    }
    else if (msg == WM_SIZING || msg == WM_SIZE)
    {
        DoResize();
        DrawFrame();
    }
    else if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSEWHEEL)
    {
        ProcessMouseMessage(msg, wParam, lParam);
    }
}

1)我很好奇这个结构中的瓶颈在哪里,我想知道是否有更有效的方法让我在WinForms控件中托管DirectX11渲染。

忽略由于在C ++ / CLI中实现SlimDX的差异(应该可以忽略不计),我在代码中看到的与SlimDX实现相比的唯一区别是您通过消息处理困扰您的引擎:

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);
    PassMessage(m);
} 

我宁愿简化并保持消息问题远离您的引擎。 处理WndProc覆盖中的消息并调用Engine需要的任何操作(例如ResizeMouseMoveMouseClick或其他种类的输入处理),并在空闲时直接调用DrawFrame

private void OnApplicationIdle(object sender, EventArgs e)
{
    while (AppStillIdle)
        if (Engine != null)
            Engine.DrawFrame();
}

我不希望这会导致约33%的性能差异,但可能值得研究。

2)有没有办法在WinForms控件的所有者以外的线程上呈现? 我怀疑它,但我想我会问。

是的,您可以使用离屏表面。 但是,问题就变成了如何更新窗口内容。 例如,您可以使用图片查看器并设置从屏幕外表面获得的图像,但这会产生更差的性能。

3)有没有办法渲染多个帧而不通过每个帧上的包装层但保持应用程序响应?

鉴于您正在使用的方法 ,帧是从您的应用程序空闲事件处理程序按需呈现,所以没有。 您可以使用前面提到的屏幕外渲染来完成此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM