start adding graphics pipeline
[kazan.git] / src / demo / demo.cpp
1 /*
2 * Copyright 2017 Jacob Lifshay
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 shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 */
23 #include <fstream>
24 #include <iostream>
25 #include <sstream>
26 #include <vector>
27 #include <array>
28 #include <type_traits>
29 #include <string>
30 #include "spirv/spirv.h"
31 #include "spirv/parser.h"
32 #include "util/optional.h"
33 #include "util/string_view.h"
34 #include "spirv_to_llvm/spirv_to_llvm.h"
35 #include "llvm_wrapper/llvm_wrapper.h"
36
37 namespace vulkan_cpu
38 {
39 namespace test
40 {
41 util::optional<std::vector<spirv::Word>> load_file(const char *filename)
42 {
43 using spirv::Word;
44 constexpr int eof = std::char_traits<char>::eof();
45 std::ifstream is;
46 is.open(filename, std::ios::in | std::ios::binary);
47 if(!is)
48 return {};
49 constexpr std::size_t block_size = 0x1000;
50 std::vector<std::array<Word, block_size>> blocks;
51 std::array<unsigned char, sizeof(Word)> word_bytes{};
52 static_assert(sizeof(Word) == 4, "");
53 static_assert(std::is_same<std::uint8_t, unsigned char>::value, "");
54 auto read_little_endian = [](const unsigned char *bytes) -> Word
55 {
56 Word retval = bytes[3];
57 retval <<= 8;
58 retval |= bytes[2];
59 retval <<= 8;
60 retval |= bytes[1];
61 retval <<= 8;
62 retval |= bytes[0];
63 return retval;
64 };
65 auto read_big_endian = [](const unsigned char *bytes) -> Word
66 {
67 Word retval = bytes[0];
68 retval <<= 8;
69 retval |= bytes[1];
70 retval <<= 8;
71 retval |= bytes[2];
72 retval <<= 8;
73 retval |= bytes[3];
74 return retval;
75 };
76 for(unsigned char &byte : word_bytes)
77 {
78 auto v = is.get();
79 if(v == eof)
80 return {};
81 byte = v;
82 }
83 Word (*read_word_fn)(const unsigned char *) = nullptr;
84 if(read_little_endian(word_bytes.data()) == spirv::magic_number)
85 read_word_fn = read_little_endian;
86 else if(read_big_endian(word_bytes.data()) == spirv::magic_number)
87 read_word_fn = read_big_endian;
88 else
89 return {};
90 std::size_t word_count = 1;
91 blocks.emplace_back();
92 blocks[0][0] = read_word_fn(word_bytes.data());
93 std::size_t word_in_block_index = 1;
94 while(is.peek() != eof)
95 {
96 for(unsigned char &byte : word_bytes)
97 {
98 auto v = is.get();
99 if(v == eof)
100 return {};
101 byte = v;
102 }
103 blocks.back()[word_in_block_index++] = read_word_fn(word_bytes.data());
104 word_count++;
105 if(word_in_block_index >= block_size)
106 {
107 word_in_block_index = 0;
108 blocks.emplace_back();
109 }
110 }
111 std::vector<Word> retval;
112 retval.reserve(word_count);
113 word_in_block_index = 0;
114 for(std::size_t word_index = 0, block_index = 0; word_index < word_count; word_index++)
115 {
116 retval.push_back(blocks[block_index][word_in_block_index++]);
117 if(word_in_block_index >= block_size)
118 {
119 word_in_block_index = 0;
120 block_index++;
121 }
122 }
123 return std::move(retval);
124 }
125
126 void dump_words(const spirv::Word *words, std::size_t word_count)
127 {
128 constexpr std::size_t max_words_per_line = 4;
129 auto old_fill = std::cerr.fill('0');
130 auto old_flags = std::cerr.flags(std::ios::uppercase | std::ios::hex | std::ios::right);
131 auto old_width = std::cerr.width();
132 bool wrote_line_beginning = false;
133 bool wrote_line_ending = true;
134 std::cerr << "Words:\n";
135 std::size_t current_words_per_line = 0;
136 std::size_t index;
137 auto seperator = "";
138 auto write_line_beginning = [&]()
139 {
140 std::cerr.width(8);
141 std::cerr << index << ":";
142 seperator = " ";
143 wrote_line_beginning = true;
144 wrote_line_ending = false;
145 };
146 std::string chars = "";
147 auto write_line_ending = [&]()
148 {
149 while(current_words_per_line < max_words_per_line)
150 {
151 std::cerr << seperator;
152 seperator = " ";
153 std::cerr.width(8);
154 std::cerr.fill(' ');
155 std::cerr << "";
156 std::cerr.fill('0');
157 current_words_per_line++;
158 }
159 std::cerr << seperator << " |" << chars << "|\n";
160 seperator = "";
161 wrote_line_ending = true;
162 wrote_line_beginning = false;
163 current_words_per_line = 0;
164 chars.clear();
165 };
166 auto append_char = [&](unsigned ch)
167 {
168 if(ch >= 0x20U && ch < 0x7FU)
169 chars += static_cast<char>(ch);
170 else
171 chars += '.';
172 };
173 auto write_word = [&](spirv::Word w)
174 {
175 std::cerr << seperator;
176 seperator = " ";
177 std::cerr.width(8);
178 std::cerr << w;
179 current_words_per_line++;
180 append_char(w & 0xFFU);
181 append_char((w >> 8) & 0xFFU);
182 append_char((w >> 16) & 0xFFU);
183 append_char((w >> 24) & 0xFFU);
184 };
185 for(index = 0; index < word_count; index++)
186 {
187 if(current_words_per_line >= max_words_per_line)
188 write_line_ending();
189 if(!wrote_line_beginning)
190 write_line_beginning();
191 write_word(words[index]);
192 }
193 if(!wrote_line_ending)
194 write_line_ending();
195 std::cerr.flush();
196 std::cerr.width(old_width);
197 std::cerr.fill(old_fill);
198 std::cerr.flags(old_flags);
199 }
200
201 void dump_words(const std::vector<spirv::Word> &words)
202 {
203 dump_words(words.data(), words.size());
204 }
205
206 int test_main(int argc, char **argv)
207 {
208 const char *filename = "test-files/test.spv";
209 if(argc > 1)
210 {
211 if(argv[1][0] == '-')
212 {
213 std::cerr << "usage: demo [<file.spv>]\n";
214 return 1;
215 }
216 filename = argv[1];
217 }
218 std::cerr << "loading " << filename << std::endl;
219 auto file = load_file(filename);
220 if(file)
221 {
222 {
223 dump_words(*file);
224 std::cerr << std::endl;
225 spirv::Dump_callbacks dump_callbacks;
226 try
227 {
228 spirv::parse(dump_callbacks, file->data(), file->size());
229 }
230 catch(spirv::Parser_error &e)
231 {
232 std::cerr << dump_callbacks.ss.str() << std::endl;
233 std::cerr << "error: " << e.what();
234 return 1;
235 }
236 std::cerr << dump_callbacks.ss.str() << std::endl;
237 }
238 auto llvm_target_machine = llvm_wrapper::Target_machine::create_native_target_machine();
239 auto llvm_context = llvm_wrapper::Context::create();
240 std::uint64_t next_module_id = 1;
241 spirv_to_llvm::Converted_module converted_module;
242 try
243 {
244 converted_module = spirv_to_llvm::spirv_to_llvm(llvm_context.get(),
245 llvm_target_machine.get(),
246 file->data(),
247 file->size(),
248 next_module_id++,
249 spirv::Execution_model::vertex,
250 "main");
251 }
252 catch(spirv::Parser_error &e)
253 {
254 std::cerr << "error: " << e.what();
255 return 1;
256 }
257 std::cerr << "Translation to LLVM succeeded." << std::endl;
258 ::LLVMDumpModule(converted_module.module.get());
259 bool failed =
260 ::LLVMVerifyModule(converted_module.module.get(), ::LLVMPrintMessageAction, nullptr);
261 if(failed)
262 return 1;
263 auto orc_jit_stack = llvm_wrapper::Orc_jit_stack::create(std::move(llvm_target_machine));
264 orc_jit_stack.add_eagerly_compiled_ir(
265 std::move(converted_module.module),
266 [](const char *symbol_name, [[gnu::unused]] void *user_data) noexcept->std::uint64_t
267 {
268 std::cerr << "resolving symbol: " << symbol_name << std::endl;
269 void *symbol = nullptr;
270 return reinterpret_cast<std::uintptr_t>(symbol);
271 },
272 nullptr);
273 auto function = reinterpret_cast<void *>(
274 orc_jit_stack.get_symbol_address(converted_module.entry_function_name.c_str()));
275 std::cerr << "entry point: " << converted_module.entry_function_name << ": " << function
276 << std::endl;
277 }
278 else
279 {
280 std::cerr << "error: can't load file" << std::endl;
281 return 1;
282 }
283 return 0;
284 }
285 }
286 }
287
288 int main(int argc, char **argv)
289 {
290 return vulkan_cpu::test::test_main(argc, argv);
291 }