1
votes

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.

1
Have you got example C++ code that succeeds in doing this?David Heffernan
No, I have not tryed this with C++. But I have other Delphi code similar to this one which is working perfectly. Please note that I'm using a D3D11.pas file which I have CreateBuffer fixed (See RSP-25524). But you are right, maybe there is another bug in D3D11.pas and I should write C code to be sure.fpiette
@DavidHeffernan I have checked C++ code and got same error. The code I used to check is from users.skynet.be/fquake/MandelDX11.zip. I added my call to CreateBuffer just before the original CreateBuffer call (Which has different purpose and hence different Desc argument.fpiette
My advice to you is that you are likely to get better interest in questions here if the code is in C++. Even if in the long run you want delphi code, you are likely to find more experience here if the code is written in c++.David Heffernan
@DavidHeffernan I created a new request using C++: stackoverflow.com/questions/57376813/…fpiette

1 Answers

1
votes

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).