zeux/volk

Use of X macro for function prototype list

rubycon opened this issue · 6 comments

volk/volk.c

Line 98 in 0c836e6

/* VOLK_GENERATE_LOAD_INSTANCE */

A modest suggestion to make the code simpler: generate.py could create separate header file for each category of Vulkan functions (volk_instance.h, volk_device.h, volk_loader.h...), these files could then be included though X macros for function loading, prototype definitions, device table setup...

zeux commented

Yeah I considered doing that but wasn't sure how important this is given that large portions are generated - that is, I wasn't sure if I should really be using preprocessor for something that's automatically generated. Definitely easier to set breakpoints without using X-macros but not sure how important that is either.

zeux commented

Oh, right... One issue with this request is the conditional availability of many functions. generator.py currently has to insert checks like this:

#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1))
extern PFN_vkAcquireNextImage2KHR vkAcquireNextImage2KHR;
#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */

This might be possible to express inside an X-Macro with something like

#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1))
#define VOLK_XMACRO_GROUP_17(X) X(vkAcquireNextImage2KHR)
#else
#define VOLK_XMACRO_GROUP_17(X)
#endif

and then have the actual X-Macro refer to these but at this point this becomes more unwieldy than the current solution.

I was thinking of this kind of X-Macro, where you can keep all your check in one place.

// volk_device.h
#if defined(VK_VERSION_1_0)
  DEFINE_VKDEVICE(AllocateCommandBuffers)
  DEFINE_VKDEVICE(AllocateDescriptorSets)
  DEFINE_VKDEVICE(AllocateMemory)
  DEFINE_VKDEVICE(BeginCommandBuffer)
  DEFINE_VKDEVICE(BindBufferMemory)
  /* ... */
#if (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1))
  DEFINE_VKDEVICE(GetDeviceGroupPresentCapabilitiesKHR)
  DEFINE_VKDEVICE(GetDeviceGroupSurfacePresentModesKHR)
#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_surface)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */
#if (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1))
  DEFINE_VKDEVICE(AcquireNextImage2KHR)
#endif /* (defined(VK_KHR_device_group) && defined(VK_KHR_swapchain)) || (defined(VK_KHR_swapchain) && defined(VK_VERSION_1_1)) */
// volk.h
struct VolkDeviceTable
{
  /* VOLK_GENERATE_DEVICE_TABLE */
  #define DEFINE_VKDEVICE(name) PFN_vk##name vk##name,
  #include "volk_device.h"
  #undef DEFINE_VKDEVICE
  /* ... */
}

/* VOLK_GENERATE_PROTOTYPES_H */
#define DEFINE_VKDEVICE(name) extern PFN_vk##name vk##name;
#include "volk_device.h"
#undef DEFINE_VKDEVICE
/* ... */
// volk.c

static void volkGenLoadDevice(void* context, PFN_vkVoidFunction (*load)(void*, const char*))
{
  /* VOLK_GENERATE_LOAD_DEVICE */
  #define DEFINE_VKDEVICE(name) vk##name = (PFN_vk##name) load(context, "vk" #name);
  #include "volk_device.h"
  #undef DEFINE_VKDEVICE
}
zeux commented

I see. That would work but it would require 3 extra headers. I'll experiment with this a bit but not sure yet this is a good idea.

zeux commented

I've added a branch xmacro: https://github.com/zeux/volk/tree/xmacro that implements the suggested technique. Overall I like this a lot and am leaning towards merging this (if anybody has thoughts on this, please comment).

One thing I still haven't done is a thorough look at navigation/autocomplete behavior across different IDEs. I'd like to be able to maintain that. So far it seems that in VS2017 autocomplete still works fine; there's a regression with navigation usability where before you could F12 to vkCmdDraw and then F12 to PFN_vkCmdDraw to see the list of arguments, which now doesn't work since first F12 takes you to the volkgen_device.h - but I plan to fix this by adding function signatures to the generated files. Still need to see how the behavior changes in other IDEs/editors.

zeux commented

I didn't really find a way to work around issues with Intellisense; additionally, trying to generate function signatures was met with significant issues wrt compatibility with multiple versions of Vulkan SDK - because of Vulkan 1.1 and various EXT->KHR promotions, it's non-trivial to generate a correct function signature with correct types that work for any version. So I decided to shelve this for now.