Manually copying texture data from a loaded image

Started by
8 comments, last by MJP 8 years, 1 month ago

I was building a simple D3D12 app which load and display an image on screen.

As you are aware, D3D12 has no calls like CreateTexture2D which we have in D3D11 so that this process has to be done in the hard way.
So far I've loaded the image in memory using WIC with DXGI_FORMAT_R8G8B8A8_UNORM and got its width and height.

Created a 2D array to store the pixels.


BYTE ** pixels = new BYTE*[height];
for (int i = 0; i < height; i++) {
pixels[i] = new BYTE[width * 4];
}

Use CopyPixels to copy the pixels to the new array


UINT stride = width * 4;
hr = pSource->CopyPixels(nullptr, stride, (sizeof(BYTE)*4*height*width), *pixels);

Note : I'm getting 0x88982f8c: insufficient buffer allocation here!

My aim is to get the texture data so that I can copy it to the upload buffer.
For that I'm extracting the texture dat as follows,


D3D12_SUBRESOURCE_FOOTPRINT srFtprint;
srFtprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srFtprint.Depth = 1; // 0 or 1?
srFtprint.Width = width;
srFtprint.Height = height;
srFtprint.RowPitch = rowPitch;

D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedTexture2D = { 0 };
placedTexture2D.Offset = 0;
placedTexture2D.Footprint = srFtprint;

UINT8 * pScan;
for (UINT y = 0; y < height; y++)
{
pScan = m_pDataBegin + placedTexture2D.Offset // Now pScan stores the texture data
+ y * srFtprint.RowPitch;
memcpy(pScan, &(pixels[y * width]),
sizeof(BYTE) * width);
}

I'm unable to accomplish this correctly because I think I'm not able to create/copy the exact number of bytes in the same expected alignment.

Advertisement
pixels is not contiguous in memory; you have it as an array of pointers to rows.
Make it a single contiguous allocation.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

pixels is not contiguous in memory; you have it as an array of pointers to rows.
Make it a single contiguous allocation.


L. Spiro

Thanks I made it like this : BYTE *pixels = new BYTE(height*width);

And do you think my stride calculation is correct?

I changed the code to use this formula for stride: stride = ((((biWidth * biBitCount) + 31) & ~31) >> 3) from msdn

I'm not sure about biBitCount. Is it 32/8 = 4 if the bpp is 32?

If the bits-per-pixel (BPP) is 32 then biBitCount is 32.
Your new calculation for stride is correct.

BYTE *pixels = new BYTE(height*width); is not correct. It should be BYTE *pixels = new BYTE(height*stride);.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

You're not supposed to fill out D3D12_SUBRESOURCE_FOOTPRINT and D3D12_PLACED_SUBRESOURCE_FOOTPRINT. You need to fill out your D3D12_RESOURCE_DESC for the 2D texture that you want to create, and then pass that to ID3D12Device::GetCopyableFootprints in order to get the array of footprints for each subresource. You can then use the footprints to fill in an UPLOAD buffer, and then use CopyTextureRegion to copy the subresources from your upload buffer to the actual 2D texture resource in a DEFAULT heap.

You may want to look at the HelloTexture sample on GitHub to use as a reference.

EDIT: actually you don't strictly need to use GetCopyableFootprints, see Brian's post below

You're not supposed to fill out D3D12_SUBRESOURCE_FOOTPRINT and D3D12_PLACED_SUBRESOURCE_FOOTPRINT. You need to fill out your D3D12_RESOURCE_DESC for the 2D texture that you want to create, and then pass that to ID3D12Device::GetCopyableFootprints in order to get the array of footprints for each subresource. You can then use the footprints to fill in an UPLOAD buffer, and then use CopyTextureRegion to copy the subresources from your upload buffer to the actual 2D texture resource in a DEFAULT heap.

You may want to look at the HelloTexture sample on GitHub to use as a reference.

Thanks a lot pointing out that smile.png BTW your D3D11 book is awesome. Any plans on making one for D3D12? It's quite challenging to learn D3D12 only from msdn pages..

Thank you! No plans for D3D12 book at a moment.

Hi MJP,

Minor clarification here:


You're not supposed to fill out D3D12_SUBRESOURCE_FOOTPRINT and D3D12_PLACED_SUBRESOURCE_FOOTPRINT

Apps can fill out these footprint structures themselves, but they must follow the documented alignment restrictions. The samples use GetCopyableFootprints, because its conciseness avoids distracting from the sample's true intention. Apps should take care to avoid GetCopyableFootprints from becoming a bottleneck. Once the restrictions are understood, applications can simplify the logic to fill out these structures. As an example, planar complications could be avoided, and the structure data could even be baked to disk.

-Brian Klamik

Thank you for pointing that out Brian!

This topic is closed to new replies.

Advertisement