When using D3D11_CPU_ACCESS_READ for textures, I am not allowed to read or write using the GPU so that it is completely useless by itself.
How do I copy the immutable texture to a staged resource and read one pixel from it?
Reading one pixel from texture to CPU in DX11
I haven't figured out how to set the dimensions and offsets. Everything I have tried returned (0,0,0,0).
D3D11_BOX SrcBox;
SrcBox.left = ?;
SrcBox.right = ?;
SrcBox.top = ?;
SrcBox.bottom = ?;
SrcBox.front = 0;
SrcBox.back = 1;
m_pImmediateContext->CopySubresourceRegion(Surface->CPUAccessBuffer,0, ?,?,?, InputResource,0,&SrcBox);
You should be able to do it like this:
And create the 1x1 texture with the same format as the source texture, staging usage, 0 bind flags, and D3D11_CPU_ACCESS_READ for the cpu access.
D3D11_BOX srcBox;
srcBox.left = pixel X coordinate;
srcBox.right = srcBox.left + 1;
srcBox.top = pixel Y coordinate;
srcBox.bottom = srcBox.top + 1;
srcBox.front = 0;
srcBox.back = 1;
pContext->CopySubresourceRegion(p1x1StagingTexture, 0, 0, 0, 0, pSourceTexture, 0, &srcBox);
D3D11_MAPPED_SUBRESOURCE msr;
pContext->Map(p1x1StagingTexture, 0, D3D11_MAP_READ, 0, &msr);
BYTE *pixel = msr.pData;
// copy data
pContext->Unmap(p1x1StagingTexture, 0);
And create the 1x1 texture with the same format as the source texture, staging usage, 0 bind flags, and D3D11_CPU_ACCESS_READ for the cpu access.
The issue seems to be when I try to use
with the type DXGI_FORMAT_R32G32B32A32_FLOAT / D3DXVECTOR4.
BYTE *pixel = msr.pData;
with the type DXGI_FORMAT_R32G32B32A32_FLOAT / D3DXVECTOR4.
// CPU Access buffer
D3D11_TEXTURE2D_DESC StagedDesc = {
1,//UINT Width;
1,//UINT Height;
1,//UINT MipLevels;
1,//UINT ArraySize;
DXGI_FORMAT_R32G32B32A32_FLOAT,//DXGI_FORMAT Format;
1, 0,//DXGI_SAMPLE_DESC SampleDesc;
D3D11_USAGE_STAGING,//D3D11_USAGE Usage;
0,//UINT BindFlags;
D3D11_CPU_ACCESS_READ,//UINT CPUAccessFlags;
0//UINT MiscFlags;
};
m_pd3dDevice->CreateTexture2D( &StagedDesc, NULL, &Surface->CPUAccessBuffer );
// Select the pixel
D3D11_BOX SrcBox;
SrcBox.left = X; // Minimum X
SrcBox.right = X+1; // Maximum X
SrcBox.top = Y; // Minimum Y
SrcBox.bottom = Y+1; // Maximum Y
SrcBox.front = 0; // Always 0 for 2D textures
SrcBox.back = 1; // Always 1 for 2D textures
// Get the texture pointer
if (Surface->HaveExtraColorBuffer == false || Surface->SwapState == true) {
InputResource = Surface->OriginalColorBuffer;
} else {
InputResource = Surface->ExtraColorBuffer;
}
// Copy the pixel to the staging buffer
m_pImmediateContext->CopySubresourceRegion(Surface->CPUAccessBuffer,0,0,0,0,InputResource,0,&SrcBox);
// Lock the memory
D3D11_MAPPED_SUBRESOURCE MappingDesc;
m_pImmediateContext->Map(Surface->CPUAccessBuffer,0,D3D11_MAP_READ,0,&MappingDesc);
// Get the data
if (MappingDesc.pData == NULL) {
::MessageBox(NULL, L"DrawSurface_GetPixelColor: Could not read the pixel color because the mapped subresource returned NULL.", L"Error!", NULL);
} else {
Result = *((D3DXVECTOR4*)MappingDesc.pData);
}
// Unlock the memory
m_pImmediateContext->Unmap(Surface->CPUAccessBuffer,0);
Is your source texture the exact same format, and not multisampled?
Use the D3D11_CREATE_DEVICE_DEBUG flag when creating your device and run with the debugger, and see if you get any debug output. If there's something wrong with the copy you will get a warning.
Use the D3D11_CREATE_DEVICE_DEBUG flag when creating your device and run with the debugger, and see if you get any debug output. If there's something wrong with the copy you will get a warning.
I had no warnings in debug mode.
I don't know if the texture is multisampled since I don't use it.
Here is the constructor for my draw surface.
I don't know if the texture is multisampled since I don't use it.
Here is the constructor for my draw surface.
void EngineCore::DrawSurface_SetSize(DrawSurface_Struct* Surface, int NewWidth, int NewHeight, bool FinalSurface, bool HaveDepthBuffer, bool HaveExtraColorBuffer) {
if (NewWidth < 1 || NewHeight < 1) {
::MessageBox(NULL, L"DrawSurface_SetSize: A draw surface can't have non positive dimensions.", L"Error!", NULL);
} else if (Surface->CurrentWidth != NewWidth || Surface->CurrentHeight != NewHeight) {
// Release any old data to avoid memory leaks
DrawSurface_Struct_Release(Surface);
// Store dimensions
Surface->CurrentWidth = NewWidth;
Surface->CurrentHeight = NewHeight;
if (FinalSurface) {
// Update the swap chain
m_pSwapChain->ResizeBuffers(1,NewWidth,NewHeight,DXGI_FORMAT_R8G8B8A8_UNORM,0);
if (HaveExtraColorBuffer) {
::MessageBox(NULL, L"DrawSurface_SetSize: The final draw surface may not have an extra color buffer.", L"Error!", NULL);
}
}
Surface->HaveExtraColorBuffer = HaveExtraColorBuffer;
// Color buffer
D3D11_TEXTURE2D_DESC TextureDescription = {
NewWidth,//UINT Width;
NewHeight,//UINT Height;
1,//UINT MipLevels;
1,//UINT ArraySize;
DXGI_FORMAT_R32G32B32A32_FLOAT,//DXGI_FORMAT Format;
1, 0,//DXGI_SAMPLE_DESC SampleDesc;
D3D11_USAGE_DEFAULT,//D3D11_USAGE Usage;
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,//UINT BindFlags;
0,//UINT CPUAccessFlags;
0//UINT MiscFlags;
};
// Color buffer
m_pd3dDevice->CreateTexture2D( &TextureDescription, NULL, &Surface->OriginalColorBuffer );
// Extra color buffer
if (HaveExtraColorBuffer) {
m_pd3dDevice->CreateTexture2D( &TextureDescription, NULL, &Surface->ExtraColorBuffer );
}
// CPU Access buffer
D3D11_TEXTURE2D_DESC StagedDesc = {
1,//UINT Width;
1,//UINT Height;
1,//UINT MipLevels;
1,//UINT ArraySize;
DXGI_FORMAT_R32G32B32A32_FLOAT,//DXGI_FORMAT Format;
1, 0,//DXGI_SAMPLE_DESC SampleDesc;
D3D11_USAGE_STAGING,//D3D11_USAGE Usage;
0,//UINT BindFlags;
D3D11_CPU_ACCESS_READ,//UINT CPUAccessFlags;
0//UINT MiscFlags;
};
m_pd3dDevice->CreateTexture2D( &StagedDesc, NULL, &Surface->CPUAccessBuffer );
// Color output
D3D11_SHADER_RESOURCE_VIEW_DESC TextureOutputDescription = { TextureDescription.Format, D3D11_SRV_DIMENSION_TEXTURE2D, 0, 0 };
TextureOutputDescription.Texture2D.MipLevels = 1;
m_pd3dDevice->CreateShaderResourceView( Surface->OriginalColorBuffer, &TextureOutputDescription, &Surface->OriginalColorOutput );
if (HaveExtraColorBuffer) { // Extra surface
m_pd3dDevice->CreateShaderResourceView( Surface->ExtraColorBuffer, &TextureOutputDescription, &Surface->ExtraColorOutput );
}
// Color input
if (FinalSurface) {
ID3D11Texture2D* pBackBuffer = NULL;
m_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
m_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &Surface->OriginalColorInput );
pBackBuffer->Release();
} else {
D3D11_RENDER_TARGET_VIEW_DESC TextureInputDescription;
TextureInputDescription.Format = TextureDescription.Format;
TextureInputDescription.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
TextureInputDescription.Texture2D.MipSlice = 0;
m_pd3dDevice->CreateRenderTargetView(Surface->OriginalColorBuffer, &TextureInputDescription, &Surface->OriginalColorInput );
if (HaveExtraColorBuffer) { // Extra surface
m_pd3dDevice->CreateRenderTargetView(Surface->ExtraColorBuffer, &TextureInputDescription, &Surface->ExtraColorInput );
}
}
DrawSurface_SetSwapState(Surface,false);
Surface->HaveDepthBuffer = HaveDepthBuffer;
if (HaveDepthBuffer) {
// Depth buffer
D3D11_TEXTURE2D_DESC DepthTextureDescription = TextureDescription;
DepthTextureDescription.Format = DXGI_FORMAT_R32_TYPELESS;
DepthTextureDescription.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
m_pd3dDevice->CreateTexture2D( &DepthTextureDescription, NULL, &Surface->DepthBuffer );
// Depth I/O
D3D11_DEPTH_STENCIL_VIEW_DESC DepthIODescription = {
DXGI_FORMAT_D32_FLOAT,
D3D11_DSV_DIMENSION_TEXTURE2D,
0
};
m_pd3dDevice->CreateDepthStencilView( Surface->DepthBuffer, &DepthIODescription, &Surface->DepthInputAndOutput );
}
}
}
Are you sure your texture contains the correct information?
Use PIX to confirm that the buffer isn't full of zeroes unless you're already drawing the buffer, and put a break-point before CopySubresourceRegion and check the values, so you're not copying from ExtraColorBuffer when you want to copy from the other one or something like that.
I don't see anything wrong with your code at a glance, but I can't say for certain. The method should definitely work however, what feature level are you running on?
Use PIX to confirm that the buffer isn't full of zeroes unless you're already drawing the buffer, and put a break-point before CopySubresourceRegion and check the values, so you're not copying from ExtraColorBuffer when you want to copy from the other one or something like that.
I don't see anything wrong with your code at a glance, but I can't say for certain. The method should definitely work however, what feature level are you running on?
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement