Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master

Bug: 79597307
Change-Id: If1240d409fc23b86ad7c9a4ba69a774e031ab087
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index e95bc5d..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-subdirs = [
-    "libs/cjson",
-    "libs/vkjson",
-]
diff --git a/libs/cjson/Android.bp b/libs/cjson/Android.bp
deleted file mode 100644
index 6a1600c..0000000
--- a/libs/cjson/Android.bp
+++ /dev/null
@@ -1,36 +0,0 @@
-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/libs/vkjson/Android.bp b/libs/vkjson/Android.bp
deleted file mode 100644
index 1b32e7a..0000000
--- a/libs/vkjson/Android.bp
+++ /dev/null
@@ -1,52 +0,0 @@
-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/vkjson.cc b/libs/vkjson/vkjson.cc
index c41a247..704ca96 100644
--- a/libs/vkjson/vkjson.cc
+++ b/libs/vkjson/vkjson.cc
@@ -50,13 +50,280 @@
 template <> struct EnumTraits<VkPhysicalDeviceType> {
   static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
   static uint32_t max() { return VK_PHYSICAL_DEVICE_TYPE_END_RANGE; }
+  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
 };
 
 template <> struct EnumTraits<VkFormat> {
-  static uint32_t min() { return VK_FORMAT_BEGIN_RANGE; }
-  static uint32_t max() { return VK_FORMAT_END_RANGE; }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_FORMAT_UNDEFINED:
+      case VK_FORMAT_R4G4_UNORM_PACK8:
+      case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
+      case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
+      case VK_FORMAT_R5G6B5_UNORM_PACK16:
+      case VK_FORMAT_B5G6R5_UNORM_PACK16:
+      case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
+      case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
+      case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
+      case VK_FORMAT_R8_UNORM:
+      case VK_FORMAT_R8_SNORM:
+      case VK_FORMAT_R8_USCALED:
+      case VK_FORMAT_R8_SSCALED:
+      case VK_FORMAT_R8_UINT:
+      case VK_FORMAT_R8_SINT:
+      case VK_FORMAT_R8_SRGB:
+      case VK_FORMAT_R8G8_UNORM:
+      case VK_FORMAT_R8G8_SNORM:
+      case VK_FORMAT_R8G8_USCALED:
+      case VK_FORMAT_R8G8_SSCALED:
+      case VK_FORMAT_R8G8_UINT:
+      case VK_FORMAT_R8G8_SINT:
+      case VK_FORMAT_R8G8_SRGB:
+      case VK_FORMAT_R8G8B8_UNORM:
+      case VK_FORMAT_R8G8B8_SNORM:
+      case VK_FORMAT_R8G8B8_USCALED:
+      case VK_FORMAT_R8G8B8_SSCALED:
+      case VK_FORMAT_R8G8B8_UINT:
+      case VK_FORMAT_R8G8B8_SINT:
+      case VK_FORMAT_R8G8B8_SRGB:
+      case VK_FORMAT_B8G8R8_UNORM:
+      case VK_FORMAT_B8G8R8_SNORM:
+      case VK_FORMAT_B8G8R8_USCALED:
+      case VK_FORMAT_B8G8R8_SSCALED:
+      case VK_FORMAT_B8G8R8_UINT:
+      case VK_FORMAT_B8G8R8_SINT:
+      case VK_FORMAT_B8G8R8_SRGB:
+      case VK_FORMAT_R8G8B8A8_UNORM:
+      case VK_FORMAT_R8G8B8A8_SNORM:
+      case VK_FORMAT_R8G8B8A8_USCALED:
+      case VK_FORMAT_R8G8B8A8_SSCALED:
+      case VK_FORMAT_R8G8B8A8_UINT:
+      case VK_FORMAT_R8G8B8A8_SINT:
+      case VK_FORMAT_R8G8B8A8_SRGB:
+      case VK_FORMAT_B8G8R8A8_UNORM:
+      case VK_FORMAT_B8G8R8A8_SNORM:
+      case VK_FORMAT_B8G8R8A8_USCALED:
+      case VK_FORMAT_B8G8R8A8_SSCALED:
+      case VK_FORMAT_B8G8R8A8_UINT:
+      case VK_FORMAT_B8G8R8A8_SINT:
+      case VK_FORMAT_B8G8R8A8_SRGB:
+      case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
+      case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
+      case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
+      case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
+      case VK_FORMAT_A8B8G8R8_UINT_PACK32:
+      case VK_FORMAT_A8B8G8R8_SINT_PACK32:
+      case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
+      case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+      case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
+      case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
+      case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
+      case VK_FORMAT_A2R10G10B10_UINT_PACK32:
+      case VK_FORMAT_A2R10G10B10_SINT_PACK32:
+      case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
+      case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
+      case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
+      case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
+      case VK_FORMAT_A2B10G10R10_UINT_PACK32:
+      case VK_FORMAT_A2B10G10R10_SINT_PACK32:
+      case VK_FORMAT_R16_UNORM:
+      case VK_FORMAT_R16_SNORM:
+      case VK_FORMAT_R16_USCALED:
+      case VK_FORMAT_R16_SSCALED:
+      case VK_FORMAT_R16_UINT:
+      case VK_FORMAT_R16_SINT:
+      case VK_FORMAT_R16_SFLOAT:
+      case VK_FORMAT_R16G16_UNORM:
+      case VK_FORMAT_R16G16_SNORM:
+      case VK_FORMAT_R16G16_USCALED:
+      case VK_FORMAT_R16G16_SSCALED:
+      case VK_FORMAT_R16G16_UINT:
+      case VK_FORMAT_R16G16_SINT:
+      case VK_FORMAT_R16G16_SFLOAT:
+      case VK_FORMAT_R16G16B16_UNORM:
+      case VK_FORMAT_R16G16B16_SNORM:
+      case VK_FORMAT_R16G16B16_USCALED:
+      case VK_FORMAT_R16G16B16_SSCALED:
+      case VK_FORMAT_R16G16B16_UINT:
+      case VK_FORMAT_R16G16B16_SINT:
+      case VK_FORMAT_R16G16B16_SFLOAT:
+      case VK_FORMAT_R16G16B16A16_UNORM:
+      case VK_FORMAT_R16G16B16A16_SNORM:
+      case VK_FORMAT_R16G16B16A16_USCALED:
+      case VK_FORMAT_R16G16B16A16_SSCALED:
+      case VK_FORMAT_R16G16B16A16_UINT:
+      case VK_FORMAT_R16G16B16A16_SINT:
+      case VK_FORMAT_R16G16B16A16_SFLOAT:
+      case VK_FORMAT_R32_UINT:
+      case VK_FORMAT_R32_SINT:
+      case VK_FORMAT_R32_SFLOAT:
+      case VK_FORMAT_R32G32_UINT:
+      case VK_FORMAT_R32G32_SINT:
+      case VK_FORMAT_R32G32_SFLOAT:
+      case VK_FORMAT_R32G32B32_UINT:
+      case VK_FORMAT_R32G32B32_SINT:
+      case VK_FORMAT_R32G32B32_SFLOAT:
+      case VK_FORMAT_R32G32B32A32_UINT:
+      case VK_FORMAT_R32G32B32A32_SINT:
+      case VK_FORMAT_R32G32B32A32_SFLOAT:
+      case VK_FORMAT_R64_UINT:
+      case VK_FORMAT_R64_SINT:
+      case VK_FORMAT_R64_SFLOAT:
+      case VK_FORMAT_R64G64_UINT:
+      case VK_FORMAT_R64G64_SINT:
+      case VK_FORMAT_R64G64_SFLOAT:
+      case VK_FORMAT_R64G64B64_UINT:
+      case VK_FORMAT_R64G64B64_SINT:
+      case VK_FORMAT_R64G64B64_SFLOAT:
+      case VK_FORMAT_R64G64B64A64_UINT:
+      case VK_FORMAT_R64G64B64A64_SINT:
+      case VK_FORMAT_R64G64B64A64_SFLOAT:
+      case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
+      case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
+      case VK_FORMAT_D16_UNORM:
+      case VK_FORMAT_X8_D24_UNORM_PACK32:
+      case VK_FORMAT_D32_SFLOAT:
+      case VK_FORMAT_S8_UINT:
+      case VK_FORMAT_D16_UNORM_S8_UINT:
+      case VK_FORMAT_D24_UNORM_S8_UINT:
+      case VK_FORMAT_D32_SFLOAT_S8_UINT:
+      case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
+      case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
+      case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
+      case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
+      case VK_FORMAT_BC2_UNORM_BLOCK:
+      case VK_FORMAT_BC2_SRGB_BLOCK:
+      case VK_FORMAT_BC3_UNORM_BLOCK:
+      case VK_FORMAT_BC3_SRGB_BLOCK:
+      case VK_FORMAT_BC4_UNORM_BLOCK:
+      case VK_FORMAT_BC4_SNORM_BLOCK:
+      case VK_FORMAT_BC5_UNORM_BLOCK:
+      case VK_FORMAT_BC5_SNORM_BLOCK:
+      case VK_FORMAT_BC6H_UFLOAT_BLOCK:
+      case VK_FORMAT_BC6H_SFLOAT_BLOCK:
+      case VK_FORMAT_BC7_UNORM_BLOCK:
+      case VK_FORMAT_BC7_SRGB_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
+      case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
+      case VK_FORMAT_EAC_R11_UNORM_BLOCK:
+      case VK_FORMAT_EAC_R11_SNORM_BLOCK:
+      case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
+      case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
+      case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
+      case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
+      case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
+      case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
+      case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
+      case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
+      case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
+      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
+      case VK_FORMAT_R10X6_UNORM_PACK16_KHR:
+      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
+      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
+      case VK_FORMAT_R12X4_UNORM_PACK16_KHR:
+      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
+      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
+      case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
+      case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
+      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
+      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
+      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+        return true;
+    }
+    return false;
+  }
 };
 
+template <>
+struct EnumTraits<VkPointClippingBehavior> {
+  static uint32_t min() { return VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE; }
+  static uint32_t max() { return VK_POINT_CLIPPING_BEHAVIOR_END_RANGE; }
+  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+};
+
+template <>
+struct EnumTraits<VkExternalFenceHandleTypeFlagBits> {
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
+      case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
+        return true;
+    }
+    return false;
+  }
+};
+
+template <>
+struct EnumTraits<VkExternalSemaphoreHandleTypeFlagBits> {
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
+      case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
+        return true;
+    }
+    return false;
+  }
+};
 
 // VkSparseImageFormatProperties
 
@@ -277,10 +544,9 @@
 
 template <typename Visitor>
 inline bool Iterate(Visitor* visitor,
-                    VkPhysicalDeviceVariablePointerFeaturesKHR* features) {
-  return visitor->Visit("variablePointersStorageBuffer",
-                        &features->variablePointersStorageBuffer) &&
-         visitor->Visit("variablePointers", &features->variablePointers);
+                    VkJsonExtVariablePointerFeatures* features) {
+  return visitor->Visit("variablePointerFeaturesKHR",
+                        &features->variable_pointer_features_khr);
 }
 
 template <typename Visitor>
@@ -307,6 +573,124 @@
 }
 
 template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceSubgroupProperties* properties) {
+  return visitor->Visit("subgroupSize", &properties->subgroupSize) &&
+         visitor->Visit("supportedStages", &properties->supportedStages) &&
+         visitor->Visit("supportedOperations",
+                        &properties->supportedOperations) &&
+         visitor->Visit("quadOperationsInAllStages",
+                        &properties->quadOperationsInAllStages);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDevicePointClippingProperties* properties) {
+  return visitor->Visit("pointClippingBehavior",
+                        &properties->pointClippingBehavior);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceMultiviewProperties* properties) {
+  return visitor->Visit("maxMultiviewViewCount",
+                        &properties->maxMultiviewViewCount) &&
+         visitor->Visit("maxMultiviewInstanceIndex",
+                        &properties->maxMultiviewInstanceIndex);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceIDProperties* properties) {
+  return visitor->Visit("deviceUUID", &properties->deviceUUID) &&
+         visitor->Visit("driverUUID", &properties->driverUUID) &&
+         visitor->Visit("deviceLUID", &properties->deviceLUID) &&
+         visitor->Visit("deviceNodeMask", &properties->deviceNodeMask) &&
+         visitor->Visit("deviceLUIDValid", &properties->deviceLUIDValid);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceMaintenance3Properties* properties) {
+  return visitor->Visit("maxPerSetDescriptors",
+                        &properties->maxPerSetDescriptors) &&
+         visitor->Visit("maxMemoryAllocationSize",
+                        &properties->maxMemoryAllocationSize);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDevice16BitStorageFeatures* features) {
+  return visitor->Visit("storageBuffer16BitAccess",
+                        &features->storageBuffer16BitAccess) &&
+         visitor->Visit("uniformAndStorageBuffer16BitAccess",
+                        &features->uniformAndStorageBuffer16BitAccess) &&
+         visitor->Visit("storagePushConstant16",
+                        &features->storagePushConstant16) &&
+         visitor->Visit("storageInputOutput16",
+                        &features->storageInputOutput16);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceMultiviewFeatures* features) {
+  return visitor->Visit("multiview", &features->multiview) &&
+         visitor->Visit("multiviewGeometryShader",
+                        &features->multiviewGeometryShader) &&
+         visitor->Visit("multiviewTessellationShader",
+                        &features->multiviewTessellationShader);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceVariablePointerFeatures* features) {
+  return visitor->Visit("variablePointersStorageBuffer",
+                        &features->variablePointersStorageBuffer) &&
+         visitor->Visit("variablePointers", &features->variablePointers);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceProtectedMemoryFeatures* features) {
+  return visitor->Visit("protectedMemory", &features->protectedMemory);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceSamplerYcbcrConversionFeatures* features) {
+  return visitor->Visit("samplerYcbcrConversion",
+                        &features->samplerYcbcrConversion);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkPhysicalDeviceShaderDrawParameterFeatures* features) {
+  return visitor->Visit("shaderDrawParameters",
+                        &features->shaderDrawParameters);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkExternalFenceProperties* properties) {
+  return visitor->Visit("exportFromImportedHandleTypes",
+                        &properties->exportFromImportedHandleTypes) &&
+         visitor->Visit("compatibleHandleTypes",
+                        &properties->compatibleHandleTypes) &&
+         visitor->Visit("externalFenceFeatures",
+                        &properties->externalFenceFeatures);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+                    VkExternalSemaphoreProperties* properties) {
+  return visitor->Visit("exportFromImportedHandleTypes",
+                        &properties->exportFromImportedHandleTypes) &&
+         visitor->Visit("compatibleHandleTypes",
+                        &properties->compatibleHandleTypes) &&
+         visitor->Visit("externalSemaphoreFeatures",
+                        &properties->externalSemaphoreFeatures);
+}
+
+template <typename Visitor>
 inline bool Iterate(Visitor* visitor, VkQueueFamilyProperties* properties) {
   return
     visitor->Visit("queueFlags", &properties->queueFlags) &&
@@ -346,23 +730,68 @@
 }
 
 template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonDeviceGroup* device_group) {
+  return visitor->Visit("devices", &device_group->device_inds) &&
+         visitor->Visit("subsetAllocation",
+                        &device_group->properties.subsetAllocation);
+}
+
+template <typename Visitor>
 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) &&
-         visitor->Visit("layers", &device->layers) &&
-         visitor->Visit("formats", &device->formats);
+  bool ret = true;
+  switch (device->properties.apiVersion ^
+          VK_VERSION_PATCH(device->properties.apiVersion)) {
+    case VK_API_VERSION_1_1:
+      ret &=
+          visitor->Visit("subgroupProperties", &device->subgroup_properties) &&
+          visitor->Visit("pointClippingProperties",
+                         &device->point_clipping_properties) &&
+          visitor->Visit("multiviewProperties",
+                         &device->multiview_properties) &&
+          visitor->Visit("idProperties", &device->id_properties) &&
+          visitor->Visit("maintenance3Properties",
+                         &device->maintenance3_properties) &&
+          visitor->Visit("16bitStorageFeatures",
+                         &device->bit16_storage_features) &&
+          visitor->Visit("multiviewFeatures", &device->multiview_features) &&
+          visitor->Visit("variablePointerFeatures",
+                         &device->variable_pointer_features) &&
+          visitor->Visit("protectedMemoryFeatures",
+                         &device->protected_memory_features) &&
+          visitor->Visit("samplerYcbcrConversionFeatures",
+                         &device->sampler_ycbcr_conversion_features) &&
+          visitor->Visit("shaderDrawParameterFeatures",
+                         &device->shader_draw_parameter_features) &&
+          visitor->Visit("externalFenceProperties",
+                         &device->external_fence_properties) &&
+          visitor->Visit("externalSemaphoreProperties",
+                         &device->external_semaphore_properties);
+    case VK_API_VERSION_1_0:
+      ret &= visitor->Visit("properties", &device->properties) &&
+             visitor->Visit("features", &device->features) &&
+             visitor->Visit("VK_KHR_variable_pointers",
+                            &device->ext_variable_pointer_features) &&
+             visitor->Visit("memory", &device->memory) &&
+             visitor->Visit("queues", &device->queues) &&
+             visitor->Visit("extensions", &device->extensions) &&
+             visitor->Visit("layers", &device->layers) &&
+             visitor->Visit("formats", &device->formats);
+  }
+  return ret;
 }
 
 template <typename Visitor>
 inline bool Iterate(Visitor* visitor, VkJsonInstance* instance) {
-  return visitor->Visit("layers", &instance->layers) &&
-         visitor->Visit("extensions", &instance->extensions) &&
-         visitor->Visit("devices", &instance->devices);
+  bool ret = true;
+  switch (instance->api_version ^ VK_VERSION_PATCH(instance->api_version)) {
+    case VK_API_VERSION_1_1:
+      ret &= visitor->Visit("deviceGroups", &instance->device_groups);
+    case VK_API_VERSION_1_0:
+      ret &= visitor->Visit("layers", &instance->layers) &&
+             visitor->Visit("extensions", &instance->extensions) &&
+             visitor->Visit("devices", &instance->devices);
+  }
+  return ret;
 }
 
 template <typename T>
@@ -558,12 +987,10 @@
 
 template <typename T, typename = EnableForEnum<T>, typename = void>
 inline bool AsValue(cJSON* json_value, T* t) {
-  // TODO(piman): to/from strings instead?
   uint32_t value = 0;
   if (!AsValue(json_value, &value))
       return false;
-  if (value < EnumTraits<T>::min() || value > EnumTraits<T>::max())
-    return false;
+  if (!EnumTraits<T>::exist(value)) return false;
   *t = static_cast<T>(value);
   return true;
 }
diff --git a/libs/vkjson/vkjson.h b/libs/vkjson/vkjson.h
index af3b37f..5e8428a 100644
--- a/libs/vkjson/vkjson.h
+++ b/libs/vkjson/vkjson.h
@@ -33,33 +33,93 @@
 #undef max
 #endif
 
+#ifndef VK_API_VERSION_1_0
+#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)
+#endif
+
+#ifndef VK_API_VERSION_1_1
+#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)
+#endif
+
 struct VkJsonLayer {
   VkLayerProperties properties;
   std::vector<VkExtensionProperties> extensions;
 };
 
+struct VkJsonExtVariablePointerFeatures {
+  VkJsonExtVariablePointerFeatures() {
+    memset(&variable_pointer_features_khr, 0,
+           sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
+  }
+  VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
+};
+
 struct VkJsonDevice {
   VkJsonDevice() {
-          memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
-          memset(&features, 0, sizeof(VkPhysicalDeviceFeatures));
-          memset(&variable_pointer_features, 0,
-                 sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
-          memset(&memory, 0, sizeof(VkPhysicalDeviceMemoryProperties));
+    memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
+    memset(&features, 0, sizeof(VkPhysicalDeviceFeatures));
+    memset(&memory, 0, sizeof(VkPhysicalDeviceMemoryProperties));
+    memset(&subgroup_properties, 0, sizeof(VkPhysicalDeviceSubgroupProperties));
+    memset(&point_clipping_properties, 0,
+           sizeof(VkPhysicalDevicePointClippingProperties));
+    memset(&multiview_properties, 0,
+           sizeof(VkPhysicalDeviceMultiviewProperties));
+    memset(&id_properties, 0, sizeof(VkPhysicalDeviceIDProperties));
+    memset(&maintenance3_properties, 0,
+           sizeof(VkPhysicalDeviceMaintenance3Properties));
+    memset(&bit16_storage_features, 0,
+           sizeof(VkPhysicalDevice16BitStorageFeatures));
+    memset(&multiview_features, 0, sizeof(VkPhysicalDeviceMultiviewFeatures));
+    memset(&variable_pointer_features, 0,
+           sizeof(VkPhysicalDeviceVariablePointerFeatures));
+    memset(&protected_memory_features, 0,
+           sizeof(VkPhysicalDeviceProtectedMemoryFeatures));
+    memset(&sampler_ycbcr_conversion_features, 0,
+           sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeatures));
+    memset(&shader_draw_parameter_features, 0,
+           sizeof(VkPhysicalDeviceShaderDrawParameterFeatures));
   }
   VkPhysicalDeviceProperties properties;
   VkPhysicalDeviceFeatures features;
-  VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features;
+  VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
   VkPhysicalDeviceMemoryProperties memory;
   std::vector<VkQueueFamilyProperties> queues;
   std::vector<VkExtensionProperties> extensions;
   std::vector<VkLayerProperties> layers;
   std::map<VkFormat, VkFormatProperties> formats;
+  VkPhysicalDeviceSubgroupProperties subgroup_properties;
+  VkPhysicalDevicePointClippingProperties point_clipping_properties;
+  VkPhysicalDeviceMultiviewProperties multiview_properties;
+  VkPhysicalDeviceIDProperties id_properties;
+  VkPhysicalDeviceMaintenance3Properties maintenance3_properties;
+  VkPhysicalDevice16BitStorageFeatures bit16_storage_features;
+  VkPhysicalDeviceMultiviewFeatures multiview_features;
+  VkPhysicalDeviceVariablePointerFeatures variable_pointer_features;
+  VkPhysicalDeviceProtectedMemoryFeatures protected_memory_features;
+  VkPhysicalDeviceSamplerYcbcrConversionFeatures
+      sampler_ycbcr_conversion_features;
+  VkPhysicalDeviceShaderDrawParameterFeatures shader_draw_parameter_features;
+  std::map<VkExternalFenceHandleTypeFlagBits, VkExternalFenceProperties>
+      external_fence_properties;
+  std::map<VkExternalSemaphoreHandleTypeFlagBits, VkExternalSemaphoreProperties>
+      external_semaphore_properties;
+};
+
+struct VkJsonDeviceGroup {
+  VkJsonDeviceGroup() {
+    memset(&properties, 0, sizeof(VkPhysicalDeviceGroupProperties));
+  }
+  VkPhysicalDeviceGroupProperties properties;
+  std::vector<uint32_t> device_inds;
 };
 
 struct VkJsonInstance {
+  VkJsonInstance() : api_version(0) {}
+  uint32_t api_version;
   std::vector<VkJsonLayer> layers;
   std::vector<VkExtensionProperties> extensions;
   std::vector<VkJsonDevice> devices;
+  std::vector<VkJsonDeviceGroup> device_groups;
 };
 
 VkJsonInstance VkJsonGetInstance();
diff --git a/libs/vkjson/vkjson_instance.cc b/libs/vkjson/vkjson_instance.cc
index de61101..db0450d 100644
--- a/libs/vkjson/vkjson_instance.cc
+++ b/libs/vkjson/vkjson_instance.cc
@@ -81,8 +81,6 @@
             vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
   }
 
-  // Only device extensions.
-  // TODO(piman): do we want to show layer extensions?
   uint32_t extension_count = 0;
   vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
                                        &extension_count, nullptr);
@@ -109,10 +107,12 @@
         {}  // features
     };
     if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
-      device.variable_pointer_features.sType =
+      device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
           VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
-      device.variable_pointer_features.pNext = features.pNext;
-      features.pNext = &device.variable_pointer_features;
+      device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
+          features.pNext;
+      features.pNext =
+          &device.ext_variable_pointer_features.variable_pointer_features_khr;
     }
     vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
     device.features = features.features;
@@ -142,6 +142,153 @@
       device.formats.insert(std::make_pair(format, format_properties));
     }
   }
+
+  if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
+    for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
+         format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
+         format = static_cast<VkFormat>(format + 1)) {
+      vkGetPhysicalDeviceFormatProperties(physical_device, format,
+                                          &format_properties);
+      if (format_properties.linearTilingFeatures ||
+          format_properties.optimalTilingFeatures ||
+          format_properties.bufferFeatures) {
+        device.formats.insert(std::make_pair(format, format_properties));
+      }
+    }
+
+    PFN_vkGetPhysicalDeviceProperties2 vkpGetPhysicalDeviceProperties2 =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
+    if (vkpGetPhysicalDeviceProperties2) {
+      VkPhysicalDeviceProperties2 properties2 = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
+
+      device.subgroup_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+      device.subgroup_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.subgroup_properties;
+
+      device.point_clipping_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
+      device.point_clipping_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.point_clipping_properties;
+
+      device.multiview_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+      device.multiview_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.multiview_properties;
+
+      device.id_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+      device.id_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.id_properties;
+
+      device.maintenance3_properties.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
+      device.maintenance3_properties.pNext = properties2.pNext;
+      properties2.pNext = &device.maintenance3_properties;
+
+      (*vkpGetPhysicalDeviceProperties2)(physical_device, &properties2);
+    }
+
+    PFN_vkGetPhysicalDeviceFeatures2 vkpGetPhysicalDeviceFeatures2 =
+        reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
+            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
+    if (vkpGetPhysicalDeviceFeatures2) {
+      VkPhysicalDeviceFeatures2 features2 = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, nullptr, {}};
+
+      device.bit16_storage_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
+      device.bit16_storage_features.pNext = features2.pNext;
+      features2.pNext = &device.bit16_storage_features;
+
+      device.multiview_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+      device.multiview_features.pNext = features2.pNext;
+      features2.pNext = &device.multiview_features;
+
+      device.variable_pointer_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
+      device.variable_pointer_features.pNext = features2.pNext;
+      features2.pNext = &device.variable_pointer_features;
+
+      device.protected_memory_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
+      device.protected_memory_features.pNext = features2.pNext;
+      features2.pNext = &device.protected_memory_features;
+
+      device.sampler_ycbcr_conversion_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+      device.sampler_ycbcr_conversion_features.pNext = features2.pNext;
+      features2.pNext = &device.sampler_ycbcr_conversion_features;
+
+      device.shader_draw_parameter_features.sType =
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
+      device.shader_draw_parameter_features.pNext = features2.pNext;
+      features2.pNext = &device.shader_draw_parameter_features;
+
+      (*vkpGetPhysicalDeviceFeatures2)(physical_device, &features2);
+    }
+
+    PFN_vkGetPhysicalDeviceExternalFenceProperties
+        vkpGetPhysicalDeviceExternalFenceProperties =
+            reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
+                vkGetInstanceProcAddr(
+                    instance, "vkGetPhysicalDeviceExternalFenceProperties"));
+    if (vkpGetPhysicalDeviceExternalFenceProperties) {
+      VkPhysicalDeviceExternalFenceInfo external_fence_info = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, nullptr,
+          VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT};
+      VkExternalFenceProperties external_fence_properties = {};
+
+      for (VkExternalFenceHandleTypeFlagBits handle_type =
+               VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT;
+           handle_type <= VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+           handle_type = static_cast<VkExternalFenceHandleTypeFlagBits>(
+               handle_type << 1)) {
+        external_fence_info.handleType = handle_type;
+        (*vkpGetPhysicalDeviceExternalFenceProperties)(
+            physical_device, &external_fence_info, &external_fence_properties);
+        if (external_fence_properties.exportFromImportedHandleTypes ||
+            external_fence_properties.compatibleHandleTypes ||
+            external_fence_properties.externalFenceFeatures) {
+          device.external_fence_properties.insert(
+              std::make_pair(handle_type, external_fence_properties));
+        }
+      }
+    }
+
+    PFN_vkGetPhysicalDeviceExternalSemaphoreProperties
+        vkpGetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<
+            PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
+            vkGetInstanceProcAddr(
+                instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
+    if (vkpGetPhysicalDeviceExternalSemaphoreProperties) {
+      VkPhysicalDeviceExternalSemaphoreInfo external_semaphore_info = {
+          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr,
+          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT};
+      VkExternalSemaphoreProperties external_semaphore_properties = {};
+
+      for (VkExternalSemaphoreHandleTypeFlagBits handle_type =
+               VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
+           handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+           handle_type = static_cast<VkExternalSemaphoreHandleTypeFlagBits>(
+               handle_type << 1)) {
+        external_semaphore_info.handleType = handle_type;
+        (*vkpGetPhysicalDeviceExternalSemaphoreProperties)(
+            physical_device, &external_semaphore_info,
+            &external_semaphore_properties);
+        if (external_semaphore_properties.exportFromImportedHandleTypes ||
+            external_semaphore_properties.compatibleHandleTypes ||
+            external_semaphore_properties.externalSemaphoreFeatures) {
+          device.external_semaphore_properties.insert(
+              std::make_pair(handle_type, external_semaphore_properties));
+        }
+      }
+    }
+  }
+
   return device;
 }
 
@@ -204,6 +351,7 @@
     vkDestroyInstance(vkinstance, nullptr);
     return VkJsonInstance();
   }
+
   std::vector<VkPhysicalDevice> devices(count, VK_NULL_HANDLE);
   result = vkEnumeratePhysicalDevices(vkinstance, &count, devices.data());
   if (result != VK_SUCCESS) {
@@ -211,11 +359,58 @@
     return VkJsonInstance();
   }
 
-  instance.devices.reserve(devices.size());
-  for (auto device : devices)
-    instance.devices.emplace_back(VkJsonGetDevice(vkinstance, device,
+  std::map<VkPhysicalDevice, uint32_t> device_map;
+  const uint32_t sz = devices.size();
+  instance.devices.reserve(sz);
+  for (uint32_t i = 0; i < sz; ++i) {
+    device_map.insert(std::make_pair(devices[i], i));
+    instance.devices.emplace_back(VkJsonGetDevice(vkinstance, devices[i],
                                                   instance_extensions.size(),
                                                   instance_extensions.data()));
+  }
+
+  PFN_vkEnumerateInstanceVersion vkpEnumerateInstanceVersion =
+      reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
+          vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"));
+  if (!vkpEnumerateInstanceVersion) {
+    instance.api_version = VK_API_VERSION_1_0;
+  } else {
+    result = (*vkpEnumerateInstanceVersion)(&instance.api_version);
+    if (result != VK_SUCCESS) {
+      vkDestroyInstance(vkinstance, nullptr);
+      return VkJsonInstance();
+    }
+  }
+
+  PFN_vkEnumeratePhysicalDeviceGroups vkpEnumeratePhysicalDeviceGroups =
+      reinterpret_cast<PFN_vkEnumeratePhysicalDeviceGroups>(
+          vkGetInstanceProcAddr(vkinstance, "vkEnumeratePhysicalDeviceGroups"));
+  if (vkpEnumeratePhysicalDeviceGroups) {
+    count = 0;
+    result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count, nullptr);
+    if (result != VK_SUCCESS) {
+      vkDestroyInstance(vkinstance, nullptr);
+      return VkJsonInstance();
+    }
+
+    VkJsonDeviceGroup device_group;
+    std::vector<VkPhysicalDeviceGroupProperties> group_properties;
+    group_properties.resize(count);
+    result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count,
+                                                 group_properties.data());
+    if (result != VK_SUCCESS) {
+      vkDestroyInstance(vkinstance, nullptr);
+      return VkJsonInstance();
+    }
+    for (auto properties : group_properties) {
+      device_group.properties = properties;
+      for (uint32_t i = 0; i < properties.physicalDeviceCount; ++i) {
+        device_group.device_inds.push_back(
+            device_map[properties.physicalDevices[i]]);
+      }
+      instance.device_groups.push_back(device_group);
+    }
+  }
 
   vkDestroyInstance(vkinstance, nullptr);
   return instance;