God of War. Red line rendering explained.
#1
I spend severals day to debug this god of war issue. I think I have an understanding of most of the issue to draw correctly the fog.

I really don't know how to fix it properly. But I think it would be nice to share the crazy behavior of GoW with you Smile

* Start of the frame
various input texture and primitives
output a 32 bits RT @ 0x0 + a 24 bits depth buffer @0xd00

   

Then it will compute a special effect based on the depth. Screen is split in 8 vertial bands. And effect is apply 8 times (that a shame it would be free to do it once for the full screen with current GPU)



Step1 of the effect:
input texture: 24 bits (with depth swizzling) @ 0xd00
output RT: 24 bits @ 0x2800
depth (depth disabled): 24 bits @0xd00
RT will receive the opposite of texture (3 channels), i.e. a color of 4 will return 251.

GSdx limitation1: blending will clamp not wrap
=> solution use sw blending => accurate_colclip
GSdx limitation2: depth texture is float 32 bits on GPU. So it need to be converted. And we need to reuse it as input texture.
=> half solution: add some shader to convert it
=> add various hack to copy the depth into the local memory and disable the texture cache. Temporary until I find a better solution (and that it works this way).
GSdx limitation3: RT is 24 bits so alpha channel mustn't be written
=> solution not yet implemented but doable

Yes so much issue for a single draw call! Anyway I manage to have a texture. Initially it was completely dark now you have that

   



Step2 of the effect:
no input texture
output RT: 24 bits @ 0x2800
depth (depth enabled): 24 bits @ 0x2800

GSdx limitation: support of RT/Depth as same address.
RT will receive the color of RT (so no change)
Depth will be updated with the primitive test)
Note: due to GSdx limitation alpha value will be wrongly copied



Step3 of the effect:
input texture: 16 bits (depth swizzling) @ 0x2800
output RT: 16 bits @ 0x0
depth (depth disabled): 24 bits @ 0xd00

Rt will receive texture with a mask of ~0x3FFF, which mean that red channels is left untouched. And green partially masked

Gsdx limitation: GPU only supports mask of Full channel. You can't do it halfy.
GSdx limitation: initial RT was 32 bits now it is 16 bits ! Texture cache won't like it.

Actually what happen is that depth information is more or less stored in the alpha channel of the RT. If I get it correctly
Z[14:8] is copyied into A[6:0]
0 is copyied into A[7] (due to aem stuff)

Current screenshot of the situation, due to wrong format conversion we draw silly thing:
   



Once the effect is done 8 times for the full screen. There is a final post-processing step that multiply the the alpha channel of the RT (which is reused as 32 bits). On my example the factor is 91 (i.e. 0.71%)
input texture: 32 bits @ 0x0
output RT: 32 bits @ 0x0
Reply

Sponsored links

#2
Thanks for the explanation. Is it even possible to fix these things ?
We're supposed to be working as a team, if we aren't helping and suggesting things to each other, we aren't working as a team.
- Refraction
Reply
#3
I don't know the meaning of not possible Tongue2
Reply
#4
(05-23-2015, 11:27 AM)gregory Wrote: I don't know the meaning of not possible Tongue2



That's the spirit! Tongue2
[Image: ref-sig-anim.gif]

Reply
#5
ref, I need your help with the nice GS format.

First run give you a 32 bits swizzle format (PSMCT32). Then GS will reinterpret it as PSMCT16 (no conversion).
Let's take the first line from x=8 to x=16, how do I compute the address in 16 bits format. And so which pixels in 32 bits is impacted.
Reply
#6
My gs manual is 560 miles away, without looking I wouldn't have a clue, even then I'd cry at the memory structure Tongue2
[Image: ref-sig-anim.gif]

Reply
#7
Don't worry I still need to double check previous step of the rendering.

Actually it is quite complicated because the 24 bits special texture is read back as a 16 bits depth buffer...

Maybe I will try to communicate through the GS local memory to force the conversion so it can reuse GSdx code.

Edit: yes the step2 is wrong. The depth texture used in 0x2800 is black whereas it must contains data of previous draw call
Reply
#8
Ok. I understand a bit more the purpose of the rendering.

A word can contains 32 bits pixels in RGBA8
A word can also contains two 16 bits pixels in RGB5A1

So the game draw lines because it wants to access the 2nd 16 pixels of the word (aka the upper bit of RGBA8 which mean BA8). Lower bits RG will remains untouched.
Then the game sets a mask of 0x3FFF which is logical when we decompose the remaining 16 bits
Originally you have 8 bits of alpha and 8 bits of blue. Now you must consider it as a 16 bits colors
Quote:number of bits of 32 bits representation => number ofs bit of the 16 bit representation
1A => 1A
5A => 5B
2A => 2G
3B => 3G
5B => 5R

On 16 bits a mask of 0x3FFF can be translated as a mask of 5R + 3G. Let's reuse previous representation
Quote:1A => 1A
5A => 5B
2A => 2G
3B => 3G <= masked
5B => 5R <= masked
In others word, only the alpha part of the 32 bits color will be updated ! Therefore the alpha channel will be a function of the depth. I was wrong the last post-processing step isn't a format conversion but a way to apply a final multiplication factor to the alpha.
Reply
#9
Good work Smile
[Image: ref-sig-anim.gif]

Reply
#10
I think I have a couple games that suffer from a similar issue.
Reply




Users browsing this thread: 1 Guest(s)