blob: 7fb0de60ee8f849689fe6e2ed06ce5671a4d0797 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "utils.h"
#include <cassert>
#include <cstdio>
#include <optional>
#include <unordered_set>
namespace {
static void PrintProps(const std::vector<std::string> &props) {
for (const auto &prop : props) {
printf("\t%s\n", prop.c_str());
}
printf("\n");
}
} // namespace
namespace vkp {
//
// Enumerate properties categorically using |search_prop| and populate |props_found_set|
// with the results. Returns false if no properties are enumerated.
//
static bool EnumerateProperties(SearchProp search_prop, vk::PhysicalDevice physical_device,
const char *layer,
std::unordered_set<std::string> *enumerated_props) {
std::optional<vk::ResultValue<std::vector<vk::ExtensionProperties>>> rv_ext_props;
std::optional<vk::ResultValue<std::vector<vk::LayerProperties>>> rv_layer_props;
std::vector<vk::ExtensionProperties> ext_props;
std::vector<vk::LayerProperties> layer_props;
switch (search_prop) {
case INSTANCE_EXT_PROP:
if (layer) {
rv_ext_props = vk::enumerateInstanceExtensionProperties(std::string(layer));
} else {
rv_ext_props = vk::enumerateInstanceExtensionProperties(nullptr);
}
RTN_IF_VKH_ERR(false, rv_ext_props->result,
"Failed to enumerate instance extension properties.\n");
ext_props = rv_ext_props->value;
break;
case INSTANCE_LAYER_PROP:
rv_layer_props = vk::enumerateInstanceLayerProperties();
RTN_IF_VKH_ERR(false, rv_layer_props->result,
"Failed to enumerate instance layer properties.\n");
layer_props = rv_layer_props->value;
break;
case PHYS_DEVICE_EXT_PROP:
assert(physical_device && "Null physical device used for phys device property query.");
if (layer) {
rv_ext_props = physical_device.enumerateDeviceExtensionProperties(std::string(layer));
} else {
rv_ext_props = physical_device.enumerateDeviceExtensionProperties(nullptr);
}
RTN_IF_VKH_ERR(false, rv_ext_props->result,
"Failed to enumerate physical device extension properties.\n");
ext_props = rv_ext_props->value;
break;
}
if (search_prop == INSTANCE_LAYER_PROP) {
for (auto &prop : layer_props) {
enumerated_props->insert(std::string(prop.layerName));
}
} else {
for (auto &prop : ext_props) {
if (search_prop == PHYS_DEVICE_EXT_PROP && layer) {
printf("Phys Dev Props: layer(%s) prop(%s)\n", layer,
std::string(prop.extensionName).c_str());
}
enumerated_props->insert(std::string(prop.extensionName));
}
}
return true;
}
bool FindRequiredProperties(const std::vector<const char *> &required_props, SearchProp search_prop,
const char *layer, vk::PhysicalDevice physical_device,
std::vector<std::string> *missing_props_out) {
std::unordered_set<std::string> enumerated_props_set;
// Match Vulkan properties. "Vulkan properties" are those found when the
// layer argument is set to null.
bool success =
EnumerateProperties(search_prop, physical_device, nullptr /* layer */, &enumerated_props_set);
if (!success) {
if (missing_props_out) {
missing_props_out->insert(missing_props_out->end(), required_props.begin(),
required_props.end());
}
RTN_MSG(false, "Unable to match vulkan properties.\n");
}
// Match |layer| specific properties.
if (search_prop != INSTANCE_LAYER_PROP && layer &&
enumerated_props_set.size() != required_props.size()) {
success = EnumerateProperties(search_prop, physical_device, layer, &enumerated_props_set);
}
bool has_missing_props = false;
// Add missing properties to |missing_props_out| if required.
if (missing_props_out) {
for (const auto &prop : required_props) {
auto iter = enumerated_props_set.find(prop);
if (iter == enumerated_props_set.end()) {
missing_props_out->emplace_back(prop);
has_missing_props = true;
}
}
}
if (has_missing_props) {
std::string category{};
switch (search_prop) {
case INSTANCE_EXT_PROP:
category = "instance extension";
break;
case INSTANCE_LAYER_PROP:
category = "instance layer";
break;
case PHYS_DEVICE_EXT_PROP:
category = "physical device extension";
break;
}
fprintf(stderr, "Missing %s properties\n", category.c_str());
PrintProps(*missing_props_out);
}
return (success && !has_missing_props);
}
bool FindQueueFamilyIndex(vk::PhysicalDevice physical_device, VkSurfaceKHR surface,
vk::QueueFlags queue_flags, uint32_t *queue_family_index) {
auto queue_families = physical_device.getQueueFamilyProperties();
for (uint32_t i = 0; i < queue_families.size(); ++i) {
if (surface) {
auto [r_present_support, present_support] = physical_device.getSurfaceSupportKHR(i, surface);
if (vk::Result::eSuccess != r_present_support) {
continue;
}
}
const auto &queue_family = queue_families[i];
if ((queue_family.queueCount > 0) && (queue_family.queueFlags & queue_flags)) {
if (queue_family_index) {
*queue_family_index = i;
}
return true;
}
}
RTN_MSG(false, "No matching queue family index found.\n");
}
vk::Result FindMemoryIndex(const vk::PhysicalDevice &phys_dev, const uint32_t memory_type_bits,
const vk::MemoryPropertyFlags &memory_prop_flags,
uint32_t *memory_type_index) {
vk::PhysicalDeviceMemoryProperties memory_props;
phys_dev.getMemoryProperties(&memory_props);
for (uint32_t i = 0; i < memory_props.memoryTypeCount; i++) {
if ((memory_type_bits & (1 << i)) &&
(memory_props.memoryTypes[i].propertyFlags & memory_prop_flags) == memory_prop_flags) {
*memory_type_index = i;
return vk::Result::eSuccess;
}
}
RTN_MSG(vk::Result::eErrorFormatNotSupported,
"Error: Unable to find memory property index for format.");
}
void LogMemoryProperties(const vk::PhysicalDevice &phys_dev) {
vk::PhysicalDeviceMemoryProperties memory_props;
phys_dev.getMemoryProperties(&memory_props);
const uint32_t memory_type_ct = memory_props.memoryTypeCount;
const vk::MemoryType *types = memory_props.memoryTypes;
printf("\nMemory Types: %d\n", memory_type_ct);
for (uint32_t i = 0; i < memory_type_ct; i++) {
const vk::MemoryType &type = types[i];
printf("\tHeap Index: %d\n", type.heapIndex);
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eDeviceLocal)
printf("\t\tDevice Local\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eHostVisible)
printf("\t\tHost Visible\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent)
printf("\t\tHost Coherent\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCached)
printf("\t\tHost Cached\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eLazilyAllocated)
printf("\t\tLazily Allocated\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eProtected)
printf("\t\tProtected\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eDeviceCoherentAMD)
printf("\t\tDevice Coherent AMD\n");
if (type.propertyFlags & vk::MemoryPropertyFlagBits::eDeviceUncachedAMD)
printf("\t\tDevice Uncached AMD\n");
}
printf("\n");
}
} // namespace vkp