Clone this wiki locally
The PGRAPH is the engine of the GPU that actually performs graphics operations like blitting and drawing triangles. It can be programmed by directly writing to its registers in MMIO space or by feeding commands through the PFIFO engine.
Basically, PGRAPH should be seen as a pipeline that is fed by the PFIFO CACHE.
The dispatch in PGRAPH is mainly done by dedicated PGRAPH_DISPATCH engine, which checks the commands and forwards them to the right subengine. As PGRAPH is a pipeline it doesn't end here, The subengines all dispatch stuff to one another:
- VFETCH pulls vertices, outputs decoded vertex arguments and primitive info into the next stage
- the next stage [which nobody bothered to name yet] dispatches the vertices to TPs' MPC units for VP processing, which in turn dispatch them among the available warp slots in MPs
- the processed data is pulled back, then may be dispatched again to MPs for GP processing.
- It then goes to STRMOUT, then rasterizer, then converted to fragments, dispatched to MPs for FP processing, then finally dispatched to ROPs for actually writing into the RT
Confusing enough already? The above list only mentions less than half of involved PGRAPH units :)
- MP == multiprocessor, the little buggers that run all kinds of CUDA code
- GP == geometry program / shader, one particular kind of CUDA code
- STRMOUT == stream out in D3D10/11, also known as transform feedback in GL
- FP == Fragment Program / shader. also known as pixel shader in D3D.
- ROP == Raster OutPut, the final part of 3d pipeline, which writes FP outputs to the RTs (AKA the output merger in D3D)
- RT == Render Target, a buffer that the pipeline renders to
You'll find the register map here:
NV50 & NVC0
WARNING: this part doesn't reflect our new knowledge on the matter. We'll update this when we get a fully functional AND reliable pausing procedure
To pause the PGRAPH, you need to play with the PULL(bit 0) bit of the CONTROL(0x400500) register.
Clearing it will prevent PGRAPH from pulling commands from the PFIFO which will then starve of commands --> paused!
We also need to set the bit UNK16(bit 16) because otherwise, PGRAPH could be stuck in a ctxprog context switch or an m2mf memory transfer. Anyway, this bit should already been set.
Wait for the pause
We now need to wait for PGRAPH to actually pause.
The blob first checks on these registers (wait for them to come to 0):
Then, you'll need to wait for the STATUS(0x400700) register's bit ALL(bit 0) to go down to 0.
Un-pausing is done by setting the PULL(bit 0) bit of the CONTROL(0x400500) register. Remember to also set the bit UNK16(bit 16).