Splitting primatives between render targets

Started by
11 comments, last by ankhd 9 years, 5 months ago

Hi guys

I have 2 simultaneous render targets that I am rendering to. I need to split the output of my geometry shader so that one part goes to the first target and the second to the second target.

I noticed I can use the semantic SV_RenderTargetArrayIndex but how would I set up the pixel shaders to render to separate targets?

Thanks

JB

Advertisement

You may want to check the D3D11 SDK CubeMapGS example. In the sample the pixel shader is defined as:

float4 PS_CubeMap( PS_CUBEMAP_IN input ) : SV_Target
{
return g_txDiffuse.Sample( g_samLinear, input.Tex );
}
And the geometry shader outputs the SV_RenderTargetArrayIndex.
Cheers!

Ah ok thanks.

Ok this is odd....The first render target is getting the output of the second.

Here is my pixel shader input/geometry shader output:


struct PS_INPUT
{
	float4 p : SV_POSITION;
	float2 t : TEXCOORD0;
	float4 c : COLOR;
	uint rt : SV_RenderTargetArrayIndex;
};

And here is my geometry shader:


[maxvertexcount(93)]
void GS( point GS_INPUT sprite[1], inout TriangleStream<PS_INPUT> triStream )
{
	PS_INPUT v;

	float c = cos(hdg);
	float s = sin(hdg);
	
	float2x2 rotation = {c, -s, s, c};

	v.c = float4(0, 0, 0, 1);
	v.rt = 0;

	switch(col)
	{
	case 0:
		v.c = float4(0, 0, 0, 1);
		break;
	case 1:
		v.c = float4(0, 1, 0, 1);
		break;
	case 2:
		v.c = float4(1, 1, 0, 1);
		break;
	case 3:
		v.c = float4(1, 0, 0, 1);
		break;
	}
	v.t = float2(0, 0);
	float2 center = sprite[0].pos.xy;
	float r = 0;
	if(abs(sprite[0].size.x) > abs(sprite[0].size.y))
		r = abs(sprite[0].size.x)*0.9;
	else
		r = abs(sprite[0].size.y)*0.9;
	float2 rad = {r*rng, r*rng};

	if(abs(sprite[0].ctr.x) + r > 8300.0f)
		rad.x = (r - ((abs(sprite[0].ctr.x) + r)-8300.0f))*rng;
	if(abs(sprite[0].ctr.y) + r > 8300.0f)
		rad.y = (r - ((abs(sprite[0].ctr.y) + r)-8300.0f))*rng;

	v.p = float4(mul(center+float2(rad.x, 0), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);
		
	v.p = float4(mul(center+float2(rad.x*SIN45, rad.y*SIN45), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);	
	triStream.Append(v);

	v.p = float4(mul(center+float2(rad.x*SIN45, -rad.y*SIN45), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);	
	triStream.Append(v);

	v.p = float4(mul(center+float2(0, rad.y), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);

	v.p = float4(mul(center+float2(0, -rad.y), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);

	v.p = float4(mul(center+float2(-rad.x*SIN45, rad.y*SIN45), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);	
	triStream.Append(v);

	v.p = float4(mul(center+float2(-rad.x*SIN45, -rad.y*SIN45), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);	
	triStream.Append(v);

	v.p = float4(mul(center+float2(-rad.x, 0), rotation)-float2(0.0f, 1.0f), sprite[0].pos.z, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);

	triStream.RestartStrip();

	v.rt = 1;

	if(sprite[0].ctr.x < -8000.0f)
		v.c = float4(1, 0, 0, 0);
	if(sprite[0].ctr.y > 8000.0f)
		v.c = float4(0, 1, 0, 0);
	if(sprite[0].ctr.x > 8000.0f)
		v.c = float4(0, 0, 1, 0);
	if(sprite[0].ctr.y < -8000.0f)
		v.c = float4(0, 0, 0, 1);

	float4 ep = mul(float4(-8000.0f, 0, -8000.0f, 1), world);
	v.p = float4(mul((ep.xz-latlon)*rng, rotation)-float2(0.0f, 1.0f), 0, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);

	ep = mul(float4(-8000.0f, 0, 8000.0f, 1), world);
	v.p = float4(mul((ep.xz-latlon)*rng, rotation)-float2(0.0f, 1.0f), 0, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);

	ep = mul(float4(8000.0f, 0, -8000.0f, 1), world);
	v.p = float4(mul((ep.xz-latlon)*rng, rotation)-float2(0.0f, 1.0f), 0, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);

	ep = mul(float4(8000.0f, 0, 8000.0f, 1), world);
	v.p = float4(mul((ep.xz-latlon)*rng, rotation)-float2(0.0f, 1.0f), 0, 1)*float4(0.78125f, 1.0f, 1.0f, 1.0f);
	triStream.Append(v);
	triStream.RestartStrip();
}

And the pixel shader:


float4 PS( PS_INPUT input ) : SV_Target
{ 
	float4 color = input.c*0.02f;
	return color;
}

The first render target (v.rt = 0) is supposed to receive a bunch of octagons overlaid on eachother. The second (v.rt = 1) is supposed to receive a large square covering a set area. Instead, both render targets are getting the output of the second render target.

Any ideas?

Are your rendertargets part of a texture array? that is, you are using a texture array with 2 slices? I think that you can't output to 2 render targets that aren't part of same array.

Cheers!

I see...I am using 2 separate ID3D11Texture2D objects for the render targets. You say it should be 1 3D texture with 2 slices?

Hi,

No, one 2D texture array with 2 slices.

Cheers!

Ah! Set D3D11_TEXTURE2D_DESC::ArraySize to 2 when creating the texture?

Yes!

I think that you'll need to create a ShaderResourceView each slice if you want to use them as a texture (pixel shader resource).

Cheers!

[edit] what I was thinking - one SRV is enough and in the shader you can access the slices separately with an extra parameter when sampling or loading.

I think that you'll need to create a ShaderResourceView each slice if you want to use them as a texture (pixel shader resource).


Still needs to be declared as a Texture2DArray (both the SRV description and in the pixel shader), unfortunately. Funnily it works on my NVidia when declaring a SRV array (with one slice) and a Texture2D in the shader, but you will get this:

ERROR: ID3D11DeviceContext::Draw: The Shader Resource View dimension declared in the shader code (TEXTURE2D) does not match the view type bound to slot 0 of the Pixel Shader unit (TEXTURE2DARRAY).

Better play safe and use arrays everywhere.

This topic is closed to new replies.

Advertisement