Search code examples
directxdirectx-11

DirectX 11 ID3DDevice::CreateTexture2D with initial data fail


so long I follow a tutorial that CreateTexture2D() with NULL initial data, then using UpdateSubresource() to load data,every thing works fine. But UpdateSubResource() is a device context function, so I try to use CreateTexture2D() with initial data in one shot,but it fail.

below code show the original that works fine.

tex_desc.Height = h;
tex_desc.Width = w;
tex_desc.MipLevels = 0;
tex_desc.ArraySize = 1;
tex_desc.Format= DXGI_FORMAT_R8G8B8A8_UNORM;
tex_desc.SampleDesc.Count = 1;
tex_desc.SampleDesc.Quality = 0;
tex_desc.Usage= D3D11_USAGE_DEFAULT;
tex_desc.BindFlags= D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET;
tex_desc.CPUAccessFlags= 0;
tex_desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;

row_pitch = (w * 4) * sizeof(unsigned char);
hres = _dv->CreateTexture2D(&tex_desc, NULL, &m_tex);
HR_FAIL(hres,  "create 2D texture");

_dc->UpdateSubresource(m_tex, 0, NULL, data, row_pitch, 0);

then I change it to

tex_desc.Height = h;
tex_desc.Width = w;
tex_desc.MipLevels = 0;
tex_desc.ArraySize = 1;
tex_desc.Format= DXGI_FORMAT_R8G8B8A8_UNORM;
tex_desc.SampleDesc.Count = 1;
tex_desc.SampleDesc.Quality = 0;
tex_desc.Usage= D3D11_USAGE_DEFAULT;
tex_desc.BindFlags= D3D11_BIND_SHADER_RESOURCE|D3D11_BIND_RENDER_TARGET;
tex_desc.CPUAccessFlags= 0;
tex_desc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;

row_pitch = (w * 4) * sizeof(unsigned char);

D3D11_SUBRESOURCE_DATA sdata;            // <<===changed
sdata.pSysMem = data;                  // <<===changed
sdata.SysMemPitch = row_pitch;                 // <<===changed
sdata.SysMemSlicePitch = (w*h*4)*sizeof(unsigned char);       // <<===changed
hres = _dv->CreateTexture2D(&tex_desc, &sdata, &m_tex);       // <<===changed
HR_FAIL(hres, "testing create texture 2d");

then it generate the error

testing create texture 2d fail
E_INVALIDARG : An invalid parameter was passed to the returning function.

it said some parameter is invalid but I don't see why the argument i passed is invalid


UPDATE:
so I try to follow the links to setup debug device for DirectX . Here's what I got:

D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[4].SysMemPitch cannot be 0 [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[6].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[7].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: Returning E_INVALIDARG, meaning invalid parameters were passed. [ STATE_CREATION ERROR #104: CREATETEXTURE2D_INVALIDARG_RETURN]
Exception thrown at 0x750BC54F in directx11_test.exe: Microsoft C++ exception: _com_error at memory location 0x002BF3D0.
D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[2].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[4].SysMemPitch cannot be 0 [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[6].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: pInitialData[7].pSysMem cannot be NULL. [ STATE_CREATION ERROR #100: CREATETEXTURE2D_INVALIDINITIALDATA]
D3D11 ERROR: ID3D11Device::CreateTexture2D: Returning E_INVALIDARG, meaning invalid parameters were passed. [ STATE_CREATION ERROR #104: CREATETEXTURE2D_INVALIDARG_RETURN]

so it said that the Create function try to access the InitialData as an array while I only has one element as pass as argument. One thing to notice is that I only get the debug output in release config(I manually define _DEBUG in the code). In Debug config, I get access violation exception trigger so I don't get the D3D Debug Message.

so I get a way to work around it is get an array of subresource big enough to to store all kind of mipmap level to prevent access violation.

D3D11_SUBRESOURCE_DATA sdata[20];
    int idx = 0;
    while (row_pitch > 0)
    {

        sdata[idx].pSysMem = data;
        sdata[idx].SysMemPitch = row_pitch;
        row_pitch >>= 1;
        idx++;
    }

    hres = _dv->CreateTexture2D(&tex_desc, sdata, &m_tex);
    HR_FAIL(hres, "testing create texture 2d");

but I think it's unwise since I still need generate mipmap and this function is in device context


Solution

  • I believe the reason it is failing is that you have requested auto-gen mipmaps (D3D11_RESOURCE_MISC_GENERATE_MIPS) which you can't use initial data to set up. You have to load the top level through the device context instead.

    For a full implementation of auto-gen mipmaps as well as using initData for other scenarios, see WICTextureLoader in the DirectX Tool Kit

    If you used the Direct3D Debug Device it would have provided a lot more detail in the output window when returning E_INVALIDARG.