1/* 2 * Copyright © 2015 Intel Corporation 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 * Authors: 24 * Jason Ekstrand (jason@jlekstrand.net) 25 * 26 */ 27 28/* 29 * A simple executable that opens a SPIR-V shader, converts it to NIR, and 30 * dumps out the result. This should be useful for testing the 31 * spirv_to_nir code. 32 */ 33 34#include "spirv/nir_spirv.h" 35 36#include <sys/mman.h> 37#include <sys/types.h> 38#include <fcntl.h> 39#include <unistd.h> 40#include <stdio.h> 41#include <errno.h> 42#include <string.h> 43#include <getopt.h> 44 45#define WORD_SIZE 4 46 47static gl_shader_stage 48stage_to_enum(char *stage) 49{ 50 if (!strcmp(stage, "vertex")) 51 return MESA_SHADER_VERTEX; 52 else if (!strcmp(stage, "tess-ctrl")) 53 return MESA_SHADER_TESS_CTRL; 54 else if (!strcmp(stage, "tess-eval")) 55 return MESA_SHADER_TESS_EVAL; 56 else if (!strcmp(stage, "geometry")) 57 return MESA_SHADER_GEOMETRY; 58 else if (!strcmp(stage, "fragment")) 59 return MESA_SHADER_FRAGMENT; 60 else if (!strcmp(stage, "compute")) 61 return MESA_SHADER_COMPUTE; 62 else if (!strcmp(stage, "kernel")) 63 return MESA_SHADER_KERNEL; 64 else if (!strcmp(stage, "task")) 65 return MESA_SHADER_TASK; 66 else if (!strcmp(stage, "mesh")) 67 return MESA_SHADER_MESH; 68 else 69 return MESA_SHADER_NONE; 70} 71 72static void 73print_usage(char *exec_name, FILE *f) 74{ 75 fprintf(f, 76"Usage: %s [options] file\n" 77"Options:\n" 78" -h --help Print this help.\n" 79" -s, --stage <stage> Specify the shader stage. Valid stages are:\n" 80" vertex, tess-ctrl, tess-eval, geometry, fragment,\n" 81" task, mesh, compute, and kernel (OpenCL-style compute).\n" 82" -e, --entry <name> Specify the entry-point name.\n" 83" -g, --opengl Use OpenGL environment instead of Vulkan for\n" 84" graphics stages.\n" 85 , exec_name); 86} 87 88int main(int argc, char **argv) 89{ 90 gl_shader_stage shader_stage = MESA_SHADER_FRAGMENT; 91 char *entry_point = "main"; 92 int ch; 93 enum nir_spirv_execution_environment env = NIR_SPIRV_VULKAN; 94 95 static struct option long_options[] = 96 { 97 {"help", no_argument, 0, 'h'}, 98 {"stage", required_argument, 0, 's'}, 99 {"entry", required_argument, 0, 'e'}, 100 {"opengl", no_argument, 0, 'g'}, 101 {0, 0, 0, 0} 102 }; 103 104 while ((ch = getopt_long(argc, argv, "hs:e:g", long_options, NULL)) != -1) 105 { 106 switch (ch) 107 { 108 case 'h': 109 print_usage(argv[0], stdout); 110 return 0; 111 case 's': 112 shader_stage = stage_to_enum(optarg); 113 if (shader_stage == MESA_SHADER_NONE) 114 { 115 fprintf(stderr, "Unknown stage \"%s\"\n", optarg); 116 print_usage(argv[0], stderr); 117 return 1; 118 } 119 break; 120 case 'e': 121 entry_point = optarg; 122 break; 123 case 'g': 124 env = NIR_SPIRV_OPENGL; 125 break; 126 default: 127 fprintf(stderr, "Unrecognized option \"%s\".\n", optarg); 128 print_usage(argv[0], stderr); 129 return 1; 130 } 131 } 132 133 const char *filename = argv[optind]; 134 int fd = open(filename, O_RDONLY); 135 if (fd < 0) 136 { 137 fprintf(stderr, "Failed to open %s\n", filename); 138 return 1; 139 } 140 141 off_t len = lseek(fd, 0, SEEK_END); 142 if (len % WORD_SIZE != 0) 143 { 144 fprintf(stderr, "File length isn't a multiple of the word size\n"); 145 fprintf(stderr, "Are you sure this is a valid SPIR-V shader?\n"); 146 close(fd); 147 return 1; 148 } 149 150 size_t word_count = len / WORD_SIZE; 151 152 const void *map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); 153 if (map == MAP_FAILED) 154 { 155 fprintf(stderr, "Failed to mmap the file: errno=%d, %s\n", 156 errno, strerror(errno)); 157 close(fd); 158 return 1; 159 } 160 161 glsl_type_singleton_init_or_ref(); 162 163 struct spirv_to_nir_options spirv_opts = { 164 .environment = env, 165 .use_deref_buffer_array_length = env == NIR_SPIRV_OPENGL, 166 }; 167 168 if (shader_stage == MESA_SHADER_KERNEL) { 169 spirv_opts.environment = NIR_SPIRV_OPENCL; 170 spirv_opts.caps.address = true; 171 spirv_opts.caps.float64 = true; 172 spirv_opts.caps.int8 = true; 173 spirv_opts.caps.int16 = true; 174 spirv_opts.caps.int64 = true; 175 spirv_opts.caps.kernel = true; 176 } 177 178 nir_shader *nir = spirv_to_nir(map, word_count, NULL, 0, 179 shader_stage, entry_point, 180 &spirv_opts, NULL); 181 182 if (nir) 183 nir_print_shader(nir, stderr); 184 else 185 fprintf(stderr, "SPIRV to NIR compilation failed\n"); 186 187 glsl_type_singleton_decref(); 188 189 return 0; 190} 191