Filter out unsupported vulkan ICD extensions before they reach the user

This commit is contained in:
baldurk
2016-04-26 22:49:34 +02:00
parent c329fb0770
commit 176a4f8ddf
3 changed files with 174 additions and 48 deletions
+141
View File
@@ -567,6 +567,147 @@ Serialiser *WrappedVulkan::GetThreadSerialiser()
return ser;
}
static VkResult FillPropertyCountAndList(const VkExtensionProperties *src, uint32_t numExts, uint32_t *dstCount, VkExtensionProperties *dstProps)
{
if(dstCount && !dstProps)
{
// just returning the number of extensions
*dstCount = numExts;
return VK_SUCCESS;
}
else if(dstCount && dstProps)
{
uint32_t dstSpace = *dstCount;
// copy as much as there's space for, up to how many there are
memcpy(dstProps, src, sizeof(VkExtensionProperties)*RDCMIN(numExts, dstSpace));
// if there was enough space, return success, else incomplete
if(dstSpace >= numExts)
return VK_SUCCESS;
else
return VK_INCOMPLETE;
}
// both parameters were NULL, return incomplete
return VK_INCOMPLETE;
}
bool operator <(const VkExtensionProperties &a, const VkExtensionProperties &b)
{
// assume a given extension name is unique, ie. an implementation won't report the
// same extension with two different spec versions.
return strcmp(a.extensionName, b.extensionName) < 0;
}
VkResult WrappedVulkan::FilterDeviceExtensionProperties(VkPhysicalDevice physDev, uint32_t *pPropertyCount, VkExtensionProperties *pProperties)
{
VkResult vkr;
// first fetch the list of extensions ourselves
uint32_t numExts;
vkr = ObjDisp(physDev)->EnumerateDeviceExtensionProperties(Unwrap(physDev), NULL, &numExts, NULL);
if(vkr != VK_SUCCESS)
return vkr;
vector<VkExtensionProperties> exts(numExts);
vkr = ObjDisp(physDev)->EnumerateDeviceExtensionProperties(Unwrap(physDev), NULL, &numExts, &exts[0]);
if(vkr != VK_SUCCESS)
return vkr;
// filter the list of extensions to only the ones we support. Note it's important that
// this list is kept sorted according to the above sort operator!
const VkExtensionProperties supportedExtensions[] = {
{
VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
VK_EXT_DEBUG_REPORT_SPEC_VERSION,
},
{
VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION,
},
{
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SURFACE_SPEC_VERSION,
},
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_SWAPCHAIN_SPEC_VERSION,
},
#ifdef VK_KHR_win32_surface
{
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_SPEC_VERSION,
},
#endif
#ifdef VK_KHR_xcb_surface
{
VK_KHR_XCB_SURFACE_EXTENSION_NAME,
VK_KHR_XCB_SURFACE_SPEC_VERSION,
},
#endif
#ifdef VK_KHR_xlib_surface
{
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
VK_KHR_XLIB_SURFACE_SPEC_VERSION,
},
#endif
};
// sort the reported extensions
std::sort(exts.begin(), exts.end());
std::vector<VkExtensionProperties> filtered;
filtered.reserve(exts.size());
// now we can step through both lists with two pointers,
// instead of doing an O(N*M) lookup searching through each
// supported extension for each reported extension.
size_t i = 0;
for(auto it=exts.begin(); it != exts.end() && i < ARRAY_COUNT(supportedExtensions); )
{
int nameCompare = strcmp(it->extensionName, supportedExtensions[i].extensionName);
// if neither is less than the other, the extensions are equal
if(nameCompare == 0)
{
// warn on spec version mismatch, but allow it.
if(supportedExtensions[i].specVersion != it->specVersion)
RDCWARN("Spec versions are different between supported extension (%d) and reported (%d)!", supportedExtensions[i].specVersion, it->specVersion);
filtered.push_back(*it);
++it;
++i;
}
else if(nameCompare < 0)
{
// reported extension was less. It's not supported - skip past it and continue
++it;
}
else if(nameCompare > 0)
{
// supported extension was less. Check the next supported extension
++i;
}
}
return FillPropertyCountAndList(&filtered[0], (uint32_t)filtered.size(), pPropertyCount, pProperties);
}
VkResult WrappedVulkan::GetProvidedExtensionProperties(uint32_t *pPropertyCount, VkExtensionProperties *pProperties)
{
// this is the list of extensions we provide - regardless of whether the ICD supports them
const VkExtensionProperties providedExtensions[] = {
{
DEBUG_MARKER_EXTENSION_NAME,
VK_DEBUG_MARKER_EXTENSION_REVISION
},
};
return FillPropertyCountAndList(providedExtensions, (uint32_t)ARRAY_COUNT(providedExtensions), pPropertyCount, pProperties);
}
void WrappedVulkan::Serialise_CaptureScope(uint64_t offset)
{
uint32_t FrameNumber = m_FrameCounter;
+3
View File
@@ -580,6 +580,9 @@ public:
void SetDrawcallCB(DrawcallCallback *cb) { m_DrawcallCallback = cb; }
VkResult FilterDeviceExtensionProperties(VkPhysicalDevice physDev, uint32_t *pPropertyCount, VkExtensionProperties *pProperties);
VkResult GetProvidedExtensionProperties(uint32_t *pPropertyCount, VkExtensionProperties *pProperties);
// Device initialization
IMPLEMENT_FUNCTION_SERIALISED(VkResult, vkCreateInstance,
+30 -48
View File
@@ -120,51 +120,6 @@ void VKAPI_CALL hooked_vkDestroyInstance(VkInstance instance, const VkAllocation
// Layer Intercepts
static const VkLayerProperties physLayers[] = {
{
RENDERDOC_LAYER_NAME,
VK_API_VERSION,
VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
"Debugging capture layer for RenderDoc",
}
};
static const VkExtensionProperties physExts[] = {
{
DEBUG_MARKER_EXTENSION_NAME,
VK_MAKE_VERSION(0, 1, 0),
}
};
static const VkLayerProperties globalLayers[] = {
{
RENDERDOC_LAYER_NAME,
VK_API_VERSION,
VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
"Debugging capture layer for RenderDoc",
}
};
VkResult getProps(uint32_t *dstCount, void *dstProps, uint32_t srcCount, void *srcProps, size_t elemSize)
{
if(dstCount == NULL)
return VK_RESULT_MAX_ENUM;
if(dstProps == NULL)
{
*dstCount = srcCount;
return VK_SUCCESS;
}
memcpy(dstProps, srcProps, elemSize*RDCMIN(srcCount, *dstCount));
if(*dstCount < srcCount)
return VK_INCOMPLETE;
*dstCount = srcCount;
return VK_SUCCESS;
}
#if defined(RENDERDOC_PLATFORM_WIN32) && !defined(RDC64BIT)
// Win32 __stdcall will still mangle even with extern "C", set up aliases
@@ -183,7 +138,34 @@ VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceLay
uint32_t* pPropertyCount,
VkLayerProperties* pProperties)
{
return getProps(pPropertyCount, pProperties, ARRAY_COUNT(physLayers), (void *)physLayers, sizeof(VkLayerProperties));
// must have a property count, either to fill out or use as a size
if(pPropertyCount == NULL)
return VK_INCOMPLETE;
// if we're not writing the properties, just say we have one layer
if(pProperties == NULL)
{
*pPropertyCount = 1;
return VK_SUCCESS;
}
else
{
// if the property count is somehow zero, return incomplete
if(*pPropertyCount == 0)
return VK_INCOMPLETE;
const VkLayerProperties layerProperties = {
RENDERDOC_LAYER_NAME,
VK_API_VERSION_1_0,
VK_MAKE_VERSION(RENDERDOC_VERSION_MAJOR, RENDERDOC_VERSION_MINOR, 0),
"Debugging capture layer for RenderDoc",
};
// set the one layer property
*pProperties = layerProperties;
return VK_SUCCESS;
}
}
VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExtensionProperties(
@@ -195,9 +177,9 @@ VK_LAYER_EXPORT VkResult VKAPI_CALL VK_LAYER_RENDERDOC_CaptureEnumerateDeviceExt
// if pLayerName is NULL we're calling down through the layer chain to the ICD.
// This is our chance to filter out any reported extensions that we don't support
if(pLayerName == NULL)
return ObjDisp(physicalDevice)->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), pLayerName, pPropertyCount, pProperties);
return CoreDisp(physicalDevice)->FilterDeviceExtensionProperties(physicalDevice, pPropertyCount, pProperties);
return getProps(pPropertyCount, pProperties, ARRAY_COUNT(physExts), (void *)physExts, sizeof(VkExtensionProperties));
return CoreDisp(physicalDevice)->GetProvidedExtensionProperties(pPropertyCount, pProperties);
}
#undef HookInit