101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2015 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg *
2301e04c3fSmrg * Authors:
2401e04c3fSmrg *    Jason Ekstrand (jason@jlekstrand.net)
2501e04c3fSmrg *
2601e04c3fSmrg */
2701e04c3fSmrg
2801e04c3fSmrg/*
2901e04c3fSmrg * A simple executable that opens a SPIR-V shader, converts it to NIR, and
3001e04c3fSmrg * dumps out the result.  This should be useful for testing the
3101e04c3fSmrg * spirv_to_nir code.
3201e04c3fSmrg */
3301e04c3fSmrg
3401e04c3fSmrg#include "spirv/nir_spirv.h"
3501e04c3fSmrg
3601e04c3fSmrg#include <sys/mman.h>
3701e04c3fSmrg#include <sys/types.h>
3801e04c3fSmrg#include <fcntl.h>
3901e04c3fSmrg#include <unistd.h>
4001e04c3fSmrg#include <stdio.h>
4101e04c3fSmrg#include <errno.h>
4201e04c3fSmrg#include <string.h>
437ec681f3Smrg#include <getopt.h>
4401e04c3fSmrg
4501e04c3fSmrg#define WORD_SIZE 4
4601e04c3fSmrg
477ec681f3Smrgstatic gl_shader_stage
487ec681f3Smrgstage_to_enum(char *stage)
497ec681f3Smrg{
507ec681f3Smrg   if (!strcmp(stage, "vertex"))
517ec681f3Smrg      return MESA_SHADER_VERTEX;
527ec681f3Smrg   else if (!strcmp(stage, "tess-ctrl"))
537ec681f3Smrg      return MESA_SHADER_TESS_CTRL;
547ec681f3Smrg   else if (!strcmp(stage, "tess-eval"))
557ec681f3Smrg      return MESA_SHADER_TESS_EVAL;
567ec681f3Smrg   else if (!strcmp(stage, "geometry"))
577ec681f3Smrg      return MESA_SHADER_GEOMETRY;
587ec681f3Smrg   else if (!strcmp(stage, "fragment"))
597ec681f3Smrg      return MESA_SHADER_FRAGMENT;
607ec681f3Smrg   else if (!strcmp(stage, "compute"))
617ec681f3Smrg      return MESA_SHADER_COMPUTE;
627ec681f3Smrg   else if (!strcmp(stage, "kernel"))
637ec681f3Smrg      return MESA_SHADER_KERNEL;
647ec681f3Smrg   else if (!strcmp(stage, "task"))
657ec681f3Smrg      return MESA_SHADER_TASK;
667ec681f3Smrg   else if (!strcmp(stage, "mesh"))
677ec681f3Smrg      return MESA_SHADER_MESH;
687ec681f3Smrg   else
697ec681f3Smrg      return MESA_SHADER_NONE;
707ec681f3Smrg}
717ec681f3Smrg
727ec681f3Smrgstatic void
737ec681f3Smrgprint_usage(char *exec_name, FILE *f)
747ec681f3Smrg{
757ec681f3Smrg   fprintf(f,
767ec681f3Smrg"Usage: %s [options] file\n"
777ec681f3Smrg"Options:\n"
787ec681f3Smrg"  -h  --help              Print this help.\n"
797ec681f3Smrg"  -s, --stage <stage>     Specify the shader stage.  Valid stages are:\n"
807ec681f3Smrg"                          vertex, tess-ctrl, tess-eval, geometry, fragment,\n"
817ec681f3Smrg"                          task, mesh, compute, and kernel (OpenCL-style compute).\n"
827ec681f3Smrg"  -e, --entry <name>      Specify the entry-point name.\n"
837ec681f3Smrg"  -g, --opengl            Use OpenGL environment instead of Vulkan for\n"
847ec681f3Smrg"                          graphics stages.\n"
857ec681f3Smrg   , exec_name);
867ec681f3Smrg}
877ec681f3Smrg
8801e04c3fSmrgint main(int argc, char **argv)
8901e04c3fSmrg{
907ec681f3Smrg   gl_shader_stage shader_stage = MESA_SHADER_FRAGMENT;
917ec681f3Smrg   char *entry_point = "main";
927ec681f3Smrg   int ch;
937ec681f3Smrg   enum nir_spirv_execution_environment env = NIR_SPIRV_VULKAN;
947ec681f3Smrg
957ec681f3Smrg   static struct option long_options[] =
967ec681f3Smrg     {
977ec681f3Smrg       {"help",         no_argument, 0, 'h'},
987ec681f3Smrg       {"stage",  required_argument, 0, 's'},
997ec681f3Smrg       {"entry",  required_argument, 0, 'e'},
1007ec681f3Smrg       {"opengl",       no_argument, 0, 'g'},
1017ec681f3Smrg       {0, 0, 0, 0}
1027ec681f3Smrg     };
1037ec681f3Smrg
1047ec681f3Smrg   while ((ch = getopt_long(argc, argv, "hs:e:g", long_options, NULL)) != -1)
1057ec681f3Smrg   {
1067ec681f3Smrg      switch (ch)
1077ec681f3Smrg      {
1087ec681f3Smrg      case 'h':
1097ec681f3Smrg         print_usage(argv[0], stdout);
1107ec681f3Smrg         return 0;
1117ec681f3Smrg      case 's':
1127ec681f3Smrg         shader_stage = stage_to_enum(optarg);
1137ec681f3Smrg         if (shader_stage == MESA_SHADER_NONE)
1147ec681f3Smrg         {
1157ec681f3Smrg            fprintf(stderr, "Unknown stage \"%s\"\n", optarg);
1167ec681f3Smrg            print_usage(argv[0], stderr);
1177ec681f3Smrg            return 1;
1187ec681f3Smrg         }
1197ec681f3Smrg         break;
1207ec681f3Smrg      case 'e':
1217ec681f3Smrg         entry_point = optarg;
1227ec681f3Smrg         break;
1237ec681f3Smrg      case 'g':
1247ec681f3Smrg         env = NIR_SPIRV_OPENGL;
1257ec681f3Smrg         break;
1267ec681f3Smrg      default:
1277ec681f3Smrg         fprintf(stderr, "Unrecognized option \"%s\".\n", optarg);
1287ec681f3Smrg         print_usage(argv[0], stderr);
1297ec681f3Smrg         return 1;
1307ec681f3Smrg      }
1317ec681f3Smrg   }
1327ec681f3Smrg
1337ec681f3Smrg   const char *filename = argv[optind];
1347ec681f3Smrg   int fd = open(filename, O_RDONLY);
13501e04c3fSmrg   if (fd < 0)
13601e04c3fSmrg   {
1377ec681f3Smrg      fprintf(stderr, "Failed to open %s\n", filename);
13801e04c3fSmrg      return 1;
13901e04c3fSmrg   }
14001e04c3fSmrg
14101e04c3fSmrg   off_t len = lseek(fd, 0, SEEK_END);
14201e04c3fSmrg   if (len % WORD_SIZE != 0)
14301e04c3fSmrg   {
14401e04c3fSmrg      fprintf(stderr, "File length isn't a multiple of the word size\n");
14501e04c3fSmrg      fprintf(stderr, "Are you sure this is a valid SPIR-V shader?\n");
14601e04c3fSmrg      close(fd);
14701e04c3fSmrg      return 1;
14801e04c3fSmrg   }
14901e04c3fSmrg
15001e04c3fSmrg   size_t word_count = len / WORD_SIZE;
15101e04c3fSmrg
15201e04c3fSmrg   const void *map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
15301e04c3fSmrg   if (map == MAP_FAILED)
15401e04c3fSmrg   {
15501e04c3fSmrg      fprintf(stderr, "Failed to mmap the file: errno=%d, %s\n",
15601e04c3fSmrg              errno, strerror(errno));
15701e04c3fSmrg      close(fd);
15801e04c3fSmrg      return 1;
15901e04c3fSmrg   }
16001e04c3fSmrg
1617ec681f3Smrg   glsl_type_singleton_init_or_ref();
1627ec681f3Smrg
1637ec681f3Smrg   struct spirv_to_nir_options spirv_opts = {
1647ec681f3Smrg      .environment = env,
1657ec681f3Smrg      .use_deref_buffer_array_length = env == NIR_SPIRV_OPENGL,
1667ec681f3Smrg   };
1677ec681f3Smrg
1687ec681f3Smrg   if (shader_stage == MESA_SHADER_KERNEL) {
1697ec681f3Smrg      spirv_opts.environment = NIR_SPIRV_OPENCL;
1707ec681f3Smrg      spirv_opts.caps.address = true;
1717ec681f3Smrg      spirv_opts.caps.float64 = true;
1727ec681f3Smrg      spirv_opts.caps.int8 = true;
1737ec681f3Smrg      spirv_opts.caps.int16 = true;
1747ec681f3Smrg      spirv_opts.caps.int64 = true;
1757ec681f3Smrg      spirv_opts.caps.kernel = true;
1767ec681f3Smrg   }
1777ec681f3Smrg
1787ec681f3Smrg   nir_shader *nir = spirv_to_nir(map, word_count, NULL, 0,
1797ec681f3Smrg                                  shader_stage, entry_point,
1807ec681f3Smrg                                  &spirv_opts, NULL);
1817ec681f3Smrg
1827ec681f3Smrg   if (nir)
1837ec681f3Smrg      nir_print_shader(nir, stderr);
1847ec681f3Smrg   else
1857ec681f3Smrg      fprintf(stderr, "SPIRV to NIR compilation failed\n");
18601e04c3fSmrg
1877ec681f3Smrg   glsl_type_singleton_decref();
18801e04c3fSmrg
18901e04c3fSmrg   return 0;
19001e04c3fSmrg}
191