546 lines
20 KiB
C++
546 lines
20 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2017 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/ui/vulkan/vulkan_instance.h"
|
|
|
|
#include <gflags/gflags.h>
|
|
|
|
#include <cinttypes>
|
|
#include <mutex>
|
|
#include <string>
|
|
|
|
#include "third_party/renderdoc/renderdoc_app.h"
|
|
#include "third_party/volk/volk.h"
|
|
|
|
#include "xenia/base/assert.h"
|
|
#include "xenia/base/logging.h"
|
|
#include "xenia/base/math.h"
|
|
#include "xenia/base/profiling.h"
|
|
#include "xenia/ui/vulkan/vulkan.h"
|
|
#include "xenia/ui/vulkan/vulkan_immediate_drawer.h"
|
|
#include "xenia/ui/vulkan/vulkan_util.h"
|
|
#include "xenia/ui/window.h"
|
|
|
|
#if XE_PLATFORM_LINUX
|
|
#include "xenia/ui/window_gtk.h"
|
|
#endif
|
|
|
|
#define VK_API_VERSION VK_API_VERSION_1_1
|
|
|
|
namespace xe {
|
|
namespace ui {
|
|
namespace vulkan {
|
|
|
|
VulkanInstance::VulkanInstance() {
|
|
if (FLAGS_vulkan_validation) {
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_standard_validation",
|
|
Version::Make(0, 0, 0), true);
|
|
// DeclareRequiredLayer("VK_LAYER_GOOGLE_unique_objects", Version::Make(0,
|
|
// 0, 0), true);
|
|
/*
|
|
DeclareRequiredLayer("VK_LAYER_GOOGLE_threading", Version::Make(0, 0, 0),
|
|
true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_core_validation",
|
|
Version::Make(0, 0, 0), true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_object_tracker",
|
|
Version::Make(0, 0, 0), true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_draw_state", Version::Make(0, 0, 0),
|
|
true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_parameter_validation",
|
|
Version::Make(0, 0, 0), true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_swapchain", Version::Make(0, 0, 0),
|
|
true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_device_limits",
|
|
Version::Make(0, 0, 0), true);
|
|
DeclareRequiredLayer("VK_LAYER_LUNARG_image", Version::Make(0, 0, 0), true);
|
|
*/
|
|
DeclareRequiredExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
|
|
Version::Make(0, 0, 0), true);
|
|
}
|
|
|
|
DeclareRequiredExtension(VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
|
Version::Make(0, 0, 0), true);
|
|
}
|
|
|
|
VulkanInstance::~VulkanInstance() { DestroyInstance(); }
|
|
|
|
bool VulkanInstance::Initialize() {
|
|
auto version = Version::Parse(VK_API_VERSION);
|
|
XELOGVK("Initializing Vulkan %s...", version.pretty_string.c_str());
|
|
if (volkInitialize() != VK_SUCCESS) {
|
|
XELOGE("volkInitialize() failed!");
|
|
return false;
|
|
}
|
|
|
|
// Get all of the global layers and extensions provided by the system.
|
|
if (!QueryGlobals()) {
|
|
XELOGE("Failed to query instance globals");
|
|
return false;
|
|
}
|
|
|
|
// Create the vulkan instance used by the application with our required
|
|
// extensions and layers.
|
|
if (!CreateInstance()) {
|
|
XELOGE("Failed to create instance");
|
|
return false;
|
|
}
|
|
|
|
// Query available devices so that we can pick one.
|
|
if (!QueryDevices()) {
|
|
XELOGE("Failed to query devices");
|
|
return false;
|
|
}
|
|
|
|
// Hook into renderdoc, if it's available.
|
|
EnableRenderDoc();
|
|
|
|
XELOGVK("Instance initialized successfully!");
|
|
return true;
|
|
}
|
|
|
|
bool VulkanInstance::EnableRenderDoc() {
|
|
// RenderDoc injects itself into our process, so we should be able to get it.
|
|
pRENDERDOC_GetAPI get_api = nullptr;
|
|
#if XE_PLATFORM_WIN32
|
|
auto module_handle = GetModuleHandle(L"renderdoc.dll");
|
|
if (!module_handle) {
|
|
XELOGI("RenderDoc support requested but it is not attached");
|
|
return false;
|
|
}
|
|
get_api = reinterpret_cast<pRENDERDOC_GetAPI>(
|
|
GetProcAddress(module_handle, "RENDERDOC_GetAPI"));
|
|
#else
|
|
// TODO(benvanik): dlsym/etc - abstracted in base/.
|
|
#endif // XE_PLATFORM_32
|
|
if (!get_api) {
|
|
XELOGI("RenderDoc support requested but it is not attached");
|
|
return false;
|
|
}
|
|
|
|
// Request all API function pointers.
|
|
if (!get_api(eRENDERDOC_API_Version_1_0_1,
|
|
reinterpret_cast<void**>(&renderdoc_api_))) {
|
|
XELOGE("RenderDoc found but was unable to get API - version mismatch?");
|
|
return false;
|
|
}
|
|
auto api = reinterpret_cast<RENDERDOC_API_1_0_1*>(renderdoc_api_);
|
|
|
|
// Query version.
|
|
int major;
|
|
int minor;
|
|
int patch;
|
|
api->GetAPIVersion(&major, &minor, &patch);
|
|
XELOGI("RenderDoc attached; %d.%d.%d", major, minor, patch);
|
|
|
|
is_renderdoc_attached_ = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool VulkanInstance::QueryGlobals() {
|
|
// Scan global layers and accumulate properties.
|
|
// We do this in a loop so that we can allocate the required amount of
|
|
// memory and handle race conditions while querying.
|
|
uint32_t count = 0;
|
|
std::vector<VkLayerProperties> global_layer_properties;
|
|
VkResult err;
|
|
do {
|
|
err = vkEnumerateInstanceLayerProperties(&count, nullptr);
|
|
CheckResult(err, "vkEnumerateInstanceLayerProperties");
|
|
global_layer_properties.resize(count);
|
|
err = vkEnumerateInstanceLayerProperties(&count,
|
|
global_layer_properties.data());
|
|
} while (err == VK_INCOMPLETE);
|
|
CheckResult(err, "vkEnumerateInstanceLayerProperties");
|
|
global_layers_.resize(count);
|
|
for (size_t i = 0; i < global_layers_.size(); ++i) {
|
|
auto& global_layer = global_layers_[i];
|
|
global_layer.properties = global_layer_properties[i];
|
|
|
|
// Get all extensions available for the layer.
|
|
do {
|
|
err = vkEnumerateInstanceExtensionProperties(
|
|
global_layer.properties.layerName, &count, nullptr);
|
|
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
|
global_layer.extensions.resize(count);
|
|
err = vkEnumerateInstanceExtensionProperties(
|
|
global_layer.properties.layerName, &count,
|
|
global_layer.extensions.data());
|
|
} while (err == VK_INCOMPLETE);
|
|
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
|
}
|
|
XELOGVK("Found %d global layers:", global_layers_.size());
|
|
for (size_t i = 0; i < global_layers_.size(); ++i) {
|
|
auto& global_layer = global_layers_[i];
|
|
auto spec_version = Version::Parse(global_layer.properties.specVersion);
|
|
auto impl_version =
|
|
Version::Parse(global_layer.properties.implementationVersion);
|
|
XELOGVK("- %s (spec: %s, impl: %s)", global_layer.properties.layerName,
|
|
spec_version.pretty_string.c_str(),
|
|
impl_version.pretty_string.c_str());
|
|
XELOGVK(" %s", global_layer.properties.description);
|
|
if (!global_layer.extensions.empty()) {
|
|
XELOGVK(" %d extensions:", global_layer.extensions.size());
|
|
DumpExtensions(global_layer.extensions, " ");
|
|
}
|
|
}
|
|
|
|
// Scan global extensions.
|
|
do {
|
|
err = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
|
|
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
|
global_extensions_.resize(count);
|
|
err = vkEnumerateInstanceExtensionProperties(nullptr, &count,
|
|
global_extensions_.data());
|
|
} while (err == VK_INCOMPLETE);
|
|
CheckResult(err, "vkEnumerateInstanceExtensionProperties");
|
|
XELOGVK("Found %d global extensions:", global_extensions_.size());
|
|
DumpExtensions(global_extensions_, "");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool VulkanInstance::CreateInstance() {
|
|
XELOGVK("Verifying layers and extensions...");
|
|
|
|
// Gather list of enabled layer names.
|
|
auto layers_result = CheckRequirements(required_layers_, global_layers_);
|
|
auto& enabled_layers = layers_result.second;
|
|
|
|
// Gather list of enabled extension names.
|
|
auto extensions_result =
|
|
CheckRequirements(required_extensions_, global_extensions_);
|
|
auto& enabled_extensions = extensions_result.second;
|
|
|
|
// We wait until both extensions and layers are checked before failing out so
|
|
// that the user gets a complete list of what they have/don't.
|
|
if (!extensions_result.first || !layers_result.first) {
|
|
XELOGE("Layer and extension verification failed; aborting initialization");
|
|
return false;
|
|
}
|
|
|
|
XELOGVK("Initializing application instance...");
|
|
|
|
// TODO(benvanik): use GetEntryInfo?
|
|
VkApplicationInfo application_info;
|
|
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
application_info.pNext = nullptr;
|
|
application_info.pApplicationName = "xenia";
|
|
application_info.applicationVersion = 1;
|
|
application_info.pEngineName = "xenia";
|
|
application_info.engineVersion = 1;
|
|
application_info.apiVersion = VK_API_VERSION;
|
|
|
|
VkInstanceCreateInfo instance_info;
|
|
instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
instance_info.pNext = nullptr;
|
|
instance_info.flags = 0;
|
|
instance_info.pApplicationInfo = &application_info;
|
|
instance_info.enabledLayerCount =
|
|
static_cast<uint32_t>(enabled_layers.size());
|
|
instance_info.ppEnabledLayerNames = enabled_layers.data();
|
|
instance_info.enabledExtensionCount =
|
|
static_cast<uint32_t>(enabled_extensions.size());
|
|
instance_info.ppEnabledExtensionNames = enabled_extensions.data();
|
|
|
|
auto err = vkCreateInstance(&instance_info, nullptr, &handle);
|
|
if (err != VK_SUCCESS) {
|
|
XELOGE("vkCreateInstance returned %s", to_string(err));
|
|
}
|
|
switch (err) {
|
|
case VK_SUCCESS:
|
|
// Ok!
|
|
break;
|
|
case VK_ERROR_INITIALIZATION_FAILED:
|
|
XELOGE("Instance initialization failed; generic");
|
|
return false;
|
|
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
|
XELOGE(
|
|
"Instance initialization failed; cannot find a compatible Vulkan "
|
|
"installable client driver (ICD)");
|
|
return false;
|
|
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
|
XELOGE("Instance initialization failed; requested extension not present");
|
|
return false;
|
|
case VK_ERROR_LAYER_NOT_PRESENT:
|
|
XELOGE("Instance initialization failed; requested layer not present");
|
|
return false;
|
|
default:
|
|
XELOGE("Instance initialization failed; unknown: %s", to_string(err));
|
|
return false;
|
|
}
|
|
|
|
// Load Vulkan entrypoints and extensions.
|
|
volkLoadInstance(handle);
|
|
|
|
// Enable debug validation, if needed.
|
|
EnableDebugValidation();
|
|
|
|
return true;
|
|
}
|
|
|
|
void VulkanInstance::DestroyInstance() {
|
|
if (!handle) {
|
|
return;
|
|
}
|
|
DisableDebugValidation();
|
|
vkDestroyInstance(handle, nullptr);
|
|
handle = nullptr;
|
|
}
|
|
|
|
VkBool32 VKAPI_PTR DebugMessageCallback(VkDebugReportFlagsEXT flags,
|
|
VkDebugReportObjectTypeEXT objectType,
|
|
uint64_t object, size_t location,
|
|
int32_t messageCode,
|
|
const char* pLayerPrefix,
|
|
const char* pMessage, void* pUserData) {
|
|
if (strcmp(pLayerPrefix, "Validation") == 0) {
|
|
const char* blacklist[] = {
|
|
"bound but it was never updated. You may want to either update it or "
|
|
"not bind it.",
|
|
"is being used in draw but has not been updated.",
|
|
};
|
|
for (uint32_t i = 0; i < xe::countof(blacklist); ++i) {
|
|
if (strstr(pMessage, blacklist[i]) != nullptr) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto instance = reinterpret_cast<VulkanInstance*>(pUserData);
|
|
const char* message_type = "UNKNOWN";
|
|
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
|
|
message_type = "ERROR";
|
|
} else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
|
|
message_type = "WARN";
|
|
} else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
|
|
message_type = "PERF WARN";
|
|
} else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
|
|
message_type = "INFO";
|
|
} else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
|
|
message_type = "DEBUG";
|
|
}
|
|
|
|
XELOGVK("[%s/%s:%d] %s", pLayerPrefix, message_type, messageCode, pMessage);
|
|
return false;
|
|
}
|
|
|
|
void VulkanInstance::EnableDebugValidation() {
|
|
if (dbg_report_callback_) {
|
|
DisableDebugValidation();
|
|
}
|
|
auto vk_create_debug_report_callback_ext =
|
|
reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
|
|
vkGetInstanceProcAddr(handle, "vkCreateDebugReportCallbackEXT"));
|
|
if (!vk_create_debug_report_callback_ext) {
|
|
XELOGVK("Debug validation layer not installed; ignoring");
|
|
return;
|
|
}
|
|
VkDebugReportCallbackCreateInfoEXT create_info;
|
|
create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
|
|
create_info.pNext = nullptr;
|
|
// TODO(benvanik): flags to set these.
|
|
create_info.flags =
|
|
VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
|
|
VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
|
|
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT;
|
|
create_info.pfnCallback = &DebugMessageCallback;
|
|
create_info.pUserData = this;
|
|
auto status = vk_create_debug_report_callback_ext(
|
|
handle, &create_info, nullptr, &dbg_report_callback_);
|
|
if (status == VK_SUCCESS) {
|
|
XELOGVK("Debug validation layer enabled");
|
|
} else {
|
|
XELOGVK("Debug validation layer failed to install; error %s",
|
|
to_string(status));
|
|
}
|
|
}
|
|
|
|
void VulkanInstance::DisableDebugValidation() {
|
|
if (!dbg_report_callback_) {
|
|
return;
|
|
}
|
|
auto vk_destroy_debug_report_callback_ext =
|
|
reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(
|
|
vkGetInstanceProcAddr(handle, "vkDestroyDebugReportCallbackEXT"));
|
|
if (!vk_destroy_debug_report_callback_ext) {
|
|
return;
|
|
}
|
|
vk_destroy_debug_report_callback_ext(handle, dbg_report_callback_, nullptr);
|
|
dbg_report_callback_ = nullptr;
|
|
}
|
|
|
|
bool VulkanInstance::QueryDevices() {
|
|
// Get handles to all devices.
|
|
uint32_t count = 0;
|
|
std::vector<VkPhysicalDevice> device_handles;
|
|
auto err = vkEnumeratePhysicalDevices(handle, &count, nullptr);
|
|
CheckResult(err, "vkEnumeratePhysicalDevices");
|
|
|
|
device_handles.resize(count);
|
|
err = vkEnumeratePhysicalDevices(handle, &count, device_handles.data());
|
|
CheckResult(err, "vkEnumeratePhysicalDevices");
|
|
|
|
// Query device info.
|
|
for (size_t i = 0; i < device_handles.size(); ++i) {
|
|
auto device_handle = device_handles[i];
|
|
DeviceInfo device_info;
|
|
device_info.handle = device_handle;
|
|
|
|
// Query general attributes.
|
|
vkGetPhysicalDeviceProperties(device_handle, &device_info.properties);
|
|
vkGetPhysicalDeviceFeatures(device_handle, &device_info.features);
|
|
vkGetPhysicalDeviceMemoryProperties(device_handle,
|
|
&device_info.memory_properties);
|
|
|
|
// Gather queue family properties.
|
|
vkGetPhysicalDeviceQueueFamilyProperties(device_handle, &count, nullptr);
|
|
device_info.queue_family_properties.resize(count);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(
|
|
device_handle, &count, device_info.queue_family_properties.data());
|
|
|
|
// Gather layers.
|
|
std::vector<VkLayerProperties> layer_properties;
|
|
err = vkEnumerateDeviceLayerProperties(device_handle, &count, nullptr);
|
|
CheckResult(err, "vkEnumerateDeviceLayerProperties");
|
|
layer_properties.resize(count);
|
|
err = vkEnumerateDeviceLayerProperties(device_handle, &count,
|
|
layer_properties.data());
|
|
CheckResult(err, "vkEnumerateDeviceLayerProperties");
|
|
for (size_t j = 0; j < layer_properties.size(); ++j) {
|
|
LayerInfo layer_info;
|
|
layer_info.properties = layer_properties[j];
|
|
err = vkEnumerateDeviceExtensionProperties(
|
|
device_handle, layer_info.properties.layerName, &count, nullptr);
|
|
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
|
layer_info.extensions.resize(count);
|
|
err = vkEnumerateDeviceExtensionProperties(
|
|
device_handle, layer_info.properties.layerName, &count,
|
|
layer_info.extensions.data());
|
|
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
|
device_info.layers.push_back(std::move(layer_info));
|
|
}
|
|
|
|
// Gather extensions.
|
|
err = vkEnumerateDeviceExtensionProperties(device_handle, nullptr, &count,
|
|
nullptr);
|
|
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
|
device_info.extensions.resize(count);
|
|
err = vkEnumerateDeviceExtensionProperties(device_handle, nullptr, &count,
|
|
device_info.extensions.data());
|
|
CheckResult(err, "vkEnumerateDeviceExtensionProperties");
|
|
|
|
available_devices_.push_back(std::move(device_info));
|
|
}
|
|
|
|
XELOGVK("Found %d physical devices:", available_devices_.size());
|
|
for (size_t i = 0; i < available_devices_.size(); ++i) {
|
|
auto& device_info = available_devices_[i];
|
|
XELOGVK("- Device %d:", i);
|
|
DumpDeviceInfo(device_info);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void VulkanInstance::DumpLayers(const std::vector<LayerInfo>& layers,
|
|
const char* indent) {
|
|
for (size_t i = 0; i < layers.size(); ++i) {
|
|
auto& layer = layers[i];
|
|
auto spec_version = Version::Parse(layer.properties.specVersion);
|
|
auto impl_version = Version::Parse(layer.properties.implementationVersion);
|
|
XELOGVK("%s- %s (spec: %s, impl: %s)", indent, layer.properties.layerName,
|
|
spec_version.pretty_string.c_str(),
|
|
impl_version.pretty_string.c_str());
|
|
XELOGVK("%s %s", indent, layer.properties.description);
|
|
if (!layer.extensions.empty()) {
|
|
XELOGVK("%s %d extensions:", indent, layer.extensions.size());
|
|
DumpExtensions(layer.extensions, std::strlen(indent) ? " " : " ");
|
|
}
|
|
}
|
|
}
|
|
|
|
void VulkanInstance::DumpExtensions(
|
|
const std::vector<VkExtensionProperties>& extensions, const char* indent) {
|
|
for (size_t i = 0; i < extensions.size(); ++i) {
|
|
auto& extension = extensions[i];
|
|
auto version = Version::Parse(extension.specVersion);
|
|
XELOGVK("%s- %s (%s)", indent, extension.extensionName,
|
|
version.pretty_string.c_str());
|
|
}
|
|
}
|
|
|
|
void VulkanInstance::DumpDeviceInfo(const DeviceInfo& device_info) {
|
|
auto& properties = device_info.properties;
|
|
auto api_version = Version::Parse(properties.apiVersion);
|
|
auto driver_version = Version::Parse(properties.driverVersion);
|
|
XELOGVK(" apiVersion = %s", api_version.pretty_string.c_str());
|
|
XELOGVK(" driverVersion = %s", driver_version.pretty_string.c_str());
|
|
XELOGVK(" vendorId = 0x%04x", properties.vendorID);
|
|
XELOGVK(" deviceId = 0x%04x", properties.deviceID);
|
|
XELOGVK(" deviceType = %s", to_string(properties.deviceType));
|
|
XELOGVK(" deviceName = %s", properties.deviceName);
|
|
|
|
auto& memory_props = device_info.memory_properties;
|
|
XELOGVK(" Memory Heaps:");
|
|
for (size_t j = 0; j < memory_props.memoryHeapCount; ++j) {
|
|
XELOGVK(" - Heap %u: %" PRIu64 " bytes", j,
|
|
memory_props.memoryHeaps[j].size);
|
|
for (size_t k = 0; k < memory_props.memoryTypeCount; ++k) {
|
|
if (memory_props.memoryTypes[k].heapIndex == j) {
|
|
XELOGVK(" - Type %u:", k);
|
|
auto type_flags = memory_props.memoryTypes[k].propertyFlags;
|
|
if (!type_flags) {
|
|
XELOGVK(" VK_MEMORY_PROPERTY_DEVICE_ONLY");
|
|
}
|
|
if (type_flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
|
|
XELOGVK(" VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT");
|
|
}
|
|
if (type_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
|
XELOGVK(" VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT");
|
|
}
|
|
if (type_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) {
|
|
XELOGVK(" VK_MEMORY_PROPERTY_HOST_COHERENT_BIT");
|
|
}
|
|
if (type_flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
|
|
XELOGVK(" VK_MEMORY_PROPERTY_HOST_CACHED_BIT");
|
|
}
|
|
if (type_flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
|
|
XELOGVK(" VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
XELOGVK(" Queue Families:");
|
|
for (size_t j = 0; j < device_info.queue_family_properties.size(); ++j) {
|
|
auto& queue_props = device_info.queue_family_properties[j];
|
|
XELOGVK(" - Queue %d:", j);
|
|
XELOGVK(
|
|
" queueFlags = %s%s%s%s",
|
|
(queue_props.queueFlags & VK_QUEUE_GRAPHICS_BIT) ? "graphics, " : "",
|
|
(queue_props.queueFlags & VK_QUEUE_COMPUTE_BIT) ? "compute, " : "",
|
|
(queue_props.queueFlags & VK_QUEUE_TRANSFER_BIT) ? "transfer, " : "",
|
|
(queue_props.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) ? "sparse, "
|
|
: "");
|
|
XELOGVK(" queueCount = %u", queue_props.queueCount);
|
|
XELOGVK(" timestampValidBits = %u", queue_props.timestampValidBits);
|
|
}
|
|
|
|
XELOGVK(" Layers:");
|
|
DumpLayers(device_info.layers, " ");
|
|
|
|
XELOGVK(" Extensions:");
|
|
DumpExtensions(device_info.extensions, " ");
|
|
}
|
|
|
|
} // namespace vulkan
|
|
} // namespace ui
|
|
} // namespace xe
|