From a13192229adc93b9fe5ddec9cf62f1bffd77bf35 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 3 May 2023 12:54:05 +0200 Subject: [PATCH 1/7] Add explanation for subgroup vs dynamically uniform. --- chapters/shaders.adoc | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index f96cb4239..35f7b9db9 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2498,6 +2498,86 @@ In other shader stages, each invocation in a subgroup must: be in the same Only <> have defined subgroups. + +[NOTE] +.Note +==== +In shaders, there are two kinds of uniformity that is of interest to +applications, subgroup uniform and dynamically uniform. + +While dynamically uniform appears to be a stronger kind of uniform +than subgroups, it is not necessarily the case for graphics pipelines. + +For shader stages with defined workgroups, this assumption holds. +If a value is dynamically uniform, it is by definition also uniform across the subgroup, +as this is a specific guarantee provided to stages with explicit workgroups. +This is important if writing code like: + +[source,c] +~~~~ +uniform texture2D Textures[]; +uint dynamicallyUniformValue = gl_WorkGroupID.x; +vec4 value = texelFetch(Textures[dynamicallyUniformValue], coord, 0); + +// subgroupUniformValue is guaranteed to be uniform across the subgroup. +// This value also happens to be dynamically uniform. +vec4 subgroupUniformValue = subgroupBroadcastFirst(dynamicallyUniformValue); +~~~~ + +In fragment shaders and other graphics stages, this gets complicated. +Due to scoping rules, there is no guarantee that a subgroup is a subset of the invocation scope, +which in turn defines the scope for dynamically uniform. +In graphics, the invocation scope is a single draw command. +In multi-draw indirect, there are multiple invocation scopes, one per code:DrawIndex. + +[source,c] +~~~~ +// Assume SubgroupSize = 8, where 3 draws are packed together. +// Two subgroups were generated. +uniform texture2D Textures[]; + +// DrawIndex builtin is dynamically uniform +uint dynamicallyUniformValue = gl_DrawID; +// | gl_DrawID = 0 | gl_DrawID = 1 | } +// Subgroup 0: { 0, 0, 0, 0, 1, 1, 1, 1 } +// | DrawID = 2 | DrawID = 1 | } +// Subgroup 1: { 2, 2, 2, 2, 1, 1, 1, 1 } + +uint notActuallyDynamicallyUniformAnymore = + subgroupBroadcastFirst(dynamicallyUniformValue); +// | gl_DrawID = 0 | gl_DrawID = 1 | } +// Subgroup 0: { 0, 0, 0, 0, 0, 0, 0, 0 } +// | gl_DrawID = 2 | gl_DrawID = 1 | } +// Subgroup 1: { 2, 2, 2, 2, 2, 2, 2, 2 } + +// Bug. gl_DrawID = 1's invocation scope observes both index 0 and 2. +vec4 value = texelFetch(Textures[notActuallyDynamicallyUniformAnymore], + coord, 0); +~~~~ + +Another problematic scenario is when a shader attempts to help the compiler notice +that a value is subgroup uniform to potentially improve performance. + +[source,c] +~~~~ +layout(location = 0) flat in dynamicallyUniformIndex; +// Vertex shader might have emitted a value that depends only on gl_DrawID, +// making it dynamically uniform. +// Give knowledge to compiler that the flat input is dynamically uniform, +// as this is not a guarantee otherwise. + +uint uniformIndex = subgroupBroadcastFirst(dynamicallyUniformIndex); +// Hazard: If different draw commands are packed into one subgroup, the uniformIndex is wrong. + +DrawData d = UBO.perDrawData[uniformIndex]; +~~~~ + +For implementations where subgroups are packed across draws, the implementation must +make sure to handle descriptor indexing correctly. From the specification's point of view, +a dynamically uniform index does not require code:NonUniform decoration, +and such an implementation will likely either promote descriptor indexing into code:NonUniform on its own, +or handle non-uniformity natively. +==== endif::VK_VERSION_1_1[] From e714fc873c0d37331c10fa9f6747fcd0cebdd1fe Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 31 May 2023 14:19:57 +0200 Subject: [PATCH 2/7] Apply suggestions from code review Co-authored-by: Constantine Shablia --- chapters/shaders.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index 35f7b9db9..ac7682530 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2502,11 +2502,11 @@ operations>> have defined subgroups. [NOTE] .Note ==== -In shaders, there are two kinds of uniformity that is of interest to -applications, subgroup uniform and dynamically uniform. +In shaders, there are two kinds of uniformity that are of interest to +applications: subgroup uniform and dynamically uniform. While dynamically uniform appears to be a stronger kind of uniform -than subgroups, it is not necessarily the case for graphics pipelines. +than subgroups, it is not necessarily the case for shader stages without defined workgroups. For shader stages with defined workgroups, this assumption holds. If a value is dynamically uniform, it is by definition also uniform across the subgroup, From de61c3ba7bab2a4493b45a2ca66a5a336292635d Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 31 May 2023 14:23:42 +0200 Subject: [PATCH 3/7] Be more precise about which shader stages with workgroups. --- chapters/shaders.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index ac7682530..12f547af2 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2502,7 +2502,7 @@ operations>> have defined subgroups. [NOTE] .Note ==== -In shaders, there are two kinds of uniformity that are of interest to +In shaders, there are two kinds of uniformity that are of primary interest to applications: subgroup uniform and dynamically uniform. While dynamically uniform appears to be a stronger kind of uniform @@ -2524,7 +2524,7 @@ vec4 value = texelFetch(Textures[dynamicallyUniformValue], coord, 0); vec4 subgroupUniformValue = subgroupBroadcastFirst(dynamicallyUniformValue); ~~~~ -In fragment shaders and other graphics stages, this gets complicated. +In shader stages without defined workgroups, this gets complicated. Due to scoping rules, there is no guarantee that a subgroup is a subset of the invocation scope, which in turn defines the scope for dynamically uniform. In graphics, the invocation scope is a single draw command. From 628a99b392267e3660f9a4646da51fcd975f3641 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 31 May 2023 16:03:24 +0200 Subject: [PATCH 4/7] Use imply rather than stronger. --- chapters/shaders.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index 12f547af2..c13ebf9b2 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2505,8 +2505,8 @@ operations>> have defined subgroups. In shaders, there are two kinds of uniformity that are of primary interest to applications: subgroup uniform and dynamically uniform. -While dynamically uniform appears to be a stronger kind of uniform -than subgroups, it is not necessarily the case for shader stages without defined workgroups. +While dynamically uniform appears to imply subgroup uniform, +it is not necessarily the case for shader stages without defined workgroups. For shader stages with defined workgroups, this assumption holds. If a value is dynamically uniform, it is by definition also uniform across the subgroup, From 51b65e7d68f35eba885a7fcb54d2e9a7e8caa0e6 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 14 Jun 2023 12:05:15 +0200 Subject: [PATCH 5/7] Some nits from review. --- chapters/shaders.adoc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index c13ebf9b2..0d1ccb8f0 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2503,12 +2503,13 @@ operations>> have defined subgroups. .Note ==== In shaders, there are two kinds of uniformity that are of primary interest to -applications: subgroup uniform and dynamically uniform. +applications:, subgroup uniform and dynamically uniform. -While dynamically uniform appears to imply subgroup uniform, +While one could make the assumption that being dynamically uniform implies being subgroup uniform, it is not necessarily the case for shader stages without defined workgroups. -For shader stages with defined workgroups, this assumption holds. +For shader stages with defined workgroups however, +the relationship between dynamically uniform and subgroup uniform is well defined. If a value is dynamically uniform, it is by definition also uniform across the subgroup, as this is a specific guarantee provided to stages with explicit workgroups. This is important if writing code like: @@ -2527,8 +2528,9 @@ vec4 subgroupUniformValue = subgroupBroadcastFirst(dynamicallyUniformValue); In shader stages without defined workgroups, this gets complicated. Due to scoping rules, there is no guarantee that a subgroup is a subset of the invocation scope, which in turn defines the scope for dynamically uniform. -In graphics, the invocation scope is a single draw command. -In multi-draw indirect, there are multiple invocation scopes, one per code:DrawIndex. +In graphics, the invocation scope is a single draw command, except for +multi-draw situations, and indirect draws with drawCount > 1, +where there are multiple invocation scopes, one per code:DrawIndex. [source,c] ~~~~ From b4fc83216557aa67b95dc2c04d4f3787ebe8f444 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 21 Jun 2023 14:55:56 +0200 Subject: [PATCH 6/7] Use implicit instead of native. --- chapters/shaders.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index 0d1ccb8f0..2f015a3f0 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2578,7 +2578,7 @@ For implementations where subgroups are packed across draws, the implementation make sure to handle descriptor indexing correctly. From the specification's point of view, a dynamically uniform index does not require code:NonUniform decoration, and such an implementation will likely either promote descriptor indexing into code:NonUniform on its own, -or handle non-uniformity natively. +or handle non-uniformity implicitly. ==== endif::VK_VERSION_1_1[] From 77cd4f95bf75f7571c31ee80d7e05051ae3e2b7d Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 12 Jul 2023 11:54:36 +0200 Subject: [PATCH 7/7] Avoid "subgroup uniform". --- chapters/shaders.adoc | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/chapters/shaders.adoc b/chapters/shaders.adoc index 2f015a3f0..f34ad0237 100644 --- a/chapters/shaders.adoc +++ b/chapters/shaders.adoc @@ -2503,15 +2503,16 @@ operations>> have defined subgroups. .Note ==== In shaders, there are two kinds of uniformity that are of primary interest to -applications:, subgroup uniform and dynamically uniform. +applications: uniform within an invocation group (a.k.a. dynamically uniform), +and uniform within a subgroup scope. -While one could make the assumption that being dynamically uniform implies being subgroup uniform, +While one could make the assumption that being uniform in invocation group implies being uniform in subgroup scope, it is not necessarily the case for shader stages without defined workgroups. For shader stages with defined workgroups however, -the relationship between dynamically uniform and subgroup uniform is well defined. -If a value is dynamically uniform, it is by definition also uniform across the subgroup, -as this is a specific guarantee provided to stages with explicit workgroups. +the relationship between invocation group and subgroup scope is well defined as a subgroup is a subset of the workgroup, and +the workgroup is the invocation group. +If a value is uniform in invocation group, it is by definition also uniform in subgroup scope. This is important if writing code like: [source,c] @@ -2520,17 +2521,17 @@ uniform texture2D Textures[]; uint dynamicallyUniformValue = gl_WorkGroupID.x; vec4 value = texelFetch(Textures[dynamicallyUniformValue], coord, 0); -// subgroupUniformValue is guaranteed to be uniform across the subgroup. +// subgroupUniformValue is guaranteed to be uniform within the subgroup. // This value also happens to be dynamically uniform. vec4 subgroupUniformValue = subgroupBroadcastFirst(dynamicallyUniformValue); ~~~~ In shader stages without defined workgroups, this gets complicated. -Due to scoping rules, there is no guarantee that a subgroup is a subset of the invocation scope, +Due to scoping rules, there is no guarantee that a subgroup is a subset of the invocation group, which in turn defines the scope for dynamically uniform. -In graphics, the invocation scope is a single draw command, except for +In graphics, the invocation group is a single draw command, except for multi-draw situations, and indirect draws with drawCount > 1, -where there are multiple invocation scopes, one per code:DrawIndex. +where there are multiple invocation groups, one per code:DrawIndex. [source,c] ~~~~ @@ -2552,13 +2553,13 @@ uint notActuallyDynamicallyUniformAnymore = // | gl_DrawID = 2 | gl_DrawID = 1 | } // Subgroup 1: { 2, 2, 2, 2, 2, 2, 2, 2 } -// Bug. gl_DrawID = 1's invocation scope observes both index 0 and 2. +// Bug. gl_DrawID = 1's invocation group observes both index 0 and 2. vec4 value = texelFetch(Textures[notActuallyDynamicallyUniformAnymore], coord, 0); ~~~~ Another problematic scenario is when a shader attempts to help the compiler notice -that a value is subgroup uniform to potentially improve performance. +that a value is uniform in subgroup scope to potentially improve performance. [source,c] ~~~~