diff options
-rw-r--r-- | src/vulkan/device.cc | 73 | ||||
-rw-r--r-- | src/vulkan/device.h | 16 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.cc | 18 | ||||
-rw-r--r-- | src/vulkan/engine_vulkan.h | 3 | ||||
-rw-r--r-- | tests/cases/compute_in_spirv_generated_by_clspv.amber | 163 |
5 files changed, 249 insertions, 24 deletions
diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc index 98a9c70..cd08d8a 100644 --- a/src/vulkan/device.cc +++ b/src/vulkan/device.cc @@ -15,6 +15,7 @@ #include "src/vulkan/device.h" #include <memory> +#include <set> #include <vector> #include "src/make_unique.h" @@ -204,8 +205,13 @@ VkPhysicalDeviceFeatures RequestedFeatures( } bool AreAllRequiredFeaturesSupported( - const VkPhysicalDeviceFeatures& available_features, + const VkPhysicalDevice& physical_device, const std::vector<Feature>& required_features) { + if (required_features.empty()) + return true; + + VkPhysicalDeviceFeatures available_features = {}; + vkGetPhysicalDeviceFeatures(physical_device, &available_features); for (const auto& feature : required_features) { switch (feature) { case Feature::kRobustBufferAccess: @@ -444,6 +450,40 @@ bool AreAllRequiredFeaturesSupported( return true; } +bool AreAllExtensionsSupported( + const VkPhysicalDevice& physical_device, + const std::vector<std::string>& required_extensions) { + if (required_extensions.empty()) + return true; + + uint32_t available_extension_count = 0; + std::vector<VkExtensionProperties> available_extension_properties; + + if (vkEnumerateDeviceExtensionProperties(physical_device, nullptr, + &available_extension_count, + nullptr) != VK_SUCCESS) { + return false; + } + + if (available_extension_count == 0) + return false; + + available_extension_properties.resize(available_extension_count); + if (vkEnumerateDeviceExtensionProperties( + physical_device, nullptr, &available_extension_count, + available_extension_properties.data()) != VK_SUCCESS) { + return false; + } + + std::set<std::string> required_extension_set(required_extensions.begin(), + required_extensions.end()); + for (const auto& property : available_extension_properties) { + required_extension_set.erase(property.extensionName); + } + + return required_extension_set.empty(); +} + } // namespace Device::Device() = default; @@ -457,17 +497,18 @@ void Device::Shutdown() { } } -Result Device::Initialize(const std::vector<Feature>& required_features) { +Result Device::Initialize(const std::vector<Feature>& required_features, + const std::vector<std::string>& required_extensions) { if (device_ == VK_NULL_HANDLE) { Result r = CreateInstance(); if (!r.IsSuccess()) return r; - r = ChoosePhysicalDevice(required_features); + r = ChoosePhysicalDevice(required_features, required_extensions); if (!r.IsSuccess()) return r; - r = CreateDevice(required_features); + r = CreateDevice(required_features, required_extensions); if (!r.IsSuccess()) return r; } @@ -526,7 +567,8 @@ Result Device::CreateInstance() { } Result Device::ChoosePhysicalDevice( - const std::vector<Feature>& required_features) { + const std::vector<Feature>& required_features, + const std::vector<std::string>& required_extensions) { uint32_t count; std::vector<VkPhysicalDevice> physical_devices; @@ -538,11 +580,14 @@ Result Device::ChoosePhysicalDevice( return Result("Vulkan::Calling vkEnumeratePhysicalDevices Fail"); for (uint32_t i = 0; i < count; ++i) { - VkPhysicalDeviceFeatures available_features = {}; - vkGetPhysicalDeviceFeatures(physical_devices[i], &available_features); + if (!AreAllRequiredFeaturesSupported(physical_devices[i], + required_features)) { + continue; + } - if (!AreAllRequiredFeaturesSupported(available_features, required_features)) + if (!AreAllExtensionsSupported(physical_devices[i], required_extensions)) { continue; + } if (ChooseQueueFamilyIndex(physical_devices[i])) { physical_device_ = physical_devices[i]; @@ -555,7 +600,9 @@ Result Device::ChoosePhysicalDevice( return Result("Vulkan::No physical device supports Vulkan"); } -Result Device::CreateDevice(const std::vector<Feature>& required_features) { +Result Device::CreateDevice( + const std::vector<Feature>& required_features, + const std::vector<std::string>& required_extensions) { VkDeviceQueueCreateInfo queue_info; const float priorities[] = {1.0f}; @@ -568,11 +615,17 @@ Result Device::CreateDevice(const std::vector<Feature>& required_features) { info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; info.pQueueCreateInfos = &queue_info; info.queueCreateInfoCount = 1; - // TODO(jaebaek): Enable layers, extensions + // TODO(jaebaek): Enable layers VkPhysicalDeviceFeatures requested_features = RequestedFeatures(required_features); info.pEnabledFeatures = &requested_features; + std::vector<const char*> enabled_extensions; + for (size_t i = 0; i < required_extensions.size(); ++i) + enabled_extensions.push_back(required_extensions[i].c_str()); + info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()); + info.ppEnabledExtensionNames = enabled_extensions.data(); + if (vkCreateDevice(physical_device_, &info, nullptr, &device_) != VK_SUCCESS) return Result("Vulkan::Calling vkCreateDevice Fail"); diff --git a/src/vulkan/device.h b/src/vulkan/device.h index f636701..07eb709 100644 --- a/src/vulkan/device.h +++ b/src/vulkan/device.h @@ -16,6 +16,7 @@ #define SRC_VULKAN_DEVICE_H_ #include <memory> +#include <string> #include <vector> #include "amber/result.h" @@ -32,7 +33,8 @@ class Device { explicit Device(VkDevice device); ~Device(); - Result Initialize(const std::vector<Feature>& required_features); + Result Initialize(const std::vector<Feature>& required_features, + const std::vector<std::string>& required_extensions); void Shutdown(); VkDevice GetDevice() const { return device_; } @@ -46,8 +48,10 @@ class Device { Result CreateInstance(); // Get a physical device by checking if the physical device has a proper - // queue family. - Result ChoosePhysicalDevice(const std::vector<Feature>& required_features); + // queue family, required features, and required extensions. + Result ChoosePhysicalDevice( + const std::vector<Feature>& required_features, + const std::vector<std::string>& required_extensions); // Return true if |physical_device| has a queue family that supports both // graphics and compute or only a compute pipeline. If the proper queue @@ -56,8 +60,10 @@ class Device { // queue family does not exist. bool ChooseQueueFamilyIndex(const VkPhysicalDevice& physical_device); - // Create a logical device. - Result CreateDevice(const std::vector<Feature>& required_features); + // Create a logical device with enabled features |required_features| + // and enabled extensions|required_extensions|. + Result CreateDevice(const std::vector<Feature>& required_features, + const std::vector<std::string>& required_extensions); VkInstance instance_ = VK_NULL_HANDLE; VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; diff --git a/src/vulkan/engine_vulkan.cc b/src/vulkan/engine_vulkan.cc index 896f648..b517000 100644 --- a/src/vulkan/engine_vulkan.cc +++ b/src/vulkan/engine_vulkan.cc @@ -58,8 +58,9 @@ EngineVulkan::EngineVulkan() : Engine() {} EngineVulkan::~EngineVulkan() = default; Result EngineVulkan::InitDeviceAndCreateCommand( - const std::vector<Feature>& features) { - Result r = device_->Initialize(features); + const std::vector<Feature>& features, + const std::vector<std::string>& extensions) { + Result r = device_->Initialize(features, extensions); if (!r.IsSuccess()) return r; @@ -74,17 +75,18 @@ Result EngineVulkan::InitDeviceAndCreateCommand( } Result EngineVulkan::Initialize(const std::vector<Feature>& features, - const std::vector<std::string>&) { + const std::vector<std::string>& extensions) { if (device_) return Result("Vulkan::Set device_ already exists"); device_ = MakeUnique<Device>(); - return InitDeviceAndCreateCommand(features); + return InitDeviceAndCreateCommand(features, extensions); } -Result EngineVulkan::InitializeWithConfig(EngineConfig* config, - const std::vector<Feature>& features, - const std::vector<std::string>&) { +Result EngineVulkan::InitializeWithConfig( + EngineConfig* config, + const std::vector<Feature>& features, + const std::vector<std::string>& extensions) { if (device_) return Result("Vulkan::Set device_ already exists"); @@ -93,7 +95,7 @@ Result EngineVulkan::InitializeWithConfig(EngineConfig* config, return Result("Vulkan::InitializeWithConfig device handle is null."); device_ = MakeUnique<Device>(vk_config->device); - return InitDeviceAndCreateCommand(features); + return InitDeviceAndCreateCommand(features, extensions); } Result EngineVulkan::Shutdown() { diff --git a/src/vulkan/engine_vulkan.h b/src/vulkan/engine_vulkan.h index 06da9a4..aa06c0c 100644 --- a/src/vulkan/engine_vulkan.h +++ b/src/vulkan/engine_vulkan.h @@ -68,7 +68,8 @@ class EngineVulkan : public Engine { ResourceInfo* info) override; private: - Result InitDeviceAndCreateCommand(const std::vector<Feature>& features); + Result InitDeviceAndCreateCommand(const std::vector<Feature>& features, + const std::vector<std::string>& extensions); std::vector<VkPipelineShaderStageCreateInfo> GetShaderStageInfo(); diff --git a/tests/cases/compute_in_spirv_generated_by_clspv.amber b/tests/cases/compute_in_spirv_generated_by_clspv.amber new file mode 100644 index 0000000..fba1eaf --- /dev/null +++ b/tests/cases/compute_in_spirv_generated_by_clspv.amber @@ -0,0 +1,163 @@ +[comment] +Source code in OpenCL C: + +typedef struct { int arr[2]; } S1; +typedef struct { S1 s1; int a; S1 s2; } S2; + +S2 make_s2(int n) { + S2 s2; + s2.s1.arr[0] = n; + s2.s1.arr[1] = n; + s2.a = n; + s2.s2.arr[0] = n; + s2.s2.arr[1] = n; + return s2; +} + +S2 choose(int n) { + if (n > 0) return make_s2(n - 5); + return make_s2(0); +} + +kernel void foo(global S2 *data, int n) { + *data = choose(n); +} + +The following SPIR-V code was generated by CLSPV with -cl-opt-disable option. +GIT_COMMIT = 8638849b2167fcba90dbff0ee4cfe7dbf0380d24 + +[compute shader spirv] +; SPIR-V +; Version: 1.0 +; Generator: Codeplay; 0 +; Bound: 71 +; Schema: 0 + OpCapability Shader + OpCapability VariablePointers + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_KHR_variable_pointers" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %52 "main" + OpSource OpenCL_C 120 + OpDecorate %24 SpecId 0 + OpDecorate %25 SpecId 1 + OpDecorate %26 SpecId 2 + OpMemberDecorate %_struct_4 0 Offset 0 + OpMemberDecorate %_struct_5 0 Offset 0 + OpMemberDecorate %_struct_5 1 Offset 8 + OpMemberDecorate %_struct_5 2 Offset 12 + OpDecorate %_runtimearr__struct_5 ArrayStride 20 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 Block + OpMemberDecorate %_struct_9 0 Offset 0 + OpDecorate %_struct_9 Block + OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize + OpDecorate %29 DescriptorSet 0 + OpDecorate %29 Binding 0 + OpDecorate %30 DescriptorSet 0 + OpDecorate %30 Binding 1 + OpDecorate %_arr_uint_uint_2 ArrayStride 4 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_arr_uint_uint_2 = OpTypeArray %uint %uint_2 + %_struct_4 = OpTypeStruct %_arr_uint_uint_2 + %_struct_5 = OpTypeStruct %_struct_4 %uint %_struct_4 +%_runtimearr__struct_5 = OpTypeRuntimeArray %_struct_5 + %_struct_7 = OpTypeStruct %_runtimearr__struct_5 +%_ptr_StorageBuffer__struct_7 = OpTypePointer StorageBuffer %_struct_7 + %_struct_9 = OpTypeStruct %uint +%_ptr_StorageBuffer__struct_9 = OpTypePointer StorageBuffer %_struct_9 + %void = OpTypeVoid + %12 = OpTypeFunction %void +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %14 = OpTypeFunction %_struct_5 %uint + %bool = OpTypeBool + %v3uint = OpTypeVector %uint 3 +%_ptr_Private_v3uint = OpTypePointer Private %v3uint + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %20 = OpUndef %_struct_5 + %false = OpConstantFalse %bool + %true = OpConstantTrue %bool +%uint_4294967291 = OpConstant %uint 4294967291 + %24 = OpSpecConstant %uint 1 + %25 = OpSpecConstant %uint 1 + %26 = OpSpecConstant %uint 1 +%gl_WorkGroupSize = OpSpecConstantComposite %v3uint %24 %25 %26 + %28 = OpVariable %_ptr_Private_v3uint Private %gl_WorkGroupSize + %29 = OpVariable %_ptr_StorageBuffer__struct_7 StorageBuffer + %30 = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer + %31 = OpFunction %_struct_5 Const %14 + %32 = OpFunctionParameter %uint + %33 = OpLabel + %34 = OpCompositeConstruct %_arr_uint_uint_2 %32 %32 + %35 = OpCompositeConstruct %_struct_4 %34 + %36 = OpCompositeConstruct %_struct_5 %35 %32 %35 + OpReturnValue %36 + OpFunctionEnd + %37 = OpFunction %_struct_5 Const %14 + %38 = OpFunctionParameter %uint + %39 = OpLabel + %40 = OpSGreaterThan %bool %38 %uint_0 + %41 = OpLogicalNot %bool %40 + OpSelectionMerge %44 None + OpBranchConditional %41 %42 %44 + %42 = OpLabel + %43 = OpFunctionCall %_struct_5 %31 %uint_0 + OpBranch %44 + %44 = OpLabel + %46 = OpPhi %bool %false %42 %true %39 + %45 = OpPhi %_struct_5 %43 %42 %20 %39 + OpSelectionMerge %47 None + OpBranchConditional %46 %49 %47 + %47 = OpLabel + %48 = OpPhi %_struct_5 %45 %44 %51 %49 + OpReturnValue %48 + %49 = OpLabel + %50 = OpIAdd %uint %38 %uint_4294967291 + %51 = OpFunctionCall %_struct_5 %31 %50 + OpBranch %47 + OpFunctionEnd + %52 = OpFunction %void None %12 + %53 = OpLabel + %54 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 + %55 = OpLoad %uint %54 + %56 = OpFunctionCall %_struct_5 %37 %55 + %57 = OpCompositeExtract %_struct_4 %56 0 + %58 = OpCompositeExtract %_arr_uint_uint_2 %57 0 + %59 = OpCompositeExtract %uint %58 0 + %60 = OpCompositeExtract %uint %58 1 + %61 = OpCompositeExtract %uint %56 1 + %62 = OpCompositeExtract %_struct_4 %56 2 + %63 = OpCompositeExtract %_arr_uint_uint_2 %62 0 + %64 = OpCompositeExtract %uint %63 0 + %65 = OpCompositeExtract %uint %63 1 + %66 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_0 %uint_0 %uint_0 + OpStore %66 %59 + %67 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_0 %uint_0 %uint_1 + OpStore %67 %60 + %68 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_1 + OpStore %68 %61 + %69 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_2 %uint_0 %uint_0 + OpStore %69 %64 + %70 = OpAccessChain %_ptr_StorageBuffer_uint %29 %uint_0 %uint_0 %uint_2 %uint_0 %uint_1 + OpStore %70 %65 + OpReturn + OpFunctionEnd +[require] +VK_KHR_storage_buffer_storage_class +VK_KHR_variable_pointers + +[test] +# ssbo [bind] subdata [type] [offset] [values ...] +ssbo 0 subdata int 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +ssbo 1 subdata int 0 13 + +compute 3 1 1 + +# probe ssbo [type] [bind] [offset] == [values ...] +probe ssbo int 0 0 == 8 +probe ssbo int 0 4 == 8 +probe ssbo int 0 8 == 8 +probe ssbo int 0 12 == 8 +probe ssbo int 0 16 == 8 |