🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Structured buffers in DX12

Started by
7 comments, last by MJP 3 years, 6 months ago

Hi people. Happy new year to everyone!

I've recently started learning DirectX 12 and have a question about structured buffers. So, I've used structured buffers in compute shaders by creating a resource with the size of: "numElements * sizeof(elementStruct)". I now want to create a structured buffer that will have a bunch of material structures to use in pixel shader. All my materials are stored in one resource but I want to create an SRV(-s) to only a few of the materials that are located in the middle of the resource. Is there a way to do that?

I thought that I can do the same thing as I do with the textures: create an SRV to every material in the resource, create a descriptor table in root signature (with the desired number of descriptors) and then just pass a handle to the first material SRV to SetGraphicsRootDescriptorTable(), but with this only the first material is properly displayed. (Although RenderDoc shows that if I create a descriptor table with 2 descriptors both are added to the pixel shader)

Advertisement

have u tried setting XXX to the one you are targeting ?

SetGraphicsRootDescriptorTable(XXX, …) 

ddlox said:

have u tried setting XXX to the one you are targeting ?

SetGraphicsRootDescriptorTable(XXX, …) 

I do exactly this, yes.

You see, when I use SRVs to textures and descriptor tables, root signature just needs the first SRV and then it knows how much of the next SRVs to take. Doing the same thing for my materials as a structured buffer: passing the first SRV but next SRVs are not taken. Read operations for the first material is HLSL works correct, but second material returns 0 always (seems like out of bounds operation).

Any tips on where to look for the possible mistake?

How are you creating the SRV descriptor for each material? Typically you would set the “Buffer.FirstElement” member of the D3D12_SHADER_RESOURCE_VIEW_DESC to accomplish this. If you're capturing in RenderDoc or PIX you should be able to inspect the parameters used to create the descriptor, so you can use that to double-check that you've set things up correctly. You should also make sure that you have debug validation layer enabled, which can point out simple mistakes with using the API incorrectly.

I have to say though, this sounds like a bit of an odd use-case for structured buffers. Normally you would use a structured buffer for cases where the shader needs to index into the buffer. So for instance, if you were to put all of your material info into a structured buffer with 1 element per material, and then pass a material index to the shader using a 32-bit root constant that you would use to index into the structured buffer, that would make sense. If your shader is only ever using the first element of a structured buffer, that would be something you would typically use a constant buffer for. That said, what you're describing is still valid and should work for this use case (and on some hardware there isn't even a functional difference between a constant buffer and a 1-element structured buffer, but on other hardware it could go down different paths with different performance characteristics).

@MJP Yes, you are right Matt! I thought if I could not solve this puzzle I will use just 1 resource with all needed materials and just bind them directly as usually people do with the structured buffers (but that would require some changes in my code). The Debug layer is enabled and not showing anything (so, should be correct), I thought that I maybe create SRVs incorrectly, I create them like this:

  int iIndexInHeap = i;
  auto handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(pCBVSRVUAVHeap->GetCPUDescriptorHandleForHeapStart());
  handle.Offset(iIndexInHeap, iCBVSRVUAVDescriptorSize);


  D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  srvDesc.Format = DXGI_FORMAT_UNKNOWN;
  srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
  srvDesc.Buffer.FirstElement = i;
  srvDesc.Buffer.NumElements = 1;
  srvDesc.Buffer.StructureByteStride = sizeof(MaterialData);
  srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;


  pDevice->CreateShaderResourceView(pMaterialRes, &srvDesc, handle);

Still don't know a lot about RenderDoc/PIX functionality so I would make sure to recheck the params. And as you have said about performance considerations I would probably use just 1 resource for all needed materials, just want to figure out why this is not working.

If you want to use PIX to inspect the SRV parameters, take a GPU capture of your app and then follow these steps once the capture is opened in PIX:

  1. Start analysis mode
  2. Switch to the Pipeline tab
  3. Find and select the Draw or Dispatch call you want to inspect
  4. Find and select the structured buffer SRV in the Pipeline view
  5. Enable the Info view
  6. Look at the Info window to see relevant information about the SRV and the resource it points to

@MJP Thanks again, Matt! I've already solved the problem, don't know how though, there were a few mistakes (that I found later) that fixed everything. Taking this opportunity, I would like to know what you recommend to use more often the RenderDoc or PIX?

Personally I tend to like RenderDoc's UI and flow better than PIX. However for D3D12 I almost exclusively use PIX since I'm usually working with bindless techniques, and PIX performs the necessary shader patching and analysis to show you which resources were actually used in a draw or dispatch. RenderDoc can do that for Vulkan, but not for D3D12 (currently).

This topic is closed to new replies.

Advertisement