17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2019 Ryan Houdek <Sonicadvance1@gmail.com>
37ec681f3Smrg * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
47ec681f3Smrg * Copyright © 2015 Red Hat
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
87ec681f3Smrg * to deal in the Software without restriction, including without limitation
97ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
117ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
127ec681f3Smrg *
137ec681f3Smrg * The above copyright notice and this permission notice (including the next
147ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
157ec681f3Smrg * Software.
167ec681f3Smrg *
177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
227ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
237ec681f3Smrg * SOFTWARE.
247ec681f3Smrg */
257ec681f3Smrg
267ec681f3Smrg#include "main/mtypes.h"
277ec681f3Smrg#include "compiler/glsl/standalone.h"
287ec681f3Smrg#include "compiler/glsl/glsl_to_nir.h"
297ec681f3Smrg#include "compiler/glsl/gl_nir.h"
307ec681f3Smrg#include "compiler/nir_types.h"
317ec681f3Smrg#include "util/u_dynarray.h"
327ec681f3Smrg#include "agx_compile.h"
337ec681f3Smrg#include "agx_minifloat.h"
347ec681f3Smrg
357ec681f3Smrgstatic int
367ec681f3Smrgst_packed_uniforms_type_size(const struct glsl_type *type, bool bindless)
377ec681f3Smrg{
387ec681f3Smrg   return glsl_count_dword_slots(type, bindless);
397ec681f3Smrg}
407ec681f3Smrg
417ec681f3Smrgstatic int
427ec681f3Smrgglsl_type_size(const struct glsl_type *type, bool bindless)
437ec681f3Smrg{
447ec681f3Smrg   return glsl_count_attribute_slots(type, false);
457ec681f3Smrg}
467ec681f3Smrg
477ec681f3Smrgstatic void
487ec681f3Smrginsert_sorted(struct exec_list *var_list, nir_variable *new_var)
497ec681f3Smrg{
507ec681f3Smrg   nir_foreach_variable_in_list (var, var_list) {
517ec681f3Smrg      if (var->data.location > new_var->data.location) {
527ec681f3Smrg         exec_node_insert_node_before(&var->node, &new_var->node);
537ec681f3Smrg         return;
547ec681f3Smrg      }
557ec681f3Smrg   }
567ec681f3Smrg   exec_list_push_tail(var_list, &new_var->node);
577ec681f3Smrg}
587ec681f3Smrg
597ec681f3Smrgstatic void
607ec681f3Smrgsort_varyings(nir_shader *nir, nir_variable_mode mode)
617ec681f3Smrg{
627ec681f3Smrg   struct exec_list new_list;
637ec681f3Smrg   exec_list_make_empty(&new_list);
647ec681f3Smrg   nir_foreach_variable_with_modes_safe (var, nir, mode) {
657ec681f3Smrg      exec_node_remove(&var->node);
667ec681f3Smrg      insert_sorted(&new_list, var);
677ec681f3Smrg   }
687ec681f3Smrg   exec_list_append(&nir->variables, &new_list);
697ec681f3Smrg}
707ec681f3Smrg
717ec681f3Smrgstatic void
727ec681f3Smrgfixup_varying_slots(nir_shader *nir, nir_variable_mode mode)
737ec681f3Smrg{
747ec681f3Smrg   nir_foreach_variable_with_modes (var, nir, mode) {
757ec681f3Smrg      if (var->data.location >= VARYING_SLOT_VAR0) {
767ec681f3Smrg         var->data.location += 9;
777ec681f3Smrg      } else if ((var->data.location >= VARYING_SLOT_TEX0) &&
787ec681f3Smrg                 (var->data.location <= VARYING_SLOT_TEX7)) {
797ec681f3Smrg         var->data.location += VARYING_SLOT_VAR0 - VARYING_SLOT_TEX0;
807ec681f3Smrg      }
817ec681f3Smrg   }
827ec681f3Smrg}
837ec681f3Smrg
847ec681f3Smrgstatic void
857ec681f3Smrgcompile_shader(char **argv)
867ec681f3Smrg{
877ec681f3Smrg   struct gl_shader_program *prog;
887ec681f3Smrg   nir_shader *nir[2];
897ec681f3Smrg   unsigned shader_types[2] = {
907ec681f3Smrg      MESA_SHADER_VERTEX,
917ec681f3Smrg      MESA_SHADER_FRAGMENT,
927ec681f3Smrg   };
937ec681f3Smrg
947ec681f3Smrg   struct standalone_options options = {
957ec681f3Smrg      .glsl_version = 300, /* ES - needed for precision */
967ec681f3Smrg      .do_link = true,
977ec681f3Smrg      .lower_precision = true
987ec681f3Smrg   };
997ec681f3Smrg
1007ec681f3Smrg   static struct gl_context local_ctx;
1017ec681f3Smrg
1027ec681f3Smrg   prog = standalone_compile_shader(&options, 2, argv, &local_ctx);
1037ec681f3Smrg   prog->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program->info.stage = MESA_SHADER_FRAGMENT;
1047ec681f3Smrg
1057ec681f3Smrg   struct util_dynarray binary;
1067ec681f3Smrg
1077ec681f3Smrg   util_dynarray_init(&binary, NULL);
1087ec681f3Smrg
1097ec681f3Smrg   for (unsigned i = 0; i < 2; ++i) {
1107ec681f3Smrg      nir[i] = glsl_to_nir(&local_ctx, prog, shader_types[i], &agx_nir_options);
1117ec681f3Smrg
1127ec681f3Smrg      if (i == 0) {
1137ec681f3Smrg         nir_assign_var_locations(nir[i], nir_var_shader_in, &nir[i]->num_inputs,
1147ec681f3Smrg               glsl_type_size);
1157ec681f3Smrg         sort_varyings(nir[i], nir_var_shader_out);
1167ec681f3Smrg         nir_assign_var_locations(nir[i], nir_var_shader_out, &nir[i]->num_outputs,
1177ec681f3Smrg               glsl_type_size);
1187ec681f3Smrg         fixup_varying_slots(nir[i], nir_var_shader_out);
1197ec681f3Smrg      } else {
1207ec681f3Smrg         sort_varyings(nir[i], nir_var_shader_in);
1217ec681f3Smrg         nir_assign_var_locations(nir[i], nir_var_shader_in, &nir[i]->num_inputs,
1227ec681f3Smrg               glsl_type_size);
1237ec681f3Smrg         fixup_varying_slots(nir[i], nir_var_shader_in);
1247ec681f3Smrg         nir_assign_var_locations(nir[i], nir_var_shader_out, &nir[i]->num_outputs,
1257ec681f3Smrg               glsl_type_size);
1267ec681f3Smrg      }
1277ec681f3Smrg
1287ec681f3Smrg      nir_assign_var_locations(nir[i], nir_var_uniform, &nir[i]->num_uniforms,
1297ec681f3Smrg            glsl_type_size);
1307ec681f3Smrg
1317ec681f3Smrg      NIR_PASS_V(nir[i], nir_lower_global_vars_to_local);
1327ec681f3Smrg      NIR_PASS_V(nir[i], nir_lower_io_to_temporaries, nir_shader_get_entrypoint(nir[i]), true, i == 0);
1337ec681f3Smrg      NIR_PASS_V(nir[i], nir_lower_system_values);
1347ec681f3Smrg      NIR_PASS_V(nir[i], gl_nir_lower_samplers, prog);
1357ec681f3Smrg      NIR_PASS_V(nir[i], nir_split_var_copies);
1367ec681f3Smrg      NIR_PASS_V(nir[i], nir_lower_var_copies);
1377ec681f3Smrg
1387ec681f3Smrg      NIR_PASS_V(nir[i], nir_lower_io, nir_var_uniform,
1397ec681f3Smrg                 st_packed_uniforms_type_size,
1407ec681f3Smrg                 (nir_lower_io_options)0);
1417ec681f3Smrg      NIR_PASS_V(nir[i], nir_lower_uniforms_to_ubo, true, false);
1427ec681f3Smrg
1437ec681f3Smrg      /* before buffers and vars_to_ssa */
1447ec681f3Smrg      NIR_PASS_V(nir[i], gl_nir_lower_images, true);
1457ec681f3Smrg
1467ec681f3Smrg      NIR_PASS_V(nir[i], gl_nir_lower_buffers, prog);
1477ec681f3Smrg      NIR_PASS_V(nir[i], nir_opt_constant_folding);
1487ec681f3Smrg
1497ec681f3Smrg      struct agx_shader_info out = { 0 };
1507ec681f3Smrg      struct agx_shader_key keys[2] = {
1517ec681f3Smrg         {
1527ec681f3Smrg            .vs = {
1537ec681f3Smrg               .num_vbufs = 1,
1547ec681f3Smrg               .vbuf_strides = { 16 },
1557ec681f3Smrg               .attributes = {
1567ec681f3Smrg                  {
1577ec681f3Smrg                     .buf = 0,
1587ec681f3Smrg                     .src_offset = 0,
1597ec681f3Smrg                     .format = AGX_FORMAT_I32,
1607ec681f3Smrg                     .nr_comps_minus_1 = 4 - 1
1617ec681f3Smrg                  }
1627ec681f3Smrg               },
1637ec681f3Smrg            }
1647ec681f3Smrg         },
1657ec681f3Smrg         {
1667ec681f3Smrg            .fs = {
1677ec681f3Smrg               .tib_formats = { AGX_FORMAT_U8NORM }
1687ec681f3Smrg            }
1697ec681f3Smrg         }
1707ec681f3Smrg      };
1717ec681f3Smrg
1727ec681f3Smrg      agx_compile_shader_nir(nir[i], &keys[i], &binary, &out);
1737ec681f3Smrg
1747ec681f3Smrg      char *fn = NULL;
1757ec681f3Smrg      asprintf(&fn, "shader_%u.bin", i);
1767ec681f3Smrg      assert(fn != NULL);
1777ec681f3Smrg      FILE *fp = fopen(fn, "wb");
1787ec681f3Smrg      fwrite(binary.data, 1, binary.size, fp);
1797ec681f3Smrg      fclose(fp);
1807ec681f3Smrg      free(fn);
1817ec681f3Smrg
1827ec681f3Smrg      util_dynarray_clear(&binary);
1837ec681f3Smrg   }
1847ec681f3Smrg
1857ec681f3Smrg   util_dynarray_fini(&binary);
1867ec681f3Smrg}
1877ec681f3Smrg
1887ec681f3Smrgstatic void
1897ec681f3Smrgdisassemble(const char *filename, bool verbose)
1907ec681f3Smrg{
1917ec681f3Smrg   FILE *fp = fopen(filename, "rb");
1927ec681f3Smrg   assert(fp);
1937ec681f3Smrg
1947ec681f3Smrg   fseek(fp, 0, SEEK_END);
1957ec681f3Smrg   unsigned filesize = ftell(fp);
1967ec681f3Smrg   rewind(fp);
1977ec681f3Smrg
1987ec681f3Smrg   uint32_t *code = malloc(filesize);
1997ec681f3Smrg   unsigned res = fread(code, 1, filesize, fp);
2007ec681f3Smrg   if (res != filesize) {
2017ec681f3Smrg      printf("Couldn't read full file\n");
2027ec681f3Smrg   }
2037ec681f3Smrg   fclose(fp);
2047ec681f3Smrg
2057ec681f3Smrg   /* TODO: stub */
2067ec681f3Smrg
2077ec681f3Smrg   free(code);
2087ec681f3Smrg}
2097ec681f3Smrg
2107ec681f3Smrgstatic void
2117ec681f3Smrgtests()
2127ec681f3Smrg{
2137ec681f3Smrg#ifndef NDEBUG
2147ec681f3Smrg   agx_minifloat_tests();
2157ec681f3Smrg   printf("Pass.\n");
2167ec681f3Smrg#else
2177ec681f3Smrg   fprintf(stderr, "tests not compiled in NDEBUG mode");
2187ec681f3Smrg#endif
2197ec681f3Smrg}
2207ec681f3Smrg
2217ec681f3Smrgint
2227ec681f3Smrgmain(int argc, char **argv)
2237ec681f3Smrg{
2247ec681f3Smrg   if (argc < 2) {
2257ec681f3Smrg      printf("Pass a command\n");
2267ec681f3Smrg      exit(1);
2277ec681f3Smrg   }
2287ec681f3Smrg
2297ec681f3Smrg   if (strcmp(argv[1], "compile") == 0)
2307ec681f3Smrg      compile_shader(&argv[2]);
2317ec681f3Smrg   else if (strcmp(argv[1], "disasm") == 0)
2327ec681f3Smrg      disassemble(argv[2], false);
2337ec681f3Smrg   else if (strcmp(argv[1], "disasm-verbose") == 0)
2347ec681f3Smrg      disassemble(argv[2], true);
2357ec681f3Smrg   else if (strcmp(argv[1], "test") == 0)
2367ec681f3Smrg      tests();
2377ec681f3Smrg   else
2387ec681f3Smrg      unreachable("Unknown command. Valid: compile/disasm/disasm-verbose");
2397ec681f3Smrg
2407ec681f3Smrg   return 0;
2417ec681f3Smrg}
242