aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobin Ehlis <tobine@google.com>2017-10-13 09:26:20 -0600
committerTobin Ehlis <tobine@google.com>2017-10-30 11:01:05 -0600
commit45a0a80db6d9ba3b6ca436674c6c0b107d4926b7 (patch)
treee7e0ebba5a1ec34ccd63a6bfcae8f1c8f0aab7d6
parent4be6c2f230a7f73cd214e670e43e47ad48d4189a (diff)
downloadvulkan-validation-layers-45a0a80db6d9ba3b6ca436674c6c0b107d4926b7.tar.gz
icd: Adding generated mock icd
Initial check-in for mock icd which is being built to allow validation testing without the need for an actual Vulkan device. ICD is currently building and passing 324/332 tests. It creates ptr handles for dispatchable objects and unique id handles for non-dispatchable objects. It currently has some hard-coded values for various Get* device-query functions in order to allow forward progress. The long-term intention is to allow the device configuration to be set by the test itself. See the ICD README.md file for more info.
-rw-r--r--CMakeLists.txt5
-rw-r--r--README.md3
-rw-r--r--scripts/lvl_genvk.py45
-rw-r--r--scripts/mock_icd_generator.py1080
4 files changed, 1131 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ba1a0c62e..0d3b157f3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -119,6 +119,7 @@ option(BUILD_TESTS "Build tests" ON)
option(BUILD_LAYERS "Build layers" ON)
option(BUILD_DEMOS "Build demos" ON)
option(BUILD_VKJSON "Build vkjson" ON)
+option(BUILD_ICD "Build icd" ON)
option(CUSTOM_GLSLANG_BIN_ROOT "Use the user defined GLSLANG_BINARY_ROOT" OFF)
option(CUSTOM_SPIRV_TOOLS_BIN_ROOT "Use the user defined SPIRV_TOOLS*BINARY_ROOT paths" OFF)
@@ -380,3 +381,7 @@ endif()
if(BUILD_VKJSON)
add_subdirectory(libs/vkjson)
endif()
+
+if(BUILD_ICD)
+ add_subdirectory(icd)
+endif()
diff --git a/README.md b/README.md
index 5a834df7b..e678e6807 100644
--- a/README.md
+++ b/README.md
@@ -17,13 +17,14 @@ how Vulkan is used often result in a crash. This project provides standard valid
to ease development by helping developers verify their applications correctly use the Vulkan API.
Vulkan supports multiple GPUs and multiple global contexts (VkInstance). The ICD loader is necessary to
-support multiple GPUs and the VkInstance level Vulkan commands. Additionally, the loader manages inserting
+support multiple GPUs and the VkInstance level Vulkan commands. Additionally, the loader manages inserting
Vulkan layer libraries, including validation layers between the application and the ICD.
The following components are available in this repository:
- Vulkan header files
- [*ICD Loader*](loader/)
- [*Validation Layers*](layers/)
+- [*Mock ICD*](icd/)
- Demos and tests for the loader and validation layers
## Contributing
diff --git a/scripts/lvl_genvk.py b/scripts/lvl_genvk.py
index 194106e09..09554db6c 100644
--- a/scripts/lvl_genvk.py
+++ b/scripts/lvl_genvk.py
@@ -26,6 +26,7 @@ from object_tracker_generator import ObjectTrackerGeneratorOptions, ObjectTracke
from dispatch_table_helper_generator import DispatchTableHelperOutputGenerator, DispatchTableHelperOutputGeneratorOptions
from helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions
from loader_extension_generator import LoaderExtensionOutputGenerator, LoaderExtensionGeneratorOptions
+from mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator
# Simple timer functions
startTime = None
@@ -122,7 +123,6 @@ def makeGenOpts(extensions = [], removeExtensions = [], protect = True, director
alignFuncParam = 48)
]
-
# Options for parameter validation layer
genOpts['parameter_validation.cpp'] = [
ParameterValidationOutputGenerator,
@@ -424,6 +424,49 @@ def makeGenOpts(extensions = [], removeExtensions = [], protect = True, director
helper_file_type = 'extension_helper_header')
]
+ # Options for mock ICD header
+ genOpts['mock_icd.h'] = [
+ MockICDOutputGenerator,
+ MockICDGeneratorOptions(
+ filename = 'mock_icd.h',
+ directory = directory,
+ apiname = 'vulkan',
+ profile = None,
+ versions = allVersions,
+ emitversions = allVersions,
+ defaultExtensions = 'vulkan',
+ addExtensions = addExtensions,
+ removeExtensions = removeExtensions,
+ prefixText = prefixStrings + vkPrefixStrings,
+ protectFeature = False,
+ apicall = 'VKAPI_ATTR ',
+ apientry = 'VKAPI_CALL ',
+ apientryp = 'VKAPI_PTR *',
+ alignFuncParam = 48,
+ helper_file_type = 'mock_icd_header')
+ ]
+
+ # Options for mock ICD cpp
+ genOpts['mock_icd.cpp'] = [
+ MockICDOutputGenerator,
+ MockICDGeneratorOptions(
+ filename = 'mock_icd.cpp',
+ directory = directory,
+ apiname = 'vulkan',
+ profile = None,
+ versions = allVersions,
+ emitversions = allVersions,
+ defaultExtensions = 'vulkan',
+ addExtensions = addExtensions,
+ removeExtensions = removeExtensions,
+ prefixText = prefixStrings + vkPrefixStrings,
+ protectFeature = False,
+ apicall = 'VKAPI_ATTR ',
+ apientry = 'VKAPI_CALL ',
+ apientryp = 'VKAPI_PTR *',
+ alignFuncParam = 48,
+ helper_file_type = 'mock_icd_source')
+ ]
# Generate a target based on the options in the matching genOpts{} object.
# This is encapsulated in a function so it can be profiled and/or timed.
diff --git a/scripts/mock_icd_generator.py b/scripts/mock_icd_generator.py
new file mode 100644
index 000000000..e351d70e5
--- /dev/null
+++ b/scripts/mock_icd_generator.py
@@ -0,0 +1,1080 @@
+#!/usr/bin/python3 -i
+#
+# Copyright (c) 2015-2017 The Khronos Group Inc.
+# Copyright (c) 2015-2017 Valve Corporation
+# Copyright (c) 2015-2017 LunarG, Inc.
+# Copyright (c) 2015-2017 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Author: Tobin Ehlis <tobine@google.com>
+#
+# This script generates a Mock ICD that intercepts almost all Vulkan
+# functions. That layer is not intended to be useful or even compilable
+# in its initial state. Rather it's intended to be a starting point that
+# can be copied and customized to assist in creation of a new layer.
+
+import os,re,sys
+from generator import *
+
+# Mock header code
+HEADER_C_CODE = '''
+using mutex_t = std::mutex;
+using lock_guard_t = std::lock_guard<mutex_t>;
+using unique_lock_t = std::unique_lock<mutex_t>;
+
+static mutex_t global_lock;
+static uint64_t global_unique_handle = 1;
+static const uint32_t SUPPORTED_LOADER_ICD_INTERFACE_VERSION = 5;
+static uint32_t loader_interface_version = 0;
+static bool negotiate_loader_icd_interface_called = false;
+static void* CreateDispObjHandle() {
+ auto handle = new VK_LOADER_DATA;
+ set_loader_magic_value(handle);
+ return handle;
+}
+static void DestroyDispObjHandle(void* handle) {
+ delete reinterpret_cast<VK_LOADER_DATA*>(handle);
+}
+'''
+
+# Manual code at the top of the cpp source file
+SOURCE_CPP_PREFIX = '''
+using std::unordered_map;
+
+// Map device memory handle to any mapped allocations that we'll need to free on unmap
+static unordered_map<VkDeviceMemory, std::vector<void*>> mapped_memory_map;
+
+static VkPhysicalDevice physical_device = nullptr;
+static unordered_map<VkDevice, unordered_map<uint32_t, unordered_map<uint32_t, VkQueue>>> queue_map;
+
+// TODO: Would like to codegen this but limits aren't in XML
+static VkPhysicalDeviceLimits SetLimits(VkPhysicalDeviceLimits *limits) {
+ limits->maxImageDimension1D = 4096;
+ limits->maxImageDimension2D = 4096;
+ limits->maxImageDimension3D = 256;
+ limits->maxImageDimensionCube = 4096;
+ limits->maxImageArrayLayers = 256;
+ limits->maxTexelBufferElements = 65536;
+ limits->maxUniformBufferRange = 16384;
+ limits->maxStorageBufferRange = 134217728;
+ limits->maxPushConstantsSize = 128;
+ limits->maxMemoryAllocationCount = 4096;
+ limits->maxSamplerAllocationCount = 4000;
+ limits->bufferImageGranularity = 1;
+ limits->sparseAddressSpaceSize = 2147483648;
+ limits->maxBoundDescriptorSets = 4;
+ limits->maxPerStageDescriptorSamplers = 16;
+ limits->maxPerStageDescriptorUniformBuffers = 12;
+ limits->maxPerStageDescriptorStorageBuffers = 4;
+ limits->maxPerStageDescriptorSampledImages = 16;
+ limits->maxPerStageDescriptorStorageImages = 4;
+ limits->maxPerStageDescriptorInputAttachments = 4;
+ limits->maxPerStageResources = 128^2;
+ limits->maxDescriptorSetSamplers = 96^8;
+ limits->maxDescriptorSetUniformBuffers = 72^8;
+ limits->maxDescriptorSetUniformBuffersDynamic = 8;
+ limits->maxDescriptorSetStorageBuffers = 24^8;
+ limits->maxDescriptorSetStorageBuffersDynamic = 4;
+ limits->maxDescriptorSetSampledImages = 96^8;
+ limits->maxDescriptorSetStorageImages = 24^8;
+ limits->maxDescriptorSetInputAttachments = 4;
+ limits->maxVertexInputAttributes = 16;
+ limits->maxVertexInputBindings = 16;
+ limits->maxVertexInputAttributeOffset = 2047;
+ limits->maxVertexInputBindingStride = 2048;
+ limits->maxVertexOutputComponents = 64;
+ limits->maxTessellationGenerationLevel = 64;
+ limits->maxTessellationPatchSize = 32;
+ limits->maxTessellationControlPerVertexInputComponents = 64;
+ limits->maxTessellationControlPerVertexOutputComponents = 64;
+ limits->maxTessellationControlPerPatchOutputComponents = 120;
+ limits->maxTessellationControlTotalOutputComponents = 2048;
+ limits->maxTessellationEvaluationInputComponents = 64;
+ limits->maxTessellationEvaluationOutputComponents = 64;
+ limits->maxGeometryShaderInvocations = 32;
+ limits->maxGeometryInputComponents = 64;
+ limits->maxGeometryOutputComponents = 64;
+ limits->maxGeometryOutputVertices = 256;
+ limits->maxGeometryTotalOutputComponents = 1024;
+ limits->maxFragmentInputComponents = 64;
+ limits->maxFragmentOutputAttachments = 4;
+ limits->maxFragmentDualSrcAttachments = 1;
+ limits->maxFragmentCombinedOutputResources = 4;
+ limits->maxComputeSharedMemorySize = 16384;
+ limits->maxComputeWorkGroupCount[0] = 65535;
+ limits->maxComputeWorkGroupCount[1] = 65535;
+ limits->maxComputeWorkGroupCount[2] = 65535;
+ limits->maxComputeWorkGroupInvocations = 128;
+ limits->maxComputeWorkGroupSize[0] = 128;
+ limits->maxComputeWorkGroupSize[1] = 128;
+ limits->maxComputeWorkGroupSize[2] = 64;
+ limits->subPixelPrecisionBits = 4;
+ limits->subTexelPrecisionBits = 4;
+ limits->mipmapPrecisionBits = 4;
+ limits->maxDrawIndexedIndexValue = (2^32) - 1;
+ limits->maxDrawIndirectCount = (2^16) - 1;
+ limits->maxSamplerLodBias = 2.0f;
+ limits->maxSamplerAnisotropy = 16;
+ limits->maxViewports = 16;
+ limits->maxViewportDimensions[0] = 4096;
+ limits->maxViewportDimensions[1] = 4096;
+ limits->viewportBoundsRange[0] = -8192;
+ limits->viewportBoundsRange[1] = 8191;
+ limits->viewportSubPixelBits = 0;
+ limits->minMemoryMapAlignment = 64;
+ limits->minTexelBufferOffsetAlignment = 256;
+ limits->minUniformBufferOffsetAlignment = 256;
+ limits->minStorageBufferOffsetAlignment = 256;
+ limits->minTexelOffset = -8;
+ limits->maxTexelOffset = 7;
+ limits->minTexelGatherOffset = -8;
+ limits->maxTexelGatherOffset = 7;
+ limits->minInterpolationOffset = 0.0f;
+ limits->maxInterpolationOffset = 0.5f;
+ limits->subPixelInterpolationOffsetBits = 4;
+ limits->maxFramebufferWidth = 4096;
+ limits->maxFramebufferHeight = 4096;
+ limits->maxFramebufferLayers = 256;
+ limits->framebufferColorSampleCounts = 0x7F;
+ limits->framebufferDepthSampleCounts = 0x7F;
+ limits->framebufferStencilSampleCounts = 0x7F;
+ limits->framebufferNoAttachmentsSampleCounts = 0x7F;
+ limits->maxColorAttachments = 4;
+ limits->sampledImageColorSampleCounts = 0x7F;
+ limits->sampledImageIntegerSampleCounts = 0x7F;
+ limits->sampledImageDepthSampleCounts = 0x7F;
+ limits->sampledImageStencilSampleCounts = 0x7F;
+ limits->storageImageSampleCounts = 0x7F;
+ limits->maxSampleMaskWords = 1;
+ limits->timestampComputeAndGraphics = VK_TRUE;
+ limits->timestampPeriod = 1;
+ limits->maxClipDistances = 8;
+ limits->maxCullDistances = 8;
+ limits->maxCombinedClipAndCullDistances = 8;
+ limits->discreteQueuePriorities = 2;
+ limits->pointSizeRange[0] = 1.0f;
+ limits->pointSizeRange[1] = 64.0f;
+ limits->lineWidthRange[0] = 1.0f;
+ limits->lineWidthRange[1] = 8.0f;
+ limits->pointSizeGranularity = 1.0f;
+ limits->lineWidthGranularity = 1.0f;
+ limits->strictLines = VK_TRUE;
+ limits->standardSampleLocations = VK_TRUE;
+ limits->optimalBufferCopyOffsetAlignment = 1;
+ limits->optimalBufferCopyRowPitchAlignment = 1;
+ limits->nonCoherentAtomSize = 256;
+
+ return *limits;
+}
+'''
+
+# Manual code at the end of the cpp source file
+SOURCE_CPP_POSTFIX = '''
+
+static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName) {
+ // TODO: This function should only care about physical device functions and return nullptr for other functions
+ const auto &item = name_to_funcptr_map.find(funcName);
+ if (item != name_to_funcptr_map.end()) {
+ return reinterpret_cast<PFN_vkVoidFunction>(item->second);
+ }
+ // Mock should intercept all functions so if we get here just return null
+ return nullptr;
+}
+
+} // namespace vkmock
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define EXPORT __attribute__((visibility("default")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
+#define EXPORT __attribute__((visibility("default")))
+#else
+#define EXPORT
+#endif
+
+#ifdef WIN32
+ extern "C" __declspec(dllexport) {
+#else
+ extern "C" {
+#endif
+EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetInstanceProcAddr(VkInstance instance, const char* pName) {
+ if (!vkmock::negotiate_loader_icd_interface_called) {
+ vkmock::loader_interface_version = 1;
+ }
+ return vkmock::GetInstanceProcAddr(instance, pName);
+}
+
+EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char* pName) {
+ return vkmock::GetPhysicalDeviceProcAddr(instance, pName);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t* pSupportedVersion) {
+ vkmock::negotiate_loader_icd_interface_called = true;
+ vkmock::loader_interface_version = *pSupportedVersion;
+ if (*pSupportedVersion > vkmock::SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
+ *pSupportedVersion = vkmock::SUPPORTED_LOADER_ICD_INTERFACE_VERSION;
+ }
+ return VK_SUCCESS;
+}
+
+
+EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(
+ VkInstance instance,
+ VkSurfaceKHR surface,
+ const VkAllocationCallbacks* pAllocator)
+{
+ vkmock::DestroySurfaceKHR(instance, surface, pAllocator);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(
+ VkPhysicalDevice physicalDevice,
+ uint32_t queueFamilyIndex,
+ VkSurfaceKHR surface,
+ VkBool32* pSupported)
+{
+ return vkmock::GetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, surface, pSupported);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
+{
+ return vkmock::GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, pSurfaceCapabilities);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t* pSurfaceFormatCount,
+ VkSurfaceFormatKHR* pSurfaceFormats)
+{
+ return vkmock::GetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, pSurfaceFormatCount, pSurfaceFormats);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfacePresentModesKHR(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t* pPresentModeCount,
+ VkPresentModeKHR* pPresentModes)
+{
+ return vkmock::GetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, pPresentModeCount, pPresentModes);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDisplayPlaneSurfaceKHR(
+ VkInstance instance,
+ const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateDisplayPlaneSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+
+#ifdef VK_USE_PLATFORM_XLIB_KHR
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
+ VkInstance instance,
+ const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateXlibSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_XLIB_KHR */
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
+ VkInstance instance,
+ const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateXcbSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_XCB_KHR */
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR(
+ VkInstance instance,
+ const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_WAYLAND_KHR */
+
+#ifdef VK_USE_PLATFORM_MIR_KHR
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR(
+ VkInstance instance,
+ const VkMirSurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateMirSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_MIR_KHR */
+
+#ifdef VK_USE_PLATFORM_ANDROID_KHR
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(
+ VkInstance instance,
+ const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_ANDROID_KHR */
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(
+ VkInstance instance,
+ const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateWin32SurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHX(
+ VkDevice device,
+ VkSurfaceKHR surface,
+ VkDeviceGroupPresentModeFlagsKHX* pModes)
+{
+ return vkmock::GetDeviceGroupSurfacePresentModesKHX(device, surface, pModes);
+}
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHX(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t* pRectCount,
+ VkRect2D* pRects)
+{
+ return vkmock::GetPhysicalDevicePresentRectanglesKHX(physicalDevice, surface, pRectCount, pRects);
+}
+
+#ifdef VK_USE_PLATFORM_VI_NN
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(
+ VkInstance instance,
+ const VkViSurfaceCreateInfoNN* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateViSurfaceNN(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_VI_NN */
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ VkSurfaceCapabilities2EXT* pSurfaceCapabilities)
+{
+ return vkmock::GetPhysicalDeviceSurfaceCapabilities2EXT(physicalDevice, surface, pSurfaceCapabilities);
+}
+
+#ifdef VK_USE_PLATFORM_IOS_MVK
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(
+ VkInstance instance,
+ const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateIOSSurfaceMVK(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_IOS_MVK */
+
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+
+EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(
+ VkInstance instance,
+ const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface)
+{
+ return vkmock::CreateMacOSSurfaceMVK(instance, pCreateInfo, pAllocator, pSurface);
+}
+#endif /* VK_USE_PLATFORM_MACOS_MVK */
+#ifdef WIN32
+ } // end extern "C"
+#else
+ } // end extern "C"
+#endif
+'''
+
+CUSTOM_C_INTERCEPTS = {
+'vkCreateInstance': '''
+ // TODO: If loader ver <=4 ICD must fail with VK_ERROR_INCOMPATIBLE_DRIVER for all vkCreateInstance calls with
+ // apiVersion set to > Vulkan 1.0 because the loader is still at interface version <= 4. Otherwise, the
+ // ICD should behave as normal.
+ if (loader_interface_version <= 4) {
+ return VK_ERROR_INCOMPATIBLE_DRIVER;
+ }
+ *pInstance = (VkInstance)CreateDispObjHandle();
+ // TODO: If emulating specific device caps, will need to add intelligence here
+ return VK_SUCCESS;
+''',
+'vkDestroyInstance': '''
+ // Destroy physical device
+ DestroyDispObjHandle((void*)physical_device);
+
+ DestroyDispObjHandle((void*)instance);
+''',
+'vkEnumeratePhysicalDevices': '''
+ if (pPhysicalDevices) {
+ if (!physical_device) {
+ physical_device = (VkPhysicalDevice)CreateDispObjHandle();
+ }
+ *pPhysicalDevices = physical_device;
+ } else {
+ *pPhysicalDeviceCount = 1;
+ }
+ return VK_SUCCESS;
+''',
+'vkCreateDevice': '''
+ *pDevice = (VkDevice)CreateDispObjHandle();
+ // TODO: If emulating specific device caps, will need to add intelligence here
+ return VK_SUCCESS;
+''',
+'vkDestroyDevice': '''
+ // First destroy sub-device objects
+ // Destroy Queues
+ for (auto dev_queue_map_pair : queue_map) {
+ for (auto queue_family_map_pair : queue_map[dev_queue_map_pair.first]) {
+ for (auto index_queue_pair : queue_map[dev_queue_map_pair.first][queue_family_map_pair.first]) {
+ DestroyDispObjHandle((void*)index_queue_pair.second);
+ }
+ }
+ }
+ queue_map.clear();
+ // Now destroy device
+ DestroyDispObjHandle((void*)device);
+ // TODO: If emulating specific device caps, will need to add intelligence here
+''',
+'vkGetDeviceQueue': '''
+ auto queue = queue_map[device][queueFamilyIndex][queueIndex];
+ if (queue) {
+ *pQueue = queue;
+ } else {
+ *pQueue = queue_map[device][queueFamilyIndex][queueIndex] = (VkQueue)CreateDispObjHandle();
+ }
+ // TODO: If emulating specific device caps, will need to add intelligence here
+ return;
+''',
+'vkEnumerateInstanceLayerProperties': '''
+ return VK_SUCCESS;
+''',
+'vkEnumerateDeviceLayerProperties': '''
+ return VK_SUCCESS;
+''',
+'vkEnumerateInstanceExtensionProperties': '''
+ // If requesting number of extensions, return that
+ if (!pLayerName) {
+ if (!pProperties) {
+ *pPropertyCount = instance_extension_map.size();
+ } else {
+ uint32_t i = 0;
+ for (const auto &name_ver_pair : instance_extension_map) {
+ if (i == *pPropertyCount) {
+ break;
+ }
+ std::strncpy(pProperties[i].extensionName, name_ver_pair.first.c_str(), sizeof(pProperties[i].extensionName));
+ pProperties[i].extensionName[sizeof(pProperties[i].extensionName) - 1] = 0;
+ pProperties[i].specVersion = name_ver_pair.second;
+ ++i;
+ }
+ if (i != instance_extension_map.size()) {
+ return VK_INCOMPLETE;
+ }
+ }
+ }
+ // If requesting extension properties, fill in data struct for number of extensions
+ return VK_SUCCESS;
+''',
+'vkEnumerateDeviceExtensionProperties': '''
+ // If requesting number of extensions, return that
+ if (!pLayerName) {
+ if (!pProperties) {
+ *pPropertyCount = device_extension_map.size();
+ } else {
+ uint32_t i = 0;
+ for (const auto &name_ver_pair : device_extension_map) {
+ if (i == *pPropertyCount) {
+ break;
+ }
+ std::strncpy(pProperties[i].extensionName, name_ver_pair.first.c_str(), sizeof(pProperties[i].extensionName));
+ pProperties[i].extensionName[sizeof(pProperties[i].extensionName) - 1] = 0;
+ pProperties[i].specVersion = name_ver_pair.second;
+ ++i;
+ }
+ if (i != device_extension_map.size()) {
+ return VK_INCOMPLETE;
+ }
+ }
+ }
+ // If requesting extension properties, fill in data struct for number of extensions
+ return VK_SUCCESS;
+''',
+'vkGetInstanceProcAddr': '''
+ if (!negotiate_loader_icd_interface_called) {
+ loader_interface_version = 0;
+ }
+ const auto &item = name_to_funcptr_map.find(pName);
+ if (item != name_to_funcptr_map.end()) {
+ return reinterpret_cast<PFN_vkVoidFunction>(item->second);
+ }
+ // Mock should intercept all functions so if we get here just return null
+ return nullptr;
+''',
+'vkGetDeviceProcAddr': '''
+ return GetInstanceProcAddr(nullptr, pName);
+''',
+'vkGetPhysicalDeviceMemoryProperties': '''
+ pMemoryProperties->memoryTypeCount = 2;
+ pMemoryProperties->memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ pMemoryProperties->memoryTypes[0].heapIndex = 0;
+ pMemoryProperties->memoryTypes[1].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ pMemoryProperties->memoryTypes[1].heapIndex = 1;
+ pMemoryProperties->memoryHeapCount = 2;
+ pMemoryProperties->memoryHeaps[0].flags = 0;
+ pMemoryProperties->memoryHeaps[0].size = 8000000000;
+ pMemoryProperties->memoryHeaps[1].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
+ pMemoryProperties->memoryHeaps[1].size = 8000000000;
+''',
+'vkGetPhysicalDeviceMemoryProperties2KHR': '''
+ GetPhysicalDeviceMemoryProperties(physicalDevice, &pMemoryProperties->memoryProperties);
+''',
+'vkGetPhysicalDeviceQueueFamilyProperties': '''
+ if (!pQueueFamilyProperties) {
+ *pQueueFamilyPropertyCount = 1;
+ } else {
+ if (*pQueueFamilyPropertyCount) {
+ pQueueFamilyProperties[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT;
+ pQueueFamilyProperties[0].queueCount = 1;
+ pQueueFamilyProperties[0].timestampValidBits = 0;
+ pQueueFamilyProperties[0].minImageTransferGranularity = {0,0,0};
+ }
+ }
+''',
+'vkGetPhysicalDeviceQueueFamilyProperties2KHR': '''
+ if (pQueueFamilyPropertyCount && pQueueFamilyProperties) {
+ GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, &pQueueFamilyProperties->queueFamilyProperties);
+ } else {
+ GetPhysicalDeviceQueueFamilyProperties(physicalDevice, pQueueFamilyPropertyCount, nullptr);
+ }
+''',
+'vkGetPhysicalDeviceFeatures': '''
+ uint32_t num_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
+ VkBool32 *pBool = &pFeatures->robustBufferAccess;
+ for (uint32_t i = 0; i < num_bools; ++i) {
+ pBool[i] = VK_TRUE;
+ }
+''',
+'vkGetPhysicalDeviceFeatures2KHR': '''
+ GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features);
+''',
+'vkGetPhysicalDeviceFormatProperties': '''
+ // TODO: Just returning full support for everything initially
+ *pFormatProperties = { 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF };
+''',
+'vkGetPhysicalDeviceFormatProperties2KHR': '''
+ GetPhysicalDeviceFormatProperties(physicalDevice, format, &pFormatProperties->formatProperties);
+''',
+'vkGetPhysicalDeviceImageFormatProperties': '''
+ // TODO: Just hard-coding some values for now
+ *pImageFormatProperties = { { 4096, 4096, 256 }, 12, 256, 0x7F, 4294967296 };
+ return VK_SUCCESS;
+''',
+'vkGetPhysicalDeviceImageFormatProperties2KHR': '''
+ GetPhysicalDeviceImageFormatProperties(physicalDevice, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling, pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
+ return VK_SUCCESS;
+''',
+'vkGetPhysicalDeviceProperties': '''
+ // TODO: Just hard-coding some values for now
+ pProperties->apiVersion = VK_API_VERSION_1_0;
+ pProperties->driverVersion = 1;
+ pProperties->vendorID = 0xba5eba11;
+ pProperties->deviceID = 0xf005ba11;
+ pProperties->deviceType = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU;
+ //std::string devName = "Vulkan Mock Device";
+ strcpy(pProperties->deviceName, "Vulkan Mock Device");
+ pProperties->pipelineCacheUUID[0] = 18;
+ pProperties->limits = SetLimits(&pProperties->limits);
+ pProperties->sparseProperties = { VK_TRUE, VK_TRUE, VK_TRUE, VK_TRUE, VK_TRUE };
+''',
+'vkGetPhysicalDeviceProperties2KHR': '''
+ GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties);
+''',
+'vkGetBufferMemoryRequirements': '''
+ // TODO: Just hard-coding reqs for now
+ pMemoryRequirements->size = 4096;
+ pMemoryRequirements->alignment = 1;
+ pMemoryRequirements->memoryTypeBits = 0x1F;
+''',
+'vkGetBufferMemoryRequirements2KHR': '''
+ GetBufferMemoryRequirements(device, pInfo->buffer, &pMemoryRequirements->memoryRequirements);
+''',
+'vkGetImageMemoryRequirements': '''
+ // TODO: Just hard-coding reqs for now
+ pMemoryRequirements->size = 4096;
+ pMemoryRequirements->alignment = 1;
+ pMemoryRequirements->memoryTypeBits = 0x1F;
+''',
+'vkGetImageMemoryRequirements2KHR': '''
+ GetImageMemoryRequirements(device, pInfo->image, &pMemoryRequirements->memoryRequirements);
+''',
+'vkMapMemory': '''
+ // TODO: Just hard-coding 4k whole size for now
+ if (VK_WHOLE_SIZE == size)
+ size = 4096;
+ void* map_addr = malloc(size);
+ mapped_memory_map[memory].push_back(map_addr);
+ *ppData = map_addr;
+ return VK_SUCCESS;
+''',
+'vkUnmapMemory': '''
+ for (auto map_addr : mapped_memory_map[memory]) {
+ free(map_addr);
+ }
+ mapped_memory_map.erase(memory);
+''',
+}
+
+# MockICDGeneratorOptions - subclass of GeneratorOptions.
+#
+# Adds options used by MockICDOutputGenerator objects during Mock
+# ICD generation.
+#
+# Additional members
+# prefixText - list of strings to prefix generated header with
+# (usually a copyright statement + calling convention macros).
+# protectFile - True if multiple inclusion protection should be
+# generated (based on the filename) around the entire header.
+# protectFeature - True if #ifndef..#endif protection should be
+# generated around a feature interface in the header file.
+# genFuncPointers - True if function pointer typedefs should be
+# generated
+# protectProto - If conditional protection should be generated
+# around prototype declarations, set to either '#ifdef'
+# to require opt-in (#ifdef protectProtoStr) or '#ifndef'
+# to require opt-out (#ifndef protectProtoStr). Otherwise
+# set to None.
+# protectProtoStr - #ifdef/#ifndef symbol to use around prototype
+# declarations, if protectProto is set
+# apicall - string to use for the function declaration prefix,
+# such as APICALL on Windows.
+# apientry - string to use for the calling convention macro,
+# in typedefs, such as APIENTRY.
+# apientryp - string to use for the calling convention macro
+# in function pointer typedefs, such as APIENTRYP.
+# indentFuncProto - True if prototype declarations should put each
+# parameter on a separate line
+# indentFuncPointer - True if typedefed function pointers should put each
+# parameter on a separate line
+# alignFuncParam - if nonzero and parameters are being put on a
+# separate line, align parameter names at the specified column
+class MockICDGeneratorOptions(GeneratorOptions):
+ def __init__(self,
+ filename = None,
+ directory = '.',
+ apiname = None,
+ profile = None,
+ versions = '.*',
+ emitversions = '.*',
+ defaultExtensions = None,
+ addExtensions = None,
+ removeExtensions = None,
+ sortProcedure = regSortFeatures,
+ prefixText = "",
+ genFuncPointers = True,
+ protectFile = True,
+ protectFeature = True,
+ protectProto = None,
+ protectProtoStr = None,
+ apicall = '',
+ apientry = '',
+ apientryp = '',
+ indentFuncProto = True,
+ indentFuncPointer = False,
+ alignFuncParam = 0,
+ helper_file_type = ''):
+ GeneratorOptions.__init__(self, filename, directory, apiname, profile,
+ versions, emitversions, defaultExtensions,
+ addExtensions, removeExtensions, sortProcedure)
+ self.prefixText = prefixText
+ self.genFuncPointers = genFuncPointers
+ self.protectFile = protectFile
+ self.protectFeature = protectFeature
+ self.protectProto = protectProto
+ self.protectProtoStr = protectProtoStr
+ self.apicall = apicall
+ self.apientry = apientry
+ self.apientryp = apientryp
+ self.indentFuncProto = indentFuncProto
+ self.indentFuncPointer = indentFuncPointer
+ self.alignFuncParam = alignFuncParam
+
+# MockICDOutputGenerator - subclass of OutputGenerator.
+# Generates a mock vulkan ICD.
+# This is intended to be a minimal replacement for a vulkan device in order
+# to enable Vulkan Validation testing.
+#
+# ---- methods ----
+# MockOutputGenerator(errFile, warnFile, diagFile) - args as for
+# OutputGenerator. Defines additional internal state.
+# ---- methods overriding base class ----
+# beginFile(genOpts)
+# endFile()
+# beginFeature(interface, emit)
+# endFeature()
+# genType(typeinfo,name)
+# genStruct(typeinfo,name)
+# genGroup(groupinfo,name)
+# genEnum(enuminfo, name)
+# genCmd(cmdinfo)
+class MockICDOutputGenerator(OutputGenerator):
+ """Generate specified API interfaces in a specific style, such as a C header"""
+ # This is an ordered list of sections in the header file.
+ TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum',
+ 'group', 'bitmask', 'funcpointer', 'struct']
+ ALL_SECTIONS = TYPE_SECTIONS + ['command']
+ def __init__(self,
+ errFile = sys.stderr,
+ warnFile = sys.stderr,
+ diagFile = sys.stdout):
+ OutputGenerator.__init__(self, errFile, warnFile, diagFile)
+ # Internal state - accumulators for different inner block text
+ self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+ self.intercepts = []
+
+ # Check if the parameter passed in is a pointer to an array
+ def paramIsArray(self, param):
+ return param.attrib.get('len') is not None
+
+ # Check if the parameter passed in is a pointer
+ def paramIsPointer(self, param):
+ ispointer = False
+ for elem in param:
+ if ((elem.tag is not 'type') and (elem.tail is not None)) and '*' in elem.tail:
+ ispointer = True
+ return ispointer
+
+ # Check if an object is a non-dispatchable handle
+ def isHandleTypeNonDispatchable(self, handletype):
+ handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+ if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
+ return True
+ else:
+ return False
+
+ # Check if an object is a dispatchable handle
+ def isHandleTypeDispatchable(self, handletype):
+ handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
+ if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
+ return True
+ else:
+ return False
+
+ def beginFile(self, genOpts):
+ OutputGenerator.beginFile(self, genOpts)
+ # C-specific
+ #
+ # Multiple inclusion protection & C++ namespace.
+ self.header = False
+ if (genOpts.protectFile and self.genOpts.filename and 'h' == self.genOpts.filename[-1]):
+ self.header = True
+ headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename))
+ write('#ifndef', headerSym, file=self.outFile)
+ write('#define', headerSym, '1', file=self.outFile)
+ self.newline()
+ #
+ # User-supplied prefix text, if any (list of strings)
+ if (genOpts.prefixText):
+ for s in genOpts.prefixText:
+ write(s, file=self.outFile)
+ if self.header:
+ write('#include <unordered_map>', file=self.outFile)
+ write('#include <mutex>', file=self.outFile)
+ write('#include <cstring>', file=self.outFile)
+ write('#include "vulkan/vk_icd.h"', file=self.outFile)
+ else:
+ write('#include "mock_icd.h"', file=self.outFile)
+ write('#include <string.h>', file=self.outFile)
+ write('#include <stdlib.h>', file=self.outFile)
+ write('#include <vector>', file=self.outFile)
+
+ write('namespace vkmock {', file=self.outFile)
+ if self.header:
+ self.newline()
+ write(HEADER_C_CODE, file=self.outFile)
+ # Include all of the extensions
+ # static unordered_map<void *, device_layer_data *> device_layer_data_map;
+ # typedef struct VkExtensionProperties {
+ # char extensionName[VK_MAX_EXTENSION_NAME_SIZE];
+ # uint32_t specVersion;
+ # } VkExtensionProperties;
+ device_exts = []
+ instance_exts = []
+ for ext in self.registry.tree.findall("extensions/extension"):
+ if '0' != ext[0][0].attrib['value']: # Only include implemented extensions
+ if (ext.attrib.get('type') and 'instance' == ext.attrib['type']):
+ instance_exts.append(' {"%s", %s},' % (ext.attrib['name'], ext[0][0].attrib['value']))
+ else:
+ device_exts.append(' {"%s", %s},' % (ext.attrib['name'], ext[0][0].attrib['value']))
+ write('// Map of instance extension name to version', file=self.outFile)
+ write('static const std::unordered_map<std::string, uint32_t> instance_extension_map = {', file=self.outFile)
+ write('\n'.join(instance_exts), file=self.outFile)
+ write('};', file=self.outFile)
+ write('// Map of device extension name to version', file=self.outFile)
+ write('static const std::unordered_map<std::string, uint32_t> device_extension_map = {', file=self.outFile)
+ write('\n'.join(device_exts), file=self.outFile)
+ write('};', file=self.outFile)
+
+ else:
+ self.newline()
+ write(SOURCE_CPP_PREFIX, file=self.outFile)
+
+ def endFile(self):
+ # C-specific
+ # Finish C++ namespace and multiple inclusion protection
+ self.newline()
+ if self.header:
+ # record intercepted procedures
+ write('// Map of all APIs to be intercepted by this layer', file=self.outFile)
+ write('static const std::unordered_map<std::string, void*> name_to_funcptr_map = {', file=self.outFile)
+ write('\n'.join(self.intercepts), file=self.outFile)
+ write('};\n', file=self.outFile)
+ self.newline()
+ write('} // namespace vkmock', file=self.outFile)
+ self.newline()
+ write('#endif', file=self.outFile)
+ else: # Loader-layer-interface, need to implement global interface functions
+ write(SOURCE_CPP_POSTFIX, file=self.outFile)
+ #init_commands = self.registry.tree.find("feature/require/[@comment='Device initialization']")
+ #for cmd in init_commands:
+ # cmd_name = cmd.attrib['name']
+ # write('// Found init function: %s' % (cmd_name), file=self.outFile)
+ # cmdinfo = self.registry.tree.find("commands/command/[name='%s']" % (cmd_name))
+ # write('VK_LAYER_EXPORT %s {' % (self.makeCDecls(cmdinfo.elem)[0][:-1]))
+ # Finish processing in superclass
+ OutputGenerator.endFile(self)
+ def beginFeature(self, interface, emit):
+ #write('// starting beginFeature', file=self.outFile)
+ # Start processing in superclass
+ OutputGenerator.beginFeature(self, interface, emit)
+ # C-specific
+ # Accumulate includes, defines, types, enums, function pointer typedefs,
+ # end function prototypes separately for this feature. They're only
+ # printed in endFeature().
+ self.sections = dict([(section, []) for section in self.ALL_SECTIONS])
+ #write('// ending beginFeature', file=self.outFile)
+ def endFeature(self):
+ # C-specific
+ # Actually write the interface to the output file.
+ #write('// starting endFeature', file=self.outFile)
+ if (self.emit):
+ self.newline()
+ if (self.genOpts.protectFeature):
+ write('#ifndef', self.featureName, file=self.outFile)
+ # If type declarations are needed by other features based on
+ # this one, it may be necessary to suppress the ExtraProtect,
+ # or move it below the 'for section...' loop.
+ #write('// endFeature looking at self.featureExtraProtect', file=self.outFile)
+ if (self.featureExtraProtect != None):
+ write('#ifdef', self.featureExtraProtect, file=self.outFile)
+ #write('#define', self.featureName, '1', file=self.outFile)
+ for section in self.TYPE_SECTIONS:
+ #write('// endFeature writing section'+section, file=self.outFile)
+ contents = self.sections[section]
+ if contents:
+ write('\n'.join(contents), file=self.outFile)
+ self.newline()
+ #write('// endFeature looking at self.sections[command]', file=self.outFile)
+ if (self.sections['command']):
+ write('\n'.join(self.sections['command']), end=u'', file=self.outFile)
+ self.newline()
+ if (self.featureExtraProtect != None):
+ write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile)
+ if (self.genOpts.protectFeature):
+ write('#endif /*', self.featureName, '*/', file=self.outFile)
+ # Finish processing in superclass
+ OutputGenerator.endFeature(self)
+ #write('// ending endFeature', file=self.outFile)
+ #
+ # Append a definition to the specified section
+ def appendSection(self, section, text):
+ # self.sections[section].append('SECTION: ' + section + '\n')
+ self.sections[section].append(text)
+ #
+ # Type generation
+ def genType(self, typeinfo, name):
+ pass
+ #
+ # Struct (e.g. C "struct" type) generation.
+ # This is a special case of the <type> tag where the contents are
+ # interpreted as a set of <member> tags instead of freeform C
+ # C type declarations. The <member> tags are just like <param>
+ # tags - they are a declaration of a struct or union member.
+ # Only simple member declarations are supported (no nested
+ # structs etc.)
+ def genStruct(self, typeinfo, typeName):
+ OutputGenerator.genStruct(self, typeinfo, typeName)
+ body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n'
+ # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam)
+ for member in typeinfo.elem.findall('.//member'):
+ body += self.makeCParamDecl(member, self.genOpts.alignFuncParam)
+ body += ';\n'
+ body += '} ' + typeName + ';\n'
+ self.appendSection('struct', body)
+ #
+ # Group (e.g. C "enum" type) generation.
+ # These are concatenated together with other types.
+ def genGroup(self, groupinfo, groupName):
+ pass
+ # Enumerant generation
+ # <enum> tags may specify their values in several ways, but are usually
+ # just integers.
+ def genEnum(self, enuminfo, name):
+ pass
+ #
+ # Command generation
+ def genCmd(self, cmdinfo, name):
+ decls = self.makeCDecls(cmdinfo.elem)
+ if self.header: # In the header declare all intercepts
+ self.appendSection('command', '')
+ self.appendSection('command', 'static %s' % (decls[0]))
+ if (self.featureExtraProtect != None):
+ self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
+ self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
+ if (self.featureExtraProtect != None):
+ self.intercepts += [ '#endif' ]
+ return
+
+ manual_functions = [
+ # Include functions here to be interecpted w/ manually implemented function bodies
+ 'vkGetDeviceProcAddr',
+ 'vkGetInstanceProcAddr',
+ 'vkCreateDevice',
+ 'vkDestroyDevice',
+ 'vkCreateInstance',
+ 'vkDestroyInstance',
+ #'vkCreateDebugReportCallbackEXT',
+ #'vkDestroyDebugReportCallbackEXT',
+ 'vkEnumerateInstanceLayerProperties',
+ 'vkEnumerateInstanceExtensionProperties',
+ 'vkEnumerateDeviceLayerProperties',
+ 'vkEnumerateDeviceExtensionProperties',
+ ]
+ if name in manual_functions:
+ self.appendSection('command', '')
+ if name not in CUSTOM_C_INTERCEPTS:
+ self.appendSection('command', '// declare only')
+ self.appendSection('command', 'static %s' % (decls[0]))
+ self.appendSection('command', '// TODO: Implement custom intercept body')
+ else:
+ self.appendSection('command', 'static %s' % (decls[0][:-1]))
+ self.appendSection('command', '{\n%s}' % (CUSTOM_C_INTERCEPTS[name]))
+ self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
+ return
+ # record that the function will be intercepted
+ if (self.featureExtraProtect != None):
+ self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ]
+ self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ]
+ if (self.featureExtraProtect != None):
+ self.intercepts += [ '#endif' ]
+
+ OutputGenerator.genCmd(self, cmdinfo, name)
+ #
+ self.appendSection('command', '')
+ self.appendSection('command', 'static %s' % (decls[0][:-1]))
+ if name in CUSTOM_C_INTERCEPTS:
+ self.appendSection('command', '{%s}' % (CUSTOM_C_INTERCEPTS[name]))
+ return
+ self.appendSection('command', '{')
+ # setup common to call wrappers
+ # first parameter is always dispatchable
+ dispatchable_type = cmdinfo.elem.find('param/type').text
+ #dispatchable_name = cmdinfo.elem.find('param/name').text
+ # Default to device
+ device_or_instance = 'device'
+ #dispatch_table_name = 'VkLayerDispatchTable'
+ # Set to instance as necessary
+ #if dispatchable_type in ["VkPhysicalDevice", "VkInstance"]:
+ #device_or_instance = 'instance'
+ #dispatch_table_name = 'VkLayerInstanceDispatchTable'
+ #self.appendSection('command', ' %s_layer_data *%s_data = GetLayerDataPtr(get_dispatch_key(%s), %s_layer_data_map);' % (device_or_instance, device_or_instance, dispatchable_name, device_or_instance))
+ api_function_name = cmdinfo.elem.attrib.get('name')
+ params = cmdinfo.elem.findall('param/name')
+ paramstext = ', '.join([str(param.text) for param in params])
+ # GET THE TYPE OF FUNCTION
+ if True in [ftxt in api_function_name for ftxt in ['Create', 'Allocate']]:
+ #self.appendSection('command', ' //Add object generation here for last param')
+ # Get last param
+ last_param = cmdinfo.elem.findall('param')[-1]
+ lp_txt = last_param.find('name').text
+ lp_len = None
+ if ('len' in last_param.attrib):
+ lp_len = last_param.attrib['len']
+ lp_len = lp_len.replace('::', '->')
+ lp_type = last_param.find('type').text
+ handle_type = 'dispatchable'
+ allocator_txt = 'CreateDispObjHandle()';
+ if (self.isHandleTypeNonDispatchable(lp_type)):
+ handle_type = 'non-' + handle_type
+ allocator_txt = 'global_unique_handle++';
+ # Need to lock in both cases
+ self.appendSection('command', ' unique_lock_t lock(global_lock);')
+ if (lp_len != None):
+ print("%s last params (%s) has len %s" % (handle_type, lp_txt, lp_len))
+ self.appendSection('command', ' for (uint32_t i = 0; i < %s; ++i) {' % (lp_len))
+ self.appendSection('command', ' %s[i] = (%s)%s;' % (lp_txt, lp_type, allocator_txt))
+ self.appendSection('command', ' }')
+ else:
+ print("Single %s last param is '%s' w/ type '%s'" % (handle_type, lp_txt, lp_type))
+ self.appendSection('command', ' *%s = (%s)%s;' % (lp_txt, lp_type, allocator_txt))
+ # If las param has a len, then we need to loop over that len
+ # Add unique ID to return value and increment
+
+ elif True in [ftxt in api_function_name for ftxt in ['Destroy', 'Free']]:
+ self.appendSection('command', '//Destroy object')
+ else:
+ self.appendSection('command', '//Not a CREATE or DESTROY function')
+ # GENERATE BODY CODE APPROPRIATELY
+ #API = api_function_name.replace('vk','%s_data->dispatch_table.' % (device_or_instance),1)
+ #self.appendSection('command', ' PreCall%s(%s_data, %s);' % (api_function_name[2:], device_or_instance, paramstext))
+ # Declare result variable, if any.
+ resulttype = cmdinfo.elem.find('proto/type')
+ if (resulttype != None and resulttype.text == 'void'):
+ resulttype = None
+ if (resulttype != None):
+ assignresult = resulttype.text + ' result = '
+ else:
+ assignresult = ''
+
+ #self.appendSection('command', ' ' + assignresult + API + '(' + paramstext + ');')
+ #self.appendSection('command', ' PostCall%s(%s_data, %s);' % (api_function_name[2:], device_or_instance, paramstext))
+ # Return result variable, if any.
+ if (resulttype != None):
+ self.appendSection('command', ' return VK_SUCCESS;')
+ self.appendSection('command', '}')
+ #
+ # override makeProtoName to drop the "vk" prefix
+ def makeProtoName(self, name, tail):
+ return self.genOpts.apientry + name[2:] + tail