Vulkan: Create VkInstance and register debug report
This commit is contained in:
parent
f2adf6d5bd
commit
6d9a3b82c6
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue