vulkaninfo: Refactor Supported Memory Image Types
authorCharles Giessen <charles@lunarg.com>
Fri, 17 Apr 2020 21:50:28 +0000 (15:50 -0600)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Wed, 20 May 2020 19:31:44 +0000 (13:31 -0600)
The current code was a hold over from the previous iteration of
vulkaninfo and now is more in line with the style of the rest of
vulkaninfo.

Change-Id: I18a62294c3a1f2ba9bd34d814819ba774ae87a67

vulkaninfo/vulkaninfo.cpp
vulkaninfo/vulkaninfo.h

index ef2f621..ede784b 100644 (file)
@@ -463,54 +463,45 @@ void GpuDumpMemoryProps(Printer &p, AppGpu &gpu) {
             const uint32_t memtype_bit = 1U << i;
 
             // only linear and optimal tiling considered
-            for (uint32_t tiling = VK_IMAGE_TILING_OPTIMAL; tiling < gpu.mem_type_res_support.image.size(); ++tiling) {
-                std::string usable;
-                usable += std::string(VkImageTilingString(VkImageTiling(tiling))) + ": ";
-                size_t orig_usable_str_size = usable.size();
-                bool first = true;
-                for (size_t fmt_i = 0; fmt_i < gpu.mem_type_res_support.image[tiling].size(); ++fmt_i) {
-                    const MemImageSupport *image_support = &gpu.mem_type_res_support.image[tiling][fmt_i];
-                    const bool regular_compatible =
-                        image_support->regular_supported && (image_support->regular_memtypes & memtype_bit);
-                    const bool sparse_compatible =
-                        image_support->sparse_supported && (image_support->sparse_memtypes & memtype_bit);
-                    const bool transient_compatible =
-                        image_support->transient_supported && (image_support->transient_memtypes & memtype_bit);
-
-                    if (regular_compatible || sparse_compatible || transient_compatible) {
-                        if (!first) usable += ", ";
-                        first = false;
-
-                        if (fmt_i == 0) {
-                            usable += "color images";
-                        } else {
-                            usable += VkFormatString(gpu.mem_type_res_support.image[tiling][fmt_i].format);
+            std::vector<VkFormat> tiling_optimal_formats;
+            std::vector<VkFormat> tiling_linear_formats;
+            for (auto &image_tiling : gpu.memory_image_support_types) {
+                ArrayWrapper arr(p, VkImageTilingString(VkImageTiling(image_tiling.tiling)), -1);
+                bool has_any_support_types = false;
+                bool regular = false;
+                bool transient = false;
+                bool sparse = false;
+                for (auto &image_format : image_tiling.formats) {
+                    if (image_format.type_support.size() > 0) {
+                        bool has_a_support_type = false;
+                        for (auto &img_type : image_format.type_support) {
+                            if (img_type.Compatible(memtype_bit)) {
+                                has_a_support_type = true;
+                                has_any_support_types = true;
+                                if (img_type.type == ImageTypeSupport::Type::regular) regular = true;
+                                if (img_type.type == ImageTypeSupport::Type::transient) transient = true;
+                                if (img_type.type == ImageTypeSupport::Type::sparse) sparse = true;
+                            }
                         }
-
-                        if (regular_compatible && !sparse_compatible && !transient_compatible && image_support->sparse_supported &&
-                            image_support->transient_supported) {
-                            usable += "(non-sparse, non-transient)";
-                        } else if (regular_compatible && !sparse_compatible && image_support->sparse_supported) {
-                            if (image_support->sparse_supported) usable += "(non-sparse)";
-                        } else if (regular_compatible && !transient_compatible && image_support->transient_supported) {
-                            if (image_support->transient_supported) usable += "(non-transient)";
-                        } else if (!regular_compatible && sparse_compatible && !transient_compatible &&
-                                   image_support->sparse_supported) {
-                            if (image_support->sparse_supported) usable += "(sparse only)";
-                        } else if (!regular_compatible && !sparse_compatible && transient_compatible &&
-                                   image_support->transient_supported) {
-                            if (image_support->transient_supported) usable += "(transient only)";
-                        } else if (!regular_compatible && sparse_compatible && transient_compatible &&
-                                   image_support->sparse_supported && image_support->transient_supported) {
-                            usable += "(sparse and transient only)";
+                        if (has_a_support_type) {
+                            if (image_format.format == color_format) {
+                                p.PrintString("color images");
+                            } else {
+                                p.PrintString(VkFormatString(image_format.format));
+                            }
                         }
                     }
                 }
-                if (usable.size() == orig_usable_str_size)  // not usable for anything
-                {
-                    usable += "None";
+                if (!has_any_support_types) {
+                    p.PrintString("None");
+                } else {
+                    if (regular && !transient && sparse) p.PrintString("(non-transient)");
+                    if (regular && transient && !sparse) p.PrintString("(non-sparse)");
+                    if (regular && !transient && !sparse) p.PrintString("(non-sparse, non-transient)");
+                    if (!regular && transient && sparse) p.PrintString("(sparse and transient only)");
+                    if (!regular && !transient && sparse) p.PrintString("(sparse only)");
+                    if (!regular && transient && !sparse) p.PrintString("(transient only)");
                 }
-                p.PrintString(usable);
             }
         }
     }
index 043106d..5b5e087 100644 (file)
@@ -1246,17 +1246,72 @@ std::pair<bool, VkDeviceGroupPresentCapabilitiesKHR> GetGroupCapabilities(AppIns
 
 // -------------------- Device Setup ------------------- //
 
-struct MemImageSupport {
-    bool regular_supported, sparse_supported, transient_supported;
+const VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
+
+struct ImageTypeSupport {
+    enum class Type { regular, sparse, transient } type = Type::regular;
+    bool supported = false;
+    uint32_t memoryTypeBits = 0;
+
+    bool Compatible(uint32_t memtype_bit) { return supported && (memoryTypeBits & memtype_bit); }
+};
+
+struct ImageTypeFormatInfo {
     VkFormat format;
-    uint32_t regular_memtypes, sparse_memtypes, transient_memtypes;
+    std::vector<ImageTypeSupport> type_support;
 };
 
-struct MemResSupport {
-    std::array<std::array<MemImageSupport, 8>, 2> image;
-    // TODO: buffers
+struct ImageTypeInfos {
+    VkImageTiling tiling;
+    std::vector<ImageTypeFormatInfo> formats;
 };
 
+VkImageCreateInfo GetImageCreateInfo(VkFormat format, VkImageTiling tiling, VkImageCreateFlags flags, VkImageUsageFlags usages) {
+    return {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+            nullptr,
+            flags,
+            VK_IMAGE_TYPE_2D,
+            format,
+            {8, 8, 1},
+            1,
+            1,
+            VK_SAMPLE_COUNT_1_BIT,
+            tiling,
+            usages,
+            VK_SHARING_MODE_EXCLUSIVE,
+            0,
+            nullptr,
+            VK_IMAGE_LAYOUT_UNDEFINED};
+}
+
+ImageTypeSupport FillImageTypeSupport(AppInstance &inst, VkPhysicalDevice phys_device, VkDevice device,
+                                      ImageTypeSupport::Type img_type, VkImageCreateInfo image_ci) {
+    VkImageFormatProperties img_props;
+    VkResult res = inst.dll.fp_vkGetPhysicalDeviceImageFormatProperties(
+        phys_device, image_ci.format, image_ci.imageType, image_ci.tiling, image_ci.usage, image_ci.flags, &img_props);
+
+    if (res == VK_SUCCESS) {
+        ImageTypeSupport img_type_support{};
+        img_type_support.type = img_type;
+        img_type_support.supported = true;
+
+        VkImage dummy_img;
+        res = inst.dll.fp_vkCreateImage(device, &image_ci, nullptr, &dummy_img);
+        if (res) THROW_VK_ERR("vkCreateImage", res);
+
+        VkMemoryRequirements mem_req;
+        inst.dll.fp_vkGetImageMemoryRequirements(device, dummy_img, &mem_req);
+        img_type_support.memoryTypeBits = mem_req.memoryTypeBits;
+
+        inst.dll.fp_vkDestroyImage(device, dummy_img, nullptr);
+        return img_type_support;
+    } else if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
+        return {};  // default initialization has supported being false
+    }
+    THROW_VK_ERR("vkGetPhysicalDeviceImageFormatProperties", res);
+    return {};
+}
+
 struct pNextChainInfos {
     std::vector<pNextChainBuildingBlockInfo> phys_device_props2;
     std::vector<pNextChainBuildingBlockInfo> phys_device_mem_props2;
@@ -1294,7 +1349,7 @@ struct AppGpu {
     VkPhysicalDeviceMemoryProperties memory_props;
     VkPhysicalDeviceMemoryProperties2KHR memory_props2;
 
-    MemResSupport mem_type_res_support;
+    std::vector<ImageTypeInfos> memory_image_support_types;
 
     VkPhysicalDeviceFeatures features;
     VkPhysicalDeviceFeatures2KHR features2;
@@ -1374,108 +1429,60 @@ struct AppGpu {
         VkResult err = inst.dll.fp_vkCreateDevice(phys_device, &device_ci, nullptr, &dev);
         if (err) THROW_VK_ERR("vkCreateDevice", err);
 
-        const VkFormat color_format = VK_FORMAT_R8G8B8A8_UNORM;
+        const std::vector<VkImageTiling> tilings = {VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_LINEAR};
         const std::vector<VkFormat> formats = {
             color_format,      VK_FORMAT_D16_UNORM,         VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D32_SFLOAT,
             VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT,   VK_FORMAT_D32_SFLOAT_S8_UINT};
-        assert(mem_type_res_support.image[0].size() == formats.size());
-        const std::array<VkImageUsageFlags, 2> usages = {0, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT};
-        const std::array<VkImageCreateFlags, 2> flagss = {0, VK_IMAGE_CREATE_SPARSE_BINDING_BIT};
-
-        for (size_t fmt_i = 0; fmt_i < formats.size(); ++fmt_i) {
-            // only iterate over VK_IMAGE_TILING_OPTIMAL and VK_IMAGE_TILING_LINEAR (0 and 1)
-            for (size_t tiling = VK_IMAGE_TILING_OPTIMAL; tiling <= VK_IMAGE_TILING_LINEAR; ++tiling) {
-                mem_type_res_support.image[tiling][fmt_i].format = formats[fmt_i];
-                mem_type_res_support.image[tiling][fmt_i].regular_supported = true;
-                mem_type_res_support.image[tiling][fmt_i].sparse_supported = true;
-                mem_type_res_support.image[tiling][fmt_i].transient_supported = true;
+
+        for (VkImageTiling tiling : tilings) {
+            ImageTypeInfos image_type_infos;
+            image_type_infos.tiling = tiling;
+
+            for (VkFormat format : formats) {
+                ImageTypeFormatInfo image_type_format_info;
+                image_type_format_info.format = format;
 
                 VkFormatProperties fmt_props;
-                inst.dll.fp_vkGetPhysicalDeviceFormatProperties(phys_device, formats[fmt_i], &fmt_props);
+                inst.dll.fp_vkGetPhysicalDeviceFormatProperties(phys_device, format, &fmt_props);
                 if ((tiling == VK_IMAGE_TILING_OPTIMAL && fmt_props.optimalTilingFeatures == 0) ||
                     (tiling == VK_IMAGE_TILING_LINEAR && fmt_props.linearTilingFeatures == 0)) {
-                    mem_type_res_support.image[tiling][fmt_i].regular_supported = false;
-                    mem_type_res_support.image[tiling][fmt_i].sparse_supported = false;
-                    mem_type_res_support.image[tiling][fmt_i].transient_supported = false;
                     continue;
                 }
 
-                for (size_t u_i = 0; u_i < usages.size(); ++u_i) {
-                    for (size_t flg_i = 0; flg_i < flagss.size(); ++flg_i) {
-                        VkImageCreateInfo image_ci = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
-                                                      nullptr,
-                                                      flagss[flg_i],
-                                                      VK_IMAGE_TYPE_2D,
-                                                      formats[fmt_i],
-                                                      {8, 8, 1},
-                                                      1,
-                                                      1,
-                                                      VK_SAMPLE_COUNT_1_BIT,
-                                                      static_cast<VkImageTiling>(tiling),
-                                                      usages[u_i],
-                                                      VK_SHARING_MODE_EXCLUSIVE,
-                                                      0,
-                                                      nullptr,
-                                                      VK_IMAGE_LAYOUT_UNDEFINED};
-
-                        if ((image_ci.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) &&
-                            (image_ci.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) {
-                            continue;
-                        }
-
-                        if (image_ci.usage == 0 || (image_ci.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) {
-                            if (image_ci.format == color_format)
-                                image_ci.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
-                            else
-                                image_ci.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-                        }
-
-                        if (!enabled_features.sparseBinding && (image_ci.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)) {
-                            mem_type_res_support.image[tiling][fmt_i].sparse_supported = false;
-                            continue;
-                        }
-
-                        VkImageFormatProperties img_props;
-                        err = inst.dll.fp_vkGetPhysicalDeviceImageFormatProperties(phys_device, image_ci.format, image_ci.imageType,
-                                                                                   image_ci.tiling, image_ci.usage, image_ci.flags,
-                                                                                   &img_props);
-
-                        uint32_t *memtypes;
-                        bool *support;
-
-                        if (image_ci.flags == 0 && !(image_ci.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) {
-                            memtypes = &mem_type_res_support.image[tiling][fmt_i].regular_memtypes;
-                            support = &mem_type_res_support.image[tiling][fmt_i].regular_supported;
-                        } else if ((image_ci.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) &&
-                                   !(image_ci.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) {
-                            memtypes = &mem_type_res_support.image[tiling][fmt_i].sparse_memtypes;
-                            support = &mem_type_res_support.image[tiling][fmt_i].sparse_supported;
-                        } else if (image_ci.flags == 0 && (image_ci.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT)) {
-                            memtypes = &mem_type_res_support.image[tiling][fmt_i].transient_memtypes;
-                            support = &mem_type_res_support.image[tiling][fmt_i].transient_supported;
-                        } else {
-                            assert(false);
-                            return;
-                        }
-
-                        if (err == VK_ERROR_FORMAT_NOT_SUPPORTED) {
-                            *support = false;
-                        } else {
-                            if (err != VK_SUCCESS) THROW_VK_ERR("vkGetPhysicalDeviceImageFormatProperties", err);
-
-                            VkImage dummy_img;
-                            err = inst.dll.fp_vkCreateImage(dev, &image_ci, nullptr, &dummy_img);
-                            if (err) THROW_VK_ERR("vkCreateImage", err);
-
-                            VkMemoryRequirements mem_req;
-                            inst.dll.fp_vkGetImageMemoryRequirements(dev, dummy_img, &mem_req);
-                            *memtypes = mem_req.memoryTypeBits;
-
-                            inst.dll.fp_vkDestroyImage(dev, dummy_img, nullptr);
-                        }
+                VkImageCreateInfo image_ci_regular = GetImageCreateInfo(format, tiling, 0, 0);
+                VkImageCreateInfo image_ci_transient =
+                    GetImageCreateInfo(format, tiling, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, 0);
+                VkImageCreateInfo image_ci_sparse = GetImageCreateInfo(format, tiling, 0, VK_IMAGE_CREATE_SPARSE_BINDING_BIT);
+
+                if (format == color_format) {
+                    image_ci_regular.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+                    image_ci_transient.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+                } else {
+                    image_ci_regular.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+                    image_ci_transient.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+                }
+
+                auto image_ts_regular =
+                    FillImageTypeSupport(inst, phys_device, dev, ImageTypeSupport::Type::regular, image_ci_regular);
+                if (image_ts_regular.supported) {
+                    image_type_format_info.type_support.push_back(image_ts_regular);
+                }
+                auto image_ts_transient =
+                    FillImageTypeSupport(inst, phys_device, dev, ImageTypeSupport::Type::transient, image_ci_transient);
+                if (image_ts_transient.supported) {
+                    image_type_format_info.type_support.push_back(image_ts_transient);
+                }
+
+                if (enabled_features.sparseBinding) {
+                    auto image_ts_sparse =
+                        FillImageTypeSupport(inst, phys_device, dev, ImageTypeSupport::Type::sparse, image_ci_sparse);
+                    if (image_ts_sparse.supported) {
+                        image_type_format_info.type_support.push_back(image_ts_sparse);
                     }
                 }
+                image_type_infos.formats.push_back(image_type_format_info);
             }
+            memory_image_support_types.push_back(image_type_infos);
         }
 
         // Memory //
@@ -1638,8 +1645,8 @@ struct hash<PropFlags> {
 }  // namespace std
 
 // Used to sort the formats into buckets by their properties.
-std::unordered_map<PropFlags, std::vector<VkFormat> > FormatPropMap(AppGpu &gpu) {
-    std::unordered_map<PropFlags, std::vector<VkFormat> > map;
+std::unordered_map<PropFlags, std::vector<VkFormat>> FormatPropMap(AppGpu &gpu) {
+    std::unordered_map<PropFlags, std::vector<VkFormat>> map;
     for (auto fmtRange : gpu.supported_format_ranges) {
         for (int32_t fmt = fmtRange.first_format; fmt <= fmtRange.last_format; ++fmt) {
             VkFormatProperties props;