DirectX11 Engine in C ++ and Interface in C #

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); } } 
+6
source share
1 answer

1) I am curious where the bottleneck is in this structure, and I wonder if there is a more efficient way to allow me to place the DirectX11 rendering in the WinForms control.

Excluding the difference associated with the SlimDX implementation in C ++ / CLI (which should be negligible), the only difference that I see in your code compared to the SlimDX implementation is that you bother your message processing engine:

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

I would simplify and leave problems with messages from your engine. Process the message in your WndProc override and call all the operations you need on the Engine (for example, Resize , MouseMove , MouseClick or other types of input processing) and call DrawFrame directly in standby mode:

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

I would not expect this to explain the 33% difference in performance, but it might be worth a peek into it.

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.

Yes, you can use screen surfaces. However, the question arises how to update the contents of the window. For example, you can use the image viewer and set the image obtained from the surface off the screen, but this will lead to poor performance.

3) Is there a way to render multiple frames without going through the wrapper layer on each frame, but keep the application responsive?

Given the approach you use , frames are displayed on request from your application’s inactivity event handler, so no. You can do this using the screen image as described at the previous point.

+4
source

Source: https://habr.com/ru/post/978872/


All Articles