Interpreting EOP's in GIF packets
#11
To try to clear up the original confusion, EOP is used for path control. A single GIF path has exclusive use of the GS bus until the end of the current packet. The "packets" pcsx2 sends are not the same as GIF packets and having multiple EOPs is fine.

It's just a function of the GIF and in fact the real GS bus is just 8-bit address and 64-bit data lines.
Reply

Sponsored links

#12
I have noticed that plugins like ZeroGS and GSdx do check for an EOP, but only if the transfer is on path 1, in which case they drop the rest of the packet. I have mindlessly copied this myself and it seems necessary to prevent glitches and crashes in certain games. Is there a reason behind this?
Thanks
Reply
#13
r.hackett: i've recently reviewed the gif code a bit and it turns out its hackier than i thought.
at some point we had changed gif to ony use the GSgifTransfer2() callback, but then that got reverted and we're still relying on separate callbacks for the different paths.
this likely means we're not sending atomic gif packets but instead partial packets with the different paths.
in short our implementation is hacky and for now its best to copy what the other plugins are doing.
i'm going to attempt a gif transfer rewrite to hopefully fix the problems, but i'm not guaranteeing anything incase i get bored before i finish xD
Check out my blog: Trashcan of Code
Reply
#14
Thanks cotton, keep us updated.
Quick question that may or may not seem ignorant. How come the GIF packets can't simply be sent "as is" with no modifications? Could this be for efficiency gains, or maybe as an abstraction for the plugins?
Reply
#15
r.hackett:
well we do send gif packets 'as is' in that we don't modify the contents, but the timing they're sent at is the problem.
in the real ps2 you have 3 different ways to upload stuff to the gs via the gif: through dma by path3, through vif by path2, or through vu1's xgkick instruction which is a path1 transfer.

if 2 paths are trying to transfer data at the same time then one of them is queued because only 1 path can be transferring data at a time (the gif manages arbitration of these paths according to path priority and has a special case for path3 image transfers where it can transfer it in slices with other path transfers interleaved inbetween).

the real gif basically transfers a complete gs packet at a time (a gs packet is a bunch of gs primitives that end with an EOP), and then at the end of the gs packet it checks if any other transfers are queued and arbitrates between the transfers according to their priority/settings.

i believe some transfers that are initiated by pcsx2 don't initially have the complete gs packet's data available. so if you don't handle this situation correctly and just send gs packets whenever you get them, you'll ended up sending partial packets to the GS plugin, and then you might end up sending another path's gs packet mixed up in-between a partial packet. and basically get garbage results for the GS plugin.
another problem are games that rely on the order of the path transfers by using the SIGNAL register to sync up the path transfers.
and also stalling can occur when initiating path transfers which a game may require to be emulated.

basically for accurate emulation we need to simulate the behavior of the real gif enough to make games happy. and just sending the gs primitive whenever we get them is not how the gif really works so games will complain.
Check out my blog: Trashcan of Code
Reply
#16
I see, thanks alot for the concise explanation cotton, it's very helpful. One thing I haven't emulated yet is the SIGNAL/FINISH registers, could this be a major problem?

I have another thing which i just want to clarify, about IMAGE transfers. I can see that images can be transfered in parts, even in seperate packets. Take this for example. The following is some logging information from my plugin for Tony Saveski's (dreamtime) demo2c.

Code:
GIF packet: size=5, path=3
    GIFtag: nloop=0x4, eop=0x1, pre=0x0, prim=0x0, flg=0x0, nreg=0x1
        A+D (BITBLTBUF): 0x0000000000000050_00080e0000000000
        A+D (TRXPOS): 0x0000000000000051_0000000000000000
        A+D (TRXREG): 0x0000000000000052_0000010000000200
        A+D (TRXDIR): 0x0000000000000053_0000000000000000
GIF Packet end

GIF packet: size=1, path=3
    GIFtag: nloop=0x0, eop=0x1, pre=0x0, prim=0x0, flg=0x2, nreg=0x0
GIF Packet end

GIF packet: size=16384, path=3
    Host -> Local Transmission: qwSize=16384
GIF Packet end

GIF packet: size=1, path=3
    GIFtag: nloop=0x0, eop=0x1, pre=0x0, prim=0x0, flg=0x2, nreg=0x0
GIF Packet end

GIF packet: size=16384, path=3
    Host -> Local Transmission: qwSize=16384
GIF Packet end

This is one single image transfer, so I assume that an image transfer is considered part of the same transfer as long as the FLG field is specified as an image transfer (2), but if any other value for the FLG field is read, then a new transfer is started and the old is considered complete.

I just want to confirm that this is correct, since I'm currently working on implementing textures. Thanks
Reply
#17
The first packet is setting up the transfer registers for the proceeding image transfer. However in that case the 2nd packet is essentially blank (nloop = 0 ignores everything apart from the eop flag). But yes, they are 2 seperate transfers, the first merely writes information to the registers which will be used in the next image transfer Smile

as for SIGNAL/FINISH, ignore them, they are controlled by the emulator completey (iirc)
[Image: ref-sig-anim.gif]

Reply
#18
(06-23-2011, 06:22 PM)refraction Wrote: The first packet is setting up the transfer registers for the proceeding image transfer. However in that case the 2nd packet is essentially blank (nloop = 0 ignores everything apart from the eop flag). But yes, they are 2 seperate transfers, the first merely writes information to the registers which will be used in the next image transfer Smile

as for SIGNAL/FINISH, ignore them, they are controlled by the emulator completey (iirc)

When it comes to image transfers, i used to be under the impression that nloop always specifies the size of the incoming data, but it seems that I was wrong. The log i posted is basically the only GIF packets that are sent in that demo, and the demo runs on the real hardware as well as using other graphics plugins. The way I emulate it is that if nloop is 0 and FLG is 2 (image transfer), then I ensure that I ignore the nloop for the size of the image transfer and only use the size passed from the PCSX2, however, when nloop does not equal 0, i find the minimum value of size and nloop and use that.

I know that this goes against the official documentation, but many games seem to do this.
hmmm

edit: the source code of the demo that that log's from actually sets the nloop field to the size of the data to transfer, and my plugin definately does not change the value of nloop before it's output to the log. so, slight mystery with this one.

Also, may I add that I'm pretty sure that those two seperate packets that transfer image data are part of the same image transfer. Since, the figures add up. That is...

pixels in image: RGBA 640x184 (117760)
total quad words being transfered is: 29440, or 117760 pixels (29440 * pixels_per_quad_word(4))

Put simply, those two image transfers should be considered part of the same transfer as far as I'm concerned, it makes sense.

edit2:
btw, i know that what i wrote was a little convoluted, i should have taken a breath. If you need clarification of what i'm trying to say, please ask.
Reply
#19
r.hackett: the only thing the GS Image transfer primitive does is write the subsequent data to the GS's HWREG register 64bits at a time.

this means that as far as the GS is concerned, it doesn't care if you're splitting the image data between multiple GS Image primitives; the result will still be the same.

the way you choose to handle image data split between multiple primitives is up to you as the plugin author. i haven't written a gs plugin nor do i know a lot about how the gs works, so idk what the best way to handle the situation would be.

as for SIGNAL/FINISH, do as refraction said and ignore them.
the emulator core processes the gs packet before sending it to the gs plugin, and it handles the writes to signal/finish.
Check out my blog: Trashcan of Code
Reply
#20
Thank you cotton. That's very helpful.
Reply




Users browsing this thread: 2 Guest(s)