Get pixel function for D3D11 backbuffer?

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
SamCam
Posts: 20
Joined: January 8th, 2020, 3:24 pm

Get pixel function for D3D11 backbuffer?

Post by SamCam » November 13th, 2020, 2:09 am

What's up dudes!

Has anyone tried/succeeded in making a getpixel type function in the D3D setup? Perhaps it comes later on the course, apologies if so.

From reading so far I think I need to:
1. Create a 2Dtexture
2. Fill out descriptor for the 2Dtexture
3. GetBuffer() from the pSwapChain and fill the 2Dtexture
4. Dive into the 2D texture and pull out a color?

I'm off to bed now, but if anyone has any ideas or solid resources to look at I would be grateful!

SamCam
Posts: 20
Joined: January 8th, 2020, 3:24 pm

Re: Get pixel function for D3D11 backbuffer?

Post by SamCam » November 13th, 2020, 3:03 pm

This is where I'm at currently.

Getting an excpetion thrown at pContext->Map()
"Map cannot be called with MAP_READ access, because the Resource was not created with the D3D11_CPU_ACCESS_READ flag. "

Which is confusing as the newly created resource has the D3D11_CPU_ACCESS_READ flag enabled. This is also true If I try MAP_WRITE and changet the access flags to match. I've also tried ORing the flags together with no luck.

Any ideas welcome!

Code: Select all

Color Graphics::GetPixel(int x, int y) const
{
	//Frame Pointer Setup;
	CD3D11_TEXTURE2D_DESC pFrameDesc;
	pFrameDesc.Width = WindowWidth;
	pFrameDesc.Height = WindowHeight;
	pFrameDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
	pFrameDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	pFrameDesc.MipLevels = 1u;
	pFrameDesc.ArraySize = 1u;
	pFrameDesc.SampleDesc.Count = 1u;
	pFrameDesc.SampleDesc.Quality = 0u;
	pFrameDesc.Usage = D3D11_USAGE_DEFAULT;
	pFrameDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
	pFrameDesc.MiscFlags = 0u;

	wrl::ComPtr<ID3D11Texture2D>	pFrame = nullptr;
	HRESULT hr = pDevice->CreateTexture2D(&pFrameDesc, nullptr, &pFrame);
	GFX_THROW_INFO(hr);

	hr = pSwapChain->GetBuffer(0, __uuidof(pFrame), &pFrame);
	GFX_THROW_INFO(hr);

	D3D11_MAPPED_SUBRESOURCE map;
	map.RowPitch = WindowWidth * 4;
	map.DepthPitch = WindowHeight * 4;
	hr = pContext->Map(pFrame.Get(), 0u, D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &map);
	GFX_THROW_INFO(hr);

	//return some bullshit color for now.
	return { 0.0f, 0.4f, 0.0f, 0.0f };
}

SamCam
Posts: 20
Joined: January 8th, 2020, 3:24 pm

Re: Get pixel function for D3D11 backbuffer?

Post by SamCam » November 15th, 2020, 4:03 am

Working code! I ended up making two functions, one as a single GetPixel and this one for returning the pointer to the pixels which was much more performant for my needs. Thanks to people on the Discord who helped me move this along.

Code: Select all

uint8_t* Graphics::GetFramePtr() const
{
	//Create copying/buffer texture
	wrl::ComPtr<ID3D11Texture2D> pFrame = nullptr;
	HRESULT hr = pSwapChain->GetBuffer(0, __uuidof(pFrame), &pFrame);
	GFX_THROW_INFO(hr);

	//Create staging texture
	CD3D11_TEXTURE2D_DESC pStageDesc;
	wrl::ComPtr<ID3D11Texture2D> pStage = nullptr;

	//Copy descriptors from backbuffer texture
	pFrame->GetDesc(&pStageDesc);
	pStageDesc.BindFlags = 0u;
	pStageDesc.Usage = D3D11_USAGE_STAGING;
	pStageDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
	hr = pDevice->CreateTexture2D(&pStageDesc, nullptr, &pStage);
	GFX_THROW_INFO(hr);

	//Copy into staging texture
	pContext->CopyResource(pStage.Get(), pFrame.Get());

	//Map that & gimmie my pointer to pixels fool
	D3D11_MAPPED_SUBRESOURCE map;
	map.RowPitch = WindowWidth;
	map.DepthPitch = WindowHeight;
	hr = pContext->Map(pStage.Get(), 0u, D3D11_MAP_READ, 0u, &map);
	GFX_THROW_INFO(hr);

	//Make nice for others
	uint8_t* res = reinterpret_cast<uint8_t*>(map.pData);

	return res;
}

albinopapa
Posts: 4289
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Get pixel function for D3D11 backbuffer?

Post by albinopapa » November 16th, 2020, 1:37 pm

Your code is potentially unsafe though. You create a texture locally using ComPtr, so the texture gets released when the function ends. You also map the resource on a resource that get's destroyed at the end of the function.

The staging texture should be a member of graphics, of course then you'd also need to unmap the resource before copying the back buffer to the staging texture.

The safest way, would be to memcpy the staging texture to a system buffer and have that as your graphics member.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4289
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Get pixel function for D3D11 backbuffer?

Post by albinopapa » November 16th, 2020, 1:59 pm

I can't say for sure, but if you are trying to mix hardware rendering with software rendering, there might be a more efficient way of going about it.

The steps I'm thinking of would be:
  • Create a staging texture not retrieved from the swap chain, this will be what you render 3D to.
  • Create a system buffer that can be manipulated more efficiently than a Texture2D
  • Create back buffer from swap chain
  • Rendering your 3D scene
  • Map your staging texture and copy pixel data to the system buffer
  • Unmap your staging texture to release the lock on it's memory
  • Render your 2D elements which draws on top of the copied pixels
  • Map back buffer
  • Copy system buffer pixels to back buffer
  • Unmap back buffer
  • Present frame
Or possibly more efficient
  • Create a default usage texture not retrieved from the swap chain, this will be what you render 3D to.
  • Create a system buffer that can be manipulated more efficiently than a Texture2D
  • Create system buffer texture as dynamic usage
  • Create back buffer from swap chain
  • Create vertex shader for textured quad
  • Create pixel shader for textured quad
  • Render 3D scene - draws to default usage texture
  • Render 2D scene - draws to system buffer
  • Map dynamic texture and copy system buffer pixels
  • Unmap dynamic texture
  • Bind the default and dynamic textures to pipeline
  • Call draw using a textured quad
The new pixel shader would need to take the two textures and combine them. Using the texture coordinates, you could check if the alpha channel of the system buffer is non-zero and output the pixel or if zero, use the other texture's pixel. This way the GPU does the blending.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply