xref: /aosp_15_r20/external/mesa3d/src/compiler/glsl/tests/test_gl_lower_mediump.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2023 Google LLC
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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <gtest/gtest.h>
25 #include <gtest/gtest-spi.h>
26 
27 #include "main/mtypes.h"
28 #include "standalone_scaffolding.h"
29 #include "ir.h"
30 #include "ir_optimization.h"
31 #include "nir.h"
32 #include "builtin_functions.h"
33 #include "nir.h"
34 #include "gl_nir.h"
35 #include "gl_nir_linker.h"
36 #include "glsl_to_nir.h"
37 #include "nir_builder.h"
38 #include "program.h"
39 
40 /* The printed-GLSL-IR tests use fmemopen so we can do stdio to memory (or you'd
41  * need equivalent tempfiles that you manage).  Just disable this test on those
42  * platforms (aka Windows).
43  */
44 #ifdef HAVE_FMEMOPEN
45 
46 namespace
47 {
48    class gl_nir_lower_mediump_test : public ::testing::Test
49    {
50    protected:
51       gl_nir_lower_mediump_test();
52       ~gl_nir_lower_mediump_test();
53 
54       struct gl_shader *compile_shader(GLenum type, const char *source);
55       void compile(const char *source);
56 
57       struct gl_context local_ctx;
58       struct gl_context *ctx;
59 
find_op(nir_op op)60       nir_alu_instr *find_op(nir_op op)
61       {
62          if (!nir)
63             return NULL;
64 
65          nir_foreach_function_impl(impl, nir)
66          {
67             nir_foreach_block(block, impl)
68             {
69                nir_foreach_instr(instr, block)
70                {
71                   if (instr->type == nir_instr_type_alu)
72                   {
73                      nir_alu_instr *alu = nir_instr_as_alu(instr);
74                      if (alu->op == op)
75                         return alu;
76                   }
77                }
78             }
79          }
80          return NULL;
81       }
82 
op_dest_bits(nir_op op)83       uint32_t op_dest_bits(nir_op op)
84       {
85          nir_alu_instr *alu = find_op(op);
86          EXPECT_TRUE(alu != NULL);
87          return alu->def.bit_size;
88       }
89 
get_fs_ir(void)90       char *get_fs_ir(void) {
91          char temp[4096];
92          FILE *ftemp = fmemopen(temp, sizeof(temp), "w");
93          _mesa_print_ir(ftemp, whole_program->_LinkedShaders[MESA_SHADER_FRAGMENT]->ir, NULL);
94          fclose(ftemp);
95          return strdup(temp);
96       }
97 
98       /* Returns the common bit size of all src operands (failing if not matching). */
op_src_bits(nir_op op)99       uint32_t op_src_bits(nir_op op)
100       {
101          nir_alu_instr *alu = find_op(op);
102          EXPECT_TRUE(alu != NULL);
103 
104          for (int i = 0; i < nir_op_infos[op].num_inputs; i++) {
105             EXPECT_EQ(alu->src[i].src.ssa->bit_size, alu->src[0].src.ssa->bit_size);
106          }
107          return alu->src[0].src.ssa->bit_size;
108       }
109 
110       nir_shader *nir;
111       struct gl_shader_program *whole_program;
112       const char *source;
113       char *fs_ir;
114    };
115 
gl_nir_lower_mediump_test()116    gl_nir_lower_mediump_test::gl_nir_lower_mediump_test()
117        : nir(NULL), source(NULL), fs_ir(NULL)
118    {
119       glsl_type_singleton_init_or_ref();
120    }
121 
~gl_nir_lower_mediump_test()122    gl_nir_lower_mediump_test::~gl_nir_lower_mediump_test()
123    {
124       if (HasFailure())
125       {
126          if (source)
127             printf("\nSource for the failed test:\n%s\n", source);
128          if (fs_ir) {
129             printf("\nGLSL IR from the failed test:\n\n");
130             printf("%s", fs_ir);
131 
132          }
133          if (nir) {
134             printf("\nNIR from the failed test:\n\n");
135             nir_print_shader(nir, stdout);
136          }
137       }
138 
139       ralloc_free(whole_program->_LinkedShaders[MESA_SHADER_VERTEX]->Program->nir);
140       standalone_destroy_shader_program(whole_program);
141 
142       ralloc_free(nir);
143 
144       free(fs_ir);
145 
146       glsl_type_singleton_decref();
147    }
148 
149    struct gl_shader *
compile_shader(GLenum type,const char * source)150    gl_nir_lower_mediump_test::compile_shader(GLenum type, const char *source)
151    {
152       struct gl_shader *shader = standalone_add_shader_source(ctx, whole_program, type, source);
153 
154       _mesa_glsl_compile_shader(ctx, shader, false, false, true);
155 
156       return shader;
157    }
158 
159    void
compile(const char * source)160    gl_nir_lower_mediump_test::compile(const char *source)
161    {
162       ctx = &local_ctx;
163 
164       static const struct nir_shader_compiler_options compiler_options = {
165           .support_16bit_alu = true,
166       };
167 
168       /* Get better variable names from GLSL IR for debugging. */
169       ir_variable::temporaries_allocate_names = true;
170 
171       initialize_context_to_defaults(ctx, API_OPENGLES2);
172       ctx->Version = 31;
173       for (int i = 0; i < MESA_SHADER_STAGES; i++) {
174          ctx->Const.ShaderCompilerOptions[i].LowerPrecisionFloat16 = true;
175          ctx->Const.ShaderCompilerOptions[i].LowerPrecisionInt16 = true;
176          ctx->Const.ShaderCompilerOptions[i].NirOptions = &compiler_options;
177       }
178 
179       /* GL_ARB_explicit_uniform_location, GL_MAX_UNIFORM_LOCATIONS */
180       ctx->Const.MaxUserAssignableUniformLocations =
181          4 * MESA_SHADER_STAGES * MAX_UNIFORMS;
182 
183       ctx->Const.Program[MESA_SHADER_VERTEX].MaxCombinedUniformComponents = 128 * 4;
184       ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxCombinedUniformComponents = 16 * 4;
185 
186       _mesa_glsl_builtin_functions_init_or_ref();
187 
188       whole_program = standalone_create_shader_program();
189       whole_program->IsES = true;
190 
191       const char *vs_source = R"(#version 310 es
192       void main() {
193          gl_Position = vec4(0.0);
194       })";
195       compile_shader(GL_VERTEX_SHADER, vs_source);
196 
197       compile_shader(GL_FRAGMENT_SHADER, source);
198 
199       for (unsigned i = 0; i < whole_program->NumShaders; i++)
200       {
201          struct gl_shader *shader = whole_program->Shaders[i];
202          if (shader->CompileStatus != COMPILE_SUCCESS)
203             fprintf(stderr, "Compiler error: %s", shader->InfoLog);
204          ASSERT_EQ(shader->CompileStatus, COMPILE_SUCCESS);
205       }
206 
207       link_shaders(ctx, whole_program);
208       if (whole_program->data->LinkStatus != LINKING_SUCCESS)
209          fprintf(stderr, "Linker error: %s", whole_program->data->InfoLog);
210       EXPECT_EQ(whole_program->data->LinkStatus, LINKING_SUCCESS);
211 
212       /* Save off the GLSL IR now, since glsl_to_nir() frees it. */
213       fs_ir = get_fs_ir();
214 
215       struct gl_linked_shader *sh = whole_program->_LinkedShaders[MESA_SHADER_VERTEX];
216       sh->Program->nir = glsl_to_nir(&ctx->Const, &sh->ir, &sh->Program->info,
217                                      MESA_SHADER_VERTEX, &compiler_options);
218 
219       sh = whole_program->_LinkedShaders[MESA_SHADER_FRAGMENT];
220       sh->Program->nir = glsl_to_nir(&ctx->Const, &sh->ir, &sh->Program->info,
221                                      MESA_SHADER_FRAGMENT, &compiler_options);
222       nir = sh->Program->nir;
223 
224       gl_nir_link_glsl(ctx, whole_program);
225       if (whole_program->data->LinkStatus != LINKING_SUCCESS)
226          fprintf(stderr, "Linker error: %s", whole_program->data->InfoLog);
227       EXPECT_EQ(whole_program->data->LinkStatus, LINKING_SUCCESS);
228 
229       /* Store the source for printing from later assertions. */
230       this->source = source;
231    }
232 
233    // A predicate-formatter for asserting that two integers are mutually prime.
glsl_ir_contains(const char * glsl_ir_expr,const char * needle_expr,const char * glsl_ir,const char * needle)234    testing::AssertionResult glsl_ir_contains(const char *glsl_ir_expr,
235                                              const char *needle_expr,
236                                              const char *glsl_ir,
237                                              const char *needle)
238    {
239       /* If we didn't HAVE_FMEMOPEN, we won't have GLSL IR to look at.  Just
240        * skip those parts of the tests on such platforms.
241        */
242       if (!glsl_ir)
243          return testing::AssertionSuccess();
244 
245       if (strstr(glsl_ir, needle))
246          return testing::AssertionSuccess();
247 
248       return testing::AssertionFailure() << " " << needle_expr << " not found in GLSL IR";
249    }
250 } // namespace
251 
TEST_F(gl_nir_lower_mediump_test,float_simple_mul)252 TEST_F(gl_nir_lower_mediump_test, float_simple_mul)
253 {
254    ASSERT_NO_FATAL_FAILURE(compile(
255        R"(#version 310 es
256          uniform mediump float a, b;
257          out mediump float result;
258 
259          void main()
260          {
261             result = a * b;
262          }
263     )"));
264 
265    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
266 }
267 
TEST_F(gl_nir_lower_mediump_test,int_simple_mul)268 TEST_F(gl_nir_lower_mediump_test, int_simple_mul)
269 {
270    ASSERT_NO_FATAL_FAILURE(compile(
271        R"(#version 310 es
272          precision highp float;
273          precision mediump int;
274          uniform mediump int a, b;
275          out mediump int result;
276 
277          void main()
278          {
279             result = a * b;
280          }
281     )"));
282 
283    EXPECT_EQ(op_dest_bits(nir_op_imul), 16);
284 }
285 
TEST_F(gl_nir_lower_mediump_test,int_default_precision_med)286 TEST_F(gl_nir_lower_mediump_test, int_default_precision_med)
287 {
288    ASSERT_NO_FATAL_FAILURE(compile(
289        R"(#version 310 es
290          precision highp float;
291          precision mediump int;
292          uniform int a, b;
293          out int result;
294 
295          void main()
296          {
297             result = a * b;
298          }
299     )"));
300 
301    EXPECT_EQ(op_dest_bits(nir_op_imul), 16);
302 }
303 
TEST_F(gl_nir_lower_mediump_test,int_default_precision_high)304 TEST_F(gl_nir_lower_mediump_test, int_default_precision_high)
305 {
306    ASSERT_NO_FATAL_FAILURE(compile(
307        R"(#version 310 es
308          precision mediump float;
309          precision highp int;
310          uniform int a, b;
311          out int result;
312 
313          void main()
314          {
315             result = a * b;
316          }
317     )"));
318 
319    EXPECT_EQ(op_dest_bits(nir_op_imul), 32);
320 }
321 
322 /* Test that a builtin with mediump args does mediump computation. */
TEST_F(gl_nir_lower_mediump_test,dot_builtin)323 TEST_F(gl_nir_lower_mediump_test, dot_builtin)
324 {
325    ASSERT_NO_FATAL_FAILURE(compile(
326        R"(#version 310 es
327          precision highp float;
328          precision highp int;
329          uniform mediump vec4 a, b;
330          out float result;
331 
332          void main()
333          {
334             result = dot(a, b);
335          }
336     )"));
337 
338    EXPECT_EQ(op_dest_bits(nir_op_fdot4), 16);
339 }
340 
341 /* Test that a constant-index array deref is mediump */
TEST_F(gl_nir_lower_mediump_test,array_const_index)342 TEST_F(gl_nir_lower_mediump_test, array_const_index)
343 {
344    ASSERT_NO_FATAL_FAILURE(compile(
345        R"(#version 310 es
346          precision highp float;
347          precision highp int;
348          uniform mediump float a, b[2];
349          out float result;
350 
351          void main()
352          {
353             result = a * b[1];
354          }
355     )"));
356 
357    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
358 }
359 
360 /* Test that a variable-index array deref is mediump, even if the array index is highp */
TEST_F(gl_nir_lower_mediump_test,array_uniform_index)361 TEST_F(gl_nir_lower_mediump_test, array_uniform_index)
362 {
363    ASSERT_NO_FATAL_FAILURE(compile(
364        R"(#version 310 es
365          precision highp float;
366          uniform mediump float a, b[2];
367          uniform highp int i;
368          out float result;
369 
370          void main()
371          {
372             result = a * b[i];
373          }
374     )"));
375 
376    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
377 }
378 
379 /* Test that a variable-index array deref is highp, even if the array index is mediump */
TEST_F(gl_nir_lower_mediump_test,array_mediump_index)380 TEST_F(gl_nir_lower_mediump_test, array_mediump_index)
381 {
382    ASSERT_NO_FATAL_FAILURE(compile(
383        R"(#version 310 es
384          precision highp float;
385          uniform highp int b[2];
386          uniform mediump int a, i;
387          out highp int result;
388 
389          void main()
390          {
391             result = a * b[i];
392          }
393     )"));
394 
395    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression int * ");
396 
397    EXPECT_EQ(op_dest_bits(nir_op_imul), 32);
398 }
399 
TEST_F(gl_nir_lower_mediump_test,func_return)400 TEST_F(gl_nir_lower_mediump_test, func_return)
401 {
402    ASSERT_NO_FATAL_FAILURE(compile(
403        R"(#version 310 es
404          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump return. */
405          uniform mediump float a;
406          uniform highp float b;
407          out float result;
408 
409          mediump float func()
410          {
411             return b; /* Returning highp b here, but it should be the mediump return value qualifier that matters */
412          }
413 
414          void main()
415          {
416             /* "If a function returns a value, then a call to that function may
417              *  be used as an expression, whose type will be the type that was
418              *  used to declare or define the function."
419              */
420             result = a * func();
421          }
422     )"));
423 
424    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t * ");
425 
426    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
427 }
428 
TEST_F(gl_nir_lower_mediump_test,func_args_in_mediump)429 TEST_F(gl_nir_lower_mediump_test, func_args_in_mediump)
430 {
431    ASSERT_NO_FATAL_FAILURE(compile(
432        R"(#version 310 es
433          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump return. */
434          uniform highp float a, b;
435          out highp float result;
436 
437          highp float func(mediump float x, mediump float y)
438          {
439             return x * y; /* should be mediump due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
440          }
441 
442          void main()
443          {
444             result = func(a, b);
445          }
446     )"));
447 
448    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float f162f (expression float16_t * (expression float16_t f2fmp (var_ref x) ) (expression float16_t f2fmp (var_ref y) ) )");
449 
450    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
451 }
452 
TEST_F(gl_nir_lower_mediump_test,func_args_inout_mediump)453 TEST_F(gl_nir_lower_mediump_test, func_args_inout_mediump)
454 {
455    ASSERT_NO_FATAL_FAILURE(compile(
456        R"(#version 310 es
457          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump inout. */
458          uniform highp float a, b;
459          out float result;
460 
461          void func(inout mediump float x, mediump float y)
462          {
463             x = x * y; /* should be mediump due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
464          }
465 
466          void main()
467          {
468             /* The spec says "function input and output is done through copies,
469              * and therefore qualifiers do not have to match."  So we use a
470              * highp here for our mediump inout.
471              */
472             highp float x = a;
473             func(x, b);
474             result = x;
475          }
476     )"));
477 
478    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t * ");
479 
480    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
481 }
482 
TEST_F(gl_nir_lower_mediump_test,func_args_in_out_mediump)483 TEST_F(gl_nir_lower_mediump_test, func_args_in_out_mediump)
484 {
485    ASSERT_NO_FATAL_FAILURE(compile(
486        R"(#version 310 es
487          precision highp float; /* Make sure that default highp temps in function handling don't break our mediump inout. */
488          uniform highp float a, b;
489          out float result;
490 
491          void func(mediump float x, mediump float y, out mediump float w)
492          {
493             w = x * y; /* should be mediump due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
494          }
495 
496          void main()
497          {
498             /* The spec says "function input and output is done through copies,
499              * and therefore qualifiers do not have to match."  So we use a
500              * highp here for our mediump out.
501              */
502             highp float x;
503             func(a, b, x);
504             result = x;
505          }
506     )"));
507 
508    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t * ");
509 
510    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
511 }
512 
TEST_F(gl_nir_lower_mediump_test,func_args_inout_highp)513 TEST_F(gl_nir_lower_mediump_test, func_args_inout_highp)
514 {
515    ASSERT_NO_FATAL_FAILURE(compile(
516        R"(#version 310 es
517          precision mediump float; /* Make sure that default mediump temps in function handling don't break our highp inout. */
518          uniform mediump float a, b;
519          out float result;
520 
521          void func(inout highp float x, highp float y)
522          {
523             x = x * y; /* should be highp due to x and y, but propagating qualifiers from a,b by inlining could trick it. */
524          }
525 
526          void main()
527          {
528             mediump float x = a;
529             func(x, b);
530             result = x;
531          }
532     )"));
533 
534    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float * ");
535 
536    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
537 }
538 
TEST_F(gl_nir_lower_mediump_test,if_mediump)539 TEST_F(gl_nir_lower_mediump_test, if_mediump)
540 {
541    ASSERT_NO_FATAL_FAILURE(compile(
542        R"(#version 310 es
543          precision highp float;
544          uniform mediump float a, b, c;
545          out float result;
546 
547          void main()
548          {
549             if (a * b < c)
550                result = 1.0;
551             else
552                result = 0.0;
553          }
554     )"));
555 
556    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
557    EXPECT_EQ(op_src_bits(nir_op_flt), 16);
558 }
559 
TEST_F(gl_nir_lower_mediump_test,mat_mul_mediump)560 TEST_F(gl_nir_lower_mediump_test, mat_mul_mediump)
561 {
562    ASSERT_NO_FATAL_FAILURE(compile(
563        R"(#version 310 es
564          precision highp float;
565          uniform mediump mat2 a;
566          uniform mediump vec2 b;
567          out highp vec2 result;
568 
569          void main()
570          {
571             result = a * b;
572          }
573     )"));
574 
575    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
576 }
577 
TEST_F(gl_nir_lower_mediump_test,struct_default_precision_lvalue)578 TEST_F(gl_nir_lower_mediump_test, struct_default_precision_lvalue)
579 {
580    ASSERT_NO_FATAL_FAILURE(compile(
581        R"(#version 310 es
582          precision highp float;
583          precision mediump int;
584          struct S {
585             float x, y;
586             int z, w;
587          };
588          uniform S a;
589          out mediump vec2 result;
590 
591          void main()
592          {
593             /* I believe that structure members don't have a precision
594              * qualifier, so we expect the precision of these operations to come
595              * from the lvalue (which is higher precedence than the default
596              * precision).
597              */
598             mediump float resultf = a.x * a.y;
599             highp int resulti = a.z * a.w;
600             result = vec2(resultf, float(resulti));
601          }
602     )"));
603 
604    /* GLSL fails to implement this correctly. */
605    EXPECT_NONFATAL_FAILURE(
606        EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir,
607                            "expression float16_t * (record_ref (var_ref a)  x) (record_ref (var_ref a)  y) "),
608        "not found in GLSL IR");
609    EXPECT_NONFATAL_FAILURE(
610        EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir,
611                            "expression int * (record_ref (var_ref a)  z) (record_ref (var_ref a)  w) "),
612        "not found in GLSL IR");
613 
614    // Enable these checks once we fix the GLSL.
615    //EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
616    //EXPECT_EQ(op_dest_bits(nir_op_imul), 32);
617 }
618 
TEST_F(gl_nir_lower_mediump_test,float_constructor)619 TEST_F(gl_nir_lower_mediump_test, float_constructor)
620 {
621    ASSERT_NO_FATAL_FAILURE(compile(
622        R"(#version 310 es
623          precision mediump float;
624          uniform highp uint a;
625          uniform mediump float b;
626          out mediump float result;
627 
628          void main()
629          {
630             /* It's tricky to reconcile these two bits of spec: "Literal
631              * constants do not have precision qualifiers. Neither do Boolean
632              * variables. Neither do constructors."
633              *
634              * and
635              *
636              * "For this paragraph, “operationincludes operators, built-in
637              * functions, and constructors, andoperandincludes function
638              * arguments and constructor arguments."
639              *
640              * I take this to mean that the language doesn't let you put a
641              * precision qualifier on a constructor (or literal), but the
642              * constructor operation gets precision qualification inference
643              * based on its args like normal.
644              */
645             result = float(a) * b;
646          }
647     )"));
648 
649    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
650 }
651 
TEST_F(gl_nir_lower_mediump_test,vec2_constructor)652 TEST_F(gl_nir_lower_mediump_test, vec2_constructor)
653 {
654    ASSERT_NO_FATAL_FAILURE(compile(
655        R"(#version 310 es
656          precision mediump float;
657          uniform highp float a, b;
658          uniform mediump float c;
659          out mediump vec2 result;
660 
661          void main()
662          {
663             result = c * vec2(a, b);
664          }
665     )"));
666 
667    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
668 }
TEST_F(gl_nir_lower_mediump_test,vec4_of_float_constructor)669 TEST_F(gl_nir_lower_mediump_test, vec4_of_float_constructor)
670 {
671    ASSERT_NO_FATAL_FAILURE(compile(
672        R"(#version 310 es
673          precision mediump float;
674          uniform highp float a;
675          uniform mediump float b;
676          out mediump vec4 result;
677 
678          void main()
679          {
680             result = b * vec4(a);
681          }
682     )"));
683 
684    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
685 }
686 
TEST_F(gl_nir_lower_mediump_test,vec4_of_vec2_constructor)687 TEST_F(gl_nir_lower_mediump_test, vec4_of_vec2_constructor)
688 {
689    ASSERT_NO_FATAL_FAILURE(compile(
690        R"(#version 310 es
691          precision mediump float;
692          uniform highp vec2 a, b;
693          uniform mediump vec4 c;
694          out mediump vec4 result;
695 
696          void main()
697          {
698             /* GLSL IR has to either have a temp for a*b, or clone the
699              * expression and let it get CSEed later.  If it chooses temp, that
700              * may confuse us.
701              */
702             result = c + vec4(a * b, 0.0, 0.0);
703          }
704     )"));
705 
706    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
707    EXPECT_EQ(op_dest_bits(nir_op_fadd), 32);
708 }
709 
TEST_F(gl_nir_lower_mediump_test,float_literal_mediump)710 TEST_F(gl_nir_lower_mediump_test, float_literal_mediump)
711 {
712    ASSERT_NO_FATAL_FAILURE(compile(
713        R"(#version 310 es
714          precision highp float;
715          uniform mediump float a;
716          out highp float result;
717 
718          void main()
719          {
720             /* The literal is unqualified, so it shouldn't promote the expression to highp. */
721             result = a * 2.0;
722          }
723     )"));
724 
725    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
726 }
727 
TEST_F(gl_nir_lower_mediump_test,float_const_highp)728 TEST_F(gl_nir_lower_mediump_test, float_const_highp)
729 {
730    ASSERT_NO_FATAL_FAILURE(compile(
731        R"(#version 310 es
732          precision highp float;
733          uniform mediump float a;
734          out highp float result;
735 
736          void main()
737          {
738             highp float two = 2.0;
739             /* The constant is highp, so even with constant propagation the expression should be highp. */
740             result = a * two;
741          }
742     )"));
743 
744    EXPECT_EQ(op_dest_bits(nir_op_fmul), 32);
745 }
746 
TEST_F(gl_nir_lower_mediump_test,float_const_expr_mediump)747 TEST_F(gl_nir_lower_mediump_test, float_const_expr_mediump)
748 {
749    ASSERT_NO_FATAL_FAILURE(compile(
750        R"(#version 310 es
751          precision highp float;
752          uniform mediump float a;
753          out highp float result;
754 
755          void main()
756          {
757             /* "Where the precision of a constant integral or constant floating
758              * point expression is not specified, evaluation is performed at
759              * highp. This rule does not affect the precision qualification of the
760              * expression."
761              * So the 5.0 is calculated at highp, but a * 5.0 is calculated at mediump.
762              */
763             result = a * (2.0 + 3.0);
764          }
765     )"));
766 
767    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
768 }
769 
TEST_F(gl_nir_lower_mediump_test,unpackUnorm4x8)770 TEST_F(gl_nir_lower_mediump_test, unpackUnorm4x8)
771 {
772    ASSERT_NO_FATAL_FAILURE(compile(
773        R"(#version 310 es
774          precision highp float;
775          uniform highp uint a;
776          uniform mediump float b;
777          out highp float result;
778 
779          void main()
780          {
781             result = unpackUnorm4x8(a).x * b;
782          }
783     )"));
784 
785    /* XXX: GLSL doesn't lower this one correctly, currently.  It returns highp despite the prototype being mediump. */
786    EXPECT_NONFATAL_FAILURE(
787       EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression f16vec4 unpackUnorm4x8 (var_ref a"),
788       "not found in GLSL IR");
789    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression float16_t *");
790 
791    /* XXX: NIR insists that nir_op_unpack_unorm_4x8 returns 32 bits per channel, too. */
792    EXPECT_NONFATAL_FAILURE(
793       EXPECT_EQ(op_dest_bits(nir_op_unpack_unorm_4x8), 16),
794       "op_dest_bits");
795    EXPECT_EQ(op_dest_bits(nir_op_fmul), 16);
796 }
797 
TEST_F(gl_nir_lower_mediump_test,packUnorm4x8)798 TEST_F(gl_nir_lower_mediump_test, packUnorm4x8)
799 {
800    ASSERT_NO_FATAL_FAILURE(compile(
801        R"(#version 310 es
802          precision highp float;
803          uniform mediump vec4 a;
804          uniform mediump uint b;
805          out highp uint result;
806 
807          void main()
808          {
809             result = packUnorm4x8(a) & b;
810          }
811     )"));
812 
813    /* Test both the GLSL IR return value and an op using it with a mediump
814     * value, so we can be sure it's not just that we're assigning to highp.
815     */
816    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression uint packUnorm4x8 (var_ref a)");
817    EXPECT_PRED_FORMAT2(glsl_ir_contains, fs_ir, "expression uint &");
818 
819    EXPECT_EQ(op_dest_bits(nir_op_pack_unorm_4x8), 32);
820 }
821 
822 /* XXX: Add unit tests getting at precision of temporaries inside builtin function impls. */
823 /* XXX: Add unit tests getting at precision of any other temps internally generated by the compiler */
824 /* XXX: Add unit tests checking for default precision on user-declared function temps*/
825 
826 #endif /* HAVE_FMEMOPEN */
827