Can i resolve a multisampled depth buffer into a texture?

Started by
6 comments, last by MJP 8 years, 11 months ago

I was using a supersampled depth buffer during the shadow map pass (something like: screen_width * 4, screen_height * 4) and I wanted to try whether it would be faster to use a multisampled texture instead. However I am having problems resolving it to a non-multisampled texture. Specifically I am getting two errors:


D3D11 ERROR: ID3D11DeviceContext::ResolveSubresource: The Format (0x2d, D24_UNORM_S8_UINT) is never able to resolve multisampled resources. [ RESOURCE_MANIPULATION ERROR #294: DEVICE_RESOLVESUBRESOURCE_FORMAT_INVALID]

D3D11 ERROR: ID3D11DeviceContext::ResolveSubresource: Source Resource must not have the D3D11_BIND_DEPTH_STENCIL flag set. [ RESOURCE_MANIPULATION ERROR #292: DEVICE_RESOLVESUBRESOURCE_SOURCE_INVALID]

The second one seems more menacing since the D3D11_BIND_DEPTH_STENCIL has to be set for me to be able to render into the depth buffer.

The code for shadow render target initialization:


        // Multisampled texture to be resolved
	D3D11_TEXTURE2D_DESC msDepthStencilDesc = {};
	msDepthStencilDesc.Width = (UINT)renderer->screenSize.x;
	msDepthStencilDesc.Height = (UINT)renderer->screenSize.y;
	msDepthStencilDesc.MipLevels = 1;
	msDepthStencilDesc.ArraySize = 1;
	msDepthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	msDepthStencilDesc.SampleDesc.Count = 4;
	msDepthStencilDesc.SampleDesc.Quality = D3D11_STANDARD_MULTISAMPLE_PATTERN;
	msDepthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
	msDepthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	msDepthStencilDesc.CPUAccessFlags = 0;
	msDepthStencilDesc.MiscFlags = 0;
	ID3D11Texture2D* tmpMSDepthStencilTex;
	HRESULT hr = renderer->device->CreateTexture2D(&msDepthStencilDesc, NULL, &tmpMSDepthStencilTex);
	CHECK_WIN_ERROR(hr, "Error creating Depth Buffer texture\n");

	CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2DMS, msDepthStencilDesc.Format);
	hr = renderer->device->CreateDepthStencilView(tmpMSDepthStencilTex, &depthStencilViewDesc, &renderTarget->depthStencilView);
	CHECK_WIN_ERROR(hr, "Error creating depth stencil view\n");


        // Texture to be sampled in the scene pass
	D3D11_TEXTURE2D_DESC depthStencilDesc = {};
	depthStencilDesc.Width = (UINT)renderer->screenSize.x;
	depthStencilDesc.Height = (UINT)renderer->screenSize.y;
	depthStencilDesc.MipLevels = 1;
	depthStencilDesc.ArraySize = 1;
	depthStencilDesc.Format = DXGI_FORMAT_R24G8_TYPELESS;
	depthStencilDesc.SampleDesc.Count = 1;
	depthStencilDesc.SampleDesc.Quality = 0;
	depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
	depthStencilDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	depthStencilDesc.CPUAccessFlags = 0;
	depthStencilDesc.MiscFlags = 0;
	ID3D11Texture2D* tmpDepthStencilTex;
	hr = renderer->device->CreateTexture2D(&depthStencilDesc, NULL, &tmpDepthStencilTex);
	CHECK_WIN_ERROR(hr, "Error creating Depth Buffer texture\n");

	D3D11_SHADER_RESOURCE_VIEW_DESC depthShaderResourceViewDesc = {};
	depthShaderResourceViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
	depthShaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	depthShaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
	depthShaderResourceViewDesc.Texture2D.MipLevels = 1;
	hr = renderer->device->CreateShaderResourceView(tmpDepthStencilTex, &depthShaderResourceViewDesc, &renderTarget->depthTexture);
	CHECK_WIN_ERROR(hr, "Error creating depth texture\n");The MS resolve code:

        // Resolve multisample
        ID3D11Resource *multisampleTexture;
	renderTarget->depthStencilView->GetResource(&multisampleTexture);
	ID3D11Resource *texture;
	renderTarget->depthTexture->GetResource(&texture);
	renderer->context->ResolveSubresource(texture, 0, multisampleTexture, 0, DXGI_FORMAT_D24_UNORM_S8_UINT);
	RELEASE_DX_RESOURCE(multisampleTexture);
	RELEASE_DX_RESOURCE(texture);

Thanks for your help.

Advertisement

Hmmm, sounds like you have to do that manually in which case you could do the shadowmapping with a Texture2DMS directly, I guess.

What did you expect it to do anyway? The "default" box filter resolve makes no sense whatsoever for depth values.

Mona: Well I am currently using straight dumb supersampling and increasing the size of the texture to be, say 4*screen_width, 4*screen_height improves the quality of the shadows dramatically, so I thought that using multisampling would have a similar effect. Doesn't sampling a supersampled texture have similar effect to using multisampling?

Pixelshader code:


	for (uint i = 0; i < sampleCount; i++)
	{
		if (!shadowTexture.SampleCmp(depthSampler, shadowTexCoord + poissonDisk[i] / 700.0f,
			calculatedDepth))
		{
			shadow += 0.9f / sampleCount;
		}
	}

Mona: Well I am currently using straight dumb supersampling and increasing the size of the texture to be, say 4*screen_width, 4*screen_height improves the quality of the shadows dramatically, so I thought that using multisampling would have a similar effect. Doesn't sampling a supersampled texture have similar effect to using multisampling?

He means that averaging depth values doesn't make sense, whether it's via supersampling or multi sampling.

A subpixel at depth 0.5 and a subpixel at depth 0 doesn't mean the pixel is at depth 0.25; it means there are two triangles touching that pixel, one is very close to the camera the other is a little further.

If all you want to do is increase the resolution of the shadow map, then you really should just increase the resolution of the shadow map. Multisampling isn't really useful for your particular situation.

Okay I get the idea but then why does increasing the resolution of the shadow map texture improve the quality of the shadows? I thought that when I render into a higher resolution texture and then sample it while rendering to a smaller resolution render target, then if the higher resolution texture is 4 x larger than the render target, a single sample would be an average of the 4 pixels in the larger texture.

But as you guys said this doesn't make sense for depth so why would it improve the quality of the shadows. Hopefully you will get what I'm asking :).

The part you're missing here is that your shadow map isn't lined up 1:1 with your screen. Instead it's projected onto a frustum that's oriented with your light's position, with the resulting shadows being projected onto your screen. As a result, you can end up with projective aliasing artifacts where the projection of the shadow-casting light causes the shadow map resolution to be less than the sampling rate of your back buffer. You'll see this as very jaggies in your shadow, where the jagged edges are actually bigger than a pixel on your screen. Increasing the size of your shadow map will increase the shadow map resolution, which will in turn increase the relative sampling rate of your shadow map depth vs. your screen pixel sampling rate. The end result will be that the shadows will look less jagged.

Since a shadow map projection isn't related to your screen projection, it's common to pick a resolution that's not at all tied to your screen resolution. Typically you'll just pick a size like 512x512 or 1024x1024.

This topic is closed to new replies.

Advertisement