1 /*
2  * Copyright © 2013 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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.
22  */
23 #include <gtest/gtest.h>
24 #include "standalone_scaffolding.h"
25 #include "main/compiler.h"
26 #include "main/mtypes.h"
27 #include "main/macros.h"
28 #include "ir.h"
29 #include "glsl_parser_extras.h"
30 #include "glsl_symbol_table.h"
31 
32 class common_builtin : public ::testing::Test {
33 public:
common_builtin(GLenum shader_type)34    common_builtin(GLenum shader_type)
35       : shader_type(shader_type)
36    {
37       /* empty */
38    }
39 
40    virtual void SetUp();
41    virtual void TearDown();
42 
43    void string_starts_with_prefix(const char *str, const char *prefix);
44    void names_start_with_gl();
45    void uniforms_and_system_values_dont_have_explicit_location();
46    void constants_are_constant();
47    void no_invalid_variable_modes();
48 
49    GLenum shader_type;
50    struct _mesa_glsl_parse_state *state;
51    struct gl_shader *shader;
52    void *mem_ctx;
53    gl_context ctx;
54    exec_list ir;
55 };
56 
57 void
SetUp()58 common_builtin::SetUp()
59 {
60    this->mem_ctx = ralloc_context(NULL);
61    this->ir.make_empty();
62 
63    initialize_context_to_defaults(&this->ctx, API_OPENGL_COMPAT);
64 
65    this->shader = rzalloc(this->mem_ctx, gl_shader);
66    this->shader->Type = this->shader_type;
67    this->shader->Stage = _mesa_shader_enum_to_shader_stage(this->shader_type);
68 
69    this->state =
70       new(mem_ctx) _mesa_glsl_parse_state(&this->ctx, this->shader->Stage,
71                                           this->shader);
72 
73    _mesa_glsl_initialize_types(this->state);
74    _mesa_glsl_initialize_variables(&this->ir, this->state);
75 }
76 
77 void
TearDown()78 common_builtin::TearDown()
79 {
80    ralloc_free(this->mem_ctx);
81    this->mem_ctx = NULL;
82 }
83 
84 void
string_starts_with_prefix(const char * str,const char * prefix)85 common_builtin::string_starts_with_prefix(const char *str, const char *prefix)
86 {
87    const size_t len = strlen(prefix);
88    char *const name_prefix = new char[len + 1];
89 
90    strncpy(name_prefix, str, len);
91    name_prefix[len] = '\0';
92    EXPECT_STREQ(prefix, name_prefix) << "Bad name " << str;
93 
94    delete [] name_prefix;
95 }
96 
97 void
names_start_with_gl()98 common_builtin::names_start_with_gl()
99 {
100    foreach_in_list(ir_instruction, node, &this->ir) {
101       ir_variable *const var = node->as_variable();
102 
103       string_starts_with_prefix(var->name, "gl_");
104    }
105 }
106 
107 void
uniforms_and_system_values_dont_have_explicit_location()108 common_builtin::uniforms_and_system_values_dont_have_explicit_location()
109 {
110    foreach_in_list(ir_instruction, node, &this->ir) {
111       ir_variable *const var = node->as_variable();
112 
113       if (var->data.mode != ir_var_uniform && var->data.mode != ir_var_system_value)
114          continue;
115 
116       EXPECT_FALSE(var->data.explicit_location);
117       EXPECT_EQ(-1, var->data.location);
118    }
119 }
120 
121 void
constants_are_constant()122 common_builtin::constants_are_constant()
123 {
124    foreach_in_list(ir_instruction, node, &this->ir) {
125       ir_variable *const var = node->as_variable();
126 
127       if (var->data.mode != ir_var_auto)
128          continue;
129 
130       EXPECT_FALSE(var->data.explicit_location);
131       EXPECT_EQ(-1, var->data.location);
132       EXPECT_TRUE(var->data.read_only);
133    }
134 }
135 
136 void
no_invalid_variable_modes()137 common_builtin::no_invalid_variable_modes()
138 {
139    foreach_in_list(ir_instruction, node, &this->ir) {
140       ir_variable *const var = node->as_variable();
141 
142       switch (var->data.mode) {
143       case ir_var_auto:
144       case ir_var_uniform:
145       case ir_var_shader_in:
146       case ir_var_shader_out:
147       case ir_var_system_value:
148          break;
149 
150       default:
151          ADD_FAILURE() << "Built-in variable " << var->name
152                        << " has an invalid mode " << int(var->data.mode);
153          break;
154       }
155    }
156 }
157 
158 /************************************************************/
159 
160 class vertex_builtin : public common_builtin {
161 public:
vertex_builtin()162    vertex_builtin()
163       : common_builtin(GL_VERTEX_SHADER)
164    {
165       /* empty */
166    }
167 };
168 
TEST_F(vertex_builtin,names_start_with_gl)169 TEST_F(vertex_builtin, names_start_with_gl)
170 {
171    common_builtin::names_start_with_gl();
172 }
173 
TEST_F(vertex_builtin,inputs_have_explicit_location)174 TEST_F(vertex_builtin, inputs_have_explicit_location)
175 {
176    foreach_in_list(ir_instruction, node, &this->ir) {
177       ir_variable *const var = node->as_variable();
178 
179       if (var->data.mode != ir_var_shader_in)
180          continue;
181 
182       EXPECT_TRUE(var->data.explicit_location);
183       EXPECT_NE(-1, var->data.location);
184       EXPECT_GT(VERT_ATTRIB_GENERIC0, var->data.location);
185       EXPECT_EQ(0u, var->data.location_frac);
186    }
187 }
188 
TEST_F(vertex_builtin,outputs_have_explicit_location)189 TEST_F(vertex_builtin, outputs_have_explicit_location)
190 {
191    foreach_in_list(ir_instruction, node, &this->ir) {
192       ir_variable *const var = node->as_variable();
193 
194       if (var->data.mode != ir_var_shader_out)
195          continue;
196 
197       EXPECT_TRUE(var->data.explicit_location);
198       EXPECT_NE(-1, var->data.location);
199       EXPECT_GT(VARYING_SLOT_VAR0, var->data.location);
200       EXPECT_EQ(0u, var->data.location_frac);
201 
202       /* Several varyings only exist in the fragment shader.  Be sure that no
203        * outputs with these locations exist.
204        */
205       EXPECT_NE(VARYING_SLOT_PNTC, var->data.location);
206       EXPECT_NE(VARYING_SLOT_FACE, var->data.location);
207       EXPECT_NE(VARYING_SLOT_PRIMITIVE_ID, var->data.location);
208    }
209 }
210 
TEST_F(vertex_builtin,uniforms_and_system_values_dont_have_explicit_location)211 TEST_F(vertex_builtin, uniforms_and_system_values_dont_have_explicit_location)
212 {
213    common_builtin::uniforms_and_system_values_dont_have_explicit_location();
214 }
215 
TEST_F(vertex_builtin,constants_are_constant)216 TEST_F(vertex_builtin, constants_are_constant)
217 {
218    common_builtin::constants_are_constant();
219 }
220 
TEST_F(vertex_builtin,no_invalid_variable_modes)221 TEST_F(vertex_builtin, no_invalid_variable_modes)
222 {
223    common_builtin::no_invalid_variable_modes();
224 }
225 
226 /********************************************************************/
227 
228 class fragment_builtin : public common_builtin {
229 public:
fragment_builtin()230    fragment_builtin()
231       : common_builtin(GL_FRAGMENT_SHADER)
232    {
233       /* empty */
234    }
235 };
236 
TEST_F(fragment_builtin,names_start_with_gl)237 TEST_F(fragment_builtin, names_start_with_gl)
238 {
239    common_builtin::names_start_with_gl();
240 }
241 
TEST_F(fragment_builtin,inputs_have_explicit_location)242 TEST_F(fragment_builtin, inputs_have_explicit_location)
243 {
244    foreach_in_list(ir_instruction, node, &this->ir) {
245       ir_variable *const var = node->as_variable();
246 
247       if (var->data.mode != ir_var_shader_in)
248 	 continue;
249 
250       EXPECT_TRUE(var->data.explicit_location);
251       EXPECT_NE(-1, var->data.location);
252       EXPECT_GT(VARYING_SLOT_VAR0, var->data.location);
253       EXPECT_EQ(0u, var->data.location_frac);
254 
255       /* Several varyings only exist in the vertex / geometry shader.  Be sure
256        * that no inputs with these locations exist.
257        */
258       EXPECT_TRUE(_mesa_varying_slot_in_fs((gl_varying_slot) var->data.location));
259    }
260 }
261 
TEST_F(fragment_builtin,outputs_have_explicit_location)262 TEST_F(fragment_builtin, outputs_have_explicit_location)
263 {
264    foreach_in_list(ir_instruction, node, &this->ir) {
265       ir_variable *const var = node->as_variable();
266 
267       if (var->data.mode != ir_var_shader_out)
268 	 continue;
269 
270       EXPECT_TRUE(var->data.explicit_location);
271       EXPECT_NE(-1, var->data.location);
272 
273       /* gl_FragData[] has location FRAG_RESULT_DATA0.  Locations beyond that
274        * are invalid.
275        */
276       EXPECT_GE(FRAG_RESULT_DATA0, var->data.location);
277 
278       EXPECT_EQ(0u, var->data.location_frac);
279    }
280 }
281 
TEST_F(fragment_builtin,uniforms_and_system_values_dont_have_explicit_location)282 TEST_F(fragment_builtin, uniforms_and_system_values_dont_have_explicit_location)
283 {
284    common_builtin::uniforms_and_system_values_dont_have_explicit_location();
285 }
286 
TEST_F(fragment_builtin,constants_are_constant)287 TEST_F(fragment_builtin, constants_are_constant)
288 {
289    common_builtin::constants_are_constant();
290 }
291 
TEST_F(fragment_builtin,no_invalid_variable_modes)292 TEST_F(fragment_builtin, no_invalid_variable_modes)
293 {
294    common_builtin::no_invalid_variable_modes();
295 }
296 
297 /********************************************************************/
298 
299 class geometry_builtin : public common_builtin {
300 public:
geometry_builtin()301    geometry_builtin()
302       : common_builtin(GL_GEOMETRY_SHADER)
303    {
304       /* empty */
305    }
306 };
307 
TEST_F(geometry_builtin,names_start_with_gl)308 TEST_F(geometry_builtin, names_start_with_gl)
309 {
310    common_builtin::names_start_with_gl();
311 }
312 
TEST_F(geometry_builtin,inputs_have_explicit_location)313 TEST_F(geometry_builtin, inputs_have_explicit_location)
314 {
315    foreach_in_list(ir_instruction, node, &this->ir) {
316       ir_variable *const var = node->as_variable();
317 
318       if (var->data.mode != ir_var_shader_in)
319 	 continue;
320 
321       if (var->is_interface_instance()) {
322          EXPECT_STREQ("gl_in", var->name);
323          EXPECT_FALSE(var->data.explicit_location);
324          EXPECT_EQ(-1, var->data.location);
325 
326          ASSERT_TRUE(var->type->is_array());
327 
328          const glsl_type *const instance_type = var->type->fields.array;
329 
330          for (unsigned i = 0; i < instance_type->length; i++) {
331             const glsl_struct_field *const input =
332                &instance_type->fields.structure[i];
333 
334             string_starts_with_prefix(input->name, "gl_");
335             EXPECT_NE(-1, input->location);
336             EXPECT_GT(VARYING_SLOT_VAR0, input->location);
337 
338             /* Several varyings only exist in the fragment shader.  Be sure
339              * that no inputs with these locations exist.
340              */
341             EXPECT_NE(VARYING_SLOT_PNTC, input->location);
342             EXPECT_NE(VARYING_SLOT_FACE, input->location);
343          }
344       } else {
345          EXPECT_TRUE(var->data.explicit_location);
346          EXPECT_NE(-1, var->data.location);
347          EXPECT_GT(VARYING_SLOT_VAR0, var->data.location);
348          EXPECT_EQ(0u, var->data.location_frac);
349       }
350 
351       /* Several varyings only exist in the fragment shader.  Be sure that no
352        * inputs with these locations exist.
353        */
354       EXPECT_NE(VARYING_SLOT_PNTC, var->data.location);
355       EXPECT_NE(VARYING_SLOT_FACE, var->data.location);
356    }
357 }
358 
TEST_F(geometry_builtin,outputs_have_explicit_location)359 TEST_F(geometry_builtin, outputs_have_explicit_location)
360 {
361    foreach_in_list(ir_instruction, node, &this->ir) {
362       ir_variable *const var = node->as_variable();
363 
364       if (var->data.mode != ir_var_shader_out)
365 	 continue;
366 
367       EXPECT_TRUE(var->data.explicit_location);
368       EXPECT_NE(-1, var->data.location);
369       EXPECT_GT(VARYING_SLOT_VAR0, var->data.location);
370       EXPECT_EQ(0u, var->data.location_frac);
371 
372       /* Several varyings only exist in the fragment shader.  Be sure that no
373        * outputs with these locations exist.
374        */
375       EXPECT_NE(VARYING_SLOT_PNTC, var->data.location);
376       EXPECT_NE(VARYING_SLOT_FACE, var->data.location);
377    }
378 }
379 
TEST_F(geometry_builtin,uniforms_and_system_values_dont_have_explicit_location)380 TEST_F(geometry_builtin, uniforms_and_system_values_dont_have_explicit_location)
381 {
382    common_builtin::uniforms_and_system_values_dont_have_explicit_location();
383 }
384 
TEST_F(geometry_builtin,constants_are_constant)385 TEST_F(geometry_builtin, constants_are_constant)
386 {
387    common_builtin::constants_are_constant();
388 }
389 
TEST_F(geometry_builtin,no_invalid_variable_modes)390 TEST_F(geometry_builtin, no_invalid_variable_modes)
391 {
392    common_builtin::no_invalid_variable_modes();
393 }
394