Vulkan: Create VkInstance and register debug report

This commit is contained in:
Corentin Wallez 2017-11-20 10:51:23 -05:00 committed by Corentin Wallez
parent f2adf6d5bd
commit 6d9a3b82c6
6 changed files with 218 additions and 2 deletions

View File

@ -19,6 +19,8 @@
#include <spirv-cross/spirv_cross.hpp>
#include <iostream>
#if NXT_PLATFORM_LINUX
const char kVulkanLibName[] = "libvulkan.so.1";
#elif NXT_PLATFORM_WINDOWS
@ -58,9 +60,38 @@ namespace vulkan {
ASSERT(false);
return;
}
KnownGlobalVulkanExtensions usedGlobals;
if (!CreateInstance(&usedGlobals)) {
ASSERT(false);
return;
}
if (!functions->LoadInstanceProcs(instance, usedGlobals)) {
ASSERT(false);
return;
}
vulkanInfo->SetUsedGlobals(usedGlobals);
if(usedGlobals.debugReport) {
if (!RegisterDebugReport()) {
ASSERT(false);
return;
}
}
}
Device::~Device() {
if (debugReportCallback != VK_NULL_HANDLE) {
fn.DestroyDebugReportCallbackEXT(instance, debugReportCallback, nullptr);
debugReportCallback = VK_NULL_HANDLE;
}
if (instance != VK_NULL_HANDLE) {
fn.DestroyInstance(instance, nullptr);
instance = VK_NULL_HANDLE;
}
}
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
@ -129,6 +160,76 @@ namespace vulkan {
void Device::TickImpl() {
}
bool Device::CreateInstance(KnownGlobalVulkanExtensions* usedGlobals) {
std::vector<const char*> layersToRequest;
std::vector<const char*> extensionsToRequest;
#if defined(NXT_ENABLE_ASSERTS)
if (info.global.standardValidation) {
layersToRequest.push_back(kLayerNameLunargStandardValidation);
usedGlobals->standardValidation = true;
}
if (info.global.debugReport) {
extensionsToRequest.push_back(kExtensionNameExtDebugReport);
usedGlobals->debugReport = true;
}
#endif
VkApplicationInfo appInfo;
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pNext = nullptr;
appInfo.pApplicationName = nullptr;
appInfo.applicationVersion = 0;
appInfo.pEngineName = nullptr;
appInfo.engineVersion = 0;
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledLayerCount = static_cast<uint32_t>(layersToRequest.size());
createInfo.ppEnabledLayerNames = layersToRequest.data();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensionsToRequest.size());
createInfo.ppEnabledExtensionNames = extensionsToRequest.data();
if (fn.CreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
return false;
}
return true;
}
bool Device::RegisterDebugReport() {
VkDebugReportCallbackCreateInfoEXT createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
createInfo.pNext = nullptr;
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
createInfo.pfnCallback = Device::OnDebugReportCallback;
createInfo.pUserData = this;
if (fn.CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &debugReportCallback) != VK_SUCCESS) {
return false;
}
return true;
}
VkBool32 Device::OnDebugReportCallback(VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT /*objectType*/,
uint64_t /*object*/,
size_t /*location*/,
int32_t /*messageCode*/,
const char* /*pLayerPrefix*/,
const char* pMessage,
void* /*pUserdata*/) {
std::cout << pMessage << std::endl;
ASSERT((flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) == 0);
return VK_FALSE;
}
VulkanFunctions* Device::GetMutableFunctions() {
return const_cast<VulkanFunctions*>(&fn);
}

View File

@ -125,12 +125,27 @@ namespace vulkan {
const VulkanInfo info;
private:
bool CreateInstance(KnownGlobalVulkanExtensions* usedGlobals);
bool RegisterDebugReport();
static VkBool32 OnDebugReportCallback(VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objectType,
uint64_t object,
size_t location,
int32_t messageCode,
const char* pLayerPrefix,
const char* pMessage,
void* pUserdata);
// To make it easier to use fn it is a public const member. However
// the Device is allowed to mutate them through these private methods.
VulkanFunctions* GetMutableFunctions();
VulkanInfo* GetMutableInfo();
DynamicLib vulkanLib;
VkInstance instance = VK_NULL_HANDLE;
VkDebugReportCallbackEXT debugReportCallback = VK_NULL_HANDLE;
};
class Buffer : public BufferBase {

View File

@ -14,6 +14,7 @@
#include "backend/vulkan/VulkanFunctions.h"
#include "backend/vulkan/VulkanInfo.h"
#include "common/DynamicLib.h"
namespace backend {
@ -38,5 +39,34 @@ namespace vulkan {
return true;
}
#define GET_INSTANCE_PROC(name) \
name = reinterpret_cast<decltype(name)>(GetInstanceProcAddr(instance, "vk" #name)); \
if (name == nullptr) { \
return false; \
}
bool VulkanFunctions::LoadInstanceProcs(VkInstance instance, const KnownGlobalVulkanExtensions& usedGlobals) {
GET_INSTANCE_PROC(CreateDevice);
GET_INSTANCE_PROC(DestroyDevice);
GET_INSTANCE_PROC(EnumerateDeviceExtensionProperties);
GET_INSTANCE_PROC(EnumerateDeviceLayerProperties);
GET_INSTANCE_PROC(EnumeratePhysicalDevices);
GET_INSTANCE_PROC(GetPhysicalDeviceFeatures);
GET_INSTANCE_PROC(GetPhysicalDeviceFormatProperties);
GET_INSTANCE_PROC(GetPhysicalDeviceImageFormatProperties);
GET_INSTANCE_PROC(GetPhysicalDeviceMemoryProperties);
GET_INSTANCE_PROC(GetPhysicalDeviceProperties);
GET_INSTANCE_PROC(GetPhysicalDeviceQueueFamilyProperties);
GET_INSTANCE_PROC(GetPhysicalDeviceSparseImageFormatProperties);
if (usedGlobals.debugReport) {
GET_INSTANCE_PROC(CreateDebugReportCallbackEXT);
GET_INSTANCE_PROC(DebugReportMessageEXT);
GET_INSTANCE_PROC(DestroyDebugReportCallbackEXT);
}
return true;
}
}
}

View File

@ -22,10 +22,13 @@ class DynamicLib;
namespace backend {
namespace vulkan {
struct KnownGlobalVulkanExtensions;
// Stores the Vulkan entry points. Also loads them from the dynamic library
// and the vkGet*ProcAddress entry points.
struct VulkanFunctions {
bool LoadGlobalProcs(const DynamicLib& vulkanLib);
bool LoadInstanceProcs(VkInstance instance, const KnownGlobalVulkanExtensions& usedGlobals);
// Initial proc from which we can get all the others
PFN_vkGetInstanceProcAddr GetInstanceProcAddr = nullptr;
@ -37,7 +40,30 @@ namespace vulkan {
// DestroyInstance isn't technically a global proc but we want to be able to use it
// before querying the instance procs in case we need to error out during initialization.
PFN_vkDestroyInstance DestroyInstance = nullptr;
// Instance procs
PFN_vkCreateDevice CreateDevice = nullptr;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties = nullptr;
PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties = nullptr;
PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices = nullptr;
PFN_vkGetPhysicalDeviceFeatures GetPhysicalDeviceFeatures = nullptr;
PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties = nullptr;
PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties = nullptr;
PFN_vkGetPhysicalDeviceMemoryProperties GetPhysicalDeviceMemoryProperties = nullptr;
PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties = nullptr;
PFN_vkGetPhysicalDeviceQueueFamilyProperties GetPhysicalDeviceQueueFamilyProperties = nullptr;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties = nullptr;
// Not technically an instance proc but we want to be able to use it as soon as the
// device is created.
PFN_vkDestroyDevice DestroyDevice = nullptr;
// VK_EXT_debug_report
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT = nullptr;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT = nullptr;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT = nullptr;
};
}
}

View File

@ -16,9 +16,25 @@
#include "backend/vulkan/VulkanBackend.h"
#include <cstring>
namespace {
bool IsLayerName(const VkLayerProperties& layer, const char* name) {
return strncmp(layer.layerName, name, VK_MAX_EXTENSION_NAME_SIZE) == 0;
}
bool IsExtensionName(const VkExtensionProperties& extension, const char* name) {
return strncmp(extension.extensionName, name, VK_MAX_EXTENSION_NAME_SIZE) == 0;
}
}
namespace backend {
namespace vulkan {
const char kLayerNameLunargStandardValidation[] = "VK_LAYER_LUNARG_standard_validation";
const char kExtensionNameExtDebugReport[] = "VK_EXT_debug_report";
bool VulkanInfo::GatherGlobalInfo(const Device& device) {
// Gather the info about the instance layers
{
@ -36,6 +52,12 @@ namespace vulkan {
if (result != VK_SUCCESS) {
return false;
}
for (const auto& layer : global.layers) {
if (IsLayerName(layer, kLayerNameLunargStandardValidation)) {
global.standardValidation = true;
}
}
}
// Gather the info about the instance extensions
@ -51,11 +73,21 @@ namespace vulkan {
if (result != VK_SUCCESS) {
return false;
}
for (const auto& extension : global.extensions) {
if (IsExtensionName(extension, kExtensionNameExtDebugReport)) {
global.debugReport = true;
}
}
}
// TODO(cwallez@chromium:org): Each layer can expose additional extensions, query them?
return true;
}
void VulkanInfo::SetUsedGlobals(const KnownGlobalVulkanExtensions& usedGlobals) {
*static_cast<KnownGlobalVulkanExtensions*>(&global) = usedGlobals;
}
}
}

View File

@ -24,18 +24,30 @@ namespace vulkan {
class Device;
extern const char kLayerNameLunargStandardValidation[];
extern const char kExtensionNameExtDebugReport[];
struct KnownGlobalVulkanExtensions {
// Layers
bool standardValidation = false;
// Extensions
bool debugReport = false;
};
// Stores the information about the Vulkan system that are required to use Vulkan.
// Also does the querying of the information.
struct VulkanInfo {
// Global information - gathered before the instance is created
struct {
struct : KnownGlobalVulkanExtensions {
std::vector<VkLayerProperties> layers;
std::vector<VkExtensionProperties> extensions;
// TODO(cwallez@chromium.org): layer instance extensions
} global;
bool GatherGlobalInfo(const Device& device);
void SetUsedGlobals(const KnownGlobalVulkanExtensions& usedGlobals);
};
}