• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <cassert>
16 #include <cstdio>
17 #include <cstring>
18 #include <functional>
19 #include <iostream>
20 #include <memory>
21 #include <vector>
22 
23 #include "source/spirv_target_env.h"
24 #include "source/table.h"
25 #include "spirv-tools/markv.h"
26 #include "tools/io.h"
27 
28 namespace {
29 
30 enum Task {
31   kNoTask = 0,
32   kEncode,
33   kDecode,
34 };
35 
36 struct ScopedContext {
ScopedContext__anon1132de7f0111::ScopedContext37   ScopedContext(spv_target_env env) : context(spvContextCreate(env)) {}
~ScopedContext__anon1132de7f0111::ScopedContext38   ~ScopedContext() { spvContextDestroy(context); }
39   spv_context context;
40 };
41 
print_usage(char * argv0)42 void print_usage(char* argv0) {
43   printf(
44       R"(%s - Encodes or decodes a SPIR-V binary to or from a MARK-V binary.
45 
46 USAGE: %s [e|d] [options] [<filename>]
47 
48 The input binary is read from <filename>. If no file is specified,
49 or if the filename is "-", then the binary is read from standard input.
50 
51 If no output is specified then the output is printed to stdout in a human
52 readable format.
53 
54 WIP: MARK-V codec is in early stages of development. At the moment it only
55 can encode and decode some SPIR-V files and only if exacly the same build of
56 software is used (is doesn't write or handle version numbers yet).
57 
58 Tasks:
59   e               Encode SPIR-V to MARK-V.
60   d               Decode MARK-V to SPIR-V.
61 
62 Options:
63   -h, --help      Print this help.
64   --comments      Write codec comments to stdout.
65   --version       Display MARK-V codec version.
66 
67   -o <filename>   Set the output filename.
68                   Output goes to standard output if this option is
69                   not specified, or if the filename is "-".
70 )",
71       argv0, argv0);
72 }
73 
DiagnosticsMessageHandler(spv_message_level_t level,const char *,const spv_position_t & position,const char * message)74 void DiagnosticsMessageHandler(spv_message_level_t level, const char*,
75                                const spv_position_t& position,
76                                const char* message) {
77   switch (level) {
78     case SPV_MSG_FATAL:
79     case SPV_MSG_INTERNAL_ERROR:
80     case SPV_MSG_ERROR:
81       std::cerr << "error: " << position.index << ": " << message
82                 << std::endl;
83       break;
84     case SPV_MSG_WARNING:
85       std::cout << "warning: " << position.index << ": " << message
86                 << std::endl;
87       break;
88     case SPV_MSG_INFO:
89       std::cout << "info: " << position.index << ": " << message << std::endl;
90       break;
91     default:
92       break;
93   }
94 }
95 
96 }  // namespace
97 
main(int argc,char ** argv)98 int main(int argc, char** argv) {
99   const char* input_filename = nullptr;
100   const char* output_filename = nullptr;
101 
102   Task task = kNoTask;
103 
104   if (argc < 3) {
105     print_usage(argv[0]);
106     return 0;
107   }
108 
109   const char* task_char = argv[1];
110   if (0 == strcmp("e", task_char)) {
111     task = kEncode;
112   } else if (0 == strcmp("d", task_char)) {
113     task = kDecode;
114   }
115 
116   if (task == kNoTask) {
117     print_usage(argv[0]);
118     return 1;
119   }
120 
121   bool want_comments = false;
122 
123   for (int argi = 2; argi < argc; ++argi) {
124     if ('-' == argv[argi][0]) {
125       switch (argv[argi][1]) {
126         case 'h':
127           print_usage(argv[0]);
128           return 0;
129         case 'o': {
130           if (!output_filename && argi + 1 < argc) {
131             output_filename = argv[++argi];
132           } else {
133             print_usage(argv[0]);
134             return 1;
135           }
136         } break;
137         case '-': {
138           if (0 == strcmp(argv[argi], "--help")) {
139             print_usage(argv[0]);
140             return 0;
141           } else if (0 == strcmp(argv[argi], "--comments")) {
142             want_comments = true;
143           } else if (0 == strcmp(argv[argi], "--version")) {
144             fprintf(stderr, "error: Not implemented\n");
145             return 1;
146           } else {
147             print_usage(argv[0]);
148             return 1;
149           }
150         } break;
151         case '\0': {
152           // Setting a filename of "-" to indicate stdin.
153           if (!input_filename) {
154             input_filename = argv[argi];
155           } else {
156             fprintf(stderr, "error: More than one input file specified\n");
157             return 1;
158           }
159         } break;
160         default:
161           print_usage(argv[0]);
162           return 1;
163       }
164     } else {
165       if (!input_filename) {
166         input_filename = argv[argi];
167       } else {
168         fprintf(stderr, "error: More than one input file specified\n");
169         return 1;
170       }
171     }
172   }
173 
174   if (task == kDecode && want_comments) {
175     fprintf(stderr, "warning: Decoder comments not yet implemented\n");
176     want_comments = false;
177   }
178 
179   const bool write_to_stdout = output_filename == nullptr ||
180       0 == strcmp(output_filename, "-");
181 
182   spv_text comments = nullptr;
183   spv_text* comments_ptr = want_comments ? &comments : nullptr;
184 
185   ScopedContext ctx(SPV_ENV_UNIVERSAL_1_2);
186   SetContextMessageConsumer(ctx.context, DiagnosticsMessageHandler);
187 
188   if (task == kEncode) {
189     std::vector<uint32_t> contents;
190     if (!ReadFile<uint32_t>(input_filename, "rb", &contents)) return 1;
191 
192     std::unique_ptr<spv_markv_encoder_options_t,
193         std::function<void(spv_markv_encoder_options_t*)>> options(
194             spvMarkvEncoderOptionsCreate(), &spvMarkvEncoderOptionsDestroy);
195     spv_markv_binary markv_binary = nullptr;
196 
197     if (SPV_SUCCESS !=
198         spvSpirvToMarkv(ctx.context, contents.data(), contents.size(),
199                         options.get(), &markv_binary, comments_ptr, nullptr)) {
200       std::cerr << "error: Failed to encode " << input_filename << " to MARK-V "
201                 << std::endl;
202       return 1;
203     }
204 
205     if (want_comments) {
206       if (!WriteFile<char>(nullptr, "w", comments->str,
207                            comments->length)) return 1;
208     }
209 
210     if (!want_comments || !write_to_stdout) {
211       if (!WriteFile<uint8_t>(output_filename, "wb", markv_binary->data,
212                               markv_binary->length)) return 1;
213     }
214   } else if (task == kDecode) {
215     std::vector<uint8_t> contents;
216     if (!ReadFile<uint8_t>(input_filename, "rb", &contents)) return 1;
217 
218     std::unique_ptr<spv_markv_decoder_options_t,
219         std::function<void(spv_markv_decoder_options_t*)>> options(
220             spvMarkvDecoderOptionsCreate(), &spvMarkvDecoderOptionsDestroy);
221     spv_binary spirv_binary = nullptr;
222 
223     if (SPV_SUCCESS !=
224         spvMarkvToSpirv(ctx.context, contents.data(), contents.size(),
225                         options.get(), &spirv_binary, comments_ptr, nullptr)) {
226       std::cerr << "error: Failed to encode " << input_filename << " to MARK-V "
227                 << std::endl;
228       return 1;
229     }
230 
231     if (want_comments) {
232       if (!WriteFile<char>(nullptr, "w", comments->str,
233                            comments->length)) return 1;
234     }
235 
236     if (!want_comments || !write_to_stdout) {
237       if (!WriteFile<uint32_t>(output_filename, "wb", spirv_binary->code,
238                               spirv_binary->wordCount)) return 1;
239     }
240   } else {
241     assert(false && "Unknown task");
242   }
243 
244   spvTextDestroy(comments);
245 
246   return 0;
247 }
248