2 * Copyright © 2017 Ilia Mirkin
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
25 * \file lower_cs_derived.cpp
27 * For hardware that does not support the gl_GlobalInvocationID and
28 * gl_LocalInvocationIndex system values, replace them with fresh
29 * globals. Note that we can't rely on gl_WorkGroupSize or
30 * gl_LocalGroupSizeARB being available, since they may only have been defined
31 * in a non-main shader.
33 * [ This can happen if only a secondary shader has the layout(local_size_*)
36 * This is meant to be run post-linking.
39 #include "glsl_symbol_table.h"
40 #include "ir_hierarchical_visitor.h"
42 #include "ir_builder.h"
44 #include "program/prog_statevars.h"
45 #include "builtin_functions.h"
47 using namespace ir_builder
;
51 class lower_cs_derived_visitor
: public ir_hierarchical_visitor
{
53 explicit lower_cs_derived_visitor(gl_linked_shader
*shader
)
56 local_size_variable(shader
->Program
->info
.cs
.local_size_variable
),
57 gl_WorkGroupSize(NULL
),
59 gl_LocalInvocationID(NULL
),
60 gl_GlobalInvocationID(NULL
),
61 gl_LocalInvocationIndex(NULL
)
63 main_sig
= _mesa_get_main_function_signature(shader
->symbols
);
67 virtual ir_visitor_status
visit(ir_dereference_variable
*);
69 ir_variable
*add_system_value(
70 int slot
, const glsl_type
*type
, const char *name
);
72 void make_gl_GlobalInvocationID();
73 void make_gl_LocalInvocationIndex();
78 gl_linked_shader
*shader
;
79 bool local_size_variable
;
80 ir_function_signature
*main_sig
;
82 ir_rvalue
*gl_WorkGroupSize
;
83 ir_variable
*gl_WorkGroupID
;
84 ir_variable
*gl_LocalInvocationID
;
86 ir_variable
*gl_GlobalInvocationID
;
87 ir_variable
*gl_LocalInvocationIndex
;
90 } /* anonymous namespace */
93 lower_cs_derived_visitor::add_system_value(
94 int slot
, const glsl_type
*type
, const char *name
)
96 ir_variable
*var
= new(shader
) ir_variable(type
, name
, ir_var_system_value
);
97 var
->data
.how_declared
= ir_var_declared_implicitly
;
98 var
->data
.read_only
= true;
99 var
->data
.location
= slot
;
100 var
->data
.explicit_location
= true;
101 var
->data
.explicit_index
= 0;
102 shader
->ir
->push_head(var
);
108 lower_cs_derived_visitor::find_sysvals()
110 if (gl_WorkGroupSize
!= NULL
)
113 ir_variable
*WorkGroupSize
;
114 if (local_size_variable
)
115 WorkGroupSize
= shader
->symbols
->get_variable("gl_LocalGroupSizeARB");
117 WorkGroupSize
= shader
->symbols
->get_variable("gl_WorkGroupSize");
119 gl_WorkGroupSize
= new(shader
) ir_dereference_variable(WorkGroupSize
);
120 gl_WorkGroupID
= shader
->symbols
->get_variable("gl_WorkGroupID");
121 gl_LocalInvocationID
= shader
->symbols
->get_variable("gl_LocalInvocationID");
124 * These may be missing due to either dead code elimination, or, in the
125 * case of the group size, due to the layout being declared in a non-main
126 * shader. Re-create them.
130 gl_WorkGroupID
= add_system_value(
131 SYSTEM_VALUE_WORK_GROUP_ID
, glsl_type::uvec3_type
, "gl_WorkGroupID");
132 if (!gl_LocalInvocationID
)
133 gl_LocalInvocationID
= add_system_value(
134 SYSTEM_VALUE_LOCAL_INVOCATION_ID
, glsl_type::uvec3_type
,
135 "gl_LocalInvocationID");
136 if (!WorkGroupSize
) {
137 if (local_size_variable
) {
138 gl_WorkGroupSize
= new(shader
) ir_dereference_variable(
140 SYSTEM_VALUE_LOCAL_GROUP_SIZE
, glsl_type::uvec3_type
,
141 "gl_LocalGroupSizeARB"));
143 ir_constant_data data
;
144 memset(&data
, 0, sizeof(data
));
145 for (int i
= 0; i
< 3; i
++)
146 data
.u
[i
] = shader
->Program
->info
.cs
.local_size
[i
];
147 gl_WorkGroupSize
= new(shader
) ir_constant(glsl_type::uvec3_type
, &data
);
153 lower_cs_derived_visitor::make_gl_GlobalInvocationID()
155 if (gl_GlobalInvocationID
!= NULL
)
160 /* gl_GlobalInvocationID =
161 * gl_WorkGroupID * gl_WorkGroupSize + gl_LocalInvocationID
163 gl_GlobalInvocationID
= new(shader
) ir_variable(
164 glsl_type::uvec3_type
, "__GlobalInvocationID", ir_var_temporary
);
165 shader
->ir
->push_head(gl_GlobalInvocationID
);
167 ir_instruction
*inst
=
168 assign(gl_GlobalInvocationID
,
169 add(mul(gl_WorkGroupID
, gl_WorkGroupSize
->clone(shader
, NULL
)),
170 gl_LocalInvocationID
));
171 main_sig
->body
.push_head(inst
);
175 lower_cs_derived_visitor::make_gl_LocalInvocationIndex()
177 if (gl_LocalInvocationIndex
!= NULL
)
182 /* gl_LocalInvocationIndex =
183 * gl_LocalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +
184 * gl_LocalInvocationID.y * gl_WorkGroupSize.x +
185 * gl_LocalInvocationID.x;
187 gl_LocalInvocationIndex
= new(shader
)
188 ir_variable(glsl_type::uint_type
, "__LocalInvocationIndex", ir_var_temporary
);
189 shader
->ir
->push_head(gl_LocalInvocationIndex
);
191 ir_expression
*index_z
=
192 mul(mul(swizzle_z(gl_LocalInvocationID
), swizzle_x(gl_WorkGroupSize
->clone(shader
, NULL
))),
193 swizzle_y(gl_WorkGroupSize
->clone(shader
, NULL
)));
194 ir_expression
*index_y
=
195 mul(swizzle_y(gl_LocalInvocationID
), swizzle_x(gl_WorkGroupSize
->clone(shader
, NULL
)));
196 ir_expression
*index_y_plus_z
= add(index_y
, index_z
);
197 operand
index_x(swizzle_x(gl_LocalInvocationID
));
198 ir_expression
*index_x_plus_y_plus_z
= add(index_y_plus_z
, index_x
);
199 ir_instruction
*inst
=
200 assign(gl_LocalInvocationIndex
, index_x_plus_y_plus_z
);
201 main_sig
->body
.push_head(inst
);
205 lower_cs_derived_visitor::visit(ir_dereference_variable
*ir
)
207 if (ir
->var
->data
.mode
== ir_var_system_value
&&
208 ir
->var
->data
.location
== SYSTEM_VALUE_GLOBAL_INVOCATION_ID
) {
209 make_gl_GlobalInvocationID();
210 ir
->var
= gl_GlobalInvocationID
;
214 if (ir
->var
->data
.mode
== ir_var_system_value
&&
215 ir
->var
->data
.location
== SYSTEM_VALUE_LOCAL_INVOCATION_INDEX
) {
216 make_gl_LocalInvocationIndex();
217 ir
->var
= gl_LocalInvocationIndex
;
221 return visit_continue
;
225 lower_cs_derived(gl_linked_shader
*shader
)
227 if (shader
->Stage
!= MESA_SHADER_COMPUTE
)
230 lower_cs_derived_visitor
v(shader
);