Advertisement

Copy one vertex buffer to another vertex buffer in compute shader

Started by January 07, 2024 01:27 PM
6 comments, last by Alundra 11 months, 2 weeks ago

Hi everybody!
I'm trying to copy one vertex buffer to another vertex buffer in compute shader.
This is a first step to then add more vertex processing once the copy is working properly.
The copy is from a vertex buffer containing skinning data to another vertex buffer without skinning data.
Here the entire compute shader:

struct SourceVertex
{
    float3 Position;
    float3 Normal;
    float2 TexCoord;
    float4 Tangent;
    float4 Weights;
    uint4 Indices;
};

struct OutputVertex
{
    float3 Position;
    float3 Normal;
    float2 TexCoord;
    float4 Tangent;
};


RWByteAddressBuffer OutputVertexBuffer : register(u0);
ByteAddressBuffer VertexBuffer : register(t0);

[numthreads(1, 1, 1)]
void main(in uint3 dispatchThreadID : SV_DispatchThreadID)
{
    // Load the current vertex.
    uint SourceByteOffset = dispatchThreadID.x * sizeof(SourceVertex);
    SourceVertex CurrentVertex = VertexBuffer.Load<SourceVertex>(SourceByteOffset);

    // Set the output current vertex.
    OutputVertex OutputCurrentVertex;
    OutputCurrentVertex.Position = CurrentVertex.Position;
    OutputCurrentVertex.Normal = CurrentVertex.Normal;
    OutputCurrentVertex.TexCoord = CurrentVertex.TexCoord;
    OutputCurrentVertex.Tangent = CurrentVertex.Tangent;

    // Store the output current vertex.
    uint OutputByteOffset = dispatchThreadID.x * sizeof(OutputVertex);
    OutputVertexBuffer.Store(OutputByteOffset, OutputCurrentVertex);
}

I create the SRV and UVA using DXGI_FORMAT_R32_TYPELESS with bufferSize / 4 for NumElements.

D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
srvDesc.Buffer.NumElements = size / 4;
srvDesc.Buffer.StructureByteStride = 0;
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
uavDesc.Buffer.CounterOffsetInBytes = 0;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
uavDesc.Buffer.NumElements = size / 4;
uavDesc.Buffer.StructureByteStride = 0;

Without dispatching the compute shader, using just the initially created copied buffer, it's all fine, but once the compute shader is dispatched to simply copy the whole data from one vertex buffer to another the result is not good anymore.

Thank you for your help!

I did not mention but the dispatch of the compute shader is like that:

graphicsCommandList->Dispatch(numVertices, 1, 1);
Advertisement

Also, tried this way but the result is not good as well:

RWByteAddressBuffer OutputVertexBuffer : register(u0);
ByteAddressBuffer VertexBuffer : register(t0);

[numthreads(1, 1, 1)]
void main(in uint3 dispatchThreadID : SV_DispatchThreadID)
{
    // Load the current vertex.
    uint sourceVertexSize = 80;
    uint SourceByteOffset = dispatchThreadID.x * sourceVertexSize;
    float3 CurrentPosition = asfloat(VertexBuffer.Load3(SourceByteOffset));

    // Store the output current vertex.
    uint outputVertexSize = 48;
    uint OutputByteOffset = dispatchThreadID.x * outputVertexSize;
    OutputVertexBuffer.Store3(OutputByteOffset, asuint(CurrentPosition));
}

I tried to change to a structured buffer but I got the same result:

struct SourceVertex
{
    float3 Position;
    float3 Normal;
    float2 TexCoord;
    float4 Tangent;
    float4 Weights;
    uint4 Indices;
};

struct OutputVertex
{
    float3 Position;
    float3 Normal;
    float2 TexCoord;
    float4 Tangent;
};

RWStructuredBuffer<OutputVertex> OutputVertexBuffer : register(u0);
StructuredBuffer<SourceVertex> VertexBuffer : register(t0);

[numthreads(1, 1, 1)]
void main(in uint3 dispatchThreadID : SV_DispatchThreadID)
{
    SourceVertex CurrentVertex = VertexBuffer[dispatchThreadID.x];
    OutputVertexBuffer[dispatchThreadID.x].Position = CurrentVertex.Position;
    OutputVertexBuffer[dispatchThreadID.x].Normal = CurrentVertex.Normal;
    OutputVertexBuffer[dispatchThreadID.x].TexCoord = CurrentVertex.TexCoord;
    OutputVertexBuffer[dispatchThreadID.x].Tangent = CurrentVertex.Tangent;
}
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
srvDesc.Buffer.NumElements = size / 80;
srvDesc.Buffer.StructureByteStride = 80;
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.Buffer.CounterOffsetInBytes = 0;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
uavDesc.Buffer.NumElements = size / 48;
uavDesc.Buffer.StructureByteStride = 48;

Another method that was not successful:

RWByteAddressBuffer OutputVertexBuffer : register(u0);
ByteAddressBuffer VertexBuffer : register(t0);

[numthreads(1, 1, 1)]
void main(in uint3 dispatchThreadID : SV_DispatchThreadID)
{
    // Load the vertex buffer data.
    uint startSourceOffsetByte = dispatchThreadID.x * 80;
    float3 sourcePosition = asfloat(VertexBuffer.Load3(startSourceOffsetByte));
    float3 sourceNormal = asfloat(VertexBuffer.Load3(startSourceOffsetByte + 12));
    float2 sourceTexCoord = asfloat(VertexBuffer.Load2(startSourceOffsetByte + 24));
    float4 sourceTangent = asfloat(VertexBuffer.Load4(startSourceOffsetByte + 32));

    // Store in the output vertex buffer.
    uint startOutputOffsetByte = dispatchThreadID.x * 48;
    OutputVertexBuffer.Store3(startOutputOffsetByte, asuint(sourcePosition));
    OutputVertexBuffer.Store3(startOutputOffsetByte + 12, asuint(sourceNormal));
    OutputVertexBuffer.Store2(startOutputOffsetByte + 24, asuint(sourceTexCoord));
    OutputVertexBuffer.Store4(startOutputOffsetByte + 32, asuint(sourceTangent));
}
Advertisement

The problem is I can not have it working at all and I have no idea why with all the tested methods.
D3D12 says 0 error/warnings too…

Turned out all the methods are valid. It was related to the source buffer data types.
Problem solved!

This topic is closed to new replies.

Advertisement