Jump to content
  • Advertisement
Sign in to follow this  
Blue Goose

DX12 Using typed buffers with the compute shader

This topic is 793 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been using Introduction to 3D Programming by Frank Luna to introduce myself to graphics programming. In the compute shader chapter exercises, we're asked to make a program to input 64 vectors and output their magnitudes. This was simple enough, however the second question asks us to do the same thing except this time using typed instead of structured buffers. Up to this point, there hasn't been much discussion about typed buffers so I may be missing some simple change that needs to be made, but after switching from structured to typed buffers, my output is incorrect.


Here is the shader I'm using:
      Buffer gInput : register(b0);
      RWBuffer gOutput : register(u1);

    [numthreads(64, 1, 1)]
      void CS(int3 dtid : SV_DispatchThreadID)
      {
       gOutput[dtid.x] = sqrt((gInput[dtid.x].x * gInput[dtid.x].x)
        + (gInput[dtid.x].y * gInput[dtid.x].y)
        + (gInput[dtid.x].z * gInput[dtid.x].z));
      }
       


Here are my buffer declarations:

 void VecAddCSApp::BuildBuffers()
 {
   // Generate some data.
   std::vector data(NumDataElements);
   srand(clock());
   for(int i = 0; i < NumDataElements; ++i)
   {
     //Spherical coordinates will allow us to randomize direction
     //And randomize magnitude between 1-10.
     float r = float(rand() % 10 + 1);
     float phi = (rand() % 90 + 1) * XM_PI / 180;
     float theta = (rand() % 360 + 1) * XM_PI / 180;

     data[i] = XMFLOAT3(r*sinf(theta)*cosf(phi), r * cosf(theta), r*sinf(theta)*sinf(phi));
        mData.push_back(data[i]);
   }

    UINT64 byteSize = data.size() * sizeof(XMFLOAT3);

    // Create some buffers to be used as SRVs.
    mInputBuffer = d3dUtil::CreateDefaultBuffer(
        md3dDevice.Get(),
        mCommandList.Get(),
        data.data(),
        byteSize,
        mInputUploadBuffer);

    // Create the buffer that will be a UAV.
    ThrowIfFailed(md3dDevice->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(NumDataElements*sizeof(float), D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS),
        D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
        nullptr,
        IID_PPV_ARGS(&mOutputBuffer)));

    ThrowIfFailed(md3dDevice->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(NumDataElements*sizeof(float)),
        D3D12_RESOURCE_STATE_COPY_DEST,
        nullptr,
        IID_PPV_ARGS(&mReadBackBuffer)));
      }
      


And Root signature:
void VecAddCSApp::BuildRootSignature()
{
 // Root parameter can be a table, root descriptor or root constants.
 CD3DX12_ROOT_PARAMETER slotRootParameter[2];

 // Perfomance TIP: Order from most frequent to least frequent.
 slotRootParameter[0].InitAsShaderResourceView(0);
 slotRootParameter[1].InitAsUnorderedAccessView(0);

 // A root signature is an array of root parameters.
 CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(2, slotRootParameter,
    0, nullptr,
    D3D12_ROOT_SIGNATURE_FLAG_NONE);

 ComPtr serializedRootSig = nullptr;
 ComPtr errorBlob = nullptr;
 HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
    serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());

 if(errorBlob != nullptr)
    {
     ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
    }
 ThrowIfFailed(hr);

 ThrowIfFailed(md3dDevice->CreateRootSignature(
    0,
    serializedRootSig->GetBufferPointer(),
    serializedRootSig->GetBufferSize(),
    IID_PPV_ARGS(mRootSignature.GetAddressOf())));
}


The command list:

     // Reuse the memory associated with command recording.
     // We can only reset when the associated command lists have finished execution on the GPU.
    ThrowIfFailed(mDirectCmdListAlloc->Reset());

    // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
    // Reusing the command list reuses memory.
    ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), mPSOs["vectorMag"].Get()));

    mCommandList->SetComputeRootSignature(mRootSignature.Get());
   
    mCommandList->SetComputeRootShaderResourceView(0, mInputBuffer->GetGPUVirtualAddress());
    mCommandList->SetComputeRootUnorderedAccessView(1, mOutputBuffer->GetGPUVirtualAddress());

    mCommandList->Dispatch(64, 1, 1);

    // Schedule to copy the data to the default buffer to the readback buffer.
    mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mOutputBuffer.Get(),
        D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_SOURCE));

    mCommandList->CopyResource(mReadBackBuffer.Get(), mOutputBuffer.Get());

    mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(mOutputBuffer.Get(),
        D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_COMMON));

    // Done recording commands.
    ThrowIfFailed(mCommandList->Close());

      
      

    // Add the command list to the queue for execution.
    ID3D12CommandList* cmdsLists[] = {mCommandList.Get()};
       mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

    // Wait for the work to finish.
    FlushCommandQueue();

    // Map the data so we can read it on CPU.
    FLOAT* radiusData = nullptr;
    ThrowIfFailed(mReadBackBuffer->Map(0, nullptr, reinterpret_cast(&radiusData)));

    std::ofstream fout("results.txt");

    for(int i = 0; i < NumDataElements; ++i)
       {
        fout << "(" << mData[i].x << ", " << mData[i].y << ", " << mData[i].z <<
         " Magnitude = "<< radiusData[i] << " Real Magnitude = " << sqrt((mData[i].x * mData[i].x)
         + (mData[i].y * mData[i].y) + (mData[i].z * mData[i].z)) << " )" << std::endl;
       }

    mReadBackBuffer->Unmap(0, nullptr);
      

Finally, an example output:


(-5.50813, -3.50697, -4.62187 Magnitude = -5.50813 Real Magnitude = 8 )
  (5.79389, -5.45599, 0.814278 Magnitude = -3.50697 Real Magnitude = 8 )
  (0.789096, 0.716736, 1.69222 Magnitude = -4.62187 Real Magnitude = 2 )
  (0.747479, -3.91259, 0.36457 Magnitude = 8 Real Magnitude = 4 )
  (-1.46659e-07, -3, -2.1743e-07 Magnitude = -5.45599 Real Magnitude = 3 )
  (6.90184, 4, 0.603833 Magnitude = 0.814278 Real Magnitude = 8 )
  (-0.076552, 1.364, -1.4607 Magnitude = 0.789096 Real Magnitude = 2 )
  (-0.620317, 2.93444, -0.0651979 Magnitude = 5.57257 Real Magnitude = 3 )
  (8.59365, -3.58368, 3.64779 Magnitude = 1.69222 Real Magnitude = 10 )
  (-2.34608, -2.62424, -1.89982 Magnitude = 0.747479 Real Magnitude = 4 )
  (0.261428, -0.0523574, 2.98813 Magnitude = -3.91259 Real Magnitude = 3 )
  (1.52366, 9.13545, 3.7712 Magnitude = 4.3279 Real Magnitude = 10 )
  (0.766105, 6.87139, 1.09411 Magnitude = -1.46659e-07 Real Magnitude = 7 )
  (-0.899552, -0.121869, -0.419468 Magnitude = -3 Real Magnitude = 1 )
  (2.26752, 3.91435, 5.34193 Magnitude = -2.1743e-07 Real Magnitude = 7 )
  (-1.69119, 1.56284, -8.70043 Magnitude = 3 Real Magnitude = 9 )
  (-0.233754, -0.961262, -0.146066 Magnitude = 4 Real Magnitude = 1 )
  (-1.38741, 0.104672, -1.43671 Magnitude = 0.603833 Real Magnitude = 2 )
  (1.82593, -1.04189, 5.61965 Magnitude = -0.076552 Real Magnitude = 6 )
  (-1.2194, 1.79961, -7.69899 Magnitude = 4.04604 Real Magnitude = 8 )
  (-0.392427, 6.53506, -2.47769 Magnitude = -1.4607 Real Magnitude = 7 )
  (-1.22947, 4.60253, -1.51827 Magnitude = -0.620317 Real Magnitude = 5 )
  (1.47912, -3.25568, 9.33878 Magnitude = 2.93444 Real Magnitude = 10 )
  (-2.96151, 8.22191, -2.15166 Magnitude = 3.33608 Real Magnitude = 9 )
  (7.91732, 1.11338, 0.276479 Magnitude = 8.59365 Real Magnitude = 8 )
  (0.585262, 9.70296, 2.34736 Magnitude = -3.58368 Real Magnitude = 10 )
  (-1.33538, 3.70944, -5.78419 Magnitude = 3.64779 Real Magnitude = 7 )
  (2.53683, 6.39482, 1.29258 Magnitude = 10 Real Magnitude = 7 )
  (-0.0994007, 2.94488, -0.56373 Magnitude = -2.62424 Real Magnitude = 3 )
  (0.179783, -0.669131, 0.72107 Magnitude = -1.89982 Real Magnitude = 1 )
  (0.445332, -3.97018, 0.198275 Magnitude = 0.261428 Real Magnitude = 4 )
  (-2.84828, 0.469304, -0.816731 Magnitude = 3.25027 Real Magnitude = 3 )
  (-7.33189e-08, -1.08928, 1.67734 Magnitude = 2.98813 Real Magnitude = 2 )
  (0.677366, 1.72073, 2.36226 Magnitude = 1.52366 Real Magnitude = 3 )
  (-0.103008, 1.81262, -0.838936 Magnitude = 9.13545 Real Magnitude = 2 )
  (-1.33241, 6.87139, -0.093171 Magnitude = 9.73175 Real Magnitude = 7 )
  (-2.06838, -1.22021, -1.79802 Magnitude = 0.766105 Real Magnitude = 3 )
  (2.14183, 3.21394, 3.1754 Magnitude = 6.87139 Real Magnitude = 5 )
  (-1.30389, -1.38932, -0.608012 Magnitude = 1.09411 Real Magnitude = 2 )
  (0.0145142, 3.99939, 0.0682841 Magnitude = 7 Real Magnitude = 4 )
  (5.34965, -7.18772, 0.847301 Magnitude = -0.121869 Real Magnitude = 9 )
  (-0.153639, -1.8712, -8.80199 Magnitude = -0.419468 Real Magnitude = 9 )
  (-3.32725, -1.23607, -1.84433 Magnitude = 2.26752 Real Magnitude = 4 )
  (5.05645, 4.77399, 0.800863 Magnitude = 2.30921 Real Magnitude = 7 )
  (2.55447, 7.46864, 1.30157 Magnitude = 5.34193 Real Magnitude = 8 )
  (1.18966, -4.16795, 4.14884 Magnitude = -1.69119 Real Magnitude = 6 )
  (-3.70672, 0.899805, -1.20439 Magnitude = 1.56284 Real Magnitude = 4 )
  (0.805886, 9.61262, 2.63593 Magnitude = 5.81711 Real Magnitude = 10 )
  (-0.746079, 7.63243, -4.71056 Magnitude = -0.233754 Real Magnitude = 9 )
  (-6.79612, -5.41634, -2.34009 Magnitude = -0.961262 Real Magnitude = 9 )
  (0.7241, -5.95528, 0.101766 Magnitude = -0.146066 Real Magnitude = 6 )
  (0.321241, -4.75528, 1.51132 Magnitude = 1 Real Magnitude = 5 )
  (2.68116, 2.95833, 5.74976 Magnitude = 0.104672 Real Magnitude = 7 )
  (-1.20059, -4.85148, -0.147414 Magnitude = -1.43671 Real Magnitude = 5 )
  (-2.67924, 6.00017, -2.41239 Magnitude = 1.82593 Real Magnitude = 7 )
  (0.348739, 1.08928, 1.64069 Magnitude = 2.32575 Real Magnitude = 2 )
  (-0.113535, -2.96306, -0.455364 Magnitude = 5.61965 Real Magnitude = 3 )
  (-0.169315, -1.98509, -0.175331 Magnitude = -1.2194 Real Magnitude = 2 )
  (7.58217, -2.93011, 3.86331 Magnitude = 1.79961 Real Magnitude = 9 )
  (-3.4559, 1.10255, -1.68556 Magnitude = 6.02544 Real Magnitude = 4 )
  (1.04636, -7.46134, 4.92276 Magnitude = -0.392427 Real Magnitude = 9 )
  (-2.53412, 3.34565, -2.71751 Magnitude = 6.53506 Real Magnitude = 5 )
  (0.00364799, 0.999391, 0.0347083 Magnitude = -2.47769 Real Magnitude = 1 )
  (-8.56645, -5.15038, -0.299147 Magnitude = 7 Real Magnitude = 10 )

Looking at the output, you can see that instead of simply writing the computed magnitude to the output texture, its actually writing every vector component and occasionally overwriting one with the output. Why is this happening? Any help is appreciated.

Share this post


Link to post
Share on other sites
Advertisement

Buffer and RWBuffer are arrays of XMFLOAT4 (so to speak). You treat gInput as array of XMLFLOAT3, and gOutput as array of float.

 

You can change definitions of gInput and gOutput to match provided data by using StructuredBuffer and RWStructuredBuffer:

      StructuredBuffer<float3> gInput : register(b0);
      RWStructuredBuffer<float> gOutput : register(u1);

Share this post


Link to post
Share on other sites

Buffer and RWBuffer are arrays of XMFLOAT4 (so to speak). You treat gInput as array of XMLFLOAT3, and gOutput as array of float.
&nbsp;
You can change definitions of gInput and gOutput to match provided data by using StructuredBuffer and RWStructuredBuffer:

StructuredBuffer&lt;float3&gt; gInput : register(b0);      RWStructuredBuffer&lt;float&gt; gOutput : register(u1);

So if I'm understanding you, a Buffer type will always be a 4 dimensional vector? Even if I typecast it to a float?

Interesting. The book advised me to typecast the buffers to float3 and float respectively. Perhaps its outdated however, since the book has had other mistakes.

Thanks for the info.

Edited by Blue Goose

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!