I have a Compute Shader which uses InterlockedMin()
and InterlockedMax()
.
The Compute Shader works very well on my PC (AMD Rx6600) but for Android (Google Pixel 5) it doesn't calculate the atomic Min/Max, just leaves it as the original value.
Know that the Android build always uses Vulkan API.
So, how to run atomic Min/Max in Android build?
Thank you very much!
P.S.: For more info, I am generating terrain. atomicMin/Max is required to ensure the same result in any game session.
Updated
The staffs of Unity3D confirmed InterlockedMin/Max still works for Android. So the problem may be devices's compatibility.
For a workaround, I quit using the atomic function and instead have fixed min/max as constants. I ran my code manytimes and decided min/max would be -1.8/1.8. If I make any change in the algorithm stats I have to pre-calculate the min/max again.
Updated 2
More detail about the algorithm which I had used.
Context:
- The map is 2D, squared
- The height map be stored in 1D float array
mapSize
is the edge length of the 2D map, map squared size ismapSize * mapSize
The Compute Shader
// snoise is a function to calculate procedural (simplex?) noise
// long script here: https://github.com/SebLague/Hydraulic-Erosion/blob/master/Assets/Scripts/ComputeShaders/HeightMap.compute
RWStructuredBuffer<float> heightMap;//1D aray of height map
RWStructuredBuffer<int> minMax;// index 0 is min, index 1 is max
StructuredBuffer<float2> offsets;//octaves offsets
int floatToIntMultiplier;// 1000
int mapSize;// size of an edge of the 2D map
int octaves;
float lacunarity;
float persistence;
float scaleFactor;
[numthreads(1,1,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// get 2D position,
int x = id.x % mapSize;
int y = id.x / mapSize;
float scale = scaleFactor;
float weight = 1;
for (int i = 0; i < octaves; i ++) {
heightMap[id.x] += snoise(float2(x,y)/mapSize * scale + offsets[i]) * weight;
scale *= lacunarity;
weight *= persistence;
}
int val = int(heightMap[id.x] * floatToIntMultiplier);
InterlockedMin(minMax[0],val);// calculate min here
InterlockedMax(minMax[1],val);// calculate max here
}
The C# script
int mapSize = 1000;
int floatToIntMultiplier = 1000;
float[] heightMap = new float[ mapSize * mapSize ];
...
// set stats and dispatch the compute shader
// get calculated data from the compute shader
...
float min = minMax[0] / (float)floatToIntMultiplier ;
float max = minMax[1] / (float)floatToIntMultiplier ;
for(int i = 0; i < heightMap.Length; ++i)
{
heightMap[i] = Mathf.InverseLerp(min, max, heightMap[i])
}