SharpDX: best practice for multiple RenderForms?

Posted by Rob Jellinghaus on Game Development See other posts from Game Development or by Rob Jellinghaus
Published on 2012-07-26T06:20:36Z Indexed on 2012/09/24 9:51 UTC
Read the original article Hit count: 1684

Filed under:
|

I have an XNA app, but I really need to add multiple render windows, which XNA doesn't do. I'm looking at SharpDX (both for multi-window support and for DX11 / Metro / many other reasons). I decided to hack up the SharpDX DX11 MultiCubeTexture sample to see if I could make it work.

My changes are pretty trivial. The original sample had:

[STAThread]
private static void Main()
{
    var form = new RenderForm("SharpDX - MiniCubeTexture Direct3D11 Sample");
    ...

I changed this to:

        struct RenderFormWithActions
        {
            internal readonly RenderForm Form;
            // should just be Action but it's not in System namespace?!
            internal readonly Action RenderAction;
            internal readonly Action DisposeAction;
            internal RenderFormWithActions(RenderForm form, Action renderAction, Action disposeAction)
            {
                Form = form;
                RenderAction = renderAction;
                DisposeAction = disposeAction;
            }
        }

        [STAThread]
        private static void Main()
        {
            // hackity hack
            new Thread(new ThreadStart(() =>
            {
                RenderFormWithActions form1 = CreateRenderForm();
                RenderLoop.Run(form1.Form, () => form1.RenderAction(0));
                form1.DisposeAction(0);
            })).Start();
            new Thread(new ThreadStart(() =>
            {
                RenderFormWithActions form2 = CreateRenderForm();
                RenderLoop.Run(form2.Form, () => form2.RenderAction(0));
                form2.DisposeAction(0);
            })).Start();
        }

        private static RenderFormWithActions CreateRenderForm()
        {
            var form = new RenderForm("SharpDX - MiniCubeTexture Direct3D11 Sample");
            ...

Basically, I split out all the Main() code into a separate method which creates a RenderForm and two delegates (a render delegate, and a dispose delegate), and bundles them all together into a struct. I call this method twice, each time from a separate, new thread. Then I just have one RenderLoop on each new thread.

I was thinking this wouldn't work because of the [STAThread] declaration -- I thought I would need to create the RenderForm on the main (STA) thread, and run only a single RenderLoop on that thread. Fortunately, it seems I was wrong. This works quite well -- if you drag one of the forms around, it stops rendering while being dragged, but starts again when you drop it; and the other form keeps chugging away.

My questions are pretty basic:

  1. Is this a reasonable approach, or is there some lurking threading issue that might make trouble?
  2. My code simply duplicates all the setup code -- it makes a duplicate SwapChain, Device, Texture2D, vertex buffer, everything. I don't have a problem with this level of duplication -- my app is not intensive enough to suffer resource issues -- but nonetheless, is there a better practice? Is there any good reference for which DirectX structures can safely be shared, and which can't?
  3. It appears that RenderLoop.Run calls the render delegate in a tight loop. Is there any standard way to limit the frame rate of RenderLoop.Run, if you don't want a 400FPS app eating 100% of your CPU? Should I just Thread.Sleep(30) in the render delegate?

(I asked on the sharpdx.org forums as well, but Alexandre is on vacation for two weeks, and my sister wants me to do a performance with my app at her wedding in three and a half weeks, so I'm mighty incented here! http://robjsoftware.org for details of what I'm building....)

© Game Development or respective owner

Related posts about directx11

Related posts about sharpdx