Advertisement

[DirectX] Multiple Render Target sampling

Started by October 17, 2019 12:01 AM
7 comments, last by binder2 5 years, 2 months ago

I have an application that renders to two targets.


struct PixelOut
{
	float4 Colour: SV_Target0;
	unsigned int Pick: SV_Target1;
};

The value I write to SV_Target1 is an ID that describes the geometry rendered. After rendering the frame, I read this texture back on the CPU for analysis.

The above works fine when I have multisampling disabled, but when I enable it, I also have to set the second rendertarget to have sampling too. But this obviously doesn't work as I need the ID to be intact, not some resolved value that will produce a different value.

Is there any way around this? I am using DirectX 11

If you don't call ResolveSubresource() for the texture, it won't be resolved. I'd say you can't auto resolve a UINT texture anyway but I might be wrong. It might also be tricky to read back a multisampled texture on the CPU. I'm not sure if you can do that, so you might need to resolve it yourself first with a shader or extract into multiple single sample textures.

Advertisement
10 hours ago, turanszkij said:

I'd say you can't auto resolve a UINT texture anyway but I might be wrong. 

That's correct, there's no hardware resolve support for UINT formats: https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/format-support-for-direct3d-11-0-feature-level-hardware

You also can't create a multisampled texture with STAGING usage, so there's no direct way to read back the data on the CPU. Instead you should write a compute shader or pixel shader that can read the raw subsample data from the MSAA render target, and then output it to a larger 2D texture or buffer.

 

Cheers guys. Do you have a link to a pixel shader that does the processing?

Something like this should work for converting the MSAA render target to a regular render target that's either 2x, 4x, or 8x width:


Texture2DMS<uint> MSAATexture;

uint UnpackMSAA(in float4 ScreenPos : SV_Position)
{
    const uint2 srcTexelPos = uint2(ScreenPos.xy) / uint2(msaaSampleCount, 1);
    const uint srcSubSampleIdx = uint(ScreenPos.x) % msaaSampleCount;
    return MSAATexture.Load(srcTexelPos, srcSubSampleIdx);
}

 

Sorry - only just getting around to trying this.

I cannot get it working with the code you posted, but can with the following :


uint UnpackMSAA(in float4 ScreenPos : SV_Position)
{
	// the sample count we have set for the rendertargets (needs moving to a shader variable)
	const uint msaaSampleCount = 8;

	// rather than use a for loop to perform eight samples/loads, only sample once per pixel, but "randomise" the index we use (the index increments as we move from column to column)
	const uint srcSubSampleIdx = uint(ScreenPos.x) % msaaSampleCount;

	// SV_Position xy is the current pixel coord 
	return pickTexture.Load(uint2(ScreenPos.xy), srcSubSampleIdx);
}

 

What is :


const uint2 srcTexelPos = uint2(ScreenPos.xy) / uint2(msaaSampleCount, 1);

Supposed to be doing in your code? from what I understand, ScreenPos.XY is the screen coords of the pixel currently being rendered. Which is exactly what I need? ... not sure why I need to divide it by the samplecount?

Advertisement

So let's say you have 2 subsamples (MSAA 2x) to make things simple, and we're working with a 1000x1000 render target. If we want to unpack this so that you can read every individual subsample on the CPU, then we need to expand that 2xMSAA render target to a 2000x1000 render target. From there we can copy to an 2000x1000 staging texture, and then call Map to read its contents on the CPU. 

If you're rendering to an 2000x1000 render target, then the X values of SV_Position will go from 0 to 1999. We can't use this X value directly as an address to read from from your 1000x1000 source texture with 2xMSAA, since the valid range of X address values is 0 to 999. So instead we map each X value of the destination render target to a particular X value of the source MSAA texture. Let's say that we want to output the subsamples in this format:


[Texel (0,0), Subsample 0][Texel (0,0), Subsample 1][Texel (1,0), Subsample 0][Texel (1,0), Subsample 1] ... [Texel (999,0), Subsample 0][Texel (999,0), Subsample 1]
[Texel (0,1), Subsample 0][Texel (0,1), Subsample 1][Texel (1,1), Subsample 0][Texel (1,1), Subsample 1] ... [Texel (999,1), Subsample 0][Texel (999,1), Subsample 1]

Does that make more sense now? Basically you just need to convert the output pixel coordinate to source texel coordinate + subsample index, and I did that putting all N subsamples right next to each other in the output target. There's plenty of other ways you could do this: for instance you could create N render targets (or make a texture array with N slices), and draw N fullscreen quads to render 1 set of subsamples to each render target or array slice. 

Ah, gotcha!

As the MSAA rendertarget I am reading from contains ID's for picking (not colour), my goal was to just read one of the samples per pixel, and ignore the other samples. The pixels around the very edge of the object might be incorrect, but I'm not too fussed about that.

So the NON-MSAA target I'm writing into (which I will then be reading back on the CPU by copying to a staging texture) will be the same dimension as the MSAA rendertarget.

 

 

 

This topic is closed to new replies.

Advertisement