0
votes

I was reading an MSDN documentation for Memory Management in Direct3D, titled "Uploading Texture Data Through Buffers". I'm wondering how this piece of code (below) can copy texture data from a bitmap source to a buffer, and also what is the pixels method of pBitmap, I tried to search for it, but couldn't find.

// Copy texture data from pBitmap to the buffer. //

for (UINT y = 0; y < pitchedDesc.Height; y++)
{
    UINT8 *pScan = m_pDataBegin + placedTexture2D.Offset 
                   + y * pitchedDesc.RowPitch;
    memcpy( pScan, &(pBitmap->pixels[y * pitchedDesc.Width]), 
        sizeof(DWORD) * pitchedDesc.Width );
}
1

1 Answers

1
votes

The MSDN page tells you at the top:

// Prepare a pBitmap in memory, with bitmapWidth, bitmapHeight, and pixel format of DXGI_FORMAT_B8G8R8A8_UNORM. 

It's just a generic 2D array of 32-bit pixels. Where it comes from is not covered on MSDN at all.

The code is a bit confusing because it would only work if pBitmap->pixels is itself a DWORD array--this is implied because the comment above states is a DXGI_FORMAT_B8G8R8A8_UNORM format which is a 32-bit per pixel format. The code is also copying more data than you necessarily have in the pixels array unless it is exactly aligned to the same pitch as D3D12 is using.

A more clear & correct code snippet would be:

//
// Copy texture data from DWORD* pBitmap->pixels to the buffer
//

for (UINT y = 0; y < bitmapHeight; y++)
{
    UINT8 *pScan = m_pDataBegin + placedTexture2D.Offset 
                   + y * pitchedDesc.RowPitch;
    memcpy( pScan, &(pBitmap->pixels[y * bitmapWidth]), 
        sizeof(DWORD) * bitmapWidth );
}

If you are having difficulty with this code, then you should really rethink if you are ready for Direct3D 12. Maybe you should stick with Direct3D 11 for now. See this thread

Typically image readers will return the pixel data in a simple packed array without any special pitch alignment (the default is usually byte aligned). Direct3D lays out resources using some more specific aligned pitch which can change from driver to driver, which varies by resource type and format. It might be byte aligned, 4-byte aligned, 16-byte aligned, 64-byte aligned or something else entirely. Therefore, the only robust way to do the copy is to do it "row-by-row" where the destination is determined by the requested row pitch, and the source pitch is usually equal to or smaller than the aligned pitch.

Generically something like:

const uint8_t* sptr = reinterpret_cast<const uint8_t*>( srcImage.pixels );
auto dptr = reinterpret_cast<uint8_t*>( destImage.pixels );

size_t spitch = srcImage.rowPitch;
size_t dpitch = destImage.rowPitch;

size_t size = std::min<size_t>( dpitch, spitch );

for( size_t y = 0; y < height; ++y )
{
    memcpy_s( dptr, dpitch, sptr, size );
    sptr += spitch;
    dptr += dpitch;
}

You can find loads of this kind of 'row-by-row' pixel manipulation code in DirectXTex.