Merge remote-tracking branch 'aosp/upstream-master' into 20180302-merge-android_layers_to_master

Change-Id: I5b213c9c6e83929a921f9f2bae17a98d294745d2
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..e95bc5d
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,4 @@
+subdirs = [
+    "libs/cjson",
+    "libs/vkjson",
+]
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..c948812
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,2 @@
+# Leave this Android.mk empty, deleting it unmasks
+# invalid Android.mks in subdirectories.
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..3c65815
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,170 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as 
+defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner 
+that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that 
+control, are controlled by, or are under common control with that entity. For the 
+purposes of this definition, "control" means (i) the power, direct or indirect, to 
+cause the direction or management of such entity, whether by contract or otherwise, 
+or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or 
+(iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions 
+granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not 
+limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or 
+translation of a Source form, including but not limited to compiled object code, 
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made 
+available under the License, as indicated by a copyright notice that is included in or 
+attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based 
+on (or derived from) the Work and for which the editorial revisions, annotations, 
+elaborations, or other modifications represent, as a whole, an original work of 
+authorship. For the purposes of this License, Derivative Works shall not include works 
+that remain separable from, or merely link (or bind by name) to the interfaces of, the 
+Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the 
+Work and any modifications or additions to that Work or Derivative Works thereof, that 
+is intentionally submitted to Licensor for inclusion in the Work by the copyright owner 
+or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. 
+For the purposes of this definition, "submitted" means any form of electronic, verbal, 
+or written communication sent to the Licensor or its representatives, including but not 
+limited to communication on electronic mailing lists, source code control systems, and 
+issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose 
+of discussing and improving the Work, but excluding communication that is conspicuously 
+marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a 
+Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each 
+Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 
+royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, 
+publicly display, publicly perform, sublicense, and distribute the Work and such 
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each 
+Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 
+royalty-free, irrevocable (except as stated in this section) patent license to make, 
+have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such 
+license applies only to those patent claims licensable by such Contributor that are 
+necessarily infringed by their Contribution(s) alone or by combination of their 
+Contribution(s) with the Work to which such Contribution(s) was submitted. If You 
+institute patent litigation against any entity (including a cross-claim or counterclaim 
+in a lawsuit) alleging that the Work or a Contribution incorporated within the Work 
+constitutes direct or contributory patent infringement, then any patent licenses granted 
+to You under this License for that Work shall terminate as of the date such litigation 
+is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative 
+Works thereof in any medium, with or without modifications, and in Source or Object form, 
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of this 
+License; and
+You must cause any modified files to carry prominent notices stating that You changed 
+the files; and
+You must retain, in the Source form of any Derivative Works that You distribute, all 
+copyright, patent, trademark, and attribution notices from the Source form of the Work, 
+excluding those notices that do not pertain to any part of the Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any 
+Derivative Works that You distribute must include a readable copy of the attribution 
+notices contained within such NOTICE file, excluding those notices that do not pertain 
+to any part of the Derivative Works, in at least one of the following places: within a 
+NOTICE text file distributed as part of the Derivative Works; within the Source form or 
+documentation, if provided along with the Derivative Works; or, within a display 
+generated by the Derivative Works, if and wherever such third-party notices normally 
+appear. The contents of the NOTICE file are for informational purposes only and do not 
+modify the License. You may add Your own attribution notices within Derivative Works 
+that You distribute, alongside or as an addendum to the NOTICE text from the Work, 
+provided that such additional attribution notices cannot be construed as modifying 
+the License. 
+
+You may add Your own copyright statement to Your modifications and may provide 
+additional or different license terms and conditions for use, reproduction, or 
+distribution of Your modifications, or for any such Derivative Works as a whole, 
+provided Your use, reproduction, and distribution of the Work otherwise complies with 
+the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution 
+intentionally submitted for inclusion in the Work by You to the Licensor shall be under 
+the terms and conditions of this License, without any additional terms or conditions. 
+Notwithstanding the above, nothing herein shall supersede or modify the terms of any 
+separate license agreement you may have executed with Licensor regarding such 
+Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, 
+trademarks, service marks, or product names of the Licensor, except as required for 
+reasonable and customary use in describing the origin of the Work and reproducing the 
+content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, 
+Licensor provides the Work (and each Contributor provides its Contributions) on an 
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 
+ including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, 
+ MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for 
+ determining the appropriateness of using or redistributing the Work and assume any 
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort 
+(including negligence), contract, or otherwise, unless required by applicable law (such 
+as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor 
+be liable to You for damages, including any direct, indirect, special, incidental, or 
+consequential damages of any character arising as a result of this License or out of the 
+use or inability to use the Work (including but not limited to damages for loss of 
+goodwill, work stoppage, computer failure or malfunction, or any and all other 
+commercial damages or losses), even if such Contributor has been advised of the 
+possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or 
+Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of 
+support, warranty, indemnity, or other liability obligations and/or rights consistent 
+with this License. However, in accepting such obligations, You may act only on Your own 
+behalf and on Your sole responsibility, not on behalf of any other Contributor, and only 
+if You agree to indemnify, defend, and hold each Contributor harmless for any liability 
+incurred by, or claims asserted against, such Contributor by reason of your accepting 
+any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: HOW TO APPLY THE APACHE LICENSE TO YOUR WORK
+To apply the Apache License to your work, attach the following boilerplate notice, with 
+the fields enclosed by brackets "[]" replaced with your own identifying information. 
+(Don't include the brackets!) The text should be enclosed in the appropriate comment 
+syntax for the file format. We also recommend that a file or class name and description 
+of purpose be included on the same "printed page" as the copyright notice for easier 
+identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
+
diff --git a/build-android/android-generate.sh b/build-android/android-generate.sh
index 0c0f5e1..4fa5a5c 100755
--- a/build-android/android-generate.sh
+++ b/build-android/android-generate.sh
@@ -59,7 +59,7 @@
     echo No spirv-tools git_dir found, generating UUID for external_revision_generator.py
 
     # Ensure uuidgen is installed, this should error if not found
-    uuidgen --v
+    type uuidgen
 
     uuidgen > $SPIRV_TOOLS_UUID;
     cat $SPIRV_TOOLS_UUID;
diff --git a/build-android/build.py b/build-android/build.py
new file mode 100755
index 0000000..05af005
--- /dev/null
+++ b/build-android/build.py
@@ -0,0 +1,300 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# 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.
+#
+
+import argparse
+import multiprocessing
+import os
+import shutil
+import subprocess
+import sys
+import time
+
+from subprocess import PIPE, STDOUT
+
+def install_file(file_name, src_dir, dst_dir):
+    src_file = os.path.join(src_dir, file_name)
+    dst_file = os.path.join(dst_dir, file_name)
+
+    print('Copying {} to {}...'.format(src_file, dst_file))
+    if os.path.isdir(src_file):
+        _install_dir(src_file, dst_file)
+    elif os.path.islink(src_file):
+        _install_symlink(src_file, dst_file)
+    else:
+        _install_file(src_file, dst_file)
+
+
+def _install_dir(src_dir, dst_dir):
+    parent_dir = os.path.normpath(os.path.join(dst_dir, '..'))
+    if not os.path.exists(parent_dir):
+        os.makedirs(parent_dir)
+    shutil.copytree(src_dir, dst_dir, symlinks=True)
+
+
+def _install_symlink(src_file, dst_file):
+    dirname = os.path.dirname(dst_file)
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+    link_target = os.readlink(src_file)
+    os.symlink(link_target, dst_file)
+
+
+def _install_file(src_file, dst_file):
+    dirname = os.path.dirname(dst_file)
+    if not os.path.exists(dirname):
+        os.makedirs(dirname)
+    # copy2 is just copy followed by copystat (preserves file metadata).
+    shutil.copy2(src_file, dst_file)
+
+THIS_DIR = os.path.realpath(os.path.dirname(__file__))
+
+ALL_ARCHITECTURES = (
+  'arm',
+  'arm64',
+  'mips',
+  'mips64',
+  'x86',
+  'x86_64',
+)
+
+# According to vk_platform.h, armeabi is not supported for Vulkan
+# so remove it from the abis list.
+ALL_ABIS = (
+  'armeabi-v7a',
+  'arm64-v8a',
+  'mips',
+  'mips64',
+  'x86',
+  'x86_64',
+)
+
+def jobs_arg():
+  return '-j{}'.format(multiprocessing.cpu_count() * 2)
+
+def arch_to_abis(arch):
+  return {
+    'arm': ['armeabi-v7a'],
+    'arm64': ['arm64-v8a'],
+    'mips': ['mips'],
+    'mips64': ['mips64'],
+    'x86': ['x86'],
+    'x86_64': ['x86_64'],
+  }[arch]
+
+class ArgParser(argparse.ArgumentParser):
+  def __init__(self):
+    super(ArgParser, self).__init__()
+
+    self.add_argument(
+      '--out-dir', help='Directory to place temporary build files.',
+      type=os.path.realpath, default=os.path.join(THIS_DIR, 'out'))
+
+    self.add_argument(
+      '--arch', choices=ALL_ARCHITECTURES,
+      help='Architectures to build. Builds all if not present.')
+
+    self.add_argument('--installdir', dest='installdir', required=True,
+      help='Installation directory. Required.')
+
+    # The default for --dist-dir has to be handled after parsing all
+    # arguments because the default is derived from --out-dir. This is
+    # handled in run().
+    self.add_argument(
+      '--dist-dir', help='Directory to place the packaged artifact.',
+      type=os.path.realpath)
+
+
+def main():
+  print('THIS_DIR: %s' % THIS_DIR)
+  parser = ArgParser()
+  args = parser.parse_args()
+
+  arches = ALL_ARCHITECTURES
+  if args.arch is not None:
+    arches = [args.arch]
+
+  # Make paths absolute, and ensure directories exist.
+  installdir = os.path.abspath(args.installdir)
+
+  abis = []
+  for arch in arches:
+    abis.extend(arch_to_abis(arch))
+
+  shaderc_path = installdir + '/shaderc/android_test'
+  print('shaderc_path = %s' % shaderc_path)
+
+  ndk_dir = os.path.join(THIS_DIR, '../../../prebuilts/toolchain')
+
+  ndk_build = os.path.join(ndk_dir, 'ndk-build')
+  platforms_root = os.path.join(ndk_dir, 'platforms')
+  toolchains_root = os.path.join(ndk_dir, 'toolchains')
+  build_dir = THIS_DIR
+
+  print('installdir: %s' % installdir)
+  print('ndk_dir: %s' % ndk_dir)
+  print('ndk_build: %s' % ndk_build)
+  print('platforms_root: %s' % platforms_root)
+
+  compiler = 'clang'
+  stl = 'c++_static'
+  obj_out = os.path.join(THIS_DIR, stl, 'obj')
+  lib_out = os.path.join(THIS_DIR, 'jniLibs')
+
+  print('obj_out: %s' % obj_out)
+  print('lib_out: %s' % lib_out)
+
+  print('Constructing shaderc build tree...')
+  shaderc_root_dir = os.path.join(THIS_DIR, '../../shaderc')
+
+  copies = [
+      {
+          'source_dir': os.path.join(shaderc_root_dir, 'shaderc'),
+          'dest_dir': 'third_party/shaderc',
+          'files': [
+              'Android.mk', 'libshaderc/Android.mk',
+              'libshaderc_util/Android.mk',
+              'third_party/Android.mk',
+              'utils/update_build_version.py',
+              'CHANGES',
+          ],
+          'dirs': [
+              'libshaderc/include', 'libshaderc/src',
+              'libshaderc_util/include', 'libshaderc_util/src',
+              'android_test'
+          ],
+      },
+      {
+          'source_dir': os.path.join(shaderc_root_dir, 'spirv-tools'),
+          'dest_dir': 'third_party/shaderc/third_party/spirv-tools',
+          'files': [
+              'utils/generate_grammar_tables.py',
+              'utils/generate_language_headers.py',
+              'utils/generate_registry_tables.py',
+              'utils/update_build_version.py',
+              'Android.mk',
+              'CHANGES',
+          ],
+          'dirs': ['include', 'source'],
+      },
+      {
+          'source_dir': os.path.join(shaderc_root_dir, 'spirv-headers'),
+          'dest_dir':
+              'third_party/shaderc/third_party/spirv-tools/external/spirv-headers',
+          'dirs': ['include',],
+          'files': [
+              'include/spirv/1.0/spirv.py',
+              'include/spirv/1.1/spirv.py',
+              'include/spirv/1.2/spirv.py',
+          ],
+      },
+      {
+          'source_dir': os.path.join(shaderc_root_dir, 'glslang'),
+          'dest_dir': 'third_party/shaderc/third_party/glslang',
+          'files': ['glslang/OSDependent/osinclude.h'],
+          'dirs': [
+              'SPIRV',
+              'OGLCompilersDLL',
+              'glslang/GenericCodeGen',
+              'hlsl',
+              'glslang/Include',
+              'glslang/MachineIndependent',
+              'glslang/OSDependent/Unix',
+              'glslang/Public',
+          ],
+      },
+  ]
+
+  default_ignore_patterns = shutil.ignore_patterns(
+      "*CMakeLists.txt",
+      "*.py",
+      "*test.h",
+      "*test.cc")
+
+  for properties in copies:
+      source_dir = properties['source_dir']
+      dest_dir = os.path.join(installdir, properties['dest_dir'])
+      for d in properties['dirs']:
+          src = os.path.join(source_dir, d)
+          dst = os.path.join(dest_dir, d)
+          print(src, " -> ", dst)
+          shutil.copytree(src, dst,
+                          ignore=default_ignore_patterns)
+      for f in properties['files']:
+          print(source_dir, ':', dest_dir, ":", f)
+          # Only copy if the source file exists.  That way
+          # we can update this script in anticipation of
+          # source files yet-to-come.
+          if os.path.exists(os.path.join(source_dir, f)):
+              install_file(f, source_dir, dest_dir)
+          else:
+              print(source_dir, ':', dest_dir, ":", f, "SKIPPED")
+
+  print('Constructing Vulkan validation layer source...')
+
+  build_cmd = [
+    'bash', THIS_DIR + '/android-generate.sh'
+  ]
+  print('Generating generated layers...')
+  subprocess.check_call(build_cmd)
+  print('Generation finished')
+
+  build_cmd = [
+    'bash', ndk_build, '-C', build_dir,
+    jobs_arg(),
+    'APP_ABI=' + ' '.join(abis),
+    # Use the prebuilt platforms and toolchains.
+    'NDK_PLATFORMS_ROOT=' + platforms_root,
+    'NDK_TOOLCHAINS_ROOT=' + toolchains_root,
+    'NDK_MODULE_PATH=' + installdir,
+    'GNUSTL_PREFIX=',
+    'APP_STL=' + stl,
+    'NDK_TOOLCHAIN_VERSION=' + compiler,
+
+    # Tell ndk-build where to put the results
+    'NDK_OUT=' + obj_out,
+    'NDK_LIBS_OUT=' + lib_out,
+  ]
+
+  print('Building Vulkan validation layers for ABIs:' +
+    ' {}'.format(', '.join(abis)) + "...")
+  print(' '.join(build_cmd))
+
+  subprocess.check_call(build_cmd)
+
+  print('Finished building Vulkan validation layers')
+  out_package = os.path.join(installdir, 'vulkan_validation_layers.zip')
+  os.chdir(lib_out)
+  build_cmd = [
+      'zip', '-9qr', out_package, "."
+  ]
+
+  print('Packaging Vulkan validation layers')
+  subprocess.check_call(build_cmd)
+  print('Finished Packaging Vulkan validation layers')
+
+  for properties in copies:
+      dest_dir = os.path.join(installdir, properties['dest_dir'])
+      for d in properties['dirs']:
+          dst = os.path.join(dest_dir, d)
+          print('Remove: %s' % dst)
+          shutil.rmtree(dst)
+
+  return 0
+
+
+if __name__ == '__main__':
+  main()
diff --git a/build-android/jni/Android.mk b/build-android/jni/Android.mk
index 2915de1..cbdc8c1 100644
--- a/build-android/jni/Android.mk
+++ b/build-android/jni/Android.mk
@@ -165,8 +165,9 @@
 LOCAL_SRC_FILES += $(SRC_DIR)/libs/vkjson/vkjson.cc \
                    $(SRC_DIR)/libs/vkjson/vkjson_instance.cc \
                    $(SRC_DIR)/common/vulkan_wrapper.cpp \
-                   $(SRC_DIR)/loader/cJSON.c
+                   $(SRC_DIR)/libs/cjson/cJSON.c
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/$(SRC_DIR)/include \
+                    $(LOCAL_PATH)/$(SRC_DIR)/libs/cjson/includes \
                     $(LOCAL_PATH)/$(SRC_DIR)/loader
 
 LOCAL_CPPFLAGS += -std=c++11 -DVK_PROTOTYPES -Wall -Werror -Wno-unused-function -Wno-unused-const-variable
diff --git a/libs/cjson/Android.bp b/libs/cjson/Android.bp
new file mode 100644
index 0000000..6a1600c
--- /dev/null
+++ b/libs/cjson/Android.bp
@@ -0,0 +1,36 @@
+cc_library_static {
+    name: "cjson",
+    clang: true,
+    srcs: [
+        "cJSON.c",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    local_include_dirs: [
+        "includes",
+    ],
+    export_include_dirs: [
+        "includes",
+    ],
+}
+
+cc_library_static {
+    name: "cjson_ndk",
+    clang: true,
+    srcs: [
+        "cJSON.c",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    local_include_dirs: [
+        "includes",
+    ],
+    export_include_dirs: [
+        "includes",
+    ],
+    sdk_version: "24",
+}
diff --git a/loader/cJSON.c b/libs/cjson/cJSON.c
similarity index 100%
rename from loader/cJSON.c
rename to libs/cjson/cJSON.c
diff --git a/loader/cJSON.h b/libs/cjson/includes/cJSON.h
similarity index 100%
rename from loader/cJSON.h
rename to libs/cjson/includes/cJSON.h
diff --git a/libs/vkjson/Android.bp b/libs/vkjson/Android.bp
new file mode 100644
index 0000000..1b32e7a
--- /dev/null
+++ b/libs/vkjson/Android.bp
@@ -0,0 +1,52 @@
+cc_library_static {
+    name: "libvkjson",
+    srcs: [
+        "vkjson.cc",
+        "vkjson_instance.cc",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++11",
+        "-Wno-sign-compare",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    whole_static_libs: [
+        "cjson",
+    ],
+    header_libs: [
+        "vulkan_headers",
+    ],
+}
+
+cc_library_static {
+    name: "libvkjson_ndk",
+    clang: true,
+    srcs: [
+        "vkjson.cc",
+        "vkjson_instance.cc",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++11",
+        "-Wno-sign-compare",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    whole_static_libs: [
+        "cjson_ndk",
+    ],
+    header_libs: [
+        "vulkan_headers_ndk",
+    ],
+    sdk_version: "24",
+    stl: "libc++_static",
+}
diff --git a/libs/vkjson/CMakeLists.txt b/libs/vkjson/CMakeLists.txt
index 2e79d91..80357b2 100644
--- a/libs/vkjson/CMakeLists.txt
+++ b/libs/vkjson/CMakeLists.txt
@@ -23,9 +23,10 @@
 	${CMAKE_CURRENT_SOURCE_DIR}
 	${CMAKE_CURRENT_SOURCE_DIR}/../../loader
 	${CMAKE_CURRENT_SOURCE_DIR}/../../include/vulkan
+	${CMAKE_CURRENT_SOURCE_DIR}/../../libs/cjson/includes
 	)
 
-add_library(vkjson STATIC vkjson.cc vkjson_instance.cc ../../loader/cJSON.c)
+add_library(vkjson STATIC vkjson.cc vkjson_instance.cc ../../libs/cjson/cJSON.c)
 
 if(UNIX)
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare")
diff --git a/libs/vkjson/vkjson.cc b/libs/vkjson/vkjson.cc
index 177be92..c41a247 100644
--- a/libs/vkjson/vkjson.cc
+++ b/libs/vkjson/vkjson.cc
@@ -34,7 +34,6 @@
 #include <utility>
 
 #include <cJSON.h>
-#include <vulkan/vk_sdk_platform.h>
 
 namespace {
 
@@ -277,6 +276,14 @@
 }
 
 template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceVariablePointerFeaturesKHR* features) {
+  return visitor->Visit("variablePointersStorageBuffer",
+                        &features->variablePointersStorageBuffer) &&
+         visitor->Visit("variablePointers", &features->variablePointers);
+}
+
+template <typename Visitor>
 inline bool Iterate(Visitor* visitor, VkMemoryType* type) {
   return
     visitor->Visit("propertyFlags", &type->propertyFlags) &&
@@ -342,6 +349,8 @@
 inline bool Iterate(Visitor* visitor, VkJsonDevice* device) {
   return visitor->Visit("properties", &device->properties) &&
          visitor->Visit("features", &device->features) &&
+         visitor->Visit("variablePointersFeaturesKHR",
+                        &device->variable_pointer_features) &&
          visitor->Visit("memory", &device->memory) &&
          visitor->Visit("queues", &device->queues) &&
          visitor->Visit("extensions", &device->extensions) &&
diff --git a/libs/vkjson/vkjson.h b/libs/vkjson/vkjson.h
index b703750..af3b37f 100644
--- a/libs/vkjson/vkjson.h
+++ b/libs/vkjson/vkjson.h
@@ -42,10 +42,13 @@
   VkJsonDevice() {
           memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
           memset(&features, 0, sizeof(VkPhysicalDeviceFeatures));
+          memset(&variable_pointer_features, 0,
+                 sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
           memset(&memory, 0, sizeof(VkPhysicalDeviceMemoryProperties));
   }
   VkPhysicalDeviceProperties properties;
   VkPhysicalDeviceFeatures features;
+  VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features;
   VkPhysicalDeviceMemoryProperties memory;
   std::vector<VkQueueFamilyProperties> queues;
   std::vector<VkExtensionProperties> extensions;
@@ -65,7 +68,10 @@
                             VkJsonInstance* instance,
                             std::string* errors);
 
-VkJsonDevice VkJsonGetDevice(VkPhysicalDevice device);
+VkJsonDevice VkJsonGetDevice(VkInstance instance,
+                             VkPhysicalDevice device,
+                             uint32_t instanceExtensionCount,
+                             const char* const* instanceExtensions);
 std::string VkJsonDeviceToJson(const VkJsonDevice& device);
 bool VkJsonDeviceFromJson(const std::string& json,
                           VkJsonDevice* device,
@@ -81,7 +87,7 @@
 typedef VkJsonDevice VkJsonAllProperties;
 inline VkJsonAllProperties VkJsonGetAllProperties(
     VkPhysicalDevice physicalDevice) {
-  return VkJsonGetDevice(physicalDevice);
+  return VkJsonGetDevice(VK_NULL_HANDLE, physicalDevice, 0, nullptr);
 }
 inline std::string VkJsonAllPropertiesToJson(
     const VkJsonAllProperties& properties) {
diff --git a/libs/vkjson/vkjson_instance.cc b/libs/vkjson/vkjson_instance.cc
index 51b5cfa..de61101 100644
--- a/libs/vkjson/vkjson_instance.cc
+++ b/libs/vkjson/vkjson_instance.cc
@@ -24,9 +24,13 @@
 
 #include "vkjson.h"
 
+#include <algorithm>
 #include <utility>
 
 namespace {
+const char* kSupportedInstanceExtensions[] = {
+    "VK_KHR_get_physical_device_properties2"};
+
 bool EnumerateExtensions(const char* layer_name,
                          std::vector<VkExtensionProperties>* extensions) {
   VkResult result;
@@ -42,21 +46,39 @@
   return true;
 }
 
+bool HasExtension(const char* extension_name,
+                  uint32_t count,
+                  const char* const* extensions) {
+  return std::find_if(extensions, extensions + count,
+                      [extension_name](const char* extension) {
+                        return strcmp(extension, extension_name) == 0;
+                      }) != extensions + count;
+}
+
+bool HasExtension(const char* extension_name,
+                  const std::vector<VkExtensionProperties>& extensions) {
+  return std::find_if(extensions.cbegin(), extensions.cend(),
+                      [extension_name](const VkExtensionProperties& extension) {
+                        return strcmp(extension.extensionName,
+                                      extension_name) == 0;
+                      }) != extensions.cend();
+}
 }  // anonymous namespace
 
-VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) {
+VkJsonDevice VkJsonGetDevice(VkInstance instance,
+                             VkPhysicalDevice physical_device,
+                             uint32_t instance_extension_count,
+                             const char* const* instance_extensions) {
   VkJsonDevice device;
-  vkGetPhysicalDeviceProperties(physical_device, &device.properties);
-  vkGetPhysicalDeviceFeatures(physical_device, &device.features);
-  vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);
 
-  uint32_t queue_family_count = 0;
-  vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
-                                           nullptr);
-  if (queue_family_count > 0) {
-    device.queues.resize(queue_family_count);
-    vkGetPhysicalDeviceQueueFamilyProperties(
-        physical_device, &queue_family_count, device.queues.data());
+  PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
+      nullptr;
+  if (instance != VK_NULL_HANDLE &&
+      HasExtension("VK_KHR_get_physical_device_properties2",
+                   instance_extension_count, instance_extensions)) {
+    vkpGetPhysicalDeviceFeatures2KHR =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
   }
 
   // Only device extensions.
@@ -78,6 +100,36 @@
                                      device.layers.data());
   }
 
+  vkGetPhysicalDeviceProperties(physical_device, &device.properties);
+  if (HasExtension("VK_KHR_get_physical_device_properties2",
+                   instance_extension_count, instance_extensions)) {
+    VkPhysicalDeviceFeatures2KHR features = {
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
+        nullptr,
+        {}  // features
+    };
+    if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
+      device.variable_pointer_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
+      device.variable_pointer_features.pNext = features.pNext;
+      features.pNext = &device.variable_pointer_features;
+    }
+    vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
+    device.features = features.features;
+  } else {
+    vkGetPhysicalDeviceFeatures(physical_device, &device.features);
+  }
+  vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);
+
+  uint32_t queue_family_count = 0;
+  vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
+                                           nullptr);
+  if (queue_family_count > 0) {
+    device.queues.resize(queue_family_count);
+    vkGetPhysicalDeviceQueueFamilyProperties(
+        physical_device, &queue_family_count, device.queues.data());
+  }
+
   VkFormatProperties format_properties = {};
   for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
        format <= VK_FORMAT_END_RANGE;
@@ -119,6 +171,12 @@
   if (!EnumerateExtensions(nullptr, &instance.extensions))
     return VkJsonInstance();
 
+  std::vector<const char*> instance_extensions;
+  for (const auto extension : kSupportedInstanceExtensions) {
+    if (HasExtension(extension, instance.extensions))
+      instance_extensions.push_back(extension);
+  }
+
   const VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
                                       nullptr,
                                       "vkjson_info",
@@ -133,8 +191,8 @@
       &app_info,
       0,
       nullptr,
-      0,
-      nullptr};
+      static_cast<uint32_t>(instance_extensions.size()),
+      instance_extensions.data()};
   VkInstance vkinstance;
   result = vkCreateInstance(&instance_info, nullptr, &vkinstance);
   if (result != VK_SUCCESS)
@@ -155,7 +213,9 @@
 
   instance.devices.reserve(devices.size());
   for (auto device : devices)
-    instance.devices.emplace_back(VkJsonGetDevice(device));
+    instance.devices.emplace_back(VkJsonGetDevice(vkinstance, device,
+                                                  instance_extensions.size(),
+                                                  instance_extensions.data()));
 
   vkDestroyInstance(vkinstance, nullptr);
   return instance;
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index 779ebbd..9c0f7ea 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -78,8 +78,8 @@
     debug_report.c
     debug_report.h
     gpa_helper.h
-    cJSON.c
-    cJSON.h
+    ../libs/cjson/includes/cJSON.h
+    ../libs/cjson/cJSON.c
     murmurhash.c
     murmurhash.h
 )