Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ LOCAL_SRC_FILES:= \
src/vulkan/vertex_buffer.cc \
src/vulkan_engine_config.cc
LOCAL_STATIC_LIBRARIES:=glslang SPIRV-Tools shaderc
LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include
LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include $(LOCAL_PATH)/third_party/vulkan-headers/include
LOCAL_EXPORT_C_INCLUDES:=$(LOCAL_PATH)/include
include $(BUILD_STATIC_LIBRARY)

Expand Down
278 changes: 173 additions & 105 deletions src/vulkan/device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -403,121 +403,145 @@ Result Device::Initialize(
if (!r.IsSuccess())
return r;

bool use_physical_device_features_2 = false;
for (auto& ext : required_instance_extensions) {
if (ext == "VK_KHR_get_physical_device_properties2")
use_physical_device_features_2 = true;
// Check for the core features. We don't know if available_features or
// available_features2 is provided, so check both.
if (!AreAllRequiredFeaturesSupported(available_features, required_features) &&
!AreAllRequiredFeaturesSupported(available_features2.features,
required_features)) {
return Result(
"Vulkan: Device::Initialize given physical device does not support "
"required features");
}

VkPhysicalDeviceFeatures available_vulkan_features =
VkPhysicalDeviceFeatures();
if (use_physical_device_features_2) {
available_vulkan_features = available_features2.features;

VkPhysicalDeviceVariablePointerFeaturesKHR* var_ptrs = nullptr;
VkPhysicalDeviceFloat16Int8FeaturesKHR* float16_ptrs = nullptr;
VkPhysicalDevice8BitStorageFeaturesKHR* storage8_ptrs = nullptr;
VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr;
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*
subgroup_size_control_features = nullptr;
void* ptr = available_features2.pNext;
while (ptr != nullptr) {
BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
if (s->sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR) {
// Search for additional features in case they are found in pNext field of
// available_features2.
VkPhysicalDeviceVariablePointerFeaturesKHR* var_ptrs = nullptr;
VkPhysicalDeviceFloat16Int8FeaturesKHR* float16_ptrs = nullptr;
VkPhysicalDevice8BitStorageFeaturesKHR* storage8_ptrs = nullptr;
VkPhysicalDevice16BitStorageFeaturesKHR* storage16_ptrs = nullptr;
VkPhysicalDeviceVulkan11Features* vulkan11_ptrs = nullptr;
VkPhysicalDeviceVulkan12Features* vulkan12_ptrs = nullptr;
VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*
subgroup_size_control_features = nullptr;
void* ptr = available_features2.pNext;
while (ptr != nullptr) {
BaseOutStructure* s = static_cast<BaseOutStructure*>(ptr);
switch (s->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR:
var_ptrs =
static_cast<VkPhysicalDeviceVariablePointerFeaturesKHR*>(ptr);
} else if (s->sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR) {
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR:
float16_ptrs =
static_cast<VkPhysicalDeviceFloat16Int8FeaturesKHR*>(ptr);
} else if (s->sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR) {
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR:
storage8_ptrs =
static_cast<VkPhysicalDevice8BitStorageFeaturesKHR*>(ptr);
} else if (s->sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR) {
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR:
storage16_ptrs =
static_cast<VkPhysicalDevice16BitStorageFeaturesKHR*>(ptr);
} else if (
s->sType ==
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT) { // NOLINT(whitespace/line_length)
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT:
subgroup_size_control_features =
static_cast<VkPhysicalDeviceSubgroupSizeControlFeaturesEXT*>(ptr);
}
ptr = s->pNext;
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES:
vulkan11_ptrs = static_cast<VkPhysicalDeviceVulkan11Features*>(ptr);
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES:
vulkan12_ptrs = static_cast<VkPhysicalDeviceVulkan12Features*>(ptr);
break;
default:
break;
}
ptr = s->pNext;
}

std::vector<std::string> required_features1;
for (const auto& feature : required_features) {
// No dot means this is a features1 feature.
if (feature.find_first_of('.') == std::string::npos) {
required_features1.push_back(feature);
continue;
}
// Compare the available additional (non-core) features against the
// requirements.
//
// Vulkan 1.2 added support for defining non-core physical device features
// using VkPhysicalDeviceVulkan11Features and VkPhysicalDeviceVulkan12Features
// structures. If |vulkan11_ptrs| and/or |vulkan12_ptrs| are null, we must
// check for features using the old approach (by checking across various
// feature structs); otherwise, we can check features via the new structs.
for (const auto& feature : required_features) {
// First check the feature structures are provided for the required
// features.
if ((feature == kVariablePointers ||
feature == kVariablePointersStorageBuffer) &&
var_ptrs == nullptr && vulkan11_ptrs == nullptr) {
return amber::Result(
"Variable pointers requested but feature not returned");
}
if ((feature == k16BitStorage_Storage ||
feature == k16BitStorage_UniformAndStorage ||
feature == k16BitStorage_PushConstant ||
feature == k16BitStorage_InputOutput) &&
storage16_ptrs == nullptr && vulkan11_ptrs == nullptr) {
return amber::Result(
"Shader 16-bit storage requested but feature not returned");
}
if ((feature == kFloat16Int8_Float16 || feature == kFloat16Int8_Int8) &&
float16_ptrs == nullptr && vulkan12_ptrs == nullptr) {
return amber::Result(
"Shader float16/int8 requested but feature not returned");
}
if ((feature == k8BitStorage_UniformAndStorage ||
feature == k8BitStorage_Storage ||
feature == k8BitStorage_PushConstant) &&
storage8_ptrs == nullptr && vulkan12_ptrs == nullptr) {
return amber::Result(
"Shader 8-bit storage requested but feature not returned");
}
if ((feature == kSubgroupSizeControl || feature == kComputeFullSubgroups) &&
subgroup_size_control_features == nullptr) {
return amber::Result("Missing subgroup size control features");
}

if ((feature == kVariablePointers ||
feature == kVariablePointersStorageBuffer) &&
var_ptrs == nullptr) {
return amber::Result(
"Variable pointers requested but feature not returned");
}
// Next check the fields of the feature structures.

// If Vulkan 1.1 structure exists the features are set there.
if (vulkan11_ptrs) {
if (feature == kVariablePointers &&
var_ptrs->variablePointers != VK_TRUE) {
vulkan11_ptrs->variablePointers != VK_TRUE) {
return amber::Result("Missing variable pointers feature");
}
if (feature == kVariablePointersStorageBuffer &&
var_ptrs->variablePointersStorageBuffer != VK_TRUE) {
vulkan11_ptrs->variablePointersStorageBuffer != VK_TRUE) {
return amber::Result(
"Missing variable pointers storage buffer feature");
}

if ((feature == kFloat16Int8_Float16 || feature == kFloat16Int8_Int8) &&
float16_ptrs == nullptr) {
return amber::Result(
"Shader float16/int8 requested but feature not returned");
}

if (feature == kFloat16Int8_Float16 &&
float16_ptrs->shaderFloat16 != VK_TRUE) {
return amber::Result("Missing float16 feature");
}

if (feature == kFloat16Int8_Int8 && float16_ptrs->shaderInt8 != VK_TRUE) {
return amber::Result("Missing int8 feature");
if (feature == k16BitStorage_Storage &&
vulkan11_ptrs->storageBuffer16BitAccess != VK_TRUE) {
return amber::Result("Missing 16-bit storage access");
}

if ((feature == k8BitStorage_UniformAndStorage ||
feature == k8BitStorage_Storage ||
feature == k8BitStorage_PushConstant) &&
storage8_ptrs == nullptr) {
return amber::Result(
"Shader 8-bit storage requested but feature not returned");
if (feature == k16BitStorage_UniformAndStorage &&
vulkan11_ptrs->uniformAndStorageBuffer16BitAccess != VK_TRUE) {
return amber::Result("Missing 16-bit uniform and storage access");
}

if (feature == k8BitStorage_Storage &&
storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) {
return amber::Result("Missing 8-bit storage access");
if (feature == k16BitStorage_PushConstant &&
vulkan11_ptrs->storagePushConstant16 != VK_TRUE) {
return amber::Result("Missing 16-bit push constant access");
}
if (feature == k8BitStorage_UniformAndStorage &&
storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
return amber::Result("Missing 8-bit uniform and storage access");
if (feature == k16BitStorage_InputOutput &&
vulkan11_ptrs->storageInputOutput16 != VK_TRUE) {
return amber::Result("Missing 16-bit input/output access");
}
if (feature == k8BitStorage_PushConstant &&
storage8_ptrs->storagePushConstant8 != VK_TRUE) {
return amber::Result("Missing 8-bit push constant access");
} else {
// Vulkan 1.1 structure was not found. Use separate structures per each
// feature.
if (feature == kVariablePointers &&
var_ptrs->variablePointers != VK_TRUE) {
return amber::Result("Missing variable pointers feature");
}

if ((feature == k16BitStorage_Storage ||
feature == k16BitStorage_UniformAndStorage ||
feature == k16BitStorage_PushConstant ||
feature == k16BitStorage_InputOutput) &&
storage16_ptrs == nullptr) {
if (feature == kVariablePointersStorageBuffer &&
var_ptrs->variablePointersStorageBuffer != VK_TRUE) {
return amber::Result(
"Shader 16-bit storage requested but feature not returned");
"Missing variable pointers storage buffer feature");
}

if (feature == k16BitStorage_Storage &&
storage16_ptrs->storageBuffer16BitAccess != VK_TRUE) {
return amber::Result("Missing 16-bit storage access");
Expand All @@ -534,31 +558,62 @@ Result Device::Initialize(
storage16_ptrs->storageInputOutput16 != VK_TRUE) {
return amber::Result("Missing 16-bit input/output access");
}
}

if ((feature == kSubgroupSizeControl ||
feature == kComputeFullSubgroups) &&
subgroup_size_control_features == nullptr) {
return amber::Result("Missing subgroup size control features");
// If Vulkan 1.2 structure exists the features are set there.
if (vulkan12_ptrs) {
if (feature == kFloat16Int8_Float16 &&
vulkan12_ptrs->shaderFloat16 != VK_TRUE) {
return amber::Result("Missing float16 feature");
}
if (feature == kFloat16Int8_Int8 &&
vulkan12_ptrs->shaderInt8 != VK_TRUE) {
return amber::Result("Missing int8 feature");
}
if (feature == k8BitStorage_Storage &&
vulkan12_ptrs->storageBuffer8BitAccess != VK_TRUE) {
return amber::Result("Missing 8-bit storage access");
}
if (feature == k8BitStorage_UniformAndStorage &&
vulkan12_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
return amber::Result("Missing 8-bit uniform and storage access");
}
if (feature == k8BitStorage_PushConstant &&
vulkan12_ptrs->storagePushConstant8 != VK_TRUE) {
return amber::Result("Missing 8-bit push constant access");
}
} else {
// Vulkan 1.2 structure was not found. Use separate structures per each
// feature.
if (feature == kFloat16Int8_Float16 &&
float16_ptrs->shaderFloat16 != VK_TRUE) {
return amber::Result("Missing float16 feature");
}
if (feature == kFloat16Int8_Int8 && float16_ptrs->shaderInt8 != VK_TRUE) {
return amber::Result("Missing int8 feature");
}
if (feature == kSubgroupSizeControl &&
subgroup_size_control_features->subgroupSizeControl != VK_TRUE) {
return amber::Result("Missing subgroup size control feature");
if (feature == k8BitStorage_Storage &&
storage8_ptrs->storageBuffer8BitAccess != VK_TRUE) {
return amber::Result("Missing 8-bit storage access");
}
if (feature == k8BitStorage_UniformAndStorage &&
storage8_ptrs->uniformAndStorageBuffer8BitAccess != VK_TRUE) {
return amber::Result("Missing 8-bit uniform and storage access");
}
if (feature == kComputeFullSubgroups &&
subgroup_size_control_features->computeFullSubgroups != VK_TRUE) {
return amber::Result("Missing compute full subgroups feature");
if (feature == k8BitStorage_PushConstant &&
storage8_ptrs->storagePushConstant8 != VK_TRUE) {
return amber::Result("Missing 8-bit push constant access");
}
}

} else {
available_vulkan_features = available_features;
}

if (!AreAllRequiredFeaturesSupported(available_vulkan_features,
required_features)) {
return Result(
"Vulkan: Device::Initialize given physical device does not support "
"required features");
if (feature == kSubgroupSizeControl &&
subgroup_size_control_features->subgroupSizeControl != VK_TRUE) {
return amber::Result("Missing subgroup size control feature");
}
if (feature == kComputeFullSubgroups &&
subgroup_size_control_features->computeFullSubgroups != VK_TRUE) {
return amber::Result("Missing compute full subgroups feature");
}
}

if (!AreAllExtensionsSupported(available_extensions,
Expand All @@ -574,11 +629,24 @@ Result Device::Initialize(
ptrs_.vkGetPhysicalDeviceMemoryProperties(physical_device_,
&physical_memory_properties_);

bool use_physical_device_features_2 = false;
for (auto& ext : required_instance_extensions) {
if (ext == "VK_KHR_get_physical_device_properties2")
use_physical_device_features_2 = true;
}

subgroup_size_control_properties_ = {};
const bool needs_subgroup_size_control =
std::find(required_features.begin(), required_features.end(),
kSubgroupSizeControl) != required_features.end();
if (needs_subgroup_size_control && use_physical_device_features_2) {

if (needs_subgroup_size_control) {
if (!use_physical_device_features_2) {
return Result(
"Vulkan: Device::Initialize subgroup size control feature also "
"requires VK_KHR_get_physical_device_properties2");
}

PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
getInstanceProcAddr(instance_,
Expand Down