diff options
Diffstat (limited to 'vulkan')
-rw-r--r-- | vulkan/Android.bp | 1 | ||||
-rw-r--r-- | vulkan/include/vulkan/vulkan_loader_data.h | 33 | ||||
-rw-r--r-- | vulkan/libvulkan/Android.bp | 5 | ||||
-rw-r--r-- | vulkan/libvulkan/api.cpp | 37 | ||||
-rw-r--r-- | vulkan/libvulkan/driver.cpp | 13 | ||||
-rw-r--r-- | vulkan/libvulkan/layers_extensions.cpp | 47 | ||||
-rw-r--r-- | vulkan/libvulkan/swapchain.cpp | 140 | ||||
-rw-r--r-- | vulkan/libvulkan/vulkan_loader_data.cpp | 24 | ||||
-rw-r--r-- | vulkan/vkjson/.clang-format | 1 | ||||
-rw-r--r-- | vulkan/vkjson/Android.bp | 52 | ||||
-rw-r--r-- | vulkan/vkjson/vkjson.cc | 1125 | ||||
-rw-r--r-- | vulkan/vkjson/vkjson.h | 162 | ||||
-rw-r--r-- | vulkan/vkjson/vkjson_info.cc | 184 | ||||
-rw-r--r-- | vulkan/vkjson/vkjson_instance.cc | 417 | ||||
-rw-r--r-- | vulkan/vkjson/vkjson_unittest.cc | 101 |
15 files changed, 2245 insertions, 97 deletions
diff --git a/vulkan/Android.bp b/vulkan/Android.bp index a49b6ddde2..b15bed99c5 100644 --- a/vulkan/Android.bp +++ b/vulkan/Android.bp @@ -55,4 +55,5 @@ subdirs = [ "nulldrv", "libvulkan", "tools", + "vkjson", ] diff --git a/vulkan/include/vulkan/vulkan_loader_data.h b/vulkan/include/vulkan/vulkan_loader_data.h deleted file mode 100644 index 8ea46666c5..0000000000 --- a/vulkan/include/vulkan/vulkan_loader_data.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 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. - */ - -#ifndef VULKAN_VULKAN_LOADER_DATA_H -#define VULKAN_VULKAN_LOADER_DATA_H - -#include <string> - -struct android_namespace_t; - -namespace vulkan { - struct LoaderData { - std::string layer_path; - android_namespace_t* app_namespace; - - __attribute__((visibility("default"))) static LoaderData& GetInstance(); - }; -} - -#endif diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index b55fa27a76..7f4f2c4ab3 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -61,7 +61,6 @@ cc_library_shared { "layers_extensions.cpp", "stubhal.cpp", "swapchain.cpp", - "vulkan_loader_data.cpp", ], export_header_lib_headers: ["vulkan_headers"], @@ -69,10 +68,14 @@ cc_library_shared { "vulkan_headers", ], shared_libs: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", "libziparchive", "libhardware", "libsync", "libbase", + "libhidlbase", + "libhidltransport", "liblog", "libui", "libgraphicsenv", diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp index d840786ae5..673a066182 100644 --- a/vulkan/libvulkan/api.cpp +++ b/vulkan/libvulkan/api.cpp @@ -29,14 +29,17 @@ #include <new> #include <utility> +#include <android-base/strings.h> #include <cutils/properties.h> #include <log/log.h> #include <vulkan/vk_layer_interface.h> +#include <graphicsenv/GraphicsEnv.h> #include "api.h" #include "driver.h" #include "layers_extensions.h" + namespace vulkan { namespace api { @@ -121,15 +124,33 @@ class OverrideLayerNames { if (!is_instance_ || !driver::Debuggable()) return; - ParseDebugVulkanLayers(); - property_list(ParseDebugVulkanLayer, this); + GetLayersFromSettings(); - // sort by priorities - auto& arr = implicit_layers_; - std::sort(arr.elements, arr.elements + arr.count, - [](const ImplicitLayer& a, const ImplicitLayer& b) { - return (a.priority < b.priority); - }); + // If no layers specified via Settings, check legacy properties + if (implicit_layers_.count <= 0) { + ParseDebugVulkanLayers(); + property_list(ParseDebugVulkanLayer, this); + + // sort by priorities + auto& arr = implicit_layers_; + std::sort(arr.elements, arr.elements + arr.count, + [](const ImplicitLayer& a, const ImplicitLayer& b) { + return (a.priority < b.priority); + }); + } + } + + void GetLayersFromSettings() { + // These will only be available if conditions are met in GraphicsEnvironemnt + // gpu_debug_layers = layer1:layer2:layerN + const std::string layers = android::GraphicsEnv::getInstance().getDebugLayers(); + if (!layers.empty()) { + ALOGV("Debug layer list: %s", layers.c_str()); + std::vector<std::string> paths = android::base::Split(layers, ":"); + for (uint32_t i = 0; i < paths.size(); i++) { + AddImplicitLayer(int(i), paths[i].c_str(), paths[i].length()); + } + } } void ParseDebugVulkanLayers() { diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 4beb315a65..56bc35ec70 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -27,6 +27,8 @@ #include <log/log.h> #include <android/dlext.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <configstore/Utils.h> #include <cutils/properties.h> #include <graphicsenv/GraphicsEnv.h> #include <utils/Vector.h> @@ -36,6 +38,9 @@ #include "driver.h" #include "stubhal.h" +using namespace android::hardware::configstore; +using namespace android::hardware::configstore::V1_0; + // TODO(b/37049319) Get this from a header once one exists extern "C" { android_namespace_t* android_get_exported_namespace(const char*); @@ -884,6 +889,14 @@ VkResult EnumerateDeviceExtensionProperties( VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION}); + bool hdrBoardConfig = + getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>( + false); + if (hdrBoardConfig) { + loader_extensions.push_back({VK_EXT_HDR_METADATA_EXTENSION_NAME, + VK_EXT_HDR_METADATA_SPEC_VERSION}); + } + VkPhysicalDevicePresentationPropertiesANDROID presentation_properties; if (QueryPresentationProperties(physicalDevice, &presentation_properties) && presentation_properties.sharedImage) { diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp index 05856d3c1c..3a59208446 100644 --- a/vulkan/libvulkan/layers_extensions.cpp +++ b/vulkan/libvulkan/layers_extensions.cpp @@ -29,11 +29,10 @@ #include <android/dlext.h> #include <android-base/strings.h> #include <cutils/properties.h> +#include <graphicsenv/GraphicsEnv.h> #include <log/log.h> #include <ziparchive/zip_archive.h> -#include <vulkan/vulkan_loader_data.h> - // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and // not a good long-term solution. Having a hard-coded enum of extensions is // bad, of course. Representing sets of extensions (requested, supported, etc.) @@ -69,11 +68,16 @@ const char kSystemLayerLibraryDir[] = "/data/local/debug/vulkan"; class LayerLibrary { public: - explicit LayerLibrary(const std::string& path) - : path_(path), dlhandle_(nullptr), refcount_(0) {} + explicit LayerLibrary(const std::string& path, + const std::string& filename) + : path_(path), + filename_(filename), + dlhandle_(nullptr), + refcount_(0) {} LayerLibrary(LayerLibrary&& other) : path_(std::move(other.path_)), + filename_(std::move(other.filename_)), dlhandle_(other.dlhandle_), refcount_(other.refcount_) { other.dlhandle_ = nullptr; @@ -94,9 +98,14 @@ class LayerLibrary { const char* gpa_name, size_t gpa_name_len) const; + const std::string GetFilename() { return filename_; } + private: const std::string path_; + // Track the filename alone so we can detect duplicates + const std::string filename_; + std::mutex mutex_; void* dlhandle_; size_t refcount_; @@ -111,7 +120,7 @@ bool LayerLibrary::Open() { // any symbol dependencies will be resolved by system libraries. They // can't safely use libc++_shared, for example. Which is one reason // (among several) we only allow them in non-user builds. - auto app_namespace = LoaderData::GetInstance().app_namespace; + auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace(); if (app_namespace && !android::base::StartsWith(path_, kSystemLayerLibraryDir)) { android_dlextinfo dlextinfo = {}; @@ -305,8 +314,8 @@ void* LayerLibrary::GetGPA(const Layer& layer, std::vector<LayerLibrary> g_layer_libraries; std::vector<Layer> g_instance_layers; -void AddLayerLibrary(const std::string& path) { - LayerLibrary library(path); +void AddLayerLibrary(const std::string& path, const std::string& filename) { + LayerLibrary library(path + "/" + filename, filename); if (!library.Open()) return; @@ -398,7 +407,25 @@ void DiscoverLayersInPathList(const std::string& pathstr) { ForEachFileInPath(path, [&](const std::string& filename) { if (android::base::StartsWith(filename, "libVkLayer") && android::base::EndsWith(filename, ".so")) { - AddLayerLibrary(path + "/" + filename); + + // Check to ensure we haven't seen this layer already + // Let the first instance of the shared object be enumerated + // We're searching for layers in following order: + // 1. system path + // 2. libraryPermittedPath (if enabled) + // 3. libraryPath + + bool duplicate = false; + for (auto& layer : g_layer_libraries) { + if (layer.GetFilename() == filename) { + ALOGV("Skipping duplicate layer %s in %s", + filename.c_str(), path.c_str()); + duplicate = true; + } + } + + if (!duplicate) + AddLayerLibrary(path, filename); } }); } @@ -428,8 +455,8 @@ void DiscoverLayers() { prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { DiscoverLayersInPathList(kSystemLayerLibraryDir); } - if (!LoaderData::GetInstance().layer_path.empty()) - DiscoverLayersInPathList(LoaderData::GetInstance().layer_path); + if (!android::GraphicsEnv::getInstance().getLayerPaths().empty()) + DiscoverLayersInPathList(android::GraphicsEnv::getInstance().getLayerPaths()); } uint32_t GetLayerCount() { diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 03e6ee0870..3db8a3962e 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -185,6 +185,7 @@ class TimingInfo { struct Surface { android::sp<ANativeWindow> window; VkSwapchainKHR swapchain_handle; + uint64_t consumer_usage; }; VkSurfaceKHR HandleFromSurface(Surface* surface) { @@ -496,9 +497,18 @@ VkResult CreateAndroidSurfaceKHR( surface->window = pCreateInfo->window; surface->swapchain_handle = VK_NULL_HANDLE; + int err = native_window_get_consumer_usage(surface->window.get(), + &surface->consumer_usage); + if (err != android::NO_ERROR) { + ALOGE("native_window_get_consumer_usage() failed: %s (%d)", + strerror(-err), err); + surface->~Surface(); + allocator->pfnFree(allocator->pUserData, surface); + return VK_ERROR_INITIALIZATION_FAILED; + } // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. - int err = + err = native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); if (err != 0) { // TODO(jessehall): Improve error reporting. Can we enumerate possible @@ -536,9 +546,45 @@ void DestroySurfaceKHR(VkInstance instance, VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/, uint32_t /*queue_family*/, - VkSurfaceKHR /*surface*/, + VkSurfaceKHR surface_handle, VkBool32* supported) { - *supported = VK_TRUE; + const Surface* surface = SurfaceFromHandle(surface_handle); + if (!surface) { + return VK_ERROR_SURFACE_LOST_KHR; + } + const ANativeWindow* window = surface->window.get(); + + int query_value; + int err = window->query(window, NATIVE_WINDOW_FORMAT, &query_value); + if (err != 0 || query_value < 0) { + ALOGE("NATIVE_WINDOW_FORMAT query failed: %s (%d) value=%d", + strerror(-err), err, query_value); + return VK_ERROR_SURFACE_LOST_KHR; + } + + android_pixel_format native_format = + static_cast<android_pixel_format>(query_value); + + bool format_supported = false; + switch (native_format) { + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_RGB_565: + format_supported = true; + break; + default: + break; + } + + // USAGE_CPU_READ_MASK 0xFUL + // USAGE_CPU_WRITE_MASK (0xFUL << 4) + // The currently used bits are as below: + // USAGE_CPU_READ_RARELY = 2UL + // USAGE_CPU_READ_OFTEN = 3UL + // USAGE_CPU_WRITE_RARELY = (2UL << 4) + // USAGE_CPU_WRITE_OFTEN = (3UL << 4) + *supported = static_cast<VkBool32>(format_supported || + (surface->consumer_usage & 0xFFUL) == 0); + return VK_SUCCESS; } @@ -573,8 +619,15 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( } // TODO(jessehall): Figure out what the min/max values should be. - capabilities->minImageCount = 2; - capabilities->maxImageCount = 3; + int max_buffer_count; + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count); + if (err != 0) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2; + capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count); capabilities->currentExtent = VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)}; @@ -744,11 +797,32 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR( VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, - VkSurfaceKHR /*surface*/, + VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes) { + int err; + int query_value; + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + + err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); + if (err != 0 || query_value < 0) { + ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) value=%d", + strerror(-err), err, query_value); + return VK_ERROR_SURFACE_LOST_KHR; + } + uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value); + + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value); + if (err != 0 || query_value < 0) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d", + strerror(-err), err, query_value); + return VK_ERROR_SURFACE_LOST_KHR; + } + uint32_t max_buffer_count = static_cast<uint32_t>(query_value); + android::Vector<VkPresentModeKHR> present_modes; - present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); + if (min_undequeued_buffers + 1 < max_buffer_count) + present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); VkPhysicalDevicePresentationPropertiesANDROID present_properties; @@ -1194,19 +1268,19 @@ VkResult CreateSwapchainKHR(VkDevice device, // // TODO(jessehall): The error path here is the same as DestroySwapchain, // but not the non-error path. Should refactor/unify. - if (!swapchain->shared) { - for (uint32_t i = 0; i < num_images; i++) { - Swapchain::Image& img = swapchain->images[i]; - if (img.dequeued) { + for (uint32_t i = 0; i < num_images; i++) { + Swapchain::Image& img = swapchain->images[i]; + if (img.dequeued) { + if (!swapchain->shared) { surface.window->cancelBuffer(surface.window.get(), img.buffer.get(), img.dequeue_fence); img.dequeue_fence = -1; img.dequeued = false; } - if (result != VK_SUCCESS) { - if (img.image) - dispatch.DestroyImage(device, img.image, nullptr); - } + } + if (result != VK_SUCCESS) { + if (img.image) + dispatch.DestroyImage(device, img.image, nullptr); } } @@ -1650,15 +1724,39 @@ VkResult GetSwapchainStatusKHR( } VKAPI_ATTR void SetHdrMetadataEXT( - VkDevice device, + VkDevice, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pHdrMetadataEXTs) { - // TODO: courtneygo: implement actual function - (void)device; - (void)swapchainCount; - (void)pSwapchains; - (void)pHdrMetadataEXTs; + + for (uint32_t idx = 0; idx < swapchainCount; idx++) { + Swapchain* swapchain = SwapchainFromHandle(pSwapchains[idx]); + if (!swapchain) + continue; + + if (swapchain->surface.swapchain_handle != pSwapchains[idx]) continue; + + ANativeWindow* window = swapchain->surface.window.get(); + + VkHdrMetadataEXT vulkanMetadata = pHdrMetadataEXTs[idx]; + const android_smpte2086_metadata smpteMetdata = { + {vulkanMetadata.displayPrimaryRed.x, + vulkanMetadata.displayPrimaryRed.y}, + {vulkanMetadata.displayPrimaryGreen.x, + vulkanMetadata.displayPrimaryGreen.y}, + {vulkanMetadata.displayPrimaryBlue.x, + vulkanMetadata.displayPrimaryBlue.y}, + {vulkanMetadata.whitePoint.x, vulkanMetadata.whitePoint.y}, + vulkanMetadata.maxLuminance, + vulkanMetadata.minLuminance}; + native_window_set_buffers_smpte2086_metadata(window, &smpteMetdata); + + const android_cta861_3_metadata cta8613Metadata = { + vulkanMetadata.maxContentLightLevel, + vulkanMetadata.maxFrameAverageLightLevel}; + native_window_set_buffers_cta861_3_metadata(window, &cta8613Metadata); + } + return; } diff --git a/vulkan/libvulkan/vulkan_loader_data.cpp b/vulkan/libvulkan/vulkan_loader_data.cpp deleted file mode 100644 index 0eda0af59a..0000000000 --- a/vulkan/libvulkan/vulkan_loader_data.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 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. - */ - -#include <vulkan/vulkan_loader_data.h> - -using namespace vulkan; - -LoaderData& LoaderData::GetInstance() { - static LoaderData loader_data = {}; - return loader_data; -} diff --git a/vulkan/vkjson/.clang-format b/vulkan/vkjson/.clang-format new file mode 100644 index 0000000000..3f19e61618 --- /dev/null +++ b/vulkan/vkjson/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Chromium diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp new file mode 100644 index 0000000000..e387165442 --- /dev/null +++ b/vulkan/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: [ + "libjsoncpp", + ], + 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: [ + "libjsoncpp_ndk", + ], + header_libs: [ + "vulkan_headers_ndk", + ], + sdk_version: "24", + stl: "libc++_static", +} diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc new file mode 100644 index 0000000000..62003839b7 --- /dev/null +++ b/vulkan/vkjson/vkjson.cc @@ -0,0 +1,1125 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +// 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. +/////////////////////////////////////////////////////////////////////////////// + +#include "vkjson.h" + +#include <assert.h> +#include <string.h> +#include <stdlib.h> + +#include <cmath> +#include <cinttypes> +#include <cstdio> +#include <limits> +#include <memory> +#include <sstream> +#include <type_traits> +#include <utility> + +#include <json/json.h> + +namespace { + +inline bool IsIntegral(double value) { +#if defined(ANDROID) + // Android NDK doesn't provide std::trunc yet + return trunc(value) == value; +#else + return std::trunc(value) == value; +#endif +} + +template <typename T> struct EnumTraits; +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 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 + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkExtent3D* extents) { + return + visitor->Visit("width", &extents->width) && + visitor->Visit("height", &extents->height) && + visitor->Visit("depth", &extents->depth); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkImageFormatProperties* properties) { + return + visitor->Visit("maxExtent", &properties->maxExtent) && + visitor->Visit("maxMipLevels", &properties->maxMipLevels) && + visitor->Visit("maxArrayLayers", &properties->maxArrayLayers) && + visitor->Visit("sampleCounts", &properties->sampleCounts) && + visitor->Visit("maxResourceSize", &properties->maxResourceSize); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceLimits* limits) { + return + visitor->Visit("maxImageDimension1D", &limits->maxImageDimension1D) && + visitor->Visit("maxImageDimension2D", &limits->maxImageDimension2D) && + visitor->Visit("maxImageDimension3D", &limits->maxImageDimension3D) && + visitor->Visit("maxImageDimensionCube", &limits->maxImageDimensionCube) && + visitor->Visit("maxImageArrayLayers", &limits->maxImageArrayLayers) && + visitor->Visit("maxTexelBufferElements", &limits->maxTexelBufferElements) && + visitor->Visit("maxUniformBufferRange", &limits->maxUniformBufferRange) && + visitor->Visit("maxStorageBufferRange", &limits->maxStorageBufferRange) && + visitor->Visit("maxPushConstantsSize", &limits->maxPushConstantsSize) && + visitor->Visit("maxMemoryAllocationCount", &limits->maxMemoryAllocationCount) && + visitor->Visit("maxSamplerAllocationCount", &limits->maxSamplerAllocationCount) && + visitor->Visit("bufferImageGranularity", &limits->bufferImageGranularity) && + visitor->Visit("sparseAddressSpaceSize", &limits->sparseAddressSpaceSize) && + visitor->Visit("maxBoundDescriptorSets", &limits->maxBoundDescriptorSets) && + visitor->Visit("maxPerStageDescriptorSamplers", &limits->maxPerStageDescriptorSamplers) && + visitor->Visit("maxPerStageDescriptorUniformBuffers", &limits->maxPerStageDescriptorUniformBuffers) && + visitor->Visit("maxPerStageDescriptorStorageBuffers", &limits->maxPerStageDescriptorStorageBuffers) && + visitor->Visit("maxPerStageDescriptorSampledImages", &limits->maxPerStageDescriptorSampledImages) && + visitor->Visit("maxPerStageDescriptorStorageImages", &limits->maxPerStageDescriptorStorageImages) && + visitor->Visit("maxPerStageDescriptorInputAttachments", &limits->maxPerStageDescriptorInputAttachments) && + visitor->Visit("maxPerStageResources", &limits->maxPerStageResources) && + visitor->Visit("maxDescriptorSetSamplers", &limits->maxDescriptorSetSamplers) && + visitor->Visit("maxDescriptorSetUniformBuffers", &limits->maxDescriptorSetUniformBuffers) && + visitor->Visit("maxDescriptorSetUniformBuffersDynamic", &limits->maxDescriptorSetUniformBuffersDynamic) && + visitor->Visit("maxDescriptorSetStorageBuffers", &limits->maxDescriptorSetStorageBuffers) && + visitor->Visit("maxDescriptorSetStorageBuffersDynamic", &limits->maxDescriptorSetStorageBuffersDynamic) && + visitor->Visit("maxDescriptorSetSampledImages", &limits->maxDescriptorSetSampledImages) && + visitor->Visit("maxDescriptorSetStorageImages", &limits->maxDescriptorSetStorageImages) && + visitor->Visit("maxDescriptorSetInputAttachments", &limits->maxDescriptorSetInputAttachments) && + visitor->Visit("maxVertexInputAttributes", &limits->maxVertexInputAttributes) && + visitor->Visit("maxVertexInputBindings", &limits->maxVertexInputBindings) && + visitor->Visit("maxVertexInputAttributeOffset", &limits->maxVertexInputAttributeOffset) && + visitor->Visit("maxVertexInputBindingStride", &limits->maxVertexInputBindingStride) && + visitor->Visit("maxVertexOutputComponents", &limits->maxVertexOutputComponents) && + visitor->Visit("maxTessellationGenerationLevel", &limits->maxTessellationGenerationLevel) && + visitor->Visit("maxTessellationPatchSize", &limits->maxTessellationPatchSize) && + visitor->Visit("maxTessellationControlPerVertexInputComponents", &limits->maxTessellationControlPerVertexInputComponents) && + visitor->Visit("maxTessellationControlPerVertexOutputComponents", &limits->maxTessellationControlPerVertexOutputComponents) && + visitor->Visit("maxTessellationControlPerPatchOutputComponents", &limits->maxTessellationControlPerPatchOutputComponents) && + visitor->Visit("maxTessellationControlTotalOutputComponents", &limits->maxTessellationControlTotalOutputComponents) && + visitor->Visit("maxTessellationEvaluationInputComponents", &limits->maxTessellationEvaluationInputComponents) && + visitor->Visit("maxTessellationEvaluationOutputComponents", &limits->maxTessellationEvaluationOutputComponents) && + visitor->Visit("maxGeometryShaderInvocations", &limits->maxGeometryShaderInvocations) && + visitor->Visit("maxGeometryInputComponents", &limits->maxGeometryInputComponents) && + visitor->Visit("maxGeometryOutputComponents", &limits->maxGeometryOutputComponents) && + visitor->Visit("maxGeometryOutputVertices", &limits->maxGeometryOutputVertices) && + visitor->Visit("maxGeometryTotalOutputComponents", &limits->maxGeometryTotalOutputComponents) && + visitor->Visit("maxFragmentInputComponents", &limits->maxFragmentInputComponents) && + visitor->Visit("maxFragmentOutputAttachments", &limits->maxFragmentOutputAttachments) && + visitor->Visit("maxFragmentDualSrcAttachments", &limits->maxFragmentDualSrcAttachments) && + visitor->Visit("maxFragmentCombinedOutputResources", &limits->maxFragmentCombinedOutputResources) && + visitor->Visit("maxComputeSharedMemorySize", &limits->maxComputeSharedMemorySize) && + visitor->Visit("maxComputeWorkGroupCount", &limits->maxComputeWorkGroupCount) && + visitor->Visit("maxComputeWorkGroupInvocations", &limits->maxComputeWorkGroupInvocations) && + visitor->Visit("maxComputeWorkGroupSize", &limits->maxComputeWorkGroupSize) && + visitor->Visit("subPixelPrecisionBits", &limits->subPixelPrecisionBits) && + visitor->Visit("subTexelPrecisionBits", &limits->subTexelPrecisionBits) && + visitor->Visit("mipmapPrecisionBits", &limits->mipmapPrecisionBits) && + visitor->Visit("maxDrawIndexedIndexValue", &limits->maxDrawIndexedIndexValue) && + visitor->Visit("maxDrawIndirectCount", &limits->maxDrawIndirectCount) && + visitor->Visit("maxSamplerLodBias", &limits->maxSamplerLodBias) && + visitor->Visit("maxSamplerAnisotropy", &limits->maxSamplerAnisotropy) && + visitor->Visit("maxViewports", &limits->maxViewports) && + visitor->Visit("maxViewportDimensions", &limits->maxViewportDimensions) && + visitor->Visit("viewportBoundsRange", &limits->viewportBoundsRange) && + visitor->Visit("viewportSubPixelBits", &limits->viewportSubPixelBits) && + visitor->Visit("minMemoryMapAlignment", &limits->minMemoryMapAlignment) && + visitor->Visit("minTexelBufferOffsetAlignment", &limits->minTexelBufferOffsetAlignment) && + visitor->Visit("minUniformBufferOffsetAlignment", &limits->minUniformBufferOffsetAlignment) && + visitor->Visit("minStorageBufferOffsetAlignment", &limits->minStorageBufferOffsetAlignment) && + visitor->Visit("minTexelOffset", &limits->minTexelOffset) && + visitor->Visit("maxTexelOffset", &limits->maxTexelOffset) && + visitor->Visit("minTexelGatherOffset", &limits->minTexelGatherOffset) && + visitor->Visit("maxTexelGatherOffset", &limits->maxTexelGatherOffset) && + visitor->Visit("minInterpolationOffset", &limits->minInterpolationOffset) && + visitor->Visit("maxInterpolationOffset", &limits->maxInterpolationOffset) && + visitor->Visit("subPixelInterpolationOffsetBits", &limits->subPixelInterpolationOffsetBits) && + visitor->Visit("maxFramebufferWidth", &limits->maxFramebufferWidth) && + visitor->Visit("maxFramebufferHeight", &limits->maxFramebufferHeight) && + visitor->Visit("maxFramebufferLayers", &limits->maxFramebufferLayers) && + visitor->Visit("framebufferColorSampleCounts", &limits->framebufferColorSampleCounts) && + visitor->Visit("framebufferDepthSampleCounts", &limits->framebufferDepthSampleCounts) && + visitor->Visit("framebufferStencilSampleCounts", &limits->framebufferStencilSampleCounts) && + visitor->Visit("framebufferNoAttachmentsSampleCounts", &limits->framebufferNoAttachmentsSampleCounts) && + visitor->Visit("maxColorAttachments", &limits->maxColorAttachments) && + visitor->Visit("sampledImageColorSampleCounts", &limits->sampledImageColorSampleCounts) && + visitor->Visit("sampledImageIntegerSampleCounts", &limits->sampledImageIntegerSampleCounts) && + visitor->Visit("sampledImageDepthSampleCounts", &limits->sampledImageDepthSampleCounts) && + visitor->Visit("sampledImageStencilSampleCounts", &limits->sampledImageStencilSampleCounts) && + visitor->Visit("storageImageSampleCounts", &limits->storageImageSampleCounts) && + visitor->Visit("maxSampleMaskWords", &limits->maxSampleMaskWords) && + visitor->Visit("timestampComputeAndGraphics", &limits->timestampComputeAndGraphics) && + visitor->Visit("timestampPeriod", &limits->timestampPeriod) && + visitor->Visit("maxClipDistances", &limits->maxClipDistances) && + visitor->Visit("maxCullDistances", &limits->maxCullDistances) && + visitor->Visit("maxCombinedClipAndCullDistances", &limits->maxCombinedClipAndCullDistances) && + visitor->Visit("discreteQueuePriorities", &limits->discreteQueuePriorities) && + visitor->Visit("pointSizeRange", &limits->pointSizeRange) && + visitor->Visit("lineWidthRange", &limits->lineWidthRange) && + visitor->Visit("pointSizeGranularity", &limits->pointSizeGranularity) && + visitor->Visit("lineWidthGranularity", &limits->lineWidthGranularity) && + visitor->Visit("strictLines", &limits->strictLines) && + visitor->Visit("standardSampleLocations", &limits->standardSampleLocations) && + visitor->Visit("optimalBufferCopyOffsetAlignment", &limits->optimalBufferCopyOffsetAlignment) && + visitor->Visit("optimalBufferCopyRowPitchAlignment", &limits->optimalBufferCopyRowPitchAlignment) && + visitor->Visit("nonCoherentAtomSize", &limits->nonCoherentAtomSize); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceSparseProperties* properties) { + return + visitor->Visit("residencyStandard2DBlockShape", &properties->residencyStandard2DBlockShape) && + visitor->Visit("residencyStandard2DMultisampleBlockShape", &properties->residencyStandard2DMultisampleBlockShape) && + visitor->Visit("residencyStandard3DBlockShape", &properties->residencyStandard3DBlockShape) && + visitor->Visit("residencyAlignedMipSize", &properties->residencyAlignedMipSize) && + visitor->Visit("residencyNonResidentStrict", &properties->residencyNonResidentStrict); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceProperties* properties) { + return + visitor->Visit("apiVersion", &properties->apiVersion) && + visitor->Visit("driverVersion", &properties->driverVersion) && + visitor->Visit("vendorID", &properties->vendorID) && + visitor->Visit("deviceID", &properties->deviceID) && + visitor->Visit("deviceType", &properties->deviceType) && + visitor->Visit("deviceName", &properties->deviceName) && + visitor->Visit("pipelineCacheUUID", &properties->pipelineCacheUUID) && + visitor->Visit("limits", &properties->limits) && + visitor->Visit("sparseProperties", &properties->sparseProperties); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceFeatures* features) { + return + visitor->Visit("robustBufferAccess", &features->robustBufferAccess) && + visitor->Visit("fullDrawIndexUint32", &features->fullDrawIndexUint32) && + visitor->Visit("imageCubeArray", &features->imageCubeArray) && + visitor->Visit("independentBlend", &features->independentBlend) && + visitor->Visit("geometryShader", &features->geometryShader) && + visitor->Visit("tessellationShader", &features->tessellationShader) && + visitor->Visit("sampleRateShading", &features->sampleRateShading) && + visitor->Visit("dualSrcBlend", &features->dualSrcBlend) && + visitor->Visit("logicOp", &features->logicOp) && + visitor->Visit("multiDrawIndirect", &features->multiDrawIndirect) && + visitor->Visit("drawIndirectFirstInstance", &features->drawIndirectFirstInstance) && + visitor->Visit("depthClamp", &features->depthClamp) && + visitor->Visit("depthBiasClamp", &features->depthBiasClamp) && + visitor->Visit("fillModeNonSolid", &features->fillModeNonSolid) && + visitor->Visit("depthBounds", &features->depthBounds) && + visitor->Visit("wideLines", &features->wideLines) && + visitor->Visit("largePoints", &features->largePoints) && + visitor->Visit("alphaToOne", &features->alphaToOne) && + visitor->Visit("multiViewport", &features->multiViewport) && + visitor->Visit("samplerAnisotropy", &features->samplerAnisotropy) && + visitor->Visit("textureCompressionETC2", &features->textureCompressionETC2) && + visitor->Visit("textureCompressionASTC_LDR", &features->textureCompressionASTC_LDR) && + visitor->Visit("textureCompressionBC", &features->textureCompressionBC) && + visitor->Visit("occlusionQueryPrecise", &features->occlusionQueryPrecise) && + visitor->Visit("pipelineStatisticsQuery", &features->pipelineStatisticsQuery) && + visitor->Visit("vertexPipelineStoresAndAtomics", &features->vertexPipelineStoresAndAtomics) && + visitor->Visit("fragmentStoresAndAtomics", &features->fragmentStoresAndAtomics) && + visitor->Visit("shaderTessellationAndGeometryPointSize", &features->shaderTessellationAndGeometryPointSize) && + visitor->Visit("shaderImageGatherExtended", &features->shaderImageGatherExtended) && + visitor->Visit("shaderStorageImageExtendedFormats", &features->shaderStorageImageExtendedFormats) && + visitor->Visit("shaderStorageImageMultisample", &features->shaderStorageImageMultisample) && + visitor->Visit("shaderStorageImageReadWithoutFormat", &features->shaderStorageImageReadWithoutFormat) && + visitor->Visit("shaderStorageImageWriteWithoutFormat", &features->shaderStorageImageWriteWithoutFormat) && + visitor->Visit("shaderUniformBufferArrayDynamicIndexing", &features->shaderUniformBufferArrayDynamicIndexing) && + visitor->Visit("shaderSampledImageArrayDynamicIndexing", &features->shaderSampledImageArrayDynamicIndexing) && + visitor->Visit("shaderStorageBufferArrayDynamicIndexing", &features->shaderStorageBufferArrayDynamicIndexing) && + visitor->Visit("shaderStorageImageArrayDynamicIndexing", &features->shaderStorageImageArrayDynamicIndexing) && + visitor->Visit("shaderClipDistance", &features->shaderClipDistance) && + visitor->Visit("shaderCullDistance", &features->shaderCullDistance) && + visitor->Visit("shaderFloat64", &features->shaderFloat64) && + visitor->Visit("shaderInt64", &features->shaderInt64) && + visitor->Visit("shaderInt16", &features->shaderInt16) && + visitor->Visit("shaderResourceResidency", &features->shaderResourceResidency) && + visitor->Visit("shaderResourceMinLod", &features->shaderResourceMinLod) && + visitor->Visit("sparseBinding", &features->sparseBinding) && + visitor->Visit("sparseResidencyBuffer", &features->sparseResidencyBuffer) && + visitor->Visit("sparseResidencyImage2D", &features->sparseResidencyImage2D) && + visitor->Visit("sparseResidencyImage3D", &features->sparseResidencyImage3D) && + visitor->Visit("sparseResidency2Samples", &features->sparseResidency2Samples) && + visitor->Visit("sparseResidency4Samples", &features->sparseResidency4Samples) && + visitor->Visit("sparseResidency8Samples", &features->sparseResidency8Samples) && + visitor->Visit("sparseResidency16Samples", &features->sparseResidency16Samples) && + visitor->Visit("sparseResidencyAliased", &features->sparseResidencyAliased) && + visitor->Visit("variableMultisampleRate", &features->variableMultisampleRate) && + visitor->Visit("inheritedQueries", &features->inheritedQueries); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkJsonExtVariablePointerFeatures* features) { + return visitor->Visit("variablePointerFeaturesKHR", + &features->variable_pointer_features_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkMemoryType* type) { + return + visitor->Visit("propertyFlags", &type->propertyFlags) && + visitor->Visit("heapIndex", &type->heapIndex); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkMemoryHeap* heap) { + return + visitor->Visit("size", &heap->size) && + visitor->Visit("flags", &heap->flags); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceMemoryProperties* properties) { + return + visitor->Visit("memoryTypeCount", &properties->memoryTypeCount) && + visitor->VisitArray("memoryTypes", properties->memoryTypeCount, &properties->memoryTypes) && + visitor->Visit("memoryHeapCount", &properties->memoryHeapCount) && + visitor->VisitArray("memoryHeaps", properties->memoryHeapCount, &properties->memoryHeaps); +} + +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) && + visitor->Visit("queueCount", &properties->queueCount) && + visitor->Visit("timestampValidBits", &properties->timestampValidBits) && + visitor->Visit("minImageTransferGranularity", &properties->minImageTransferGranularity); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkExtensionProperties* properties) { + return + visitor->Visit("extensionName", &properties->extensionName) && + visitor->Visit("specVersion", &properties->specVersion); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkLayerProperties* properties) { + return + visitor->Visit("layerName", &properties->layerName) && + visitor->Visit("specVersion", &properties->specVersion) && + visitor->Visit("implementationVersion", &properties->implementationVersion) && + visitor->Visit("description", &properties->description); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkFormatProperties* properties) { + return + visitor->Visit("linearTilingFeatures", &properties->linearTilingFeatures) && + visitor->Visit("optimalTilingFeatures", &properties->optimalTilingFeatures) && + visitor->Visit("bufferFeatures", &properties->bufferFeatures); +} + +template <typename Visitor> +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, 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) { + 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) { + 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> +using EnableForArithmetic = + typename std::enable_if<std::is_arithmetic<T>::value, void>::type; + +template <typename T> +using EnableForStruct = + typename std::enable_if<std::is_class<T>::value, void>::type; + +template <typename T> +using EnableForEnum = + typename std::enable_if<std::is_enum<T>::value, void>::type; + +template <typename T, typename = EnableForStruct<T>, typename = void> +Json::Value ToJsonValue(const T& value); + +template <typename T, typename = EnableForArithmetic<T>> +inline Json::Value ToJsonValue(const T& value) { + return Json::Value(static_cast<double>(value)); +} + +inline Json::Value ToJsonValue(const uint64_t& value) { + char string[19] = {0}; // "0x" + 16 digits + terminal \0 + snprintf(string, sizeof(string), "0x%016" PRIx64, value); + return Json::Value(string); +} + +template <typename T, typename = EnableForEnum<T>, typename = void, + typename = void> +inline Json::Value ToJsonValue(const T& value) { + return Json::Value(static_cast<double>(value)); +} + +template <typename T> +inline Json::Value ArrayToJsonValue(uint32_t count, const T* values) { + Json::Value array(Json::arrayValue); + for (unsigned int i = 0; i < count; ++i) array.append(ToJsonValue(values[i])); + return array; +} + +template <typename T, unsigned int N> +inline Json::Value ToJsonValue(const T (&value)[N]) { + return ArrayToJsonValue(N, value); +} + +template <size_t N> +inline Json::Value ToJsonValue(const char (&value)[N]) { + assert(strlen(value) < N); + return Json::Value(value); +} + +template <typename T> +inline Json::Value ToJsonValue(const std::vector<T>& value) { + assert(value.size() <= std::numeric_limits<uint32_t>::max()); + return ArrayToJsonValue(static_cast<uint32_t>(value.size()), value.data()); +} + +template <typename F, typename S> +inline Json::Value ToJsonValue(const std::pair<F, S>& value) { + Json::Value array(Json::arrayValue); + array.append(ToJsonValue(value.first)); + array.append(ToJsonValue(value.second)); + return array; +} + +template <typename F, typename S> +inline Json::Value ToJsonValue(const std::map<F, S>& value) { + Json::Value array(Json::arrayValue); + for (auto& kv : value) array.append(ToJsonValue(kv)); + return array; +} + +class JsonWriterVisitor { + public: + JsonWriterVisitor() : object_(Json::objectValue) {} + + ~JsonWriterVisitor() {} + + template <typename T> bool Visit(const char* key, const T* value) { + object_[key] = ToJsonValue(*value); + return true; + } + + template <typename T, uint32_t N> + bool VisitArray(const char* key, uint32_t count, const T (*value)[N]) { + assert(count <= N); + object_[key] = ArrayToJsonValue(count, *value); + return true; + } + + Json::Value get_object() const { return object_; } + + private: + Json::Value object_; +}; + +template <typename Visitor, typename T> +inline void VisitForWrite(Visitor* visitor, const T& t) { + Iterate(visitor, const_cast<T*>(&t)); +} + +template <typename T, typename /*= EnableForStruct<T>*/, typename /*= void*/> +Json::Value ToJsonValue(const T& value) { + JsonWriterVisitor visitor; + VisitForWrite(&visitor, value); + return visitor.get_object(); +} + +template <typename T, typename = EnableForStruct<T>> +bool AsValue(Json::Value* json_value, T* t); + +inline bool AsValue(Json::Value* json_value, int32_t* value) { + if (json_value->type() != Json::realValue) return false; + double d = json_value->asDouble(); + if (!IsIntegral(d) || + d < static_cast<double>(std::numeric_limits<int32_t>::min()) || + d > static_cast<double>(std::numeric_limits<int32_t>::max())) + return false; + *value = static_cast<int32_t>(d); + return true; +} + +inline bool AsValue(Json::Value* json_value, uint64_t* value) { + if (json_value->type() != Json::stringValue) return false; + int result = + std::sscanf(json_value->asString().c_str(), "0x%016" PRIx64, value); + return result == 1; +} + +inline bool AsValue(Json::Value* json_value, uint32_t* value) { + if (json_value->type() != Json::realValue) return false; + double d = json_value->asDouble(); + if (!IsIntegral(d) || d < 0.0 || + d > static_cast<double>(std::numeric_limits<uint32_t>::max())) + return false; + *value = static_cast<uint32_t>(d); + return true; +} + +inline bool AsValue(Json::Value* json_value, uint8_t* value) { + uint32_t value32 = 0; + AsValue(json_value, &value32); + if (value32 > std::numeric_limits<uint8_t>::max()) + return false; + *value = static_cast<uint8_t>(value32); + return true; +} + +inline bool AsValue(Json::Value* json_value, float* value) { + if (json_value->type() != Json::realValue) return false; + *value = static_cast<float>(json_value->asDouble()); + return true; +} + +template <typename T> +inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) { + if (json_value->type() != Json::arrayValue || json_value->size() != count) + return false; + for (uint32_t i = 0; i < count; ++i) { + if (!AsValue(&(*json_value)[i], values + i)) return false; + } + return true; +} + +template <typename T, unsigned int N> +inline bool AsValue(Json::Value* json_value, T (*value)[N]) { + return AsArray(json_value, N, *value); +} + +template <size_t N> +inline bool AsValue(Json::Value* json_value, char (*value)[N]) { + if (json_value->type() != Json::stringValue) return false; + size_t len = json_value->asString().length(); + if (len >= N) + return false; + memcpy(*value, json_value->asString().c_str(), len); + memset(*value + len, 0, N-len); + return true; +} + +template <typename T, typename = EnableForEnum<T>, typename = void> +inline bool AsValue(Json::Value* json_value, T* t) { + uint32_t value = 0; + if (!AsValue(json_value, &value)) + return false; + if (!EnumTraits<T>::exist(value)) return false; + *t = static_cast<T>(value); + return true; +} + +template <typename T> +inline bool AsValue(Json::Value* json_value, std::vector<T>* value) { + if (json_value->type() != Json::arrayValue) return false; + int size = json_value->size(); + value->resize(size); + return AsArray(json_value, size, value->data()); +} + +template <typename F, typename S> +inline bool AsValue(Json::Value* json_value, std::pair<F, S>* value) { + if (json_value->type() != Json::arrayValue || json_value->size() != 2) + return false; + return AsValue(&(*json_value)[0], &value->first) && + AsValue(&(*json_value)[1], &value->second); +} + +template <typename F, typename S> +inline bool AsValue(Json::Value* json_value, std::map<F, S>* value) { + if (json_value->type() != Json::arrayValue) return false; + int size = json_value->size(); + for (int i = 0; i < size; ++i) { + std::pair<F, S> elem; + if (!AsValue(&(*json_value)[i], &elem)) return false; + if (!value->insert(elem).second) + return false; + } + return true; +} + +template <typename T> +bool ReadValue(Json::Value* object, const char* key, T* value, + std::string* errors) { + Json::Value json_value = (*object)[key]; + if (!json_value) { + if (errors) + *errors = std::string(key) + " missing."; + return false; + } + if (AsValue(&json_value, value)) return true; + if (errors) + *errors = std::string("Wrong type for ") + std::string(key) + "."; + return false; +} + +template <typename Visitor, typename T> +inline bool VisitForRead(Visitor* visitor, T* t) { + return Iterate(visitor, t); +} + +class JsonReaderVisitor { + public: + JsonReaderVisitor(Json::Value* object, std::string* errors) + : object_(object), errors_(errors) {} + + template <typename T> bool Visit(const char* key, T* value) const { + return ReadValue(object_, key, value, errors_); + } + + template <typename T, uint32_t N> + bool VisitArray(const char* key, uint32_t count, T (*value)[N]) { + if (count > N) + return false; + Json::Value json_value = (*object_)[key]; + if (!json_value) { + if (errors_) + *errors_ = std::string(key) + " missing."; + return false; + } + if (AsArray(&json_value, count, *value)) return true; + if (errors_) + *errors_ = std::string("Wrong type for ") + std::string(key) + "."; + return false; + } + + + private: + Json::Value* object_; + std::string* errors_; +}; + +template <typename T, typename /*= EnableForStruct<T>*/> +bool AsValue(Json::Value* json_value, T* t) { + if (json_value->type() != Json::objectValue) return false; + JsonReaderVisitor visitor(json_value, nullptr); + return VisitForRead(&visitor, t); +} + + +template <typename T> std::string VkTypeToJson(const T& t) { + JsonWriterVisitor visitor; + VisitForWrite(&visitor, t); + return visitor.get_object().toStyledString(); +} + +template <typename T> bool VkTypeFromJson(const std::string& json, + T* t, + std::string* errors) { + *t = T(); + Json::Value object(Json::objectValue); + Json::Reader reader; + reader.parse(json, object, false); + if (!object) { + if (errors) errors->assign(reader.getFormatedErrorMessages()); + return false; + } + return AsValue(&object, t); +} + +} // anonymous namespace + +std::string VkJsonInstanceToJson(const VkJsonInstance& instance) { + return VkTypeToJson(instance); +} + +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( + const VkImageFormatProperties& properties) { + return VkTypeToJson(properties); +} + +bool VkJsonImageFormatPropertiesFromJson(const std::string& json, + VkImageFormatProperties* properties, + std::string* errors) { + return VkTypeFromJson(json, properties, errors); +}; diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h new file mode 100644 index 0000000000..5e8428ab17 --- /dev/null +++ b/vulkan/vkjson/vkjson.h @@ -0,0 +1,162 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +// 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. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VKJSON_H_ +#define VKJSON_H_ + +#include <vulkan/vulkan.h> +#include <string.h> + +#include <map> +#include <string> +#include <vector> + +#ifdef WIN32 +#undef min +#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(&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; + 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(); +std::string VkJsonInstanceToJson(const VkJsonInstance& instance); +bool VkJsonInstanceFromJson(const std::string& json, + VkJsonInstance* instance, + std::string* errors); + +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, + std::string* errors); + +std::string VkJsonImageFormatPropertiesToJson( + const VkImageFormatProperties& properties); +bool VkJsonImageFormatPropertiesFromJson(const std::string& json, + VkImageFormatProperties* properties, + std::string* errors); + +// Backward-compatibility aliases +typedef VkJsonDevice VkJsonAllProperties; +inline VkJsonAllProperties VkJsonGetAllProperties( + VkPhysicalDevice physicalDevice) { + return VkJsonGetDevice(VK_NULL_HANDLE, physicalDevice, 0, nullptr); +} +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/vulkan/vkjson/vkjson_info.cc b/vulkan/vkjson/vkjson_info.cc new file mode 100644 index 0000000000..3c4b08b16f --- /dev/null +++ b/vulkan/vkjson/vkjson_info.cc @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +// 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. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VK_PROTOTYPES +#define VK_PROTOTYPES +#endif + +#include "vkjson.h" + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include <iostream> +#include <vector> + +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; +}; + +bool ParseOptions(int argc, char* argv[], Options* options) { + for (int i = 1; i < argc; ++i) { + std::string arg(argv[i]); + if (arg == "--instance" || arg == "-i") { + options->instance = true; + } else if (arg == "--first" || arg == "-f") { + options->device_index = 0; + } else { + ++i; + if (i >= argc) { + std::cerr << "Missing parameter after: " << arg << std::endl; + return false; + } + std::string arg2(argv[i]); + if (arg == "--device-index" || arg == "-d") { + int result = sscanf(arg2.c_str(), "%u", &options->device_index); + if (result != 1) { + options->device_index = static_cast<uint32_t>(-1); + std::cerr << "Unable to parse index: " << arg2 << std::endl; + return false; + } + } else if (arg == "--device-name" || arg == "-n") { + options->device_name = arg2; + } else if (arg == "--output" || arg == "-o") { + options->output_file = arg2; + } else { + std::cerr << "Unknown argument: " << arg << std::endl; + return false; + } + } + } + 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->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 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); +#if defined(ANDROID) + output_file.assign("/sdcard/Android/" + std::string(out_device->properties.deviceName)); +#else + output_file.assign(out_device->properties.deviceName); +#endif + output_file.append(".json"); + } else { + output_file = options.output_file; + } + FILE* file = nullptr; + if (output_file == "-") { + file = stdout; + } else { + file = fopen(output_file.c_str(), "w"); + if (!file) { + std::cerr << "Unable to open file " << output_file << "." << std::endl; + return false; + } + } + + 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; + if (out_device) + std::cout << " for device " << out_device->properties.deviceName; + std::cout << "." << std::endl; + } + return true; +} + +int main(int argc, char* argv[]) { +#if defined(ANDROID) + int vulkanSupport = InitVulkan(); + if (vulkanSupport == 0) + return 1; +#endif + Options options; + if (!ParseOptions(argc, argv, &options)) + 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 = static_cast<uint32_t>(instance.devices.size()); i < n; i++) { + options.device_index = i; + Dump(instance, options); + } + } + + return 0; +} diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc new file mode 100644 index 0000000000..db0450d2c2 --- /dev/null +++ b/vulkan/vkjson/vkjson_instance.cc @@ -0,0 +1,417 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +// 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. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VK_PROTOTYPES +#define VK_PROTOTYPES +#endif + +#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; + 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; +} + +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(VkInstance instance, + VkPhysicalDevice physical_device, + uint32_t instance_extension_count, + const char* const* instance_extensions) { + VkJsonDevice device; + + 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")); + } + + 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()); + } + + 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.ext_variable_pointer_features.variable_pointer_features_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR; + 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; + } 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; + 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)); + } + } + + 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; +} + +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*> 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", + 1, + "", + 0, + VK_API_VERSION_1_0}; + VkInstanceCreateInfo instance_info = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + nullptr, + 0, + &app_info, + 0, + nullptr, + static_cast<uint32_t>(instance_extensions.size()), + instance_extensions.data()}; + 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(); + } + + 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; +} diff --git a/vulkan/vkjson/vkjson_unittest.cc b/vulkan/vkjson/vkjson_unittest.cc new file mode 100644 index 0000000000..de765cdd73 --- /dev/null +++ b/vulkan/vkjson/vkjson_unittest.cc @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +// 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. +/////////////////////////////////////////////////////////////////////////////// + +#include "vkjson.h" + +#include <stdlib.h> +#include <string.h> + +#include <iostream> + +#define EXPECT(X) if (!(X)) \ + ReportFailure(__FILE__, __LINE__, #X); + +#define ASSERT(X) if (!(X)) { \ + ReportFailure(__FILE__, __LINE__, #X); \ + return 2; \ +} + +int g_failures; + +void ReportFailure(const char* file, int line, const char* assertion) { + std::cout << file << ":" << line << ": \"" << assertion << "\" failed." + << std::endl; + ++g_failures; +} + +int main(int argc, char* argv[]) { + std::string errors; + bool result = false; + + VkJsonInstance instance; + instance.devices.resize(1); + VkJsonDevice& device = instance.devices[0]; + + const char name[] = "Test device"; + 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.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; + + 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.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))); + } + + VkImageFormatProperties props = {}; + json = VkJsonImageFormatPropertiesToJson(props); + VkImageFormatProperties props2 = {}; + result = VkJsonImageFormatPropertiesFromJson(json, &props2, &errors); + EXPECT(result); + if (!result) + std::cout << "Error: " << errors << std::endl; + + EXPECT(!memcmp(&props, &props2, sizeof(props))); + + if (g_failures) { + std::cout << g_failures << " failures." << std::endl; + return 1; + } else { + std::cout << "Success." << std::endl; + return 0; + } +} |