From a2ce81eb996878cfe12aaccd5b8f5c1bf8633477 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Tue, 13 Oct 2020 20:45:45 +0200 Subject: [PATCH 01/38] Read and store Vulkan 1.1 and 1.2 core features and properties structures --- vulkanDeviceInfo.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++- vulkanDeviceInfo.h | 5 + 2 files changed, 214 insertions(+), 5 deletions(-) diff --git a/vulkanDeviceInfo.cpp b/vulkanDeviceInfo.cpp index 075f715..f5c910e 100644 --- a/vulkanDeviceInfo.cpp +++ b/vulkanDeviceInfo.cpp @@ -34,6 +34,13 @@ bool VulkanDeviceInfo::vulkan_1_1() return ((major > 1) || ((major == 1) && (minor >= 1))); } +bool VulkanDeviceInfo::vulkan_1_2() +{ + uint32_t major = VK_VERSION_MAJOR(props.apiVersion); + uint32_t minor = VK_VERSION_MINOR(props.apiVersion); + return ((major > 1) || ((major == 1) && (minor >= 2))); +} + void VulkanDeviceInfo::readExtensions() { assert(device != NULL); @@ -188,6 +195,15 @@ std::string VulkanDeviceInfo::getDriverVersion() } } +QJsonArray UUIDToJson(uint8_t* UUID) +{ + QJsonArray jsonArray; + for (uint32_t i = 0; i < VK_UUID_SIZE; i++) { + jsonArray.append(UUID[i]); + } + return jsonArray; +} + void VulkanDeviceInfo::readPhysicalProperties() { assert(device != NULL); @@ -221,9 +237,34 @@ void VulkanDeviceInfo::readPhysicalProperties() // VK 1.1 core if (vulkan_1_1()) { VkPhysicalDeviceProperties2KHR deviceProps2{}; + deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + + // Core + VkPhysicalDeviceVulkan11Properties coreProps{}; + coreProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; + deviceProps2.pNext = &coreProps; + pfnGetPhysicalDeviceProperties2KHR(device, &deviceProps2); + + core11Properties.clear(); + core11Properties["deviceUUID"] = UUIDToJson(coreProps.deviceUUID); + core11Properties["driverUUID"] = UUIDToJson(coreProps.driverUUID); + core11Properties["deviceLUID"] = UUIDToJson(coreProps.deviceLUID); + core11Properties["deviceNodeMask"] = coreProps.deviceNodeMask; + core11Properties["deviceLUIDValid"] = coreProps.deviceLUIDValid; + core11Properties["subgroupSize"] = coreProps.subgroupSize; + core11Properties["subgroupSupportedStages"] = coreProps.subgroupSupportedStages; + core11Properties["subgroupSupportedOperations"] = coreProps.subgroupSupportedOperations; + core11Properties["subgroupQuadOperationsInAllStages"] = coreProps.subgroupQuadOperationsInAllStages; + core11Properties["pointClippingBehavior"] = coreProps.pointClippingBehavior; + core11Properties["maxMultiviewViewCount"] = coreProps.maxMultiviewViewCount; + core11Properties["maxMultiviewInstanceIndex"] = coreProps.maxMultiviewInstanceIndex; + core11Properties["protectedNoFault"] = coreProps.protectedNoFault; + core11Properties["maxPerSetDescriptors"] = coreProps.maxPerSetDescriptors; + core11Properties["maxMemoryAllocationSize"] = coreProps.maxMemoryAllocationSize; + + // Subgroup props (@todo: Still required?) VkPhysicalDeviceSubgroupProperties extProps{}; extProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; - deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; deviceProps2.pNext = &extProps; pfnGetPhysicalDeviceProperties2KHR(device, &deviceProps2); hasSubgroupProperties = true; @@ -245,6 +286,73 @@ void VulkanDeviceInfo::readPhysicalProperties() properties2.push_back(Property2("maxMemoryAllocationSize", QVariant::fromValue(extProps.maxMemoryAllocationSize), extName)); } } + + // VK 1.2 core + if (vulkan_1_2()) { + VkPhysicalDeviceProperties2KHR deviceProps2{}; + deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + + // Core + VkPhysicalDeviceVulkan12Properties coreProps{}; + coreProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; + deviceProps2.pNext = &coreProps; + pfnGetPhysicalDeviceProperties2KHR(device, &deviceProps2); + + core12Properties.clear(); + core12Properties["driverID"] = coreProps.driverID; + core12Properties["driverName"] = QString(coreProps.driverName); + core12Properties["driverInfo"] = QString(coreProps.driverInfo); + core12Properties["conformanceVersion"] = QString::fromStdString(vulkanResources::conformanceVersionKHRString(coreProps.conformanceVersion)); + core12Properties["denormBehaviorIndependence"] = coreProps.denormBehaviorIndependence; + core12Properties["roundingModeIndependence"] = coreProps.roundingModeIndependence; + core12Properties["shaderSignedZeroInfNanPreserveFloat16"] = coreProps.shaderSignedZeroInfNanPreserveFloat16; + core12Properties["shaderSignedZeroInfNanPreserveFloat32"] = coreProps.shaderSignedZeroInfNanPreserveFloat32; + core12Properties["shaderSignedZeroInfNanPreserveFloat64"] = coreProps.shaderSignedZeroInfNanPreserveFloat64; + core12Properties["shaderDenormPreserveFloat16"] = coreProps.shaderDenormPreserveFloat16; + core12Properties["shaderDenormPreserveFloat32"] = coreProps.shaderDenormPreserveFloat32; + core12Properties["shaderDenormPreserveFloat64"] = coreProps.shaderDenormPreserveFloat64; + core12Properties["shaderDenormFlushToZeroFloat16"] = coreProps.shaderDenormFlushToZeroFloat16; + core12Properties["shaderDenormFlushToZeroFloat32"] = coreProps.shaderDenormFlushToZeroFloat32; + core12Properties["shaderDenormFlushToZeroFloat64"] = coreProps.shaderDenormFlushToZeroFloat64; + core12Properties["shaderRoundingModeRTEFloat16"] = coreProps.shaderRoundingModeRTEFloat16; + core12Properties["shaderRoundingModeRTEFloat32"] = coreProps.shaderRoundingModeRTEFloat32; + core12Properties["shaderRoundingModeRTEFloat64"] = coreProps.shaderRoundingModeRTEFloat64; + core12Properties["shaderRoundingModeRTZFloat16"] = coreProps.shaderRoundingModeRTZFloat16; + core12Properties["shaderRoundingModeRTZFloat32"] = coreProps.shaderRoundingModeRTZFloat32; + core12Properties["shaderRoundingModeRTZFloat64"] = coreProps.shaderRoundingModeRTZFloat64; + core12Properties["maxUpdateAfterBindDescriptorsInAllPools"] = coreProps.maxUpdateAfterBindDescriptorsInAllPools; + core12Properties["shaderUniformBufferArrayNonUniformIndexingNative"] = coreProps.shaderUniformBufferArrayNonUniformIndexingNative; + core12Properties["shaderSampledImageArrayNonUniformIndexingNative"] = coreProps.shaderSampledImageArrayNonUniformIndexingNative; + core12Properties["shaderStorageBufferArrayNonUniformIndexingNative"] = coreProps.shaderStorageBufferArrayNonUniformIndexingNative; + core12Properties["shaderStorageImageArrayNonUniformIndexingNative"] = coreProps.shaderStorageImageArrayNonUniformIndexingNative; + core12Properties["shaderInputAttachmentArrayNonUniformIndexingNative"] = coreProps.shaderInputAttachmentArrayNonUniformIndexingNative; + core12Properties["robustBufferAccessUpdateAfterBind"] = coreProps.robustBufferAccessUpdateAfterBind; + core12Properties["quadDivergentImplicitLod"] = coreProps.quadDivergentImplicitLod; + core12Properties["maxPerStageDescriptorUpdateAfterBindSamplers"] = coreProps.maxPerStageDescriptorUpdateAfterBindSamplers; + core12Properties["maxPerStageDescriptorUpdateAfterBindUniformBuffers"] = coreProps.maxPerStageDescriptorUpdateAfterBindUniformBuffers; + core12Properties["maxPerStageDescriptorUpdateAfterBindStorageBuffers"] = coreProps.maxPerStageDescriptorUpdateAfterBindStorageBuffers; + core12Properties["maxPerStageDescriptorUpdateAfterBindSampledImages"] = coreProps.maxPerStageDescriptorUpdateAfterBindSampledImages; + core12Properties["maxPerStageDescriptorUpdateAfterBindStorageImages"] = coreProps.maxPerStageDescriptorUpdateAfterBindStorageImages; + core12Properties["maxPerStageDescriptorUpdateAfterBindInputAttachments"] = coreProps.maxPerStageDescriptorUpdateAfterBindInputAttachments; + core12Properties["maxPerStageUpdateAfterBindResources"] = coreProps.maxPerStageUpdateAfterBindResources; + core12Properties["maxDescriptorSetUpdateAfterBindSamplers"] = coreProps.maxDescriptorSetUpdateAfterBindSamplers; + core12Properties["maxDescriptorSetUpdateAfterBindUniformBuffers"] = coreProps.maxDescriptorSetUpdateAfterBindUniformBuffers; + core12Properties["maxDescriptorSetUpdateAfterBindUniformBuffersDynamic"] = coreProps.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + core12Properties["maxDescriptorSetUpdateAfterBindStorageBuffers"] = coreProps.maxDescriptorSetUpdateAfterBindStorageBuffers; + core12Properties["maxDescriptorSetUpdateAfterBindStorageBuffersDynamic"] = coreProps.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + core12Properties["maxDescriptorSetUpdateAfterBindSampledImages"] = coreProps.maxDescriptorSetUpdateAfterBindSampledImages; + core12Properties["maxDescriptorSetUpdateAfterBindStorageImages"] = coreProps.maxDescriptorSetUpdateAfterBindStorageImages; + core12Properties["maxDescriptorSetUpdateAfterBindInputAttachments"] = coreProps.maxDescriptorSetUpdateAfterBindInputAttachments; + core12Properties["supportedDepthResolveModes"] = coreProps.supportedDepthResolveModes; + core12Properties["supportedStencilResolveModes"] = coreProps.supportedStencilResolveModes; + core12Properties["independentResolveNone"] = coreProps.independentResolveNone; + core12Properties["independentResolve"] = coreProps.independentResolve; + core12Properties["filterMinmaxSingleComponentFormats"] = coreProps.filterMinmaxSingleComponentFormats; + core12Properties["filterMinmaxImageComponentMapping"] = coreProps.filterMinmaxImageComponentMapping; + core12Properties["maxTimelineSemaphoreValueDifference"] = coreProps.maxTimelineSemaphoreValueDifference; + core12Properties["framebufferIntegerColorSampleCounts"] = coreProps.framebufferIntegerColorSampleCounts; + + } } } @@ -315,20 +423,102 @@ void VulkanDeviceInfo::readPhysicalFeatures() readExtendedFeatures(); - // VK 1.1 Core + // Vulkan 1.1 if (vulkan_1_1()) { + VkPhysicalDeviceFeatures2KHR deviceFeatures2{}; + deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; + + // Core + VkPhysicalDeviceVulkan11Features coreFeatures{}; + coreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + deviceFeatures2.pNext = &coreFeatures; + pfnGetPhysicalDeviceFeatures2KHR(device, &deviceFeatures2); + + core11Features.clear(); + core11Features["storageBuffer16BitAccess"] = coreFeatures.storageBuffer16BitAccess; + core11Features["uniformAndStorageBuffer16BitAcces"] = coreFeatures.uniformAndStorageBuffer16BitAccess; + core11Features["storagePushConstant16"] = coreFeatures.storagePushConstant16; + core11Features["storageInputOutput16"] = coreFeatures.storageInputOutput16; + core11Features["multiview"] = coreFeatures.multiview; + core11Features["multiviewGeometryShader"] = coreFeatures.multiviewGeometryShader; + core11Features["multiviewTessellationShader"] = coreFeatures.multiviewTessellationShader; + core11Features["variablePointersStorageBuffer"] = coreFeatures.variablePointersStorageBuffer; + core11Features["variablePointers"] = coreFeatures.variablePointers; + core11Features["protectedMemory"] = coreFeatures.protectedMemory; + core11Features["samplerYcbcrConversion"] = coreFeatures.samplerYcbcrConversion; + core11Features["shaderDrawParameters"] = coreFeatures.shaderDrawParameters; + // VK_KHR_shader_draw_parameters if (extensionSupported(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME)) { - VkPhysicalDeviceFeatures2KHR deviceFeatures2{}; VkPhysicalDeviceShaderDrawParameterFeatures extFeatures{}; extFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; deviceFeatures2.pNext = &extFeatures; pfnGetPhysicalDeviceFeatures2KHR(device, &deviceFeatures2); features2.push_back(Feature2("shaderDrawParameters", extFeatures.shaderDrawParameters, VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME)); } } + // Vulkan 1.2 + if (vulkan_1_2()) { + VkPhysicalDeviceFeatures2KHR deviceFeatures2{}; + deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; + + // Core + VkPhysicalDeviceVulkan12Features coreFeatures{}; + coreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + deviceFeatures2.pNext = &coreFeatures; + pfnGetPhysicalDeviceFeatures2KHR(device, &deviceFeatures2); + + core12Features.clear(); + core12Features["samplerMirrorClampToEdge"] = coreFeatures.samplerMirrorClampToEdge; + core12Features["drawIndirectCount"] = coreFeatures.drawIndirectCount; + core12Features["storageBuffer8BitAccess"] = coreFeatures.storageBuffer8BitAccess; + core12Features["uniformAndStorageBuffer8BitAccess"] = coreFeatures.uniformAndStorageBuffer8BitAccess; + core12Features["storagePushConstant8"] = coreFeatures.storagePushConstant8; + core12Features["shaderBufferInt64Atomics"] = coreFeatures.shaderBufferInt64Atomics; + core12Features["shaderSharedInt64Atomics"] = coreFeatures.shaderSharedInt64Atomics; + core12Features["shaderFloat16"] = coreFeatures.shaderFloat16; + core12Features["shaderInt8"] = coreFeatures.shaderInt8; + core12Features["descriptorIndexing"] = coreFeatures.descriptorIndexing; + core12Features["shaderInputAttachmentArrayDynamicIndexing"] = coreFeatures.shaderInputAttachmentArrayDynamicIndexing; + core12Features["shaderUniformTexelBufferArrayDynamicIndexing"] = coreFeatures.shaderUniformTexelBufferArrayDynamicIndexing; + core12Features["shaderStorageTexelBufferArrayDynamicIndexing"] = coreFeatures.shaderStorageTexelBufferArrayDynamicIndexing; + core12Features["shaderUniformBufferArrayNonUniformIndexing"] = coreFeatures.shaderUniformBufferArrayNonUniformIndexing; + core12Features["shaderSampledImageArrayNonUniformIndexing"] = coreFeatures.shaderSampledImageArrayNonUniformIndexing; + core12Features["shaderStorageBufferArrayNonUniformIndexing"] = coreFeatures.shaderStorageBufferArrayNonUniformIndexing; + core12Features["shaderStorageImageArrayNonUniformIndexing"] = coreFeatures.shaderStorageImageArrayNonUniformIndexing; + core12Features["shaderInputAttachmentArrayNonUniformIndexing"] = coreFeatures.shaderInputAttachmentArrayNonUniformIndexing; + core12Features["shaderUniformTexelBufferArrayNonUniformIndexing"] = coreFeatures.shaderUniformTexelBufferArrayNonUniformIndexing; + core12Features["shaderStorageTexelBufferArrayNonUniformIndexing"] = coreFeatures.shaderStorageTexelBufferArrayNonUniformIndexing; + core12Features["descriptorBindingUniformBufferUpdateAfterBind"] = coreFeatures.descriptorBindingUniformBufferUpdateAfterBind; + core12Features["descriptorBindingSampledImageUpdateAfterBind"] = coreFeatures.descriptorBindingSampledImageUpdateAfterBind; + core12Features["descriptorBindingStorageImageUpdateAfterBind"] = coreFeatures.descriptorBindingStorageImageUpdateAfterBind; + core12Features["descriptorBindingStorageBufferUpdateAfterBind"] = coreFeatures.descriptorBindingStorageBufferUpdateAfterBind; + core12Features["descriptorBindingUniformTexelBufferUpdateAfterBind"] = coreFeatures.descriptorBindingUniformTexelBufferUpdateAfterBind; + core12Features["descriptorBindingStorageTexelBufferUpdateAfterBind"] = coreFeatures.descriptorBindingStorageTexelBufferUpdateAfterBind; + core12Features["descriptorBindingUpdateUnusedWhilePending"] = coreFeatures.descriptorBindingUpdateUnusedWhilePending; + core12Features["descriptorBindingPartiallyBound"] = coreFeatures.descriptorBindingPartiallyBound; + core12Features["descriptorBindingVariableDescriptorCount"] = coreFeatures.descriptorBindingVariableDescriptorCount; + core12Features["runtimeDescriptorArray"] = coreFeatures.runtimeDescriptorArray; + core12Features["samplerFilterMinmax"] = coreFeatures.samplerFilterMinmax; + core12Features["scalarBlockLayout"] = coreFeatures.scalarBlockLayout; + core12Features["imagelessFramebuffer"] = coreFeatures.imagelessFramebuffer; + core12Features["uniformBufferStandardLayout"] = coreFeatures.uniformBufferStandardLayout; + core12Features["shaderSubgroupExtendedTypes"] = coreFeatures.shaderSubgroupExtendedTypes; + core12Features["separateDepthStencilLayouts"] = coreFeatures.separateDepthStencilLayouts; + core12Features["hostQueryReset"] = coreFeatures.hostQueryReset; + core12Features["timelineSemaphore"] = coreFeatures.timelineSemaphore; + core12Features["bufferDeviceAddress"] = coreFeatures.bufferDeviceAddress; + core12Features["bufferDeviceAddressCaptureReplay"] = coreFeatures.bufferDeviceAddressCaptureReplay; + core12Features["bufferDeviceAddressMultiDevice"] = coreFeatures.bufferDeviceAddressMultiDevice; + core12Features["vulkanMemoryModel"] = coreFeatures.vulkanMemoryModel; + core12Features["vulkanMemoryModelDeviceScope"] = coreFeatures.vulkanMemoryModelDeviceScope; + core12Features["vulkanMemoryModelAvailabilityVisibilityChains"] = coreFeatures.vulkanMemoryModelAvailabilityVisibilityChains; + core12Features["shaderOutputViewportIndex"] = coreFeatures.shaderOutputViewportIndex; + core12Features["shaderOutputLayer"] = coreFeatures.shaderOutputLayer; + core12Features["subgroupBroadcastDynamicId"] = coreFeatures.subgroupBroadcastDynamicId; + } + } } @@ -493,6 +683,12 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) jsonProperties["sparseProperties"] = QJsonObject::fromVariantMap(sparseProperties); jsonProperties["subgroupProperties"] = QJsonObject::fromVariantMap(subgroupProperties); jsonProperties["limits"] = QJsonObject::fromVariantMap(limits); + if (!core11Properties.empty()) { + jsonProperties["core11"] = QJsonObject::fromVariantMap(core11Properties); + } + if (!core12Properties.empty()) { + jsonProperties["core12"] = QJsonObject::fromVariantMap(core12Properties); + } // Pipeline cache UUID QJsonArray jsonPipelineCache; for (uint32_t i = 0; i < VK_UUID_SIZE; i++) { @@ -505,7 +701,15 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) root["properties"] = jsonProperties; // Device features - root["features"] = QJsonObject::fromVariantMap(features); + QJsonObject jsonFeatures; + jsonFeatures = QJsonObject::fromVariantMap(features); + if (!core11Properties.empty()) { + jsonFeatures["core11"] = QJsonObject::fromVariantMap(core11Features); + } + if (!core12Properties.empty()) { + jsonFeatures["core12"] = QJsonObject::fromVariantMap(core12Features); + } + root["features"] = jsonFeatures; // Extensions QJsonArray jsonExtensions; diff --git a/vulkanDeviceInfo.h b/vulkanDeviceInfo.h index eb0ad3f..0ff1dfd 100644 --- a/vulkanDeviceInfo.h +++ b/vulkanDeviceInfo.h @@ -75,6 +75,7 @@ class VulkanDeviceInfo: public VulkanDeviceInfoExtensions private: std::vector layers; bool vulkan_1_1(); + bool vulkan_1_2(); bool extensionSupported(const char* extensionName); #if defined(__ANDROID__) std::string getSystemProperty(const char* propname); @@ -90,8 +91,12 @@ class VulkanDeviceInfo: public VulkanDeviceInfoExtensions VkPhysicalDeviceProperties props; VkPhysicalDeviceMemoryProperties memoryProperties; VkPhysicalDeviceFeatures deviceFeatures; + QVariantMap core11Features; + QVariantMap core12Features; bool hasSubgroupProperties = false; QVariantMap subgroupProperties; + QVariantMap core11Properties; + QVariantMap core12Properties; std::vector queueFamilies; std::vector formats; VulkanSurfaceInfo surfaceInfo; From 2dd98de386c07f877b07d9010f0ebda4dce97f47 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Wed, 14 Oct 2020 19:24:52 +0200 Subject: [PATCH 02/38] Value casts --- vulkanDeviceInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vulkanDeviceInfo.cpp b/vulkanDeviceInfo.cpp index f5c910e..dde6741 100644 --- a/vulkanDeviceInfo.cpp +++ b/vulkanDeviceInfo.cpp @@ -260,7 +260,7 @@ void VulkanDeviceInfo::readPhysicalProperties() core11Properties["maxMultiviewInstanceIndex"] = coreProps.maxMultiviewInstanceIndex; core11Properties["protectedNoFault"] = coreProps.protectedNoFault; core11Properties["maxPerSetDescriptors"] = coreProps.maxPerSetDescriptors; - core11Properties["maxMemoryAllocationSize"] = coreProps.maxMemoryAllocationSize; + core11Properties["maxMemoryAllocationSize"] = QVariant::fromValue(coreProps.maxMemoryAllocationSize); // Subgroup props (@todo: Still required?) VkPhysicalDeviceSubgroupProperties extProps{}; @@ -349,7 +349,7 @@ void VulkanDeviceInfo::readPhysicalProperties() core12Properties["independentResolve"] = coreProps.independentResolve; core12Properties["filterMinmaxSingleComponentFormats"] = coreProps.filterMinmaxSingleComponentFormats; core12Properties["filterMinmaxImageComponentMapping"] = coreProps.filterMinmaxImageComponentMapping; - core12Properties["maxTimelineSemaphoreValueDifference"] = coreProps.maxTimelineSemaphoreValueDifference; + core12Properties["maxTimelineSemaphoreValueDifference"] = QVariant::fromValue(coreProps.maxTimelineSemaphoreValueDifference); core12Properties["framebufferIntegerColorSampleCounts"] = coreProps.framebufferIntegerColorSampleCounts; } From 42bce8f57b74b7186e143661fd4d9c67473898a9 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 22 Oct 2020 19:58:26 +0200 Subject: [PATCH 03/38] Version bump JSON export structure --- vulkanDeviceInfo.cpp | 42 ++++++++++++++++++++++++++++-------------- vulkancapsviewer.cpp | 4 ++-- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/vulkanDeviceInfo.cpp b/vulkanDeviceInfo.cpp index dde6741..99fb1f0 100644 --- a/vulkanDeviceInfo.cpp +++ b/vulkanDeviceInfo.cpp @@ -436,7 +436,7 @@ void VulkanDeviceInfo::readPhysicalFeatures() core11Features.clear(); core11Features["storageBuffer16BitAccess"] = coreFeatures.storageBuffer16BitAccess; - core11Features["uniformAndStorageBuffer16BitAcces"] = coreFeatures.uniformAndStorageBuffer16BitAccess; + core11Features["uniformAndStorageBuffer16BitAccess"] = coreFeatures.uniformAndStorageBuffer16BitAccess; core11Features["storagePushConstant16"] = coreFeatures.storagePushConstant16; core11Features["storageInputOutput16"] = coreFeatures.storageInputOutput16; core11Features["multiview"] = coreFeatures.multiview; @@ -683,12 +683,6 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) jsonProperties["sparseProperties"] = QJsonObject::fromVariantMap(sparseProperties); jsonProperties["subgroupProperties"] = QJsonObject::fromVariantMap(subgroupProperties); jsonProperties["limits"] = QJsonObject::fromVariantMap(limits); - if (!core11Properties.empty()) { - jsonProperties["core11"] = QJsonObject::fromVariantMap(core11Properties); - } - if (!core12Properties.empty()) { - jsonProperties["core12"] = QJsonObject::fromVariantMap(core12Properties); - } // Pipeline cache UUID QJsonArray jsonPipelineCache; for (uint32_t i = 0; i < VK_UUID_SIZE; i++) { @@ -697,19 +691,39 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) jsonPipelineCache.append(jsonVal); } jsonProperties["pipelineCacheUUID"] = jsonPipelineCache; - root["properties"] = jsonProperties; + if (!core12Properties.empty()) { + root["propertiesCore12"] = QJsonObject::fromVariantMap(core12Properties); + } + // Device features QJsonObject jsonFeatures; - jsonFeatures = QJsonObject::fromVariantMap(features); - if (!core11Properties.empty()) { - jsonFeatures["core11"] = QJsonObject::fromVariantMap(core11Features); + root["features"] = QJsonObject::fromVariantMap(features); + + // Core 1.1 + if ((!core11Properties.empty()) || (!core11Features.empty())) { + QJsonObject jsonCore11; + if (!core11Properties.empty()) { + jsonCore11["properties"] = QJsonObject::fromVariantMap(core11Properties); + } + if (!core11Features.empty()) { + jsonCore11["features"] = QJsonObject::fromVariantMap(core11Features); + } + root["core11"] = jsonCore11; } - if (!core12Properties.empty()) { - jsonFeatures["core12"] = QJsonObject::fromVariantMap(core12Features); + + // Core 1.2 + if ((!core11Properties.empty()) || (!core11Features.empty())) { + QJsonObject jsonCore12; + if (!core12Properties.empty()) { + jsonCore12["properties"] = QJsonObject::fromVariantMap(core12Properties); + } + if (!core12Features.empty()) { + jsonCore12["features"] = QJsonObject::fromVariantMap(core12Features); + } + root["core12"] = jsonCore12; } - root["features"] = jsonFeatures; // Extensions QJsonArray jsonExtensions; diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 450be3c..2658ede 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -77,8 +77,8 @@ using std::to_string; #define VK_API_VERSION VK_API_VERSION_1_1 -const std::string vulkanCapsViewer::version = "2.21"; -const std::string vulkanCapsViewer::reportVersion = "2.0"; +const std::string vulkanCapsViewer::version = "2.3"; +const std::string vulkanCapsViewer::reportVersion = "2.1"; /// /// Returns operating system name From 9db051d780dc5f278c10f0bfaf25ebafa20608af Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Wed, 23 Dec 2020 20:54:56 +0100 Subject: [PATCH 04/38] Display Core 1.1 and Core 1.2 features --- vulkancapsviewer.cpp | 57 +++++++++- vulkancapsviewer.h | 6 + vulkancapsviewer.ui | 261 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 266 insertions(+), 58 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 2658ede..42eb02c 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -192,10 +192,18 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) ui.treeViewDeviceLimits->setModel(&filterProxies.limits); filterProxies.limits.setSourceModel(&models.limits); connect(ui.filterLineEditLimits, SIGNAL(textChanged(QString)), this, SLOT(slotFilterLimits(QString))); - // Features + // Core 1.0 features ui.treeViewDeviceFeatures->setModel(&filterProxies.features); filterProxies.features.setSourceModel(&models.features); connect(ui.filterLineEditFeatures, SIGNAL(textChanged(QString)), this, SLOT(slotFilterFeatures(QString))); + // Core 1.1 features + ui.treeViewDeviceFeaturesCore11->setModel(&filterProxies.featuresCore11); + filterProxies.featuresCore11.setSourceModel(&models.featuresCore11); + connect(ui.filterLineEditFeaturesCore11, SIGNAL(textChanged(QString)), this, SLOT(slotFilterFeaturesCore11(QString))); + // Core 1.2 features + ui.treeViewDeviceFeaturesCore12->setModel(&filterProxies.featuresCore12); + filterProxies.featuresCore12.setSourceModel(&models.featuresCore12); + connect(ui.filterLineEditFeaturesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterFeaturesCore12(QString))); // Extensions ui.treeViewDeviceExtensions->setModel(&filterProxies.extensions); filterProxies.extensions.setSourceModel(&models.extensions); @@ -368,6 +376,18 @@ void vulkanCapsViewer::slotFilterFeatures(QString text) filterProxies.features.setFilterRegExp(regExp); } +void vulkanCapsViewer::slotFilterFeaturesCore11(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.featuresCore11.setFilterRegExp(regExp); +} + +void vulkanCapsViewer::slotFilterFeaturesCore12(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.featuresCore12.setFilterRegExp(regExp); +} + void vulkanCapsViewer::slotFilterExtensions(QString text) { QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); @@ -1024,10 +1044,9 @@ void vulkanCapsViewer::displayDeviceLimits(VulkanDeviceInfo *device) void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) { + // Core 1.0 models.features.clear(); QStandardItem *rootItem = models.features.invisibleRootItem(); - - // Basic features for(QVariantMap::const_iterator iter = device->features.begin(); iter != device->features.end(); ++iter) { QList rowItems; rowItems << new QStandardItem(iter.key()); @@ -1035,10 +1054,38 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); rootItem->appendRow(rowItems); } - ui.treeViewDeviceFeatures->expandAll(); ui.treeViewDeviceFeatures->header()->setSectionResizeMode(QHeaderView::ResizeToContents); - ui.treeViewDeviceFeatures->header()->setStretchLastSection(false); + + // Core 1.1 + if (!(device->core11Features.empty())) { + models.featuresCore11.clear(); + QStandardItem *rootItem = models.featuresCore11.invisibleRootItem(); + for(QVariantMap::const_iterator iter = device->core11Features.begin(); iter != device->core11Features.end(); ++iter) { + QList rowItems; + rowItems << new QStandardItem(iter.key()); + rowItems << new QStandardItem(iter.value().toBool() ? "true" : "false"); + rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); + rootItem->appendRow(rowItems); + } + ui.treeViewDeviceFeaturesCore11->expandAll(); + ui.treeViewDeviceFeaturesCore11->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + } + + // Core 1.2 + if (!(device->core12Features.empty())) { + models.featuresCore12.clear(); + QStandardItem *rootItem = models.featuresCore12.invisibleRootItem(); + for(QVariantMap::const_iterator iter = device->core12Features.begin(); iter != device->core12Features.end(); ++iter) { + QList rowItems; + rowItems << new QStandardItem(iter.key()); + rowItems << new QStandardItem(iter.value().toBool() ? "true" : "false"); + rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); + rootItem->appendRow(rowItems); + } + ui.treeViewDeviceFeaturesCore12->expandAll(); + ui.treeViewDeviceFeaturesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + } } void vulkanCapsViewer::displayGlobalLayers(QTreeWidget *tree) diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index b4e3d3b..c6f05fd 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -58,12 +58,16 @@ class vulkanCapsViewer : public QMainWindow struct { TreeProxyFilter limits; TreeProxyFilter features; + TreeProxyFilter featuresCore11; + TreeProxyFilter featuresCore12; TreeProxyFilter formats; TreeProxyFilter extensions; } filterProxies; struct { QStandardItemModel limits; QStandardItemModel features; + QStandardItemModel featuresCore11; + QStandardItemModel featuresCore12; QStandardItemModel formats; QStandardItemModel extensions; } models; @@ -97,6 +101,8 @@ private Q_SLOTS: void slotSettings(); void slotFilterLimits(QString text); void slotFilterFeatures(QString text); + void slotFilterFeaturesCore11(QString text); + void slotFilterFeaturesCore12(QString text); void slotFilterExtensions(QString text); void slotFilterFormats(QString text); void slotComboTabChanged(int index); diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index 4da6481..39bc3e0 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -82,6 +82,10 @@ QTreeView::item { QTreeView { font-size: 12px; +} + +QTreeView { + alternate-background-color: #F6F6F6; } @@ -623,63 +627,214 @@ height: 24px; - + Features - - - - - - 0 - - - 2 - - - 0 - - - 2 - - - - - - 0 - 0 - - - - - - - - Filter : - - - - - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - QTreeView::item { height: 1.25em; } - - - QAbstractItemView::NoEditTriggers - - - true + + + 0 - - false - - - 200 - + + + Core 1.0 + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + + + + Core 1.1 + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + + + + Core 1.2 + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + @@ -1046,7 +1201,7 @@ height: 24px; 0 - 5 + 0 0 From 55476f7b537bf7b4e73038a803c0481aa589396e Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 11:19:44 +0100 Subject: [PATCH 05/38] Display Core 1.1 and Core 1.2 properties --- vulkancapsviewer.cpp | 71 +++++++++++++++++++++++++++++++++++++++++--- vulkancapsviewer.h | 37 ++++++++++++++++++++--- 2 files changed, 100 insertions(+), 8 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 42eb02c..b7ef8f4 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -2,7 +2,7 @@ * * Vulkan hardware capability viewer * -* Copyright (C) 2016 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -192,6 +192,18 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) ui.treeViewDeviceLimits->setModel(&filterProxies.limits); filterProxies.limits.setSourceModel(&models.limits); connect(ui.filterLineEditLimits, SIGNAL(textChanged(QString)), this, SLOT(slotFilterLimits(QString))); + // Core 1.0 properties + ui.treeViewDeviceProperties->setModel(&filterProxies.propertiesCore10); + filterProxies.features.setSourceModel(&models.propertiesCore10); + connect(ui.filterLineEditProperties, SIGNAL(textChanged(QString)), this, SLOT(slotFilterProperties10(QString))); + // Core 1.1 properties + ui.treeViewDevicePropertiesCore11->setModel(&filterProxies.propertiesCore11); + filterProxies.propertiesCore11.setSourceModel(&models.propertiesCore11); + connect(ui.filterLineEditPropertiesCore11, SIGNAL(textChanged(QString)), this, SLOT(slotFilterProperties11(QString))); + // Core 1.2 properties + ui.treeViewDevicePropertiesCore12->setModel(&filterProxies.propertiesCore12); + filterProxies.propertiesCore12.setSourceModel(&models.propertiesCore12); + connect(ui.filterLineEditPropertiesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterProperties11(QString))); // Core 1.0 features ui.treeViewDeviceFeatures->setModel(&filterProxies.features); filterProxies.features.setSourceModel(&models.features); @@ -370,6 +382,24 @@ void vulkanCapsViewer::slotFilterLimits(QString text) filterProxies.limits.setFilterRegExp(regExp); } +void vulkanCapsViewer::slotFilterPropertiesCore10(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.propertiesCore10.setFilterRegExp(regExp); +} + +void vulkanCapsViewer::slotFilterPropertiesCore11(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.propertiesCore11.setFilterRegExp(regExp); +} + +void vulkanCapsViewer::slotFilterPropertiesCore12(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.propertiesCore12.setFilterRegExp(regExp); +} + void vulkanCapsViewer::slotFilterFeatures(QString text) { QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); @@ -966,6 +996,36 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) for (int i = 0; i < treeWidget->columnCount(); i++) treeWidget->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); + + // Core 1.1 + if (!(device->core11Properties.empty())) { + models.propertiesCore11.clear(); + QStandardItem* rootItem = models.propertiesCore11.invisibleRootItem(); + for (QVariantMap::const_iterator iter = device->core11Properties.begin(); iter != device->core11Properties.end(); ++iter) { + QList rowItems; + // @todo: Special treatment for values like UUIDs + rowItems << new QStandardItem(iter.key()); + rowItems << new QStandardItem(iter.value().toString()); + rootItem->appendRow(rowItems); + } + ui.treeViewDevicePropertiesCore11->expandAll(); + ui.treeViewDevicePropertiesCore11->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + } + + // Core 1.2 + if (!(device->core12Properties.empty())) { + models.propertiesCore12.clear(); + QStandardItem* rootItem = models.propertiesCore12.invisibleRootItem(); + for (QVariantMap::const_iterator iter = device->core12Properties.begin(); iter != device->core12Properties.end(); ++iter) { + QList rowItems; + // @todo: Special treatment for values like UUIDs + rowItems << new QStandardItem(iter.key()); + rowItems << new QStandardItem(iter.value().toString()); + rootItem->appendRow(rowItems); + } + ui.treeViewDevicePropertiesCore12->expandAll(); + ui.treeViewDevicePropertiesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + } } void vulkanCapsViewer::displayDeviceMemoryProperites(VulkanDeviceInfo *device) @@ -1114,7 +1174,8 @@ void vulkanCapsViewer::displayDeviceLayers(VulkanDeviceInfo *device) QTreeWidget *treeWidget = ui.treeWidgetDeviceLayers; treeWidget->clear(); - ui.tabWidgetDevice->setTabText(5, "Layers (" + QString::number(device->getLayers().size()) + ")"); + // @todo: adjust to new structure +// ui.tabWidgetDevice->setTabText(5, "Layers (" + QString::number(device->getLayers().size()) + ")"); for (auto& layer : device->getLayers()) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(treeWidget); @@ -1268,7 +1329,8 @@ QString arrayToStr(QVariant value) { */ void vulkanCapsViewer::displayDeviceExtensions(VulkanDeviceInfo *device) { - ui.tabWidgetDevice->setTabText(3, "Extensions (" + QString::number(device->extensions.size()) + ")"); + // @todo: adjust to new structure + //ui.tabWidgetDevice->setTabText(3, "Extensions (" + QString::number(device->extensions.size()) + ")"); models.extensions.clear(); QStandardItem *rootItem = models.extensions.invisibleRootItem(); @@ -1338,7 +1400,8 @@ void vulkanCapsViewer::displayDeviceExtensions(VulkanDeviceInfo *device) void vulkanCapsViewer::displayDeviceQueues(VulkanDeviceInfo *device) { - ui.tabWidgetDevice->setTabText(6, "Queues Families (" + QString::number(device->queueFamilies.size()) + ")"); + // @todo: adjust to new structure + //ui.tabWidgetDevice->setTabText(6, "Queues Families (" + QString::number(device->queueFamilies.size()) + ")"); QTreeWidget* treeWidget = ui.treeWidgetQueues; treeWidget->clear(); for (auto& queueFamily : device->queueFamilies) diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index c6f05fd..04ccd0f 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -1,3 +1,23 @@ +/* +* +* Vulkan hardware capability viewer +* +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) +* +* This code is free software, you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License version 3 as published by the Free Software Foundation. +* +* Please review the following information to ensure the GNU Lesser +* General Public License version 3 requirements will be met: +* http://opensource.org/licenses/lgpl-3.0.html +* +* The code is distributed WITHOUT ANY WARRANTY; without even the +* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +* PURPOSE. See the GNU LGPL 3.0 for more details. +* +*/ + #ifndef VULKANCAPSVIEWER_H #define VULKANCAPSVIEWER_H @@ -56,8 +76,11 @@ class vulkanCapsViewer : public QMainWindow Ui::vulkanCapsViewerClass ui; settings appSettings; struct { - TreeProxyFilter limits; - TreeProxyFilter features; + TreeProxyFilter limits; + TreeProxyFilter propertiesCore10; + TreeProxyFilter propertiesCore11; + TreeProxyFilter propertiesCore12; + TreeProxyFilter features; TreeProxyFilter featuresCore11; TreeProxyFilter featuresCore12; TreeProxyFilter formats; @@ -65,7 +88,10 @@ class vulkanCapsViewer : public QMainWindow } filterProxies; struct { QStandardItemModel limits; - QStandardItemModel features; + QStandardItemModel propertiesCore10; + QStandardItemModel propertiesCore11; + QStandardItemModel propertiesCore12; + QStandardItemModel features; QStandardItemModel featuresCore11; QStandardItemModel featuresCore12; QStandardItemModel formats; @@ -100,7 +126,10 @@ private Q_SLOTS: void slotUploadReport(); void slotSettings(); void slotFilterLimits(QString text); - void slotFilterFeatures(QString text); + void slotFilterPropertiesCore10(QString text); + void slotFilterPropertiesCore11(QString text); + void slotFilterPropertiesCore12(QString text); + void slotFilterFeatures(QString text); void slotFilterFeaturesCore11(QString text); void slotFilterFeaturesCore12(QString text); void slotFilterExtensions(QString text); From 61f3d0e2562179f3ef25f31ca3141ac6bc0e6032 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 11:31:46 +0100 Subject: [PATCH 06/38] Display Core 1.1 and Core 1.2 properties --- vulkancapsviewer.cpp | 6 +- vulkancapsviewer.ui | 214 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 216 insertions(+), 4 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index b7ef8f4..8af5495 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -195,15 +195,15 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) // Core 1.0 properties ui.treeViewDeviceProperties->setModel(&filterProxies.propertiesCore10); filterProxies.features.setSourceModel(&models.propertiesCore10); - connect(ui.filterLineEditProperties, SIGNAL(textChanged(QString)), this, SLOT(slotFilterProperties10(QString))); + connect(ui.filterLineEditProperties, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesCore10(QString))); // Core 1.1 properties ui.treeViewDevicePropertiesCore11->setModel(&filterProxies.propertiesCore11); filterProxies.propertiesCore11.setSourceModel(&models.propertiesCore11); - connect(ui.filterLineEditPropertiesCore11, SIGNAL(textChanged(QString)), this, SLOT(slotFilterProperties11(QString))); + connect(ui.filterLineEditPropertiesCore11, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesCore11(QString))); // Core 1.2 properties ui.treeViewDevicePropertiesCore12->setModel(&filterProxies.propertiesCore12); filterProxies.propertiesCore12.setSourceModel(&models.propertiesCore12); - connect(ui.filterLineEditPropertiesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterProperties11(QString))); + connect(ui.filterLineEditPropertiesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesCore12(QString))); // Core 1.0 features ui.treeViewDeviceFeatures->setModel(&filterProxies.features); filterProxies.features.setSourceModel(&models.features); diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index 39bc3e0..724aa47 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -580,7 +580,7 @@ height: 24px; QTabWidget::Rounded - 0 + 1 false @@ -627,6 +627,218 @@ height: 24px; + + + Properties + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + Core 1.0 + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + + + + Core 1.1 + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + + + + Core 1.2 + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + + + + + Features From ab80b9f30c3e4bd5905b0ff9dc5c1d8d1874131a Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 12:12:28 +0100 Subject: [PATCH 07/38] Refactoring --- vulkancapsviewer.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 8af5495..380b10d 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -883,6 +883,15 @@ QTreeWidgetItem *addTreeItemFlags(QTreeWidgetItem *parent, const std::string& fl return flagsItem; } +void addVkBool32Item(QStandardItem* parent, const QVariantMap::const_iterator& iterator) +{ + QList item; + item << new QStandardItem(iterator.key()); + item << new QStandardItem(iterator.value().toBool() ? "true" : "false"); + item[1]->setForeground(iterator.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); + parent->appendRow(item); +} + /// /// Display information on given device /// @@ -1108,11 +1117,7 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) models.features.clear(); QStandardItem *rootItem = models.features.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->features.begin(); iter != device->features.end(); ++iter) { - QList rowItems; - rowItems << new QStandardItem(iter.key()); - rowItems << new QStandardItem(iter.value().toBool() ? "true" : "false"); - rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); - rootItem->appendRow(rowItems); + addVkBool32Item(rootItem, iter); } ui.treeViewDeviceFeatures->expandAll(); ui.treeViewDeviceFeatures->header()->setSectionResizeMode(QHeaderView::ResizeToContents); @@ -1122,11 +1127,7 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) models.featuresCore11.clear(); QStandardItem *rootItem = models.featuresCore11.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->core11Features.begin(); iter != device->core11Features.end(); ++iter) { - QList rowItems; - rowItems << new QStandardItem(iter.key()); - rowItems << new QStandardItem(iter.value().toBool() ? "true" : "false"); - rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); - rootItem->appendRow(rowItems); + addVkBool32Item(rootItem, iter); } ui.treeViewDeviceFeaturesCore11->expandAll(); ui.treeViewDeviceFeaturesCore11->header()->setSectionResizeMode(QHeaderView::ResizeToContents); @@ -1137,11 +1138,7 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) models.featuresCore12.clear(); QStandardItem *rootItem = models.featuresCore12.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->core12Features.begin(); iter != device->core12Features.end(); ++iter) { - QList rowItems; - rowItems << new QStandardItem(iter.key()); - rowItems << new QStandardItem(iter.value().toBool() ? "true" : "false"); - rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); - rootItem->appendRow(rowItems); + addVkBool32Item(rootItem, iter); } ui.treeViewDeviceFeaturesCore12->expandAll(); ui.treeViewDeviceFeaturesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); From de6684851c972adcc3a8da0960737ba5843d0899 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 12:23:21 +0100 Subject: [PATCH 08/38] Added visualization mapping tables --- vulkanresources.h | 58 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/vulkanresources.h b/vulkanresources.h index 7c0e89b..a73b44f 100644 --- a/vulkanresources.h +++ b/vulkanresources.h @@ -4,7 +4,7 @@ * * Helpers converting Vulkan entities to strings * -* Copyright (C) 2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2015-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,9 +31,9 @@ #include #include +#include #include "vulkan/vulkan.h" - namespace vulkanResources { template inline std::string toHexString(const Number number) @@ -615,4 +615,58 @@ namespace vulkanResources { return joinString('.', versionAsStringList); } + + // Values that are treated as sample counts + const QSet sampleFlagsValueNames = { + "framebufferColorSampleCounts", + "framebufferDepthSampleCounts", + "framebufferStencilSampleCounts", + "framebufferNoAttachmentsSampleCounts", + "sampledImageColorSampleCounts", + "sampledImageIntegerSampleCounts", + "sampledImageDepthSampleCounts", + "sampledImageStencilSampleCounts", + "storageImageSampleCounts", + // Core 1.2 + "framebufferIntegerColorSampleCounts" + }; + + // Values that are treated as booleans + const QSet boolValueNames = { + "timestampComputeAndGraphics", + "strictLines", + "standardSampleLocations", + // Core 1.1 + "deviceLUIDValid", + "subgroupQuadOperationsInAllStages", + "protectedNoFault", + // Core 1.2 + "shaderSignedZeroInfNanPreserveFloat16", + "shaderSignedZeroInfNanPreserveFloat32", + "shaderSignedZeroInfNanPreserveFloat64", + "shaderDenormPreserveFloat16", + "shaderDenormPreserveFloat32", + "shaderDenormPreserveFloat64", + "shaderDenormFlushToZeroFloat16", + "shaderDenormFlushToZeroFloat32", + "shaderDenormFlushToZeroFloat64", + "shaderRoundingModeRTEFloat16", + "shaderRoundingModeRTEFloat32", + "shaderRoundingModeRTEFloat64", + "shaderRoundingModeRTZFloat16", + "shaderRoundingModeRTZFloat32", + "shaderRoundingModeRTZFloat64", + "shaderUniformBufferArrayNonUniformIndexingNative", + "shaderSampledImageArrayNonUniformIndexingNative", + "shaderStorageBufferArrayNonUniformIndexingNative", + "shaderStorageImageArrayNonUniformIndexingNative", + "shaderInputAttachmentArrayNonUniformIndexingNative", + "robustBufferAccessUpdateAfterBind", + "quadDivergentImplicitLod", + "independentResolveNone", + "independentResolve", + "filterMinmaxSingleComponentFormats", + "filterMinmaxImageComponentMapping" + }; + }; From a09682bc7b9f377c13d1678cf4f9015fb06b5010 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 12:23:52 +0100 Subject: [PATCH 09/38] Property visualization --- vulkancapsviewer.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 380b10d..17a15bb 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -892,6 +892,19 @@ void addVkBool32Item(QStandardItem* parent, const QVariantMap::const_iterator& i parent->appendRow(item); } +void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& iterator) +{ + if (vulkanResources::boolValueNames.contains(iterator.key())) { + addVkBool32Item(parent, iterator); + return; + }; + QList item; + // @todo: Special treatment for values like UUIDs + item << new QStandardItem(iterator.key()); + item << new QStandardItem(iterator.value().toString()); + parent->appendRow(item); +} + /// /// Display information on given device /// @@ -1011,11 +1024,7 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) models.propertiesCore11.clear(); QStandardItem* rootItem = models.propertiesCore11.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->core11Properties.begin(); iter != device->core11Properties.end(); ++iter) { - QList rowItems; - // @todo: Special treatment for values like UUIDs - rowItems << new QStandardItem(iter.key()); - rowItems << new QStandardItem(iter.value().toString()); - rootItem->appendRow(rowItems); + addPropertiesRow(rootItem, iter); } ui.treeViewDevicePropertiesCore11->expandAll(); ui.treeViewDevicePropertiesCore11->header()->setSectionResizeMode(QHeaderView::ResizeToContents); @@ -1026,11 +1035,7 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) models.propertiesCore12.clear(); QStandardItem* rootItem = models.propertiesCore12.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->core12Properties.begin(); iter != device->core12Properties.end(); ++iter) { - QList rowItems; - // @todo: Special treatment for values like UUIDs - rowItems << new QStandardItem(iter.key()); - rowItems << new QStandardItem(iter.value().toString()); - rootItem->appendRow(rowItems); + addPropertiesRow(rootItem, iter); } ui.treeViewDevicePropertiesCore12->expandAll(); ui.treeViewDevicePropertiesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); From 3786e3e58082a5a53f3e19aa284c63d1f12829e8 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 12:24:03 +0100 Subject: [PATCH 10/38] Fixed filter --- vulkancapsviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 17a15bb..fcccf0f 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -194,7 +194,7 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) connect(ui.filterLineEditLimits, SIGNAL(textChanged(QString)), this, SLOT(slotFilterLimits(QString))); // Core 1.0 properties ui.treeViewDeviceProperties->setModel(&filterProxies.propertiesCore10); - filterProxies.features.setSourceModel(&models.propertiesCore10); + filterProxies.propertiesCore10.setSourceModel(&models.propertiesCore10); connect(ui.filterLineEditProperties, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesCore10(QString))); // Core 1.1 properties ui.treeViewDevicePropertiesCore11->setModel(&filterProxies.propertiesCore11); From 916d0a8371cc77b4b6b97600d4a185355403b2be Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 12:27:25 +0100 Subject: [PATCH 11/38] Property visualization Sample count flags --- vulkancapsviewer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index fcccf0f..60edc95 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -892,12 +892,26 @@ void addVkBool32Item(QStandardItem* parent, const QVariantMap::const_iterator& i parent->appendRow(item); } +void addVkSampleCountFlagsItem(QStandardItem* parent, const QVariantMap::const_iterator& iterator) +{ + const auto samples = static_cast(iterator.value().toUInt()); + QList item; + item << new QStandardItem(iterator.key()); + item << new QStandardItem(vulkanResources::toQStringList(samples)); + parent->appendRow(item); +} + void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { if (vulkanResources::boolValueNames.contains(iterator.key())) { addVkBool32Item(parent, iterator); return; }; + if (vulkanResources::sampleFlagsValueNames.contains(iterator.key())) { + addVkSampleCountFlagsItem(parent, iterator); + return; + } + QList item; // @todo: Special treatment for values like UUIDs item << new QStandardItem(iterator.key()); From 4c735a6813f24b5949bc0a982a0b857cfa085810 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 12:51:28 +0100 Subject: [PATCH 12/38] Property visualization UUIDs --- vulkancapsviewer.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 60edc95..f56fbd8 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -901,6 +901,21 @@ void addVkSampleCountFlagsItem(QStandardItem* parent, const QVariantMap::const_i parent->appendRow(item); } +void addUUIDItem(QStandardItem* parent, const QVariantMap::const_iterator& iterator) +{ + const QJsonArray values = iterator.value().toJsonArray(); + std::ostringstream uuidSs; + uuidSs << std::hex << std::noshowbase << std::uppercase; + for (uint32_t i = 0; i < values.size(); i++) { + uuidSs << std::right << std::setw(2) << std::setfill('0') << static_cast(values[i].toInt()); + if (i == 3 || i == 5 || i == 7 || i == 9) uuidSs << '-'; + } + QList item; + item << new QStandardItem(iterator.key()); + item << new QStandardItem(QString::fromStdString(uuidSs.str())); + parent->appendRow(item); +} + void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { if (vulkanResources::boolValueNames.contains(iterator.key())) { @@ -911,6 +926,10 @@ void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& addVkSampleCountFlagsItem(parent, iterator); return; } + if (vulkanResources::uuidValueNames.contains(iterator.key())) { + addUUIDItem(parent, iterator); + return; + } QList item; // @todo: Special treatment for values like UUIDs From 0582ef3e1cd3b5193a59beb56e2d337ff3c67771 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 13:30:51 +0100 Subject: [PATCH 13/38] Property visualization hex, lists --- vulkancapsviewer.cpp | 32 ++++++++++++++++++++++++++++++++ vulkanresources.h | 19 +++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index f56fbd8..9f7a9b3 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -916,6 +916,30 @@ void addUUIDItem(QStandardItem* parent, const QVariantMap::const_iterator& itera parent->appendRow(item); } +void addHexItem(QStandardItem* parent, const QVariantMap::const_iterator& iterator) +{ + QList item; + item << new QStandardItem(iterator.key()); + item << new QStandardItem(vulkanResources::toHexQString(iterator.value().toULongLong())); + parent->appendRow(item); +} + +void addVariantListItem(QStandardItem* parent, const QVariantMap::const_iterator& iterator) +{ + QList list = iterator.value().toList(); + QString listStr = "["; + for (int i = 0; i < list.size(); i++) { + listStr += list[i].toString(); + if (i < list.size() - 1) + listStr += ", "; + } + listStr += "]"; + QList item; + item << new QStandardItem(iterator.key()); + item << new QStandardItem(listStr); + parent->appendRow(item); +} + void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { if (vulkanResources::boolValueNames.contains(iterator.key())) { @@ -930,6 +954,14 @@ void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& addUUIDItem(parent, iterator); return; } + if (vulkanResources::hexValueNames.contains(iterator.key())) { + addHexItem(parent, iterator); + return; + } + if (iterator.value().canConvert(QVariant::List)) { + addVariantListItem(parent, iterator); + return; + } QList item; // @todo: Special treatment for values like UUIDs diff --git a/vulkanresources.h b/vulkanresources.h index a73b44f..633384e 100644 --- a/vulkanresources.h +++ b/vulkanresources.h @@ -616,7 +616,7 @@ namespace vulkanResources { return joinString('.', versionAsStringList); } - // Values that are treated as sample counts + // Values to be displayed as sample counts const QSet sampleFlagsValueNames = { "framebufferColorSampleCounts", "framebufferDepthSampleCounts", @@ -631,7 +631,7 @@ namespace vulkanResources { "framebufferIntegerColorSampleCounts" }; - // Values that are treated as booleans + // Values to be displayed as booleans const QSet boolValueNames = { "timestampComputeAndGraphics", "strictLines", @@ -669,4 +669,19 @@ namespace vulkanResources { "filterMinmaxImageComponentMapping" }; + // Values to be displayed as UUIds + const QSet uuidValueNames = { + "deviceUUID", + // Core 1.1 + "driverUUID", + "deviceLUID" + }; + + // Values to be displayed as hex + const QSet hexValueNames = { + "vendorID", + "deviceID" + }; + + }; From 267569e1aa81b1eca4b5a7b716dc159501fa6dc9 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 13:40:11 +0100 Subject: [PATCH 14/38] Skip and replace certain keys --- vulkancapsviewer.cpp | 21 ++++++++---- vulkanresources.h | 78 ++++++++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 9f7a9b3..3d1191e 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -942,19 +942,25 @@ void addVariantListItem(QStandardItem* parent, const QVariantMap::const_iterator void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { - if (vulkanResources::boolValueNames.contains(iterator.key())) { + QString key = iterator.key(); + + if (vulkanResources::skipValueNames.contains(key)) { + return; + } + + if (vulkanResources::boolValueNames.contains(key)) { addVkBool32Item(parent, iterator); return; }; - if (vulkanResources::sampleFlagsValueNames.contains(iterator.key())) { + if (vulkanResources::sampleFlagsValueNames.contains(key)) { addVkSampleCountFlagsItem(parent, iterator); return; } - if (vulkanResources::uuidValueNames.contains(iterator.key())) { + if (vulkanResources::uuidValueNames.contains(key)) { addUUIDItem(parent, iterator); return; } - if (vulkanResources::hexValueNames.contains(iterator.key())) { + if (vulkanResources::hexValueNames.contains(key)) { addHexItem(parent, iterator); return; } @@ -963,9 +969,12 @@ void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& return; } + if (vulkanResources::replaceKeyNames.contains(key)) { + key = vulkanResources::replaceKeyNames[key]; + } + QList item; - // @todo: Special treatment for values like UUIDs - item << new QStandardItem(iterator.key()); + item << new QStandardItem(key); item << new QStandardItem(iterator.value().toString()); parent->appendRow(item); } diff --git a/vulkanresources.h b/vulkanresources.h index 633384e..6aa982c 100644 --- a/vulkanresources.h +++ b/vulkanresources.h @@ -118,7 +118,7 @@ namespace vulkanResources { STR(VIRTUAL_GPU); STR(CPU); #undef STR - default: return "UNKNOWN_DEVICE_TYPE (" + toHexString(type) + ")"; + default: return "UNKNOWN_DEVICE_TYPE (" + toHexString(type) + ")"; } } @@ -160,7 +160,7 @@ namespace vulkanResources { STR(ERROR_INVALID_DEVICE_ADDRESS_EXT); STR(ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT); #undef STR - default: return "UNKNOWN_RESULT (" + toHexString(result) + ")"; + default: return "UNKNOWN_RESULT (" + toHexString(result) + ")"; } } @@ -389,7 +389,7 @@ namespace vulkanResources { STR(G16_B16R16_2PLANE_422_UNORM); STR(G16_B16_R16_3PLANE_444_UNORM); #undef STR - default: return "UNKNOWN_ENUM (" + toHexString(format) + ")"; + default: return "UNKNOWN_ENUM (" + toHexString(format) + ")"; } } @@ -405,7 +405,7 @@ namespace vulkanResources { STR(SHARED_DEMAND_REFRESH); STR(SHARED_CONTINUOUS_REFRESH); #undef STR - default: return "UNKNOWN_ENUM (" + toHexString(presentMode) + ")"; + default: return "UNKNOWN_ENUM (" + toHexString(presentMode) + ")"; } } @@ -431,13 +431,13 @@ namespace vulkanResources { STR(EXTENDED_SRGB_NONLINEAR_EXT); STR(DISPLAY_NATIVE_AMD); #undef STR - default: return "UNKNOWN_ENUM (" + toHexString(colorSpace) + ")"; + default: return "UNKNOWN_ENUM (" + toHexString(colorSpace) + ")"; } } inline std::string driverIdKHRString(const VkDriverIdKHR driverId) { - switch(driverId){ + switch (driverId) { #define STR(r) case VK_DRIVER_ID_##r##_KHR: return #r STR(AMD_PROPRIETARY); STR(AMD_OPEN_SOURCE); @@ -452,13 +452,13 @@ namespace vulkanResources { STR(GGP_PROPRIETARY); STR(BROADCOM_PROPRIETARY); #undef STR - default: return "UNKNOWN_ENUM (" + toHexString(driverId) + ")"; + default: return "UNKNOWN_ENUM (" + toHexString(driverId) + ")"; }; } inline std::string imageUsageBitString(const VkImageUsageFlagBits usageBit) { - switch(usageBit){ + switch (usageBit) { #define STR(r) case VK_IMAGE_USAGE_##r: return #r STR(TRANSFER_SRC_BIT); STR(TRANSFER_DST_BIT); @@ -471,13 +471,13 @@ namespace vulkanResources { STR(SHADING_RATE_IMAGE_BIT_NV); STR(FRAGMENT_DENSITY_MAP_BIT_EXT); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(usageBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(usageBit) + ")"; }; } inline std::string surfaceTransformBitString(const VkSurfaceTransformFlagBitsKHR transformBit) { - switch(transformBit){ + switch (transformBit) { #define STR(r) case VK_SURFACE_TRANSFORM_##r##_KHR: return #r STR(IDENTITY_BIT); STR(ROTATE_90_BIT); @@ -489,26 +489,26 @@ namespace vulkanResources { STR(HORIZONTAL_MIRROR_ROTATE_270_BIT); STR(INHERIT_BIT); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(transformBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(transformBit) + ")"; }; } inline std::string compositeAlphaBitString(const VkCompositeAlphaFlagBitsKHR alphaBit) { - switch(alphaBit){ + switch (alphaBit) { #define STR(r) case VK_COMPOSITE_ALPHA_##r##_KHR: return #r STR(OPAQUE_BIT); STR(PRE_MULTIPLIED_BIT); STR(POST_MULTIPLIED_BIT); STR(INHERIT_BIT); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(alphaBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(alphaBit) + ")"; }; } inline std::string memoryPropBitString(const VkMemoryPropertyFlagBits memoryPropBit) { - switch(memoryPropBit){ + switch (memoryPropBit) { #define STR(r) case VK_MEMORY_PROPERTY_##r: return #r STR(DEVICE_LOCAL_BIT); STR(HOST_VISIBLE_BIT); @@ -519,24 +519,24 @@ namespace vulkanResources { STR(DEVICE_COHERENT_BIT_AMD); STR(DEVICE_UNCACHED_BIT_AMD); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(memoryPropBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(memoryPropBit) + ")"; }; } inline std::string memoryHeapBitString(const VkMemoryPropertyFlagBits heapBit) { - switch(heapBit){ + switch (heapBit) { #define STR(r) case VK_MEMORY_HEAP_##r: return #r STR(DEVICE_LOCAL_BIT); STR(MULTI_INSTANCE_BIT); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(heapBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(heapBit) + ")"; }; } inline std::string queueBitString(const VkQueueFlagBits queueBit) { - switch(queueBit){ + switch (queueBit) { #define STR(r) case VK_QUEUE_##r: return #r STR(GRAPHICS_BIT); STR(COMPUTE_BIT); @@ -544,13 +544,13 @@ namespace vulkanResources { STR(SPARSE_BINDING_BIT); STR(PROTECTED_BIT); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(queueBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(queueBit) + ")"; }; } inline std::string subgroupFeatureBitString(const VkSubgroupFeatureFlagBits subgroupBit) { - switch(subgroupBit){ + switch (subgroupBit) { #define STR(r) case VK_SUBGROUP_FEATURE_##r: return #r STR(BASIC_BIT); STR(VOTE_BIT); @@ -562,13 +562,13 @@ namespace vulkanResources { STR(QUAD_BIT); STR(PARTITIONED_BIT_NV); #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(subgroupBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(subgroupBit) + ")"; }; } inline std::string shaderStagesBitString(const VkShaderStageFlagBits stageBit) { - switch(stageBit){ + switch (stageBit) { #define STR(r) case VK_SHADER_STAGE_##r: return #r STR(VERTEX_BIT); STR(TESSELLATION_CONTROL_BIT); @@ -587,7 +587,7 @@ namespace vulkanResources { STR(MESH_BIT_NV); STR(ALL); // technically not a single bit, but it should work here #undef STR - default: return "UNKNOWN_FLAG (" + toHexString(stageBit) + ")"; + default: return "UNKNOWN_FLAG (" + toHexString(stageBit) + ")"; }; } @@ -606,7 +606,7 @@ namespace vulkanResources { inline std::string conformanceVersionKHRString(const VkConformanceVersionKHR& conformanceVersion) { - const std::vector versionAsList = {conformanceVersion.major, conformanceVersion.minor, conformanceVersion.subminor, conformanceVersion.patch}; + const std::vector versionAsList = { conformanceVersion.major, conformanceVersion.minor, conformanceVersion.subminor, conformanceVersion.patch }; std::vector versionAsStringList; const auto u8ToString = [](const uint8_t num) { return std::to_string(static_cast(num)); @@ -618,13 +618,13 @@ namespace vulkanResources { // Values to be displayed as sample counts const QSet sampleFlagsValueNames = { - "framebufferColorSampleCounts", + "framebufferColorSampleCounts", "framebufferDepthSampleCounts", - "framebufferStencilSampleCounts", + "framebufferStencilSampleCounts", "framebufferNoAttachmentsSampleCounts", - "sampledImageColorSampleCounts", - "sampledImageIntegerSampleCounts", - "sampledImageDepthSampleCounts", + "sampledImageColorSampleCounts", + "sampledImageIntegerSampleCounts", + "sampledImageDepthSampleCounts", "sampledImageStencilSampleCounts", "storageImageSampleCounts", // Core 1.2 @@ -632,9 +632,9 @@ namespace vulkanResources { }; // Values to be displayed as booleans - const QSet boolValueNames = { - "timestampComputeAndGraphics", - "strictLines", + const QSet boolValueNames = { + "timestampComputeAndGraphics", + "strictLines", "standardSampleLocations", // Core 1.1 "deviceLUIDValid", @@ -683,5 +683,19 @@ namespace vulkanResources { "deviceID" }; + // Values not to be displayd + const QSet skipValueNames = { + "apiVersion", + "deviceType", + "driverVersion", + "headerversion" + }; + + // Key replacement for display + const QMap replaceKeyNames = { + { "apiVersionText", "apiVersion" }, + { "deviceTypeText", "driverVersion" }, + { "driverVersionText", "driverVersion" }, + }; }; From 709880742421b919c0397c50125265f8d16b7681 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 13:51:32 +0100 Subject: [PATCH 15/38] Reworked core 1.0 properties Removed separate limits page Limits are now part of the core 1.0 properties tab, like they should have been from the very beginning --- vulkancapsviewer.cpp | 82 +++++++++++++------------------------------- vulkancapsviewer.h | 4 --- vulkancapsviewer.ui | 60 +------------------------------- 3 files changed, 25 insertions(+), 121 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 3d1191e..31db026 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -188,10 +188,6 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) appSettings.restore(); // Models and filters - // Limits - ui.treeViewDeviceLimits->setModel(&filterProxies.limits); - filterProxies.limits.setSourceModel(&models.limits); - connect(ui.filterLineEditLimits, SIGNAL(textChanged(QString)), this, SLOT(slotFilterLimits(QString))); // Core 1.0 properties ui.treeViewDeviceProperties->setModel(&filterProxies.propertiesCore10); filterProxies.propertiesCore10.setSourceModel(&models.propertiesCore10); @@ -376,12 +372,6 @@ void vulkanCapsViewer::slotSettings() appSettings.restore(); } -void vulkanCapsViewer::slotFilterLimits(QString text) -{ - QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); - filterProxies.limits.setFilterRegExp(regExp); -} - void vulkanCapsViewer::slotFilterPropertiesCore10(QString text) { QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); @@ -991,7 +981,6 @@ void vulkanCapsViewer::displayDevice(int index) displayDeviceProperties(&device); displayDeviceMemoryProperites(&device); - displayDeviceLimits(&device); displayDeviceFeatures(&device); displayDeviceLayers(&device); displayDeviceFormats(&device); @@ -1026,14 +1015,6 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) } } - // Sparse properties - QTreeWidgetItem *parentItem = new QTreeWidgetItem(treeItem); - parentItem->setText(0, "sparse properties"); - treeItem->addChild(parentItem); - for(QVariantMap::const_iterator iter = device->sparseProperties.begin(); iter != device->sparseProperties.end(); ++iter) { - addTreeItemVkBool32(parentItem, iter.key().toStdString(), iter.value().toBool()); - } - // Subgroup operations properties if (device->hasSubgroupProperties) { QTreeWidgetItem *parentItem = new QTreeWidgetItem(treeItem); @@ -1093,6 +1074,30 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) for (int i = 0; i < treeWidget->columnCount(); i++) treeWidget->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); + // Core 1.0 + models.propertiesCore10.clear(); + QStandardItem* rootItem = models.propertiesCore10.invisibleRootItem(); + for (QVariantMap::const_iterator iter = device->properties.begin(); iter != device->properties.end(); ++iter) { + addPropertiesRow(rootItem, iter); + } + // Core 1.0 limits + QList core10LimitsItem; + core10LimitsItem << new QStandardItem("Limits"); + rootItem->appendRow(core10LimitsItem); + for (QVariantMap::const_iterator iter = device->limits.begin(); iter != device->limits.end(); ++iter) { + addPropertiesRow(core10LimitsItem[0], iter); + } + // Core 1.0 sparse properties + QList core10SparseItem; + core10SparseItem << new QStandardItem("Sparse properties"); + rootItem->appendRow(core10SparseItem); + for (QVariantMap::const_iterator iter = device->sparseProperties.begin(); iter != device->sparseProperties.end(); ++iter) { + addVkBool32Item(core10SparseItem[0], iter); + } + + ui.treeViewDeviceProperties->expandAll(); + ui.treeViewDeviceProperties->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + // Core 1.1 if (!(device->core11Properties.empty())) { models.propertiesCore11.clear(); @@ -1151,45 +1156,6 @@ void vulkanCapsViewer::displayDeviceMemoryProperites(VulkanDeviceInfo *device) treeWidget->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); } -void vulkanCapsViewer::displayDeviceLimits(VulkanDeviceInfo *device) -{ - const QSet sampleFlagsLims = { - "framebufferColorSampleCounts", "framebufferDepthSampleCounts", "framebufferStencilSampleCounts", "framebufferNoAttachmentsSampleCounts", - "sampledImageColorSampleCounts", "sampledImageIntegerSampleCounts", "sampledImageDepthSampleCounts", "sampledImageStencilSampleCounts", - "storageImageSampleCounts" - }; - - const QSet boolLims = {"timestampComputeAndGraphics", "strictLines", "standardSampleLocations"}; - - models.limits.clear(); - QStandardItem *rootItem = models.limits.invisibleRootItem(); - for(QVariantMap::const_iterator iter = device->limits.begin(); iter != device->limits.end(); ++iter) { - QList rowItems; - rowItems << new QStandardItem(iter.key()); - if (iter.value().canConvert(QVariant::List)) { - QList list = iter.value().toList(); - QString listStr = "["; - for (int i = 0; i < list.size(); i++) { - listStr += list[i].toString(); - if (i < list.size() - 1) - listStr += ", "; - } - listStr += "]"; - rowItems << new QStandardItem(listStr); - } else if (sampleFlagsLims.contains(iter.key())){ - const auto samples = static_cast(iter.value().toUInt()); - rowItems << new QStandardItem(vulkanResources::toQStringList(samples)); - } else if (boolLims.contains(iter.key())){ - rowItems << new QStandardItem(iter.value().toBool() ? "true" : "false"); - rowItems[1]->setForeground(iter.value().toBool() ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); - } else { - rowItems << new QStandardItem(iter.value().toString()); - } - rootItem->appendRow(rowItems); - } - ui.treeViewDeviceLimits->header()->setSectionResizeMode(QHeaderView::ResizeToContents); -} - void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) { // Core 1.0 diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index 04ccd0f..e754e0f 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -76,7 +76,6 @@ class vulkanCapsViewer : public QMainWindow Ui::vulkanCapsViewerClass ui; settings appSettings; struct { - TreeProxyFilter limits; TreeProxyFilter propertiesCore10; TreeProxyFilter propertiesCore11; TreeProxyFilter propertiesCore12; @@ -87,7 +86,6 @@ class vulkanCapsViewer : public QMainWindow TreeProxyFilter extensions; } filterProxies; struct { - QStandardItemModel limits; QStandardItemModel propertiesCore10; QStandardItemModel propertiesCore11; QStandardItemModel propertiesCore12; @@ -106,7 +104,6 @@ class vulkanCapsViewer : public QMainWindow void displayDevice(int index); void displayDeviceProperties(VulkanDeviceInfo *device); void displayDeviceMemoryProperites(VulkanDeviceInfo *device); - void displayDeviceLimits(VulkanDeviceInfo *device); void displayDeviceFeatures(VulkanDeviceInfo *device); void displayDeviceLayers(VulkanDeviceInfo *device); void displayDeviceFormats(VulkanDeviceInfo *device); @@ -125,7 +122,6 @@ private Q_SLOTS: void slotSaveReport(); void slotUploadReport(); void slotSettings(); - void slotFilterLimits(QString text); void slotFilterPropertiesCore10(QString text); void slotFilterPropertiesCore11(QString text); void slotFilterPropertiesCore12(QString text); diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index 724aa47..d94f508 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -1051,64 +1051,6 @@ height: 24px; - - - Limits - - - - - - - 0 - - - 2 - - - 0 - - - 2 - - - - - Filter : - - - - - - - - 0 - 0 - - - - - - - - - - - QTreeView::item { height: 1.25em; } - - - QAbstractItemView::NoEditTriggers - - - true - - - true - - - - - Extensions @@ -1530,7 +1472,7 @@ height: 24px; 0 0 927 - 20 + 21 From be18931628c7a10dc9828cd3a59788eda76f24cc Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 14:16:59 +0100 Subject: [PATCH 16/38] Subgroup related flags display --- vulkancapsviewer.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 31db026..88fe022 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -930,6 +930,38 @@ void addVariantListItem(QStandardItem* parent, const QVariantMap::const_iterator parent->appendRow(item); } +template +void addBitFlagsItem(QStandardItem* parent, const QString& key, const VkFlags flags, std::string(* const flagToString)(BitsType)) +{ + QList flagsParentItem; + flagsParentItem << new QStandardItem(key); + flagsParentItem << new QStandardItem(QString::fromStdString(vulkanResources::toHexString(flags))); + parent->appendRow(flagsParentItem); + for (typename std::underlying_type::type bit = 0x1; bit != 0; bit <<= 1) { + const QString bitName = QString::fromStdString(flagToString(static_cast(bit))); + if (flags & bit) { + QList flagItem; + flagItem << new QStandardItem(bitName); + flagItem << new QStandardItem(); + flagsParentItem[0]->appendRow(flagItem); + } + } + if (key == "subgroupSupportedStages") { + if ((flags & VK_SHADER_STAGE_ALL_GRAPHICS) == VK_SHADER_STAGE_ALL_GRAPHICS) { + QList flagItem; + flagItem << new QStandardItem(QString::fromStdString(vulkanResources::shaderStagesBitString(VK_SHADER_STAGE_ALL_GRAPHICS))); + flagItem << new QStandardItem(); + flagsParentItem[0]->appendRow(flagItem); + } + if ((flags & VK_SHADER_STAGE_ALL) == VK_SHADER_STAGE_ALL) { + QList flagItem; + flagItem << new QStandardItem(QString::fromStdString(vulkanResources::shaderStagesBitString(VK_SHADER_STAGE_ALL))); + flagItem << new QStandardItem(); + flagsParentItem[0]->appendRow(flagItem); + } + } +} + void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { QString key = iterator.key(); @@ -958,6 +990,16 @@ void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& addVariantListItem(parent, iterator); return; } + if (key == "subgroupSupportedOperations") { + const VkSubgroupFeatureFlags flags = iterator.value().toUInt(); + addBitFlagsItem(parent, iterator.key(), flags, vulkanResources::subgroupFeatureBitString); + return; + } + if (key == "subgroupSupportedStages") { + const VkShaderStageFlags flags = iterator.value().toUInt(); + addBitFlagsItem(parent, iterator.key(), flags, vulkanResources::shaderStagesBitString); + return; + } if (vulkanResources::replaceKeyNames.contains(key)) { key = vulkanResources::replaceKeyNames[key]; From c81dd5566a38d1421803838b4b1de93f0857ee03 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 14:48:49 +0100 Subject: [PATCH 17/38] Removed device tab All relevant information presented there has now been moved to the core 1.0 tab This is more in line with the Vulkan structures Additional code refactoring and cleanup --- vulkancapsviewer.cpp | 151 +++++++------------------------------------ vulkancapsviewer.h | 4 +- vulkancapsviewer.ui | 41 +----------- 3 files changed, 26 insertions(+), 170 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 88fe022..b09b6d1 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -201,8 +201,8 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) filterProxies.propertiesCore12.setSourceModel(&models.propertiesCore12); connect(ui.filterLineEditPropertiesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesCore12(QString))); // Core 1.0 features - ui.treeViewDeviceFeatures->setModel(&filterProxies.features); - filterProxies.features.setSourceModel(&models.features); + ui.treeViewDeviceFeatures->setModel(&filterProxies.featuresCore10); + filterProxies.featuresCore10.setSourceModel(&models.featuresCore10); connect(ui.filterLineEditFeatures, SIGNAL(textChanged(QString)), this, SLOT(slotFilterFeatures(QString))); // Core 1.1 features ui.treeViewDeviceFeaturesCore11->setModel(&filterProxies.featuresCore11); @@ -282,7 +282,7 @@ void vulkanCapsViewer::slotAbout() "Copyright (c) 2016-2020 by Sascha Willems

" "Build against Vulkan API " + vulkanApiVersion.toStdString() + " header version " + to_string(VK_HEADER_VERSION) + "

" - "This tool is FREEWARE

" + "This tool is Free Open Source Software

" "For usage and distribution details refer to the readme


" "https://www.gpuinfo.org

"; aboutText << "

"; @@ -393,7 +393,7 @@ void vulkanCapsViewer::slotFilterPropertiesCore12(QString text) void vulkanCapsViewer::slotFilterFeatures(QString text) { QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); - filterProxies.features.setFilterRegExp(regExp); + filterProxies.featuresCore10.setFilterRegExp(regExp); } void vulkanCapsViewer::slotFilterFeaturesCore11(QString text) @@ -814,32 +814,6 @@ QTreeWidgetItem *addTreeItem(QTreeWidgetItem *parent, const std::string& key, co return newItem; } -enum ItemFormat {DEFAULT_FORMAT, HEX_FORMAT}; -QTreeWidgetItem *addTreeItem(QTreeWidgetItem *parent, QVariantMap::const_iterator iter, const ItemFormat format = DEFAULT_FORMAT) -{ - // Map some key names to different display names - QMap replaceList; - replaceList["apiVersionText"] = "apiVersion"; - replaceList["deviceTypeText"] = "deviceType"; - replaceList["driverVersionText"] = "driverVersion"; - - QString keyName = iter.key(); - if (replaceList.contains(keyName)) { - keyName = replaceList[keyName]; - } - - QTreeWidgetItem *newItem = new QTreeWidgetItem(parent); - newItem->setText(0, keyName); - if (format == HEX_FORMAT){ - newItem->setText(1, vulkanResources::toHexQString(iter.value().toULongLong())); - } else { - assert(format == DEFAULT_FORMAT); - newItem->setText(1, iter.value().toString()); - } - parent->addChild(newItem); - return newItem; -} - QTreeWidgetItem *addTreeItemVkBool32(QTreeWidgetItem *parent, const std::string& key, const VkBool32 value) { QTreeWidgetItem *newItem = new QTreeWidgetItem(parent); @@ -891,13 +865,27 @@ void addVkSampleCountFlagsItem(QStandardItem* parent, const QVariantMap::const_i parent->appendRow(item); } +void addUUIDItem(QStandardItem* parent, const QString& key, uint8_t* UUID) +{ + std::ostringstream uuidSs; + uuidSs << std::hex << std::noshowbase << std::uppercase; + for (uint32_t i = 0; i < VK_UUID_SIZE; i++) { + uuidSs << std::right << std::setw(2) << std::setfill('0') << static_cast(UUID[i]); + if (i == 3 || i == 5 || i == 7 || i == 9) uuidSs << '-'; + } + QList item; + item << new QStandardItem(key); + item << new QStandardItem(QString::fromStdString(uuidSs.str())); + parent->appendRow(item); +} + void addUUIDItem(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { const QJsonArray values = iterator.value().toJsonArray(); std::ostringstream uuidSs; uuidSs << std::hex << std::noshowbase << std::uppercase; - for (uint32_t i = 0; i < values.size(); i++) { - uuidSs << std::right << std::setw(2) << std::setfill('0') << static_cast(values[i].toInt()); + for (size_t i = 0; i < values.size(); i++) { + uuidSs << std::right << std::setw(2) << std::setfill('0') << static_cast(values[static_cast(i)].toInt()); if (i == 3 || i == 5 || i == 7 || i == 9) uuidSs << '-'; } QList item; @@ -1011,9 +999,6 @@ void addPropertiesRow(QStandardItem* parent, const QVariantMap::const_iterator& parent->appendRow(item); } -/// -/// Display information on given device -/// void vulkanCapsViewer::displayDevice(int index) { assert(index < vulkanGPUs.size()); @@ -1035,93 +1020,13 @@ void vulkanCapsViewer::displayDevice(int index) void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) { - QTreeWidget *treeWidget = ui.treeWidgetDeviceProperties; - treeWidget->clear(); - QTreeWidgetItem *treeItem = treeWidget->invisibleRootItem(); - - - { - // Some keys are doubled for raw and readable data for vkjson compatiblity, filter them out and display readable versions only - const QSet skipList = {"apiVersion", "deviceType", "driverVersion", "headerversion"}; - - // Some values look better as hex int - const QSet hexList = {"vendorID", "deviceID"}; - - // Basic properties - for(QVariantMap::const_iterator iter = device->properties.begin(); iter != device->properties.end(); ++iter) { - const QString& propName = iter.key(); - if (skipList.contains(propName)) continue; - - const ItemFormat itemFormat = hexList.contains(propName) ? HEX_FORMAT : DEFAULT_FORMAT; - addTreeItem(treeItem, iter, itemFormat); - } - } - - // Subgroup operations properties - if (device->hasSubgroupProperties) { - QTreeWidgetItem *parentItem = new QTreeWidgetItem(treeItem); - parentItem->setText(0, "subgroup properties"); - for(QVariantMap::const_iterator iter = device->subgroupProperties.begin(); iter != device->subgroupProperties.end(); ++iter) { - QString keyName = iter.key(); - if (keyName == "quadOperationsInAllStages") { - addTreeItemVkBool32(parentItem, iter.key().toStdString(), iter.value().toBool()); - } - if (keyName == "subgroupSize") { - addTreeItem(parentItem, iter); - } - if (keyName == "supportedOperations") { - const VkSubgroupFeatureFlags flags = iter.value().toUInt(); - addTreeItemFlags(parentItem, iter.key().toStdString(), flags, vulkanResources::subgroupFeatureBitString); - } - if (keyName == "supportedStages") { - VkShaderStageFlags flags = iter.value().toUInt(); - QTreeWidgetItem *stagesItem = addTreeItemFlags(parentItem, iter.key().toStdString(), flags, vulkanResources::shaderStagesBitString); - addTreeItemFlag(stagesItem, - QString::fromStdString(vulkanResources::shaderStagesBitString(VK_SHADER_STAGE_ALL_GRAPHICS)), - (flags & VK_SHADER_STAGE_ALL_GRAPHICS) == VK_SHADER_STAGE_ALL_GRAPHICS); - addTreeItemFlag(stagesItem, - QString::fromStdString(vulkanResources::shaderStagesBitString(VK_SHADER_STAGE_ALL)), - (flags & VK_SHADER_STAGE_ALL) == VK_SHADER_STAGE_ALL); - } - } - } - - // Pipeline cache UUID - std::ostringstream uuidSs; - uuidSs << std::hex << std::noshowbase << std::nouppercase; - assert(VK_UUID_SIZE == 16); - for (uint32_t i = 0; i < VK_UUID_SIZE; ++i){ - uuidSs << std::right << std::setw(2) << std::setfill('0') << static_cast(device->props.pipelineCacheUUID[i]); - if (i == 3 || i == 5 || i == 7 || i == 9) uuidSs << '-'; - } - addTreeItem(treeItem, "pipelineCacheUUID", uuidSs.str()); - - // Operating system - stringstream ss; - ss << device->os.name << " " << device->os.version << " (" << device->os.architecture << ")"; - addTreeItem(treeItem, "operatingsystem", ss.str()); - - // Platform specific info - if (device->platformdetails.size() > 0) { - QTreeWidgetItem *platformItem = new QTreeWidgetItem(treeItem); - platformItem->setText(0, "Platform details"); - treeItem->addChild(platformItem); - for (auto& detail : device->platformdetails) { - addTreeItem(platformItem, detail.first, detail.second); - } - } - - ui.treeWidgetDeviceProperties->expandAll(); - - for (int i = 0; i < treeWidget->columnCount(); i++) - treeWidget->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); - // Core 1.0 models.propertiesCore10.clear(); QStandardItem* rootItem = models.propertiesCore10.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->properties.begin(); iter != device->properties.end(); ++iter) { addPropertiesRow(rootItem, iter); } + addUUIDItem(rootItem, "pipelineCacheUUID", device->props.pipelineCacheUUID); // Core 1.0 limits QList core10LimitsItem; core10LimitsItem << new QStandardItem("Limits"); @@ -1201,8 +1106,8 @@ void vulkanCapsViewer::displayDeviceMemoryProperites(VulkanDeviceInfo *device) void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) { // Core 1.0 - models.features.clear(); - QStandardItem *rootItem = models.features.invisibleRootItem(); + models.featuresCore10.clear(); + QStandardItem *rootItem = models.featuresCore10.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->features.begin(); iter != device->features.end(); ++iter) { addVkBool32Item(rootItem, iter); } @@ -1258,8 +1163,6 @@ void vulkanCapsViewer::displayDeviceLayers(VulkanDeviceInfo *device) QTreeWidget *treeWidget = ui.treeWidgetDeviceLayers; treeWidget->clear(); - // @todo: adjust to new structure -// ui.tabWidgetDevice->setTabText(5, "Layers (" + QString::number(device->getLayers().size()) + ")"); for (auto& layer : device->getLayers()) { QTreeWidgetItem *treeItem = new QTreeWidgetItem(treeWidget); @@ -1408,14 +1311,8 @@ QString arrayToStr(QVariant value) { return listStr; } -/* - Fill extension tree model incudling extension features and properties -*/ void vulkanCapsViewer::displayDeviceExtensions(VulkanDeviceInfo *device) { - // @todo: adjust to new structure - //ui.tabWidgetDevice->setTabText(3, "Extensions (" + QString::number(device->extensions.size()) + ")"); - models.extensions.clear(); QStandardItem *rootItem = models.extensions.invisibleRootItem(); @@ -1484,8 +1381,6 @@ void vulkanCapsViewer::displayDeviceExtensions(VulkanDeviceInfo *device) void vulkanCapsViewer::displayDeviceQueues(VulkanDeviceInfo *device) { - // @todo: adjust to new structure - //ui.tabWidgetDevice->setTabText(6, "Queues Families (" + QString::number(device->queueFamilies.size()) + ")"); QTreeWidget* treeWidget = ui.treeWidgetQueues; treeWidget->clear(); for (auto& queueFamily : device->queueFamilies) diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index e754e0f..b5c4b22 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -79,7 +79,7 @@ class vulkanCapsViewer : public QMainWindow TreeProxyFilter propertiesCore10; TreeProxyFilter propertiesCore11; TreeProxyFilter propertiesCore12; - TreeProxyFilter features; + TreeProxyFilter featuresCore10; TreeProxyFilter featuresCore11; TreeProxyFilter featuresCore12; TreeProxyFilter formats; @@ -89,7 +89,7 @@ class vulkanCapsViewer : public QMainWindow QStandardItemModel propertiesCore10; QStandardItemModel propertiesCore11; QStandardItemModel propertiesCore12; - QStandardItemModel features; + QStandardItemModel featuresCore10; QStandardItemModel featuresCore11; QStandardItemModel featuresCore12; QStandardItemModel formats; diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index d94f508..32de8f9 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -580,7 +580,7 @@ height: 24px; QTabWidget::Rounded - 1 + 0 false @@ -588,45 +588,6 @@ height: 24px; false - - - Device - - - - - - QTreeView::item { height: 1.25em; } - - - QAbstractItemView::NoEditTriggers - - - true - - - true - - - 200 - - - true - - - - key - - - - - value - - - - - - Properties From f48e41c19e1f4333d33c64a2212ee8b3029a142a Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 15:36:11 +0100 Subject: [PATCH 18/38] Android combo box selector entries --- vulkancapsviewer.ui | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index 32de8f9..89417e3 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -502,7 +502,7 @@ height: 24px; - Device Info + Properties 16 @@ -512,7 +512,7 @@ height: 24px; - Device Info + Properties @@ -520,11 +520,6 @@ height: 24px; Features - - - Limits - - Extensions From 432dfcfdb62fa44f6f1058b65260721bf9c05870 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 16:01:37 +0100 Subject: [PATCH 19/38] Always clear features and properties models --- vulkancapsviewer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index b09b6d1..d442aa7 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -1046,8 +1046,8 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) ui.treeViewDeviceProperties->header()->setSectionResizeMode(QHeaderView::ResizeToContents); // Core 1.1 + models.propertiesCore11.clear(); if (!(device->core11Properties.empty())) { - models.propertiesCore11.clear(); QStandardItem* rootItem = models.propertiesCore11.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->core11Properties.begin(); iter != device->core11Properties.end(); ++iter) { addPropertiesRow(rootItem, iter); @@ -1057,8 +1057,8 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) } // Core 1.2 + models.propertiesCore12.clear(); if (!(device->core12Properties.empty())) { - models.propertiesCore12.clear(); QStandardItem* rootItem = models.propertiesCore12.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->core12Properties.begin(); iter != device->core12Properties.end(); ++iter) { addPropertiesRow(rootItem, iter); @@ -1115,8 +1115,8 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) ui.treeViewDeviceFeatures->header()->setSectionResizeMode(QHeaderView::ResizeToContents); // Core 1.1 + models.featuresCore11.clear(); if (!(device->core11Features.empty())) { - models.featuresCore11.clear(); QStandardItem *rootItem = models.featuresCore11.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->core11Features.begin(); iter != device->core11Features.end(); ++iter) { addVkBool32Item(rootItem, iter); @@ -1126,8 +1126,8 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) } // Core 1.2 + models.featuresCore12.clear(); if (!(device->core12Features.empty())) { - models.featuresCore12.clear(); QStandardItem *rootItem = models.featuresCore12.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->core12Features.begin(); iter != device->core12Features.end(); ++iter) { addVkBool32Item(rootItem, iter); From 241524e2690c02af22b4752be61ef09e30aaeed0 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 16:25:33 +0100 Subject: [PATCH 20/38] Moved extension features and properties into the feature and properties main tabs This is in line with the online database front-end --- vulkancapsviewer.cpp | 169 +++++++++++++++++++++++++++---------------- vulkancapsviewer.h | 6 ++ vulkancapsviewer.ui | 122 +++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 64 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index d442aa7..57c8feb 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -200,6 +200,10 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) ui.treeViewDevicePropertiesCore12->setModel(&filterProxies.propertiesCore12); filterProxies.propertiesCore12.setSourceModel(&models.propertiesCore12); connect(ui.filterLineEditPropertiesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesCore12(QString))); + // Extension properties + ui.treeViewDevicePropertiesExtensions->setModel(&filterProxies.propertiesExtensions); + filterProxies.propertiesExtensions.setSourceModel(&models.propertiesExtensions); + connect(ui.filterLineEditPropertiesExtensions, SIGNAL(textChanged(QString)), this, SLOT(slotFilterPropertiesExtensions(QString))); // Core 1.0 features ui.treeViewDeviceFeatures->setModel(&filterProxies.featuresCore10); filterProxies.featuresCore10.setSourceModel(&models.featuresCore10); @@ -212,6 +216,10 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) ui.treeViewDeviceFeaturesCore12->setModel(&filterProxies.featuresCore12); filterProxies.featuresCore12.setSourceModel(&models.featuresCore12); connect(ui.filterLineEditFeaturesCore12, SIGNAL(textChanged(QString)), this, SLOT(slotFilterFeaturesCore12(QString))); + // Extension features + ui.treeViewDeviceFeaturesExtensions->setModel(&filterProxies.featuresExtensions); + filterProxies.featuresExtensions.setSourceModel(&models.featuresExtensions); + connect(ui.filterLineEditFeaturesExtensions, SIGNAL(textChanged(QString)), this, SLOT(slotFilterFeaturesExtensions(QString))); // Extensions ui.treeViewDeviceExtensions->setModel(&filterProxies.extensions); filterProxies.extensions.setSourceModel(&models.extensions); @@ -390,6 +398,12 @@ void vulkanCapsViewer::slotFilterPropertiesCore12(QString text) filterProxies.propertiesCore12.setFilterRegExp(regExp); } +void vulkanCapsViewer::slotFilterPropertiesExtensions(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.propertiesExtensions.setFilterRegExp(regExp); +} + void vulkanCapsViewer::slotFilterFeatures(QString text) { QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); @@ -408,6 +422,12 @@ void vulkanCapsViewer::slotFilterFeaturesCore12(QString text) filterProxies.featuresCore12.setFilterRegExp(regExp); } +void vulkanCapsViewer::slotFilterFeaturesExtensions(QString text) +{ + QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); + filterProxies.featuresExtensions.setFilterRegExp(regExp); +} + void vulkanCapsViewer::slotFilterExtensions(QString text) { QRegExp regExp(text, Qt::CaseInsensitive, QRegExp::RegExp); @@ -1018,6 +1038,19 @@ void vulkanCapsViewer::displayDevice(int index) checkReportDatabaseState(); } +// @todo: replace +QString arrayToStr(QVariant value) { + QList list = value.toList(); + QString listStr = "["; + for (int i = 0; i < list.size(); i++) { + listStr += list[i].toString(); + if (i < list.size() - 1) + listStr += ", "; + } + listStr += "]"; + return listStr; +} + void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) { // Core 1.0 @@ -1066,6 +1099,49 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) ui.treeViewDevicePropertiesCore12->expandAll(); ui.treeViewDevicePropertiesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + + // Extensions + models.propertiesExtensions.clear(); + if (!(device->properties2.empty())) { + QStandardItem* rootItem = models.propertiesExtensions.invisibleRootItem(); + for (auto& extension : device->extensions) { + bool hasProperties = false; + QList extItem; + for (auto& property : device->properties2) { + if (strcmp(property.extension, extension.extensionName) == 0) { + if (!hasProperties) { + hasProperties = true; + extItem << new QStandardItem(QString::fromStdString(extension.extensionName)); + extItem << new QStandardItem(); + } + QList propertyItem; + propertyItem << new QStandardItem(QString::fromStdString(property.name)); + + if (property.value.canConvert(QVariant::List)) { + propertyItem << new QStandardItem(arrayToStr(property.value)); + } + else { + switch (property.value.type()) { + case QVariant::Bool: { + bool boolVal = property.value.toBool(); + propertyItem << new QStandardItem(boolVal ? "true" : "false"); + propertyItem[1]->setForeground(boolVal ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); + break; + } + default: + propertyItem << new QStandardItem(property.value.toString()); + } + } + extItem.first()->appendRow(propertyItem); + } + } + if (hasProperties) { + rootItem->appendRow(extItem); + } + } + ui.treeViewDevicePropertiesExtensions->expandAll(); + ui.treeViewDevicePropertiesExtensions->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + } } void vulkanCapsViewer::displayDeviceMemoryProperites(VulkanDeviceInfo *device) @@ -1135,6 +1211,35 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) ui.treeViewDeviceFeaturesCore12->expandAll(); ui.treeViewDeviceFeaturesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + + // Extensions + models.featuresExtensions.clear(); + if (!(device->features2.empty())) { + QStandardItem* rootItem = models.featuresExtensions.invisibleRootItem(); + for (auto& extension : device->extensions) { + bool hasFeatures = false; + QList extItem; + for (auto& feature : device->features2) { + if (strcmp(feature.extension, extension.extensionName) == 0) { + if (!hasFeatures) { + hasFeatures = true; + extItem << new QStandardItem(QString::fromStdString(extension.extensionName)); + extItem << new QStandardItem(); + } + QList featureItem; + featureItem << new QStandardItem(QString::fromStdString(feature.name)); + featureItem << new QStandardItem((feature.supported) ? "true" : "false"); + featureItem[1]->setForeground((feature.supported) ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); + extItem.first()->appendRow(featureItem); + } + } + if (hasFeatures) { + rootItem->appendRow(extItem); + } + } + ui.treeViewDeviceFeaturesExtensions->expandAll(); + ui.treeViewDeviceFeaturesExtensions->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + } } void vulkanCapsViewer::displayGlobalLayers(QTreeWidget *tree) @@ -1299,18 +1404,6 @@ void vulkanCapsViewer::displayDeviceFormats(VulkanDeviceInfo *device) ui.treeViewFormats->sortByColumn(0, Qt::SortOrder::AscendingOrder); } -QString arrayToStr(QVariant value) { - QList list = value.toList(); - QString listStr = "["; - for (int i = 0; i < list.size(); i++) { - listStr += list[i].toString(); - if (i < list.size() - 1) - listStr += ", "; - } - listStr += "]"; - return listStr; -} - void vulkanCapsViewer::displayDeviceExtensions(VulkanDeviceInfo *device) { models.extensions.clear(); @@ -1320,58 +1413,6 @@ void vulkanCapsViewer::displayDeviceExtensions(VulkanDeviceInfo *device) QList extItem; extItem << new QStandardItem(QString::fromStdString(extension.extensionName)); extItem << new QStandardItem(QString::fromStdString(vulkanResources::revisionToString(extension.specVersion))); - - // Features - bool hasFeatures = false; - QList featureRootItem; - for (auto& feature : device->features2) { - featureRootItem << new QStandardItem("Features"); - featureRootItem << new QStandardItem(" "); - if (strcmp(feature.extension, extension.extensionName) == 0) { - hasFeatures = true; - QList featureItem; - featureItem << new QStandardItem(QString::fromStdString(feature.name)); - featureItem << new QStandardItem((feature.supported) ? "true" : "false"); - featureItem[1]->setForeground((feature.supported) ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); - featureRootItem.first()->appendRow(featureItem); - } - } - if (hasFeatures) { - extItem.first()->appendRow(featureRootItem); - } - - // Properties - bool hasProperties = false; - QList propertiesRootItem; - for (auto& property : device->properties2) { - propertiesRootItem << new QStandardItem("Properties"); - propertiesRootItem << new QStandardItem(" "); - if (strcmp(property.extension, extension.extensionName) == 0) { - hasProperties = true; - QList propertyItem; - propertyItem << new QStandardItem(QString::fromStdString(property.name)); - - if (property.value.canConvert(QVariant::List)) { - propertyItem << new QStandardItem(arrayToStr(property.value)); - } else { - switch (property.value.type()) { - case QVariant::Bool: { - bool boolVal = property.value.toBool(); - propertyItem << new QStandardItem(boolVal ? "true" : "false"); - propertyItem[1]->setForeground(boolVal ? QColor::fromRgb(0, 128, 0) : QColor::fromRgb(255, 0, 0)); - break; - } - default: - propertyItem << new QStandardItem(property.value.toString()); - } - } - propertiesRootItem.first()->appendRow(propertyItem); - } - } - if (hasProperties) { - extItem.first()->appendRow(propertiesRootItem); - } - rootItem->appendRow(extItem); } diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index b5c4b22..3955670 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -79,9 +79,11 @@ class vulkanCapsViewer : public QMainWindow TreeProxyFilter propertiesCore10; TreeProxyFilter propertiesCore11; TreeProxyFilter propertiesCore12; + TreeProxyFilter propertiesExtensions; TreeProxyFilter featuresCore10; TreeProxyFilter featuresCore11; TreeProxyFilter featuresCore12; + TreeProxyFilter featuresExtensions; TreeProxyFilter formats; TreeProxyFilter extensions; } filterProxies; @@ -89,9 +91,11 @@ class vulkanCapsViewer : public QMainWindow QStandardItemModel propertiesCore10; QStandardItemModel propertiesCore11; QStandardItemModel propertiesCore12; + QStandardItemModel propertiesExtensions; QStandardItemModel featuresCore10; QStandardItemModel featuresCore11; QStandardItemModel featuresCore12; + QStandardItemModel featuresExtensions; QStandardItemModel formats; QStandardItemModel extensions; } models; @@ -125,9 +129,11 @@ private Q_SLOTS: void slotFilterPropertiesCore10(QString text); void slotFilterPropertiesCore11(QString text); void slotFilterPropertiesCore12(QString text); + void slotFilterPropertiesExtensions(QString text); void slotFilterFeatures(QString text); void slotFilterFeaturesCore11(QString text); void slotFilterFeaturesCore12(QString text); + void slotFilterFeaturesExtensions(QString text); void slotFilterExtensions(QString text); void slotFilterFormats(QString text); void slotComboTabChanged(int index); diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index 89417e3..8c78f50 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -791,6 +791,67 @@ height: 24px; + + + Extensions + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + @@ -1003,6 +1064,67 @@ height: 24px; + + + Extensions + + + + + + + 0 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + + + + Filter : + + + + + + + + + + QTreeView::item { height: 1.25em; } + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + 200 + + + + + From 697431af68930434074360bf0486b8cee576eb98 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 16:27:25 +0100 Subject: [PATCH 21/38] Removed device layer display These have been deprecated long time ago --- vulkancapsviewer.cpp | 24 ------------------- vulkancapsviewer.h | 1 - vulkancapsviewer.ui | 56 -------------------------------------------- 3 files changed, 81 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 57c8feb..3cad475 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -1029,7 +1029,6 @@ void vulkanCapsViewer::displayDevice(int index) displayDeviceProperties(&device); displayDeviceMemoryProperites(&device); displayDeviceFeatures(&device); - displayDeviceLayers(&device); displayDeviceFormats(&device); displayDeviceExtensions(&device); displayDeviceQueues(&device); @@ -1262,29 +1261,6 @@ void vulkanCapsViewer::displayGlobalLayers(QTreeWidget *tree) tree->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); } -void vulkanCapsViewer::displayDeviceLayers(VulkanDeviceInfo *device) -{ - using namespace vulkanResources; - - QTreeWidget *treeWidget = ui.treeWidgetDeviceLayers; - treeWidget->clear(); - for (auto& layer : device->getLayers()) - { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(treeWidget); - treeItem->setText(0, QString::fromUtf8(layer.properties.layerName)); - treeItem->setText(1, QString::fromStdString(versionToString(layer.properties.specVersion))); - treeItem->setText(2, QString::fromStdString(revisionToString(layer.properties.implementationVersion))); - treeItem->setText(3, QString::fromStdString(to_string(layer.extensions.size()))); - treeItem->setText(4, layer.properties.description); - for (auto& layerExt : layer.extensions) - { - addTreeItem(treeItem, layerExt.extensionName, revisionToString(layerExt.specVersion)); - } - } - for (int i = 0; i < treeWidget->columnCount(); i++) - treeWidget->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); -} - void addFlagModelItem(QStandardItem *parent, QString flagName, bool flag) { if (flag) diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index 3955670..d28f246 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -109,7 +109,6 @@ class vulkanCapsViewer : public QMainWindow void displayDeviceProperties(VulkanDeviceInfo *device); void displayDeviceMemoryProperites(VulkanDeviceInfo *device); void displayDeviceFeatures(VulkanDeviceInfo *device); - void displayDeviceLayers(VulkanDeviceInfo *device); void displayDeviceFormats(VulkanDeviceInfo *device); void displayDeviceExtensions(VulkanDeviceInfo *device); void displayDeviceQueues(VulkanDeviceInfo *device); diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index 8c78f50..e6513de 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -530,11 +530,6 @@ height: 24px; Formats - - - Layers - - Queue Families @@ -1253,57 +1248,6 @@ height: 24px; - - - Layers - - - - - - QTreeView::item { height: 1.25em; } - - - QAbstractItemView::NoEditTriggers - - - true - - - 200 - - - true - - - - Name - - - - - Specification - - - - - Impementation - - - - - Extension count - - - - - Description - - - - - - Queue families From fcf9abb948eb87d5987284cc6051a69ccb10b8c8 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 24 Dec 2020 17:14:45 +0100 Subject: [PATCH 22/38] Version bump to 3.0 --- android/AndroidManifest.xml | 2 +- vulkancapsviewer.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 362b325..a6dfbec 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + > diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 3cad475..2a20361 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -77,8 +77,8 @@ using std::to_string; #define VK_API_VERSION VK_API_VERSION_1_1 -const std::string vulkanCapsViewer::version = "2.3"; -const std::string vulkanCapsViewer::reportVersion = "2.1"; +const std::string vulkanCapsViewer::version = "3.0"; +const std::string vulkanCapsViewer::reportVersion = "3.0"; /// /// Returns operating system name From 48b54014e6deb278ae03ec4dd8a10ffddabdffd2 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 10:28:50 +0100 Subject: [PATCH 23/38] Use vkEnumerateInstanceVersion (if available) to query Vulkan version to be requested Removed old, fixed version --- vulkancapsviewer.cpp | 45 +++++++++++++++++++++++--------------------- vulkancapsviewer.h | 2 +- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 2a20361..6c9d528 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -75,8 +75,6 @@ extern "C"{ using std::to_string; -#define VK_API_VERSION VK_API_VERSION_1_1 - const std::string vulkanCapsViewer::version = "3.0"; const std::string vulkanCapsViewer::reportVersion = "3.0"; @@ -132,13 +130,11 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) qApp->setStyle(QStyleFactory::create("Fusion")); - vulkanApiVersion = QString::fromStdString(vulkanResources::versionToString(VK_API_VERSION)); - ui.label_header_top->setText(ui.label_header_top->text() + " " + QString::fromStdString(version)); #ifdef ANDROID // Load Vulkan libraries on Android manually if (!loadVulkanLibrary()) { - QMessageBox::warning(this, "Error", "Could not initialize Vulkan!\n\nPlease make sure that this device actually supports the Vulkan API!"); + QMessageBox::warning(this, "Error", "Could not initialize Vulkan!\n\nPlease make sure that this device actually supports the Vulkan API."); exit(EXIT_FAILURE); } // Adjust toolbar to better fit mobile devices @@ -181,7 +177,7 @@ vulkanCapsViewer::vulkanCapsViewer(QWidget *parent) if (!initVulkan()) { - QMessageBox::warning(this, "Error", "Could not initialize Vulkan!\nDevice must support Vulkan API version " + vulkanApiVersion + "!"); + QMessageBox::warning(this, "Error", "Could not initialize Vulkan!\n\nMake sure that at least one installed device supports Vulkan and supports at least Version 1.1."); exit(EXIT_FAILURE); } @@ -280,21 +276,23 @@ void vulkanCapsViewer::slotRefresh() // getGPUs(); TODO : Clean up before refresh } -/// -/// Display an about box -/// +std::string apiVersionText(uint32_t apiVersion) +{ + return to_string(VK_VERSION_MAJOR(apiVersion)) + "." + to_string(VK_VERSION_MINOR(apiVersion)) + "." + to_string(VK_VERSION_PATCH(apiVersion)); +} + void vulkanCapsViewer::slotAbout() { std::stringstream aboutText; aboutText << "

Vulkan Hardware Capability Viewer " << version << "

" "Copyright (c) 2016-2020 by Sascha Willems

" - "Build against Vulkan API " + vulkanApiVersion.toStdString() + - " header version " + to_string(VK_HEADER_VERSION) + "

" - "This tool is Free Open Source Software

" - "For usage and distribution details refer to the readme


" - "https://www.gpuinfo.org

"; + "This tool is Free Open Source Software

" + "For usage and distribution details refer to the readme

" + "https://www.gpuinfo.org

" + "Vulkan instance API version: " + apiVersionText(instanceApiVersion) + "
" + "Compiled against Vulkan header version: " + to_string(VK_HEADER_VERSION) + "

"; aboutText << "

"; - QMessageBox::about(this, tr("About the Vulkan hardware capability viewer"), QString::fromStdString(aboutText.str())); + QMessageBox::about(this, tr("About the Vulkan Hardware Capability Viewer"), QString::fromStdString(aboutText.str())); } /// @@ -339,7 +337,7 @@ void vulkanCapsViewer::slotUploadReport() if (reportId > -1) { QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "Device already present", "A report for the selected device is aleady present in the database.\n\nDo you want to open the report in your browser?", QMessageBox::Yes | QMessageBox::No); + reply = QMessageBox::question(this, "Device already present", "A report for the selected device is already present in the database.\n\nDo you want to open the report in your browser?", QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { QString url = QString::fromStdString(databaseConnection.getBaseUrl() + "displayreport.php?id=" + to_string(reportId)); @@ -459,20 +457,25 @@ void vulkanCapsViewer::displayGlobalExtensions() } } -/// -/// Initialize vulkan and dome some initial setup -/// bool vulkanCapsViewer::initVulkan() { VkResult vkRes; + // Get the max. supported Vulkan Version if vkEnumerateInstanceVersion is available (loader version 1.1 and up) + PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = reinterpret_cast(vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); + if (vkEnumerateInstanceVersion) { + vkEnumerateInstanceVersion(&instanceApiVersion); + } else { + instanceApiVersion = VK_API_VERSION_1_0; + } + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "VulkanCapsViewer"; appInfo.applicationVersion = 1; appInfo.pEngineName = "VulkanCapsViewer"; appInfo.engineVersion = 1; - appInfo.apiVersion = VK_API_VERSION_1_0; + appInfo.apiVersion = instanceApiVersion; // Create Vulkan instance VkInstanceCreateInfo instanceCreateInfo = {}; @@ -573,7 +576,7 @@ bool vulkanCapsViewer::initVulkan() QString error; if (vkRes == VK_ERROR_INCOMPATIBLE_DRIVER) { - error = "No compatible Vulkan driver found!\nThis version requires a Vulkan driver that is compatible with API Level " + QString::fromStdString(vulkanResources::versionToString(VK_API_VERSION)); + error = "No compatible Vulkan driver found!\nThis version requires a Vulkan driver that is compatible with at least Vulkan 1.1"; } else { diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index d28f246..2435f94 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -68,7 +68,7 @@ class vulkanCapsViewer : public QMainWindow void exportReportAsJSON(std::string fileName, std::string submitter, std::string comment); int uploadReportNonVisual(int deviceIndex, QString submitter, QString comment); private: - QString vulkanApiVersion; + uint32_t instanceApiVersion; int selectedDeviceIndex = 0; VkInstance vkInstance = VK_NULL_HANDLE; VkSurfaceKHR surface; From a3b84ea554ea51c9e4250d4528f63c3ec4aec6e8 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 10:55:21 +0100 Subject: [PATCH 24/38] Hide tabs if data is not available --- vulkancapsviewer.cpp | 25 +++++++++++++++++++++++++ vulkancapsviewer.ui | 15 ++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 6c9d528..c356dba 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -1083,6 +1083,7 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) // Core 1.1 models.propertiesCore11.clear(); if (!(device->core11Properties.empty())) { + ui.tabWidgetProperties->setTabEnabled(1, true); QStandardItem* rootItem = models.propertiesCore11.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->core11Properties.begin(); iter != device->core11Properties.end(); ++iter) { addPropertiesRow(rootItem, iter); @@ -1090,10 +1091,14 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) ui.treeViewDevicePropertiesCore11->expandAll(); ui.treeViewDevicePropertiesCore11->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + else { + ui.tabWidgetProperties->setTabEnabled(1, false); + } // Core 1.2 models.propertiesCore12.clear(); if (!(device->core12Properties.empty())) { + ui.tabWidgetProperties->setTabEnabled(2, true); QStandardItem* rootItem = models.propertiesCore12.invisibleRootItem(); for (QVariantMap::const_iterator iter = device->core12Properties.begin(); iter != device->core12Properties.end(); ++iter) { addPropertiesRow(rootItem, iter); @@ -1101,10 +1106,14 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) ui.treeViewDevicePropertiesCore12->expandAll(); ui.treeViewDevicePropertiesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + else { + ui.tabWidgetProperties->setTabEnabled(2, false); + } // Extensions models.propertiesExtensions.clear(); if (!(device->properties2.empty())) { + ui.tabWidgetProperties->setTabEnabled(3, true); QStandardItem* rootItem = models.propertiesExtensions.invisibleRootItem(); for (auto& extension : device->extensions) { bool hasProperties = false; @@ -1144,6 +1153,9 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) ui.treeViewDevicePropertiesExtensions->expandAll(); ui.treeViewDevicePropertiesExtensions->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + else { + ui.tabWidgetProperties->setTabEnabled(3, false); + } } void vulkanCapsViewer::displayDeviceMemoryProperites(VulkanDeviceInfo *device) @@ -1195,6 +1207,7 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) // Core 1.1 models.featuresCore11.clear(); if (!(device->core11Features.empty())) { + ui.tabWidgetFeatures->setTabEnabled(1, true); QStandardItem *rootItem = models.featuresCore11.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->core11Features.begin(); iter != device->core11Features.end(); ++iter) { addVkBool32Item(rootItem, iter); @@ -1202,10 +1215,14 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) ui.treeViewDeviceFeaturesCore11->expandAll(); ui.treeViewDeviceFeaturesCore11->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + else { + ui.tabWidgetFeatures->setTabEnabled(1, false); + } // Core 1.2 models.featuresCore12.clear(); if (!(device->core12Features.empty())) { + ui.tabWidgetFeatures->setTabEnabled(2, true); QStandardItem *rootItem = models.featuresCore12.invisibleRootItem(); for(QVariantMap::const_iterator iter = device->core12Features.begin(); iter != device->core12Features.end(); ++iter) { addVkBool32Item(rootItem, iter); @@ -1213,10 +1230,14 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) ui.treeViewDeviceFeaturesCore12->expandAll(); ui.treeViewDeviceFeaturesCore12->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + else { + ui.tabWidgetFeatures->setTabEnabled(2, false); + } // Extensions models.featuresExtensions.clear(); if (!(device->features2.empty())) { + ui.tabWidgetFeatures->setTabEnabled(3, true); QStandardItem* rootItem = models.featuresExtensions.invisibleRootItem(); for (auto& extension : device->extensions) { bool hasFeatures = false; @@ -1242,6 +1263,10 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) ui.treeViewDeviceFeaturesExtensions->expandAll(); ui.treeViewDeviceFeaturesExtensions->header()->setSectionResizeMode(QHeaderView::ResizeToContents); } + else { + ui.tabWidgetFeatures->setTabEnabled(3, false); + } + } void vulkanCapsViewer::displayGlobalLayers(QTreeWidget *tree) diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index e6513de..c839c16 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -19,7 +19,7 @@ - Vulkan Hardware Capability Viewer 1.0 (beta) + Vulkan Hardware Capability Viewer false @@ -41,6 +41,15 @@ QTabWidget::tab-bar { alignment: center; } +QTabBar::tab:disabled { + min-width: 0 !important; + width: 0 !important; + height: 0 !important; + margin: 0 !important; + padding: 0 !important; + border: none !important; +} + QTabBar::tab { min-width: 8ex; padding: 8px 16px; @@ -599,7 +608,7 @@ height: 24px; 0 - + 0 @@ -872,7 +881,7 @@ height: 24px; 0 - + 0 From 4db1170d5ecb1c1c49c8f951e083385240842950 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 11:06:38 +0100 Subject: [PATCH 25/38] Hide device selection if only one device is available (Android only) --- vulkancapsviewer.cpp | 5 +++++ vulkancapsviewer.ui | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index c356dba..948b9e4 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -826,6 +826,11 @@ void vulkanCapsViewer::getGPUs() { QMessageBox::warning(this, tr("Error"), "Could not find a GPU with Vulkan support!"); } + + // Only display device selection of more than once device is present (Android only) +#ifdef __ANDROID__ + ui.widgetDeviceSelection->setVisible(vulkanGPUs.size() > 1); +#endif } QTreeWidgetItem *addTreeItem(QTreeWidgetItem *parent, const std::string& key, const std::string& value) diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index c839c16..a437d09 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -383,7 +383,7 @@ QTreeView { - + background-color: rgb(68, 68, 68); From c12acfaf03b4250b9ca48e53b5affa4abe172861 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 12:12:27 +0100 Subject: [PATCH 26/38] Updated logos and readme --- README.md | 11 ++++------- Resources/vulkan32.png | Bin 2493 -> 4638 bytes Resources/vulkan48.png | Bin 3728 -> 6763 bytes images/vulkanlogo.png | Bin 9378 -> 19618 bytes vulkancapsviewer.qrc | 32 ++++++++++++++++---------------- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index f9e070e..06adf90 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Vulkan Hardware Capability Viewer -![Vulkan Logo](./images/vulkanlogo.png) + -Client application to display hardware implementation details for GPUs supporting the new [Vulkan(tm)](https://www.khronos.org/vulkan/) API by Khronos. +Client application to display hardware implementation details for GPUs supporting the [Vulkan](https://www.khronos.org/vulkan/) API by Khronos. The hardware reports can be submitted to a public [online database](http://vulkan.gpuinfo.org/) that allows comparing different devices, browsing available features, extensions, formats, etc. @@ -11,20 +11,17 @@ The hardware reports can be submitted to a public [online database](http://vulka # Supported platforms -**A Vulkan compatible driver (or on Android image) is required** +**A Vulkan compatible device is required** - Windows (x64) - Linux (x64) - Android (Including Android TV) - Mac OS X -# API version -Due to the explicit nature of Vulkan, the API version of the Vulkan driver (or Android image) must fit the API level against which the application was build. - # Building [![Build Status](https://travis-ci.org/SaschaWillems/VulkanCapsViewer.svg?branch=master)](https://travis-ci.org/SaschaWillems/VulkanCapsViewer) -The repository includes a project file for the [Qt Creator IDE](https://www.qt.io/ide/) that has been tested to work with Windows, Linux and Android. This is the preferred (and easiest) way of building the application if you want to build it yourself. +The repository includes a project file for the [Qt Creator IDE](https://www.qt.io/ide/) that has been tested to work with Windows, Linux and Android. This is the preferred (and easiest) way of building the application if you want to build it yourself. Using the [Qt Visual Studio Tools](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019), it's also possible to use a current Visual Studio version. Alternatively, you can simply run `qmake` followed by `make` in the source directory. # Releases diff --git a/Resources/vulkan32.png b/Resources/vulkan32.png index 5dc85e8f8f5641981fb72a98e9ccd1be95f02bee..a076edbf5d9dc7bf5aafc3d46cde26fe2d7bcfe8 100644 GIT binary patch literal 4638 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 z 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 literal 9378 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%0A3(`>T*^FID#wwa= zEVuvQl+Jt^JpZz46`A66@KxtDJ+0oic1nkax|^YGy_r%u&aA2=K^Oij>>p$tlJU;q z>k2dGfrgiX&wO?kI8Cgo){tqtrjMYunMv*Syt3Q5p~d~sW3`AKVE-&4>x zN%8rAqbix(ES=k32c?j7Elcn7JLTck42n=&MG|x&=T3~X;inov(8oBYwS{@ca|P0z zU4ou_d*A@~4(DWRS$g*}H2X5mazowiic4?RAPKsVKkkSmAE`N$vDw!+r{s7RefJcy zd1R0e_ZUD|&E8(pI=b{ez0>`>q+Dh^ayzT4js#t(-&t{N`55h()-mXyXLOw5td7f{ zRTZO{rPFKU(J3U|k)?Mp%lm~=oSidh%u%X2f&@K|4vfwwUTgqC_uNNZG$iMjJvzkh zxG(}(XVu1Nz*yr?IH%c>rFXA559_2@R(pY~sLBWu^mvfBwR;x6+h1@_?_h}WaW#s0 zFB6UhR0X3NfDPWR-p`1!Ux?j`1QdNU;WAG4G$ z6ck!wjHmN@4GomBj(g;kg)9V}GvRN+8J*LmYtF4KB<(%mv*5en#E|TPcD5Nfm)04? zhJiNLP^~Kj{tEsYT*fiYYQn6(>ReCHL_Iyy0@KtY=3C)%9XMwSWiI17&CrE{h-z!d zBvdNyF&URfQc9jPA0FE|7koG*p($xqPyg9t!IwkgYWFyad7%cntTX$hkaVR>@2^_@ z@dCpf53!~4jtKeEAccHzN@6Z(hAudPXK?$~`9R`Ea5KGXp$bud2qMPV>3cgT&87Dh z+lt@7nKb_AzToShfc5_sr27!A_kxduZ{S{^wIbjP*y_ZZHpAc02Cu1tJ{gdo@v41} zV%xPV>(D$E3?QFxrM_J`b;^{9md;`!Ii^^O^CjriRmG?VyWBoGB!#3a zS$ZEHvT@x?=QA{LTga|?_RsUH)+~pSjq4AZ}FXPOGUhM*REYG9b%jWJ$}%y z`v>(b=;$EFM%+Pu6B4WH?^P9}!~rP`2HSNwgE~ut%E1zJp`(~OWy;s!coIKODf!c+ z=HG+gwD{VCcI^o<=l(k#6wPRD;7JL3{Id|w2D0+)p6POX3tU)ISz`g6ne5IZgsO?r zwhz|V<5EbvlBM_Ghh%>9)7@{wXe7g*dm1XsJ&t`2J4m^-wj72KU*O$8wuP zM-Of7A0_B<;xX{kdKUDO4zhOyqRyGkUdYd-s(OW(rT-9;BWzQhldfdxo!$<&41SRV zJunhn3wgUgB%bX&0?MqWniid)Zvn1tpNB}$i_>9o={N0V_dJ)|OP`g;G5*g6F?oPx z&*T%3BijVqrkR)32s;9ut!Np~FLBl$KRz$fet!xc}p-ZiU22;M*yr zdj-U7mUika?JVf*<;;+e0VR#}Rzg0GG;eyPc+??%?%D33DwaQJOcxU8L!qtNxdc6K z(0yr|%X$N1dRQ)_f^??9y}Jui6n3UduVc&Neg}aQRMiSQOXrcEeN#x9p?S}!;Qo_A z#vxxeBo0BoOZkzxPfnw^m2uxbZ5VG3b-Ld^p21{NK%O)cOoyV(=ps1|?wBqXa(MDx+Kn?mAvh!|e-yPvhS zrfJg>`-!F|4a9^vVauPZha^%OgIX+NA@y{j$#;ejaU*%jH~Ypn)g{*&NW0w2t~k)Y~srnnJsy&t@HO{vZf~AP7Qn c@&5u008b66jlIl0EdT%j07*qoM6N<$f~AIWdjJ3c diff --git a/vulkancapsviewer.qrc b/vulkancapsviewer.qrc index 1233a77..14fabae 100644 --- a/vulkancapsviewer.qrc +++ b/vulkancapsviewer.qrc @@ -1,18 +1,18 @@ - - Resources/vulkan48.png - Resources/device48.png - Resources/refresh16.png - Resources/compare24.png - Resources/db24.png - Resources/gpu32.png - Resources/save48.png - Resources/close48.png - Resources/about48.png - Resources/browse48.png - Resources/settings48.png - Resources/upload48.png - Resources/refresh48.png - Resources/vulkan32.png - + + Resources/vulkan32.png + Resources/vulkan48.png + Resources/device48.png + Resources/refresh16.png + Resources/compare24.png + Resources/db24.png + Resources/gpu32.png + Resources/save48.png + Resources/close48.png + Resources/about48.png + Resources/browse48.png + Resources/settings48.png + Resources/upload48.png + Resources/refresh48.png + From 6ddec39c09f64c9ed14c98c8e3df00e37930c2e1 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 12:13:36 +0100 Subject: [PATCH 27/38] Code cleanup --- vulkancapsviewer.cpp | 77 ++++++++------------------------------------ vulkancapsviewer.h | 1 - 2 files changed, 14 insertions(+), 64 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 948b9e4..8c60c4d 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -78,9 +78,6 @@ using std::to_string; const std::string vulkanCapsViewer::version = "3.0"; const std::string vulkanCapsViewer::reportVersion = "3.0"; -/// -/// Returns operating system name -/// OSInfo getOperatingSystem() { // QSysInfo works for all supported operating systems @@ -91,6 +88,19 @@ OSInfo getOperatingSystem() return osInfo; } +// Convert a list variant into an imploded string +QString arrayToStr(QVariant value) { + QList list = value.toList(); + QString imploded; + for (auto i = 0; i < list.size(); i++) { + imploded += list[i].toString(); + if (i < list.size() - 1) + imploded += ", "; + } + return "[" + imploded + "]"; +} + + #ifdef __ANDROID__ void setTouchProps(QWidget *widget) { QScroller *scroller = QScroller::scroller(widget); @@ -240,26 +250,17 @@ vulkanCapsViewer::~vulkanCapsViewer() } } -/// -/// Close the application -/// void vulkanCapsViewer::slotClose() { close(); } -/// -/// Display database in default browser -/// void vulkanCapsViewer::slotBrowseDatabase() { QString link = "https://vulkan.gpuinfo.org/"; QDesktopServices::openUrl(QUrl(link)); } -/// -/// Display device report in default browser -/// void vulkanCapsViewer::slotDisplayOnlineReport() { int reportId = databaseConnection.getReportId(vulkanGPUs[selectedDeviceIndex]); @@ -268,14 +269,6 @@ void vulkanCapsViewer::slotDisplayOnlineReport() QDesktopServices::openUrl(QUrl(QString::fromStdString(ss.str()))); } -/// -/// Refresh GPU list -/// -void vulkanCapsViewer::slotRefresh() -{ - // getGPUs(); TODO : Clean up before refresh -} - std::string apiVersionText(uint32_t apiVersion) { return to_string(VK_VERSION_MAJOR(apiVersion)) + "." + to_string(VK_VERSION_MINOR(apiVersion)) + "." + to_string(VK_VERSION_PATCH(apiVersion)); @@ -295,9 +288,6 @@ void vulkanCapsViewer::slotAbout() QMessageBox::about(this, tr("About the Vulkan Hardware Capability Viewer"), QString::fromStdString(aboutText.str())); } -/// -/// GPU selection changed -/// void vulkanCapsViewer::slotComboBoxGPUIndexChanged(int index) { if (index != selectedDeviceIndex) @@ -306,9 +296,6 @@ void vulkanCapsViewer::slotComboBoxGPUIndexChanged(int index) } } -/// -/// Save report to disk (JSON) -/// void vulkanCapsViewer::slotSaveReport() { VulkanDeviceInfo device = vulkanGPUs[selectedDeviceIndex]; @@ -319,9 +306,6 @@ void vulkanCapsViewer::slotSaveReport() } } -/// -/// Upload report to online database -/// void vulkanCapsViewer::slotUploadReport() { VulkanDeviceInfo device = vulkanGPUs[selectedDeviceIndex]; @@ -709,9 +693,6 @@ bool vulkanCapsViewer::initVulkan() return true; } -/// -/// Get details for the specificed vulkan GPU -/// void vulkanCapsViewer::getGPUinfo(VulkanDeviceInfo *GPU, uint32_t id, VkPhysicalDevice device) { VkResult vkRes; @@ -755,11 +736,8 @@ void vulkanCapsViewer::getGPUinfo(VulkanDeviceInfo *GPU, uint32_t id, VkPhysical VkDeviceCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - info.pNext = NULL; info.pQueueCreateInfos = queueCreateInfos.data(); info.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(); - info.pEnabledFeatures = NULL; - info.ppEnabledLayerNames = NULL; info.enabledLayerCount = 0; // info.enabledExtensionCount = enabledExtensions.size(); // info.ppEnabledExtensionNames = enabledExtensions.data(); @@ -779,9 +757,6 @@ void vulkanCapsViewer::getGPUinfo(VulkanDeviceInfo *GPU, uint32_t id, VkPhysical GPU->appVersion = version; } -/// -/// Get list of all available GPUs that support Vulkan -/// void vulkanCapsViewer::getGPUs() { VkResult vkRes; @@ -932,17 +907,9 @@ void addHexItem(QStandardItem* parent, const QVariantMap::const_iterator& iterat void addVariantListItem(QStandardItem* parent, const QVariantMap::const_iterator& iterator) { - QList list = iterator.value().toList(); - QString listStr = "["; - for (int i = 0; i < list.size(); i++) { - listStr += list[i].toString(); - if (i < list.size() - 1) - listStr += ", "; - } - listStr += "]"; QList item; item << new QStandardItem(iterator.key()); - item << new QStandardItem(listStr); + item << new QStandardItem(arrayToStr(iterator.value())); parent->appendRow(item); } @@ -1045,19 +1012,6 @@ void vulkanCapsViewer::displayDevice(int index) checkReportDatabaseState(); } -// @todo: replace -QString arrayToStr(QVariant value) { - QList list = value.toList(); - QString listStr = "["; - for (int i = 0; i < list.size(); i++) { - listStr += list[i].toString(); - if (i < list.size() - 1) - listStr += ", "; - } - listStr += "]"; - return listStr; -} - void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) { // Core 1.0 @@ -1585,9 +1539,6 @@ void vulkanCapsViewer::exportReportAsJSON(std::string fileName, std::string subm jsonFile.write(doc.toJson(QJsonDocument::Indented)); } -/// -/// Display database state for the currently selected device -/// void vulkanCapsViewer::checkReportDatabaseState() { ui.labelDevicePresent->setText("Connecting to database..."); diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index 2435f94..c78b254 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -119,7 +119,6 @@ private Q_SLOTS: void slotClose(); void slotBrowseDatabase(); void slotDisplayOnlineReport(); - void slotRefresh(); void slotAbout(); void slotComboBoxGPUIndexChanged(int index); void slotSaveReport(); From 1238f619911d450515d594012ffac66ea3caab06 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 12:20:36 +0100 Subject: [PATCH 28/38] Renamed Vulkan tab to Instance Renamed instance related functions --- vulkancapsviewer.cpp | 49 +++++++++++++++++++++----------------------- vulkancapsviewer.h | 4 ++-- vulkancapsviewer.ui | 4 ++-- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 8c60c4d..8031aab 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -427,20 +427,6 @@ void vulkanCapsViewer::slotComboTabChanged(int index) ui.tabWidgetDevice->setCurrentIndex(index); } -void vulkanCapsViewer::displayGlobalExtensions() -{ - QTreeWidget *tree = ui.treeWidgetGlobalExtenssions; - - for (auto& ext : instanceInfo.extensions) { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(tree); - treeItem->setText(0, QString::fromUtf8(ext.extensionName)); - treeItem->setText(1, QString::fromStdString(vulkanResources::revisionToString(ext.specVersion))); - } - for (int i = 0; i < tree->columnCount(); i++) { - tree->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); - } -} - bool vulkanCapsViewer::initVulkan() { VkResult vkRes; @@ -687,8 +673,8 @@ bool vulkanCapsViewer::initVulkan() surface = VK_NULL_HANDLE; } - displayGlobalLayers(ui.treeWidgetGlobalLayers); - displayGlobalExtensions(); + displayInstanceLayers(); + displayInstanceExtensions(); return true; } @@ -1228,24 +1214,35 @@ void vulkanCapsViewer::displayDeviceFeatures(VulkanDeviceInfo *device) } -void vulkanCapsViewer::displayGlobalLayers(QTreeWidget *tree) +void vulkanCapsViewer::displayInstanceLayers() { - using namespace vulkanResources; - - tree->clear(); + ui.treeWidgetGlobalLayers->clear(); for (auto& layer : instanceInfo.layers) { - QTreeWidgetItem *treeItem = new QTreeWidgetItem(tree); + QTreeWidgetItem *treeItem = new QTreeWidgetItem(ui.treeWidgetGlobalLayers); treeItem->setText(0, QString::fromUtf8(layer.properties.layerName)); - treeItem->setText(1, QString::fromStdString(versionToString(layer.properties.specVersion))); - treeItem->setText(2, QString::fromStdString(revisionToString(layer.properties.implementationVersion))); + treeItem->setText(1, QString::fromStdString(vulkanResources::versionToString(layer.properties.specVersion))); + treeItem->setText(2, QString::fromStdString(vulkanResources::revisionToString(layer.properties.implementationVersion))); treeItem->setText(3, QString::fromStdString(to_string(layer.extensions.size()))); treeItem->setText(4, layer.properties.description); for (auto& layerExt : layer.extensions) { - addTreeItem(treeItem, layerExt.extensionName, revisionToString(layerExt.specVersion)); + addTreeItem(treeItem, layerExt.extensionName, vulkanResources::revisionToString(layerExt.specVersion)); } } - for (int i = 0; i < tree->columnCount(); i++) - tree->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); + for (int i = 0; i < ui.treeWidgetGlobalLayers->columnCount(); i++) + ui.treeWidgetGlobalLayers->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); +} + +void vulkanCapsViewer::displayInstanceExtensions() +{ + ui.treeWidgetGlobalExtenssions->clear(); + for (auto& ext : instanceInfo.extensions) { + QTreeWidgetItem* treeItem = new QTreeWidgetItem(ui.treeWidgetGlobalExtenssions); + treeItem->setText(0, QString::fromUtf8(ext.extensionName)); + treeItem->setText(1, QString::fromStdString(vulkanResources::revisionToString(ext.specVersion))); + } + for (int i = 0; i < ui.treeWidgetGlobalExtenssions->columnCount(); i++) { + ui.treeWidgetGlobalExtenssions->header()->setSectionResizeMode(i, QHeaderView::ResizeToContents); + } } void addFlagModelItem(QStandardItem *parent, QString flagName, bool flag) diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index c78b254..feba381 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -113,8 +113,8 @@ class vulkanCapsViewer : public QMainWindow void displayDeviceExtensions(VulkanDeviceInfo *device); void displayDeviceQueues(VulkanDeviceInfo *device); void displayDeviceSurfaceInfo(VulkanDeviceInfo &device); - void displayGlobalLayers(QTreeWidget *tree); - void displayGlobalExtensions(); + void displayInstanceLayers(); + void displayInstanceExtensions(); private Q_SLOTS: void slotClose(); void slotBrowseDatabase(); diff --git a/vulkancapsviewer.ui b/vulkancapsviewer.ui index a437d09..69285ef 100644 --- a/vulkancapsviewer.ui +++ b/vulkancapsviewer.ui @@ -556,7 +556,7 @@ height: 24px; - Vulkan Instance + Instance @@ -1376,7 +1376,7 @@ height: 24px; - Vulkan + Instance From a13234ec0e9169b8322fb2ca43489abb9adb2177 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 12:28:52 +0100 Subject: [PATCH 29/38] Updated Vulkan library --- libs/vulkan/vulkan-1.lib | Bin 45852 -> 52366 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/vulkan/vulkan-1.lib b/libs/vulkan/vulkan-1.lib index 755930e2d779cae94df9eccac7e5f47bf91cb7cc..a3b0bbd923b2f4a34a5551c61012170d84738f92 100644 GIT binary patch literal 52366 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 CiaN0X From 1a0fa099357b905f31cd62243b6e14a16ad4a80a Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 25 Dec 2020 12:29:20 +0100 Subject: [PATCH 30/38] Updated Visual Studio Build files (VS2019) --- vulkanCapsViewer.vcxproj | 380 ++++++++++++++++++------------- vulkanCapsViewer.vcxproj.filters | 244 +++++++++++++------- 2 files changed, 385 insertions(+), 239 deletions(-) diff --git a/vulkanCapsViewer.vcxproj b/vulkanCapsViewer.vcxproj index cd1e278..4751ba1 100644 --- a/vulkanCapsViewer.vcxproj +++ b/vulkanCapsViewer.vcxproj @@ -1,220 +1,292 @@  - + - - Debug - x64 - Release x64 + + Debug + x64 + - {B12702AD-ABFB-343A-A199-8E24837244A3} - Qt4VSv1.0 + {560F3AD5-17F2-395D-B675-082A25172590} + vulkanCapsViewer + QtVS_v303 + 10.0 + 10.0.19041.0 + $(MSBuildProjectDirectory)\QtMsBuild - - Application - v142 - Unicode - + v142 + Win32\Release\ + false + NotSet Application + release\ + vulkanCapsViewer + + v142 - Unicode + Win32\Release\ + false + NotSet + Application + debug\ + vulkanCapsViewer - + + + + + + - - - - + - - <_ProjectFileVersion>12.0.30501.0 - + + + - $(SolutionDir)$(Platform)\$(Configuration)\ + Win32\Release\ + debug\ + vulkanCapsViewer + true - $(SolutionDir)$(Platform)\$(Configuration)\ + Win32\Release\ + release\ + vulkanCapsViewer + true + false - + + 5.13.2 + core;network;gui;widgets + + + 5.13.2 + core;network;gui;widgets + + + + + - VK_USE_PLATFORM_WIN32_KHR;WIN32;WIN64;QT_CORE_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_WIDGETS_LIB;QT_NO_SIGNALS_SLOTS_KEYWORDS;VK_PROTOTYPES;%(PreprocessorDefinitions) - .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWidgets;.\Vulkan-Headers\include;%(AdditionalIncludeDirectories) - Disabled - ProgramDatabase - MultiThreadedDebugDLL + GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;GeneratedFiles\Release;Vulkan-Headers\include;/Vulkan-Headers/include;GeneratedFiles\release;1.2.154.0/include;%(AdditionalIncludeDirectories) + -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) + release\ + false + None + 4577;4467;%(DisableSpecificWarnings) + Sync + release\ + MaxSpeed + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_DLL;VK_ENABLE_BETA_EXTENSIONS;WIN64;VK_USE_PLATFORM_WIN32_KHR;QT_NO_DEBUG;%(PreprocessorDefinitions) + false + + + MultiThreadedDLL + true true Level3 - true - stdcpp14 + true + .\libs\vulkan\vulkan-1.lib;Advapi32.lib;shell32.lib;%(AdditionalDependencies) + C:\openssl\lib;C:\Utils\my_sql\mysql-5.7.25-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + false + true + false + $(OutDir)\vulkanCapsViewer.exe + true Windows - $(OutDir)\$(ProjectName).exe - $(VULKAN_SDK)\Lib;$(QTDIR)\lib;libs\vulkan;%(AdditionalLibraryDirectories) - true - vulkan-1.lib;qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Networkd.lib;Qt5Widgetsd.lib;libs\vulkan\vulkan-1.lib;%(AdditionalDependencies) + true + + Unsigned + None + 0 + + + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;NDEBUG;QT_DLL;QT_NETWORK_LIB;QT_WIDGETS_LIB;VK_ENABLE_BETA_EXTENSIONS;WIN64;VK_USE_PLATFORM_WIN32_KHR;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) + + + msvc + ./GeneratedFiles/$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + GeneratedFiles\$(Configuration) + moc_%(Filename).cpp + + + vulkancapsviewer + default + Rcc'ing %(Identity)... + GeneratedFiles + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + GeneratedFiles + ui_%(Filename).h + - + - VK_USE_PLATFORM_WIN32_KHR;WIN32;WIN64;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_WIDGETS_LIB;VK_PROTOTYPES;%(PreprocessorDefinitions) - .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtWidgets;.\Vulkan-Headers\include;%(AdditionalIncludeDirectories) - - MultiThreadedDLL + GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;GeneratedFiles\Release;Vulkan-Headers\include;/Vulkan-Headers/include;GeneratedFiles\debug;1.2.154.0/include;%(AdditionalIncludeDirectories) + -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) + debug\ + false + ProgramDatabase + 4577;4467;%(DisableSpecificWarnings) + Sync + debug\ + Disabled + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;VK_ENABLE_BETA_EXTENSIONS;WIN64;VK_USE_PLATFORM_WIN32_KHR;%(PreprocessorDefinitions) + false + MultiThreadedDebugDLL + true true Level3 - true - stdcpp14 + true + .\libs\vulkan\vulkan-1.lib;Advapi32.lib;shell32.lib;%(AdditionalDependencies) + C:\openssl\lib;C:\Utils\my_sql\mysql-5.7.25-winx64\lib;C:\Utils\postgresql\pgsql\lib;%(AdditionalLibraryDirectories) + "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + true + true + $(OutDir)\vulkanCapsViewer.exe + true Windows - $(OutDir)\$(ProjectName).exe - $(VULKAN_SDK)\Lib;$(QTDIR)\lib;%(AdditionalLibraryDirectories) - false - vulkan-1.lib;qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Network.lib;Qt5Widgets.lib;libs\vulkan\vulkan-1.lib;%(AdditionalDependencies) + true + + Unsigned + None + 0 + + + _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NETWORK_LIB;QT_WIDGETS_LIB;VK_ENABLE_BETA_EXTENSIONS;WIN64;VK_USE_PLATFORM_WIN32_KHR;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) + + + msvc + ./GeneratedFiles/$(Configuration)/moc_predefs.h + Moc'ing %(Identity)... + output + GeneratedFiles\$(Configuration) + moc_%(Filename).cpp + + + vulkancapsviewer + default + Rcc'ing %(Identity)... + GeneratedFiles + qrc_%(Filename).cpp + + + Uic'ing %(Identity)... + GeneratedFiles + ui_%(Filename).h + - - true - - - true - - - true - - - true - - - - - - - - - true - - - true - - - true - - - true - + + - - - - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing vulkancapsviewer.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing vulkancapsviewer.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" - - - - - $(QTDIR)\bin\uic.exe;%(AdditionalInputs) - Uic%27ing %(Identity)... - .\GeneratedFiles\ui_%(Filename).h;%(Outputs) - "$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)" - $(QTDIR)\bin\uic.exe;%(AdditionalInputs) - Uic%27ing %(Identity)... - .\GeneratedFiles\ui_%(Filename).h;%(Outputs) - "$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)" - - - - + + - - - - - - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing submitDialog.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing submitDialog.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" - + + + + - + - - - - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing vulkandatabase.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing vulkandatabase.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" + + + + + + + + + + + Document + true + $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) + cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >GeneratedFiles\debug\moc_predefs.h + Generate moc_predefs.h + GeneratedFiles\debug\moc_predefs.h;%(Outputs) - - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing settingsDialog.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DQT_NO_SIGNALS_SLOTS_KEYWORDS -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing settingsDialog.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DVK_USE_PLATFORM_WIN32_KHR -DWIN32 -DWIN64 -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_WIDGETS_LIB -DVK_PROTOTYPES -D%(PreprocessorDefinitions) "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtWidgets" "-I.\Vulkan-Headers\include" + + Document + $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) + cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >GeneratedFiles\release\moc_predefs.h + Generate moc_predefs.h + GeneratedFiles\release\moc_predefs.h;%(Outputs) + true - - %(FullPath);%(AdditionalInputs) - Rcc%27ing %(Identity)... - .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) - "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp - %(FullPath);%(AdditionalInputs) - Rcc%27ing %(Identity)... - .\GeneratedFiles\qrc_%(Filename).cpp;%(Outputs) - "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - - - - + \ No newline at end of file diff --git a/vulkanCapsViewer.vcxproj.filters b/vulkanCapsViewer.vcxproj.filters index c071ad4..e5e7565 100644 --- a/vulkanCapsViewer.vcxproj.filters +++ b/vulkanCapsViewer.vcxproj.filters @@ -1,95 +1,90 @@  - + - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;cxx;c;def - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h + + {99349809-55BA-4b9d-BF79-8FDBB0286EB3} + ui + false {99349809-55BA-4b9d-BF79-8FDBB0286EB3} ui + false + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + cpp;c;cxx;moc;h;def;odl;idl;res; + + + {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} + cpp;c;cxx;moc;h;def;odl;idl;res; + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} qrc;* false - - {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} - moc;h;cpp - False + + {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} + qrc;* + false + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx - - {760a2d73-3f6e-4039-9618-7de4faa56424} - cpp;moc - False + + {B83CAF91-C7BF-462F-B76C-EA11631F866C} + * + false - - {2eff770d-359a-4717-b7d0-3e4bae13e6f3} - cpp;moc - False + + {B83CAF91-C7BF-462F-B76C-EA11631F866C} + * + false - + Source Files - + Source Files - - Generated Files\Debug - - - Generated Files\Release - - - Generated Files - - - Generated Files\Debug - - - Generated Files\Release - Source Files Source Files - - Source Files - - - Generated Files\Debug - - - Generated Files\Release - - - Generated Files\Debug - - - Generated Files\Release - Source Files Source Files + + Source Files + Source Files - + Source Files - + Source Files @@ -97,63 +92,142 @@ - - Header Files - - - Form Files - - - Resource Files - - - Header Files - - + Header Files - - + + Header Files - - - - - Generated Files Header Files - + Header Files - - + + Header Files - + Header Files - + Header Files Header Files - + Header Files - + Header Files - + Header Files - - + + + Header Files + + Header Files - + Header Files + + + Generated Files + + + Generated Files + + + + + + + + + + + + + + + Form Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + + + Distribution Files + + + Distribution Files + + + Distribution Files + + + Distribution Files + + + Distribution Files + + + Distribution Files + + + Distribution Files + + From 5f6172cfedf952eec94c4ab10ff24b6c1c90b4cb Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 26 Dec 2020 10:54:32 +0100 Subject: [PATCH 31/38] Code cleanup Copyright --- vulkancapsviewer.cpp | 4 ++-- vulkandatabase.cpp | 14 +++----------- vulkandatabase.h | 4 +--- vulkansurfaceinfo.hpp | 10 ++++------ 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 8031aab..93b6ec5 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -1554,7 +1554,7 @@ void vulkanCapsViewer::checkReportDatabaseState() if (databaseConnection.checkReportPresent(vulkanGPUs[selectedDeviceIndex])) { ui.toolButtonOnlineDevice->setEnabled(true); - ui.labelDevicePresent->setText("Device report already present in database"); + ui.labelDevicePresent->setText("Device is already present in the database"); // Report present, check if it can be updated // TODO : Update mechanics! /* @@ -1566,7 +1566,7 @@ void vulkanCapsViewer::checkReportDatabaseState() } else { - ui.labelDevicePresent->setText("Device report not present in database yet"); + ui.labelDevicePresent->setText("Device can be uploaded to the database"); } ui.labelDevicePresent->setVisible(true); QApplication::restoreOverrideCursor(); diff --git a/vulkandatabase.cpp b/vulkandatabase.cpp index 50d6101..133effc 100644 --- a/vulkandatabase.cpp +++ b/vulkandatabase.cpp @@ -1,10 +1,10 @@ /* * -* OpenGL hardware capability viewer and database +* Vulkan hardware capability viewer and database * -* Server http communication class implementation +* Database communication class implementation * -* Copyright (C) 2011-2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,14 +33,6 @@ QString VulkanDatabase::username = ""; QString VulkanDatabase::password = ""; QString VulkanDatabase::databaseUrl = "http://vulkan.gpuinfo.org/"; -VulkanDatabase::VulkanDatabase() -{ -} - -VulkanDatabase::~VulkanDatabase() -{ -} - /// /// Checks if the online database can be reached /// diff --git a/vulkandatabase.h b/vulkandatabase.h index acb1fa0..e72de4b 100644 --- a/vulkandatabase.h +++ b/vulkandatabase.h @@ -4,7 +4,7 @@ * * Database communication class implementation * -* Copyright (C) 2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -55,7 +55,5 @@ class VulkanDatabase : string fetchReport(int reportId); string postReport(string xml); string postReportForUpdate(string xml); - VulkanDatabase(); - ~VulkanDatabase(); }; diff --git a/vulkansurfaceinfo.hpp b/vulkansurfaceinfo.hpp index 36624d3..082ed7c 100644 --- a/vulkansurfaceinfo.hpp +++ b/vulkansurfaceinfo.hpp @@ -4,7 +4,7 @@ * * Surface information class * -* Copyright (C) 2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,9 +43,7 @@ struct VulkanSurfaceInfo return; } - //todo: error checking - VkResult vkRes; - vkRes = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &capabilities); // Present modes uint32_t presentModeCount; @@ -54,7 +52,7 @@ struct VulkanSurfaceInfo presentModes.resize(presentModeCount); if (presentModeCount > 0) { - vkRes = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data()); + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data()); } } @@ -65,7 +63,7 @@ struct VulkanSurfaceInfo formats.resize(surfaceFormatCount); if (surfaceFormatCount > 0) { - vkRes = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &surfaceFormatCount, formats.data()); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &surfaceFormatCount, formats.data()); } } } From a6028a2ee0df4ac20e405f8643214ea076cc6a1c Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 26 Dec 2020 18:15:21 +0100 Subject: [PATCH 32/38] Submit dialog caption can be customized --- submitDialog.cpp | 10 +++++----- submitDialog.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/submitDialog.cpp b/submitDialog.cpp index 6e438d7..8e0b3ee 100644 --- a/submitDialog.cpp +++ b/submitDialog.cpp @@ -1,10 +1,10 @@ /* * -* OpenGL hardware capability viewer and database +* Vulkan hardware capability viewer * * Submit report dialog * -* Copyright (C) 2011-2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -30,14 +30,14 @@ #include #include -submitDialog::submitDialog(QString submitter) +submitDialog::submitDialog(QString submitter, QString caption) { QFormLayout *formLayout = new QFormLayout; // QDialogBox doesn't appear modal on Android which makes it hard to see #ifdef ANDROID QLabel *labelCaption = new QLabel(); - labelCaption->setText("Submit report to database"); + labelCaption->setText(caption); formLayout->addRow(labelCaption); setStyleSheet("QDialog{ border: 2px solid black; border-style: solid; border-radius: 4px; }"); #endif @@ -63,7 +63,7 @@ submitDialog::submitDialog(QString submitter) formLayout->addWidget(buttonBox); setLayout(formLayout); - setWindowTitle("Submit report"); + setWindowTitle(caption); } diff --git a/submitDialog.h b/submitDialog.h index 304b019..3abf9bb 100644 --- a/submitDialog.h +++ b/submitDialog.h @@ -4,7 +4,7 @@ * * Submit report dialog * -* Copyright (C) 2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -34,7 +34,7 @@ class submitDialog : public QDialog public: std::string submitter; std::string comment; - submitDialog(QString submitter); + submitDialog(QString submitter, QString caption = "Submit new report"); ~submitDialog(); std::string getSubmitter(); std::string getComment(); From 78b1ed3a48ddb53114d98d299996226412736635 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 26 Dec 2020 18:15:41 +0100 Subject: [PATCH 33/38] Added update check and post functions to database class --- vulkandatabase.cpp | 100 +++++++++++++++++++++++++++++++-------------- vulkandatabase.h | 4 +- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/vulkandatabase.cpp b/vulkandatabase.cpp index 133effc..bbca972 100644 --- a/vulkandatabase.cpp +++ b/vulkandatabase.cpp @@ -31,7 +31,9 @@ QString VulkanDatabase::username = ""; QString VulkanDatabase::password = ""; -QString VulkanDatabase::databaseUrl = "http://vulkan.gpuinfo.org/"; +// @todo: do not commit +//QString VulkanDatabase::databaseUrl = "http://vulkan.gpuinfo.org/"; +QString VulkanDatabase::databaseUrl = "http://localhost:8080/"; /// /// Checks if the online database can be reached @@ -175,33 +177,14 @@ int VulkanDatabase::getReportId(VulkanDeviceInfo device) return (!reply.empty()) ? atoi(reply.c_str()) : -1; } -/// /// Checks if the report is present in the online database -/// bool VulkanDatabase::checkReportPresent(VulkanDeviceInfo device) { int reportID = getReportId(device); return (reportID > -1) ? true : false; } -/// -/// Fechtes an xml with all report data from the online database -/// -/// id of the report to get the report xml for -/// xml string -string VulkanDatabase::fetchReport(int reportId) -{ - string reportXml; - stringstream urlss; - urlss << getBaseUrl() << "services/getreport.php?id=" << reportId; - reportXml = httpGet(urlss.str()); - return reportXml; -} - -/// /// Posts the given xml for a report to the database -/// -/// todo string VulkanDatabase::postReport(string xml) { string httpReply; @@ -211,19 +194,76 @@ string VulkanDatabase::postReport(string xml) return httpReply; } -/// -/// Posts the given url to the db report update script -/// -/// Coma separated list of updated caps -string VulkanDatabase::postReportForUpdate(string xml) +// Checks if the report stored in the database can be updated with missing data from the local report +bool VulkanDatabase::checkCanUpdateReport(VulkanDeviceInfo& device, int reportId) { - string httpReply; - stringstream urlss; - urlss << getBaseUrl() << "services/updatereport.php"; - httpReply = httpPost(urlss.str(), xml); - return httpReply; + manager = new QNetworkAccessManager(nullptr); + QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart jsonPart; + jsonPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"data\"; filename=\"update_check_report.json\"")); + QJsonDocument doc(device.toJson("", "")); + jsonPart.setBody(doc.toJson()); + multiPart->append(jsonPart); + QUrl qurl(databaseUrl + "api/v3/checkcanupdatereport.php?reportid=" + QString::number(reportId)); + QNetworkRequest request(qurl); + QNetworkReply* reply = manager->post(request, multiPart); + multiPart->setParent(reply); + QEventLoop loop; + connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + bool result = false; + if (reply->error() == QNetworkReply::NoError) + { + QJsonDocument response = QJsonDocument::fromJson(reply->readAll()); + bool canUpdate = response.isObject() ? response.object()["canupdate"].toBool() : false; + result = canUpdate; + } + else + { + QString err(reply->errorString()); + result = false; + } + delete(manager); + return result; } +// Upload the current report for updating an existing report +bool VulkanDatabase::postReportForUpdate(VulkanDeviceInfo &device, int reportId, QString& updateLog) +{ + manager = new QNetworkAccessManager(nullptr); + QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart jsonPart; + jsonPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"data\"; filename=\"update_report.json\"")); + QJsonDocument doc(device.toJson("", "")); + jsonPart.setBody(doc.toJson()); + multiPart->append(jsonPart); + QUrl qurl(databaseUrl + "api/v3/updatereport.php?reportid=" + QString::number(reportId)); + QNetworkRequest request(qurl); + QNetworkReply* reply = manager->post(request, multiPart); + multiPart->setParent(reply); + QEventLoop loop; + connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(QEventLoop::ExcludeUserInputEvents); + bool result = false; + if (reply->error() == QNetworkReply::NoError) + { + QJsonDocument response = QJsonDocument::fromJson(reply->readAll()); + if (response.isObject() && response.object()["log"].isArray()) { + QJsonArray logArray = response.object()["log"].toArray(); + foreach(const QJsonValue logEntry, logArray) { + updateLog += logEntry.toString() + "\n"; + } + } + result = true; + } + else + { + QString err(reply->errorString()); + result = false; + } + delete(manager); + return result; +} string VulkanDatabase::getBaseUrl() { diff --git a/vulkandatabase.h b/vulkandatabase.h index e72de4b..1d12b91 100644 --- a/vulkandatabase.h +++ b/vulkandatabase.h @@ -50,10 +50,10 @@ class VulkanDatabase : static QString databaseUrl; int getReportId(VulkanDeviceInfo device); bool checkReportPresent(VulkanDeviceInfo device); + bool checkCanUpdateReport(VulkanDeviceInfo &device, int reportId); bool checkServerConnection(); string getBaseUrl(); - string fetchReport(int reportId); string postReport(string xml); - string postReportForUpdate(string xml); + bool postReportForUpdate(VulkanDeviceInfo &device, int reportId, QString &updateLog); }; From 73c706367fefc233fa9b9b089bd82dec3590a1fe Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 26 Dec 2020 21:40:45 +0100 Subject: [PATCH 34/38] Reworked report state handling Proper database state is now stored for the report and used throughout the code to enable/disable actions Uploads are now also blocking --- vulkancapsviewer.cpp | 139 ++++++++++++++++++++++++++++--------------- vulkancapsviewer.h | 4 ++ vulkandatabase.cpp | 16 +++-- vulkandatabase.h | 2 +- 4 files changed, 103 insertions(+), 58 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 93b6ec5..2a1a725 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -317,41 +317,61 @@ void vulkanCapsViewer::slotUploadReport() return; } - int reportId = databaseConnection.getReportId(device); - if (reportId > -1) - { - QMessageBox::StandardButton reply; - reply = QMessageBox::question(this, "Device already present", "A report for the selected device is already present in the database.\n\nDo you want to open the report in your browser?", QMessageBox::Yes | QMessageBox::No); - if (reply == QMessageBox::Yes) - { - QString url = QString::fromStdString(databaseConnection.getBaseUrl() + "displayreport.php?id=" + to_string(reportId)); - QDesktopServices::openUrl(QUrl(url)); - } - return; - } + // Upload new report + if (reportState == ReportState::not_present) { + submitDialog dialog(appSettings.submitterName, "Submit new report"); + if (dialog.exec() == QDialog::Accepted) { + exportReportAsJSON("vulkanreport.json", dialog.getSubmitter(), dialog.getComment()); + std::ostringstream sstream(std::ios::out | std::ios::binary); + std::ifstream inFile("vulkanreport.json"); + std::string line; + while (std::getline(inFile, line)) sstream << line << "\r\n"; + string reply = databaseConnection.postReport(sstream.str()); + if (reply == "res_uploaded") + { + QMessageBox::information(this, "Report submitted", "Your report has been uploaded to the database!\n\nThank you for your contribution!"); + checkReportDatabaseState(); + } + else + { + QMessageBox::warning(this, "Error", "The report could not be uploaded : \n" + QString::fromStdString(reply)); + } + } + return; + } - submitDialog dialog(appSettings.submitterName); - bool ok = (dialog.exec() == QDialog::Accepted); + // Update existing report + if (reportState == ReportState::is_updatable) { + submitDialog dialog(appSettings.submitterName, "Update existing report"); + if (dialog.exec() == QDialog::Accepted) { + int reportId = databaseConnection.getReportId(device); + QApplication::setOverrideCursor(Qt::WaitCursor); + QString updateLog; + bool updateResult = databaseConnection.postReportForUpdate(device, reportId, updateLog); + QApplication::restoreOverrideCursor(); + if (updateResult) { + QMessageBox::information(this, "Report updated", "The report has been updated with the following information:\n\n" + updateLog + "\nThank you for your contribution!"); + } + else { + QMessageBox::warning(this, "Error", "The report could not be updated : \n" + QString::fromStdString("xxx")); + } + checkReportDatabaseState(); + } + return; + } - if (ok) - { - exportReportAsJSON("vulkanreport.json", dialog.getSubmitter(), dialog.getComment()); - std::ostringstream sstream(std::ios::out | std::ios::binary); - std::ifstream inFile("vulkanreport.json"); - std::string line; - while (std::getline(inFile, line)) sstream << line << "\r\n"; - - string reply = databaseConnection.postReport(sstream.str()); - if (reply == "res_uploaded") - { - QMessageBox::information(this, "Report submitted", "Your report has been uploaded to the database!\n\nThanks for your contribution!"); - checkReportDatabaseState(); - } - else - { - QMessageBox::warning(this, "Error", "The report could not be uploaded : \n" + QString::fromStdString(reply)); - } - } + // Show link to database for existing reports + if (reportState == ReportState::is_present) { + int reportId = databaseConnection.getReportId(device); + QMessageBox::StandardButton reply; + reply = QMessageBox::question(this, "Device already present", "A report for the selected device is already present in the database.\n\nDo you want to open the report in your browser?", QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) + { + QString url = QString::fromStdString(databaseConnection.getBaseUrl() + "displayreport.php?id=" + to_string(reportId)); + QDesktopServices::openUrl(QUrl(url)); + } + return; + } } void vulkanCapsViewer::slotSettings() @@ -1539,36 +1559,31 @@ void vulkanCapsViewer::exportReportAsJSON(std::string fileName, std::string subm void vulkanCapsViewer::checkReportDatabaseState() { ui.labelDevicePresent->setText("Connecting to database..."); - ui.labelDevicePresent->setVisible(true); ui.toolButtonOnlineDevice->setEnabled(false); QApplication::setOverrideCursor(Qt::WaitCursor); if (!databaseConnection.checkServerConnection()) { ui.labelDevicePresent->setText("Could not connect to the database!\n\nPlease check your internet connection and proxy settings!"); - ui.labelDevicePresent->setVisible(true); QApplication::restoreOverrideCursor(); return; } - if (databaseConnection.checkReportPresent(vulkanGPUs[selectedDeviceIndex])) + int reportId; + if (databaseConnection.checkReportPresent(vulkanGPUs[selectedDeviceIndex], reportId)) { - ui.toolButtonOnlineDevice->setEnabled(true); - ui.labelDevicePresent->setText("Device is already present in the database"); - // Report present, check if it can be updated - // TODO : Update mechanics! - /* - int reportId = glhttp.getReportId(core.description); - if (canUpdateReport(reportId)) { - ui.labelDevicePresent->setText("Device already present in database, but can be updated with missing values!"); - } - */ + // Check if report can be updated with new information not yet stored in the database + if (databaseConnection.checkCanUpdateReport(vulkanGPUs[selectedDeviceIndex], reportId)) { + setReportState(ReportState::is_updatable); + } + else { + setReportState(ReportState::is_present); + } } else { - ui.labelDevicePresent->setText("Device can be uploaded to the database"); + setReportState(ReportState::not_present); } - ui.labelDevicePresent->setVisible(true); QApplication::restoreOverrideCursor(); } @@ -1609,3 +1624,31 @@ int vulkanCapsViewer::uploadReportNonVisual(int deviceIndex, QString submitter, return -3; } } + +void vulkanCapsViewer::setReportState(ReportState state) +{ + reportState = state; + switch (reportState) { + case ReportState::is_present: + ui.toolButtonOnlineDevice->setEnabled(false); + ui.toolButtonOnlineDevice->setEnabled(true); + ui.toolButtonUpload->setText("Upload"); + ui.labelDevicePresent->setText("Device is already present in the database"); + break; + case ReportState::not_present: + ui.toolButtonOnlineDevice->setEnabled(false); + ui.toolButtonUpload->setText("Upload"); + ui.labelDevicePresent->setText("Device can be uploaded to the database"); + break; + case ReportState::is_updatable: + ui.toolButtonOnlineDevice->setEnabled(true); + ui.toolButtonUpload->setText("Update"); + ui.labelDevicePresent->setText("Device is already present in the database, but can be updated"); + break; + default: + ui.toolButtonOnlineDevice->setEnabled(false); + ui.toolButtonUpload->setText("n.a."); + ui.labelDevicePresent->setText("Could not get report state from database"); + } +} + diff --git a/vulkancapsviewer.h b/vulkancapsviewer.h index feba381..5a1c420 100644 --- a/vulkancapsviewer.h +++ b/vulkancapsviewer.h @@ -51,6 +51,8 @@ struct vulkanGlobalInfo } features; }; +enum ReportState { unknown, not_present, is_present, is_updatable }; + class vulkanCapsViewer : public QMainWindow { Q_OBJECT @@ -58,6 +60,7 @@ class vulkanCapsViewer : public QMainWindow public: static const std::string version; static const std::string reportVersion; + ReportState reportState = ReportState::unknown; std::vector vulkanGPUs; vulkanInstanceInfo instanceInfo; vulkanGlobalInfo globalInfo; @@ -115,6 +118,7 @@ class vulkanCapsViewer : public QMainWindow void displayDeviceSurfaceInfo(VulkanDeviceInfo &device); void displayInstanceLayers(); void displayInstanceExtensions(); + void setReportState(ReportState state); private Q_SLOTS: void slotClose(); void slotBrowseDatabase(); diff --git a/vulkandatabase.cpp b/vulkandatabase.cpp index bbca972..1b71e31 100644 --- a/vulkandatabase.cpp +++ b/vulkandatabase.cpp @@ -31,9 +31,7 @@ QString VulkanDatabase::username = ""; QString VulkanDatabase::password = ""; -// @todo: do not commit -//QString VulkanDatabase::databaseUrl = "http://vulkan.gpuinfo.org/"; -QString VulkanDatabase::databaseUrl = "http://localhost:8080/"; +QString VulkanDatabase::databaseUrl = "http://vulkan.gpuinfo.org/"; /// /// Checks if the online database can be reached @@ -80,7 +78,7 @@ string VulkanDatabase::httpGet(string url) QEventLoop loop; connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); + loop.exec(QEventLoop::ExcludeUserInputEvents); if (reply->error() == QNetworkReply::NoError) { @@ -129,7 +127,7 @@ string VulkanDatabase::httpPost(string url, string data) QEventLoop loop; connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); + loop.exec(QEventLoop::ExcludeUserInputEvents); if (reply->error() == QNetworkReply::NoError) { @@ -178,10 +176,10 @@ int VulkanDatabase::getReportId(VulkanDeviceInfo device) } /// Checks if the report is present in the online database -bool VulkanDatabase::checkReportPresent(VulkanDeviceInfo device) +bool VulkanDatabase::checkReportPresent(VulkanDeviceInfo device, int& reportId) { - int reportID = getReportId(device); - return (reportID > -1) ? true : false; + reportId = getReportId(device); + return (reportId > -1) ? true : false; } /// Posts the given xml for a report to the database @@ -210,7 +208,7 @@ bool VulkanDatabase::checkCanUpdateReport(VulkanDeviceInfo& device, int reportId multiPart->setParent(reply); QEventLoop loop; connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); + loop.exec(QEventLoop::ExcludeUserInputEvents); bool result = false; if (reply->error() == QNetworkReply::NoError) { diff --git a/vulkandatabase.h b/vulkandatabase.h index 1d12b91..8a058a5 100644 --- a/vulkandatabase.h +++ b/vulkandatabase.h @@ -49,7 +49,7 @@ class VulkanDatabase : static QString password; static QString databaseUrl; int getReportId(VulkanDeviceInfo device); - bool checkReportPresent(VulkanDeviceInfo device); + bool checkReportPresent(VulkanDeviceInfo device, int &reportId); bool checkCanUpdateReport(VulkanDeviceInfo &device, int reportId); bool checkServerConnection(); string getBaseUrl(); From ae28aa2c1c0164baac57189649fb858ceab0eda2 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 26 Dec 2020 22:17:29 +0100 Subject: [PATCH 35/38] Supply additional details to report id fetch api on Android On Android, the device name only contains the GPU name, so additional information is required to identify a specific device report --- vulkandatabase.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vulkandatabase.cpp b/vulkandatabase.cpp index 1b71e31..183c80a 100644 --- a/vulkandatabase.cpp +++ b/vulkandatabase.cpp @@ -163,13 +163,18 @@ int VulkanDatabase::getReportId(VulkanDeviceInfo device) { string reply; stringstream urlss; - urlss << getBaseUrl() << "/services/getreportid.php?" + urlss << getBaseUrl() << "/api/v3/getreportid.php?" << "devicename=" << device.props.deviceName << "&driverversion=" << device.getDriverVersion() << "&osname=" << device.os.name << "&osversion=" << device.os.version << "&osarchitecture=" << device.os.architecture << "&apiversion=" << vulkanResources::versionToString(device.props.apiVersion); +#ifdef __ANDROID__ + // Compare against platform info on Android, as driver version and device name (which is just the GPU name on android) are not sufficient to identify a single report + urlss << "&androidproductmodel=" << device.platformdetails["android.ProductModel"]; + urlss << "&androidproductmanufacturer=" << device.platformdetails["android.ProductManufacturer"]; +#endif; string url = encodeUrl(urlss.str()); reply = httpGet(url); return (!reply.empty()) ? atoi(reply.c_str()) : -1; From 7ef9297f7ba777798ab292dd72092ccb1bfc48bd Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 27 Dec 2020 09:29:38 +0100 Subject: [PATCH 36/38] Minor fixed, and Android related changes --- vulkanDeviceInfo.cpp | 8 +++----- vulkanDeviceInfo.h | 2 +- vulkancapsviewer.cpp | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/vulkanDeviceInfo.cpp b/vulkanDeviceInfo.cpp index 99fb1f0..9ad023a 100644 --- a/vulkanDeviceInfo.cpp +++ b/vulkanDeviceInfo.cpp @@ -4,7 +4,7 @@ * * Device information class * -* Copyright (C) 2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -670,6 +670,7 @@ void VulkanDeviceInfo::readPlatformDetails() platformdetails["android.ProductManufacturer"] = getSystemProperty("ro.product.manufacturer"); platformdetails["android.BuildID"] = getSystemProperty("ro.build.id"); platformdetails["android.BuildVersionIncremental"] = getSystemProperty("ro.build.version.incremental"); + properties["displayName"] = QString::fromStdString(platformdetails["android.ProductManufacturer"] + " " + platformdetails["android.ProductModel"]); #endif } @@ -714,7 +715,7 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) } // Core 1.2 - if ((!core11Properties.empty()) || (!core11Features.empty())) { + if ((!core12Properties.empty()) || (!core12Features.empty())) { QJsonObject jsonCore12; if (!core12Properties.empty()) { jsonCore12["properties"] = QJsonObject::fromVariantMap(core12Properties); @@ -877,8 +878,6 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) jsonEnv["appversion"] = QString::fromStdString(appVersion); root["environment"] = jsonEnv; -#define EXTENDED_PROPS -#if defined(EXTENDED_PROPS) QJsonObject jsonExtended; // VK_KHR_get_physical_device_properties2 @@ -909,7 +908,6 @@ QJsonObject VulkanDeviceInfo::toJson(std::string submitter, std::string comment) jsonExtended["devicefeatures2"] = jsonFeatures2; root["extended"] = jsonExtended; -#endif return root; } diff --git a/vulkanDeviceInfo.h b/vulkanDeviceInfo.h index 0ff1dfd..50e7370 100644 --- a/vulkanDeviceInfo.h +++ b/vulkanDeviceInfo.h @@ -4,7 +4,7 @@ * * Device information class * -* Copyright (C) 2015 by Sascha Willems (www.saschawillems.de) +* Copyright (C) 2016-2020 by Sascha Willems (www.saschawillems.de) * * This code is free software, you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 2a1a725..7673868 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -1041,8 +1041,9 @@ void vulkanCapsViewer::displayDeviceProperties(VulkanDeviceInfo *device) for (QVariantMap::const_iterator iter = device->sparseProperties.begin(); iter != device->sparseProperties.end(); ++iter) { addVkBool32Item(core10SparseItem[0], iter); } - +#if !defined(__ANDROID__) ui.treeViewDeviceProperties->expandAll(); +#endif ui.treeViewDeviceProperties->header()->setSectionResizeMode(QHeaderView::ResizeToContents); // Core 1.1 From 1d045eab84672aa5fc743732504a54972bd3f7c0 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 27 Dec 2020 11:55:28 +0100 Subject: [PATCH 37/38] Refactored database URl setup Use v3 api for report uploads --- vulkancapsviewer.cpp | 9 ++++----- vulkandatabase.cpp | 14 ++++---------- vulkandatabase.h | 1 - 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/vulkancapsviewer.cpp b/vulkancapsviewer.cpp index 7673868..2be85c2 100644 --- a/vulkancapsviewer.cpp +++ b/vulkancapsviewer.cpp @@ -264,9 +264,8 @@ void vulkanCapsViewer::slotBrowseDatabase() void vulkanCapsViewer::slotDisplayOnlineReport() { int reportId = databaseConnection.getReportId(vulkanGPUs[selectedDeviceIndex]); - stringstream ss; - ss << databaseConnection.getBaseUrl() << "displayreport.php?id=" << reportId; - QDesktopServices::openUrl(QUrl(QString::fromStdString(ss.str()))); + QUrl url(databaseConnection.databaseUrl + "displayreport.php?id=" + QString::number(reportId)); + QDesktopServices::openUrl(url); } std::string apiVersionText(uint32_t apiVersion) @@ -367,8 +366,8 @@ void vulkanCapsViewer::slotUploadReport() reply = QMessageBox::question(this, "Device already present", "A report for the selected device is already present in the database.\n\nDo you want to open the report in your browser?", QMessageBox::Yes | QMessageBox::No); if (reply == QMessageBox::Yes) { - QString url = QString::fromStdString(databaseConnection.getBaseUrl() + "displayreport.php?id=" + to_string(reportId)); - QDesktopServices::openUrl(QUrl(url)); + QUrl url(databaseConnection.databaseUrl + "displayreport.php?id=" + QString::number(reportId)); + QDesktopServices::openUrl(url); } return; } diff --git a/vulkandatabase.cpp b/vulkandatabase.cpp index 183c80a..db0ead7 100644 --- a/vulkandatabase.cpp +++ b/vulkandatabase.cpp @@ -40,7 +40,7 @@ bool VulkanDatabase::checkServerConnection() { manager = new QNetworkAccessManager(nullptr); - QUrl qurl(QString::fromStdString(getBaseUrl() + "/services/serverstate.php")); + QUrl qurl(databaseUrl + "api/v3/serverstate.php"); if (username != "" && password != "") { @@ -163,7 +163,7 @@ int VulkanDatabase::getReportId(VulkanDeviceInfo device) { string reply; stringstream urlss; - urlss << getBaseUrl() << "/api/v3/getreportid.php?" + urlss << databaseUrl.toStdString() << "api/v3/getreportid.php?" << "devicename=" << device.props.deviceName << "&driverversion=" << device.getDriverVersion() << "&osname=" << device.os.name @@ -192,7 +192,7 @@ string VulkanDatabase::postReport(string xml) { string httpReply; stringstream urlss; - urlss << getBaseUrl() << "api/v2/uploadreport.php"; + urlss << databaseUrl.toStdString() << "api/v3/uploadreport.php"; httpReply = httpPost(urlss.str(), xml); return httpReply; } @@ -231,7 +231,7 @@ bool VulkanDatabase::checkCanUpdateReport(VulkanDeviceInfo& device, int reportId } // Upload the current report for updating an existing report -bool VulkanDatabase::postReportForUpdate(VulkanDeviceInfo &device, int reportId, QString& updateLog) +bool VulkanDatabase::postReportForUpdate(VulkanDeviceInfo &device, int reportId, QString &updateLog) { manager = new QNetworkAccessManager(nullptr); QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); @@ -267,9 +267,3 @@ bool VulkanDatabase::postReportForUpdate(VulkanDeviceInfo &device, int reportId, delete(manager); return result; } - -string VulkanDatabase::getBaseUrl() -{ - return databaseUrl.toStdString(); -} - diff --git a/vulkandatabase.h b/vulkandatabase.h index 8a058a5..e1d6243 100644 --- a/vulkandatabase.h +++ b/vulkandatabase.h @@ -52,7 +52,6 @@ class VulkanDatabase : bool checkReportPresent(VulkanDeviceInfo device, int &reportId); bool checkCanUpdateReport(VulkanDeviceInfo &device, int reportId); bool checkServerConnection(); - string getBaseUrl(); string postReport(string xml); bool postReportForUpdate(VulkanDeviceInfo &device, int reportId, QString &updateLog); }; From 872023afd9033e82877251e0678db55867b73a43 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Thu, 31 Dec 2020 16:54:07 +0100 Subject: [PATCH 38/38] Only fetch Vulkan 1.1. core features and properties if implementation supports at least Vulkan 1.2 Dedicated structs for these have only been introduced with 1.2, so fetching them on 1.1 implementations isn't corect --- vulkanDeviceInfo.cpp | 309 ++++++++++++++++++++++--------------------- 1 file changed, 157 insertions(+), 152 deletions(-) diff --git a/vulkanDeviceInfo.cpp b/vulkanDeviceInfo.cpp index 9ad023a..a17041a 100644 --- a/vulkanDeviceInfo.cpp +++ b/vulkanDeviceInfo.cpp @@ -238,31 +238,6 @@ void VulkanDeviceInfo::readPhysicalProperties() if (vulkan_1_1()) { VkPhysicalDeviceProperties2KHR deviceProps2{}; deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; - - // Core - VkPhysicalDeviceVulkan11Properties coreProps{}; - coreProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; - deviceProps2.pNext = &coreProps; - pfnGetPhysicalDeviceProperties2KHR(device, &deviceProps2); - - core11Properties.clear(); - core11Properties["deviceUUID"] = UUIDToJson(coreProps.deviceUUID); - core11Properties["driverUUID"] = UUIDToJson(coreProps.driverUUID); - core11Properties["deviceLUID"] = UUIDToJson(coreProps.deviceLUID); - core11Properties["deviceNodeMask"] = coreProps.deviceNodeMask; - core11Properties["deviceLUIDValid"] = coreProps.deviceLUIDValid; - core11Properties["subgroupSize"] = coreProps.subgroupSize; - core11Properties["subgroupSupportedStages"] = coreProps.subgroupSupportedStages; - core11Properties["subgroupSupportedOperations"] = coreProps.subgroupSupportedOperations; - core11Properties["subgroupQuadOperationsInAllStages"] = coreProps.subgroupQuadOperationsInAllStages; - core11Properties["pointClippingBehavior"] = coreProps.pointClippingBehavior; - core11Properties["maxMultiviewViewCount"] = coreProps.maxMultiviewViewCount; - core11Properties["maxMultiviewInstanceIndex"] = coreProps.maxMultiviewInstanceIndex; - core11Properties["protectedNoFault"] = coreProps.protectedNoFault; - core11Properties["maxPerSetDescriptors"] = coreProps.maxPerSetDescriptors; - core11Properties["maxMemoryAllocationSize"] = QVariant::fromValue(coreProps.maxMemoryAllocationSize); - - // Subgroup props (@todo: Still required?) VkPhysicalDeviceSubgroupProperties extProps{}; extProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; deviceProps2.pNext = &extProps; @@ -289,68 +264,95 @@ void VulkanDeviceInfo::readPhysicalProperties() // VK 1.2 core if (vulkan_1_2()) { + // Vulkan 1.2 introduced dedicated structures for properties promoted to core in 1.1 and 1.2 + // Fetching the core 1.1 properties also requires a Vulkan 1.2 (or later) implementation + VkPhysicalDeviceProperties2KHR deviceProps2{}; deviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; - // Core - VkPhysicalDeviceVulkan12Properties coreProps{}; - coreProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; - deviceProps2.pNext = &coreProps; + // Core 1.1 + VkPhysicalDeviceVulkan11Properties coreProps11{}; + coreProps11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; + deviceProps2.pNext = &coreProps11; + pfnGetPhysicalDeviceProperties2KHR(device, &deviceProps2); + + core11Properties.clear(); + core11Properties["deviceUUID"] = UUIDToJson(coreProps11.deviceUUID); + core11Properties["driverUUID"] = UUIDToJson(coreProps11.driverUUID); + core11Properties["deviceLUID"] = UUIDToJson(coreProps11.deviceLUID); + core11Properties["deviceNodeMask"] = coreProps11.deviceNodeMask; + core11Properties["deviceLUIDValid"] = coreProps11.deviceLUIDValid; + core11Properties["subgroupSize"] = coreProps11.subgroupSize; + core11Properties["subgroupSupportedStages"] = coreProps11.subgroupSupportedStages; + core11Properties["subgroupSupportedOperations"] = coreProps11.subgroupSupportedOperations; + core11Properties["subgroupQuadOperationsInAllStages"] = coreProps11.subgroupQuadOperationsInAllStages; + core11Properties["pointClippingBehavior"] = coreProps11.pointClippingBehavior; + core11Properties["maxMultiviewViewCount"] = coreProps11.maxMultiviewViewCount; + core11Properties["maxMultiviewInstanceIndex"] = coreProps11.maxMultiviewInstanceIndex; + core11Properties["protectedNoFault"] = coreProps11.protectedNoFault; + core11Properties["maxPerSetDescriptors"] = coreProps11.maxPerSetDescriptors; + core11Properties["maxMemoryAllocationSize"] = QVariant::fromValue(coreProps11.maxMemoryAllocationSize); + + + // Core 1.2 + VkPhysicalDeviceVulkan12Properties coreProps12{}; + coreProps12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; + deviceProps2.pNext = &coreProps12; pfnGetPhysicalDeviceProperties2KHR(device, &deviceProps2); core12Properties.clear(); - core12Properties["driverID"] = coreProps.driverID; - core12Properties["driverName"] = QString(coreProps.driverName); - core12Properties["driverInfo"] = QString(coreProps.driverInfo); - core12Properties["conformanceVersion"] = QString::fromStdString(vulkanResources::conformanceVersionKHRString(coreProps.conformanceVersion)); - core12Properties["denormBehaviorIndependence"] = coreProps.denormBehaviorIndependence; - core12Properties["roundingModeIndependence"] = coreProps.roundingModeIndependence; - core12Properties["shaderSignedZeroInfNanPreserveFloat16"] = coreProps.shaderSignedZeroInfNanPreserveFloat16; - core12Properties["shaderSignedZeroInfNanPreserveFloat32"] = coreProps.shaderSignedZeroInfNanPreserveFloat32; - core12Properties["shaderSignedZeroInfNanPreserveFloat64"] = coreProps.shaderSignedZeroInfNanPreserveFloat64; - core12Properties["shaderDenormPreserveFloat16"] = coreProps.shaderDenormPreserveFloat16; - core12Properties["shaderDenormPreserveFloat32"] = coreProps.shaderDenormPreserveFloat32; - core12Properties["shaderDenormPreserveFloat64"] = coreProps.shaderDenormPreserveFloat64; - core12Properties["shaderDenormFlushToZeroFloat16"] = coreProps.shaderDenormFlushToZeroFloat16; - core12Properties["shaderDenormFlushToZeroFloat32"] = coreProps.shaderDenormFlushToZeroFloat32; - core12Properties["shaderDenormFlushToZeroFloat64"] = coreProps.shaderDenormFlushToZeroFloat64; - core12Properties["shaderRoundingModeRTEFloat16"] = coreProps.shaderRoundingModeRTEFloat16; - core12Properties["shaderRoundingModeRTEFloat32"] = coreProps.shaderRoundingModeRTEFloat32; - core12Properties["shaderRoundingModeRTEFloat64"] = coreProps.shaderRoundingModeRTEFloat64; - core12Properties["shaderRoundingModeRTZFloat16"] = coreProps.shaderRoundingModeRTZFloat16; - core12Properties["shaderRoundingModeRTZFloat32"] = coreProps.shaderRoundingModeRTZFloat32; - core12Properties["shaderRoundingModeRTZFloat64"] = coreProps.shaderRoundingModeRTZFloat64; - core12Properties["maxUpdateAfterBindDescriptorsInAllPools"] = coreProps.maxUpdateAfterBindDescriptorsInAllPools; - core12Properties["shaderUniformBufferArrayNonUniformIndexingNative"] = coreProps.shaderUniformBufferArrayNonUniformIndexingNative; - core12Properties["shaderSampledImageArrayNonUniformIndexingNative"] = coreProps.shaderSampledImageArrayNonUniformIndexingNative; - core12Properties["shaderStorageBufferArrayNonUniformIndexingNative"] = coreProps.shaderStorageBufferArrayNonUniformIndexingNative; - core12Properties["shaderStorageImageArrayNonUniformIndexingNative"] = coreProps.shaderStorageImageArrayNonUniformIndexingNative; - core12Properties["shaderInputAttachmentArrayNonUniformIndexingNative"] = coreProps.shaderInputAttachmentArrayNonUniformIndexingNative; - core12Properties["robustBufferAccessUpdateAfterBind"] = coreProps.robustBufferAccessUpdateAfterBind; - core12Properties["quadDivergentImplicitLod"] = coreProps.quadDivergentImplicitLod; - core12Properties["maxPerStageDescriptorUpdateAfterBindSamplers"] = coreProps.maxPerStageDescriptorUpdateAfterBindSamplers; - core12Properties["maxPerStageDescriptorUpdateAfterBindUniformBuffers"] = coreProps.maxPerStageDescriptorUpdateAfterBindUniformBuffers; - core12Properties["maxPerStageDescriptorUpdateAfterBindStorageBuffers"] = coreProps.maxPerStageDescriptorUpdateAfterBindStorageBuffers; - core12Properties["maxPerStageDescriptorUpdateAfterBindSampledImages"] = coreProps.maxPerStageDescriptorUpdateAfterBindSampledImages; - core12Properties["maxPerStageDescriptorUpdateAfterBindStorageImages"] = coreProps.maxPerStageDescriptorUpdateAfterBindStorageImages; - core12Properties["maxPerStageDescriptorUpdateAfterBindInputAttachments"] = coreProps.maxPerStageDescriptorUpdateAfterBindInputAttachments; - core12Properties["maxPerStageUpdateAfterBindResources"] = coreProps.maxPerStageUpdateAfterBindResources; - core12Properties["maxDescriptorSetUpdateAfterBindSamplers"] = coreProps.maxDescriptorSetUpdateAfterBindSamplers; - core12Properties["maxDescriptorSetUpdateAfterBindUniformBuffers"] = coreProps.maxDescriptorSetUpdateAfterBindUniformBuffers; - core12Properties["maxDescriptorSetUpdateAfterBindUniformBuffersDynamic"] = coreProps.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; - core12Properties["maxDescriptorSetUpdateAfterBindStorageBuffers"] = coreProps.maxDescriptorSetUpdateAfterBindStorageBuffers; - core12Properties["maxDescriptorSetUpdateAfterBindStorageBuffersDynamic"] = coreProps.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; - core12Properties["maxDescriptorSetUpdateAfterBindSampledImages"] = coreProps.maxDescriptorSetUpdateAfterBindSampledImages; - core12Properties["maxDescriptorSetUpdateAfterBindStorageImages"] = coreProps.maxDescriptorSetUpdateAfterBindStorageImages; - core12Properties["maxDescriptorSetUpdateAfterBindInputAttachments"] = coreProps.maxDescriptorSetUpdateAfterBindInputAttachments; - core12Properties["supportedDepthResolveModes"] = coreProps.supportedDepthResolveModes; - core12Properties["supportedStencilResolveModes"] = coreProps.supportedStencilResolveModes; - core12Properties["independentResolveNone"] = coreProps.independentResolveNone; - core12Properties["independentResolve"] = coreProps.independentResolve; - core12Properties["filterMinmaxSingleComponentFormats"] = coreProps.filterMinmaxSingleComponentFormats; - core12Properties["filterMinmaxImageComponentMapping"] = coreProps.filterMinmaxImageComponentMapping; - core12Properties["maxTimelineSemaphoreValueDifference"] = QVariant::fromValue(coreProps.maxTimelineSemaphoreValueDifference); - core12Properties["framebufferIntegerColorSampleCounts"] = coreProps.framebufferIntegerColorSampleCounts; + core12Properties["driverID"] = coreProps12.driverID; + core12Properties["driverName"] = QString(coreProps12.driverName); + core12Properties["driverInfo"] = QString(coreProps12.driverInfo); + core12Properties["conformanceVersion"] = QString::fromStdString(vulkanResources::conformanceVersionKHRString(coreProps12.conformanceVersion)); + core12Properties["denormBehaviorIndependence"] = coreProps12.denormBehaviorIndependence; + core12Properties["roundingModeIndependence"] = coreProps12.roundingModeIndependence; + core12Properties["shaderSignedZeroInfNanPreserveFloat16"] = coreProps12.shaderSignedZeroInfNanPreserveFloat16; + core12Properties["shaderSignedZeroInfNanPreserveFloat32"] = coreProps12.shaderSignedZeroInfNanPreserveFloat32; + core12Properties["shaderSignedZeroInfNanPreserveFloat64"] = coreProps12.shaderSignedZeroInfNanPreserveFloat64; + core12Properties["shaderDenormPreserveFloat16"] = coreProps12.shaderDenormPreserveFloat16; + core12Properties["shaderDenormPreserveFloat32"] = coreProps12.shaderDenormPreserveFloat32; + core12Properties["shaderDenormPreserveFloat64"] = coreProps12.shaderDenormPreserveFloat64; + core12Properties["shaderDenormFlushToZeroFloat16"] = coreProps12.shaderDenormFlushToZeroFloat16; + core12Properties["shaderDenormFlushToZeroFloat32"] = coreProps12.shaderDenormFlushToZeroFloat32; + core12Properties["shaderDenormFlushToZeroFloat64"] = coreProps12.shaderDenormFlushToZeroFloat64; + core12Properties["shaderRoundingModeRTEFloat16"] = coreProps12.shaderRoundingModeRTEFloat16; + core12Properties["shaderRoundingModeRTEFloat32"] = coreProps12.shaderRoundingModeRTEFloat32; + core12Properties["shaderRoundingModeRTEFloat64"] = coreProps12.shaderRoundingModeRTEFloat64; + core12Properties["shaderRoundingModeRTZFloat16"] = coreProps12.shaderRoundingModeRTZFloat16; + core12Properties["shaderRoundingModeRTZFloat32"] = coreProps12.shaderRoundingModeRTZFloat32; + core12Properties["shaderRoundingModeRTZFloat64"] = coreProps12.shaderRoundingModeRTZFloat64; + core12Properties["maxUpdateAfterBindDescriptorsInAllPools"] = coreProps12.maxUpdateAfterBindDescriptorsInAllPools; + core12Properties["shaderUniformBufferArrayNonUniformIndexingNative"] = coreProps12.shaderUniformBufferArrayNonUniformIndexingNative; + core12Properties["shaderSampledImageArrayNonUniformIndexingNative"] = coreProps12.shaderSampledImageArrayNonUniformIndexingNative; + core12Properties["shaderStorageBufferArrayNonUniformIndexingNative"] = coreProps12.shaderStorageBufferArrayNonUniformIndexingNative; + core12Properties["shaderStorageImageArrayNonUniformIndexingNative"] = coreProps12.shaderStorageImageArrayNonUniformIndexingNative; + core12Properties["shaderInputAttachmentArrayNonUniformIndexingNative"] = coreProps12.shaderInputAttachmentArrayNonUniformIndexingNative; + core12Properties["robustBufferAccessUpdateAfterBind"] = coreProps12.robustBufferAccessUpdateAfterBind; + core12Properties["quadDivergentImplicitLod"] = coreProps12.quadDivergentImplicitLod; + core12Properties["maxPerStageDescriptorUpdateAfterBindSamplers"] = coreProps12.maxPerStageDescriptorUpdateAfterBindSamplers; + core12Properties["maxPerStageDescriptorUpdateAfterBindUniformBuffers"] = coreProps12.maxPerStageDescriptorUpdateAfterBindUniformBuffers; + core12Properties["maxPerStageDescriptorUpdateAfterBindStorageBuffers"] = coreProps12.maxPerStageDescriptorUpdateAfterBindStorageBuffers; + core12Properties["maxPerStageDescriptorUpdateAfterBindSampledImages"] = coreProps12.maxPerStageDescriptorUpdateAfterBindSampledImages; + core12Properties["maxPerStageDescriptorUpdateAfterBindStorageImages"] = coreProps12.maxPerStageDescriptorUpdateAfterBindStorageImages; + core12Properties["maxPerStageDescriptorUpdateAfterBindInputAttachments"] = coreProps12.maxPerStageDescriptorUpdateAfterBindInputAttachments; + core12Properties["maxPerStageUpdateAfterBindResources"] = coreProps12.maxPerStageUpdateAfterBindResources; + core12Properties["maxDescriptorSetUpdateAfterBindSamplers"] = coreProps12.maxDescriptorSetUpdateAfterBindSamplers; + core12Properties["maxDescriptorSetUpdateAfterBindUniformBuffers"] = coreProps12.maxDescriptorSetUpdateAfterBindUniformBuffers; + core12Properties["maxDescriptorSetUpdateAfterBindUniformBuffersDynamic"] = coreProps12.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic; + core12Properties["maxDescriptorSetUpdateAfterBindStorageBuffers"] = coreProps12.maxDescriptorSetUpdateAfterBindStorageBuffers; + core12Properties["maxDescriptorSetUpdateAfterBindStorageBuffersDynamic"] = coreProps12.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic; + core12Properties["maxDescriptorSetUpdateAfterBindSampledImages"] = coreProps12.maxDescriptorSetUpdateAfterBindSampledImages; + core12Properties["maxDescriptorSetUpdateAfterBindStorageImages"] = coreProps12.maxDescriptorSetUpdateAfterBindStorageImages; + core12Properties["maxDescriptorSetUpdateAfterBindInputAttachments"] = coreProps12.maxDescriptorSetUpdateAfterBindInputAttachments; + core12Properties["supportedDepthResolveModes"] = coreProps12.supportedDepthResolveModes; + core12Properties["supportedStencilResolveModes"] = coreProps12.supportedStencilResolveModes; + core12Properties["independentResolveNone"] = coreProps12.independentResolveNone; + core12Properties["independentResolve"] = coreProps12.independentResolve; + core12Properties["filterMinmaxSingleComponentFormats"] = coreProps12.filterMinmaxSingleComponentFormats; + core12Properties["filterMinmaxImageComponentMapping"] = coreProps12.filterMinmaxImageComponentMapping; + core12Properties["maxTimelineSemaphoreValueDifference"] = QVariant::fromValue(coreProps12.maxTimelineSemaphoreValueDifference); + core12Properties["framebufferIntegerColorSampleCounts"] = coreProps12.framebufferIntegerColorSampleCounts; } } @@ -428,26 +430,6 @@ void VulkanDeviceInfo::readPhysicalFeatures() VkPhysicalDeviceFeatures2KHR deviceFeatures2{}; deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; - // Core - VkPhysicalDeviceVulkan11Features coreFeatures{}; - coreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; - deviceFeatures2.pNext = &coreFeatures; - pfnGetPhysicalDeviceFeatures2KHR(device, &deviceFeatures2); - - core11Features.clear(); - core11Features["storageBuffer16BitAccess"] = coreFeatures.storageBuffer16BitAccess; - core11Features["uniformAndStorageBuffer16BitAccess"] = coreFeatures.uniformAndStorageBuffer16BitAccess; - core11Features["storagePushConstant16"] = coreFeatures.storagePushConstant16; - core11Features["storageInputOutput16"] = coreFeatures.storageInputOutput16; - core11Features["multiview"] = coreFeatures.multiview; - core11Features["multiviewGeometryShader"] = coreFeatures.multiviewGeometryShader; - core11Features["multiviewTessellationShader"] = coreFeatures.multiviewTessellationShader; - core11Features["variablePointersStorageBuffer"] = coreFeatures.variablePointersStorageBuffer; - core11Features["variablePointers"] = coreFeatures.variablePointers; - core11Features["protectedMemory"] = coreFeatures.protectedMemory; - core11Features["samplerYcbcrConversion"] = coreFeatures.samplerYcbcrConversion; - core11Features["shaderDrawParameters"] = coreFeatures.shaderDrawParameters; - // VK_KHR_shader_draw_parameters if (extensionSupported(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME)) { VkPhysicalDeviceShaderDrawParameterFeatures extFeatures{}; @@ -460,63 +442,86 @@ void VulkanDeviceInfo::readPhysicalFeatures() // Vulkan 1.2 if (vulkan_1_2()) { + // Vulkan 1.2 introduced dedicated structures for features promoted to core in 1.1 and 1.2 + // Fetching the core 1.1 features also requires a Vulkan 1.2 (or later) implementation + VkPhysicalDeviceFeatures2KHR deviceFeatures2{}; deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; - // Core - VkPhysicalDeviceVulkan12Features coreFeatures{}; - coreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - deviceFeatures2.pNext = &coreFeatures; + // Core 1.1 + VkPhysicalDeviceVulkan11Features coreFeatures11{}; + coreFeatures11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + deviceFeatures2.pNext = &coreFeatures11; + pfnGetPhysicalDeviceFeatures2KHR(device, &deviceFeatures2); + + core11Features.clear(); + core11Features["storageBuffer16BitAccess"] = coreFeatures11.storageBuffer16BitAccess; + core11Features["uniformAndStorageBuffer16BitAccess"] = coreFeatures11.uniformAndStorageBuffer16BitAccess; + core11Features["storagePushConstant16"] = coreFeatures11.storagePushConstant16; + core11Features["storageInputOutput16"] = coreFeatures11.storageInputOutput16; + core11Features["multiview"] = coreFeatures11.multiview; + core11Features["multiviewGeometryShader"] = coreFeatures11.multiviewGeometryShader; + core11Features["multiviewTessellationShader"] = coreFeatures11.multiviewTessellationShader; + core11Features["variablePointersStorageBuffer"] = coreFeatures11.variablePointersStorageBuffer; + core11Features["variablePointers"] = coreFeatures11.variablePointers; + core11Features["protectedMemory"] = coreFeatures11.protectedMemory; + core11Features["samplerYcbcrConversion"] = coreFeatures11.samplerYcbcrConversion; + core11Features["shaderDrawParameters"] = coreFeatures11.shaderDrawParameters; + + // Core 1.2 + VkPhysicalDeviceVulkan12Features coreFeatures12{}; + coreFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + deviceFeatures2.pNext = &coreFeatures12; pfnGetPhysicalDeviceFeatures2KHR(device, &deviceFeatures2); core12Features.clear(); - core12Features["samplerMirrorClampToEdge"] = coreFeatures.samplerMirrorClampToEdge; - core12Features["drawIndirectCount"] = coreFeatures.drawIndirectCount; - core12Features["storageBuffer8BitAccess"] = coreFeatures.storageBuffer8BitAccess; - core12Features["uniformAndStorageBuffer8BitAccess"] = coreFeatures.uniformAndStorageBuffer8BitAccess; - core12Features["storagePushConstant8"] = coreFeatures.storagePushConstant8; - core12Features["shaderBufferInt64Atomics"] = coreFeatures.shaderBufferInt64Atomics; - core12Features["shaderSharedInt64Atomics"] = coreFeatures.shaderSharedInt64Atomics; - core12Features["shaderFloat16"] = coreFeatures.shaderFloat16; - core12Features["shaderInt8"] = coreFeatures.shaderInt8; - core12Features["descriptorIndexing"] = coreFeatures.descriptorIndexing; - core12Features["shaderInputAttachmentArrayDynamicIndexing"] = coreFeatures.shaderInputAttachmentArrayDynamicIndexing; - core12Features["shaderUniformTexelBufferArrayDynamicIndexing"] = coreFeatures.shaderUniformTexelBufferArrayDynamicIndexing; - core12Features["shaderStorageTexelBufferArrayDynamicIndexing"] = coreFeatures.shaderStorageTexelBufferArrayDynamicIndexing; - core12Features["shaderUniformBufferArrayNonUniformIndexing"] = coreFeatures.shaderUniformBufferArrayNonUniformIndexing; - core12Features["shaderSampledImageArrayNonUniformIndexing"] = coreFeatures.shaderSampledImageArrayNonUniformIndexing; - core12Features["shaderStorageBufferArrayNonUniformIndexing"] = coreFeatures.shaderStorageBufferArrayNonUniformIndexing; - core12Features["shaderStorageImageArrayNonUniformIndexing"] = coreFeatures.shaderStorageImageArrayNonUniformIndexing; - core12Features["shaderInputAttachmentArrayNonUniformIndexing"] = coreFeatures.shaderInputAttachmentArrayNonUniformIndexing; - core12Features["shaderUniformTexelBufferArrayNonUniformIndexing"] = coreFeatures.shaderUniformTexelBufferArrayNonUniformIndexing; - core12Features["shaderStorageTexelBufferArrayNonUniformIndexing"] = coreFeatures.shaderStorageTexelBufferArrayNonUniformIndexing; - core12Features["descriptorBindingUniformBufferUpdateAfterBind"] = coreFeatures.descriptorBindingUniformBufferUpdateAfterBind; - core12Features["descriptorBindingSampledImageUpdateAfterBind"] = coreFeatures.descriptorBindingSampledImageUpdateAfterBind; - core12Features["descriptorBindingStorageImageUpdateAfterBind"] = coreFeatures.descriptorBindingStorageImageUpdateAfterBind; - core12Features["descriptorBindingStorageBufferUpdateAfterBind"] = coreFeatures.descriptorBindingStorageBufferUpdateAfterBind; - core12Features["descriptorBindingUniformTexelBufferUpdateAfterBind"] = coreFeatures.descriptorBindingUniformTexelBufferUpdateAfterBind; - core12Features["descriptorBindingStorageTexelBufferUpdateAfterBind"] = coreFeatures.descriptorBindingStorageTexelBufferUpdateAfterBind; - core12Features["descriptorBindingUpdateUnusedWhilePending"] = coreFeatures.descriptorBindingUpdateUnusedWhilePending; - core12Features["descriptorBindingPartiallyBound"] = coreFeatures.descriptorBindingPartiallyBound; - core12Features["descriptorBindingVariableDescriptorCount"] = coreFeatures.descriptorBindingVariableDescriptorCount; - core12Features["runtimeDescriptorArray"] = coreFeatures.runtimeDescriptorArray; - core12Features["samplerFilterMinmax"] = coreFeatures.samplerFilterMinmax; - core12Features["scalarBlockLayout"] = coreFeatures.scalarBlockLayout; - core12Features["imagelessFramebuffer"] = coreFeatures.imagelessFramebuffer; - core12Features["uniformBufferStandardLayout"] = coreFeatures.uniformBufferStandardLayout; - core12Features["shaderSubgroupExtendedTypes"] = coreFeatures.shaderSubgroupExtendedTypes; - core12Features["separateDepthStencilLayouts"] = coreFeatures.separateDepthStencilLayouts; - core12Features["hostQueryReset"] = coreFeatures.hostQueryReset; - core12Features["timelineSemaphore"] = coreFeatures.timelineSemaphore; - core12Features["bufferDeviceAddress"] = coreFeatures.bufferDeviceAddress; - core12Features["bufferDeviceAddressCaptureReplay"] = coreFeatures.bufferDeviceAddressCaptureReplay; - core12Features["bufferDeviceAddressMultiDevice"] = coreFeatures.bufferDeviceAddressMultiDevice; - core12Features["vulkanMemoryModel"] = coreFeatures.vulkanMemoryModel; - core12Features["vulkanMemoryModelDeviceScope"] = coreFeatures.vulkanMemoryModelDeviceScope; - core12Features["vulkanMemoryModelAvailabilityVisibilityChains"] = coreFeatures.vulkanMemoryModelAvailabilityVisibilityChains; - core12Features["shaderOutputViewportIndex"] = coreFeatures.shaderOutputViewportIndex; - core12Features["shaderOutputLayer"] = coreFeatures.shaderOutputLayer; - core12Features["subgroupBroadcastDynamicId"] = coreFeatures.subgroupBroadcastDynamicId; + core12Features["samplerMirrorClampToEdge"] = coreFeatures12.samplerMirrorClampToEdge; + core12Features["drawIndirectCount"] = coreFeatures12.drawIndirectCount; + core12Features["storageBuffer8BitAccess"] = coreFeatures12.storageBuffer8BitAccess; + core12Features["uniformAndStorageBuffer8BitAccess"] = coreFeatures12.uniformAndStorageBuffer8BitAccess; + core12Features["storagePushConstant8"] = coreFeatures12.storagePushConstant8; + core12Features["shaderBufferInt64Atomics"] = coreFeatures12.shaderBufferInt64Atomics; + core12Features["shaderSharedInt64Atomics"] = coreFeatures12.shaderSharedInt64Atomics; + core12Features["shaderFloat16"] = coreFeatures12.shaderFloat16; + core12Features["shaderInt8"] = coreFeatures12.shaderInt8; + core12Features["descriptorIndexing"] = coreFeatures12.descriptorIndexing; + core12Features["shaderInputAttachmentArrayDynamicIndexing"] = coreFeatures12.shaderInputAttachmentArrayDynamicIndexing; + core12Features["shaderUniformTexelBufferArrayDynamicIndexing"] = coreFeatures12.shaderUniformTexelBufferArrayDynamicIndexing; + core12Features["shaderStorageTexelBufferArrayDynamicIndexing"] = coreFeatures12.shaderStorageTexelBufferArrayDynamicIndexing; + core12Features["shaderUniformBufferArrayNonUniformIndexing"] = coreFeatures12.shaderUniformBufferArrayNonUniformIndexing; + core12Features["shaderSampledImageArrayNonUniformIndexing"] = coreFeatures12.shaderSampledImageArrayNonUniformIndexing; + core12Features["shaderStorageBufferArrayNonUniformIndexing"] = coreFeatures12.shaderStorageBufferArrayNonUniformIndexing; + core12Features["shaderStorageImageArrayNonUniformIndexing"] = coreFeatures12.shaderStorageImageArrayNonUniformIndexing; + core12Features["shaderInputAttachmentArrayNonUniformIndexing"] = coreFeatures12.shaderInputAttachmentArrayNonUniformIndexing; + core12Features["shaderUniformTexelBufferArrayNonUniformIndexing"] = coreFeatures12.shaderUniformTexelBufferArrayNonUniformIndexing; + core12Features["shaderStorageTexelBufferArrayNonUniformIndexing"] = coreFeatures12.shaderStorageTexelBufferArrayNonUniformIndexing; + core12Features["descriptorBindingUniformBufferUpdateAfterBind"] = coreFeatures12.descriptorBindingUniformBufferUpdateAfterBind; + core12Features["descriptorBindingSampledImageUpdateAfterBind"] = coreFeatures12.descriptorBindingSampledImageUpdateAfterBind; + core12Features["descriptorBindingStorageImageUpdateAfterBind"] = coreFeatures12.descriptorBindingStorageImageUpdateAfterBind; + core12Features["descriptorBindingStorageBufferUpdateAfterBind"] = coreFeatures12.descriptorBindingStorageBufferUpdateAfterBind; + core12Features["descriptorBindingUniformTexelBufferUpdateAfterBind"] = coreFeatures12.descriptorBindingUniformTexelBufferUpdateAfterBind; + core12Features["descriptorBindingStorageTexelBufferUpdateAfterBind"] = coreFeatures12.descriptorBindingStorageTexelBufferUpdateAfterBind; + core12Features["descriptorBindingUpdateUnusedWhilePending"] = coreFeatures12.descriptorBindingUpdateUnusedWhilePending; + core12Features["descriptorBindingPartiallyBound"] = coreFeatures12.descriptorBindingPartiallyBound; + core12Features["descriptorBindingVariableDescriptorCount"] = coreFeatures12.descriptorBindingVariableDescriptorCount; + core12Features["runtimeDescriptorArray"] = coreFeatures12.runtimeDescriptorArray; + core12Features["samplerFilterMinmax"] = coreFeatures12.samplerFilterMinmax; + core12Features["scalarBlockLayout"] = coreFeatures12.scalarBlockLayout; + core12Features["imagelessFramebuffer"] = coreFeatures12.imagelessFramebuffer; + core12Features["uniformBufferStandardLayout"] = coreFeatures12.uniformBufferStandardLayout; + core12Features["shaderSubgroupExtendedTypes"] = coreFeatures12.shaderSubgroupExtendedTypes; + core12Features["separateDepthStencilLayouts"] = coreFeatures12.separateDepthStencilLayouts; + core12Features["hostQueryReset"] = coreFeatures12.hostQueryReset; + core12Features["timelineSemaphore"] = coreFeatures12.timelineSemaphore; + core12Features["bufferDeviceAddress"] = coreFeatures12.bufferDeviceAddress; + core12Features["bufferDeviceAddressCaptureReplay"] = coreFeatures12.bufferDeviceAddressCaptureReplay; + core12Features["bufferDeviceAddressMultiDevice"] = coreFeatures12.bufferDeviceAddressMultiDevice; + core12Features["vulkanMemoryModel"] = coreFeatures12.vulkanMemoryModel; + core12Features["vulkanMemoryModelDeviceScope"] = coreFeatures12.vulkanMemoryModelDeviceScope; + core12Features["vulkanMemoryModelAvailabilityVisibilityChains"] = coreFeatures12.vulkanMemoryModelAvailabilityVisibilityChains; + core12Features["shaderOutputViewportIndex"] = coreFeatures12.shaderOutputViewportIndex; + core12Features["shaderOutputLayer"] = coreFeatures12.shaderOutputLayer; + core12Features["subgroupBroadcastDynamicId"] = coreFeatures12.subgroupBroadcastDynamicId; } }