1/*
2 * Copyright © 2012 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 "main/compiler.h"
25#include "main/mtypes.h"
26#include "main/macros.h"
27#include "ralloc.h"
28#include "uniform_initializer_utils.h"
29
30namespace linker {
31extern void
32set_uniform_initializer(void *mem_ctx, gl_shader_program *prog,
33			const char *name, const glsl_type *type,
34			ir_constant *val);
35}
36
37class set_uniform_initializer : public ::testing::Test {
38public:
39   virtual void SetUp();
40   virtual void TearDown();
41
42   /**
43    * Index of the uniform to be tested.
44    *
45    * All of the \c set_uniform_initializer tests create several slots for
46    * unifroms.  All but one of the slots is fake.  This field holds the index
47    * of the slot for the uniform being tested.
48    */
49   unsigned actual_index;
50
51   /**
52    * Name of the uniform to be tested.
53    */
54   const char *name;
55
56   /**
57    * Shader program used in the test.
58    */
59   struct gl_shader_program *prog;
60
61   /**
62    * Ralloc memory context used for all temporary allocations.
63    */
64   void *mem_ctx;
65};
66
67void
68set_uniform_initializer::SetUp()
69{
70   this->mem_ctx = ralloc_context(NULL);
71   this->prog = rzalloc(NULL, struct gl_shader_program);
72
73   /* Set default values used by the test cases.
74    */
75   this->actual_index = 1;
76   this->name = "i";
77}
78
79void
80set_uniform_initializer::TearDown()
81{
82   ralloc_free(this->mem_ctx);
83   this->mem_ctx = NULL;
84
85   ralloc_free(this->prog);
86   this->prog = NULL;
87}
88
89/**
90 * Create some uniform storage for a program.
91 *
92 * \param prog          Program to get some storage
93 * \param num_storage   Total number of storage slots
94 * \param index_to_set  Storage slot that will actually get a value
95 * \param name          Name for the actual storage slot
96 * \param type          Type for the elements of the actual storage slot
97 * \param array_size    Size for the array of the actual storage slot.  This
98 *                      should be zero for non-arrays.
99 */
100static unsigned
101establish_uniform_storage(struct gl_shader_program *prog, unsigned num_storage,
102			  unsigned index_to_set, const char *name,
103			  const glsl_type *type, unsigned array_size)
104{
105   const unsigned elements = MAX2(1, array_size);
106   const unsigned data_components = elements * type->components();
107   const unsigned total_components = MAX2(17, (data_components
108					       + type->components()));
109   const unsigned red_zone_components = total_components - data_components;
110
111   prog->UniformStorage = rzalloc_array(prog, struct gl_uniform_storage,
112					num_storage);
113   prog->NumUserUniformStorage = num_storage;
114
115   prog->UniformStorage[index_to_set].name = (char *) name;
116   prog->UniformStorage[index_to_set].type = type;
117   prog->UniformStorage[index_to_set].array_elements = array_size;
118   prog->UniformStorage[index_to_set].initialized = false;
119   prog->UniformStorage[index_to_set].sampler = ~0;
120   prog->UniformStorage[index_to_set].num_driver_storage = 0;
121   prog->UniformStorage[index_to_set].driver_storage = NULL;
122   prog->UniformStorage[index_to_set].storage =
123      rzalloc_array(prog, union gl_constant_value, total_components);
124
125   fill_storage_array_with_sentinels(prog->UniformStorage[index_to_set].storage,
126				     data_components,
127				     red_zone_components);
128
129   for (unsigned i = 0; i < num_storage; i++) {
130      if (i == index_to_set)
131	 continue;
132
133      prog->UniformStorage[i].name = (char *) "invalid slot";
134      prog->UniformStorage[i].type = glsl_type::void_type;
135      prog->UniformStorage[i].array_elements = 0;
136      prog->UniformStorage[i].initialized = false;
137      prog->UniformStorage[i].sampler = ~0;
138      prog->UniformStorage[i].num_driver_storage = 0;
139      prog->UniformStorage[i].driver_storage = NULL;
140      prog->UniformStorage[i].storage = NULL;
141   }
142
143   return red_zone_components;
144}
145
146/**
147 * Verify that the correct uniform is marked as having been initialized.
148 */
149static void
150verify_initialization(struct gl_shader_program *prog, unsigned actual_index)
151{
152   for (unsigned i = 0; i < prog->NumUserUniformStorage; i++) {
153      if (i == actual_index) {
154	 EXPECT_TRUE(prog->UniformStorage[actual_index].initialized);
155      } else {
156	 EXPECT_FALSE(prog->UniformStorage[i].initialized);
157      }
158   }
159}
160
161static void
162non_array_test(void *mem_ctx, struct gl_shader_program *prog,
163	       unsigned actual_index, const char *name,
164	       enum glsl_base_type base_type,
165	       unsigned columns, unsigned rows)
166{
167   const glsl_type *const type =
168      glsl_type::get_instance(base_type, rows, columns);
169
170   unsigned red_zone_components =
171      establish_uniform_storage(prog, 3, actual_index, name, type, 0);
172
173   ir_constant *val;
174   generate_data(mem_ctx, base_type, columns, rows, val);
175
176   linker::set_uniform_initializer(mem_ctx, prog, name, type, val);
177
178   verify_initialization(prog, actual_index);
179   verify_data(prog->UniformStorage[actual_index].storage, 0, val,
180	       red_zone_components);
181}
182
183TEST_F(set_uniform_initializer, int_uniform)
184{
185   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 1);
186}
187
188TEST_F(set_uniform_initializer, ivec2_uniform)
189{
190   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 2);
191}
192
193TEST_F(set_uniform_initializer, ivec3_uniform)
194{
195   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 3);
196}
197
198TEST_F(set_uniform_initializer, ivec4_uniform)
199{
200   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 4);
201}
202
203TEST_F(set_uniform_initializer, uint_uniform)
204{
205   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 1);
206}
207
208TEST_F(set_uniform_initializer, uvec2_uniform)
209{
210   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 2);
211}
212
213TEST_F(set_uniform_initializer, uvec3_uniform)
214{
215   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 3);
216}
217
218TEST_F(set_uniform_initializer, uvec4_uniform)
219{
220   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 4);
221}
222
223TEST_F(set_uniform_initializer, bool_uniform)
224{
225   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 1);
226}
227
228TEST_F(set_uniform_initializer, bvec2_uniform)
229{
230   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 2);
231}
232
233TEST_F(set_uniform_initializer, bvec3_uniform)
234{
235   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 3);
236}
237
238TEST_F(set_uniform_initializer, bvec4_uniform)
239{
240   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 4);
241}
242
243TEST_F(set_uniform_initializer, float_uniform)
244{
245   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 2);
246}
247
248TEST_F(set_uniform_initializer, vec2_uniform)
249{
250   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 2);
251}
252
253TEST_F(set_uniform_initializer, vec3_uniform)
254{
255   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 3);
256}
257
258TEST_F(set_uniform_initializer, vec4_uniform)
259{
260   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 4);
261}
262
263TEST_F(set_uniform_initializer, mat2x2_uniform)
264{
265   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 2);
266}
267
268TEST_F(set_uniform_initializer, mat2x3_uniform)
269{
270   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 3);
271}
272
273TEST_F(set_uniform_initializer, mat2x4_uniform)
274{
275   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 4);
276}
277
278TEST_F(set_uniform_initializer, mat3x2_uniform)
279{
280   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 2);
281}
282
283TEST_F(set_uniform_initializer, mat3x3_uniform)
284{
285   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 3);
286}
287
288TEST_F(set_uniform_initializer, mat3x4_uniform)
289{
290   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 4);
291}
292
293TEST_F(set_uniform_initializer, mat4x2_uniform)
294{
295   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 2);
296}
297
298TEST_F(set_uniform_initializer, mat4x3_uniform)
299{
300   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 3);
301}
302
303TEST_F(set_uniform_initializer, mat4x4_uniform)
304{
305   non_array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 4);
306}
307
308static void
309array_test(void *mem_ctx, struct gl_shader_program *prog,
310	   unsigned actual_index, const char *name,
311	   enum glsl_base_type base_type,
312	   unsigned columns, unsigned rows, unsigned array_size,
313	   unsigned excess_data_size)
314{
315   const glsl_type *const element_type =
316      glsl_type::get_instance(base_type, rows, columns);
317
318   const unsigned red_zone_components =
319      establish_uniform_storage(prog, 3, actual_index, name, element_type,
320				array_size);
321
322   /* The constant value generated may have more array elements than the
323    * uniform that it initializes.  In the real compiler and linker this can
324    * happen when a uniform array is compacted because some of the tail
325    * elements are not used.  In this case, the type of the uniform will be
326    * modified, but the initializer will not.
327    */
328   ir_constant *val;
329   generate_array_data(mem_ctx, base_type, columns, rows,
330		       array_size + excess_data_size, val);
331
332   linker::set_uniform_initializer(mem_ctx, prog, name, element_type, val);
333
334   verify_initialization(prog, actual_index);
335   verify_data(prog->UniformStorage[actual_index].storage, array_size,
336	       val, red_zone_components);
337}
338
339TEST_F(set_uniform_initializer, int_array_uniform)
340{
341   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 1, 4, 0);
342}
343
344TEST_F(set_uniform_initializer, ivec2_array_uniform)
345{
346   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 2, 4, 0);
347}
348
349TEST_F(set_uniform_initializer, ivec3_array_uniform)
350{
351   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 3, 4, 0);
352}
353
354TEST_F(set_uniform_initializer, ivec4_array_uniform)
355{
356   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 4, 4, 0);
357}
358
359TEST_F(set_uniform_initializer, uint_array_uniform)
360{
361   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 1, 4, 0);
362}
363
364TEST_F(set_uniform_initializer, uvec2_array_uniform)
365{
366   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 2, 4, 0);
367}
368
369TEST_F(set_uniform_initializer, uvec3_array_uniform)
370{
371   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 3, 4, 0);
372}
373
374TEST_F(set_uniform_initializer, uvec4_array_uniform)
375{
376   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 4, 4, 0);
377}
378
379TEST_F(set_uniform_initializer, bool_array_uniform)
380{
381   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 1, 4, 0);
382}
383
384TEST_F(set_uniform_initializer, bvec2_array_uniform)
385{
386   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 2, 4, 0);
387}
388
389TEST_F(set_uniform_initializer, bvec3_array_uniform)
390{
391   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 3, 4, 0);
392}
393
394TEST_F(set_uniform_initializer, bvec4_array_uniform)
395{
396   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 4, 4, 0);
397}
398
399TEST_F(set_uniform_initializer, float_array_uniform)
400{
401   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 1, 4, 0);
402}
403
404TEST_F(set_uniform_initializer, vec2_array_uniform)
405{
406   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 2, 4, 0);
407}
408
409TEST_F(set_uniform_initializer, vec3_array_uniform)
410{
411   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 3, 4, 0);
412}
413
414TEST_F(set_uniform_initializer, vec4_array_uniform)
415{
416   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 4, 4, 0);
417}
418
419TEST_F(set_uniform_initializer, mat2x2_array_uniform)
420{
421   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 2, 4, 0);
422}
423
424TEST_F(set_uniform_initializer, mat2x3_array_uniform)
425{
426   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 3, 4, 0);
427}
428
429TEST_F(set_uniform_initializer, mat2x4_array_uniform)
430{
431   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 4, 4, 0);
432}
433
434TEST_F(set_uniform_initializer, mat3x2_array_uniform)
435{
436   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 2, 4, 0);
437}
438
439TEST_F(set_uniform_initializer, mat3x3_array_uniform)
440{
441   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 3, 4, 0);
442}
443
444TEST_F(set_uniform_initializer, mat3x4_array_uniform)
445{
446   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 4, 4, 0);
447}
448
449TEST_F(set_uniform_initializer, mat4x2_array_uniform)
450{
451   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 2, 4, 0);
452}
453
454TEST_F(set_uniform_initializer, mat4x3_array_uniform)
455{
456   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 3, 4, 0);
457}
458
459TEST_F(set_uniform_initializer, mat4x4_array_uniform)
460{
461   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 4, 4, 0);
462}
463
464TEST_F(set_uniform_initializer, int_array_uniform_excess_initializer)
465{
466   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 1, 4, 5);
467}
468
469TEST_F(set_uniform_initializer, ivec2_array_uniform_excess_initializer)
470{
471   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 2, 4, 5);
472}
473
474TEST_F(set_uniform_initializer, ivec3_array_uniform_excess_initializer)
475{
476   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 3, 4, 5);
477}
478
479TEST_F(set_uniform_initializer, ivec4_array_uniform_excess_initializer)
480{
481   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_INT, 1, 4, 4, 5);
482}
483
484TEST_F(set_uniform_initializer, uint_array_uniform_excess_initializer)
485{
486   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 1, 4, 5);
487}
488
489TEST_F(set_uniform_initializer, uvec2_array_uniform_excess_initializer)
490{
491   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 2, 4, 5);
492}
493
494TEST_F(set_uniform_initializer, uvec3_array_uniform_excess_initializer)
495{
496   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 3, 4, 5);
497}
498
499TEST_F(set_uniform_initializer, uvec4_array_uniform_excess_initializer)
500{
501   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_UINT, 1, 4, 4, 5);
502}
503
504TEST_F(set_uniform_initializer, bool_array_uniform_excess_initializer)
505{
506   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 1, 4, 5);
507}
508
509TEST_F(set_uniform_initializer, bvec2_array_uniform_excess_initializer)
510{
511   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 2, 4, 5);
512}
513
514TEST_F(set_uniform_initializer, bvec3_array_uniform_excess_initializer)
515{
516   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 3, 4, 5);
517}
518
519TEST_F(set_uniform_initializer, bvec4_array_uniform_excess_initializer)
520{
521   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_BOOL, 1, 4, 4, 5);
522}
523
524TEST_F(set_uniform_initializer, float_array_uniform_excess_initializer)
525{
526   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 1, 4, 5);
527}
528
529TEST_F(set_uniform_initializer, vec2_array_uniform_excess_initializer)
530{
531   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 2, 4, 5);
532}
533
534TEST_F(set_uniform_initializer, vec3_array_uniform_excess_initializer)
535{
536   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 3, 4, 5);
537}
538
539TEST_F(set_uniform_initializer, vec4_array_uniform_excess_initializer)
540{
541   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 1, 4, 4, 5);
542}
543
544TEST_F(set_uniform_initializer, mat2x2_array_uniform_excess_initializer)
545{
546   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 2, 4, 5);
547}
548
549TEST_F(set_uniform_initializer, mat2x3_array_uniform_excess_initializer)
550{
551   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 3, 4, 5);
552}
553
554TEST_F(set_uniform_initializer, mat2x4_array_uniform_excess_initializer)
555{
556   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 2, 4, 4, 5);
557}
558
559TEST_F(set_uniform_initializer, mat3x2_array_uniform_excess_initializer)
560{
561   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 2, 4, 5);
562}
563
564TEST_F(set_uniform_initializer, mat3x3_array_uniform_excess_initializer)
565{
566   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 3, 4, 5);
567}
568
569TEST_F(set_uniform_initializer, mat3x4_array_uniform_excess_initializer)
570{
571   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 3, 4, 4, 5);
572}
573
574TEST_F(set_uniform_initializer, mat4x2_array_uniform_excess_initializer)
575{
576   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 2, 4, 5);
577}
578
579TEST_F(set_uniform_initializer, mat4x3_array_uniform_excess_initializer)
580{
581   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 3, 4, 5);
582}
583
584TEST_F(set_uniform_initializer, mat4x4_array_uniform_excess_initializer)
585{
586   array_test(mem_ctx, prog, actual_index, name, GLSL_TYPE_FLOAT, 4, 4, 4, 5);
587}
588