ProjectPSX – A C# coded emulator of the original Playstation
github.com
github.com
Very impressive. This makes it more interesting to see how the drawing code and the controls were implemented in addition to the possibility of it being cross-platform if it using .NET Core.
Should be straightforward to port to GTK# or Eto.Forms or something, if one had the inclination.
(As long as you have Windows or Linux, that is...)
- Do you ever find that the Garbage Collector causes noticeable pausing in the emulator?
- Did you do this with 100% managed memory, or do you need to use unsafe code / real pointers?
(Apologies that I didn't read the source code.)
However, for an ancient platform on modern hardware I guess the per-frame budget is plentiful even for an emulator.
That being said, it is still doable to avoid allocations and the standard library has become much better with not allocating unless really necessary. A lot of the newer things with Span<T> enable zero-allocation usage of certain APIs that before would have allocated.
This requires some care though, as the struct may still be copied needlessly if it is not also marked as `readonly` [2].
[1] - https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-serie... [2] - https://docs.microsoft.com/en-us/dotnet/csharp/write-safe-ef...
D also has something similar as compiler switch.
The .Net garbage collector is a highly optimized generational garbage collector. Practices like pre-allocating and pooling are discouraged, because most of the time they are premature optimization.
In general, the best way to think about it is to pretend that the garbage collector is a built-in library for pooling and reusing objects.
If, early in your project's lifecycle, you suspect that you'll need to implement your own object pool, just start with stub "Get/Recycle" methods that call new / no-op. You can always swap in a pool later.
Otherwise, everything looks statically allocated. So there should be no GC collections at all.
There's also managed ways to do that, but they are slower and involve copying memory.
I didn't learn by following someone's example, in my case, I have to work with so many different structs in a high performance use case that I took the time to re-learn pointers. (Haven't used them in years.)
1: Memory is allocated using new byte[bufferSize]
2: That byte[] is pinned to a byte* or void* via fixed
3: The pointer is passed to DeviceIOControl
4: Traditional c-style typecasting inside of fixed
5: Traditional GC cleans up your byte[]. This avoids problems with managed programs that allocate lots of native memory.
I don't know how to use pointers with Span<T>...
BUT: I do similar things with ArraySegment<byte[]>. All that's needed is pointer arithmetic:
ArraySegment<byte> arraySegment = ...
fixed (byte* dataArrayPtr = arraySegment.Array)
{
var dataPtr = dataArrayPtr + arraySegment.Offset;
var ptr = (SomeStruct*)dataPtr;
}I only mention it because I'm not entirely clear on what is going on or how it works (largely because I tend to only be able to learn things by doing them, which is my own issue, not your failure to describe it), but after reading the docs on MemoryMappedFiles, I wonder if it's something that could be useful to you.
Another thing you can do in C# is leverage stack allocation using structs.
- Do you ever find that the Garbage Collector causes noticeable pausing in the emulator?
The GC dosn't cause noticeable pausing on my setup. Even tho it could allocate less.
- Did you do this with 100% managed memory, or do you need to use unsafe code / real pointers?
In fact it was done without unsafe code or pointers till some of the latest commits. Where i switched to unsafe because performance reasons. On my setup that was arround 10 fps more.
(1) instead it could be a runtime that just gives you an interface to the frame buffer somehow and it's up to the integrator to use WinForms/WPF/Qt etc.
> ProjectPSX dosn't use any external dependency and uses rather simplistic C# code.
And for a learning project I think the ability to download the code and get it to run immediately without hunting for dependencies, is a very important property. More important I'd say than complicating the code to make it run everywhere.
MS has no interest in this space [0]. Your best bet at this moment is Electron or other open source alternates like eto forms.
[0] - Scott hunter's .net rocks podcast. The related commentary is past 30 mins from beginning of the show - https://www.dotnetrocks.com/?show=1634
They were running a developer survey about that
I bet our outcries are getting too loud in Redmond. Similar to those of us not bothering with Core until key frameworks got ported.
https://devblogs.microsoft.com/dotnet/calling-all-net-deskto...
Even in regards to WCF, I am not sure if they won't be forced to provide some gRPC migration path, when some Fortune 500 start to complain rather loudly.
Not sure it’s such a huge deal, .NET core already has the most complex parts of the WCF. It has fast async TCP and named pipe streams. It has .NET binary XML support, DataContractSerializer, XmlDictionaryReader, XmlDictionaryWriter classes, technically IMO better than protocol buffers: no foreign languages, similar level of performance, convertable to/from text XML if you want a human readable format for easier debugging.
When I needed RPC server in a Linux app written in .NET core, I wrote my own WCF-like thing. I’ve made a T4 template which generates requests/response & envelope classes, and channel factories, using compile-time reflection (EnvDTE stuff) of my service contracts. Took me a few hours. These Fortune 500 companies can probably afford doing the same when they need RPC in .NET.
There was a time when i had a SDL multiplatform branch but it was noticeably slower so i didn't put much effort on it and it ended deleted.
I mainly focused on the core PSX things and not much on the program itself like the emulator window itself...
As you should. Core functionality always comes first. UI can always be messed about with after, when it 'just works'.
Also, fantastic work, here! :)
Super nice and simple to read - e.g. cpu.cs has the thing that does the actual "MUL" and "MOV" etc op codes. Nice :-)
Thanks :-)
PSX.NET or PSX# would be good.
This might sound weird, but make sure .NET is capitalized otherwise people might mistake your project for a website.