0

I'm making Nes emulator in C# and WPF. My problem, basically is how to move emulation work on another thread while still seeing screen updates it makes on window i UI thread. I'm currently set up like this.

MainWindow.xaml

<Image x:Name="NesScreen" Stretch="Fill" Height="720" Width="768"/>

First, naive, solution I tried was:

MainWindow.xaml.cs

namespace NesEmulatorGUI
{

    public partial class MainWindow : Window
    {
        private Nes nes;

        public MainWindow()
        {
            InitializeComponent();
            nes = new Nes();

            CompositionTarget.Rendering += RenderNesScreen;
        }

        protected void RenderNesScreen(object sender, EventArgs e)
        {
            // ... handle input
            //Stopwatch stopwatch = Stopwatch.StartNew();
            do
            {
                nes.Clock();
            }
            while (!nes.FrameComplete);
            //stopwatch.Stop();
            NesScreen.Source = nes.Screen;
            nes.FrameComplete = false;

            //long timeTaken = stopwatch.ElapsedMilliseconds;
            //int timeToSleep = Math.Max((int)(1000.0 / 60 - timeTaken), 0);

            //Thread.Sleep(timeToSleep);
        }
    }
}

nes.Screen is WriteableBitmap containing current frame. This turned out to produce sluggish experience (especially in Debug build) as Nes emulation is blocking main thread. Window controls are irresponve and moving windows itself is sluggish.

Second problem with this approach is in commented lines. I don't have any control to render in 60fps, as I would block main thread even further if I uncommented those lines.

According to all above, I think that moving emulation to another thread is best approach here. But I faced some issues with all approaches I took:

  1. moving Nes clock to BackgroundWorker
  2. creating thread to run Nes clocks
nesThread = new Thread(new ThreadStart(RunNes));
nesThread.IsBackground = true;
nesThread.Start();

But with all these I tend to get the same issue. In Nes thread I get this error

System.InvalidOperationException: 'The calling thread cannot access this object because a different thread owns it.'

on line in Nes implementation where I write to WriteableBitmap, once frame is finished.

I think it is because I've set NesScreen source to nes.Screen once and Nes thread doesn't have access to that object anymore. I tried locking NesScreen before altering its source but that seems to result in the same issue.

How can I best organize Nes emulation and rendering into threads? Another thing I have to keep in mind is that I want Nes to produce new frames in 60fps and for that I would need either some kind of scheduling of single frame emulation call or thread sleeping like in commented lines above.

Thanks in advance

  • Welcome to SO! Might help to take a look at [the source code for my Gamebuino emulator](https://github.com/Myndale/Simbuino), notably the `Simulation.cs` file. The emulation and sound mixing etc are done in their own threads so that the GUI remains responsive. – Mark Feldman May 24 '20 at 00:02
  • 1
    Thanks, your code and linked thread above helped me solve this problem. For any future readers, it turned out that best approach is using ```BackBuffer``` and writing new frame information directly into memory address returned from ```BackBuffer```. – Danilo Petkovic May 24 '20 at 16:14

0 Answers0