#include "pipeline.h"

#include "renderer.h"
#include "texture.h"

void pipeline::create_pipeline_layout() {
    const renderer* render_vk = application::get()->get_renderer();
    const vk::Device& device = render_vk->device;

    vk::DescriptorSetLayoutCreateInfo descriptor_set_layout_create_info;
    descriptor_set_layout_create_info.setBindings(descriptor_set_layout_bindings_);
    descriptor_set_layout_ = device.createDescriptorSetLayout(descriptor_set_layout_create_info);

    vk::PipelineLayoutCreateInfo pipeline_layout_create_info;
    pipeline_layout_create_info.setSetLayouts(descriptor_set_layout_);
    pipeline_layout_ = device.createPipelineLayout(pipeline_layout_create_info);

    vk::DescriptorSetAllocateInfo descriptor_set_allocate_info;
    descriptor_set_allocate_info.setDescriptorPool(render_vk->descriptor_pool);
    descriptor_set_allocate_info.setSetLayouts(descriptor_set_layout_);
    descriptor_set_ = device.allocateDescriptorSets(descriptor_set_allocate_info).front();

    std::vector<vk::WriteDescriptorSet> write_descriptor_sets;

    for (const auto& binding_info: descriptor_set_layout_bindings_) {
        vk::WriteDescriptorSet write_descriptor_set;
        write_descriptor_set.setDstSet(descriptor_set_);
        write_descriptor_set.setDstBinding(binding_info.binding);
        write_descriptor_set.setDescriptorType(binding_info.descriptorType);

        switch (binding_info.descriptorType) {
            case vk::DescriptorType::eCombinedImageSampler:
            case vk::DescriptorType::eSampledImage:
            case vk::DescriptorType::eStorageImage: {
                const auto& t = textures_[binding_info.binding];
                vk::DescriptorImageInfo image_info = *t.get();
                write_descriptor_set.setImageInfo(image_info);
            }
                break;
            case vk::DescriptorType::eUniformBuffer:
            case vk::DescriptorType::eStorageBuffer: {
                vk::DescriptorBufferInfo buffer_info = buffers_[binding_info.binding];
                write_descriptor_set.setBufferInfo(buffer_info);
            }
                break;
            default:
                continue;
        }
        write_descriptor_sets.push_back(write_descriptor_set);
    }

    device.updateDescriptorSets(write_descriptor_sets, nullptr);
}