nir: Optimize some specific arrays to transforms on an index
One thing I have noticed is that sometimes we get terrible output that involves buffer loads and stuff from doing something like the following:
#version 450
layout(push_constant, row_major) uniform UBO {
mat4 proj;
vec2 uv_offset;
vec2 uv_size;
} data;
layout(location = 0) out vec2 uv;
// 4 outlining points and uv coords
const vec2[] values = {
{0, 0},
{1, 0},
{1, 1},
{0, 1},
};
void main() {
vec2 pos = values[gl_VertexIndex % 4];
uv = data.uv_offset + pos * data.uv_size;
gl_Position = data.proj * vec4(pos, 0.0, 1.0);
}
We can transform this index into the array to the following:
#version 450
layout(push_constant, row_major) uniform UBO {
mat4 proj;
vec2 uv_offset;
vec2 uv_size;
} data;
layout(location = 0) out vec2 uv;
void main() {
vec2 pos = vec2(float((gl_VertexIndex + 1) & 2) * 0.5f,
float(gl_VertexIndex & 2) * 0.5f);
uv = data.uv_offset + pos * data.uv_size;
gl_Position = data.proj * vec4(pos, 0.0, 1.0);
}
NIR should detect small arrays like that one for a quad, or for a fullscreen tri and convert them into an operation on the index. Same goes for opposite windings.
In this instance, the index is gl_VertexIndex
but it'd work for any n
for a const array of that size.
Eg. for fullcsreen tri:
{ 0, 0 },
{ 0, 2 },
{ 2, 0 },
->
vec2 coord = vec2(
float(gl_VertexIndex & 2),
float(gl_VertexIndex & 1) * 2.0f);