1/*
2 * Copyright (c) 2017 Lima Project
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, sub license,
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
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the 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 NON-INFRINGEMENT. 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 */
24
25#include <err.h>
26#include <stdio.h>
27#include <string.h>
28
29#include "main/mtypes.h"
30
31#include "compiler/glsl/standalone.h"
32#include "compiler/glsl/glsl_to_nir.h"
33#include "compiler/glsl/gl_nir.h"
34#include "compiler/nir_types.h"
35
36#include "lima_context.h"
37#include "lima_program.h"
38#include "ir/lima_ir.h"
39#include "standalone/glsl.h"
40
41static void
42print_usage(void)
43{
44   printf("Usage: lima_compiler [OPTIONS]... FILE\n");
45   printf("    --help            - show this message\n");
46}
47
48static void
49insert_sorted(struct exec_list *var_list, nir_variable *new_var)
50{
51   nir_foreach_variable_in_list(var, var_list) {
52      if (var->data.location > new_var->data.location &&
53          new_var->data.location >= 0) {
54         exec_node_insert_node_before(&var->node, &new_var->node);
55         return;
56      }
57   }
58   exec_list_push_tail(var_list, &new_var->node);
59}
60
61static void
62sort_varyings(nir_shader *nir, nir_variable_mode mode)
63{
64   struct exec_list new_list;
65   exec_list_make_empty(&new_list);
66   nir_foreach_variable_with_modes_safe(var, nir, mode) {
67      exec_node_remove(&var->node);
68      insert_sorted(&new_list, var);
69   }
70   exec_list_append(&nir->variables, &new_list);
71}
72
73static void
74fixup_varying_slots(nir_shader *nir, nir_variable_mode mode)
75{
76   nir_foreach_variable_with_modes(var, nir, mode) {
77      if (var->data.location >= VARYING_SLOT_VAR0) {
78         var->data.location += 9;
79      } else if ((var->data.location >= VARYING_SLOT_TEX0) &&
80                 (var->data.location <= VARYING_SLOT_TEX7)) {
81         var->data.location += VARYING_SLOT_VAR0 - VARYING_SLOT_TEX0;
82      }
83   }
84}
85
86static nir_shader *
87load_glsl(unsigned num_files, char* const* files, gl_shader_stage stage)
88{
89   static const struct standalone_options options = {
90      .glsl_version = 110,
91      .do_link = false,
92   };
93   unsigned shader = 0;
94   switch (stage) {
95   case MESA_SHADER_FRAGMENT:
96      shader = PIPE_SHADER_FRAGMENT;
97      break;
98   case MESA_SHADER_VERTEX:
99      shader = PIPE_SHADER_VERTEX;
100      break;
101   default:
102      unreachable("bad stage");
103   }
104   struct gl_shader_program *prog;
105   const nir_shader_compiler_options *nir_options =
106      lima_program_get_compiler_options(shader);
107   static struct gl_context local_ctx;
108
109   prog = standalone_compile_shader(&options, num_files, files, &local_ctx);
110   if (!prog)
111      errx(1, "couldn't parse `%s'", files[0]);
112
113   lima_do_glsl_optimizations(prog->_LinkedShaders[stage]->ir);
114
115   nir_shader *nir = glsl_to_nir(&local_ctx, prog, stage, nir_options);
116
117   /* required NIR passes: */
118   if (nir_options->lower_all_io_to_temps ||
119       nir->info.stage == MESA_SHADER_VERTEX ||
120       nir->info.stage == MESA_SHADER_GEOMETRY) {
121      NIR_PASS_V(nir, nir_lower_io_to_temporaries,
122                 nir_shader_get_entrypoint(nir),
123                 true, true);
124   } else if (nir->info.stage == MESA_SHADER_FRAGMENT) {
125      NIR_PASS_V(nir, nir_lower_io_to_temporaries,
126                 nir_shader_get_entrypoint(nir),
127                 true, false);
128   }
129
130   NIR_PASS_V(nir, nir_lower_global_vars_to_local);
131   NIR_PASS_V(nir, nir_split_var_copies);
132   NIR_PASS_V(nir, nir_lower_var_copies);
133
134   NIR_PASS_V(nir, nir_split_var_copies);
135   NIR_PASS_V(nir, nir_lower_var_copies);
136   nir_print_shader(nir, stdout);
137   NIR_PASS_V(nir, gl_nir_lower_atomics, prog, true);
138   NIR_PASS_V(nir, nir_lower_atomics_to_ssbo);
139   nir_print_shader(nir, stdout);
140
141   switch (stage) {
142   case MESA_SHADER_VERTEX:
143      nir_assign_var_locations(nir, nir_var_shader_in, &nir->num_inputs,
144                               st_glsl_type_size);
145
146      /* Re-lower global vars, to deal with any dead VS inputs. */
147      NIR_PASS_V(nir, nir_lower_global_vars_to_local);
148
149      sort_varyings(nir, nir_var_shader_out);
150      nir_assign_var_locations(nir, nir_var_shader_out, &nir->num_outputs,
151                               st_glsl_type_size);
152      fixup_varying_slots(nir, nir_var_shader_out);
153      break;
154   case MESA_SHADER_FRAGMENT:
155      sort_varyings(nir, nir_var_shader_in);
156      nir_assign_var_locations(nir, nir_var_shader_in, &nir->num_inputs,
157                               st_glsl_type_size);
158      fixup_varying_slots(nir, nir_var_shader_in);
159      nir_assign_var_locations(nir, nir_var_shader_out, &nir->num_outputs,
160                               st_glsl_type_size);
161      break;
162   default:
163      errx(1, "unhandled shader stage: %d", stage);
164   }
165
166   nir_assign_var_locations(nir, nir_var_uniform,
167                            &nir->num_uniforms,
168                            st_glsl_type_size);
169
170   NIR_PASS_V(nir, nir_lower_system_values);
171   NIR_PASS_V(nir, nir_lower_frexp);
172   NIR_PASS_V(nir, gl_nir_lower_samplers, prog);
173
174   return nir;
175}
176
177int
178main(int argc, char **argv)
179{
180   int n;
181
182   lima_debug = LIMA_DEBUG_GP | LIMA_DEBUG_PP;
183
184   if (argc < 2) {
185      print_usage();
186      return 1;
187   }
188
189   for (n = 1; n < argc; n++) {
190      if (!strcmp(argv[n], "--help")) {
191         print_usage();
192         return 1;
193      }
194
195      break;
196   }
197
198   char *filename[10] = {0};
199   filename[0] = argv[n];
200
201   char *ext = rindex(filename[0], '.');
202   unsigned stage = 0;
203
204   if (!strcmp(ext, ".frag")) {
205      stage = MESA_SHADER_FRAGMENT;
206   }
207   else if (!strcmp(ext, ".vert")) {
208      stage = MESA_SHADER_VERTEX;
209   }
210   else {
211      print_usage();
212      return -1;
213   }
214
215   struct nir_lower_tex_options tex_options = {
216      .lower_txp = ~0u,
217   };
218
219   nir_shader *nir = load_glsl(1, filename, stage);
220
221   switch (stage) {
222   case MESA_SHADER_VERTEX:
223      lima_program_optimize_vs_nir(nir);
224
225      nir_print_shader(nir, stdout);
226
227      struct lima_vs_compiled_shader *vs = ralloc(nir, struct lima_vs_compiled_shader);
228      gpir_compile_nir(vs, nir, NULL);
229      break;
230   case MESA_SHADER_FRAGMENT:
231      lima_program_optimize_fs_nir(nir, &tex_options);
232
233      nir_print_shader(nir, stdout);
234
235      struct lima_fs_compiled_shader *so = rzalloc(NULL, struct lima_fs_compiled_shader);
236      struct ra_regs *ra = ppir_regalloc_init(NULL);
237      ppir_compile_nir(so, nir, ra, NULL);
238      break;
239   default:
240      errx(1, "unhandled shader stage: %d", stage);
241   }
242
243   ralloc_free(nir);
244   return 0;
245}
246