vertex shader works; working on adding debugger-friendly compiler stack
authorJacob Lifshay <programmerjake@gmail.com>
Fri, 18 Aug 2017 00:25:45 +0000 (17:25 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Fri, 18 Aug 2017 00:25:45 +0000 (17:25 -0700)
src/demo/demo.cpp
src/llvm_wrapper/CMakeLists.txt
src/llvm_wrapper/llvm_wrapper.h
src/llvm_wrapper/orc_compile_stack.cpp [new file with mode: 0644]
src/llvm_wrapper/orc_compile_stack.h [new file with mode: 0644]
src/pipeline/CMakeLists.txt
src/pipeline/pipeline.cpp
src/pipeline/pipeline.h

index 3a9ccc9922a932c58f2fdd4f68760078440894cb..17f1619feebc3d34bd5c449deeaaa727a8d6262d 100644 (file)
@@ -341,13 +341,19 @@ int test_main(int argc, char **argv)
             constexpr std::uint32_t vertex_end_index = 3;
             constexpr std::uint32_t instance_id = 0;
             constexpr std::size_t vertex_count = vertex_end_index - vertex_start_index;
-            std::unique_ptr<unsigned char[]> output_buffer(
-                new unsigned char[graphics_pipeline->get_vertex_shader_output_struct_size()
-                                  * vertex_count]);
-            auto vertex_shader_function = graphics_pipeline->get_vertex_shader_function();
-            vertex_shader_function(
+            std::size_t output_buffer_size =
+                graphics_pipeline->get_vertex_shader_output_struct_size() * vertex_count;
+            std::unique_ptr<unsigned char[]> output_buffer(new unsigned char[output_buffer_size]);
+            for(std::size_t i = 0; i < output_buffer_size; i++)
+                output_buffer[i] = 0;
+            graphics_pipeline->run_vertex_shader(
                 vertex_start_index, vertex_end_index, instance_id, output_buffer.get());
             std::cerr << "shader completed" << std::endl;
+            for(std::size_t i = 0; i < vertex_count; i++)
+            {
+                graphics_pipeline->dump_vertex_shader_output_struct(output_buffer.get()
+                                                                    + graphics_pipeline->get_vertex_shader_output_struct_size() * i);
+            }
         }
         catch(std::runtime_error &e)
         {
index 30fad9f912fb1017238e7f1a43eceead2d16cef3..8a56efc168ba357d5f3ba7223b7ae05c06b9e08d 100644 (file)
@@ -20,7 +20,8 @@
 #
 cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
-set(sources llvm_wrapper.cpp)
+set(sources llvm_wrapper.cpp
+            orc_compile_stack.cpp)
 add_library(vulkan_cpu_llvm_wrapper STATIC ${sources})
 if(0)
 llvm_map_components_to_libnames(llvm_libraries core native analysis orcjit mcjit nativecodegen)
index 4f2b2068bf8bb4578c557960a467367fcc092310..8ab6604020f5bfc8353439cedbc5ed820264c92f 100644 (file)
@@ -101,7 +101,7 @@ public:
 
 struct LLVM_string_deleter
 {
-    void operator()(char *str)
+    void operator()(char *str) const noexcept
     {
         ::LLVMDisposeMessage(str);
     }
@@ -149,7 +149,7 @@ public:
 
 struct Context_deleter
 {
-    void operator()(::LLVMContextRef context) noexcept
+    void operator()(::LLVMContextRef context) const noexcept
     {
         ::LLVMContextDispose(context);
     }
@@ -177,7 +177,7 @@ public:
 
 struct Target_deleter
 {
-    void operator()(::LLVMTargetRef target) noexcept
+    void operator()(::LLVMTargetRef target) const noexcept
     {
         static_cast<void>(target);
     }
@@ -220,7 +220,7 @@ struct Target : public Wrapper<::LLVMTargetRef, Target_deleter>
 
 struct Target_data_deleter
 {
-    void operator()(::LLVMTargetDataRef v) noexcept
+    void operator()(::LLVMTargetDataRef v) const noexcept
     {
         ::LLVMDisposeTargetData(v);
     }
@@ -250,7 +250,7 @@ struct Target_data : public Wrapper<::LLVMTargetDataRef, Target_data_deleter>
 
 struct Target_machine_deleter
 {
-    void operator()(::LLVMTargetMachineRef tm) noexcept
+    void operator()(::LLVMTargetMachineRef tm) const noexcept
     {
         ::LLVMDisposeTargetMachine(tm);
     }
@@ -304,7 +304,7 @@ struct Target_machine : public Wrapper<::LLVMTargetMachineRef, Target_machine_de
 
 struct Module_deleter
 {
-    void operator()(::LLVMModuleRef module) noexcept
+    void operator()(::LLVMModuleRef module) const noexcept
     {
         ::LLVMDisposeModule(module);
     }
@@ -341,7 +341,7 @@ inline LLVM_string print_type_to_string(::LLVMTypeRef type)
 
 struct Builder_deleter
 {
-    void operator()(::LLVMBuilderRef v) noexcept
+    void operator()(::LLVMBuilderRef v) const noexcept
     {
         return ::LLVMDisposeBuilder(v);
     }
@@ -401,7 +401,7 @@ inline ::LLVMTypeRef get_scalar_or_vector_element_type(::LLVMTypeRef type)
 #if LLVM_WRAPPER_ORC_REVISION_NUMBER >= 306166
 struct Orc_shared_module_ref_deleter
 {
-    void operator()(::LLVMSharedModuleRef v) noexcept
+    void operator()(::LLVMSharedModuleRef v) const noexcept
     {
         ::LLVMOrcDisposeSharedModuleRef(v);
     }
@@ -419,7 +419,7 @@ struct Orc_shared_module_ref : public Wrapper<::LLVMSharedModuleRef, Orc_shared_
 
 struct Orc_jit_stack_deleter
 {
-    void operator()(::LLVMOrcJITStackRef v) noexcept
+    void operator()(::LLVMOrcJITStackRef v) const noexcept
     {
         ::LLVMOrcDisposeInstance(v);
     }
diff --git a/src/llvm_wrapper/orc_compile_stack.cpp b/src/llvm_wrapper/orc_compile_stack.cpp
new file mode 100644 (file)
index 0000000..3b437e9
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "orc_compile_stack.h"
+#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
+#include <llvm/ExecutionEngine/JITEventListener.h>
+#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Config/llvm-config.h>
+
+#if LLVM_VERSION_MAJOR != 4 || LLVM_VERSION_MINOR != 0
+#error Orc compile stack is not yet implemented for this version of LLVM
+#endif
+
+namespace vulkan_cpu
+{
+namespace llvm_wrapper
+{
+namespace
+{
+// implement the unwrap functions that aren't in public llvm headers
+llvm::TargetMachine *unwrap(::LLVMTargetMachineRef v) noexcept
+{
+    return reinterpret_cast<llvm::TargetMachine *>(v);
+}
+}
+
+class Orc_compile_stack_implementation
+{
+    Orc_compile_stack_implementation(const Orc_compile_stack_implementation &) = delete;
+    Orc_compile_stack_implementation(Orc_compile_stack_implementation &&) = delete;
+    Orc_compile_stack_implementation &operator=(const Orc_compile_stack_implementation &) = delete;
+    Orc_compile_stack_implementation &operator=(Orc_compile_stack_implementation &&) = delete;
+
+private:
+    std::unique_ptr<llvm::TargetMachine> target_machine;
+    const llvm::DataLayout data_layout;
+    llvm::orc::ObjectLinkingLayer<> object_linking_layer;
+
+public:
+    explicit Orc_compile_stack_implementation(Target_machine target_machine_in)
+        : target_machine(unwrap(target_machine_in.release())),
+          data_layout(target_machine->createDataLayout())
+    {
+#warning finish
+        assert(!"finish");
+    }
+    void add_eagerly_compiled_ir(Module module,
+                                 ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
+                                 void *symbol_resolver_user_data)
+    {
+#warning finish
+        assert(!"finish");
+    }
+    std::uintptr_t get_symbol_address(const char *symbol_name)
+    {
+#warning finish
+        assert(!"finish");
+        return 0;
+    }
+};
+
+void Orc_compile_stack_deleter::operator()(Orc_compile_stack_ref v) const noexcept
+{
+    delete v;
+}
+
+Orc_compile_stack Orc_compile_stack::create(Target_machine target_machine)
+{
+#warning finish
+    assert(!"finish");
+    return {};
+}
+
+void Orc_compile_stack::add_eagerly_compiled_ir(Orc_compile_stack_ref orc_compile_stack,
+                                                Module module,
+                                                ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
+                                                void *symbol_resolver_user_data)
+{
+    orc_compile_stack->add_eagerly_compiled_ir(
+        std::move(module), symbol_resolver_callback, symbol_resolver_user_data);
+}
+
+std::uintptr_t Orc_compile_stack::get_symbol_address(Orc_compile_stack_ref orc_compile_stack,
+                                                     const char *symbol_name)
+{
+    return orc_compile_stack->get_symbol_address(symbol_name);
+}
+}
+}
diff --git a/src/llvm_wrapper/orc_compile_stack.h b/src/llvm_wrapper/orc_compile_stack.h
new file mode 100644 (file)
index 0000000..413d314
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#ifndef LLVM_WRAPPER_ORC_COMPILE_STACK_H_
+#define LLVM_WRAPPER_ORC_COMPILE_STACK_H_
+
+#include "llvm_wrapper.h"
+
+namespace vulkan_cpu
+{
+namespace llvm_wrapper
+{
+class Orc_compile_stack_implementation;
+
+typedef Orc_compile_stack_implementation *Orc_compile_stack_ref;
+
+struct Orc_compile_stack_deleter
+{
+    void operator()(Orc_compile_stack_ref v) const noexcept;
+};
+
+struct Orc_compile_stack : public Wrapper<Orc_compile_stack_ref, Orc_compile_stack_deleter>
+{
+    using Wrapper::Wrapper;
+    static Orc_compile_stack create(Target_machine target_machine);
+    static void add_eagerly_compiled_ir(Orc_compile_stack_ref orc_compile_stack,
+                                        Module module,
+                                        ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
+                                        void *symbol_resolver_user_data);
+    void add_eagerly_compiled_ir(Module module,
+                                 ::LLVMOrcSymbolResolverFn symbol_resolver_callback,
+                                 void *symbol_resolver_user_data)
+    {
+        add_eagerly_compiled_ir(
+            get(), std::move(module), symbol_resolver_callback, symbol_resolver_user_data);
+    }
+    static std::uintptr_t get_symbol_address(Orc_compile_stack_ref orc_compile_stack,
+                                             const char *symbol_name);
+    template <typename T>
+    static T *get_symbol(Orc_compile_stack_ref orc_compile_stack, const char *symbol_name)
+    {
+        return reinterpret_cast<T *>(get_symbol_address(orc_compile_stack, symbol_name));
+    }
+    std::uintptr_t get_symbol_address(const char *symbol_name)
+    {
+        return get_symbol_address(get(), symbol_name);
+    }
+    template <typename T>
+    T *get_symbol(const char *symbol_name)
+    {
+        return get_symbol<T>(get(), symbol_name);
+    }
+};
+}
+}
+
+#endif // LLVM_WRAPPER_ORC_COMPILE_STACK_H_
index 65fdb9416992f64c28a49c97b4e6f8d259455113..5b4d9807302fe2a242bb56834e750359101c5714 100644 (file)
@@ -22,4 +22,4 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
 set(sources pipeline.cpp)
 add_library(vulkan_cpu_pipeline STATIC ${sources})
-target_link_libraries(vulkan_cpu_pipeline vulkan_cpu_spirv_to_llvm vulkan_cpu_util vulkan_cpu_spirv vulkan_cpu_llvm_wrapper vulkan_cpu_vulkan)
+target_link_libraries(vulkan_cpu_pipeline vulkan_cpu_spirv_to_llvm vulkan_cpu_json vulkan_cpu_util vulkan_cpu_spirv vulkan_cpu_llvm_wrapper vulkan_cpu_vulkan)
index 20544e47da23aa3b99ed08f2c32db4894ea58f81..84182a5b8fb39c3c8913e0d844cc12ebd694b607 100644 (file)
@@ -24,6 +24,8 @@
 #include "spirv_to_llvm/spirv_to_llvm.h"
 #include "llvm_wrapper/llvm_wrapper.h"
 #include "vulkan/util.h"
+#include "util/soft_float.h"
+#include "json/json.h"
 #include <stdexcept>
 #include <cassert>
 #include <vector>
@@ -78,16 +80,266 @@ Pipeline_layout_handle Pipeline_layout_handle::make(
 
 struct Graphics_pipeline::Implementation
 {
+    llvm_wrapper::Context llvm_context = llvm_wrapper::Context::create();
     spirv_to_llvm::Jit_symbol_resolver jit_symbol_resolver;
     llvm_wrapper::Orc_jit_stack jit_stack;
-    llvm_wrapper::Context llvm_context = llvm_wrapper::Context::create();
-    std::uint64_t next_module_id = 1;
-    std::uint64_t make_module_id() noexcept
+    llvm_wrapper::Target_data data_layout;
+    std::vector<spirv_to_llvm::Converted_module> compiled_shaders;
+    std::shared_ptr<spirv_to_llvm::Struct_type_descriptor> vertex_shader_output_struct;
+    std::string append_value_to_string(std::string str,
+                                       spirv_to_llvm::Type_descriptor &type,
+                                       const void *value) const
     {
-        return next_module_id++;
+        struct Visitor : public spirv_to_llvm::Type_descriptor::Type_visitor
+        {
+            const Implementation *this_;
+            std::string &str;
+            const void *value;
+            Visitor(const Implementation *this_, std::string &str, const void *value) noexcept
+                : this_(this_),
+                  str(str),
+                  value(value)
+            {
+            }
+            virtual void visit(spirv_to_llvm::Simple_type_descriptor &type) override
+            {
+                auto llvm_type = type.get_or_make_type().type;
+                switch(::LLVMGetTypeKind(llvm_type))
+                {
+                case ::LLVMVoidTypeKind:
+                case ::LLVMX86_FP80TypeKind:
+                case ::LLVMFP128TypeKind:
+                case ::LLVMPPC_FP128TypeKind:
+                case ::LLVMLabelTypeKind:
+                case ::LLVMFunctionTypeKind:
+                case ::LLVMStructTypeKind:
+                case ::LLVMArrayTypeKind:
+                case ::LLVMPointerTypeKind:
+                case ::LLVMVectorTypeKind:
+                case ::LLVMMetadataTypeKind:
+                case ::LLVMX86_MMXTypeKind:
+                case ::LLVMTokenTypeKind:
+                    break;
+                case ::LLVMHalfTypeKind:
+                {
+                    auto integer_value = *static_cast<const std::uint16_t *>(value);
+                    auto float_value =
+                        util::soft_float::ExtendedFloat::fromHalfPrecision(integer_value);
+                    str = json::ast::Number_value::append_double_to_string(
+                        static_cast<double>(float_value), std::move(str));
+                    if(float_value.isNaN())
+                    {
+                        str += " (0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += ")";
+                    }
+                    return;
+                }
+                case ::LLVMFloatTypeKind:
+                {
+                    static_assert(sizeof(std::uint32_t) == sizeof(float)
+                                      && alignof(std::uint32_t) == alignof(float),
+                                  "");
+                    union
+                    {
+                        std::uint32_t integer_value;
+                        float float_value;
+                    };
+                    integer_value = *static_cast<const std::uint32_t *>(value);
+                    str = json::ast::Number_value::append_double_to_string(float_value,
+                                                                           std::move(str));
+                    if(std::isnan(float_value))
+                    {
+                        str += " (0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += ")";
+                    }
+                    return;
+                }
+                case ::LLVMDoubleTypeKind:
+                {
+                    static_assert(sizeof(std::uint64_t) == sizeof(double)
+                                      && alignof(std::uint64_t) == alignof(double),
+                                  "");
+                    union
+                    {
+                        std::uint64_t integer_value;
+                        double float_value;
+                    };
+                    integer_value = *static_cast<const std::uint64_t *>(value);
+                    str = json::ast::Number_value::append_double_to_string(float_value,
+                                                                           std::move(str));
+                    if(std::isnan(float_value))
+                    {
+                        str += " (0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += ")";
+                    }
+                    return;
+                }
+                case ::LLVMIntegerTypeKind:
+                {
+                    switch(::LLVMGetIntTypeWidth(llvm_type))
+                    {
+                    case 8:
+                    {
+                        auto integer_value = *static_cast<const std::uint8_t *>(value);
+                        str += "0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += " ";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str));
+                        str += " ";
+                        str = json::ast::Number_value::append_signed_integer_to_string(
+                            static_cast<std::int8_t>(integer_value), std::move(str));
+                        return;
+                    }
+                    case 16:
+                    {
+                        auto integer_value = *static_cast<const std::uint16_t *>(value);
+                        str += "0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += " ";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str));
+                        str += " ";
+                        str = json::ast::Number_value::append_signed_integer_to_string(
+                            static_cast<std::int16_t>(integer_value), std::move(str));
+                        return;
+                    }
+                    case 32:
+                    {
+                        auto integer_value = *static_cast<const std::uint32_t *>(value);
+                        str += "0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += " ";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str));
+                        str += " ";
+                        str = json::ast::Number_value::append_signed_integer_to_string(
+                            static_cast<std::int32_t>(integer_value), std::move(str));
+                        return;
+                    }
+                    case 64:
+                    {
+                        auto integer_value = *static_cast<const std::uint64_t *>(value);
+                        str += "0x";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str), 0x10);
+                        str += " ";
+                        str = json::ast::Number_value::append_unsigned_integer_to_string(
+                            integer_value, std::move(str));
+                        str += " ";
+                        str = json::ast::Number_value::append_signed_integer_to_string(
+                            static_cast<std::int64_t>(integer_value), std::move(str));
+                        return;
+                    }
+                    }
+                    break;
+                }
+                }
+                assert(!"unhandled type");
+                throw std::runtime_error("unhandled type");
+            }
+            virtual void visit(spirv_to_llvm::Vector_type_descriptor &type) override
+            {
+                auto llvm_element_type = type.get_element_type()->get_or_make_type().type;
+                std::size_t element_size =
+                    ::LLVMABISizeOfType(this_->data_layout.get(), llvm_element_type);
+                std::size_t element_count = type.get_element_count();
+                str += "<";
+                auto separator = "";
+                for(std::size_t i = 0; i < element_count; i++)
+                {
+                    str += separator;
+                    separator = ", ";
+                    str = this_->append_value_to_string(
+                        std::move(str),
+                        *type.get_element_type(),
+                        static_cast<const char *>(value) + i * element_size);
+                }
+                str += ">";
+            }
+            virtual void visit(spirv_to_llvm::Matrix_type_descriptor &type) override
+            {
+                assert(!"dumping matrix not implemented");
+                throw std::runtime_error("dumping matrix not implemented");
+#warning dumping matrix not implemented
+            }
+            virtual void visit(spirv_to_llvm::Array_type_descriptor &type) override
+            {
+                auto llvm_element_type = type.get_element_type()->get_or_make_type().type;
+                std::size_t element_size =
+                    ::LLVMABISizeOfType(this_->data_layout.get(), llvm_element_type);
+                std::size_t element_count = type.get_element_count();
+                str += "[";
+                auto separator = "";
+                for(std::size_t i = 0; i < element_count; i++)
+                {
+                    str += separator;
+                    separator = ", ";
+                    str = this_->append_value_to_string(
+                        std::move(str),
+                        *type.get_element_type(),
+                        static_cast<const char *>(value) + i * element_size);
+                }
+                str += "]";
+            }
+            virtual void visit(spirv_to_llvm::Pointer_type_descriptor &type) override
+            {
+                str += "pointer:0x";
+                str = json::ast::Number_value::append_unsigned_integer_to_string(
+                    reinterpret_cast<std::uint64_t>(*static_cast<const void *const *>(value)),
+                    std::move(str),
+                    0x10);
+            }
+            virtual void visit(spirv_to_llvm::Function_type_descriptor &type) override
+            {
+                str += "function:0x";
+                str = json::ast::Number_value::append_unsigned_integer_to_string(
+                    reinterpret_cast<std::uint64_t>(*static_cast<const void *const *>(value)),
+                    std::move(str),
+                    0x10);
+            }
+            virtual void visit(spirv_to_llvm::Struct_type_descriptor &type) override
+            {
+                auto &&members = type.get_members(true);
+                auto llvm_type = type.get_or_make_type().type;
+                str += "{";
+                auto separator = "";
+                for(auto &member : members)
+                {
+                    str += separator;
+                    separator = ", ";
+                    str = this_->append_value_to_string(
+                        std::move(str),
+                        *member.type,
+                        static_cast<const char *>(value)
+                            + ::LLVMOffsetOfElement(
+                                  this_->data_layout.get(), llvm_type, member.llvm_member_index));
+                }
+                str += "}";
+            }
+        };
+        type.visit(Visitor(this, str, value));
+        return str;
     }
 };
 
+void Graphics_pipeline::dump_vertex_shader_output_struct(const void *output_struct) const
+{
+    std::cerr << "output: "
+              << implementation->append_value_to_string(
+                     {}, *implementation->vertex_shader_output_struct, output_struct)
+              << std::endl;
+}
+
 std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
     Pipeline_cache *pipeline_cache, const VkGraphicsPipelineCreateInfo &create_info)
 {
@@ -103,8 +355,7 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
     }
     auto implementation = std::make_shared<Implementation>();
     auto llvm_target_machine = llvm_wrapper::Target_machine::create_native_target_machine();
-    std::vector<spirv_to_llvm::Converted_module> compiled_shaders;
-    compiled_shaders.reserve(create_info.stageCount);
+    implementation->compiled_shaders.reserve(create_info.stageCount);
     for(std::size_t i = 0; i < create_info.stageCount; i++)
     {
         auto &stage_info = create_info.pStages[i];
@@ -131,7 +382,7 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
                                                             llvm_target_machine.get(),
                                                             shader_module->words(),
                                                             shader_module->word_count(),
-                                                            implementation->make_module_id(),
+                                                            implementation->compiled_shaders.size(),
                                                             execution_model,
                                                             stage_info.pName);
         std::cerr << "Translation to LLVM succeeded." << std::endl;
@@ -140,13 +391,13 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
             ::LLVMVerifyModule(compiled_shader.module.get(), ::LLVMPrintMessageAction, nullptr);
         if(failed)
             throw std::runtime_error("LLVM module verification failed");
-        compiled_shaders.push_back(std::move(compiled_shader));
+        implementation->compiled_shaders.push_back(std::move(compiled_shader));
     }
-    auto data_layout = llvm_target_machine.create_target_data_layout();
+    implementation->data_layout = llvm_target_machine.create_target_data_layout();
     implementation->jit_stack = llvm_wrapper::Orc_jit_stack::create(std::move(llvm_target_machine));
     Vertex_shader_function vertex_shader_function = nullptr;
     std::size_t vertex_shader_output_struct_size = 0;
-    for(auto &compiled_shader : compiled_shaders)
+    for(auto &compiled_shader : implementation->compiled_shaders)
     {
         vertex_shader_output_struct_size = implementation->jit_stack.add_eagerly_compiled_ir(
             std::move(compiled_shader.module),
@@ -176,8 +427,10 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::make(
         {
             vertex_shader_function =
                 reinterpret_cast<Vertex_shader_function>(shader_entry_point_address);
+            implementation->vertex_shader_output_struct = compiled_shader.outputs_struct;
             vertex_shader_output_struct_size = ::LLVMABISizeOfType(
-                data_layout.get(), compiled_shader.outputs_struct->get_or_make_type().type);
+                implementation->data_layout.get(),
+                implementation->vertex_shader_output_struct->get_or_make_type().type);
 #warning finish implementing Graphics_pipeline::make
             continue;
         }
index 60600440265853f8aa166f32437c51b259503eca..80ccedc5ac3c15b612d38d5c699e1a28950ff6c8 100644 (file)
@@ -204,14 +204,18 @@ public:
                                            void *output_buffer);
 
 public:
-    Vertex_shader_function get_vertex_shader_function() const noexcept
+    void run_vertex_shader(std::uint32_t vertex_start_index,
+                           std::uint32_t vertex_end_index,
+                           std::uint32_t instance_id,
+                           void *output_buffer) const noexcept
     {
-        return vertex_shader_function;
+        vertex_shader_function(vertex_start_index, vertex_end_index, instance_id, output_buffer);
     }
     std::size_t get_vertex_shader_output_struct_size() const noexcept
     {
         return vertex_shader_output_struct_size;
     }
+    void dump_vertex_shader_output_struct(const void *output_struct) const;
     static std::unique_ptr<Graphics_pipeline> make(Pipeline_cache *pipeline_cache,
                                                    const VkGraphicsPipelineCreateInfo &create_info);
     static std::unique_ptr<Graphics_pipeline> move_from_handle(VkPipeline pipeline) noexcept