Shawn Hargreaves Blog
The bad news:
If you had a program using rendertargets that worked with the XNA Framework 1.0, it might not still work with 2.0.
The good news:
Things are actually much more consistent now, honest!
Let me explain...
Problem with the 1.0 behavior:
It was far too easy to write a program that worked fine on one platform, but then rendered incorrectly when you run it on the other!
If you don't like that default:
Other good stuff:
Great post Shawn, this really helped me understand the differences! :)
If you happen to have some time left some day, could you write about how you do the MRT stuff on the 360 in XNA 2.0? I know it looks and works the same on 360 and pc in the XNA framework. I'm really curious as to how it works inside the framework itself, because afaik, the 360 does not support MRT like the pc does.
"This is ok ... But this is not"
That example is plain and simple, so it explains it all quite ok. Always works ... thanks!
Is there any extreme case where this cannot be avoided? I'll follow your advice and use "DiscardContents", but I'm asking for learning purposes ...
"... you no longer need to call the GraphicsDevice.ResolveRenderTarget method ..."
So no more situations like: "why I'm getting a blank ...?" / "Did you resolve the render target?".
"I'm really curious as to how it works inside the framework itself, because afaik, the 360 does not support MRT like the pc does."
> afaik, the 360 does not support MRT like the pc does.
Easy: the 360 does support MRT in hardware! We just didn't expose that in v1, because we didn't have time to finish all the (rather large and complex) driver code needed to actually make it work.
> Is there any extreme case where this cannot be avoided? I'll follow your advice and use "DiscardContents", but I'm asking for learning purposes ...
I can't think of any, but there are certainly some situations (like doing image feedback from one frame to the next) where the preserve behavior can be useful. If you found yourself having to implement a preserve-like behavior by using two buffers and manually drawing the contents of one over the other each time, you might as well just simplify your code by setting the PreserveContents flag to ask us to take care of that for you.
I remember a technique to obtain a better framerate -lossing some quality- by doing something like that with two halves of images: one from the new one and the other from the old one. So you kinda render a moving "average" each frame, you just preserve the last image and "merge" an new half (so you render half the screen on each Draw call).
It's like the method used to cast images in old TVs, I guess.
I have to check it, but maybe it was explained on the ShaderX4 book.
"Easy: the 360 does support MRT in hardware! We just didn't expose that in v1, because we didn't have time to finish all the (rather large and complex) driver code needed to actually make it work."
I'm sorry, what I was trying to refer to was the 'predicated tiling' I read about. I found a set of powerpoint slides* in the meantime that talk about it, and I think I understand how it works now.
I am curious as to the use of predicated tiling in other situations. It's supposedly necessary in case of 720p and MSAA, but since the 360's EDRAM is only 10MB large, it seems it's also not possible to get a full HD resolution backbuffer and depth-stencil buffer into it. Does that mean that tiling is also used with 1080p resolution?
Given the number of uses of the predicated tiling, I'm really interested to know how much of a performance hit it gives? I read that it's only the vertices of polygons on two different tiles that have to be recalculated, but there's the cost of copying as well, or is that negligible? Is the total cost high enough to search for alternatives to MRT, MSAA and 1080p?
Sorry about all the questions, I just get excited by reading about technology and 'tricks' like these ;)
Predicated tiling is used any time the combined rendertarget(s) + depth buffer are bigger than 10 megabytes. The XNA Framework handles this entirely automatically (unlike the native API, where you have to write code specifically to make this work).
Performance is usually a lot better than you would expect. The fillrate is not changed at all, and while vertex processing workload goes up, this is usually not the bottleneck so it may not have any measurable difference at all. Predicated tiling is only really going to hurt you on games which are:
a) GPU limited
b) Vertex shader limited within the GPU (ie. have a lot of very high polycount models and/or complex vertex shaders)
In the current model, what happens with the DepthBuffer ? Is it still discarded when changing the RenderTarget?
The depth buffer matches the rendertarget behavior. It's preserved if the rendertarget is, or discarded otherwise.
Stencil is never preserved, though (not for any particularly good reason: we just didn't have time to make that work :-)
And if I'm using MRTs, and the 0 RT is set to Preserve, while the others are not, the Depth will also be saved, right? is this true on the Xbox also?
And one more question (sorry for spamming you with questions):
Is the depth buffer preserver from one RT to another?
I set an RT, draw stuff, and when I set a new RT, will the depth buffer (when using the new RT) be the same, or will it be cleared?
The reason I need the DepthBuffer to be preserved is the following:
In your deferred rendering slides, you mention using Stencil tests to lower the number of pixels affected by each individual light.
But if the depthbuffer is cleared when changing from the Gbuffer creation to the light processing, this is no longer possible. Any ideas on how to solve this problem?
For that technique you would need to enable the preserve contents mode, yes.
I'm not sure that would actually give you a perf gain on Xbox, though. I'm guessing restoring the depth contents is going to be slower than however much you gain through the stencil tests.
Deferred rendering is actually quite an awkward fit for the 360, because of the limited size but very fast EDRAM hardware design. The technique as a whole may work ok, but I think that light volumes idea is probably more work than it is worth.
When trying to implement RenderToTarget feature in 2.0, I used the same setup as in a 1.0 application. The only changes I made were as described above. I removed the calls to ResolveRenderTarget, and selected the old default of PreserveContents, attempting to get my previous behavior. It all compiles, but when I run this program I get the error "The active render target and depth stencil surface must have the same pixel size and multisampling type" when I call clear on the first render target. I'm not sure how there would be a difference, though. Any suggestions on resolving this mis-match?
I could use this code to get a rendertarget's surface pointer when i use RenderTargetUsage.DiscardContents
public unsafe IntPtr GetSurface(RenderTarget renderTarget)
type = typeof(RenderTarget);
fi = type.GetField("pRenderTargetSurface", BindingFlags.NonPublic | BindingFlags.Instance);
ptr = fi.GetValue(renderTarget);
return new IntPtr(Pointer.Unbox(ptr));
however, if i set use RenderTargetUsage.PreserveContents,i get result 0x00000000
can you tell me why? thanks!