blob: 26a33e30e7351dc75278e0269254c6b0da8e811f [file] [log] [blame]
// Copyright 2021 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "iree/hal/drivers/vulkan/builtin_executables.h"
#include <cstddef>
#include "iree/hal/drivers/vulkan/builtin/builtin_shaders_spv.h"
#include "iree/hal/drivers/vulkan/pipeline_layout.h"
#include "iree/hal/drivers/vulkan/status_util.h"
namespace iree {
namespace hal {
namespace vulkan {
namespace {
typedef struct iree_hal_vulkan_builtin_fill_unaligned_constants_t {
uint32_t fill_pattern;
uint32_t fill_pattern_width;
uint32_t fill_offset_bytes;
uint32_t fill_length_bytes;
} iree_hal_vulkan_builtin_fill_unaligned_constants_t;
static_assert(sizeof(iree_hal_vulkan_builtin_fill_unaligned_constants_t) ==
IREE_HAL_VULKAN_BUILTIN_PUSH_CONSTANTS_SIZE,
"push constant count must match struct size");
} // namespace
BuiltinExecutables::BuiltinExecutables(VkDeviceHandle* logical_device)
: logical_device_(logical_device) {}
BuiltinExecutables::~BuiltinExecutables() {
if (pipeline_ != VK_NULL_HANDLE) {
logical_device_->syms()->vkDestroyPipeline(*logical_device_, pipeline_,
logical_device_->allocator());
}
if (pipeline_layout_) {
iree_hal_vulkan_pipeline_layout_release(pipeline_layout_);
}
for (size_t i = 0; i < IREE_HAL_VULKAN_BUILTIN_DESCRIPTOR_SET_COUNT; ++i) {
iree_hal_vulkan_descriptor_set_layout_release(descriptor_set_layouts_[i]);
}
}
iree_status_t BuiltinExecutables::InitializeExecutables() {
IREE_TRACE_SCOPE();
// Create descriptor set layouts for our compute pipeline.
// Even though we're just using one set, we still need to create dummy set
// layout (without any bindings) for those preceding this set.
for (size_t i = 0; i < IREE_HAL_VULKAN_BUILTIN_DESCRIPTOR_SET_COUNT; ++i) {
iree_hal_vulkan_descriptor_set_layout_t* layout = NULL;
if (i == IREE_HAL_VULKAN_BUILTIN_DESCRIPTOR_SET) {
VkDescriptorSetLayoutBinding layout_binding;
layout_binding.binding = 0;
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
layout_binding.descriptorCount = 1;
layout_binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
layout_binding.pImmutableSamplers = NULL;
IREE_RETURN_IF_ERROR(iree_hal_vulkan_descriptor_set_layout_create(
logical_device_, /*flags=*/0,
/*binding_count=*/1, &layout_binding, &layout));
} else {
IREE_RETURN_IF_ERROR(iree_hal_vulkan_descriptor_set_layout_create(
logical_device_, /*flags=*/0,
/*binding_count=*/0, /*bindings=*/nullptr, &layout));
}
descriptor_set_layouts_[i] = layout;
}
iree_status_t status = iree_ok_status();
// Create shader module.
VkShaderModule fill_unaligned_shader = VK_NULL_HANDLE;
if (iree_status_is_ok(status)) {
VkShaderModuleCreateInfo shader_create_info;
shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_create_info.pNext = NULL;
shader_create_info.flags = 0;
shader_create_info.codeSize = builtin_shaders_spv_create()[0].size;
shader_create_info.pCode =
(const uint32_t*)builtin_shaders_spv_create()[0].data;
status = VK_RESULT_TO_STATUS(logical_device_->syms()->vkCreateShaderModule(
*logical_device_, &shader_create_info, logical_device_->allocator(),
&fill_unaligned_shader));
}
// Create pipeline layout.
if (iree_status_is_ok(status)) {
VkPushConstantRange push_constant_ranges[1];
push_constant_ranges[0].offset = 0;
push_constant_ranges[0].size = IREE_HAL_VULKAN_BUILTIN_PUSH_CONSTANTS_SIZE;
push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
status = iree_hal_vulkan_pipeline_layout_create(
logical_device_, IREE_ARRAYSIZE(push_constant_ranges),
push_constant_ranges, IREE_HAL_VULKAN_BUILTIN_DESCRIPTOR_SET_COUNT,
descriptor_set_layouts_, &pipeline_layout_);
}
// Create pipeline.
if (iree_status_is_ok(status)) {
VkComputePipelineCreateInfo pipeline_create_info;
pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
pipeline_create_info.pNext = NULL;
pipeline_create_info.flags = VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT;
pipeline_create_info.layout =
iree_hal_vulkan_pipeline_layout_handle(pipeline_layout_);
pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE;
pipeline_create_info.basePipelineIndex = 0;
VkPipelineShaderStageCreateInfo* stage_create_info =
&pipeline_create_info.stage;
stage_create_info->sType =
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
stage_create_info->pNext = NULL;
stage_create_info->flags = 0;
stage_create_info->stage = VK_SHADER_STAGE_COMPUTE_BIT;
stage_create_info->module = fill_unaligned_shader;
stage_create_info->pName = "main";
stage_create_info->pSpecializationInfo = NULL;
status =
VK_RESULT_TO_STATUS(logical_device_->syms()->vkCreateComputePipelines(
*logical_device_, /*pipeline_cache=*/VK_NULL_HANDLE,
/*pipeline_count=*/1, &pipeline_create_info,
logical_device_->allocator(), &pipeline_));
}
// Destroy shader module now that the pipeline is created.
if (fill_unaligned_shader != VK_NULL_HANDLE) {
logical_device_->syms()->vkDestroyShaderModule(
*logical_device_, fill_unaligned_shader, logical_device_->allocator());
}
return status;
}
iree_status_t BuiltinExecutables::FillBufferUnaligned(
VkCommandBuffer command_buffer, DescriptorSetArena* descriptor_set_arena,
iree_hal_buffer_t* target_buffer, iree_device_size_t target_offset,
iree_device_size_t length, const void* pattern,
iree_host_size_t pattern_length) {
IREE_TRACE_SCOPE();
iree_hal_vulkan_builtin_fill_unaligned_constants_t constants;
switch (pattern_length) {
case 1:
constants.fill_pattern = *static_cast<const uint8_t*>(pattern);
break;
case 2:
constants.fill_pattern = *static_cast<const uint16_t*>(pattern);
break;
case 4:
constants.fill_pattern = *static_cast<const uint32_t*>(pattern);
break;
default:
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"pattern length (%" PRIhsz
") is not a power of two or is too large",
pattern_length);
}
iree_hal_buffer_ref_t binding;
binding.reserved = 0;
binding.buffer = target_buffer;
binding.offset = 0;
binding.length = IREE_HAL_WHOLE_BUFFER;
IREE_RETURN_IF_ERROR(descriptor_set_arena->BindDescriptorSet(
command_buffer, pipeline_layout_, IREE_HAL_VULKAN_BUILTIN_DESCRIPTOR_SET,
/*binding_count=*/1, &binding));
logical_device_->syms()->vkCmdBindPipeline(
command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_);
constants.fill_pattern_width = pattern_length;
constants.fill_offset_bytes = target_offset;
constants.fill_length_bytes = length;
logical_device_->syms()->vkCmdPushConstants(
command_buffer, iree_hal_vulkan_pipeline_layout_handle(pipeline_layout_),
VK_SHADER_STAGE_COMPUTE_BIT, /*offset=*/0,
sizeof(iree_hal_vulkan_builtin_fill_unaligned_constants_t), &constants);
// TODO(scotttodd): insert memory barrier if we need to do dispatch<->dispatch
// synchronization. The barriers inserted normally by callers would be for
// transfer<->dispatch.
logical_device_->syms()->vkCmdDispatch(command_buffer, 1, 1, 1);
return iree_ok_status();
}
} // namespace vulkan
} // namespace hal
} // namespace iree