aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordan sinclair <dj2@everburning.com>2019-03-05 11:07:37 -0500
committerGitHub <noreply@github.com>2019-03-05 11:07:37 -0500
commit0242b3c38c2bdf3fb56b0f2c3b6c048899e9ea50 (patch)
tree2f4da403e93e8bd33680291ff52d93c1a5be7d33
parent4c4017d29dddd40433b5865aa391e212ffe741d6 (diff)
downloadamber-0242b3c38c2bdf3fb56b0f2c3b6c048899e9ea50.tar.gz
[vulkan] Generate wrapper functions for vulkan methods. (#328)
This CL adds a update_vk_wrappers.py script which is executed during the build. The script will generate src/vk-wrappers.h and src/vk-wrappers.inc files into the binary directory. The .h file lists the struct entries for the VulkanPtr struct. The vk-wrappers.inc file contains the code to load the vulkan function pointers. If the vk.xml file is found, the wrappers will be lambdas, if vk.xml is not found they're straight function pointers. This should allow us to work with the CTS as we do now. Issue #324.
-rw-r--r--.gitignore1
-rw-r--r--DEPS4
-rw-r--r--kokoro/ndk-build/build.sh1
-rw-r--r--samples/CMakeLists.txt8
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/vulkan/CMakeLists.txt13
-rw-r--r--src/vulkan/device.cc8
-rw-r--r--src/vulkan/device.h5
-rwxr-xr-xtools/update_vk_wrappers.py189
9 files changed, 216 insertions, 14 deletions
diff --git a/.gitignore b/.gitignore
index c81c3cf..6398fa9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ third_party/lodepng
third_party/shaderc
third_party/spirv-tools
third_party/spirv-headers
+third_party/vulkan-headers
.vs
# Vim swap files
diff --git a/DEPS b/DEPS
index 097c94f..026dbae 100644
--- a/DEPS
+++ b/DEPS
@@ -12,6 +12,7 @@ vars = {
'shaderc_revision': '53c776f776821bc037b31b8b3b79db2fa54b4ce7',
'spirv_headers_revision': '8bea0a266ac9b718aa0818d9e3a47c0b77c2cb23',
'spirv_tools_revision': '39bfb6b978e937487a9cedfd964d61a3ac4384b8',
+ 'vulkan_headers_revision': '8e2c4cd554b644592a6d904f2c8000ebbd4aa77f',
}
deps = {
@@ -35,4 +36,7 @@ deps = {
'third_party/spirv-tools': vars['khronos_git'] + '/SPIRV-Tools.git@' +
vars['spirv_tools_revision'],
+
+ 'third_party/vulkan-headers': vars['khronos_git'] + '/Vulkan-Headers.git@' +
+ vars['vulkan_headers_revision'],
}
diff --git a/kokoro/ndk-build/build.sh b/kokoro/ndk-build/build.sh
index 06defe6..6d6bdc9 100644
--- a/kokoro/ndk-build/build.sh
+++ b/kokoro/ndk-build/build.sh
@@ -30,6 +30,7 @@ export PATH="$PWD:$PATH"
cd $SRC
./tools/git-sync-deps
./tools/update_build_version.py . samples/ third_party/
+./tools/update_vk_wrappers.py . .
mkdir -p build/libs build/app
cd $SRC/build
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index 77e1da7..33e3517 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -44,7 +44,7 @@ if (${Dawn_FOUND})
endif()
add_executable(amber ${AMBER_SOURCES})
-target_include_directories(amber PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/..")
+target_include_directories(amber PRIVATE "${CMAKE_BINARY_DIR}")
set_target_properties(amber PROPERTIES OUTPUT_NAME "amber")
target_link_libraries(amber libamber ${AMBER_EXTRA_LIBS})
@@ -52,10 +52,10 @@ add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/src/build-versions.h.fake
COMMAND
${PYTHON_EXE}
- ${CMAKE_CURRENT_SOURCE_DIR}/../tools/update_build_version.py
+ ${PROJECT_SOURCE_DIR}/tools/update_build_version.py
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/../third_party
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.."
+ ${PROJECT_SOURCE_DIR}/third_party
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
COMMENT "Update build-versions.h in the build directory"
)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index db63393..ae9fa76 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -51,6 +51,7 @@ endif()
add_library(libamber ${AMBER_SOURCES})
amber_default_compile_options(libamber)
+target_include_directories(libamber PRIVATE "${CMAKE_BINARY_DIR}")
set_target_properties(libamber PROPERTIES OUTPUT_NAME "amber")
if (${AMBER_ENABLE_SPIRV_TOOLS})
diff --git a/src/vulkan/CMakeLists.txt b/src/vulkan/CMakeLists.txt
index 93cd639..9654ca6 100644
--- a/src/vulkan/CMakeLists.txt
+++ b/src/vulkan/CMakeLists.txt
@@ -30,10 +30,12 @@ set(VULKAN_ENGINE_SOURCES
push_constant.cc
resource.cc
vertex_buffer.cc
+ ${CMAKE_BINARY_DIR}/src/vk-wrappers.inc.fake
)
add_library(libamberenginevulkan ${VULKAN_ENGINE_SOURCES})
amber_default_compile_options(libamberenginevulkan)
+target_include_directories(libamberenginevulkan PRIVATE "${CMAKE_BINARY_DIR}")
set_target_properties(libamberenginevulkan PROPERTIES
OUTPUT_NAME "amberenginevulkan"
)
@@ -47,3 +49,14 @@ if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
# with XCode 10.
target_compile_options(libamberenginevulkan PRIVATE -Wno-zero-as-null-pointer-constant)
endif()
+
+add_custom_command(
+ OUTPUT ${CMAKE_BINARY_DIR}/src/vk-wrappers.inc.fake
+ COMMAND
+ ${PYTHON_EXE}
+ ${PROJECT_SOURCE_DIR}/tools/update_vk_wrappers.py
+ ${CMAKE_BINARY_DIR}
+ ${PROJECT_SOURCE_DIR}
+ WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
+ COMMENT "Update vk-wrapper files in the build directory"
+)
diff --git a/src/vulkan/device.cc b/src/vulkan/device.cc
index 92191fa..89d1948 100644
--- a/src/vulkan/device.cc
+++ b/src/vulkan/device.cc
@@ -356,13 +356,7 @@ Device::~Device() = default;
Result Device::LoadVulkanPointers(
PFN_vkGetInstanceProcAddr getInstanceProcAddr) {
-#define AMBER_VK_FUNC(func) \
- if (!(ptrs_.func = reinterpret_cast<PFN_##func>( \
- getInstanceProcAddr(instance_, #func)))) { \
- return Result("Vulkan: Unable to load " #func " pointer"); \
- }
-#include "src/vulkan/vk-funcs.inc"
-#undef AMBER_VK_FUNC
+#include "src/vk-wrappers.inc"
return {};
}
diff --git a/src/vulkan/device.h b/src/vulkan/device.h
index 2a9d263..36df393 100644
--- a/src/vulkan/device.h
+++ b/src/vulkan/device.h
@@ -15,6 +15,7 @@
#ifndef SRC_VULKAN_DEVICE_H_
#define SRC_VULKAN_DEVICE_H_
+#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -26,9 +27,7 @@ namespace amber {
namespace vulkan {
struct VulkanPtrs {
-#define AMBER_VK_FUNC(func) PFN_##func func;
-#include "src/vulkan/vk-funcs.inc"
-#undef AMBER_VK_FUNC
+#include "src/vk-wrappers.h"
};
class Device {
diff --git a/tools/update_vk_wrappers.py b/tools/update_vk_wrappers.py
new file mode 100755
index 0000000..15ffb02
--- /dev/null
+++ b/tools/update_vk_wrappers.py
@@ -0,0 +1,189 @@
+#!/usr/bin/env python
+
+# Copyright 2019 The Amber Authors. All rights reserved.
+#
+# 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.
+
+# Generates vk-wrappers.inc in the src/ directory.
+
+from __future__ import print_function
+
+import os.path
+import re
+import sys
+import xml.etree.ElementTree as ET
+
+
+def read_inc(file):
+ methods = []
+ pattern = re.compile(r"AMBER_VK_FUNC\((\w+)\)")
+ with open(file, 'r') as f:
+ for line in f:
+ match = pattern.search(line)
+ if match == None:
+ raise Exception("FAILED TO MATCH PATTERN");
+
+ methods.append(match.group(1))
+ return methods
+
+
+def read_vk(file):
+ methods = {}
+ tree = ET.parse(file)
+ root = tree.getroot();
+ for command in root.iter("command"):
+ proto = command.find('proto')
+ if proto == None:
+ continue
+
+ return_type = proto.find('type').text
+ name = proto.find('name').text
+
+ param_list = []
+ for param in command.findall('param'):
+ param_val = "".join(param.itertext())
+ param_name = param.find('name').text
+ param_list.append({
+ 'def': param_val,
+ 'name': param_name
+ })
+
+ methods[name] = {
+ 'return_type': return_type,
+ 'name': name,
+ 'params': param_list
+ }
+
+ return methods
+
+def gen_wrappers(methods, xml):
+ content = ""
+ for method in methods:
+ data = xml[method]
+ if data == None:
+ raise Exception("Failed to find {}".format(method))
+
+ param_vals = []
+ param_names = []
+ for param in data['params']:
+ param_vals.append(param['def'])
+ param_names.append(param['name'])
+
+ content += "{\n"
+ content += " PFN_{} ptr = reinterpret_cast<PFN_{}>(".format(method, method)
+ content += "getInstanceProcAddr(instance_, \"{}\"));\n".format(method);
+ content += " if (!ptr) {\n"
+ content += " return Result(\"Vulkan: Unable to "
+ content += "load {} pointer\");\n".format(method)
+ content += " }\n"
+ content += " ptrs_.{} = [ptr](".format(method)
+ content += ', '.join(str(x) for x in param_vals)
+ content += ") -> " + data['return_type'] + " {\n"
+
+ if data['return_type'] != 'void':
+ content += " {} ret = ".format(data['return_type'])
+ content += " ptr(" + ", ".join(str(x) for x in param_names) + ");\n"
+
+ content += " return";
+ if data['return_type'] != 'void':
+ content += " ret"
+ content += ";\n"
+
+ content += "};\n"
+ content += "}\n"
+
+ return content
+
+
+def gen_headers(methods, xml):
+ content = ""
+ for method in methods:
+ data = xml[method]
+ if data == None:
+ raise Exception("Failed to find {}".format(method))
+
+ param_vals = []
+ param_names = []
+ for param in data['params']:
+ param_vals.append(param['def'])
+ param_names.append(param['name'])
+
+ content += "std::function<{}({})> {};\n".format(data['return_type'],
+ ', '.join(str(x) for x in param_vals), method)
+
+ return content
+
+
+def gen_direct(methods):
+ content = "";
+ for method in methods:
+ content += "if (!(ptrs_.{} = reinterpret_cast<PFN_{}>(".format(method, method)
+ content += "getInstanceProcAddr(instance_, \"{}\"))))".format(method)
+ content += " {\n"
+ content += " return Result(\"Vulkan: Unable to load {} pointer\");\n".format(method)
+ content += "}\n"
+
+ return content
+
+
+def gen_direct_headers(methods):
+ content = ""
+ for method in methods:
+ content += "PFN_{} {};\n".format(method, method);
+
+ return content
+
+
+def main():
+ if len(sys.argv) != 3:
+ print('usage: {} <outdir> <src_dir>'.format(
+ sys.argv[0]))
+ sys.exit(1)
+
+ outdir = sys.argv[1]
+ srcdir = sys.argv[2]
+
+ vkfile = os.path.join(srcdir, 'third_party', 'vulkan-headers', 'registry', 'vk.xml')
+ incfile = os.path.join(srcdir, 'src', 'vulkan', 'vk-funcs.inc')
+
+ data = read_inc(incfile)
+
+ wrapper_content = ''
+ header_content = ''
+ if os.path.isfile(vkfile):
+ vk_data = read_vk(vkfile)
+ wrapper_content = gen_wrappers(data, vk_data)
+ header_content = gen_headers(data, vk_data)
+ else:
+ wrapper_content = gen_direct(data)
+ header_content = gen_direct_headers(data)
+
+ outfile = os.path.join(outdir, 'src', 'vk-wrappers.inc')
+ if os.path.isfile(outfile):
+ with open(outfile, 'r') as f:
+ if wrapper_content == f.read():
+ return
+ with open(outfile, 'w') as f:
+ f.write(wrapper_content)
+
+ hdrfile = os.path.join(outdir, 'src', 'vk-wrappers.h')
+ if os.path.isfile(hdrfile):
+ with open(hdrfile, 'r') as f:
+ if header_content == f.read():
+ return
+ with open(hdrfile, 'w') as f:
+ f.write(header_content)
+
+
+if __name__ == '__main__':
+ main()