init
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
#version 450
|
||||
/* Copyright (c) 2021-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Adds support for nonuniformEXT and unsized descriptor arrays.
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D Textures[];
|
||||
layout(set = 1, binding = 0) uniform sampler ImmutableSampler;
|
||||
|
||||
layout(location = 0) in vec2 in_uv;
|
||||
layout(location = 1) flat in int in_texture_index;
|
||||
layout(location = 0) out vec4 out_frag_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Here we are indexing into the texture array, with a non-uniform index.
|
||||
// Across the draw-call, there are different instance indices being used, so we must use nonuniformEXT.
|
||||
// It is important to note that to be 100% correct, we must use:
|
||||
// nonuniformEXT(sampler2D()).
|
||||
// It is the final argument to a call like texture() which determines if the access is to be considered non-uniform.
|
||||
// It is very common in the wild to see code like:
|
||||
// - sampler2D(Textures[nonuniformEXT(in_texture_index)], ...)
|
||||
// This looks very similar to HLSL, but it is somewhat wrong.
|
||||
// Generally, it will work on drivers, but it is not technically correct.
|
||||
|
||||
// To quote GL_EXT_nonuniform_qualifier:
|
||||
|
||||
/*
|
||||
Only some operations discussed in Chapter 5 (Operators and Expressions)
|
||||
can be applied to nonuniform value(s) and still yield a result that is
|
||||
nonuniform. The operations that do so are listed below. When a
|
||||
nonuniform value is operated on with one of these operators (regardless
|
||||
of whether any and other operands are nonuniform), the result is
|
||||
implicitly nonuniform:
|
||||
|
||||
...
|
||||
|
||||
* Structure and Array Operations in Section 5.7, except for the length
|
||||
method and assignment operator.
|
||||
|
||||
...
|
||||
|
||||
Constructors and builtin functions, which all have return types that
|
||||
are not qualified by nonuniformEXT, will not generate nonuniform results.
|
||||
Shaders need to use the constructor syntax (or assignment to a
|
||||
nonuniformEXT-qualified variable) to re-add the nonuniformEXT qualifier
|
||||
to the result of builtin functions.
|
||||
|
||||
...
|
||||
*/
|
||||
|
||||
// sampler2D is such a constructor, so we must add nonuniformEXT afterwards.
|
||||
out_frag_color = texture(nonuniformEXT(sampler2D(Textures[in_texture_index], ImmutableSampler)), in_uv);
|
||||
// For all other use cases of nonuniformEXT however, we can write code like:
|
||||
// uniform UBO { vec4 data; } UBOs[]; vec4 foo = UBOs[nonuniformEXT(index)].data;
|
||||
// buffer SSBO { vec4 data; } SSBOs[]; vec4 foo = SSBOs[nonuniformEXT(index)].data;
|
||||
// uniform sampler2D Tex[]; vec4 foo = texture(Tex[nonuniformEXT(index)], uv);
|
||||
// uniform uimage2D Img[]; uint count = imageAtomicAdd(Img[nonuniformEXT(index)], uv, val);
|
||||
// etc. The nonuniform qualifier will propagate up to the final argument which is used in the load/store or atomic operation.
|
||||
|
||||
// Using implicit LOD with nonuniformEXT can be spicy! If the threads in a quad do not have the same index,
|
||||
// LOD might not be computed correctly. The quadDivergentImplicitLOD property lets you know if it will work.
|
||||
// In this case however, it is completely fine, since the helper lanes in a quad must come from the same primitive,
|
||||
// which all have the same flat fragment input.
|
||||
|
||||
// You might consider using subgroup operations to implement nonuniformEXT on your own.
|
||||
// This is technically out of spec, since the SPIR-V specification states that to avoid nonuniformEXT,
|
||||
// the shader must guarantee that the index is "dynamically uniform".
|
||||
// "Dynamically uniform" means the value is the same across all invocations in an "invocation group".
|
||||
// The invocation group is defined to be all invocations (threads) for:
|
||||
// - An entire draw command (for graphics)
|
||||
// - A single workgroup (for compute).
|
||||
// Avoiding nonuniformEXT with clever programming is far more likely to succeed when writing compute shaders,
|
||||
// since the workgroup boundary serves as a much easier boundary to control than entire draw commands.
|
||||
// It is often possible to match workgroup to subgroup 1:1, unlike graphics where you cannot control how
|
||||
// quads are packed into subgroups at all.
|
||||
// The recommended approach here is to just let the compiler do its thing to avoid horrible bugs in the future.
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
#version 450
|
||||
/* Copyright (c) 2021-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
layout(location = 0) out vec2 out_uv;
|
||||
layout(location = 1) flat out int out_texture_index;
|
||||
|
||||
layout(push_constant) uniform Registers
|
||||
{
|
||||
float phase;
|
||||
} registers;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 local_offset = vec2(gl_VertexIndex & 1, gl_VertexIndex >> 1);
|
||||
out_uv = local_offset;
|
||||
|
||||
// A lazy quad rotation, could easily have been precomputed on CPU.
|
||||
float cos_phase = cos(registers.phase);
|
||||
float sin_phase = sin(registers.phase);
|
||||
local_offset = mat2(cos_phase, -sin_phase, sin_phase, cos_phase) * (local_offset - 0.5);
|
||||
|
||||
// To keep the sample as simple as possible, use gl_InstanceIndex to move the quads around on screen.
|
||||
int instance_x = gl_InstanceIndex % 8;
|
||||
int instance_y = gl_InstanceIndex / 8;
|
||||
vec2 instance_offset = vec2(instance_x, instance_y) / vec2(15.0, 7.0);
|
||||
instance_offset = 2.1 * (instance_offset - 0.5);
|
||||
|
||||
gl_Position = vec4((0.10 * local_offset) + instance_offset, 0.0, 1.0);
|
||||
|
||||
// Pass down an index which we will use to index into the descriptor array.
|
||||
out_texture_index = gl_InstanceIndex;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
#version 450
|
||||
/* Copyright (c) 2021-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D Textures[];
|
||||
layout(set = 1, binding = 0) uniform sampler ImmutableSampler;
|
||||
|
||||
layout(location = 0) in vec2 in_uv;
|
||||
layout(location = 0) out vec4 out_frag_color;
|
||||
|
||||
layout(push_constant) uniform Registers
|
||||
{
|
||||
// Offset 0 is used by vertex.
|
||||
layout(offset = 4) uint table_offset;
|
||||
} registers;
|
||||
|
||||
void main()
|
||||
{
|
||||
// This is a very common usage pattern for streamed descriptors with UPDATE_AFTER_BIND.
|
||||
// We only need to update push constants, and our materials can access new descriptors.
|
||||
// This avoids having to allocate and manage individual descriptor sets.
|
||||
// It does mean that the chance to introduce bugs is higher however ...
|
||||
|
||||
// A push constant must be dynamically uniform over our draw call, so we do not have to do anything here.
|
||||
// This is simply considered dynamic indexing, which is a feature in core Vulkan 1.0.
|
||||
out_frag_color = texture(sampler2D(Textures[registers.table_offset], ImmutableSampler), in_uv);
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
#version 450
|
||||
/* Copyright (c) 2021-2024, Arm Limited and Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 the "License";
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
layout(location = 0) out vec2 out_uv;
|
||||
|
||||
layout(push_constant) uniform Registers
|
||||
{
|
||||
float phase;
|
||||
} registers;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 local_offset = vec2(gl_VertexIndex & 1, gl_VertexIndex >> 1);
|
||||
out_uv = local_offset;
|
||||
|
||||
// A lazy quad rotation, could easily have been precomputed on CPU.
|
||||
float cos_phase = cos(registers.phase);
|
||||
float sin_phase = sin(registers.phase);
|
||||
local_offset = mat2(cos_phase, -sin_phase, sin_phase, cos_phase) * (local_offset - 0.5);
|
||||
|
||||
// To keep the sample as simple as possible, use gl_InstanceIndex to move the quads around on screen.
|
||||
int instance_x = gl_InstanceIndex % 8 + 8;
|
||||
int instance_y = gl_InstanceIndex / 8;
|
||||
vec2 instance_offset = vec2(instance_x, instance_y) / vec2(15.0, 7.0);
|
||||
instance_offset = 2.1 * (instance_offset - 0.5);
|
||||
|
||||
gl_Position = vec4((0.10 * local_offset) + instance_offset, 0.0, 1.0);
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user