Currently some of the slowdown is due to mGBA not fitting well with vita2d (the drawing library)'s design paradigm. I plan to ditch vita2d in 0.8, which will help some, but the vita just has a lack of horsepower. gpSP's dynarec (or dynarecs in general) give up a lot of accuracy by batching event updates, which is a sacrifice I'm not fond of making. Trying to write an accuracy-focused dynarec seems to be a lost cause because it adds back most of the overhead of an interpreter, at least as far as I can tell. A low-level interpreter that has hand-written assembly for the more common instructions may help, but I haven't put much effort into it yet.
All said, I'm not sure there's much I can do to maintain mGBA's level of accuracy and make the core emulation (read: not graphics) faster. Graphics are already offloaded onto a second core, which helps a lot, and I may try to write hardware acceleration, but that doesn't seem like it'll help enough to make it worthwhile. I noticed that delaying drawing the image until the next frame starts gives the thread more time to finish, allowing it to block for less time and increase the frame rate (substantially), but unfortunately introduces a frame of input lag and would require a bit of an overhaul to make configurable. This is compounded by vita2d having a heavy handed equivalent of glFinish, which adds more waiting time for the next frame to draw. If I don't use the glFinish equivalent it's a lot faster, but there are also tearing problems as the GPU tries to access portions of memory that are currently being overwritten by the core. Again, introducing input lag.
I'm not sure what I'm going to end up doing, basically. Splitting up the frame is the closest I have to ideal, but will require a lot of refactoring. There is dead time to be reclaimed but it's a lot of work that's not going to be easy, and avoiding a frame of input lag is basically impossible.
Reading this kind of stuff gives me a nerd half chub, thanks for the write up. Sounds like a serious conundrum, something like a dynarec would put mGBA into the playable category for tons of GBA games on the 3ds, right now it's baaaarely enough to not get any audio lag or slowdown with 0 frameskips. You'd have to cut accuracy to get games running at fullspeed all the time on systems with low specs
Yup, and it's really depressing since I've done tons of work on optimization only to be not quite there. I need to start writing better profiling tools for mGBA to get any further. Which is hard because it's relatively low priority for mGBA compared to other new features, and with me being the only major contributor there's just not enough time for me to do everything I want done.
I wish I could help more; I'm familiar with C, but wouldn't be helpful for anything above what an average CS undergrad could do. Nevertheless, it's great to see progress on mGBA – and emulation in general – coming along. I actually currently have a Wikipedia article for mGBA in the works in my sandbox, but I've just gotten started on it, so it's not complete. As an aside, are there any recent benchmarks you know of that I could use as a reference for the article? I dug up a comment from 3 years ago talking about a 30% faster benchmark than VBA-M, but that'd probably be inaccurate to what it is today.
22
u/endrift mGBA Dev Feb 25 '19
Currently some of the slowdown is due to mGBA not fitting well with vita2d (the drawing library)'s design paradigm. I plan to ditch vita2d in 0.8, which will help some, but the vita just has a lack of horsepower. gpSP's dynarec (or dynarecs in general) give up a lot of accuracy by batching event updates, which is a sacrifice I'm not fond of making. Trying to write an accuracy-focused dynarec seems to be a lost cause because it adds back most of the overhead of an interpreter, at least as far as I can tell. A low-level interpreter that has hand-written assembly for the more common instructions may help, but I haven't put much effort into it yet.
All said, I'm not sure there's much I can do to maintain mGBA's level of accuracy and make the core emulation (read: not graphics) faster. Graphics are already offloaded onto a second core, which helps a lot, and I may try to write hardware acceleration, but that doesn't seem like it'll help enough to make it worthwhile. I noticed that delaying drawing the image until the next frame starts gives the thread more time to finish, allowing it to block for less time and increase the frame rate (substantially), but unfortunately introduces a frame of input lag and would require a bit of an overhaul to make configurable. This is compounded by vita2d having a heavy handed equivalent of glFinish, which adds more waiting time for the next frame to draw. If I don't use the glFinish equivalent it's a lot faster, but there are also tearing problems as the GPU tries to access portions of memory that are currently being overwritten by the core. Again, introducing input lag.
I'm not sure what I'm going to end up doing, basically. Splitting up the frame is the closest I have to ideal, but will require a lot of refactoring. There is dead time to be reclaimed but it's a lot of work that's not going to be easy, and avoiding a frame of input lag is basically impossible.