Skip to content

Commit

Permalink
Merge pull request #47250 from BastiaanOlij/check_vulkan_version
Browse files Browse the repository at this point in the history
Obtain supported Vulkan API
  • Loading branch information
akien-mga authored Mar 31, 2021
2 parents 6b25c94 + e93c9fc commit 9cd1e50
Show file tree
Hide file tree
Showing 9 changed files with 366 additions and 10 deletions.
13 changes: 13 additions & 0 deletions drivers/vulkan/rendering_device_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7834,6 +7834,18 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
}

void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
// get our device capabilities
{
device_capabilities.version_major = p_context->get_vulkan_major();
device_capabilities.version_minor = p_context->get_vulkan_minor();

// get info about subgroups
VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities();
device_capabilities.subgroup_size = subgroup_capabilities.size;
device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
}

context = p_context;
device = p_context->get_device();
if (p_local_device) {
Expand Down Expand Up @@ -8253,6 +8265,7 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() {
}

RenderingDeviceVulkan::RenderingDeviceVulkan() {
device_capabilities.device_family = DEVICE_VULKAN;
}

RenderingDeviceVulkan::~RenderingDeviceVulkan() {
Expand Down
232 changes: 231 additions & 1 deletion drivers/vulkan/vulkan_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/string/ustring.h"
#include "core/version.h"
#include "servers/rendering/rendering_device.h"

#include "vk_enum_string_helper.h"

Expand Down Expand Up @@ -263,6 +264,39 @@ Error VulkanContext::_create_validation_layers() {
return OK;
}

typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *);

Error VulkanContext::_obtain_vulkan_version() {
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
// for Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
_vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
if (func != nullptr) {
uint32_t api_version;
VkResult res = func(&api_version);
if (res == VK_SUCCESS) {
vulkan_major = VK_VERSION_MAJOR(api_version);
vulkan_minor = VK_VERSION_MINOR(api_version);
uint32_t vulkan_patch = VK_VERSION_PATCH(api_version);

print_line("Vulkan API " + itos(vulkan_major) + "." + itos(vulkan_minor) + "." + itos(vulkan_patch));
} else {
// according to the documentation this shouldn't fail with anything except a memory allocation error
// in which case we're in deep trouble anyway
ERR_FAIL_V(ERR_CANT_CREATE);
}
} else {
print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0");
}

// we don't go above 1.2
if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) {
vulkan_major = 1;
vulkan_minor = 2;
}

return OK;
}

Error VulkanContext::_initialize_extensions() {
uint32_t instance_extension_count = 0;

Expand Down Expand Up @@ -320,12 +354,200 @@ Error VulkanContext::_initialize_extensions() {
return OK;
}

typedef void(VKAPI_PTR *_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *);

uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
uint32_t flags = 0;

if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
flags += RenderingDevice::ShaderStage::SHADER_STAGE_VERTEX_BIT;
}
if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_CONTROL_BIT;
}
if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_EVALUATION_BIT;
}
// if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
// flags += RenderingDevice::ShaderStage::SHADER_STAGE_GEOMETRY_BIT;
// }
if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
flags += RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT;
}
if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
flags += RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT;
}

return flags;
}

String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
String res;

if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
res += ", STAGE_VERTEX";
}
if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
res += ", STAGE_TESSELLATION_CONTROL";
}
if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
res += ", STAGE_TESSELLATION_EVALUATION";
}
if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
res += ", STAGE_GEOMETRY";
}
if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
res += ", STAGE_FRAGMENT";
}
if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
res += ", STAGE_COMPUTE";
}

/* these are not defined on Android GRMBL */
if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) {
res += ", STAGE_RAYGEN_KHR";
}
if (supportedStages & 0x00000200 /* VK_SHADER_STAGE_ANY_HIT_BIT_KHR */) {
res += ", STAGE_ANY_HIT_KHR";
}
if (supportedStages & 0x00000400 /* VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR */) {
res += ", STAGE_CLOSEST_HIT_KHR";
}
if (supportedStages & 0x00000800 /* VK_SHADER_STAGE_MISS_BIT_KHR */) {
res += ", STAGE_MISS_KHR";
}
if (supportedStages & 0x00001000 /* VK_SHADER_STAGE_INTERSECTION_BIT_KHR */) {
res += ", STAGE_INTERSECTION_KHR";
}
if (supportedStages & 0x00002000 /* VK_SHADER_STAGE_CALLABLE_BIT_KHR */) {
res += ", STAGE_CALLABLE_KHR";
}
if (supportedStages & 0x00000040 /* VK_SHADER_STAGE_TASK_BIT_NV */) {
res += ", STAGE_TASK_NV";
}
if (supportedStages & 0x00000080 /* VK_SHADER_STAGE_MESH_BIT_NV */) {
res += ", STAGE_MESH_NV";
}

return res.substr(2); // remove first ", "
}

uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
uint32_t flags = 0;

if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT;
}
if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
flags += RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT;
}

return flags;
}

String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
String res;

if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
res += ", FEATURE_BASIC";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
res += ", FEATURE_VOTE";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
res += ", FEATURE_ARITHMETIC";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
res += ", FEATURE_BALLOT";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
res += ", FEATURE_SHUFFLE";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
res += ", FEATURE_SHUFFLE_RELATIVE";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
res += ", FEATURE_CLUSTERED";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
res += ", FEATURE_QUAD";
}
if (supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV) {
res += ", FEATURE_PARTITIONED_NV";
}

return res.substr(2); // remove first ", "
}

Error VulkanContext::_check_capabilities() {
// check subgroups
// https://www.khronos.org/blog/vulkan-subgroup-tutorial
// for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
_vkGetPhysicalDeviceProperties2 func = (_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
if (func != nullptr) {
VkPhysicalDeviceSubgroupProperties subgroupProperties;
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
subgroupProperties.pNext = NULL;

VkPhysicalDeviceProperties2 physicalDeviceProperties;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProperties.pNext = &subgroupProperties;

func(gpu, &physicalDeviceProperties);

subgroup_capabilities.size = subgroupProperties.subgroupSize;
subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
// Note: quadOperationsInAllStages will be true if:
// - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT
// - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;

// only output this when debugging?
print_line("- Vulkan subgroup size " + itos(subgroup_capabilities.size));
print_line("- Vulkan subgroup stages " + subgroup_capabilities.supported_stages_desc());
print_line("- Vulkan subgroup supported ops " + subgroup_capabilities.supported_operations_desc());
if (subgroup_capabilities.quadOperationsInAllStages) {
print_line("- Vulkan subgroup quad operations in all stages");
}
} else {
subgroup_capabilities.size = 0;
subgroup_capabilities.supportedStages = 0;
subgroup_capabilities.supportedOperations = 0;
subgroup_capabilities.quadOperationsInAllStages = false;
}

return OK;
}

Error VulkanContext::_create_physical_device() {
/* obtain version */
_obtain_vulkan_version();

/* Look for validation layers */
if (use_validation_layers) {
_create_validation_layers();
}

/* initialise extensions */
{
Error err = _initialize_extensions();
if (err != OK) {
Expand All @@ -343,7 +565,7 @@ Error VulkanContext::_create_physical_device() {
/*applicationVersion*/ 0,
/*pEngineName*/ namecs.get_data(),
/*engineVersion*/ 0,
/*apiVersion*/ VK_API_VERSION_1_0,
/*apiVersion*/ VK_MAKE_VERSION(vulkan_major, vulkan_minor, 0)
};
VkInstanceCreateInfo inst_info = {
/*sType*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
Expand Down Expand Up @@ -630,6 +852,14 @@ Error VulkanContext::_create_physical_device() {
GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);

// get info about what our vulkan driver is capable off
{
Error res = _check_capabilities();
if (res != OK) {
return res;
}
}

return OK;
}

Expand Down
25 changes: 25 additions & 0 deletions drivers/vulkan/vulkan_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@
#include <vulkan/vulkan.h>

class VulkanContext {
public:
struct SubgroupCapabilities {
uint32_t size;
VkShaderStageFlags supportedStages;
VkSubgroupFeatureFlags supportedOperations;
VkBool32 quadOperationsInAllStages;

uint32_t supported_stages_flags_rd() const;
String supported_stages_desc() const;
uint32_t supported_operations_flags_rd() const;
String supported_operations_desc() const;
};

private:
enum {
MAX_EXTENSIONS = 128,
MAX_LAYERS = 64,
Expand All @@ -57,6 +71,11 @@ class VulkanContext {
bool device_initialized = false;
bool inst_initialized = false;

// Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
uint32_t vulkan_major = 1;
uint32_t vulkan_minor = 0;
SubgroupCapabilities subgroup_capabilities;

String device_vendor;
String device_name;
String pipeline_cache_id;
Expand Down Expand Up @@ -160,8 +179,10 @@ class VulkanContext {
VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;

Error _obtain_vulkan_version();
Error _create_validation_layers();
Error _initialize_extensions();
Error _check_capabilities();

VkBool32 _check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers);
static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(
Expand Down Expand Up @@ -206,6 +227,10 @@ class VulkanContext {
}

public:
uint32_t get_vulkan_major() const { return vulkan_major; };
uint32_t get_vulkan_minor() const { return vulkan_minor; };
SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };

VkDevice get_device();
VkPhysicalDevice get_physical_device();
int get_swapchain_image_count() const;
Expand Down
Loading

0 comments on commit 9cd1e50

Please sign in to comment.