icd: Adding generated mock icd
authorTobin Ehlis <tobine@google.com>
Fri, 13 Oct 2017 15:26:20 +0000 (09:26 -0600)
committerTobin Ehlis <tobine@google.com>
Mon, 30 Oct 2017 17:01:05 +0000 (11:01 -0600)
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.

CMakeLists.txt
README.md
icd/CMakeLists.txt [new file with mode: 0644]
icd/README.md [new file with mode: 0644]
icd/VkICD_mock_icd.json [new file with mode: 0644]
scripts/lvl_genvk.py
scripts/mock_icd_generator.py [new file with mode: 0644]

index ba1a0c6..0d3b157 100644 (file)
@@ -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()
index 5a834df..e678e68 100644 (file)
--- 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/icd/CMakeLists.txt b/icd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6216268
--- /dev/null
@@ -0,0 +1,173 @@
+cmake_minimum_required (VERSION 2.8.11)
+if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+    add_definitions(-DVK_USE_PLATFORM_WIN32_KHR -DVK_USE_PLATFORM_WIN32_KHX -DWIN32_LEAN_AND_MEAN)
+    set(DisplayServer Win32)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
+    add_definitions(-DVK_USE_PLATFORM_ANDROID_KHR -DVK_USE_PLATFORM_ANDROID_KHX)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    if (BUILD_WSI_XCB_SUPPORT)
+        add_definitions(-DVK_USE_PLATFORM_XCB_KHR -DVK_USE_PLATFORM_XCB_KHX)
+    endif()
+
+    if (BUILD_WSI_XLIB_SUPPORT)
+       add_definitions(-DVK_USE_PLATFORM_XLIB_KHR -DVK_USE_PLATFORM_XLIB_KHX -DVK_USE_PLATFORM_XLIB_XRANDR_EXT)
+    endif()
+
+    if (BUILD_WSI_WAYLAND_SUPPORT)
+       add_definitions(-DVK_USE_PLATFORM_WAYLAND_KHR -DVK_USE_PLATFORM_WAYLAND_KHX)
+    endif()
+
+    if (BUILD_WSI_MIR_SUPPORT)
+        add_definitions(-DVK_USE_PLATFORM_MIR_KHR -DVK_USE_PLATFORM_MIR_KHX)
+        include_directories(${MIR_INCLUDE_DIR})
+    endif()
+else()
+    message(FATAL_ERROR "Unsupported Platform!")
+endif()
+
+set(ICD_JSON_FILES VkICD_mock_icd)
+
+if (WIN32)
+    if (NOT (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR))
+        if (CMAKE_GENERATOR MATCHES "^Visual Studio.*")
+            foreach (config_file ${ICD_JSON_FILES})
+                FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${config_file}.json src_json)
+                FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>/${config_file}.json dst_json)
+                add_custom_target(${config_file}-json ALL
+                    COMMAND copy ${src_json} ${dst_json}
+                    VERBATIM
+                    )
+            endforeach(config_file)
+        else()
+            foreach (config_file ${ICD_JSON_FILES})
+                FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${config_file}.json src_json)
+                FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${config_file}.json dst_json)
+                add_custom_target(${config_file}-json ALL
+                    COMMAND copy ${src_json} ${dst_json}
+                    VERBATIM
+                    )
+            endforeach(config_file)
+        endif()
+    endif()
+else()
+    # extra setup for out-of-tree builds
+    if (NOT (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR))
+        foreach (config_file ${ICD_JSON_FILES})
+            add_custom_target(${config_file}-json ALL
+                COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/${config_file}.json
+                VERBATIM
+                )
+        endforeach(config_file)
+    endif()
+endif()
+# For ICD with a direct dependency on a project with the same name, use it.
+foreach (config_file ${ICD_JSON_FILES})
+    add_dependencies(${config_file}-json ${config_file})
+endforeach(config_file)
+
+add_custom_target(generate_icd_files DEPENDS
+    mock_icd.h
+    mock_icd.cpp
+    )
+
+# Add targets for JSON file install on Linux.
+# Need to remove the "./" from the library path before installing to /etc.
+if(UNIX)
+    if(INSTALL_LVL_FILES)
+        foreach (config_file ${ICD_JSON_FILES})
+            add_custom_target(${config_file}-staging-json ALL
+                COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/staging-json
+                COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${config_file}.json ${CMAKE_CURRENT_BINARY_DIR}/staging-json
+                COMMAND sed -i -e "/\"library_path\":/s$./libVkICD$libVkICD$" ${CMAKE_CURRENT_BINARY_DIR}/staging-json/${config_file}.json
+                VERBATIM
+                DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${config_file}.json
+                )
+            install(FILES ${CMAKE_CURRENT_BINARY_DIR}/staging-json/${config_file}.json DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/vulkan/icd.d)
+        endforeach(config_file)
+    endif()
+endif()
+
+if (WIN32)
+    macro(add_vk_icd target)
+    FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/VkICD_${target}.def DEF_FILE)
+    add_custom_target(copy-${target}-def-file ALL
+        COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DEF_FILE} VkICD_${target}.def
+        VERBATIM
+    )
+    add_library(VkICD_${target} SHARED ${ARGN} VkICD_${target}.def)
+    add_dependencies(VkICD_${target} generate_icd_files)
+    #target_link_Libraries(VkICD_${target} VkICD_utils)
+    #add_dependencies(VkICD_${target} generate_helper_files VkICD_utils)
+    endmacro()
+else()
+    macro(add_vk_icd target)
+    add_library(VkICD_${target} SHARED ${ARGN})
+    #target_link_Libraries(VkICD_${target} VkICD_utils)
+    add_dependencies(VkICD_${target} generate_icd_files)
+    set_target_properties(VkICD_${target} PROPERTIES LINK_FLAGS "-Wl,-export-dynamic,-Bsymbolic,--exclude-libs,ALL")
+    if(INSTALL_ICD_FILES)
+        install(TARGETS VkICD_${target} DESTINATION ${CMAKE_INSTALL_LIBDIR})
+    endif()
+    endmacro()
+endif()
+
+include_directories(
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../loader
+    ${CMAKE_CURRENT_SOURCE_DIR}/../include/vulkan
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_PROJECT_BINARY_DIR}
+    ${CMAKE_BINARY_DIR}
+)
+
+if (WIN32)
+    set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -D_CRT_SECURE_NO_WARNINGS")
+    set (CMAKE_C_FLAGS_RELEASE   "${CMAKE_C_FLAGS_RELEASE} -D_CRT_SECURE_NO_WARNINGS")
+    set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_CRT_SECURE_NO_WARNINGS")
+    set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_CRT_SECURE_NO_WARNINGS")
+    set (CMAKE_CXX_FLAGS_DEBUG   "${CMAKE_CXX_FLAGS_DEBUG} -D_CRT_SECURE_NO_WARNINGS /bigobj")
+    set (CMAKE_C_FLAGS_DEBUG     "${CMAKE_C_FLAGS_DEBUG} -D_CRT_SECURE_NO_WARNINGS /bigobj")
+    # Turn off transitional "changed behavior" warning message for Visual Studio versions prior to 2015.
+    # The changed behavior is that constructor initializers are now fixed to clear the struct members.
+    add_compile_options("$<$<AND:$<CXX_COMPILER_ID:MSVC>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,19>>:/wd4351>")
+else()
+    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpointer-arith -Wno-unused-function -Wno-sign-compare")
+    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith -Wno-unused-function -Wno-sign-compare")
+endif()
+
+if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips64")
+    if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
+        set_source_files_properties(mock_icd.cpp PROPERTIES COMPILE_FLAGS -mxgot)
+    endif()
+endif()
+
+run_vk_xml_generate(mock_icd_generator.py mock_icd.h)
+run_vk_xml_generate(mock_icd_generator.py mock_icd.cpp)
+
+# Layer Utils Library
+# For Windows, we use a static lib because the Windows loader has a fairly restrictive loader search
+# path that can't be easily modified to point it to the same directory that contains the layers.
+#if (WIN32)
+#    add_library(VkLayer_utils STATIC vk_layer_config.cpp vk_layer_extension_utils.cpp vk_layer_utils.cpp vk_format_utils.cpp)
+#else()
+#    add_library(VkLayer_utils SHARED vk_layer_config.cpp vk_layer_extension_utils.cpp vk_layer_utils.cpp vk_format_utils.cpp)
+#    if(INSTALL_LVL_FILES)
+#        install(TARGETS VkLayer_utils DESTINATION ${CMAKE_INSTALL_LIBDIR})
+#    endif()
+#endif()
+#add_dependencies(VkLayer_utils generate_helper_files)
+
+#add_vk_layer(core_validation core_validation.cpp vk_layer_table.cpp descriptor_sets.cpp buffer_validation.cpp shader_validation.cpp)
+#add_vk_layer(object_tracker object_tracker.cpp object_tracker_utils.cpp vk_layer_table.cpp)
+# generated
+#add_vk_layer(threading threading.cpp thread_check.h vk_layer_table.cpp)
+#add_vk_layer(unique_objects unique_objects.cpp unique_objects_wrappers.h vk_layer_table.cpp)
+#add_vk_layer(parameter_validation parameter_validation.cpp parameter_validation_utils.cpp parameter_validation.h vk_layer_table.cpp vk_validation_error_messages.h)
+#add_vk_layer(mock_layer mock_layer.cpp mock_layer.h vk_layer_table.cpp)
+
+add_vk_icd(mock_icd mock_icd.cpp mock_icd.h)
+
+# Core validation has additional dependencies
+#target_include_directories(VkLayer_core_validation PRIVATE ${GLSLANG_SPIRV_INCLUDE_DIR})
+#target_include_directories(VkLayer_core_validation PRIVATE ${SPIRV_TOOLS_INCLUDE_DIR})
+#target_link_libraries(VkLayer_core_validation ${SPIRV_TOOLS_LIBRARIES})
diff --git a/icd/README.md b/icd/README.md
new file mode 100644 (file)
index 0000000..7504228
--- /dev/null
@@ -0,0 +1,113 @@
+# Vulkan Mock ICD
+
+This directory contains a mock ICD driver designed for validation layer testing.
+
+## Introduction
+
+The mock ICD is focused on enabling validation testing apart from an actual device. Because the validation layers
+sit on top of the ICD and don't depend upon the results of Vulkan rendering, they can be tested without having actual
+GPU hardware backing the ICD. The final mock driver will be composed of three main features: a null driver, flexible
+device configuration, and entrypoint tracking & verification.
+
+### Null Driver
+The intial mock driver features just the null driver capability. This allows all of the validation tests to be run
+on a fixed device configuration that is hard-coded into the ICD.
+
+### Device Configuration
+Device configuration can be added by running the DevSim layer below the validation layers, but above the mock driver.
+The current plan is that if device customization beyond DevSim's capabilities are required for validation layer testing
+then the DevSim layer will be enhanced with the required features. The mock layer itself is just planned to have some
+hard-coded device settings that will enable it to run all of the validation tests.
+
+### Entrypoint Tracking & Verification
+Entrypoint tracking and verification will be added to the mock layer as a later feature. The idea is that all expected
+Vulkan function calls and their parameters can be stored in the ICD and then a separate call can be made to verify that
+the exepected calls and parameters actually entered the ICD. This allows verification that the validation layers are
+correctly passing calls and their parameters through to the ICD unchanged.
+
+## Using the Mock ICD
+
+To enable the mock ICD, set VK\_ICD\_FILENAMES environment variable to point to your {BUILD_DIR}/icd/VkICD\_mock\_icd.json.
+
+## Plans
+
+The initial mock ICD is just the null driver which can be used in combination with DevSim to test validation layers on
+simulated devices. Here's a rough sequence of tasks planned for the mock driver going forward:
+- Get all LVL tests passing on the bare null driver
+ - Get failing tests passing
+ - Get skipped tests passing as able
+- Get all LVL tests to run without unexpected errors
+- Develop automated test flow using mock ICD (alternative to or replacement for run\_all\_tests.sh)
+- Get all LVL tests to pass on a selection of device profiles using DevSim layer
+- Update LVL tests with device dependencies to target specific device profiles
+- Add entrypoint tracking & verification
+ - Initially track expected calls
+ - Update some tests to verify expected capability
+ - Expand tracking to include parameters
+
+## Beyond Validation Layer Testing
+
+The focus of the mock icd is for validation testing, but the code is available to use and enhance for anyone wishing to apply it for alternative
+purposes.
+With the following enhancements, the mock driver state available to the app should very closely mimic an actual ICD:
+- Update various function return codes
+- Simulated synchronization objects
+- Simulated query with mock data
+- Basic command buffer state tracking to note synch object transitions and query state updates
+
+Beyond that it's certainly possible that the mock icd could be hooked up to a SW renderer and serve as a virtual GPU with complete rendering/compute
+capabilities.
+
+## Status
+
+This is a temporary section used for tracking as the mock icd is being developed. Once all tests are passing with the mock, this section can be removed.
+Currently 324/332 tests are passing with the mock icd, but many passing tests have unexpected validation errors that need to be cleaned up.
+
+### Failing Tests
+
+VkLayerTest.InvalidBarriers
+VkLayerTest.ImageFormatLimits
+VkLayerTest.CopyImageTypeExtentMismatch
+VkLayerTest.CopyImageCompressedBlockAlignment
+VkLayerTest.CopyImageSrcSizeExceeded
+VkLayerTest.CopyImageDstSizeExceeded
+VkPositiveLayerTest.UncompressedToCompressedImageCopy
+VkPositiveLayerTest.EmptyDescriptorUpdateTest
+
+### Passing Tests With Unexpected Errors
+
+VkLayerTest.InvalidUsageBits
+VkLayerTest.ImageSampleCounts
+VkLayerTest.InvalidCmdBufferBufferDestroyed
+VkLayerTest.RenderPassInUseDestroyedSignaled
+VkLayerTest.BufferMemoryNotBound
+VkLayerTest.InvalidCmdBufferDescriptorSetBufferDestroyed
+VkLayerTest.DSUsageBitsErrors
+VkLayerTest.DSBufferInfoErrors
+VkLayerTest.DSBufferLimitErrors
+VkLayerTest.RenderPassIncompatible
+VkLayerTest.InvalidImageLayout
+VkLayerTest.CopyImageLayerCountMismatch
+VkLayerTest.MiscImageLayerTests
+VkLayerTest.CopyImageTypeExtentMismatchMaintenance1
+VkLayerTest.CopyImageFormatSizeMismatch
+VkLayerTest.CopyImageDepthStencilFormatMismatch
+VkLayerTest.CopyImageAspectMismatch
+
+
+### Skipped Tests
+
+VkLayerTest.BindImageInvalidMemoryType
+VkLayerTest.CreatePipelineBadVertexAttributeFormat
+VkLayerTest.MiscBlitImageTests
+VkLayerTest.TemporaryExternalSemaphore
+VkLayerTest.TemporaryExternalFence
+VkLayerTest.InvalidDynamicOffsetCases
+VkLayerTest.PSOViewportScissorCountTests
+VkLayerTest.ImageBufferCopyTests
+VkLayerTest.CommandQueueFlags
+VkPositiveLayerTest.TwoQueuesEnsureCorrectRetirementWithWorkStolen
+VkPositiveLayerTest.ExternalSemaphore
+VkPositiveLayerTest.ExternalFence
+
+
diff --git a/icd/VkICD_mock_icd.json b/icd/VkICD_mock_icd.json
new file mode 100644 (file)
index 0000000..88876d0
--- /dev/null
@@ -0,0 +1,12 @@
+{
+    "file_format_version" : "1.0.1",
+    "ICD": {
+        "library_path": "./libVkICD_mock_icd.so",
+        "api_version": "1.0.63"
+    }
+}
+
+
+
+
+
index 194106e..09554db 100644 (file)
@@ -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 (file)
index 0000000..e351d70
--- /dev/null
@@ -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