delphidirectx-11directcompute

DirectX/DirectCompute CreateBuffer failure with error 0x80070057 (E_INVALIDARG)


I'm trying to create a buffer in GPU memory to upload data from CPU. GPU access will be readonly. Data will be used as an input buffer for a compute shader.

CreateBuffer() fails with error 0x80070057 (E_INVALIDARG). I read the docs and read it again without discovering which argument cause the failure.

InitDevice() return success.

Here is an extract from my code:

function TGpuImageControl.InitDevice: HRESULT;
var
    hr                : HRESULT;
    createDeviceFlags : UINT;
    driverTypes       : array [0..0] of D3D_DRIVER_TYPE;
    numDriverTypes    : UINT;
    driverTypeIndex   : UINT;
    sd                : DXGI_SWAP_CHAIN_DESC;
    FeatureLevels     : D3D_FEATURE_LEVEL;
    featureLevel      : D3D_FEATURE_LEVEL;
const
    D3D10_SHADER_DEBUG = 1;
begin
    hr     := S_OK;

    createDeviceFlags := 0;
{$ifdef DEBUG}
    createDeviceFlags := createDeviceFlags or D3D11_CREATE_DEVICE_DEBUG;
{$endif}

{$ifdef WARP}
    driverTypes[0] := D3D_DRIVER_TYPE_REFERENCE;
{$else}
    driverTypes[0] := D3D_DRIVER_TYPE_HARDWARE;
{$endif}
    numDriverTypes := SizeOf(driverTypes) div SizeOf(driverTypes[0]);

    ZeroMemory(@sd, SizeOf(sd));
    sd.BufferCount                        := 1;
    sd.BufferDesc.Width                   := width;
    sd.BufferDesc.Height                  := height;
    sd.BufferDesc.Format                  := DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator   := 60;
    sd.BufferDesc.RefreshRate.Denominator := 1;
    sd.BufferUsage                        := DXGI_USAGE_RENDER_TARGET_OUTPUT or
                                             DXGI_USAGE_UNORDERED_ACCESS;//     or
                                             //DXGI_USAGE_SHADER_INPUT;
    sd.OutputWindow                       := Handle;
    sd.SampleDesc.Count                   := 1;
    sd.SampleDesc.Quality                 := 0;
    sd.Windowed                           := TRUE;
    //sd.Flags                            := DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

    FeatureLevels :=   D3D_FEATURE_LEVEL_11_0;

    for driverTypeIndex := 0 to numDriverTypes do begin
        g_driverType := driverTypes[driverTypeIndex];
        hr := D3D11CreateDeviceAndSwapChain(
                  nil,                    // Graphic Adapter, use default
                  g_driverType,           // Driver type to use
                  0,                      // HModule for software driver
                  createDeviceFlags,      // Create flags
                  @FeatureLevels,         // Feature levels
                  1,                      // Feature level size
                  D3D11_SDK_VERSION,      // SDK Version
                  @sd,                    // Swap Chain descriptor
                  g_pSwapChain,           // Out: Created swap chain
                  g_pd3dDevice,           // Out: Created device
                  featureLevel,           // Out: Feature level
                  g_pImmediateContext);   // Out: Context
        if SUCCEEDED(hr) then
            break;
    end;
    if FAILED(hr) then begin
        Result := hr;
        Exit;
    end;

    ImageResize();

    Result := S_OK;
end;

procedure TGpuImageControl.ImageResize;
var
    hr       : HRESULT;
    sd       : DXGI_SWAP_CHAIN_DESC;
    pTexture : ID3D11Texture2D;
    vp       : D3D11_VIEWPORT;
begin
    if g_pd3dDevice = nil then
        Exit;

    // release first else resize problem
    SAFE_RELEASE(IUnknown(g_pComputeOutput));

    g_pSwapChain.GetDesc(sd);
    hr := g_pSwapChain.ResizeBuffers(sd.BufferCount,
                                     Width,
                                     Height,
                                     sd.BufferDesc.Format,
                                     0);                   // Swap chain flags
    if FAILED(hr) then begin
        ShowError('SwapChain.ResizeBuffers failed with error %d', [hr]);
        Exit;
    end;

    hr := g_pSwapChain.GetBuffer(0, TGUID(ID3D11Texture2D), pTexture);
    if FAILED(hr) then begin
        ShowError('SwapChain.GetBuffer failed with error %d', [hr]);
        Exit;
    end;

    // create shader unordered access view on back buffer for compute shader to write into texture
    hr := g_pd3dDevice.CreateUnorderedAccessView(pTexture,
                                                 nil,
                                                 g_pComputeOutput);
    if FAILED(hr) then begin
        ShowError('pd3dDevice.CreateUnorderedAccessView failed with error %d', [hr]);
        Exit;
    end;

    pTexture := nil;

    // Setup the viewport
    vp.Width    := Width;
    vp.Height   := Height;
    vp.MinDepth := 0.0;
    vp.MaxDepth := 1.0;
    vp.TopLeftX := 0;
    vp.TopLeftY := 0;
    g_pImmediateContext.RSSetViewports(1, @vp);
end;

The code which fails is the following:

function TGpuImageControl.CreateStructuredBuffer(
    uElementSize : UINT;
    uCount       : UINT;
    pInitData    : Pointer;
    out ppBufOut : ID3D11Buffer): HRESULT;
var
    desc     : D3D11_BUFFER_DESC;
    InitData : D3D11_SUBRESOURCE_DATA;
begin
    ppBufOut := nil;

    ZeroMemory(@desc, SizeOf(desc));
    desc.BindFlags           := D3D11_BIND_UNORDERED_ACCESS or
                                D3D11_BIND_SHADER_RESOURCE;
    desc.Usage               := D3D11_USAGE_DYNAMIC;
    desc.CPUAccessFlags      := D3D11_CPU_ACCESS_WRITE;
    desc.ByteWidth           := uElementSize * uCount;
    desc.MiscFlags           := UINT(D3D11_RESOURCE_MISC_BUFFER_STRUCTURED);
    desc.StructureByteStride := uElementSize;

    if pInitData <> nil then begin
        InitData.pSysMem := pInitData;
        Result := g_pd3dDevice.CreateBuffer(desc, @InitData, ppBufOut);
    end
    else
        Result := g_pd3dDevice.CreateBuffer(desc, nil, ppBufOut);
end;

When calling the function, I pass uElementSize=2, uCount=100 and pInitData pointing to an allocated 200 bytes buffer in CPU memory.

I don't understand what I'm doing wrong. Any help appreciated.


Solution

  • The answer has been given by Chuck Walbourn to the C++ question I asked there DirectCompute CreateBuffer fails with error 0x80070057 (E_INVALIDARG)

    The most important part to debug this error is simply look at Delphi Event Viewer and just look the error message the API is triggering when debugging is enabled (I I already had enabled debugging but didn't figured that messages where output to the events windows).