Tell me more ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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....)

share|improve this question
Well using winforms sample for XNA you can render to multiple forms. – Kikaimaru Nov 23 '12 at 9:13

1 Answer

You can't do the rendering of multiple viewport in separated threads, D3D doesn't work this way, it's not thread safe (unless you use the deferred rendering feature of D3D11).

In multiple viewport case you have to adopt a structure that looks like this:

  • A RenderingDevice class that takes care of all the D3DRendering device setup.
  • A Viewport class that takes care of the Viewport related initialization (use RenderingDevice, create the SwapChain, rendering target, etc.). In case of 3D, the Viewport is attached to a Camera which is in a scene that can be shared among multiple Viewport.
  • A Scene class, which contains all the 3D resources (Mesh, Texture, Camera, etc.)

Concerning the rendering loop, there's no a "best way" of doing this, in Winform, you can:

1) Use CompositionTarget.Rendering += OnRendering; And call the rendering loop of your viewports sequentially. This is ok if your scene render fast, if it takes more time than the frequency of CompositionTarget.Rendering you'll got some stuttering and bad interaction issues.

2) Use Application.Idle += ApplicationOnIdle; with a timer like : _ticker = new Timer(); with an interval base on the frequency of rendering you aim (_ticker.Interval = 1000/100; for 100hz). The timer only set a bool "DoRender = true" and the ApplicationOnIdle checks this bool for true to perform the render. This way works best if you rendering loop take a lots of time, but the fluidity of the overall animations/interaction my not be the best as OnIdle may not be called as much as it would be necessary.

3) Hooking the Windows Proc of you Winform control like Alexandre did in his sample. I can't comment this as I don't know it much, but I know this may not be the easiest way in your case.

By the way, use RenderControl and not RenderForm in case of multiple viewport scenario.

Try 1) it's a quick test, then 2) and see what works best for you.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.