xref: /aosp_15_r20/external/mesa3d/src/imagination/rogue/tools/vk_compiler.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2022 Imagination Technologies Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * 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 THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include "compiler/shader_enums.h"
25 #include "nir/nir.h"
26 #include "rogue.h"
27 #include "util/macros.h"
28 #include "util/os_file.h"
29 #include "util/ralloc.h"
30 #include "util/u_dynarray.h"
31 
32 #include <getopt.h>
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 /* Number of hex columns to print before starting a new line. */
39 #define ARRAY_PRINT_COLS 16
40 
41 /**
42  * \file vk_compiler.c
43  *
44  * \brief Rogue offline Vulkan shader compiler.
45  */
46 
47 static const struct option cmdline_opts[] = {
48    /* Arguments. */
49    { "stage", required_argument, NULL, 's' },
50    { "file", required_argument, NULL, 'f' },
51    { "entry", required_argument, NULL, 'e' },
52 
53    /* Options. */
54    { "help", no_argument, NULL, 'h' },
55    { "out", required_argument, NULL, 'o' },
56 
57    { NULL, 0, NULL, 0 },
58 };
59 
60 typedef struct compiler_opts {
61    gl_shader_stage stage;
62    char *file;
63    char *entry;
64    char *out_file;
65 } compiler_opts;
66 
usage(const char * argv0)67 static void usage(const char *argv0)
68 {
69    /* clang-format off */
70    printf("Rogue offline Vulkan shader compiler.\n");
71    printf("Usage: %s -s <stage> -f <file> [-e <entry>] [-o <file>] [-h]\n", argv0);
72    printf("\n");
73 
74    printf("Required arguments:\n");
75    printf("\t-s, --stage <stage> Shader stage (supported options: frag, vert).\n");
76    printf("\t-f, --file <file>   Shader SPIR-V filename.\n");
77    printf("\n");
78 
79    printf("Options:\n");
80    printf("\t-h, --help          Prints this help message.\n");
81    printf("\t-e, --entry <entry> Overrides the shader entry-point name (default: 'main').\n");
82    printf("\t-o, --out <file>    Overrides the output filename (default: 'out.bin').\n");
83    printf("\n");
84    /* clang-format on */
85 }
86 
parse_cmdline(int argc,char * argv[],struct compiler_opts * opts)87 static bool parse_cmdline(int argc, char *argv[], struct compiler_opts *opts)
88 {
89    int opt;
90    int longindex;
91 
92    while (
93       (opt = getopt_long(argc, argv, "hs:f:e:o:", cmdline_opts, &longindex)) !=
94       -1) {
95       switch (opt) {
96       case 'e':
97          if (opts->entry)
98             continue;
99 
100          opts->entry = optarg;
101          break;
102 
103       case 'f':
104          if (opts->file)
105             continue;
106 
107          opts->file = optarg;
108          break;
109 
110       case 'o':
111          if (opts->out_file)
112             continue;
113 
114          opts->out_file = optarg;
115          break;
116 
117       case 's':
118          if (opts->stage != MESA_SHADER_NONE)
119             continue;
120 
121          if (!strcmp(optarg, "frag") || !strcmp(optarg, "f"))
122             opts->stage = MESA_SHADER_FRAGMENT;
123          else if (!strcmp(optarg, "vert") || !strcmp(optarg, "v"))
124             opts->stage = MESA_SHADER_VERTEX;
125          else {
126             fprintf(stderr, "Unsupported stage \"%s\".\n", optarg);
127             usage(argv[0]);
128             return false;
129          }
130 
131          break;
132 
133       case 'h':
134       default:
135          usage(argv[0]);
136          return false;
137       }
138    }
139 
140    if (opts->stage == MESA_SHADER_NONE || !opts->file) {
141       fprintf(stderr,
142               "%s: --stage and --file are required arguments.\n",
143               argv[0]);
144       usage(argv[0]);
145       return false;
146    }
147 
148    if (!opts->out_file)
149       opts->out_file = "out.bin";
150 
151    if (!opts->entry)
152       opts->entry = "main";
153 
154    return true;
155 }
156 
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159    /* Command-line options. */
160    /* N.B. MESA_SHADER_NONE != 0 */
161    compiler_opts opts = { .stage = MESA_SHADER_NONE, 0 };
162 
163    /* Input file data. */
164    char *input_data;
165    size_t input_size;
166 
167    /* Compiler context. */
168    struct rogue_compiler *compiler;
169 
170    /* Multi-stage build context. */
171    struct rogue_build_ctx *ctx;
172 
173    /* Output file. */
174    FILE *fp;
175    size_t bytes_written;
176 
177    /* Parse command-line options. */
178    if (!parse_cmdline(argc, argv, &opts))
179       return 1;
180 
181    /* Load SPIR-V input file. */
182    input_data = os_read_file(opts.file, &input_size);
183    if (!input_data) {
184       fprintf(stderr, "Failed to read file \"%s\".\n", opts.file);
185       return 1;
186    }
187 
188    /* Create compiler context. */
189    compiler = rogue_compiler_create(NULL);
190    if (!compiler) {
191       fprintf(stderr, "Failed to set up compiler context.\n");
192       goto err_free_input;
193    }
194 
195    /* Create build context. */
196    ctx = rogue_build_context_create(compiler, NULL);
197    if (!ctx) {
198       fprintf(stderr, "Failed to set up build context.\n");
199       goto err_destroy_compiler;
200    }
201 
202    /* SPIR-V -> NIR. */
203    ctx->nir[opts.stage] = rogue_spirv_to_nir(ctx,
204                                              opts.stage,
205                                              opts.entry,
206                                              input_size / sizeof(uint32_t),
207                                              (uint32_t *)input_data,
208                                              0,
209                                              NULL);
210    if (!ctx->nir[opts.stage]) {
211       fprintf(stderr, "Failed to translate SPIR-V input to NIR.\n");
212       goto err_free_build_context;
213    }
214 
215    /* NIR -> Rogue. */
216    ctx->rogue[opts.stage] = rogue_nir_to_rogue(ctx, ctx->nir[opts.stage]);
217    if (!ctx->rogue[opts.stage]) {
218       fprintf(stderr, "Failed to translate NIR input to Rogue.\n");
219       goto err_free_build_context;
220    }
221 
222    rogue_encode_shader(ctx, ctx->rogue[opts.stage], &ctx->binary[opts.stage]);
223 
224    /* Write shader binary to disk. */
225    fp = fopen(opts.out_file, "wb");
226    if (!fp) {
227       fprintf(stderr, "Failed to open output file \"%s\".\n", opts.out_file);
228       goto err_free_build_context;
229    }
230 
231    bytes_written = fwrite(util_dynarray_begin(&ctx->binary[opts.stage]),
232                           1,
233                           ctx->binary[opts.stage].size,
234                           fp);
235    if (bytes_written != ctx->binary[opts.stage].size) {
236       fprintf(
237          stderr,
238          "Failed to write to output file \"%s\" (%zu bytes of %u written).\n",
239          opts.out_file,
240          bytes_written,
241          ctx->binary[opts.stage].size);
242       goto err_close_outfile;
243    }
244 
245    /* Clean up. */
246    fclose(fp);
247    ralloc_free(ctx);
248    ralloc_free(compiler);
249    free(input_data);
250 
251    return 0;
252 
253 err_close_outfile:
254    fclose(fp);
255 err_free_build_context:
256    ralloc_free(ctx);
257 err_destroy_compiler:
258    ralloc_free(compiler);
259 err_free_input:
260    free(input_data);
261 
262    return 1;
263 }
264