C# - Direct3D and Threading

Associate
Joined
9 Jan 2005
Posts
715
Location
High Wycombe :/
This is doing my head.

I've got a USB device constantly pumping out image data. I want to use Direct3D to paint this data to multiple child windows in an MdiContainer in real-time.

My first attempt was to create an instance of a render form after clicking a button in the MdiContainer and start a thread running the render loop. Problem is that when it comes to doing the Device.Present(renderform) or SwapChain.Present(renderform) it'll give me an error because the window it's trying to print to was created outside of the current thread.

So ok I think I'll create the instance of the window inside the render loop thread, but if I do that I can't set the MdiParent to the MdiContainer form (with something like "renderform.MdiParent = mainform" as again it'll tell me that I'm trying to access a control created outside the current thread (I guess the mainform created at Application.Run).

Catch 22 :/

Also is it even possible to have multiple render loops on the same direct3d device running in threads? Can't really think of any other way of having different windows being rendered at the same time.
 
Soldato
Joined
5 Mar 2003
Posts
10,757
Location
Nottingham
My first attempt was to create an instance of a render form after clicking a button in the MdiContainer and start a thread running the render loop. Problem is that when it comes to doing the Device.Present(renderform) or SwapChain.Present(renderform) it'll give me an error because the window it's trying to print to was created outside of the current thread.
I don't know about the rest of it, but to overcome this problem is pretty each. Just check "this.InvokeRequired" and if its true, just do "this.Invoke(new MethodInvoker(delegate() { MethodName(params_here); }));", where "this" is the form.

Might allow you to go back to your first attempt?
 
Associate
OP
Joined
9 Jan 2005
Posts
715
Location
High Wycombe :/
Woah thanks matey that got rid of the error. Only thing now is that moving windows and clicking buttons is ultra slow while that thread is running. Here's most of the offending class if it helps. I know it's ugly and unsafe but I'm really just figuring out how it'll work at the moment.

Code:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;


namespace USBScanner
{
    public class SSGraphics
    {
        public Device m_device;
        SSDevice m_usbscanner;
        VertexBuffer m_vb;
        GraphicsStream m_gs;
        CustomVertex.TransformedColored[] points;
        int i, j, size;
        MainForm m_mainform;
        Thread renderloop;
        GraphicsForm renderwindow;
        MethodInvoker methodinvoker;

        public SSGraphics(ref SSDevice ss, MainForm mainform)
        {
            m_usbscanner = ss;
            m_mainform = mainform;
            renderloop = new Thread(new ThreadStart(StartRenderLoop));
            methodinvoker = new MethodInvoker(DisplayImageUsingVBPoints);
        }

        public bool Initialise()
        {
            PresentParameters m_pp = new PresentParameters();
            m_pp.SwapEffect = SwapEffect.Discard;
            m_pp.Windowed = true;
            m_pp.BackBufferHeight = 512;
            m_pp.BackBufferWidth = 512;
            m_pp.PresentationInterval = PresentInterval.Immediate;
            m_device = new Device(0, DeviceType.Hardware, m_mainform.Handle, CreateFlags.HardwareVertexProcessing, m_pp);
            return true;
        }

        public bool CreateGraphicsForm()
        {   
            renderwindow = new GraphicsForm();
            renderwindow.MdiParent = m_mainform;
            renderwindow.Show();
            renderloop.Start();
            return true;
        }

        public void StartRenderLoop()
        {
            while (!renderwindow.IsDisposed)
            {
                renderwindow.Invoke(methodinvoker);
               // next line used to throw the threading error
               // this.DisplayImageUsingVBPoints(renderwindow.Handle);
            }
            
        }

        public void DisplayImageUsingVBPoints()
        {
            m_device.Clear(ClearFlags.Target, Color.White.ToArgb(), 1.0f, 0);
            size = m_usbscanner.scan.Length * m_usbscanner.scan.Length;

            m_vb = new VertexBuffer(typeof(CustomVertex.TransformedColored), size, m_device, Usage.None, CustomVertex.TransformedColored.Format, Pool.Managed);
            points = new CustomVertex.TransformedColored[size];

            for (i = 0; i < m_usbscanner.scan.Length; i++)
            {
                for (j = 0; j < m_usbscanner.scan.Length; j++)
                {
                    points[j + (i * m_usbscanner.scan.Length)] = new CustomVertex.TransformedColored(new Vector4(0.0f + i, 0.0f + j, 0.0f, 1.0f), m_usbscanner.scan[j] * m_usbscanner.scan[j] * m_usbscanner.scan[j]);               
                }
            }

            m_gs = m_vb.Lock(0, CustomVertex.TransformedColored.StrideSize * size, LockFlags.None);
            m_gs.Write(points);
            m_vb.Unlock();

            m_device.SetStreamSource(0, m_vb, 0, CustomVertex.TransformedColored.StrideSize);
            m_device.VertexFormat = CustomVertex.TransformedColored.Format;

            m_device.BeginScene();
            m_device.DrawPrimitives(PrimitiveType.PointList, 0, size);
            m_device.EndScene();
            m_device.Present(renderwindow.Handle);
          
            m_vb.Dispose();
            points = null;
        }

    }
}
 
Last edited:
Associate
OP
Joined
9 Jan 2005
Posts
715
Location
High Wycombe :/
Think I've got it. I just took the m_device.Present(renderwindow.handle) out and stuck that in it's own method which is called by the MethodInvoker. All the vertex writing is still done in the thread.

Thanks again Goksly, expect I'll be back with more problems soon though :)
 
Soldato
Joined
5 Mar 2003
Posts
10,757
Location
Nottingham
Also putting in a sleep command in the worker thread will allow the CPU to work on the UI thread more often (when sleeping the CPU does a context switch IIRC).
 
Back
Top Bottom