Get a pixel color on directx11 from the screen

Viewed 36

I need to do function like:

RGBTRIPLE GetPixelColor(int x, int y)

to get a color on a single pixel on directx 11 from the actual frame in my screen

For the moment I have this code:

//For each Call to Present() do the following:

//Get Device
ID3D11Device* device;
HRESULT gd = pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&device);
assert(gd == S_OK);

//Get context
ID3D11DeviceContext* context;
device->GetImmediateContext(&context);

//get back buffer
ID3D11Texture2D* backbufferTex;
HRESULT gb = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2d), (LPVOID*)&backbufferTex);
assert(gb == S_OK);

I'am not an expert on directx.

I ask how I can get the pixel color of coordinate x,y from buffer or context or other.

Can you help me please ?

Thanks !

1 Answers

There are several ways to do that, first one, you read the entire texture back to memory and pick your pixel from there (Pseudo code) :

  • create another ID3D11Texture2D same size/format as backbufferTex (with no bind flags, read cpu access and staging usage.
  • Use CopyResource to copy your back buffer to the staging texture.
  • Use Map (with read flag) on the staging texture to have access to it in memory
  • You now have a D3D11_MAPPED_SUBRESOURCE that contains a pointer to your image data (beware of the RowPitch parameter when trying to locate pixel).

This is rather simple, but it requires to download the whole texture from vram to ram, which is rather inefficient it you want to do this only once (also your have to handle texture format properly, it can be rgb/bgr, also 10 bits or 16 bits floats in some cases.

Another version is to use a compute shader to go pick that single pixel and store it in a gpu guffer (3 or 4 floats), then only download back that single pixel.

This is the process for it:

  • Create a shader resource view for backbufferTex (to allow compute shader read access)
  • Create a constant buffer (16 bytes), to allow to upload the coordinates of the pixel you want to read.
  • Create a compute writeable structured buffer (16 bytes strides, 1 element)
  • Create a UnorderedAccessView for this buffer.
  • Create a staging buffer (16 bytes), read access.
  • Create compute shader to access pixel data (code below).
  • Attach your constant buffer/texture as input, UnorderedAccessView as output of compute pipeline
  • Call Dispatch (1,1,1)
  • Copy writeable structured buffer to staging buffer
  • Map staging buffer, which contains 4 floats as your pixel data (normalized from 0->1 normally)

Compute shader code to read the pixel

cbuffer cbPixelLocation : register(b0)
{
    uint2 pixelLocation;
    uint2 padding;
}
Texture2D BackBufferTexture : register(t0);

RWStructuredBuffer<float4> RWPixel : register(u0);

[numthreads(1,1,1)]
void CS(uint3 tid : SV_DispatchThreadID)
{
   RWPixel[0] = BackBufferTexture.Load(int3(pixelLocation,0));
}

Setup is rather more complex, but it has the big advantage of only downloading 16 bytes of data instead of a whole texture.

Related