Originally I have in
_floatArray = new float; _floatArray = 1f; _floatArray = 0.5f;
And use ComputeShader.SetFloats() to pass the values from C# to Compute Shader.
Reading the values in Compute Shader, I found that only FloatArray has the value. So FloatArray will equals to 0.
Unity dev (Marton E.) replied me that:
This is expected behavior and user code should be modified to follow packing rules.
HLSL specs says:
“Arrays are not packed in HLSL by default. To avoid forcing the shader to take on ALU overhead for offset computations, every element in an array is stored in a four-component vector. Note that you can achieve packing for arrays (and incur the addressing calculations) by using casting.”
Unity documentation says:
“This function can be used to set float vector, float array or float vector array values. For example, float4 myArray in the compute shader can be filled by passing 16 floats. See Compute Shaders for information on data layout rules and cross-platform compatibility.”
Unity implementation doesn’t do casting suggested in HLSL documentation but just goes for unpacked storage (same as std140 GLSL directive) therefore calling SetFloats with a float argument should be aligned according to HLSL rules, i.e. float should be packed as every array item on 16 byte (float4) boundary.
So I should have in
_floatArray = new float[4 * 4]; _floatArray = 1f; _floatArray = 0.5f; _floatArray = 0.75f; _floatArray = 1f;
And read values in Compute Shader with
FloatArray, FloatArray, FloatArray, FloatArray like usual.
One more note for Mac Metal:
Metal does not enforce similar packing restriction but in order to maintain compatibility (along with GLCore) it was implemented the same way.