Closed purplemarshmallow closed 4 years ago
Definitely, but I don't know of any solutions there. Any optional extension to the specs would require adding to the PLUGIN_INFO (i.e. RSP_INFO etc.) struct's in the headers, which changes the size of the struct and can and will go out of bounds for the memory info that the emulator core's implementation of the specs expects.
The only compatible solution I know of would be to make a new official release of the plugin specs, like Gfx 1.4, Audio 1.2, Controller 1.2 and RSP 1.2, where the plugin info struct's supply a size_t max_DRAM_address
or the like.
The Gfx 1.4, Audio, 1.2 Controller 1.2 and RSP 1.2 spec already exists but I'm not sure what is changed and only PJ64 supports it
Glide64 for PJ64 already uses the 1.4 spec. It could be changed to 1.5 and this ugly code could be removed https://github.com/project64/project64/blob/master/Source/Glide64/Main.cpp#L1620
I think an official release of the new spec with new headers would be a good idea.
The Gfx 1.4, Audio, 1.2 Controller 1.2 and RSP 1.2 spec already exists
They actually kind of do not.
That's because that's just Project64-ization garbage and not really legitimate versions of the spec. zilmar mostly used those version numbers as a means of keeping people from using the plugins on other emulators, primarily as far as the donations lifespan of Project64 1.7 was concerned.
Glide64 for PJ64 already uses the 1.4 spec.
Again that really is just because of personal custom extensions zilmar did to the specs for Project64. Said custom extensions were custom to begin with, so I stand by what I said about adding this size_t RDRAM_size
member of the plugin info structs you suggest in a Gfx 1.4, Audio 1.2, Controller 1.2 and RSP 1.2 of the specs.
This would cause the 1.7 beta plugins by Jabo to break I guess, if the core adds your corrections to those custom version numbers. If that's an issue, we can do 1.5 instead of 1.4 like you suggest.
This would cause the 1.7 beta plugins by Jabo to break I guess
For this very reason, I think doing 1.5 is ideal.
Well just disassemble his plugins and fix them to use the fixed 1.4 then. :P
You guys can do 1.5 if you really want but bumping the version for one single struct member change is kind of overkill. I'd rather do 2.0 or something and completely change the spec files to not use Windows types everywhere.
It should be possible without changing the spec. The emulator could call an optional function before RomOpen() and tell the plugin the RDRAM size.
If there's going to be a new version like 2.0 I think the plugins shuld tell the emulator if they support HLE or not. So no HLE dlists and alists are sent to LLE plugins
If the plugin spec is going to be updated, it would be ideal if the save state graphics issues affecting Mischief Makers and Starcraft could be looked into, also.
edit: No to mention making an official version of fbinfo.
@cxd4 Time to fire up x64dbg! :wink:
Would changing the plugin spec break anything about previous plugins? I mean, I assume with changes that you guys are talking about it would, which would make it hard to test plugins. And you guys know I love plugin testing. :smiley:
If the plugin spec is going to be updated, it would be ideal if the save state graphics issues affecting Mischief Makers and Starcraft could be looked into, also.
I don't know about a problem in Starcraft. But the problem in Mischief Makers is not only because of the plugin spec, also because of the save state format. Changing it would make old save states incompatible. Keep in mind 1964 and mupen64plus also support PJ64 savestates.
Currently save states are just a RDRAM dump and to be perfectly accurate the whole rdp state would need to be restored from the savestate. I think this can get complicated because different plugins implement things differently
Would changing the plugin spec break anything about previous plugins?
It won't break old plugins but new plugins won't work in old emulators
I don't know about a problem in Starcraft.
IIRC, the little booster graphics on certain ships disappear after loading save states. Affects all emulators.
But the problem in Mischief Makers is not only because of the plugin spec, also because of the save state format. Changing it would make old save states incompatible. Keep in mind 1964 and mupen64plus also support PJ64 savestates.
In all fairness, swapping save state files around different emulators or dramatically different versions of the same emulator is generally a bad idea. Some emulators won't allow it. (PCSX2 and Dolphin, for example.)
Currently save states are just a RDRAM dump and to be perfectly accurate the whole rdp state would need to be restored from the savestate. I think this can get complicated because different plugins implement things differently
That's a good point.
In all fairness, swapping save state files around different emulators or dramatically different versions of the same emulator is generally a bad idea.
Why? The format never changed. A savestate from emulator A can help emulator B to get ingame or past a point where it crashes
@purplemarshmallow OK, gotcha. I thought maybe the older plugins might stop working if they don't implement things the same way.
Why? The format never changed. A savestate from emulator A can help emulator B to get ingame
Maybe, but if even one thing about the emulated hardware is different and then you load a save state, it might break things that weren't broken before, which may be hard to debug and also might cause problems that wouldn't happen otherwise.
You can also load save states from other games while running a different game, so there's that as well. I have never known why that was allowed, but you know it is really funny to see what happens. :laughing:
Maybe, but if even one thing about the emulated hardware is different and then you load a save state, it might break things that weren't broken before, which may be hard to debug and also might cause problems that wouldn't happen otherwise.
The emulated hardware should not be differnt. If it is different you may want to test with a savestate and find out what's wrong. It's only useful for testing and debugging
@purplemarshmallow It shouldn't be different, but it is for one reason or another from emulator to emulator.
An example being the CPU emulation in Project64 and Mupen64Plus. Things are radically different, even though you would think the emulation would be nearly the same. Take Donkey Kong 64 or the Banjo series, for example. You can play for hours using the same plugins and not notice any difference, but put them side-by-side and you notice one is slightly faster than real hardware, and the other is slower than real hardware. Or in some cases, the opposite. Or in rare cases, one handles something correctly and the other doesn't, resulting in small differences in emulation over time causing incorrect timings, broken graphics or audio, or de-synced cutscenes.
Debugging this can be hard, since the first thing you think is "oh, the plugin must be doing something wrong". But what actually happened was that the CPU did one thing wrong and the ladder of instructions now is different than what it is supposed to be, and the game is assuming you are doing everything right.
Even small bugs can cause hardware to behave completely differently. It sucks when something isn't the same across emulators, but then the N64 isn't exactly known for it's simplicity.
It's confusing and hard to debug, but it's there. I can't remember, but I think the difference between the two emulators was so big at one point that I had gotten to the main menu after the DK Rap in one emulator and the other was in the middle of it. It scared the hell out of me, because I had never noticed. But how could I? People don't commonly run two emulators at the same time.
It goes to show you that even the most well-documented parts of the N64 still have yet to be done perfectly.
These are just examples and my experience, anyway. :smile:
I'm not reading that shit.
All I know is either a 1.4, 2.0 or even maybe a 1.5 spec is fine. Marshmallow I forgot about that idea you mentioned, yes you could add an optional function to the plugin and have the core optionally execute it if it exists without requiring it. In that sense you may be able to avoid having to bump the plugin spec version at all period; it can stay where it's at with 1.3.
/*
* optional function in Gfx #1.3
* input : the maximum RDRAM address, in MIPS-sized bytes
* output: none
*/
#include <stddef.h>
#include "Gfx #1.3.h"
...
extern size_t MB_of_RAM_detected_by_z64gl;
EXPORT void CALL signal_max_addr(size_t max_address)
{
MB_of_RAM_detected_by_z64gl = (max_address + 1) / (1024 * 1024);
return;
}
And somewhere in the Project64-core source this hypothetical function may be called shortly before RomOpen gets called after ROM is imported into client-side memory and byte-swapped or whatever.
Why? The format never changed. A savestate from emulator A can help emulator B to get ingame or past a point where it crashes
That's an edge case. I personally think save state swapping should be allowed, but it can introduce problems. Suppose there's a crash bug caused by the recompiler. Well, a save state created using the recompiler may end up crashing every version of the emulator it is tested with. Compared to using a proper game save file, using save states can introduce unknown variables.
I think it's a good idea to introduce this extension So new plugins can still work with older versions of PJ64 and other emulators
And it will allow plugins to support PJ64's custom RDRAMsize feature
I agree not having rdram size in the original spec was a bad mistake and something that should have been there.
Mostly to not muck around with compatibility especially since a lot of old plugins are never going to be updated, I think the easiest and safest way would be just have an addition function the emulator can look for and call before RomOpened. if it does not exist, no big deal will work as it is now, if it does then it will be called and the plugin will know.
With the save state information, what state information needs to be kept, I am not sure if I will do anything for the next version, but after that sure, might even get in to the next version, where I can see giving the plugin the ability to pass a blob of data that could be stored along side the save (when it is zipped, in the zip). Then when the save is loaded then get that file passed back to the plugin.
Mischief Makers writes to the tile descriptors just once. When loading a savestate 3D gfx will look incorrect because this information is lost.
But only with accurate plugins. Glide64 uses a hack to emulate 3D in this game and it will look correctly even after loading a savestate.
if I was going to test writing the code using glide, what would I actually need to save/restore? Is that textures?
First the hack for Mischief Makers in Glide64 would need to be removed. Them the problem can be fixed in an accurate way but I don't know what Glide64 does wrong. Here's the commit that fixed GLideN64 maybe Glide64 has the same problem https://github.com/gonetz/GLideN64/commit/232800a8238f918e066fa9cc1a217e0e4020679b
would I actually need to save/restore?
set_tile and set_tile_size are just called once and not once per dlist see https://github.com/gonetz/GLideN64/issues/719#issuecomment-181418348
If you want to improve save state functionality, you can include the RSP registers, so that save states work better when using mfc0 exit.
@cxd4
I'm not reading that shit.
:laughing:
@AmbientMalice
introduce unknown variables
Yeah, especially with a recompiler and HLE. That's what I was saying above, there is a lot of fluctuation that can happen.
Yeah, especially with a recompiler
How does that even make a difference?
@LegendOfDragoon The Indiana Jones save states had to be made using the CPU interpreter, otherwise they'll crash regardless. That's the biggest example I can think of. Interpreter save = works on interpreter. crashes on recompiler. Recompiler save = crashes on both recompiler and interpreter.
@AmbientMalice , interesting point. Where does it crash, with a save state? I made a save state with cpu recompiler, at the part where it shows that news paper and I don't get a crash from loading the save state.
At this point, I think it's safe to go by the same assumption 1964 did, in regards to handling the FPU registers, I think I'll try seeing how well it works with Project64.
As for the crash you reported in Indiana Jones in that issue you opened, I may look into fixing that, since I am looking into improving the accuracy and performance of the cpu recompiler. I just need to analyze the code some more and maybe @project64 can help me as well.
@LegendOfDragoon At the end of the level, with the fade to black as the helicopter flies away. That's where the save states I uploaded were made. If a recompiler save is made here, it crashes after a fade to black when loaded into interpreter. The game has heaps of interpreter errors, but nothing fatal so far as I can tell. Indiana Jones is a very unstable game on a real N64, so I wouldn't be surprised if some of the errors are unavoidable.
The sticking point is the Trading Post screen. I tested yesterday, and PJ64 now gets to the trading post screen with the recompiler. Massive slowdown on that menu, and the purchasable items are missing. Attempting to leave the Trading Post freezes the emulator.
Mupen64plus is quite interesting here. It freezes randomly playing the game, with huge tearing issues--wheras PJ64 seems perfectly stable--but if the expansion pack is disabled, it can get past the first Trading Post screen, but not the one from the second level. It seems to be a virtual memory issue, which probably explains why mupen64plus can evade the first freeze with the expansion pack disabled. It's also fairly typical for Factor 5 games to have eccentric virtual memory behavior.
I wish I knew how to play that game so I could do more testing. I'll have to watch a video or something.
Alright, I'll try seeing if I can track down any recompiler bugs today. I figure even if the interpreter is still bugged, it's still worthwhile to get the recompiler to match the same accuracy if it's more playable with interpreter.
I wish I knew how to play that game so I could do more testing. I'll have to watch a video or something.
I can upload an interpreter save just before the cutscene where the game crashes, for the American version, if you want. It'll be a few hours from now, though. (I imagine those old saves I uploaded crash on modern PJ64.)
Also, here's a video playthrough of the first level for reference. https://www.youtube.com/watch?v=5UHSVo6s1ec
Weirdly enough, on topic, Angrylion's would freeze if I changed PJ64's RAM setting before loading a save state. Saves made using 4MB could only be loaded with 4MB, or it might have been the other way around.
I can upload an interpreter save just before the cutscene where the game crashes, for the American version, if you want. It'll be a few hours from now, though.
Sure, that would be nice.
Angrylion's would freeze if I changed PJ64's RAM setting before loading a save state. Saves made using 4MB could only be loaded with 4MB, or it might have been the other way around.
This reminds me of a problem with 1964 1.1 actually. Where running a game in 8MB, then switching to Last Legion can cause problems in 4MB when using a gfx plugin that doesn't do address range checking. I'm guessing 1964 isn't clearing the RDRAM or something. Definitely another interesting problem I'll look into.
@project64 I think this should be implemented before the next release.
How should it be implemented?
It's possible to add an optional function for Rdram size but I think it would be better to release a 2.0 version of the spec and address all flaws at once
I think it would be better to release a 2.0 version of the spec and address all flaws at once
I agree. That is how I would do it.
ok what other flaws other then rdram size?
I think implementing Framebuffer info would be a great despite the alleged 5% hit in performance (the original Mupen has a working implementation and it's still pretty fast), a lot of games use the framebuffer and it would help both Project64-video and GLideN64 to copy frame buffers only when necessary instead of unconditionally.
If we're about to extend the emu spec, I think there needs to be a better communication between the core and the graphics plugins, which is related to this very issue about the lack of a RDRAM param being provided to the gfx plugin.
I think this should be addressed (I mostly looked at the gfx plugin spec):
The plugin header currently contains windows specific data types. Everything should be portable
State who is responsible for updating VI_V_CURRENT_LINE_REG. Angrylion wrote about this.
What is unnecessary? What can be removed? Are the memory byteswapped flags needed? Is this fully supported anway? Does ViWidthChanged make sense? Most plugins always check anyway
The spec does not allow cyle accuracy
Plugins should state if they support HLE or not
granted the generation of the spec was from the early days and trying to work out what jabo needed from the emu, and how it could fit with other emus, there is elements of idea like the bswap, and the early days there was no 8mb needed games.
So somethings stayed the same and still say the same for backward compatibility, Like if I add a new rdram setting in only going to work with Pj64 2.4+
So in general added to and not remove/changed functions.
Project64 has a whole setting infrastructure now that lets the plugins share setting with the main emu and lets the main emu handling all the reading/writing of these settings, so the plugin never actually touches the setting file.
Now adding that to the spec does not help unless other emu implement it, and if they don't and the plugin needs it then it can only be used on those emu's.
As well as window specific types again is a function that it was designed in a window only time for emulators. But yes internally in PJ64 there is no windows types any more. I am still using the plugin specs on android.
with implementing Framebuffer, I thought I would not be able to use exception handling like I do on windows and have to do a more function based lookup like how mupen does it. I also did it so I could implement the framebuffer, it had a decent performance hit (about 20%) I believe. So I gave up on that method. I would at some stage like to revisit that .. but I guess it is more when I have done more with the gfx plugin and trying to get it working. the other thing is at the time of creating the specs there was like 10 different n64 emus and now there is like 2. One of which has it own variations, so this is mostly just for integration with pj64 at the moment. Actually I have no idea what cen64 does (so make that 3).
The plugin header currently contains windows specific data types.
Odd, I thought that was changed already? I guess not lol.
Plugins should state if they support HLE or not
Why do you think they should?
State who is responsible for updating VI_V_CURRENT_LINE_REG
Well in the current version of PJ64, it's essentially read-only for the graphics plugin because the emulator only writes to that register and never reads it. zilmar seems to generally prefer giving the emulator more control, rather than the plugin.
Does ViWidthChanged make sense?
I think it does.
Yes, there are like 3 remaining active N64 emulators. PJ64 has zilmar-spec and Mupen64Plus has his own mupen-spec which is based off zilmar spec, but they are separate already and not interchangeable. Cen64 doenst even use plugins I think
GLideN64 ships different versions for both zilmar-spec and mupen-spec. So, changing the spec, if it's for the improvement of the graphics plugin shouldn't be a concern at all.
And the only reason is it called zlmar-spec instead of pj64-spec as it probably should be, is that I released them and were adopted before pj64 was public.
One very important problem with updating the plugin specs is that specifications bound by protocol should be extremely cautious. If you're not a perfectionist with the spec each release version to the spec will never be the last and will come before tons of new version numbers of the spec every developer has to care about, and there will be inconsistencies and things going back and forth between the plugin structures and such.
I recommend against updating the plugin spec ever again until every single last idea has been realized into making it perfect to everyone, to prevent the risk of receiving requests for subsequent updates with even more spec version updates. Such finalization and mature standardization of a protocol (even one trivial as a N64 plugins spec) requires tons of communication with lots of people.
The plugin header currently contains windows specific data types. Everything should be portable
Relatively minor as this doesn't require memory structure changes on the binary level.
I rewrote the spec headers to use portable types here. https://github.com/cxd4/rcp64
Plugins should state if they support HLE or not
They sort of do already.
All an emulator has to do is compare function pointers.
In graphics plugins, ProcessDList == NULL
means there is no exported function to the emulator for processing display lists in HLE. (The LLE counterpart is ProcessRDPList
).
Similarly, the absence of ProcessAList
in audio plugins guarantees it is LLE-only.
The only problem is different emulators mark those functions as "required" to init the plugin as valid.
The spec does not allow cyle accuracy
There's a shell for that in the RSP plugin in the variable domain to DoRspCycles
, but there has been no concrete usage of it on the emulator's side. Cycle-accuracy is such a structurally different thing for the entire emulator ignoring even the plugins.
Does ViWidthChanged make sense?
Hmm...it's not needed for anything accuracy-wise.
It is useful as a feature and maybe to optimize synchronization of static variables storing a copy of VI_WIDTH_REG on the client's side. It can't hurt to keep it, if nothing else for backwards compat.
Are the memory byteswapped flags needed?
My short answer to that is No.
MemoryBswapped is useful because it is impossible to detect client-side CPU byte order without invoking undefined or implementation-defined behavior in the C language specifications. It is best for an emulator to tell you.
However, reading MemoryBswapped every time throughout the code to check whether to XOR addresses by 3 is poor efficiency and extra instructions. A macro is best and equally as maintainable and certainly smaller code to read and write in the source, with the same benefits of flexibility if not greater maintained.
In either case, zilmar mentions a good point about backwards compatibility, so I would keep it in.
The RDRAM size thing is important only if you do not have 16 MB of RAM installed to the N64 (which nobody does in real life but can in an emulator).
RCP addresses for communicating with CPU RAM from the R4300 master are always &= 0x00FFFFFF
. Additional checks for emulating exceptions (or in the RCP's case, the lack thereof) would only slow down performance with 16 MB of RAM in the N64 emulator because the maximum address for having 16 MB of RAM installed is, itself, FFFFFF_16 while for 8 MB of RAM (standard N64 + 4 MB memory expansion pak) is only 7FFFFF_16 and you would still waste extra instructions checking the MSB.
Fundamentally though in terms of the principles of hardware accuracy it is wise for the plugin spec to have, but easy to ignore when emulating just the commercial games. It would be excellent to time-travel to 20 years ago to tell zilmar to implement it back then rather than implement it right now--the justification doing so being more of a philosophical dispute.
I disagree with @cxd4. I don't think the plugin spec has to be consistent. This made sense 15 years ago. Many different emulators and even more plugins were worked on. Some were closed source.
Today what's the number of plugins that are being worked on (and that will get an updated spec version)? It's not such a big deal to update it everywhere. And everything is open source.
And if it gets updated again support for the old version can also be removed. The emulator must not necessarily support every version of the spec.
Some time ago I tried to implement this win32 exception thing to detect the rdram size into z64gl. It didn't work and then I stopped and thought what am I actually doing here! And I also see some strange includes and definitions in z64gl to get the official 1.3 header working on linux. So please let's make zilmar spec V2.0. A plugin spec should not hold anything back
The only problem I see is testing. For testing and hunting regressions down V1.3 (for gfx) can be the conservative fallback that works everywhere. And V 2.X is tailored to the emulator to give the best experience
Plugins should state if they support HLE or not
Why do you think they should?
To prevent errors and make things more usable. It makes no sense to send HLE dlista and alists to LLE plugins
They sort of do already. All an emulator has to do is compare function pointers. In graphics plugins, ProcessDList == NULL means there is no exported function to the emulator for processing display lists in HLE. (The LLE counterpart is ProcessRDPList). Similarly, the absence of ProcessAList in audio plugins guarantees it is LLE-only. The only problem is different emulators mark those functions as "required" to init the plugin as valid.
This sounds good to me. In a new spec version ProcessDList and ProcessAList can be optional
the easiest is to add things to the spec, it does not make it cleaner .. but it does allow backwards capabilites .. so I guess a huge part is do we want backward compatibility or not .. I know I have a task down to get RDRAM size for project64-video .. which I can do not through the settings extension in pj64, but that does not help any other emu .... Tho I am also not expecting project64-video to be compatible with any other emu since it uses all the settings system.
Maybe I should create another repository just for the specs, take the current version .. add them, then make them platform agnostic and we can work out where to go from there.
Arguing that backwards compatibility is unmerited because of the small number of plugins being worked on and the number of emulators supporting plugins being worked on is not really better than arguing that the spec should be abolished altogether.
If it is such a strong point that Project64 is the only active emulator using the spec and only a handful of plugins are active or worth testing, then--for all the interest in radical changes to the spec breaking backwards compatibility--it would be far more simpler to go the Dolphin way and forget plugin architecture.
However I do not see that as a strong point because it's still more useful to isolate issues and test plugins in other emulators besides Project64 than it is challenging to maintain backwards compatibility while improving the spec to solve merited concerns.
Backwards compatibility may sound good but it will make it more difficult to make future updates to the spec and to introduce something new. That's my main point. I fear it will hold things back or make development more difficult
Maybe I should create another repository just for the specs, take the current version .. add them, then make them platform agnostic and we can work out where to go from there.
Sounds good. Ideas can be collected there
I agree with purplemarshmallow. Current only actively mantained plugins can be easily updated if the spec changes. They already ship a Zilmar spec and a mupen64plus version. Unless someone wanted to use GLideN64 on, let's say 1964 or Mupen64 (long abandoned) I don't see the point of not breaking the spec. In theory if they still wanted to, they can reverse just the few commit related to spec changes
I don't think it's unmerited to not care about backwards compatibility nor agree that the spec should be abolished in this scenario because there are actively worked on plugins with different purposes like Project64-video (aims for MLE), Angrylion (pixel accurate software render), GLideN64 (most accurate HLE gfx) UNLESS we had concentrated those efforts into a single backend like Dolphin, but realistically that's never gonna happen because N64 emu devs strive for different goals
If somebody cares so much about using an older plugin for the sake of testing and comparing, such as Rice video (why would you do that...) since the plugin is open source it can also be updated accordingly. Death-droid I bet would be willing to since he's its last semi-recent mantainer
Can't think of any other older plugin that would be broke if the spec changes that's worth checking out... Daedalus? Adaptoid?
I guess the only real loss here would be the ability to use Jabo's plugins that Zilmar has been thinking of getting rid of since they are closed source, and those can't be updated for that reason
The gfx plugin needs to know the size of RDRam for correct RDP emulation. The plugin spec does not provide it and there are no simple and not platform specific ways to detect it.
Maybe it's possible to make an optional extenson to the plugin spec without breaking compatibility with older plugins. Or bump the version of the spec.
Currectly most plugins try to detect it with causing an access violation and then they assume it's either 4 or 8 MB. PJ64 allows setting it to any amount so this solution is problematic