Take a screenshot in D3D12

Started by
1 comment, last by galop1n 7 years, 4 months ago

Hi,

here the code I used using D3D11 to take a screenshot :


CImage CDirect3D11RenderWindow::ScreenShot() const
{
	// Get the back buffer.
	ID3D11Texture2D* BackBuffer;
	m_SwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), reinterpret_cast< LPVOID* >( &BackBuffer ) );

	// Set the staging desc.
	D3D11_TEXTURE2D_DESC StagingDesc;
	BackBuffer->GetDesc( &StagingDesc );
	StagingDesc.Usage = D3D11_USAGE_STAGING;
	StagingDesc.BindFlags = 0;
	StagingDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

	// Create the back buffer staging texture.
	ID3D11Texture2D* BackBufferStaging;
	CDirect3D11Device::GetDevice()->CreateTexture2D( &StagingDesc, nullptr, &BackBufferStaging );

	// Copy back buffer to back buffer staging.
	CDirect3D11Device::GetDeviceContext()->CopyResource( BackBufferStaging, BackBuffer );

	// Get the size of the window.
	UInt32 Width, Height;
	GetSize( &Width, &Height );

	// Image data.
	UInt8* ImageData = new UInt8[ Width * Height * 4 ];

	// Create the image.
	D3D11_MAPPED_SUBRESOURCE Map;
	CDirect3D11Device::GetDeviceContext()->Map( BackBufferStaging, 0, D3D11_MAP_READ, 0, &Map );
	UInt8* BackBufferData = static_cast< UInt8* >( Map.pData );
	UInt8* ImageDataPtr = &ImageData[ 0 ];
	for( UInt32 y = 0; y < Height; ++y )
	{
		for( UInt32 x = 0; x < Width; ++x )
		{
			ImageDataPtr[ 4 * x + 0 ] = BackBufferData[ 4 * x + 0 ];
			ImageDataPtr[ 4 * x + 1 ] = BackBufferData[ 4 * x + 1 ];
			ImageDataPtr[ 4 * x + 2 ] = BackBufferData[ 4 * x + 2 ];
			ImageDataPtr[ 4 * x + 3 ] = 255;
		}
		BackBufferData += Map.RowPitch;
		ImageDataPtr += Width * 4;
	}
	CDirect3D11Device::GetDeviceContext()->Unmap( BackBufferStaging, 0 );

	// Release the backbuffer staging.
	BackBufferStaging->Release();

	// Create the image.
	CImage Image;
	Image.Create( Width, Height, ImageData );

	// Return the image.
	return Image;
}

I'm not well experienced actually in D3D12 but from what I saw, the read back is different than D3D11.

Is it possible to have informations about how to convert for D3D12 correctly ?

Thanks

Advertisement

There's no such thing as a staging or readback texture anymore in D3D12, so you'll have to copy your texture over to a readback buffer first using ID3D12GraphicsCommandList::CopyTextureRegion.

Have a look at D3D12_TEXTURE_COPY_LOCATION to see how you can set up your buffer as a texture copy destination.

I gets all your texture budgets!

If you are not an expert at d3d11, you should probably not even look at d3d12, and if you are you would probably no asking that :) But anyway, here the details :

0. Create or use an existing graphic command list

1. Use GetCopyableFootprints to obtain the size a readback buffer you are gonna need

2. Create a commited resource buffer in copy dest state

3. Transition the image resource you want to copy to generic read

4. Use CopyTextureRegion to copy from the texture to the buffer

5. Execute the command list

6. Fence and wait for everything to have complete

7. Map on the buffer, use the result of 1 to know how to read the image ( pitch, width, height, ... )

The 6 is the important concept in d3d12 that is not in d3d11, you are responsive for making sure everything execute or is unused before you proceed further or destroy any resource that may be still in use otherelse

This topic is closed to new replies.

Advertisement