Recently I've updated my system and tried to recompile my Vulkan app (which uses Vulkan cpp binding) and got almost no output from vk::DebugUtilsMessengerEXT (except the string "Added messenger"). I set it up to std::cout every kind of callback, and it printed lots of information strings (before update). Does anyone know, what to do to bring back debug output?
Here is my debug messenger code:
// ...
vk::DebugUtilsMessengerCreateInfoEXT messengerInfo;
messengerInfo.setMessageSeverity(
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose);
messengerInfo.setMessageType(
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance);
messengerInfo.setPfnUserCallback(callback);
messengerInfo.setPUserData(nullptr);
if(instance.createDebugUtilsMessengerEXT(&messengerInfo, nullptr, &debugMessenger, loader) != vk::Result::eSuccess) throw std::runtime_error("Failed to create debug messenger!\n");
}
VKAPI_ATTR VkBool32 VKAPI_CALL System::callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
{
std::cout << pCallbackData->pMessage << '\n';
return false;
}
"loader" is vk::DispatchLoaderDynamic
Seems like the trouble is not only with Vulkan-Hpp, but also with C Vulkan.
Did some testing and the callbacks seem to be working correctly. I'm thinking the issue here might be the removal of some old INFO messages for performance reasons -- see Vulkan-ValidationLayers commits 18BF5C637 and 523D9C775. If INFORMATION_BIT messages were enabled in SDK releases previous to 1.1.108, you'd have seen a ton of spew. If expected validation errors are not making it to your callback, please create a github issue in the VVL repo and we'll address it immediately.
How I'm doing it and it works, albeit not the latest SDK:
void VulkanContext::createInstance()
{
// create the list of required extensions
uint32_t glfwExtensionCount = 0;
const char **glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char *> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
auto layers = std::vector<const char *>();
if ( enableValidationLayers )
{
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
layers.push_back("VK_LAYER_LUNARG_standard_validation");
}
vk::ApplicationInfo appInfo("Vulkan test", 1, "test", 1, VK_API_VERSION_1_1);
auto createInfo = vk::InstanceCreateInfo(
vk::InstanceCreateFlags(),
&appInfo,
static_cast<uint32_t>(layers.size()),
layers.empty() ? nullptr : layers.data(),
static_cast<uint32_t>(extensions.size()),
extensions.empty() ? nullptr : extensions.data()
);
instance = vk::createInstanceUnique(createInfo);
dispatcher = vk::DispatchLoaderDynamic(instance.get(), vkGetInstanceProcAddr);
if ( enableValidationLayers )
{
auto severityFlags = vk::DebugUtilsMessageSeverityFlagBitsEXT::eError
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose
| vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo;
auto typeFlags = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral
| vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation
| vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance;
messenger = instance->createDebugUtilsMessengerEXTUnique(
{{}, severityFlags, typeFlags, debugCallback},
nullptr,
dispatcher
);
}
}
Make sure you're enabling the debug extensions and validation layers.
Check that your loader/dispatcher is initialized correctly.
Try some of the other commands for creating the messenger, not sure but maybe the API changed and the severity flags are passed in the wrong place.
Make sure the validation layers are installed correctly, don't recall dealing with that myself but saw mentions that it can be an issue.
Related
I try to read out the ActiveState property of a systemd unit with gdbus/glib-2.0. For sd-bus there exists the convenient function sd_bus_get_property_string. What would the equivalent call if gdbus is used. I am ware of the gdbus introspect command, but I need to implement that in C/C++.
I managed to start and stop units already. Now I need to verify that a unit has been successful started/stopped. I am new to dbus and have been searching the internet for some hours for an example, without finding something helpful.
I also implemented some systemd stuff in C++. Here was my solution:
std::string Unit::GetPropertyString(const std::string& property) const
{
sd_bus_error err = SD_BUS_ERROR_NULL;
char* msg = nullptr;
int r;
r = sd_bus_get_property_string(m_bus,
"org.freedesktop.systemd1",
("/org/freedesktop/systemd1/unit/" + m_unit).c_str(),
"org.freedesktop.systemd1.Unit",
property.c_str(),
&err,
&msg);
if (r < 0)
{
std::string err_msg(err.message);
sd_bus_error_free(&err);
std::string err_str("Failed to get " + property + " for service "
+ m_name + ". Error: " + err_msg);
throw slib_exception(err_str);
}
sd_bus_error_free(&err);
// Free memory (avoid leaking)
std::string ret(msg);
free (msg);
return ret;
}
From this, you can call
activestate = GetPropertyString("ActiveState");
substate = GetPropertyString("SubState");
I found that a lot of the <systemd/sd-bus.h> wasn't well documented. There is a fantastic explanation by the author here:
http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html
But outside of the few examples he gives, I found it was easier to inspect the source code. Specifically, I found it nice looking into the source-code of the systemctl and journalctl applications to see how sd-bus was used in those contexts.
I am experiencing a strange problem when trying to use the GMFBridge filter with the output of an Euresys UxH264 card.
I am trying to integrate this card into our solution, that relies on GMFBridge to handle the ability of continuous capture to multiple files, performing muxing and file-splitting without having to stop the capture graph.
This card captures video and audio from analog inputs. It provides a DirectShow filter exposing both a raw stream of the video input and a hardware-encoded H.264 stream. The audio stream is provided as an uncompressed stream only.
When I attempt to directly connect any of the output pins of the Euresys source filters to the input pins of the GMFBridge Sink, they get rejected, with the code VFW_E_NO_ALLOCATOR. (In the past I have successfully connected both H.264 and raw audio streams to the bridge).
Grasping at straws, I plugged in a pair of SampleGrabber filters between the Euresys card filters and the bridge sink filter, and -just like that- the connections between sample grabbers and sink were accepted.
However, I am not getting any packets on the other side of the bridge (the muxing graph). I inspected the running capture graph with GraphStudioNext and somehow the sample grabbers appear detached from my graph, even though I got successful confirmations when I connected them to the source filter!.
Here's the source code creating the graph.
void EuresysSourceBox::BuildGraph() {
HRESULT hRes;
CComPtr<IGraphBuilder> pGraph;
COM_CALL(pGraph.CoCreateInstance(CLSID_FilterGraph));
#ifdef REGISTER_IN_ROT
_rotEntry1 = FilterTools::RegisterGraphInROT(IntPtr(pGraph), "euresys graph");
#endif
// [*Video Source*]
String^ filterName = "Ux H.264 Visual Source";
Guid category = _GUIDToGuid((GUID)AM_KSCATEGORY_CAPTURE);
FilterMonikerList^ videoSourceList = FilterTools::GetFilterMonikersByName(category, filterName);
CComPtr<IBaseFilter> pVideoSource;
int monikerIndex = config->BoardIndex; // a filter instance will be retrieved for every installed board
clr_scoped_ptr<CComPtr<IMoniker>>^ ppVideoSourceMoniker = videoSourceList[monikerIndex];
COM_CALL((*ppVideoSourceMoniker->get())->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pVideoSource));
COM_CALL(pGraph->AddFilter(pVideoSource, L"VideoSource"));
// [Video Source]
//
// [*Audio Source*]
filterName = "Ux H.264 Audio Encoder";
FilterMonikerList^ audioSourceList = FilterTools::GetFilterMonikersByName(category, filterName);
CComPtr<IBaseFilter> pAudioSource;
clr_scoped_ptr<CComPtr<IMoniker>>^ ppAudioSourceMoniker = audioSourceList[monikerIndex];
COM_CALL((*ppAudioSourceMoniker->get())->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pAudioSource));
COM_CALL(pGraph->AddFilter(pAudioSource, L"AudioSource"));
CComPtr<IPin> pVideoCompressedOutPin(FilterTools::GetPin(pVideoSource, "Encoded"));
CComPtr<IPin> pAudioOutPin(FilterTools::GetPin(pAudioSource, "Audio"));
CComPtr<IBaseFilter> pSampleGrabber;
COM_CALL(pSampleGrabber.CoCreateInstance(CLSID_SampleGrabber));
COM_CALL(pGraph->AddFilter(pSampleGrabber, L"SampleGrabber"));
CComPtr<IPin> pSampleGrabberInPin(FilterTools::GetPin(pSampleGrabber, "Input"));
COM_CALL(pGraph->ConnectDirect(pVideoCompressedOutPin, pSampleGrabberInPin, NULL)); // DOES NOT FAIL!!
CComPtr<IBaseFilter> pSampleGrabber2;
COM_CALL(pSampleGrabber2.CoCreateInstance(CLSID_SampleGrabber));
COM_CALL(pGraph->AddFilter(pSampleGrabber2, L"SampleGrabber2"));
CComPtr<IPin> pSampleGrabber2InPin(FilterTools::GetPin(pSampleGrabber2, "Input"));
COM_CALL(pGraph->ConnectDirect(pAudioOutPin, pSampleGrabber2InPin, NULL)); // DOES NOT FAIL!!
// [Video Source]---
// |-->[*Bridge Sink*]
// [Audio Source]---
CComPtr<IPin> pSampleGrabberOutPin(FilterTools::GetPin(pSampleGrabber, "Output"));
CComPtr<IPin> pSampleGrabber2OutPin(FilterTools::GetPin(pSampleGrabber2, "Output"));
CreateGraphBridge(
IntPtr(pGraph),
IntPtr(pSampleGrabberOutPin),
IntPtr(pSampleGrabber2OutPin)
);
// Root graph to parent object
_ppCaptureGraph.reset(new CComPtr<IGraphBuilder>(pGraph));
}
COM_CALL is my HRESULT checking macro, it will raise a managed exception if the result is other than S_OK. So the connection between pins succeeded, but here is how the graph looks disjointed when it is running:
So, I have three questions:
1) What could VFW_E_NO_ALLOCATOR mean in this instance? (the source filter can be successfully connected to other components such as LAV Video decoder or ffdshow video decoder).
2) Is there a known workaround to circumvent the VFW_E_NO_ALLOCATOR problem?
3) Is it possible that a filter gets disconnected at runtime as it seems to be happening in my case?
I found a reference by Geraint Davies giving a reason as to why the GMFBridge sink filter may be rejecting the connection.
It looks as though the parser is insisting on using its own allocator
-- this is common with parsers where the output samples are merely pointers into the input samples. However, the bridge cannot implement
suspend mode without using its own allocator, so a copy is required.
With this information, I decided to create an ultra simple CTransformFilter filter that simply accepts the allocator offered by the bridge and copies to the output sample whatever comes in from the input sample. I am not 100% sure that what I did was right, but it is working now. I could successfully plug-in the Euresys card as part of my capture infrastructure.
For reference, if anyone experiences something similar, here is the code of the filter I created:
class SampleCopyGeneratorFilter : public CTransformFilter {
protected:
HRESULT CheckInputType(const CMediaType* mtIn) override { return S_OK; }
HRESULT GetMediaType(int iPosition, CMediaType* pMediaType) override;
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) override { return S_OK; }
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp) override;
HRESULT Transform(IMediaSample *pSource, IMediaSample *pDest) override;
public:
SampleCopyGeneratorFilter();
};
//--------------------------------------------------------------------------------------------------------------------
SampleCopyGeneratorFilter::SampleCopyGeneratorFilter()
: CTransformFilter(NAME("SampleCopyGeneratorFilter"), NULL, GUID_NULL)
{
}
HRESULT SampleCopyGeneratorFilter::GetMediaType(int iPosition, CMediaType* pMediaType) {
HRESULT hRes;
ASSERT(m_pInput->IsConnected());
if( iPosition < 0 )
return E_INVALIDARG;
CComPtr<IPin> connectedTo;
COM_CALL(m_pInput->ConnectedTo(&connectedTo));
CComPtr<IEnumMediaTypes> pMTEnumerator;
COM_CALL(connectedTo->EnumMediaTypes(&pMTEnumerator));
AM_MEDIA_TYPE* pIteratedMediaType;
for( int i = 0; i <= iPosition; i++ ) {
if( pMTEnumerator->Next(1, &pIteratedMediaType, NULL) != S_OK )
return VFW_S_NO_MORE_ITEMS;
if( i == iPosition )
*pMediaType = *pIteratedMediaType;
DeleteMediaType(pIteratedMediaType);
}
return S_OK;
}
HRESULT SampleCopyGeneratorFilter::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp) {
HRESULT hRes;
AM_MEDIA_TYPE mt;
COM_CALL(m_pInput->ConnectionMediaType(&mt));
try {
BITMAPINFOHEADER* pBMI = HEADER(mt.pbFormat);
pProp->cbBuffer = DIBSIZE(*pBMI); // format is compressed, uncompressed size should be enough
if( !pProp->cbAlign )
pProp->cbAlign = 1;
pProp->cbPrefix = 0;
pProp->cBuffers = 4;
ALLOCATOR_PROPERTIES actualProperties;
COM_CALL(pAlloc->SetProperties(pProp, &actualProperties));
if( pProp->cbBuffer > actualProperties.cbBuffer )
return E_FAIL;
return S_OK;
} finally{
FreeMediaType(mt);
}
}
HRESULT SampleCopyGeneratorFilter::Transform(IMediaSample *pSource, IMediaSample *pDest) {
HRESULT hRes;
BYTE* pBufferIn;
BYTE* pBufferOut;
long destSize = pDest->GetSize();
long dataLen = pSource->GetActualDataLength();
if( dataLen > destSize )
return VFW_E_BUFFER_OVERFLOW;
COM_CALL(pSource->GetPointer(&pBufferIn));
COM_CALL(pDest->GetPointer(&pBufferOut));
memcpy(pBufferOut, pBufferIn, dataLen);
pDest->SetActualDataLength(dataLen);
pDest->SetSyncPoint(pSource->IsSyncPoint() == S_OK);
return S_OK;
}
Here is how I inserted the filter in the capture graph:
CComPtr<IPin> pAACEncoderOutPin(FilterTools::GetPin(pAACEncoder, "XForm Out"));
CComPtr<IPin> pVideoSourceCompressedOutPin(FilterTools::GetPin(pVideoSource, "Encoded"));
CComPtr<IBaseFilter> pSampleCopier;
pSampleCopier = new SampleCopyGeneratorFilter();
COM_CALL(pGraph->AddFilter(pSampleCopier, L"SampleCopier"));
CComPtr<IPin> pSampleCopierInPin(FilterTools::GetPin(pSampleCopier, "XForm In"));
COM_CALL(pGraph->ConnectDirect(pVideoSourceCompressedOutPin, pSampleCopierInPin, NULL));
CComPtr<IPin> pSampleCopierOutPin(FilterTools::GetPin(pSampleCopier, "XForm Out"));
CreateGraphBridge(
IntPtr(pGraph),
IntPtr(pSampleCopierOutPin),
IntPtr(pAACEncoderOutPin)
);
Now, I still have no idea why inserting the sample grabber instead did not work and resulted in detached graphs. I corroborated this quirk by examining the graphs with Graphedit Plus too. If anyone can offer me an explanation, I would be very grateful indeed.
I'm starter of RTOS and I'm using Xenomai v2.6.3.
I'm trying to get some data using Serial communication.
I did my best on the task following the xenomai's guide and open sources, but it doesn't work well.
the link of the guide --> (https://xenomai.org//serial-16550a-driver/)
I just followed the sequence to use the module xeno_16550A. (with port io = 0x2f8 and irq=3)
I followed open source http://www.acadis.org/pages/captain.at/serial-port-example
It works well in write task, but read task doesn't work well.
It gave me the error sentence with error while RTSER_RTIOC_WAIT_EVENT, code -110 (it means connection timed out)
Moreover I checked the irq number3 by typing command 'cat /proc/xenomai/irq', but the interrupt number doesn't increase.
In my case, I don't need to write data, so I erase the write task code.
The read task proc is follow
void read_task_proc(void *arg) {
int ret;
ssize_t red = 0;
struct rtser_event rx_event;
while (1) {
/* waiting for event */
ret = rt_dev_ioctl(my_fd, RTSER_RTIOC_WAIT_EVENT, &rx_event );
if (ret) {
printf(RTASK_PREFIX "error while RTSER_RTIOC_WAIT_EVENT, code %d\n",ret);
if (ret == -ETIMEDOUT)
continue;
break;
}
unsigned char buf[1];
red = rt_dev_read(my_fd, &buf, 1);
if (red < 0 ) {
printf(RTASK_PREFIX "error while rt_dev_read, code %d\n",red);
} else {
printf(RTASK_PREFIX "only %d byte received , char : %c\n",red,buf[0]);
}
}
exit_read_task:
if (my_state & STATE_FILE_OPENED) {
if (!close_file( my_fd, READ_FILE " (rtser)")) {
my_state &= ~STATE_FILE_OPENED;
}
}
printf(RTASK_PREFIX "exit\n");
}
I could guess the causes of the problem.
buffer size or buffer is already full when new data is received.
rx_interrupt doesn't work....
I want to check whether the two things are wrong or not, but How can I check?
Furthermore, does anybody know the cause of the problem? Please give me comments.
I am starting with Vulkan and I follow the Niko Kauppi's tutorial on Youtube.
I have an error when creating a device with vkCreateDevice, it returns VK_ERROR_EXTENSION_NOT_PRESENT
Here some part of my code:
The call to vkCreateDevice
_gpu_count = 0;
vkEnumeratePhysicalDevices(instance, &_gpu_count, nullptr);
std::vector<VkPhysicalDevice> gpu_list(_gpu_count);
vkEnumeratePhysicalDevices(instance, &_gpu_count, gpu_list.data());
_gpu = gpu_list[0];
vkGetPhysicalDeviceProperties(_gpu, &_gpu_properties);
VkDeviceCreateInfo device_create_info = _CreateDeviceInfo();
vulkanCheckError(vkCreateDevice(_gpu, &device_create_info, nullptr, &_device));
_gpu_count = 1 and _gpu_properties seems to recognize well my nvidia gpu (which is not up to date)
device_create_info
VkDeviceCreateInfo _createDeviceInfo;
_createDeviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
_createDeviceInfo.queueCreateInfoCount = 1;
VkDeviceQueueCreateInfo _queueInfo = _CreateDeviceQueueInfo();
_createDeviceInfo.pQueueCreateInfos = &_queueInfo;
I don't understand the meaning of the error: "A requested extension is not supported" according to Khronos' doc.
Thanks for your help
VK_ERROR_EXTENSION_NOT_PRESENT is returned when one of the extensions in [enabledExtensionCount, ppEnabledExtensionNames] vector you provided is not supported by the driver (as queried by vkEnumerateDeviceExtensionProperties()).
Extensions can also have dependencies, so VK_ERROR_EXTENSION_NOT_PRESENT is also returned when an extension dependency of extension in the list is missing there too.
If you want no device extensions, make sure enabledExtensionCount of VkDeviceCreateInfo is 0 (and not e.g. some uninitialized value).
I assume 2. is the whole body of _CreateDeviceInfo(), which would confirm the "uninitialized value" suspicion.
Usually though you would want a swapchain extension there to be able to render to screen directly.
First of all, make sure your VkDeviceCreateInfo is zero filled, otherwise it may carry garbage to your VkCreateDevice() call.
Add following line just after declaring your VkDeviceCreateInfo:
memset ( &_createDeviceInfo, 0, sizeof(VkDeviceCreateInfo) );
Some extensions are absolutely necessary, as swapchain one.
To retrieve available extensions do this:
// Available extensions and layers names
const char* const* _ppExtensionNames = NULL;
// get extension names
uint32 _extensionCount = 0;
vkEnumerateDeviceExtensionProperties( _gpu, NULL, &_extensionCount, NULL);
std::vector<const char *> extNames;
std::vector<VkExtensionProperties> extProps(_extensionCount);
vkEnumerateDeviceExtensionProperties(_gpu, NULL, &_extensionCount, extProps.data());
for (uint32_t i = 0; i < _extensionCount; i++) {
extNames.push_back(extProps[i].extensionName);
}
_ppExtensionNames = extNames.data();
Once you have all extension names in _ppExtensionNames, pass it to your deviceCreateInfo struct:
VkDeviceCreateInfo device_create_info ...
[...]
device_create_info.enabledExtensionCount = _extensionCount;
device_create_info.ppEnabledExtensionNames = _ppExtensionNames;
[...]
vulkanCheckError(vkCreateDevice(_gpu, &device_create_info, nullptr, &_device));
I hope it helps.
Please double check above code, as I'm writing it by heart.
I am getting into Vulkan and stumbled on my first problem. When trying to create a debug report callback (validation layers and debug extensions are available on my intel hd vulkan driver, at least it says so), it fails telling me vkCreateDebugReportCallbackEXT is an unresolved symbol. When trying to get the function pointer it fails telling me vkCreateDebugReportCallbackEXT is already defined.
Which it is, in the Vulkan header. I could set VK_NO_PROTOTYPES but then I would have to load everything by hand. Is there a way around this? Just using a different name for the function pointer won't work, since I am using Vulkan-Hpp and it uses vkCreateDebugReportCallbackEXT as it is.
Is this a driver bug, telling me debug extensions are available, but there are not?
Btw, I am using VS2015.
Thanks for any help
That's normal. vulkan.h defines them as a global functions. But the loader commands obviously return function pointer.
Normally you would just use a different name you like. But I like to have the canonical names too...
I solve it by defining the function myself (using the declaration from vulkan.h) which in turn calls the loaded pointer:
VKAPI_ATTR VkResult VKAPI_CALL vkCommandEXT( /*...*/ ){
return fpCommandEXT( /*...*/ );
}
(Shameless self-promotion) Like so:
https://github.com/krOoze/Hello_Triangle/blob/8227220/ErrorHandling.h#L181
I make the command to self-load on its first use — if you don't like that, in older commit I had more conventional loader:
https://github.com/krOoze/Hello_Triangle/blob/699ab57/HelloTriangle.cpp#L731
PS:
Khronos themselves just added loader code that illustrates that nicely:
https://github.com/KhronosGroup/Vulkan-Docs/blob/1.0/src/ext_loader/vulkan_ext.c
If you handle multiple VkInstances or VkDevices the loaded functions have to be dispatched to the correct instance or device. For example, I do that (likely inefficiently) here:
https://github.com/krOoze/Hello_Triangle/blob/a691de5/ExtensionLoader.h
I had same issue, couldn't find solution so i solved it this way
(might be wrong, but i just want to share in case it will help somebody):
struct DebugDispatch {
//KHRONOS
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT = 0;
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT = 0;
//LUNARG
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = 0;
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = 0;
}
VKAPI_ATTR vk::Bool32 VKAPI_CALL debugReportCallback(...){...}
VKAPI_ATTR vk::Bool32 VKAPI_CALL debugUtilsMessengerCallback(...){...}
enum class ValidationFlagsBits : unsigned int {
NONE = 0,
KHRONOS = 1,
LUNARG = 1 << 1
};
typedef vk::Flags<ValidationFlagsBits> ValidationFlags;
void Example(){
...
vk::Instance instance;
instance = vk::createInstance(...);
DebugDispatch debug_dispatch;
vk::DebugReportCallbackEXT debug_report_callback;
vk::DebugUtilsMessengerEXT debug_utils_messenger;
if(validation_flags & ValidationFlagsBits::KHRONOS){
debug_dispatch.vkCreateDebugReportCallbackEXT =
(PFN_vkCreateDebugReportCallbackEXT)instance.getProcAddr("vkCreateDebugReportCallbackEXT");
debug_dispatch.vkDestroyDebugReportCallbackEXT =
(PFN_vkDestroyDebugReportCallbackEXT)instance.getProcAddr("vkDestroyDebugReportCallbackEXT");
vk::DebugUtilsMessengerCreateInfoEXT create_info{};
create_info.messageSeverity = ...;
create_info.messageType = ...;
create_info.pfnUserCallback = reinterpret_cast<PFN_vkDebugUtilsMessengerCallbackEXT>(&debugUtilsMessengerCallback);
debug_utils_messenger = instance.createDebugUtilsMessengerEXT(create_info, nullptr, debug_dispatch);
}
if(validation_flags & ValidationFlagsBits::LUNARG){
debug_dispatch.vkCreateDebugUtilsMessengerEXT =
(PFN_vkCreateDebugUtilsMessengerEXT)instance.getProcAddr("vkCreateDebugUtilsMessengerEXT");
debug_dispatch.vkDestroyDebugUtilsMessengerEXT =
(PFN_vkDestroyDebugUtilsMessengerEXT)instance.getProcAddr("vkDestroyDebugUtilsMessengerEXT");
vk::DebugReportCallbackCreateInfoEXT create_info{};
create_info.flags = ...;
create_info.pfnCallback = reinterpret_cast<PFN_vkDebugReportCallbackEXT>(&debugReportCallback);
debug_report_callback = instance.createDebugReportCallbackEXT(create_info, nullptr, debug_dispatch);
}
...
if(validation_flags & ValidationFlagsBits::KHRONOS){
instance.destroyDebugUtilsMessengerEXT(debug_utils_messenger, nullptr, debug_dispatch);
}
if(validation_flags & ValidationFlagsBits::LUNARG){
instance.destroyDebugReportCallbackEXT(debug_report_callback, nullptr, debug_dispatch);
}
instance.destroy();
}