Merge commit vkjson-instance into nyc-dev

Bug: 26620936
Change-Id: Id4f5a693cf23384612391e63b0529e31053ceca6
diff --git a/libs/vkjson/.clang-format b/libs/vkjson/.clang-format
new file mode 100644
index 0000000..3f19e61
--- /dev/null
+++ b/libs/vkjson/.clang-format
@@ -0,0 +1 @@
+BasedOnStyle: Chromium
diff --git a/libs/vkjson/Android.mk b/libs/vkjson/Android.mk
index 6fbf6db..d35e36e 100644
--- a/libs/vkjson/Android.mk
+++ b/libs/vkjson/Android.mk
@@ -26,7 +26,7 @@
 
 LOCAL_SRC_FILES := \
 	vkjson.cc \
-	vkjson_device.cc \
+	vkjson_instance.cc \
 	../../loader/cJSON.c
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/libs/vkjson/CMakeLists.txt b/libs/vkjson/CMakeLists.txt
index b650609..fc69bb6 100644
--- a/libs/vkjson/CMakeLists.txt
+++ b/libs/vkjson/CMakeLists.txt
@@ -28,7 +28,7 @@
 	${CMAKE_CURRENT_SOURCE_DIR}/../../include/vulkan
 	)
 
-add_library(vkjson STATIC vkjson.cc vkjson_device.cc ../../loader/cJSON.c)
+add_library(vkjson STATIC vkjson.cc vkjson_instance.cc ../../loader/cJSON.c)
 
 if(UNIX)
     add_executable(vkjson_unittest vkjson_unittest.cc)
diff --git a/libs/vkjson/vkjson.cc b/libs/vkjson/vkjson.cc
index 6e83ad8..ee87b91 100644
--- a/libs/vkjson/vkjson.cc
+++ b/libs/vkjson/vkjson.cc
@@ -334,17 +334,28 @@
 }
 
 template <typename Visitor>
-inline bool Iterate(Visitor* visitor, VkJsonAllProperties* properties) {
-  return
-    visitor->Visit("properties", &properties->properties) &&
-    visitor->Visit("features", &properties->features) &&
-    visitor->Visit("memory", &properties->memory) &&
-    visitor->Visit("queues", &properties->queues) &&
-    visitor->Visit("extensions", &properties->extensions) &&
-    visitor->Visit("layers", &properties->layers) &&
-    visitor->Visit("formats", &properties->formats);
+inline bool Iterate(Visitor* visitor, VkJsonLayer* layer) {
+  return visitor->Visit("properties", &layer->properties) &&
+         visitor->Visit("extensions", &layer->extensions);
 }
 
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonDevice* device) {
+  return visitor->Visit("properties", &device->properties) &&
+         visitor->Visit("features", &device->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);
+}
+
+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);
+}
 
 template <typename T>
 using EnableForArithmetic =
@@ -670,15 +681,24 @@
 
 }  // anonymous namespace
 
-std::string VkJsonAllPropertiesToJson(
-    const VkJsonAllProperties& properties) {
-  return VkTypeToJson(properties);
+std::string VkJsonInstanceToJson(const VkJsonInstance& instance) {
+  return VkTypeToJson(instance);
 }
 
-bool VkJsonAllPropertiesFromJson(
-    const std::string& json, VkJsonAllProperties* properties,
-    std::string* errors) {
-  return VkTypeFromJson(json, properties, errors);
+bool VkJsonInstanceFromJson(const std::string& json,
+                            VkJsonInstance* instance,
+                            std::string* errors) {
+  return VkTypeFromJson(json, instance, errors);
+}
+
+std::string VkJsonDeviceToJson(const VkJsonDevice& device) {
+  return VkTypeToJson(device);
+}
+
+bool VkJsonDeviceFromJson(const std::string& json,
+                          VkJsonDevice* device,
+                          std::string* errors) {
+  return VkTypeFromJson(json, device, errors);
 };
 
 std::string VkJsonImageFormatPropertiesToJson(
diff --git a/libs/vkjson/vkjson.h b/libs/vkjson/vkjson.h
index a248bd3..2fe953b 100644
--- a/libs/vkjson/vkjson.h
+++ b/libs/vkjson/vkjson.h
@@ -40,8 +40,13 @@
 #undef max
 #endif
 
-struct VkJsonAllProperties {
-  VkJsonAllProperties() {
+struct VkJsonLayer {
+  VkLayerProperties properties;
+  std::vector<VkExtensionProperties> extensions;
+};
+
+struct VkJsonDevice {
+  VkJsonDevice() {
           memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
           memset(&features, 0, sizeof(VkPhysicalDeviceFeatures));
           memset(&memory, 0, sizeof(VkPhysicalDeviceMemoryProperties));
@@ -55,13 +60,23 @@
   std::map<VkFormat, VkFormatProperties> formats;
 };
 
-VkJsonAllProperties VkJsonGetAllProperties(VkPhysicalDevice physicalDevice);
+struct VkJsonInstance {
+  std::vector<VkJsonLayer> layers;
+  std::vector<VkExtensionProperties> extensions;
+  std::vector<VkJsonDevice> devices;
+};
 
-std::string VkJsonAllPropertiesToJson(
-    const VkJsonAllProperties& properties);
-bool VkJsonAllPropertiesFromJson(
-    const std::string& json, VkJsonAllProperties* properties,
-    std::string* errors);
+VkJsonInstance VkJsonGetInstance();
+std::string VkJsonInstanceToJson(const VkJsonInstance& instance);
+bool VkJsonInstanceFromJson(const std::string& json,
+                            VkJsonInstance* instance,
+                            std::string* errors);
+
+VkJsonDevice VkJsonGetDevice(VkPhysicalDevice device);
+std::string VkJsonDeviceToJson(const VkJsonDevice& device);
+bool VkJsonDeviceFromJson(const std::string& json,
+                          VkJsonDevice* device,
+                          std::string* errors);
 
 std::string VkJsonImageFormatPropertiesToJson(
     const VkImageFormatProperties& properties);
@@ -69,4 +84,20 @@
                                          VkImageFormatProperties* properties,
                                          std::string* errors);
 
+// Backward-compatibility aliases
+typedef VkJsonDevice VkJsonAllProperties;
+inline VkJsonAllProperties VkJsonGetAllProperties(
+    VkPhysicalDevice physicalDevice) {
+  return VkJsonGetDevice(physicalDevice);
+}
+inline std::string VkJsonAllPropertiesToJson(
+    const VkJsonAllProperties& properties) {
+  return VkJsonDeviceToJson(properties);
+}
+inline bool VkJsonAllPropertiesFromJson(const std::string& json,
+                                        VkJsonAllProperties* properties,
+                                        std::string* errors) {
+  return VkJsonDeviceFromJson(json, properties, errors);
+}
+
 #endif  // VKJSON_H_
diff --git a/libs/vkjson/vkjson_device.cc b/libs/vkjson/vkjson_device.cc
deleted file mode 100644
index fc9540e..0000000
--- a/libs/vkjson/vkjson_device.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-//
-// Copyright (c) 2015-2016 The Khronos Group Inc.
-// Copyright (c) 2015-2016 Valve Corporation
-// Copyright (c) 2015-2016 LunarG, Inc.
-// Copyright (c) 2015-2016 Google, Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and/or associated documentation files (the "Materials"), to
-// deal in the Materials without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Materials, and to permit persons to whom the Materials are
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice(s) and this permission notice shall be included in
-// all copies or substantial portions of the Materials.
-//
-// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-//
-// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
-// USE OR OTHER DEALINGS IN THE MATERIALS.
-///////////////////////////////////////////////////////////////////////////////
-
-#define VK_PROTOTYPES
-#include "vkjson.h"
-
-#include <utility>
-
-VkJsonAllProperties VkJsonGetAllProperties(VkPhysicalDevice physical_device) {
-  VkJsonAllProperties properties;
-  vkGetPhysicalDeviceProperties(physical_device, &properties.properties);
-  vkGetPhysicalDeviceFeatures(physical_device, &properties.features);
-  vkGetPhysicalDeviceMemoryProperties(physical_device, &properties.memory);
-
-  uint32_t queue_family_count = 0;
-  vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
-                                           nullptr);
-  if (queue_family_count > 0) {
-    properties.queues.resize(queue_family_count);
-    vkGetPhysicalDeviceQueueFamilyProperties(
-        physical_device, &queue_family_count, properties.queues.data());
-  }
-
-  // Only device extensions.
-  // TODO(piman): do we want to show layer extensions?
-  uint32_t extension_count = 0;
-  vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
-                                       &extension_count, nullptr);
-  if (extension_count > 0) {
-    properties.extensions.resize(extension_count);
-    vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
-                                         &extension_count,
-                                         properties.extensions.data());
-  }
-
-  uint32_t layer_count = 0;
-  vkEnumerateDeviceLayerProperties(physical_device, &layer_count, nullptr);
-  if (layer_count > 0) {
-    properties.layers.resize(layer_count);
-    vkEnumerateDeviceLayerProperties(physical_device, &layer_count,
-                                     properties.layers.data());
-  }
-
-  VkFormatProperties format_properties = {};
-  for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
-       format <= VK_FORMAT_END_RANGE;
-       format = static_cast<VkFormat>(format + 1)) {
-    vkGetPhysicalDeviceFormatProperties(physical_device, format,
-                                        &format_properties);
-    if (format_properties.linearTilingFeatures ||
-        format_properties.optimalTilingFeatures ||
-        format_properties.bufferFeatures) {
-      properties.formats.insert(std::make_pair(format, format_properties));
-    }
-  }
-  return properties;
-}
diff --git a/libs/vkjson/vkjson_info.cc b/libs/vkjson/vkjson_info.cc
index 670eabb..38a0655 100644
--- a/libs/vkjson/vkjson_info.cc
+++ b/libs/vkjson/vkjson_info.cc
@@ -28,6 +28,7 @@
 #define VK_PROTOTYPES
 #include "vkjson.h"
 
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -37,6 +38,7 @@
 const uint32_t unsignedNegOne = (uint32_t)(-1);
 
 struct Options {
+  bool instance = false;
   uint32_t device_index = unsignedNegOne;
   std::string device_name;
   std::string output_file;
@@ -45,7 +47,9 @@
 bool ParseOptions(int argc, char* argv[], Options* options) {
   for (int i = 1; i < argc; ++i) {
     std::string arg(argv[i]);
-    if (arg == "--first" || arg == "-f") {
+    if (arg == "--instance" || arg == "-i") {
+      options->instance = true;
+    } else if (arg == "--first" || arg == "-f") {
       options->device_index = 0;
     } else {
       ++i;
@@ -71,26 +75,64 @@
       }
     }
   }
+  if (options->instance && (options->device_index != unsignedNegOne ||
+                            !options->device_name.empty())) {
+    std::cerr << "Specifying a specific device is incompatible with dumping "
+                 "the whole instance." << std::endl;
+    return false;
+  }
   if (options->device_index != unsignedNegOne && !options->device_name.empty()) {
     std::cerr << "Must specify only one of device index and device name."
               << std::endl;
     return false;
   }
-  if (!options->output_file.empty() && options->device_index == unsignedNegOne &&
-      options->device_name.empty()) {
-    std::cerr << "Must specify device index or device name when specifying "
-                 "output file"
+  if (options->instance && options->output_file.empty()) {
+    std::cerr << "Must specify an output file when dumping the whole instance."
               << std::endl;
     return false;
   }
+  if (!options->output_file.empty() && !options->instance &&
+      options->device_index == unsignedNegOne && options->device_name.empty()) {
+    std::cerr << "Must specify instance, device index, or device name when "
+                 "specifying "
+                 "output file." << std::endl;
+    return false;
+  }
   return true;
 }
 
-bool DumpProperties(const VkJsonAllProperties& props, const Options& options) {
-  std::string device_name(props.properties.deviceName);
-  std::string output_file = options.output_file;
-  if (output_file.empty())
-    output_file = device_name + ".json";
+bool Dump(const VkJsonInstance& instance, const Options& options) {
+  const VkJsonDevice* out_device = nullptr;
+  if (options.device_index != unsignedNegOne) {
+    if (static_cast<uint32_t>(options.device_index) >=
+        instance.devices.size()) {
+      std::cerr << "Error: device " << options.device_index
+                << " requested but only " << instance.devices.size()
+                << " devices found." << std::endl;
+      return false;
+    }
+    out_device = &instance.devices[options.device_index];
+  } else if (!options.device_name.empty()) {
+    for (const auto& device : instance.devices) {
+      if (device.properties.deviceName == options.device_name) {
+        out_device = &device;
+      }
+    }
+    if (!out_device) {
+      std::cerr << "Error: device '" << options.device_name
+                << "' requested but not found." << std::endl;
+      return false;
+    }
+  }
+
+  std::string output_file;
+  if (options.output_file.empty()) {
+    assert(out_device);
+    output_file.assign(out_device->properties.deviceName);
+    output_file.append(".json");
+  } else {
+    output_file = options.output_file;
+  }
   FILE* file = nullptr;
   if (output_file == "-") {
     file = stdout;
@@ -102,13 +144,17 @@
     }
   }
 
-  std::string json = VkJsonAllPropertiesToJson(props) + '\n';
+  std::string json = out_device ? VkJsonDeviceToJson(*out_device)
+                                : VkJsonInstanceToJson(instance);
   fwrite(json.data(), 1, json.size(), file);
+  fputc('\n', file);
 
   if (output_file != "-") {
     fclose(file);
-    std::cout << "Wrote file " << output_file << " for device " << device_name
-              << "." << std::endl;
+    std::cout << "Wrote file " << output_file;
+    if (out_device)
+      std::cout << " for device " << out_device->properties.deviceName;
+    std::cout << "." << std::endl;
   }
   return true;
 }
@@ -118,79 +164,16 @@
   if (!ParseOptions(argc, argv, &options))
     return 1;
 
-  const VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
-                                      nullptr,
-                                      "vkjson_info",
-                                      1,
-                                      "",
-                                      0,
-                                      VK_API_VERSION_1_0};
-  VkInstanceCreateInfo instance_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
-                                        nullptr,
-                                        0,
-                                        &app_info,
-                                        0,
-                                        nullptr,
-                                        0,
-                                        nullptr};
-  VkInstance instance;
-  VkResult result = vkCreateInstance(&instance_info, nullptr, &instance);
-  if (result != VK_SUCCESS) {
-    std::cerr << "Error: vkCreateInstance failed with error: " << result
-              << "." << std::endl;
-    return 1;
-  }
-
-  uint32_t device_count = 0;
-  result = vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
-  if (result != VK_SUCCESS) {
-    std::cerr << "Error: vkEnumeratePhysicalDevices failed with error "
-              << result << "." << std::endl;
-    return 1;
-  }
-  if (device_count == 0) {
-    std::cerr << "Error: no Vulkan device found.";
-    return 1;
-  }
-
-  std::vector<VkPhysicalDevice> physical_devices(device_count,
-                                                 VkPhysicalDevice());
-  result = vkEnumeratePhysicalDevices(instance, &device_count,
-                                      physical_devices.data());
-  if (result != VK_SUCCESS) {
-    std::cerr << "Error: vkEnumeratePhysicalDevices failed with error "
-              << result << std::endl;
-    return 1;
-  }
-
-  if (options.device_index != unsignedNegOne) {
-    if (static_cast<uint32_t>(options.device_index) >= device_count) {
-      std::cerr << "Error: device " << options.device_index
-                << " requested but only " << device_count << " found."
-                << std::endl;
-      return 1;
+  VkJsonInstance instance = VkJsonGetInstance();
+  if (options.instance || options.device_index != unsignedNegOne ||
+      !options.device_name.empty()) {
+    Dump(instance, options);
+  } else {
+    for (uint32_t i = 0, n = instance.devices.size(); i < n; i++) {
+      options.device_index = i;
+      Dump(instance, options);
     }
-    auto props = VkJsonGetAllProperties(physical_devices[options.device_index]);
-    if (!DumpProperties(props, options))
-      return 1;
-    return 0;
   }
 
-  bool found = false;
-  for (auto physical_device : physical_devices) {
-    auto props = VkJsonGetAllProperties(physical_device);
-    if (!options.device_name.empty() &&
-        options.device_name != props.properties.deviceName)
-      continue;
-    if (!DumpProperties(props, options))
-      return 1;
-    found = true;
-  }
-
-  if (!found) {
-    std::cerr << "Error: device " << options.device_name << " not found."
-              << std::endl;
-    return 1;
-  }
   return 0;
 }
diff --git a/libs/vkjson/vkjson_instance.cc b/libs/vkjson/vkjson_instance.cc
new file mode 100644
index 0000000..f1cd98d
--- /dev/null
+++ b/libs/vkjson/vkjson_instance.cc
@@ -0,0 +1,171 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (c) 2015-2016 The Khronos Group Inc.
+// Copyright (c) 2015-2016 Valve Corporation
+// Copyright (c) 2015-2016 LunarG, Inc.
+// Copyright (c) 2015-2016 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and/or associated documentation files (the "Materials"), to
+// deal in the Materials without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Materials, and to permit persons to whom the Materials are
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice(s) and this permission notice shall be included in
+// all copies or substantial portions of the Materials.
+//
+// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+//
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
+// USE OR OTHER DEALINGS IN THE MATERIALS.
+///////////////////////////////////////////////////////////////////////////////
+
+#define VK_PROTOTYPES
+#include "vkjson.h"
+
+#include <utility>
+
+namespace {
+bool EnumerateExtensions(const char* layer_name,
+                         std::vector<VkExtensionProperties>* extensions) {
+  VkResult result;
+  uint32_t count = 0;
+  result = vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
+  if (result != VK_SUCCESS)
+    return false;
+  extensions->resize(count);
+  result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
+                                                  extensions->data());
+  if (result != VK_SUCCESS)
+    return false;
+  return true;
+}
+
+}  // anonymous namespace
+
+VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) {
+  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());
+  }
+
+  // Only device extensions.
+  // TODO(piman): do we want to show layer extensions?
+  uint32_t extension_count = 0;
+  vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
+                                       &extension_count, nullptr);
+  if (extension_count > 0) {
+    device.extensions.resize(extension_count);
+    vkEnumerateDeviceExtensionProperties(
+        physical_device, nullptr, &extension_count, device.extensions.data());
+  }
+
+  uint32_t layer_count = 0;
+  vkEnumerateDeviceLayerProperties(physical_device, &layer_count, nullptr);
+  if (layer_count > 0) {
+    device.layers.resize(layer_count);
+    vkEnumerateDeviceLayerProperties(physical_device, &layer_count,
+                                     device.layers.data());
+  }
+
+  VkFormatProperties format_properties = {};
+  for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
+       format <= VK_FORMAT_END_RANGE;
+       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));
+    }
+  }
+  return device;
+}
+
+VkJsonInstance VkJsonGetInstance() {
+  VkJsonInstance instance;
+  VkResult result;
+  uint32_t count;
+
+  count = 0;
+  result = vkEnumerateInstanceLayerProperties(&count, nullptr);
+  if (result != VK_SUCCESS)
+    return VkJsonInstance();
+  if (count > 0) {
+    std::vector<VkLayerProperties> layers(count);
+    result = vkEnumerateInstanceLayerProperties(&count, layers.data());
+    if (result != VK_SUCCESS)
+      return VkJsonInstance();
+    instance.layers.reserve(count);
+    for (auto& layer : layers) {
+      instance.layers.push_back(VkJsonLayer{layer, std::vector<VkExtensionProperties>()});
+      if (!EnumerateExtensions(layer.layerName,
+                               &instance.layers.back().extensions))
+        return VkJsonInstance();
+    }
+  }
+
+  if (!EnumerateExtensions(nullptr, &instance.extensions))
+    return VkJsonInstance();
+
+  std::vector<const char*> layer_names;
+  layer_names.reserve(instance.layers.size());
+  for (auto& layer : instance.layers)
+    layer_names.push_back(layer.properties.layerName);
+
+  const VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
+                                      nullptr,
+                                      "vkjson_info",
+                                      1,
+                                      "",
+                                      0,
+                                      VK_API_VERSION_1_0};
+  VkInstanceCreateInfo instance_info = {
+      VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+      nullptr,
+      0,
+      &app_info,
+      static_cast<uint32_t>(layer_names.size()),
+      layer_names.data(),
+      0,
+      nullptr};
+  VkInstance vkinstance;
+  result = vkCreateInstance(&instance_info, nullptr, &vkinstance);
+  if (result != VK_SUCCESS)
+    return VkJsonInstance();
+
+  count = 0;
+  result = vkEnumeratePhysicalDevices(vkinstance, &count, nullptr);
+  if (result != VK_SUCCESS) {
+    vkDestroyInstance(vkinstance, nullptr);
+    return VkJsonInstance();
+  }
+  std::vector<VkPhysicalDevice> devices(count, VK_NULL_HANDLE);
+  result = vkEnumeratePhysicalDevices(vkinstance, &count, devices.data());
+  if (result != VK_SUCCESS) {
+    vkDestroyInstance(vkinstance, nullptr);
+    return VkJsonInstance();
+  }
+
+  instance.devices.reserve(devices.size());
+  for (auto device : devices)
+    instance.devices.emplace_back(VkJsonGetDevice(device));
+
+  vkDestroyInstance(vkinstance, nullptr);
+  return instance;
+}
diff --git a/libs/vkjson/vkjson_unittest.cc b/libs/vkjson/vkjson_unittest.cc
index ac9066f..2041959 100644
--- a/libs/vkjson/vkjson_unittest.cc
+++ b/libs/vkjson/vkjson_unittest.cc
@@ -52,37 +52,39 @@
   std::string errors;
   bool result = false;
 
+  VkJsonInstance instance;
+  instance.devices.resize(1);
+  VkJsonDevice& device = instance.devices[0];
+
   const char name[] = "Test device";
-  VkJsonAllProperties device_props;
-  memcpy(device_props.properties.deviceName, name, sizeof(name));
-  device_props.properties.limits.maxImageDimension1D = 3;
-  device_props.properties.limits.maxSamplerLodBias = 3.5f;
-  device_props.properties.limits.bufferImageGranularity = 0x1ffffffffull;
-  device_props.properties.limits.maxViewportDimensions[0] = 1;
-  device_props.properties.limits.maxViewportDimensions[1] = 2;
+  memcpy(device.properties.deviceName, name, sizeof(name));
+  device.properties.limits.maxImageDimension1D = 3;
+  device.properties.limits.maxSamplerLodBias = 3.5f;
+  device.properties.limits.bufferImageGranularity = 0x1ffffffffull;
+  device.properties.limits.maxViewportDimensions[0] = 1;
+  device.properties.limits.maxViewportDimensions[1] = 2;
   VkFormatProperties format_props = {
       VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT,
       VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,
       VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT};
-  device_props.formats.insert(
-      std::make_pair(VK_FORMAT_R8_UNORM, format_props));
-  device_props.formats.insert(
-      std::make_pair(VK_FORMAT_R8G8_UNORM, format_props));
-  std::string json = VkJsonAllPropertiesToJson(device_props);
+  device.formats.insert(std::make_pair(VK_FORMAT_R8_UNORM, format_props));
+  device.formats.insert(std::make_pair(VK_FORMAT_R8G8_UNORM, format_props));
+
+  std::string json = VkJsonInstanceToJson(instance);
   std::cout << json << std::endl;
 
-  VkJsonAllProperties device_props2;
-  result = VkJsonAllPropertiesFromJson(json, &device_props2, &errors);
+  VkJsonInstance instance2;
+  result = VkJsonInstanceFromJson(json, &instance2, &errors);
   EXPECT(result);
   if (!result)
     std::cout << "Error: " << errors << std::endl;
+  const VkJsonDevice& device2 = instance2.devices.at(0);
 
-  EXPECT(!memcmp(&device_props.properties,
-                 &device_props2.properties,
-                 sizeof(device_props.properties)));
-  for (auto& kv : device_props.formats) {
-    auto it = device_props2.formats.find(kv.first);
-    EXPECT(it != device_props2.formats.end());
+  EXPECT(!memcmp(&device.properties, &device2.properties,
+                 sizeof(device.properties)));
+  for (auto& kv : device.formats) {
+    auto it = device2.formats.find(kv.first);
+    EXPECT(it != device2.formats.end());
     EXPECT(!memcmp(&kv.second, &it->second, sizeof(kv.second)));
   }