0

I have an SSBO that contains a list of structs that contain both integers and vec3s as you can see below. I am using OpenTK for the C# opengl bindings.

struct BVHNode {
    vec3 AABBMin;
    int Child1;
    vec3 AABBMax;
    int Child2;
    int SplitAxis;
    int NumTriangles;
    int TriangleOffset;
    int ParentIndex;
};

layout(std430, binding=6) buffer BVHSSBO {
    BVHNode BVHNodes[];
} bvhSSBO;

The buffer is populated like this:

var gpuNodes = new Vector4[...];
...
GL.NamedBufferStorage(_bvhBufferHandle, bvhBufferSize, IntPtr.Zero, BufferStorageMask.DynamicStorageBit);
GL.BindBufferRange(BufferTargetARB.ShaderStorageBuffer, 6, _bvhBufferHandle, IntPtr.Zero, bvhBufferSize);
GL.NamedBufferSubData(_bvhBufferHandle, IntPtr.Zero, bvhBufferSize, gpuNodes);

The problem is that these integers get transformed into their floating point binary representation which is then converted back to integer. The number in the screenshot should be equal to 1, but its 1065353216, which is 111111100000000000000000000000 in binary, converting this back to decimal as IEE754 float yields 1.0.
enter image description here

If I change the type of these numbers in my shader to float, the numbers are correct but when I want to use them as indices for an array I have to do int(x) every time.
The only way I can get the integers to work is by changing the type of gpuNodes to Vector4i instead of Vector4, but this way the vector3's don't work. How do I get the correct numbers when leaving the type at int?

bortgerres
  • 185
  • 1
  • 2
  • 10
  • 1
    Why do you upload an array of Vector4 if you need mixed float/integer data? Use a struct which matches the GLSL definition. – BDL May 14 '22 at 16:07
  • I did not know that was a possibility, the examples I looked at online all used vector4 to upload to the GPU. Probably so they could have an interface with a `Vector4[] GetGpuData()`. I will try changing it to a list of structs. – bortgerres May 14 '22 at 16:11
  • @bortgerres: BTW, [don't use `vec3`s for UBOs/SSBOs](https://stackoverflow.com/q/38172696/734069). – Nicol Bolas May 14 '22 at 16:22
  • So the question is how to fill the source buffer data with ints and floats in C#? – Rabbid76 May 14 '22 at 16:24
  • @NicolBolas, I saw that question as well but for me it does seem to work fine? When I look in renderdoc all the values are there where I expect them. It's just that the values are wrong but that is a mistake on my part. – bortgerres May 14 '22 at 16:43
  • @Rabbid76, Now that I think about it some more, yes. The thought of passing in a struct instead of a vector4 like BDL said did not occur to me. – bortgerres May 14 '22 at 16:46
  • @bortgerres I missed the first time that you are using opentk. I'm not sure how you pass a struct with this library, but I'm quite sure it is possible somehow – BDL May 14 '22 at 17:51
  • [Unsafe code, pointer types, and function pointers](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code) – Rabbid76 May 14 '22 at 18:06

1 Answers1

0

See Unsafe code, pointer types, and function pointers. Use a unsafe struct with fixed size arrays, e.g.:

public unsafe struct Buffer
{
    public fixed float floatData[4];
    public fixed int intData[4];
    // [...]
}

Use marshalling and Marshal.StructureToPtr to marshals data from a managed object to an unmanaged block of memory:

using System.Runtime.InteropServices;
Buffer buffer;
int dataSize = Marshal.SizeOf(default(T_DATA));
IntPtr dataPtr = Marshal.AllocHGlobal(data_size);
Marshal.StructureToPtr(ref buffer, dataPtr, false);

GL.NamedBufferSubData(_bvhBufferHandle, IntPtr.Zero, dataSize, dataPtr);

Marshal.FreeHGlobal(data_ptr);
Rabbid76
  • 202,892
  • 27
  • 131
  • 174