working on implementing shader uniforms; implemented matrix load/store with transpose
authorJacob Lifshay <programmerjake@gmail.com>
Sun, 24 Sep 2017 08:02:08 +0000 (01:02 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Sun, 24 Sep 2017 08:02:08 +0000 (01:02 -0700)
src/demo/demo.cpp
src/pipeline/pipeline.cpp
src/pipeline/pipeline.h
src/spirv_to_llvm/CMakeLists.txt
src/spirv_to_llvm/core_instructions.cpp
src/spirv_to_llvm/fragment_entry_point.cpp
src/spirv_to_llvm/matrix_operations.h [new file with mode: 0644]
src/spirv_to_llvm/spirv_to_llvm.cpp
src/spirv_to_llvm/spirv_to_llvm.h
src/spirv_to_llvm/spirv_to_llvm_implementation.h
src/spirv_to_llvm/vertex_entry_point.cpp

index d0b976bc707ce236df5634a853aa471103226f5f..400da19089540226ddc28fcf77a8396cd244a97f 100644 (file)
@@ -230,7 +230,7 @@ std::unique_ptr<pipeline::Shader_module> load_shader(vulkan::Vulkan_device &devi
     return pipeline::Shader_module::create(device, shader_module_create_info);
 }
 
-std::unique_ptr<pipeline::Pipeline_layout> make_pipeline_layout(vulkan::Vulkan_device &device)
+std::unique_ptr<vulkan::Vulkan_pipeline_layout> make_pipeline_layout(vulkan::Vulkan_device &device)
 {
     VkPipelineLayoutCreateInfo pipeline_layout_create_info = {
         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
@@ -241,7 +241,7 @@ std::unique_ptr<pipeline::Pipeline_layout> make_pipeline_layout(vulkan::Vulkan_d
         .pushConstantRangeCount = 0,
         .pPushConstantRanges = nullptr,
     };
-    return pipeline::Pipeline_layout::create(device, pipeline_layout_create_info);
+    return vulkan::Vulkan_pipeline_layout::create(device, pipeline_layout_create_info);
 }
 
 template <typename Integer_type>
index 2cb457f7d64d4296a5d1b8af83bb543827c146ac..ed9db49d940c4f0f2c68f586679951ee91bfa76a 100644 (file)
 #include <cassert>
 #include <vector>
 #include <iostream>
+#include <algorithm>
 
 namespace kazan
 {
 namespace pipeline
 {
+Instantiated_pipeline_layout::Instantiated_pipeline_layout(vulkan::Vulkan_pipeline_layout &base,
+                                                           ::LLVMContextRef llvm_context,
+                                                           ::LLVMTargetDataRef target_data)
+    : base(base),
+      descriptor_sets(),
+      type(std::make_shared<spirv_to_llvm::Struct_type_descriptor>(
+          std::vector<spirv::Decoration_with_parameters>{},
+          llvm_context,
+          target_data,
+          "pipeline_layout",
+          0))
+{
+    auto void_pointer_type = std::make_shared<spirv_to_llvm::Pointer_type_descriptor>(
+        std::vector<spirv::Decoration_with_parameters>{},
+        std::make_shared<spirv_to_llvm::Simple_type_descriptor>(
+            std::vector<spirv::Decoration_with_parameters>{},
+            spirv_to_llvm::LLVM_type_and_alignment(
+                llvm_wrapper::Create_llvm_type<char>()(llvm_context), alignof(char))),
+        0,
+        target_data);
+    descriptor_sets.reserve(base.descriptor_set_layouts.size());
+    for(auto *descriptor_set_layout : base.descriptor_set_layouts)
+    {
+        descriptor_sets.emplace_back(*descriptor_set_layout);
+        auto &descriptor_set = descriptor_sets.back();
+        if(descriptor_set_layout->bindings.empty())
+            continue;
+        std::size_t max_binding = 0;
+        for(auto &binding : descriptor_set_layout->bindings)
+            max_binding = std::max(max_binding, static_cast<std::size_t>(binding.binding));
+        std::size_t binding_array_size = max_binding + 1;
+        if(binding_array_size == 0)
+            throw std::bad_alloc(); // overflowed, prevent later out-of-bounds access from
+        // allocating too small
+        descriptor_set.bindings.resize(binding_array_size);
+        for(auto &binding_layout : descriptor_set_layout->bindings)
+        {
+            auto &binding = descriptor_set.bindings[binding_layout.binding];
+            assert(!binding);
+            std::shared_ptr<spirv_to_llvm::Type_descriptor> element_type;
+            switch(binding_layout.descriptor_type)
+            {
+            case VK_DESCRIPTOR_TYPE_SAMPLER:
+#warning implement VK_DESCRIPTOR_TYPE_SAMPLER
+                break;
+            case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+#warning implement VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
+                break;
+            case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+#warning implement VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
+                break;
+            case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+#warning implement VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
+                break;
+            case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+#warning implement VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
+                break;
+            case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+#warning implement VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
+                break;
+            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+                element_type = void_pointer_type;
+                break;
+            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+#warning implement VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
+                break;
+            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+#warning implement VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
+                break;
+            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+#warning implement VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
+                break;
+            case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+#warning implement VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
+                break;
+            case VK_DESCRIPTOR_TYPE_MAX_ENUM:
+            case VK_DESCRIPTOR_TYPE_RANGE_SIZE:
+                break;
+            }
+            assert(element_type && "unimplemented descriptor type");
+            auto binding_type = std::make_shared<spirv_to_llvm::Array_type_descriptor>(
+                std::vector<spirv::Decoration_with_parameters>{},
+                std::move(element_type),
+                binding_layout.descriptor_count,
+                0);
+            auto member_index =
+                type->add_member(spirv_to_llvm::Struct_type_descriptor::Member({}, binding_type));
+            binding = Binding(binding_layout, std::move(binding_type), member_index);
+        }
+    }
+    type->get_members(true); // fill in llvm type
+}
+
 llvm_wrapper::Module Pipeline::optimize_module(llvm_wrapper::Module module,
                                                ::LLVMTargetMachineRef target_machine)
 {
@@ -110,6 +204,7 @@ struct Graphics_pipeline::Implementation
     spirv_to_llvm::Jit_symbol_resolver jit_symbol_resolver;
     llvm_wrapper::Orc_compile_stack jit_stack;
     llvm_wrapper::Target_data data_layout;
+    std::unique_ptr<Instantiated_pipeline_layout> instantiated_pipeline_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,
@@ -853,7 +948,7 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::create(
     assert(create_info.sType == VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO);
     auto *render_pass = vulkan::Vulkan_render_pass::from_handle(create_info.renderPass);
     assert(render_pass);
-    auto *pipeline_layout = Pipeline_layout::from_handle(create_info.layout);
+    auto *pipeline_layout = vulkan::Vulkan_pipeline_layout::from_handle(create_info.layout);
     assert(pipeline_layout);
     if(create_info.flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT)
     {
@@ -866,6 +961,9 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::create(
         optimization_level = ::LLVMCodeGenLevelNone;
     auto llvm_target_machine =
         llvm_wrapper::Target_machine::create_native_target_machine(optimization_level);
+    implementation->data_layout = llvm_target_machine.create_target_data_layout();
+    implementation->instantiated_pipeline_layout = std::make_unique<Instantiated_pipeline_layout>(
+        *pipeline_layout, implementation->llvm_context.get(), implementation->data_layout.get());
     implementation->compiled_shaders.reserve(create_info.stageCount);
     util::Enum_set<spirv::Execution_model> found_shader_stages;
     for(std::size_t i = 0; i < create_info.stageCount; i++)
@@ -897,14 +995,16 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::create(
         assert(create_info.pVertexInputState);
         assert(create_info.pVertexInputState->sType
                == VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO);
-        auto compiled_shader = spirv_to_llvm::spirv_to_llvm(implementation->llvm_context.get(),
-                                                            llvm_target_machine.get(),
-                                                            shader_module->words(),
-                                                            shader_module->word_count(),
-                                                            implementation->compiled_shaders.size(),
-                                                            execution_model,
-                                                            stage_info.pName,
-                                                            create_info.pVertexInputState);
+        auto compiled_shader =
+            spirv_to_llvm::spirv_to_llvm(implementation->llvm_context.get(),
+                                         llvm_target_machine.get(),
+                                         shader_module->words(),
+                                         shader_module->word_count(),
+                                         implementation->compiled_shaders.size(),
+                                         execution_model,
+                                         stage_info.pName,
+                                         create_info.pVertexInputState,
+                                         *implementation->instantiated_pipeline_layout);
         std::cerr << "Translation to LLVM succeeded." << std::endl;
         ::LLVMDumpModule(compiled_shader.module.get());
         bool failed =
@@ -913,7 +1013,6 @@ std::unique_ptr<Graphics_pipeline> Graphics_pipeline::create(
             throw std::runtime_error("LLVM module verification failed");
         implementation->compiled_shaders.push_back(std::move(compiled_shader));
     }
-    implementation->data_layout = llvm_target_machine.create_target_data_layout();
     implementation->jit_stack =
         llvm_wrapper::Orc_compile_stack::create(std::move(llvm_target_machine), optimize_module);
     Vertex_shader_function vertex_shader_function = nullptr;
index 637f363147eecf05239f7667c393832fe1f9589c..d5af52748d4a390345cd3662c41e224910c33bae 100644 (file)
@@ -33,6 +33,7 @@
 #include "vulkan/remove_xlib_macros.h"
 #include "spirv/spirv.h"
 #include "vulkan/api_objects.h"
+#include "spirv_to_llvm/spirv_to_llvm.h"
 
 namespace kazan
 {
@@ -52,17 +53,50 @@ public:
     }
 };
 
-class Pipeline_layout
-    : public vulkan::Vulkan_nondispatchable_object<Pipeline_layout, VkPipelineLayout>
+struct Instantiated_pipeline_layout
 {
-#warning finish implementing Pipeline_layout
-public:
-    static std::unique_ptr<Pipeline_layout> create(vulkan::Vulkan_device &,
-                                                   const VkPipelineLayoutCreateInfo &create_info)
+    vulkan::Vulkan_pipeline_layout &base;
+    struct Binding
     {
-#warning finish implementing Pipeline_layout::create
-        return std::make_unique<Pipeline_layout>();
-    }
+        vulkan::Vulkan_descriptor_set_layout::Binding *base;
+        std::shared_ptr<spirv_to_llvm::Array_type_descriptor> type;
+        std::size_t member_index;
+        constexpr Binding() noexcept : base(), type(), member_index(-1)
+        {
+        }
+        Binding(vulkan::Vulkan_descriptor_set_layout::Binding &base,
+                std::shared_ptr<spirv_to_llvm::Array_type_descriptor> type,
+                std::size_t member_index) noexcept : base(&base),
+                                                     type(std::move(type)),
+                                                     member_index(member_index)
+        {
+        }
+        explicit operator bool() const noexcept
+        {
+            return base != nullptr;
+        }
+    };
+    struct Descriptor_set
+    {
+        vulkan::Vulkan_descriptor_set_layout *base;
+        std::vector<Binding> bindings;
+        Descriptor_set() noexcept : base(nullptr), bindings()
+        {
+        }
+        explicit Descriptor_set(vulkan::Vulkan_descriptor_set_layout &base)
+            : base(&base), bindings()
+        {
+        }
+        explicit operator bool() const noexcept
+        {
+            return base != nullptr;
+        }
+    };
+    std::vector<Descriptor_set> descriptor_sets;
+    std::shared_ptr<spirv_to_llvm::Struct_type_descriptor> type;
+    Instantiated_pipeline_layout(vulkan::Vulkan_pipeline_layout &base,
+                                 ::LLVMContextRef llvm_context,
+                                 ::LLVMTargetDataRef target_data);
 };
 
 struct Shader_module : public vulkan::Vulkan_nondispatchable_object<Shader_module, VkShaderModule>
index df1072aa59ecd3d41d09bb5d4065b6a58605a659..39b1bb85a7684f8c0b7bd7a7c67b53fb99862f02 100644 (file)
@@ -27,4 +27,9 @@ set(sources core_instructions.cpp
             spirv_to_llvm.cpp
             vertex_entry_point.cpp)
 add_library(kazan_spirv_to_llvm STATIC ${sources})
-target_link_libraries(kazan_spirv_to_llvm kazan_util kazan_spirv kazan_llvm_wrapper kazan_pipeline)
+target_link_libraries(kazan_spirv_to_llvm
+                      kazan_util
+                      kazan_spirv
+                      kazan_llvm_wrapper
+                      kazan_pipeline
+                      kazan_vulkan)
index eae8eb1befe7f3bd3bda921e47fb77d98dabc948..172a0aa07f98d111905134ea6bccccc10daa4887 100644 (file)
@@ -1081,8 +1081,14 @@ void Spirv_to_llvm::handle_instruction_op_variable(Op_variable instruction,
                 return;
             }
             case Storage_class::uniform:
-#warning finish implementing Storage_class::uniform
-                break;
+            {
+                if(instruction.initializer)
+                    throw Parser_error(instruction_start_index,
+                                       instruction_start_index,
+                                       "shader uniform variable initializers are not implemented");
+                state.variable = Uniform_variable_state{};
+                return;
+            }
             case Storage_class::output:
             {
                 if(instruction.initializer)
@@ -1237,11 +1243,37 @@ void Spirv_to_llvm::handle_instruction_op_variable(Op_variable instruction,
 #warning finish implementing Decoration::index
                     break;
                 case Decoration::binding:
+                {
+                    switch(instruction.storage_class)
+                    {
+                    case spirv::Storage_class::uniform:
+                        continue;
 #warning finish implementing Decoration::binding
-                    break;
+                    default:
+                        throw Parser_error(
+                            instruction_start_index,
+                            instruction_start_index,
+                            "OpVariable Binding decoration not implemented for storage "
+                            "class: "
+                                + std::string(get_enumerant_name(instruction.storage_class)));
+                    }
+                }
                 case Decoration::descriptor_set:
+                {
+                    switch(instruction.storage_class)
+                    {
+                    case spirv::Storage_class::uniform:
+                        continue;
 #warning finish implementing Decoration::descriptor_set
-                    break;
+                    default:
+                        throw Parser_error(
+                            instruction_start_index,
+                            instruction_start_index,
+                            "OpVariable DescriptorSet decoration not implemented for storage "
+                            "class: "
+                                + std::string(get_enumerant_name(instruction.storage_class)));
+                    }
+                }
                 case Decoration::offset:
 #warning finish implementing Decoration::offset
                     break;
@@ -1472,11 +1504,34 @@ void Spirv_to_llvm::handle_instruction_op_load(Op_load instruction,
             throw Parser_error(instruction_start_index,
                                instruction_start_index,
                                "OpLoad nontemporal not implemented");
-        state.value = Value(::LLVMBuildLoad(builder.get(),
-                                            get_id_state(instruction.pointer).value.value().value,
-                                            get_name(instruction.result).c_str()),
-                            get_type(instruction.result_type, instruction_start_index));
-        ::LLVMSetAlignment(state.value->value, state.value->type->get_or_make_type().alignment);
+        auto result_type = get_type(instruction.result_type, instruction_start_index);
+        auto &pointer_value = get_id_state(instruction.pointer).value.value();
+        assert(dynamic_cast<Pointer_type_descriptor *>(pointer_value.type.get()));
+        auto pointer_type = std::static_pointer_cast<Pointer_type_descriptor>(pointer_value.type);
+        auto memory_type = pointer_type->get_base_type();
+        switch(memory_type->get_load_store_implementation_kind())
+        {
+        case Type_descriptor::Load_store_implementation_kind::Simple:
+            state.value =
+                Value(::LLVMBuildLoad(builder.get(),
+                                      get_id_state(instruction.pointer).value.value().value,
+                                      get_name(instruction.result).c_str()),
+                      result_type);
+            ::LLVMSetAlignment(state.value->value, memory_type->get_or_make_type().alignment);
+            break;
+        case Type_descriptor::Load_store_implementation_kind::Transpose_matrix:
+        {
+            auto untransposed_value = ::LLVMBuildLoad(
+                builder.get(), get_id_state(instruction.pointer).value.value().value, "");
+            ::LLVMSetAlignment(untransposed_value, memory_type->get_or_make_type().alignment);
+            state.value = Value(matrix_operations::transpose(context,
+                                                             builder.get(),
+                                                             untransposed_value,
+                                                             get_name(instruction.result).c_str()),
+                                result_type);
+            break;
+        }
+        }
         break;
     }
     }
@@ -1507,8 +1562,28 @@ void Spirv_to_llvm::handle_instruction_op_store(Op_store instruction,
                                "OpStore nontemporal not implemented");
         auto &object_value = get_id_state(instruction.object).value.value();
         auto &pointer_value = get_id_state(instruction.pointer).value.value();
-        ::LLVMSetAlignment(::LLVMBuildStore(builder.get(), object_value.value, pointer_value.value),
-                           object_value.type->get_or_make_type().alignment);
+        assert(dynamic_cast<Pointer_type_descriptor *>(pointer_value.type.get()));
+        auto pointer_type = std::static_pointer_cast<Pointer_type_descriptor>(pointer_value.type);
+        auto memory_type = pointer_type->get_base_type();
+        switch(memory_type->get_load_store_implementation_kind())
+        {
+        case Type_descriptor::Load_store_implementation_kind::Simple:
+            ::LLVMSetAlignment(
+                ::LLVMBuildStore(builder.get(), object_value.value, pointer_value.value),
+                memory_type->get_or_make_type().alignment);
+            break;
+        case Type_descriptor::Load_store_implementation_kind::Transpose_matrix:
+        {
+            auto transposed_value = matrix_operations::transpose(context,
+                                                             builder.get(),
+                                                             object_value.value,
+                                                             "");
+            ::LLVMSetAlignment(
+                ::LLVMBuildStore(builder.get(), transposed_value, pointer_value.value),
+                memory_type->get_or_make_type().alignment);
+            break;
+        }
+        }
         break;
     }
     }
index 5a5b86855db4a0117fd879459c7bc85504d856b3..0ae3979cb2388d04e658b8157594a5eff179f41d 100644 (file)
@@ -631,6 +631,11 @@ using namespace spirv;
                 after_call_callbacks.push_back(std::move(callback));
             }
         }
+        else if(member_index == uniforms_member)
+        {
+#warning implement shader uniforms
+            assert(this->pipeline_layout.descriptor_sets.empty() && "shader uniforms not implemented");
+        }
         else
         {
             throw Parser_error(0, 0, "internal error: unhandled Io_struct member");
diff --git a/src/spirv_to_llvm/matrix_operations.h b/src/spirv_to_llvm/matrix_operations.h
new file mode 100644 (file)
index 0000000..4b50332
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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 SPIRV_TO_LLVM_MATRIX_OPERATIONS_H_
+#define SPIRV_TO_LLVM_MATRIX_OPERATIONS_H_
+
+#include "llvm_wrapper/llvm_wrapper.h"
+#include "spirv_to_llvm/spirv_to_llvm.h"
+#include <cstdint>
+#include <vector>
+
+namespace kazan
+{
+namespace spirv_to_llvm
+{
+namespace matrix_operations
+{
+struct Matrix_descriptor
+{
+    std::uint32_t rows;
+    std::uint32_t columns;
+    ::LLVMTypeRef column_type;
+    ::LLVMTypeRef element_type;
+    ::LLVMTypeRef matrix_type;
+    explicit Matrix_descriptor(::LLVMTypeRef matrix_type) noexcept : matrix_type(matrix_type)
+    {
+        assert(::LLVMGetTypeKind(matrix_type) == ::LLVMArrayTypeKind);
+        columns = ::LLVMGetArrayLength(matrix_type);
+        column_type = ::LLVMGetElementType(matrix_type);
+        assert(::LLVMGetTypeKind(column_type) == ::LLVMVectorTypeKind);
+        rows = ::LLVMGetVectorSize(column_type);
+        element_type = ::LLVMGetElementType(column_type);
+    }
+    Matrix_descriptor(::LLVMTypeRef element_type, std::uint32_t rows, std::uint32_t columns)
+        : rows(rows),
+          columns(columns),
+          column_type(::LLVMVectorType(element_type, rows)),
+          element_type(element_type),
+          matrix_type(::LLVMArrayType(column_type, columns))
+    {
+    }
+};
+
+inline ::LLVMValueRef transpose(::LLVMContextRef context,
+                                ::LLVMBuilderRef builder,
+                                ::LLVMValueRef input_matrix,
+                                const char *output_name)
+{
+    auto i32_type = llvm_wrapper::Create_llvm_type<std::uint32_t>()(context);
+    Matrix_descriptor input_matrix_descriptor(::LLVMTypeOf(input_matrix));
+    Matrix_descriptor output_matrix_descriptor(input_matrix_descriptor.element_type,
+                                               input_matrix_descriptor.columns,
+                                               input_matrix_descriptor.rows);
+    std::vector<::LLVMValueRef> input_columns;
+    input_columns.reserve(input_matrix_descriptor.columns);
+    for(std::uint32_t input_column = 0; input_column < input_matrix_descriptor.columns;
+        input_column++)
+        input_columns.push_back(::LLVMBuildExtractValue(builder, input_matrix, input_column, ""));
+    auto output_value = ::LLVMGetUndef(output_matrix_descriptor.matrix_type);
+    for(std::uint32_t output_column = 0; output_column < output_matrix_descriptor.columns;
+        output_column++)
+    {
+        auto output_column_value = ::LLVMGetUndef(output_matrix_descriptor.column_type);
+        for(std::uint32_t output_row = 0; output_row < output_matrix_descriptor.rows; output_row++)
+        {
+            auto element_value =
+                ::LLVMBuildExtractElement(builder,
+                                          input_columns[output_row],
+                                          ::LLVMConstInt(i32_type, output_column, false),
+                                          "");
+            output_column_value =
+                ::LLVMBuildInsertElement(builder,
+                                         output_column_value,
+                                         element_value,
+                                         ::LLVMConstInt(i32_type, output_row, false),
+                                         "");
+        }
+        output_value =
+            ::LLVMBuildInsertValue(builder, output_value, output_column_value, output_column, "");
+    }
+    ::LLVMSetValueName(output_value, output_name);
+    return output_value;
+}
+}
+}
+}
+
+#endif // SPIRV_TO_LLVM_MATRIX_OPERATIONS_H_
index d509fccdddb4e28dd75facd03d1b342158980f8f..44e2134183b4a1be01e8e2106a397a5ff22a0910 100644 (file)
@@ -540,14 +540,16 @@ spirv_to_llvm::Converted_module spirv_to_llvm::spirv_to_llvm(
     std::uint64_t shader_id,
     spirv::Execution_model execution_model,
     util::string_view entry_point_name,
-    const VkPipelineVertexInputStateCreateInfo *vertex_input_state)
+    const VkPipelineVertexInputStateCreateInfo *vertex_input_state,
+    pipeline::Instantiated_pipeline_layout &pipeline_layout)
 {
     return Spirv_to_llvm(context,
                          target_machine,
                          shader_id,
                          execution_model,
                          entry_point_name,
-                         vertex_input_state)
+                         vertex_input_state,
+                         pipeline_layout)
         .run(shader_words, shader_size);
 }
 }
index f5ad1d43ebff7d170e746b6a218e7bde56bbf368..7cc0d7c403a5761d8b3973abd0e089bb79bcdc89 100644 (file)
 #include "util/string_view.h"
 #include "vulkan/vulkan.h"
 #include "vulkan/remove_xlib_macros.h"
+#include "vulkan/api_objects.h"
 #include "util/bitset.h"
 
 namespace kazan
 {
+namespace pipeline
+{
+struct Instantiated_pipeline_layout;
+}
+
 namespace spirv_to_llvm
 {
 struct LLVM_type_and_alignment
@@ -236,6 +242,15 @@ public:
             return get_recursion_count() > 1;
         }
     };
+    enum class Load_store_implementation_kind
+    {
+        Simple,
+        Transpose_matrix,
+    };
+    virtual Load_store_implementation_kind get_load_store_implementation_kind()
+    {
+        return Load_store_implementation_kind::Simple;
+    }
 };
 
 class Simple_type_descriptor final : public Type_descriptor
@@ -493,9 +508,14 @@ public:
             target_data);
         column_major_type = std::make_shared<Matrix_type_descriptor>(
             decorations, std::move(column_type), row_type->get_element_count());
-        column_major_type->row_major_type = std::static_pointer_cast<Row_major_matrix_type_descriptor>(shared_from_this());
+        column_major_type->row_major_type =
+            std::static_pointer_cast<Row_major_matrix_type_descriptor>(shared_from_this());
         return column_major_type;
     }
+    virtual Load_store_implementation_kind get_load_store_implementation_kind() override
+    {
+        return Load_store_implementation_kind::Transpose_matrix;
+    }
 };
 
 inline std::shared_ptr<Type_descriptor> Matrix_type_descriptor::make_row_major_type(
@@ -508,7 +528,8 @@ inline std::shared_ptr<Type_descriptor> Matrix_type_descriptor::make_row_major_t
                                                  target_data);
     auto retval = std::make_shared<Row_major_matrix_type_descriptor>(
         decorations, std::move(row_type), column_type->get_element_count());
-    retval->column_major_type = std::static_pointer_cast<Matrix_type_descriptor>(shared_from_this());
+    retval->column_major_type =
+        std::static_pointer_cast<Matrix_type_descriptor>(shared_from_this());
     return retval;
 }
 
@@ -792,7 +813,8 @@ Converted_module spirv_to_llvm(::LLVMContextRef context,
                                std::uint64_t shader_id,
                                spirv::Execution_model execution_model,
                                util::string_view entry_point_name,
-                               const VkPipelineVertexInputStateCreateInfo *vertex_input_state);
+                               const VkPipelineVertexInputStateCreateInfo *vertex_input_state,
+                               pipeline::Instantiated_pipeline_layout &pipeline_layout);
 }
 }
 
index cc4f6bf18c7408da0bce7696fc72a295eb94158a..83d8dfe60a32215ed76bec4ab662446b34db8986 100644 (file)
@@ -28,6 +28,7 @@
 #include "util/variant.h"
 #include "util/enum.h"
 #include "pipeline/pipeline.h"
+#include "matrix_operations.h"
 #include <functional>
 #include <list>
 #include <iostream>
@@ -79,8 +80,13 @@ private:
         std::shared_ptr<Type_descriptor> type;
         std::size_t member_index;
     };
-    typedef util::variant<util::monostate, Input_variable_state, Output_variable_state>
-        Variable_state;
+    struct Uniform_variable_state
+    {
+    };
+    typedef util::variant<util::monostate,
+                          Input_variable_state,
+                          Output_variable_state,
+                          Uniform_variable_state> Variable_state;
     struct Function_state
     {
         struct Entry_block
@@ -223,6 +229,8 @@ private:
     std::size_t outputs_member;
     std::shared_ptr<Struct_type_descriptor> outputs_struct;
     std::shared_ptr<Pointer_type_descriptor> outputs_struct_pointer_type;
+    std::size_t uniforms_member;
+    std::shared_ptr<Pointer_type_descriptor> uniforms_struct_pointer_type;
     Stage stage;
     spirv::Id current_function_id = 0;
     spirv::Id current_basic_block_id = 0;
@@ -233,6 +241,7 @@ private:
     util::string_view entry_point_name;
     Op_entry_point_state *entry_point_state_pointer = nullptr;
     const VkPipelineVertexInputStateCreateInfo *vertex_input_state;
+    pipeline::Instantiated_pipeline_layout &pipeline_layout;
 
 private:
     Id_state &get_id_state(spirv::Id id)
@@ -381,14 +390,16 @@ public:
                            std::uint64_t shader_id,
                            spirv::Execution_model execution_model,
                            util::string_view entry_point_name,
-                           const VkPipelineVertexInputStateCreateInfo *vertex_input_state)
+                           const VkPipelineVertexInputStateCreateInfo *vertex_input_state,
+                           pipeline::Instantiated_pipeline_layout &pipeline_layout)
         : context(context),
           target_machine(target_machine),
           shader_id(shader_id),
           stage(),
           execution_model(execution_model),
           entry_point_name(entry_point_name),
-          vertex_input_state(vertex_input_state)
+          vertex_input_state(vertex_input_state),
+          pipeline_layout(pipeline_layout)
     {
         {
             std::ostringstream ss;
@@ -434,6 +445,10 @@ public:
             std::vector<spirv::Decoration_with_parameters>{}, outputs_struct, 0, target_data);
         outputs_member =
             io_struct->add_member(Struct_type_descriptor::Member({}, outputs_struct_pointer_type));
+        uniforms_struct_pointer_type = std::make_shared<Pointer_type_descriptor>(
+            std::vector<spirv::Decoration_with_parameters>{}, pipeline_layout.type, 0, target_data);
+        uniforms_member =
+            io_struct->add_member(Struct_type_descriptor::Member({}, uniforms_struct_pointer_type));
     }
     ::LLVMValueRef generate_vertex_entry_function(Op_entry_point_state &entry_point,
                                                   ::LLVMValueRef main_function);
index 7ed6f05a9681a4341eeac9470c215e4fc77ed62a..9843972c699b1309250e0af5bc02b2e3f2aa997f 100644 (file)
@@ -850,6 +850,11 @@ using namespace spirv;
                 }
             }
         }
+        else if(member_index == uniforms_member)
+        {
+#warning implement shader uniforms
+            assert(this->pipeline_layout.descriptor_sets.empty() && "shader uniforms not implemented");
+        }
         else
         {
             throw Parser_error(0, 0, "internal error: unhandled Io_struct member");