Only expose device extension functions that are enabled

If a device extension isn't enabled, then the associated extension
functions shouldn't be exposed through vkGetDeviceProcAddr().

Bug b/117974925

Change-Id: I828cf9ff9d8aaf22c15a5379cfb9d93612d23360
Tests: dEQP-VK.api.version_check.entry_points
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31696
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Vulkan/VkDevice.cpp b/src/Vulkan/VkDevice.cpp
index 6b082e6..9871872 100644
--- a/src/Vulkan/VkDevice.cpp
+++ b/src/Vulkan/VkDevice.cpp
@@ -37,7 +37,9 @@
 {
 
 Device::Device(const Device::CreateInfo* info, void* mem)
-	: physicalDevice(info->pPhysicalDevice), queues(reinterpret_cast<Queue*>(mem))
+	: physicalDevice(info->pPhysicalDevice),
+	  queues(reinterpret_cast<Queue*>(mem)),
+	  enabledExtensionCount(info->pCreateInfo->enabledExtensionCount)
 {
 	const auto* pCreateInfo = info->pCreateInfo;
 	for(uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
@@ -57,6 +59,12 @@
 		}
 	}
 
+	extensions = reinterpret_cast<ExtensionName*>(static_cast<uint8_t*>(mem) + (sizeof(Queue) * queueCount));
+	for(uint32_t i = 0; i < enabledExtensionCount; i++)
+	{
+		strncpy(extensions[i], pCreateInfo->ppEnabledExtensionNames[i], VK_MAX_EXTENSION_NAME_SIZE);
+	}
+
 	if(pCreateInfo->enabledLayerCount)
 	{
 		// "The ppEnabledLayerNames and enabledLayerCount members of VkDeviceCreateInfo are deprecated and their values must be ignored by implementations."
@@ -87,7 +95,19 @@
 		queueCount += info->pCreateInfo->pQueueCreateInfos[i].queueCount;
 	}
 
-	return sizeof(Queue) * queueCount;
+	return (sizeof(Queue) * queueCount) + (info->pCreateInfo->enabledExtensionCount * sizeof(ExtensionName));
+}
+
+bool Device::hasExtension(const char* extensionName) const
+{
+	for(uint32_t i = 0; i < enabledExtensionCount; i++)
+	{
+		if(strncmp(extensions[i], extensionName, VK_MAX_EXTENSION_NAME_SIZE) == 0)
+		{
+			return true;
+		}
+	}
+	return false;
 }
 
 VkQueue Device::getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const
diff --git a/src/Vulkan/VkDevice.hpp b/src/Vulkan/VkDevice.hpp
index 2b129f1..3ce466d 100644
--- a/src/Vulkan/VkDevice.hpp
+++ b/src/Vulkan/VkDevice.hpp
@@ -43,6 +43,7 @@
 
 	static size_t ComputeRequiredAllocationSize(const CreateInfo* info);
 
+	bool hasExtension(const char* extensionName) const;
 	VkQueue getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const;
 	VkResult waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);
 	VkResult waitIdle();
@@ -58,6 +59,9 @@
 	Queue* queues = nullptr;
 	uint32_t queueCount = 0;
 	sw::Blitter* blitter = nullptr;
+	uint32_t enabledExtensionCount = 0;
+	typedef char ExtensionName[VK_MAX_EXTENSION_NAME_SIZE];
+	ExtensionName* extensions = nullptr;
 };
 
 using DispatchableDevice = DispatchableObject<Device, VkDevice>;
diff --git a/src/Vulkan/VkGetProcAddress.cpp b/src/Vulkan/VkGetProcAddress.cpp
index 0938ce1..194f146 100644
--- a/src/Vulkan/VkGetProcAddress.cpp
+++ b/src/Vulkan/VkGetProcAddress.cpp
@@ -13,9 +13,11 @@
 // limitations under the License.
 
 #include "VkGetProcAddress.h"
+#include "VkDevice.hpp"
 
 #include <unordered_map>
 #include <string>
+#include <vector>
 
 #ifdef __ANDROID__
 #include <cerrno>
@@ -234,44 +236,90 @@
 	MAKE_VULKAN_DEVICE_ENTRY(vkDestroyDescriptorUpdateTemplate),
 	MAKE_VULKAN_DEVICE_ENTRY(vkUpdateDescriptorSetWithTemplate),
 	MAKE_VULKAN_DEVICE_ENTRY(vkGetDescriptorSetLayoutSupport),
-	// VK_KHR_descriptor_update_template
-	MAKE_VULKAN_DEVICE_ENTRY(vkCreateDescriptorUpdateTemplateKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkDestroyDescriptorUpdateTemplateKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkUpdateDescriptorSetWithTemplateKHR),
-	// VK_KHR_device_group
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetDeviceGroupPeerMemoryFeaturesKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkCmdSetDeviceMaskKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkCmdDispatchBaseKHR),
-	// VK_KHR_maintenance1
-	MAKE_VULKAN_DEVICE_ENTRY(vkTrimCommandPoolKHR),
-	// VK_KHR_sampler_ycbcr_conversion
-	MAKE_VULKAN_DEVICE_ENTRY(vkCreateSamplerYcbcrConversionKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkDestroySamplerYcbcrConversionKHR),
-	// VK_KHR_bind_memory2
-	MAKE_VULKAN_DEVICE_ENTRY(vkBindBufferMemory2KHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkBindImageMemory2KHR),
-	// VK_KHR_get_memory_requirements2
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetImageMemoryRequirements2KHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetBufferMemoryRequirements2KHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetImageSparseMemoryRequirements2KHR),
-	// VK_KHR_maintenance3
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetDescriptorSetLayoutSupportKHR),
-#ifndef __ANDROID__
-	// VK_KHR_swapchain
-	MAKE_VULKAN_DEVICE_ENTRY(vkCreateSwapchainKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkDestroySwapchainKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetSwapchainImagesKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkAcquireNextImageKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkQueuePresentKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetDeviceGroupPresentCapabilitiesKHR),
-	MAKE_VULKAN_DEVICE_ENTRY(vkGetDeviceGroupSurfacePresentModesKHR),
-#else
+#ifdef __ANDROID__
 	MAKE_VULKAN_DEVICE_ENTRY(vkGetSwapchainGrallocUsageANDROID),
 	MAKE_VULKAN_DEVICE_ENTRY(vkGetSwapchainGrallocUsage2ANDROID),
 	MAKE_VULKAN_DEVICE_ENTRY(vkAcquireImageANDROID),
 	MAKE_VULKAN_DEVICE_ENTRY(vkQueueSignalReleaseImageANDROID),
 #endif
 };
+
+static const std::vector<std::pair<const char*, std::unordered_map<std::string, PFN_vkVoidFunction>>> deviceExtensionFunctionPointers =
+{
+	// VK_KHR_descriptor_update_template
+	{
+		VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkCreateDescriptorUpdateTemplateKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkDestroyDescriptorUpdateTemplateKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkUpdateDescriptorSetWithTemplateKHR),
+		}
+	},
+	// VK_KHR_device_group
+	{
+		VK_KHR_DEVICE_GROUP_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetDeviceGroupPeerMemoryFeaturesKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkCmdSetDeviceMaskKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkCmdDispatchBaseKHR),
+		}
+	},
+	// VK_KHR_maintenance1
+	{
+		VK_KHR_MAINTENANCE1_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkTrimCommandPoolKHR),
+		}
+	},
+	// VK_KHR_sampler_ycbcr_conversion
+	{
+		VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkCreateSamplerYcbcrConversionKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkDestroySamplerYcbcrConversionKHR),
+		}
+	},
+	// VK_KHR_bind_memory2
+	{
+		VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkBindBufferMemory2KHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkBindImageMemory2KHR),
+		}
+	},
+	// VK_KHR_get_memory_requirements2
+	{
+		VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetImageMemoryRequirements2KHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetBufferMemoryRequirements2KHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetImageSparseMemoryRequirements2KHR),
+		}
+	},
+	// VK_KHR_maintenance3
+	{
+		VK_KHR_MAINTENANCE3_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetDescriptorSetLayoutSupportKHR),
+		}
+	},
+#ifndef __ANDROID__
+	// VK_KHR_swapchain
+	{
+		VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+		{
+			MAKE_VULKAN_DEVICE_ENTRY(vkCreateSwapchainKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkDestroySwapchainKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetSwapchainImagesKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkAcquireNextImageKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkQueuePresentKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetDeviceGroupPresentCapabilitiesKHR),
+			MAKE_VULKAN_DEVICE_ENTRY(vkGetDeviceGroupSurfacePresentModesKHR),
+		}
+	},
+#endif
+};
+
 #undef MAKE_VULKAN_DEVICE_ENTRY
 
 PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName)
@@ -308,6 +356,19 @@
 		return deviceFunction->second;
 	}
 
+	vk::Device* myDevice = Cast(device);
+	for(const auto& deviceExtensionFunctions : deviceExtensionFunctionPointers)
+	{
+		if(myDevice->hasExtension(deviceExtensionFunctions.first))
+		{
+			deviceFunction = deviceExtensionFunctions.second.find(std::string(pName));
+			if(deviceFunction != deviceExtensionFunctions.second.end())
+			{
+				return deviceFunction->second;
+			}
+		}
+	}
+
 	return nullptr;
 }
 
diff --git a/src/Vulkan/libVulkan.cpp b/src/Vulkan/libVulkan.cpp
index d734bb0..3e56519 100644
--- a/src/Vulkan/libVulkan.cpp
+++ b/src/Vulkan/libVulkan.cpp
@@ -1290,8 +1290,7 @@
 		switch(extensionCreateInfo->sType)
 		{
 		case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT:
-			ASSERT(!HasExtensionProperty(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, deviceExtensionProperties,
-			                             sizeof(deviceExtensionProperties) / sizeof(deviceExtensionProperties[0])));
+			ASSERT(!vk::Cast(device)->hasExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME));
 			break;
 		default:
 			UNIMPLEMENTED("extensionCreateInfo->sType");