rgb32 data resource mapping. using directx  memcpy

상훈 김
상훈 김 used Ask the Experts™
on
I have been trying to solve the problem for a month with googling. But Now I have to ask for help here.

I want to render using ffmpeg decoded frame. and using frame, I try to render frame with DX2D texture.

ZeroMemory(&TextureDesc, sizeof(TextureDesc));

TextureDesc.Height = pFrame->height;
TextureDesc.Width = pFrame->width;
TextureDesc.MipLevels = 1;
TextureDesc.ArraySize = 1;
TextureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;            //size 16
TextureDesc.SampleDesc.Count = 1;
TextureDesc.SampleDesc.Quality = 0;
TextureDesc.Usage = D3D11_USAGE_DYNAMIC;
TextureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
TextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
TextureDesc.MiscFlags = 0;

result = m_device->CreateTexture2D(&TextureDesc, NULL, &m_2DTex);
if (FAILED(result))     return false;

ShaderResourceViewDesc.Format = TextureDesc.Format;
ShaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
ShaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
ShaderResourceViewDesc.Texture2D.MipLevels = 1;

    D3D11_MAPPED_SUBRESOURCE S_mappedResource_tt = { 0, };

ZeroMemory(&S_mappedResource_tt, sizeof(D3D11_MAPPED_SUBRESOURCE));

result = m_deviceContext->Map(m_2DTex, 0, D3D11_MAP_WRITE_DISCARD, 0, &S_mappedResource_tt);
if (FAILED(result)) return false;
BYTE* mappedData = reinterpret_cast<BYTE *>(S_mappedResource_tt.pData);
for (auto i = 0; i < pFrame->height; ++i) {
    memcpy(mappedData, pFrame->data, pFrame->linesize[0]);
    mappedData += S_mappedResource_tt.RowPitch;
    pFrame->data[0] += pFrame->linesize[0];
}

m_deviceContext->Unmap(m_2DTex, 0);

result = m_device->CreateShaderResourceView(m_2DTex, &ShaderResourceViewDesc, &m_ShaderResourceView);
if (FAILED(result))     return false;

    m_deviceContext->PSSetShaderResources(0, 1, &m_ShaderResourceView);

Open in new window

but it shows me just black screen(nothing render). I guess it's wrong memcpy size. The biggest problem is that I don't know what is the problem.

Question 1 : It has any problem creating 2D texture for mapping?

Question 2 : What size of the memcpy parameters should I enter (related to formatting)?

I based on the link below.

https://www.gamedev.net/forums/topic/667097-copy-2d-array-into-texture2d/ 
https://www.gamedev.net/forums/topic/645514-directx-11-maping-id3d11texture2d/ 
https://www.gamedev.net/forums/topic/606100-solved-dx11-updating-texture-data/

Thank U for watching, Please reply.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Top Expert 2016

Commented:
it is difficult from your code snippet to detect errors.
(A)
D3D11_MAPPED_SUBRESOURCE S_mappedResource_tt = { 0, };

Open in new window


the D3D11_MAPPED_SUBRESOURCE is a structure of size 'sizeof(D3D11_MAPPED_SUBRESOURCE)'. the statement makes all bytes zero what should be a valid initialization for all members of the structure.  

(B)
ZeroMemory(&S_mappedResource_tt, sizeof(D3D11_MAPPED_SUBRESOURCE));

Open in new window


because of (A) already sets all zero, the statement (B) doesn't change anything and should be removed. it would be different if the structure variable would be used in a for loop or while loop what is not the case in your code.

(C)
result = m_deviceContext->Map(m_2DTex, 0, D3D11_MAP_WRITE_DISCARD, 0, &S_mappedResource_tt);
if (FAILED(result)) return false;

Open in new window


this statement should get the resource (image) from a map shich is a member of your current device context. if should return a failed result if the 'm_2DTex' key wasn't found in the map. the 'D3D11_MAP_WRITE_DISCARD' has the following meaning:

Resource is mapped for writing; the previous contents of the resource will be undefined. The resource must have been created with write access and dynamic usage (See D3D11_CPU_ACCESS_WRITE and D3D11_USAGE_DYNAMIC).

anyway, if it returned without failed return code, the structure  S_mappedResource_tt  passed by pointer should be properly filled.

(D)
BYTE* mappedData = reinterpret_cast<BYTE *>(S_mappedResource_tt.pData);

Open in new window

this cast would define a pointer to the structure such that it could be used as a byte array (buffer). the pointer now can be incremented by byte counts. so if you do 'mappedData += 5' the pointer would point to the sixth byte within the buffer if it has pointed to the begin before.

(E)
for (auto i = 0; i < pFrame->height; ++i) {

Open in new window


the i counter would count the rows of the texture.

note, pFrame was not defined in your snippet, but as you defined texture width and texture height from pFrame->width and pFrame-height, things looked ok.

(F)
memcpy(mappedData, pFrame->data, pFrame->linesize[0]);

Open in new window


what is pFrame->linesize[0]? it was not used to create the texture. instead pFrame->width was used. as pFrame->linesize[0] is the row size in bytes, you may check if pFrame->linesize[0] is calculated by pFrame->width times 'cellsize'  where 'cellsize' is the size of the unit in bytes counted by pFrame->width.

the memcpy copies bytes from right buffer to left buffer. in your case it copies from frame to resource what seems to me is the wrong direction. if you want the pFrame to be filled with data from the map, you have to use

memcpy(pFrame->data, mappedData, pFrame->linesize[0]);

Open in new window


and it is clear that the pFrame can't be rendered if you wanted to do that because it was not filled with any data.

(G)
mappedData += S_mappedResource_tt.RowPitch;

Open in new window


now you were using a member of the resource structure what is explained as 'row pitch' or 'width' of the 'data' in bytes.
the statement looks fine as it was explained in the docs by


    pData points to row 0 and depth slice 0.
    RowPitch contains the value that the runtime adds to pData to move from row to row, where each row contains multiple pixels.
    DepthPitch contains the value that the runtime adds to pData to move from depth slice to depth slice, where each depth slice contains multiple rows.

(I)
pFrame->data[0] += pFrame->linesize[0];

Open in new window


this is a bad mistake again. you are incrementing the value of pFrame->data[0] what is the first byte of pFrameData. because of that only the first row of pFrame would get data (if the memcpy would have ben correct).

to make it right, you need an extra pointer which initially points to pFrame->data. then this pointer must be incremented by linesize[0] (or linesize[ i ], if the array is well set. you may use linesize[0] if all lines have same size).




BYTE* mappedData = reinterpret_cast<BYTE *>(S_mappedResource_tt.pData);
BYTE * pFrameData = pFrame->data;   // now we have a pointer that points to begin of the destination buffer
for (auto i = 0; i < pFrame->height; ++i) {
    memcpy(pFrameData, mappedData, pFrame->linesize[0]);  // copy from right to left buffer
    mappedData += S_mappedResource_tt.RowPitch;
    pFrameData += pFrame->linesize[0];
}

Open in new window


Sara

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial