I have my DirectX11 Engine written in C ++, a C ++ shell with CLR, and a C # interface.
1) I am wondering where the bottleneck in this structure is, and I wonder if there is a more efficient way to allow me to place the DirectX11 rendering in the WinForms control.
2) Is there a way to render in a thread other than the owner of the WinForms control? I doubt it, but decided that I would ask.
3) Is there a way to render multiple frames without going through the wrapper layer on each frame, but react to the application?
I compared this setting with SlimDX and actually get a little slower FPS just by clearing the screen and not making any other API calls. SlimDX ~ 3000 FPS, My Engine ~ 2000 FPS. This is not a big problem, but I wonder where the difference is from 33%, since it will probably change it later when comparing 20 frames per second to 30.
I will go through the current setup and describe as much as I can. I'm sure people will ask for more information along the way, and I will update as necessary.
My WinForms GraphicsPanel Control is below. It transfers system messages to a wrapper.
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); } }
In Engine Browser I have this function to transfer a message from a WinForms control to my own C ++ layer.
void EngineWrapper::ProcessWindowMessage(int msg, System::IntPtr wParam, System::IntPtr lParam) { m_Engine->ProcessWindowMessage(msg, (void*)wParam, (void*)lParam); }
Finally, Native C ++ Engine processes messages as such:
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); } }