Reputation: 67
I am trying to convert every frame of my DirectX program to YUV (for video encoding). Therefore I need the RGB(A) values of each pixel on every frame first. I need to get these from the backbuffer.
Because there is no glReadPixels in DirectX, I do the following:
ID3D10Texture2D
CopyResource
the texture2D from the previous step.At this point I can use D3DX10SaveTextureToFile
and this staging texture will correctly save the backbuffer as an image.
However, I don't want to use the disk as a detour, I want to get the RGB data right away, so I do the following:
The problem: the RGB values are rubbish. This is an example for pixel (1,1)
(1, 1) = (-170141183460469230000000000000000000000.000000, -170141183460469230000000000000000000000.000000, -170141183460469230000000000000000000000.000000)
This is particularly strange because I use the same code to Map another staging texture (from another offscreen render target) and this code works just fine there.
This is my code:
// Get resource pointer to backbuffer
ID3D10Resource *backbufferRes;
m_D3D->GetRenderTargetView()->GetResource(&backbufferRes);
// Cast backbuffer resource to texture2D
ID3D10Texture2D* tempTexture = 0;
backbufferRes->QueryInterface(__uuidof(ID3D10Texture2D),(LPVOID*) &tempTexture);
backbufferRes->Release();
// Get the descriptor of this texture2D
D3D10_TEXTURE2D_DESC descDefault;
tempTexture->GetDesc(&descDefault);
// Create a staging texture desc based on the texture of the backbuffer
D3D10_TEXTURE2D_DESC descStaging;
descStaging = descDefault;
descStaging.Usage = D3D10_USAGE_STAGING;
descStaging.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
descStaging.BindFlags = 0;
// Create the new empty staging texture
ID3D10Texture2D *texture = 0;
m_D3D->GetDevice()->CreateTexture2D( &descStaging, NULL, &texture);
// Copy the backbuffer texture data (tempTexture) to the staging texture (texture)
m_D3D->GetDevice()->CopyResource(texture, tempTexture);
// This call works perfectly, image is correct!
// D3DX10SaveTextureToFile(texture, D3DX10_IFF_BMP, L"D:\\img.bmp");
// We want to avoid disk access, so instead let's map the texture and read its RGB data
D3D10_MAPPED_TEXTURE2D mappedTexture;
hr = texture->Map(D3D10CalcSubresource(0, 0, 1), D3D10_MAP_READ, 0, &mappedTexture);
FLOAT* m_pBits = (FLOAT*) malloc(4 * descStaging.Width * descStaging.Height * sizeof(FLOAT));
if(!FAILED(hr)) {
memcpy(m_pBits, mappedTexture.pData, 4 * descStaging.Width * descStaging.Height);
texture->Unmap(D3D10CalcSubresource(0, 0, 1));
}
texture->Release();
tempTexture->Release();
fp = fopen("D:\\output.txt", "a");
for( UINT row = 0; row < descStaging.Height; row++ )
{
UINT rowStart = row * mappedTexture.RowPitch / 4;
for( UINT col = 0; col < descStaging.Width; col++ )
{
r = m_pBits[rowStart + col*4 + 0]; // Red (X)
g = m_pBits[rowStart + col*4 + 1]; // Green (Y)
b = m_pBits[rowStart + col*4 + 2]; // Blue (Z)
a = m_pBits[rowStart + col*4 + 3]; // Alpha (W)
// Save pixel values to disk
fprintf(fp, "%d %d - %f %f %f\n", col + 1, row + 1, r, g, b);
}
}
fclose(fp);
Does anyone have an idea on what the problem might be? All help is really appreciated.
Upvotes: 3
Views: 3347
Reputation: 176
Old question, but I think this might be the problem:
After you map the texture with texture->Map()
, you try to copy it across into m_pBits
all in one go. This won't work unless the RowPitch of the mapped texture is the same as its width (see here).
Instead, you must copy across the image row-by-row:
BYTE* source = static_cast<BYTE*>(mappedTexture.pData);
BYTE& dest = m_pBits;
for (int i = 0; i < IMAGE_HEIGHT; ++i) {
memcpy(dest, source, IMAGE_WIDTH * 4); // for 4 bytes per pixel
source += mappedTexture.RowPitch;
dest += IMAGE_WIDTH * 4;
}
Upvotes: 2