/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2021 The Khronos Group Inc. * Copyright (c) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Cover for non-zero of memoryTypeBits from vkGetBufferMemoryRequirements*() tests. *//*--------------------------------------------------------------------*/ #include "vktApiBufferMemoryRequirementsTests.hpp" #include "vktApiBufferMemoryRequirementsTestsUtils.hpp" #include "vkMemUtil.hpp" #include "vkQueryUtil.hpp" #include "vkTypeUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "deFilePath.hpp" #include "tcuTestLog.hpp" #include #include #include #include #include #include #include #include namespace vkt { namespace api { namespace { using namespace de; using namespace vk; using namespace tcu; struct TestConfig; struct InstanceConfig; enum BufferFateFlagBits { Transfer = 0x01, Storage = 0x02, Other = 0x04, AccStructure = 0x08, Video = 0x10 }; typedef deUint32 BufferFateFlags; typedef typename std::add_pointer::type>::type cstr; typedef u::BitsSet BufferFateBits; const BufferFateBits AvailableBufferFateBits { std::make_tuple(Transfer, "transfer_usage_bits" ), std::make_tuple(Storage, "storage_usage_bits" ), std::make_tuple(Other, "other_usage_bits" ), std::make_tuple(AccStructure, "acc_struct_usage_bits" ), std::make_tuple(Video, "video_usage_bits" ), }; typedef u::BitsSet BufferCreateBits; typedef u::BitsSet BufferUsageBits; typedef u::BitsSet ExternalMemoryHandleBits; typedef SharedPtr BufferCreateBitsPtr; typedef SharedPtr BufferUsageBitsPtr; typedef SharedPtr ExternalMemoryHandleBitsPtr; struct TestConfig { bool useMethod2; SharedPtr createBits; SharedPtr fateBits; bool incExtMemTypeFlags; // Tests the buffer memory size requirement is less than or equal to the aligned size of the buffer. // Requires VK_KHR_maintenance4 extension. bool testSizeRequirements; }; struct InstanceConfig { bool useMethod2; SharedPtr createBits; SharedPtr fateBits; SharedPtr> usageFlags; bool incExtMemTypeFlags; SharedPtr> extMemHandleFlags; bool testSizeRequirements; InstanceConfig(const TestConfig& conf) : useMethod2 (conf.useMethod2) , createBits (conf.createBits) , fateBits (conf.fateBits) , usageFlags (new std::vector>) , incExtMemTypeFlags (conf.incExtMemTypeFlags) , extMemHandleFlags (new std::vector>) , testSizeRequirements (conf.testSizeRequirements) {} }; const BufferCreateBits AvailableBufferCreateBits { std::make_tuple(VkBufferCreateFlagBits(0), "no_flags" ), std::make_tuple(VK_BUFFER_CREATE_PROTECTED_BIT, "protected" ), std::make_tuple(VK_BUFFER_CREATE_SPARSE_BINDING_BIT, "sparse_binding" ), std::make_tuple(VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, "sparse_residency" ), std::make_tuple(VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, "sparse_aliased" ), }; const BufferUsageBits AvailableBufferUsageBits { std::make_tuple(VK_BUFFER_USAGE_TRANSFER_SRC_BIT , Transfer ), std::make_tuple(VK_BUFFER_USAGE_TRANSFER_DST_BIT , Transfer ), std::make_tuple(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT , Storage ), std::make_tuple(VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT , Storage ), std::make_tuple(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT , Storage ), std::make_tuple(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT , Storage ), std::make_tuple(VK_BUFFER_USAGE_INDEX_BUFFER_BIT , Storage ), std::make_tuple(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT , Storage ), std::make_tuple(VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT , Other ), std::make_tuple(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT , Other ), std::make_tuple(VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR , Video ), std::make_tuple(VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR , Video ), std::make_tuple(VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT , Other ), std::make_tuple(VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT , Other ), std::make_tuple(VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT , Other ), std::make_tuple(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR , AccStructure ), std::make_tuple(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR , AccStructure ), std::make_tuple(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR , AccStructure ), std::make_tuple(VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR , Video ), std::make_tuple(VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR , Video ), }; #define INTERNALTEST_EXTERNAL_MEMORY_HANDLE_TYPE_NO_BITS VkExternalMemoryHandleTypeFlagBits(0) const ExternalMemoryHandleBits AvailableExternalMemoryHandleBits { std::make_tuple(INTERNALTEST_EXTERNAL_MEMORY_HANDLE_TYPE_NO_BITS , "no_flags", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT , "opaque_fd", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT , "opaque_win32", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT , "opaque_win32_kmt", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT , "d3d11_tex", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT , "d3d11_tex_kmt", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT , "d3d12_heap", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT , "d3d12_rsrc", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT , "dma_buf", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID , "android_hw", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT , "host_alloc", true ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT , "host_mapped", true ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA , "zircon_vmo", false ), std::make_tuple(VK_EXTERNAL_MEMORY_HANDLE_TYPE_RDMA_ADDRESS_BIT_NV , "roma_addr", false ), }; template std::string bitsToString (const u::BitsSet& bits, const std::string& prefix = std::string()) { DE_ASSERT(!bits.empty()); std::stringstream s; s << prefix; bool atLeastOne = false; for (const auto& bit : bits) { if (atLeastOne) s << '_'; s << std::get<1>(bit); atLeastOne = true; } return s.str(); } void updateBufferCreateFlags(std::vector& flags) { const auto& residencyBit = AvailableBufferCreateBits.get(VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT); const auto& aliasedBit = AvailableBufferCreateBits.get(VK_BUFFER_CREATE_SPARSE_ALIASED_BIT); const auto& bindingBit = AvailableBufferCreateBits.get(VK_BUFFER_CREATE_SPARSE_BINDING_BIT); const auto& protectedBit = AvailableBufferCreateBits.get(VK_BUFFER_CREATE_PROTECTED_BIT); const auto& noneBit = AvailableBufferCreateBits.get(VkBufferCreateFlagBits(0)); // VUID-VkBufferCreateInfo-flags-00918 { if sparse residency or sparse aliased include sparse binding } for (auto& bits : flags) { if (bits.contains(residencyBit) || bits.contains(aliasedBit)) bits.insert(bindingBit); } // VUID-VkBufferCreateInfo-None-01888 { if sparse residency, sparse aliased or sparse binding then flags must not include protected } const typename BufferCreateBits::key_type disallowdBits[] { residencyBit, aliasedBit, bindingBit }; for (auto i = flags.begin(); i != flags.end();) { auto& bits = *i; if (bits.contains(protectedBit)) { for (const auto& disallowdBit : disallowdBits) { auto find = bits.find(disallowdBit); if (find != bits.end()) bits.erase(find); } } i = bits.empty() ? flags.erase(i) : std::next(i); } // since 0 is a valid VkBufferCreateFlagBits flag then remove it flags where it exists along with other non-zero flags for (auto i = flags.begin(); i != flags.end(); ++i) { auto& bits = *i; auto find = bits.find(noneBit); if (find != bits.end() && bits.size() > 1) { bits.erase(find); } } // remove duplicates for (auto i = flags.begin(); i != flags.end(); ++i) { for (auto j = std::next(i); j != flags.end();) j = (*i == *j) ? flags.erase(j) : std::next(j); } } class BufferMemoryRequirementsInstance : public TestInstance { public: BufferMemoryRequirementsInstance (Context& context, const InstanceConfig config) : TestInstance (context) , m_config (config) {} virtual ~BufferMemoryRequirementsInstance (void) override = default; virtual tcu::TestStatus iterate (void) override; void getBufferMemoryRequirements (VkMemoryRequirements& result, const DeviceInterface& vkd, VkDevice device, VkBuffer buffer) const; void getBufferMemoryRequirements2 (VkMemoryRequirements& result, const DeviceInterface& vkd, VkDevice device, VkBuffer buffer) const; typedef void (BufferMemoryRequirementsInstance::* Method) (VkMemoryRequirements& result, const DeviceInterface& intf, VkDevice device, VkBuffer buffer) const; template void* chainVkStructure (void* pNext, const AddArgs&... addArgs) const; private: void logFailedSubtests (const std::vector& failCreateBits, const std::vector& failUsageBits, const std::vector& failExtMemHandleBits) const; const InstanceConfig m_config; }; class MemoryRequirementsTest : public TestCase { public: MemoryRequirementsTest (TestContext& testCtx, const std::string& name, const TestConfig testConfig) : TestCase (testCtx, name, std::string()) , m_testConfig (testConfig) , m_instConfig (testConfig) {} virtual ~MemoryRequirementsTest (void) override = default; virtual void checkSupport (Context& context) const override; virtual TestInstance* createInstance (Context& context) const override { return new BufferMemoryRequirementsInstance(context, m_instConfig); } private: const TestConfig m_testConfig; InstanceConfig m_instConfig; }; struct Info { enum Type { Create, Usage } m_type; std::ostringstream m_str; cstr m_file; int m_line; template Info(Type type, const Msg& msg, cstr file, int line) : m_type(type), m_str(), m_file(file), m_line(line) { m_str << msg; } friend std::ostringstream& operator<<(std::ostringstream& str, const Info& info) { switch (info.m_type) { case Create: str << " Info (Create buffer with " << info.m_str.str() << " not supported by device at " << de::FilePath(info.m_file).getBaseName() << ":" << info.m_line << ")"; break; case Usage: str << " Info (Create buffer with " << info.m_str.str() << " not supported by device at " << de::FilePath(info.m_file).getBaseName() << ":" << info.m_line << ")"; break; } return str; } }; #define INFOCREATE(msg_) Info(Info::Create, (msg_), __FILE__, __LINE__) #define INFOUSAGE(msg_) Info(Info::Usage, (msg_), __FILE__, __LINE__) void MemoryRequirementsTest::checkSupport (Context& context) const { const InstanceInterface& intf = context.getInstanceInterface(); const VkPhysicalDevice physDevice = context.getPhysicalDevice(); const std::vector supportedExtensions = enumerateDeviceExtensionProperties(intf, physDevice, nullptr); VkPhysicalDeviceProtectedMemoryFeatures protectedMemFeatures { vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES, // VkStructureType sType; nullptr, // void* pNext; VK_FALSE // VkBool32 protectedMemory; }; VkPhysicalDeviceFeatures2 extFeatures { vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, // VkStructureType sType; &protectedMemFeatures, // void* pNext; {} // VkPhysicalDeviceFeatures features; }; intf.getPhysicalDeviceFeatures2(physDevice, &extFeatures); const VkPhysicalDeviceFeatures& features = extFeatures.features; const VkBool32& protectedMemFeatureEnabled = protectedMemFeatures.protectedMemory; // check the creating bits { std::ostringstream str; bool notSupported = false; const auto& createBits = *m_testConfig.createBits; if (createBits.contains(VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && (VK_FALSE == features.sparseBinding)) { if (notSupported) str << std::endl; str << INFOCREATE(getBufferCreateFlagsStr(VK_BUFFER_CREATE_SPARSE_BINDING_BIT)); notSupported = true; } if (createBits.contains(VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && (VK_FALSE == features.sparseResidencyBuffer)) { if (notSupported) str << std::endl; str << INFOCREATE(getBufferCreateFlagsStr(VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT)); notSupported = true; } if (createBits.contains(VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && (VK_FALSE == features.sparseResidencyAliased)) { if (notSupported) str << std::endl; str << INFOCREATE(getBufferCreateFlagsStr(VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)); notSupported = true; } if (createBits.contains(VK_BUFFER_CREATE_PROTECTED_BIT) && (VK_FALSE == protectedMemFeatureEnabled)) { if (notSupported) str << std::endl; str << INFOCREATE(getBufferCreateFlagsStr(VK_BUFFER_CREATE_PROTECTED_BIT)); notSupported = true; } if (notSupported) { std::cout << str.str() << std::endl; TCU_THROW(NotSupportedError, "One or more create buffer flags not supported by device"); } } // check the usage bits and build instance input { std::vector usageFlags; for (const auto& bit : *m_testConfig.fateBits) { auto fate = m_testConfig.fateBits->extract(bit); std::vector usageHints; std::vector usageFlagsTmp; u::combine(usageFlagsTmp, AvailableBufferUsageBits.select<1>(fate), usageHints); u::mergeFlags(usageFlags, usageFlagsTmp); } std::ostringstream str; std::array msgs; bool notSupported = false; int entryCount = 0; msgs.fill(false); for (auto i = usageFlags.begin(); i != usageFlags.end();) { notSupported = false; if (i->any({VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR, VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR}) && !isExtensionSupported(supportedExtensions, RequiredExtension("VK_KHR_acceleration_structure"))) { if (!msgs[0]) { if (entryCount++) str << std::endl; str << INFOUSAGE("VK_KHR_acceleration_structure not supported by device"); msgs[0] = true; } notSupported = true; } if (i->contains(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) && !isExtensionSupported(supportedExtensions, RequiredExtension("VK_EXT_buffer_device_address"))) { if (!msgs[1]) { if (entryCount++) str << std::endl; str << INFOUSAGE("VK_EXT_buffer_device_address not supported by device"); msgs[1] = true; } notSupported = true; } if (i->any({VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR, VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR, VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR})) { } i = notSupported ? usageFlags.erase(i) : std::next(i); } // remove duplicates for (auto i = usageFlags.begin(); i != usageFlags.end(); ++i) { for (auto j = std::next(i); j != usageFlags.end();) j = (*i == *j) ? usageFlags.erase(j) : std::next(j); } if (usageFlags.empty()) { std::cout << str.str() << std::endl; TCU_THROW(NotSupportedError, "One or more buffer usage flags not supported by device"); } else { if (entryCount > 0) { std::cout << str.str() << std::endl; } DE_ASSERT(m_instConfig.usageFlags.get()); m_instConfig.usageFlags->resize(usageFlags.size()); std::transform(usageFlags.begin(), usageFlags.end(), m_instConfig.usageFlags->begin(), [](BufferUsageBits& bits){ return BufferUsageBits::makeShared(std::move(bits)); }); } } // check the external memory handle type bits and build instance input { std::vector extMemHandleFlags; if (m_testConfig.incExtMemTypeFlags) extMemHandleFlags.push_back({AvailableExternalMemoryHandleBits.get(INTERNALTEST_EXTERNAL_MEMORY_HANDLE_TYPE_NO_BITS)}); else { std::vector handleHints; std::vector handleFlagsTmp; u::combine(handleFlagsTmp, AvailableExternalMemoryHandleBits.select<2>(true), handleHints); u::mergeFlags(extMemHandleFlags, handleFlagsTmp); } DE_ASSERT(m_instConfig.extMemHandleFlags.get()); m_instConfig.extMemHandleFlags->resize(extMemHandleFlags.size()); std::transform(extMemHandleFlags.begin(), extMemHandleFlags.end(), m_instConfig.extMemHandleFlags->begin(), [](ExternalMemoryHandleBits& bits){ return ExternalMemoryHandleBits::makeShared(std::move(bits)); }); } if (m_testConfig.testSizeRequirements) { if (!context.isDeviceFunctionalitySupported("VK_KHR_maintenance4")) TCU_THROW(NotSupportedError, "VK_KHR_maintenance4 not supported"); } } void BufferMemoryRequirementsInstance::logFailedSubtests (const std::vector& failCreateBits, const std::vector& failUsageBits, const std::vector& failExtMemHandleBits) const { const deUint32 flagCount = deUint32(failCreateBits.size()); TestLog& log = m_context.getTestContext().getLog(); deUint32 entries = 0; DE_ASSERT(flagCount && flagCount == failUsageBits.size() && flagCount == failExtMemHandleBits.size()); log << TestLog::Section("Failed", "Failed subtests"); for (deUint32 i = 0; i < flagCount; ++i) { { log << TestLog::Section("VkBufferCreateFlags", "Buffer create flags"); auto msg = log << TestLog::Message; entries = 0; for (const auto& createBit : *failCreateBits[i]) { if (entries++) msg << " "; const VkBufferCreateFlags flags = BufferCreateBits::extract(createBit); if (flags == 0) msg << "0"; else msg << getBufferCreateFlagsStr(flags); } msg << TestLog::EndMessage << TestLog::EndSection; } { log << TestLog::Section("VkBufferUsageFlags", "Buffer usage flags"); auto msg = log << TestLog::Message; entries = 0; for (const auto& usageBit : *failUsageBits[i]) { if (entries++) msg << " "; msg << getBufferUsageFlagsStr(BufferUsageBits::extract(usageBit)); } msg << TestLog::EndMessage << TestLog::EndSection; } { log << TestLog::Section("VkExternalMemoryHandleTypeFlags", "External memory handle type flags"); auto msg = log << TestLog::Message; entries = 0; for (const auto& extMemHandleTypeBit : *failExtMemHandleBits[i]) { if (entries++) msg << " "; msg << getExternalMemoryHandleTypeFlagsStr(ExternalMemoryHandleBits::extract(extMemHandleTypeBit)); } msg << TestLog::EndMessage << TestLog::EndSection; } } log << TestLog::EndSection; } void BufferMemoryRequirementsInstance::getBufferMemoryRequirements2 (VkMemoryRequirements& result, const DeviceInterface& vkd, VkDevice device, VkBuffer buffer) const { VkMemoryDedicatedRequirements dedicatedRequirements = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, // VkStructureType sType; nullptr, // const void* pNext; VK_FALSE, // VkBool32 prefersDedicatedAllocation VK_FALSE // VkBool32 requiresDedicatedAllocation }; VkMemoryRequirements2 desiredRequirements = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, // VkStructureType sType &dedicatedRequirements, // void* pNext result // VkMemoryRequirements memoryRequirements }; VkBufferMemoryRequirementsInfo2 requirementsInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2, // VkStructureType sType nullptr, // const void* pNext buffer // VkBuffer buffer }; vkd.getBufferMemoryRequirements2(device, &requirementsInfo, &desiredRequirements); result = desiredRequirements.memoryRequirements; } void BufferMemoryRequirementsInstance::getBufferMemoryRequirements (VkMemoryRequirements& result, const DeviceInterface& vkd, VkDevice device, VkBuffer buffer) const { vkd.getBufferMemoryRequirements(device, buffer, &result); } template<> void* BufferMemoryRequirementsInstance::chainVkStructure (void* pNext, const VkExternalMemoryHandleTypeFlags& handleTypes) const { static VkExternalMemoryBufferCreateInfo memInfo{}; memInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; memInfo.pNext = pNext; memInfo.handleTypes = handleTypes; return &memInfo; } template<> void* BufferMemoryRequirementsInstance::chainVkStructure (void* pNext) const { static const VkVideoProfileKHR videoProfile { VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR, // VkStructureType sType; nullptr, // void* pNext; VK_VIDEO_CODEC_OPERATION_INVALID_BIT_KHR, // VkVideoCodecOperationFlagBitsKHR videoCodecOperation; VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR, // VkVideoChromaSubsamplingFlagsKHR chromaSubsampling; VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR, // VkVideoComponentBitDepthFlagsKHR lumaBitDepth; VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR // VkVideoComponentBitDepthFlagsKHR chromaBitDepth; }; static VkVideoProfilesKHR profiles; profiles.sType = VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR; profiles.pNext = pNext; profiles.profileCount = 1u; profiles.pProfiles = &videoProfile; return &profiles; } TestStatus BufferMemoryRequirementsInstance::iterate (void) { const DeviceInterface& vkd = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); const Method method = m_config.useMethod2 ? &BufferMemoryRequirementsInstance::getBufferMemoryRequirements2 : &BufferMemoryRequirementsInstance::getBufferMemoryRequirements; deUint32 passCount = 0; deUint32 failCount = 0; std::vector failCreateBits; std::vector failUsageBits; std::vector failExtMemHandleBits; DE_ASSERT(!m_config.createBits->empty()); const VkBufferCreateFlags infoCreateFlags = *m_config.createBits; { DE_ASSERT(!m_config.usageFlags->empty()); for (auto u = m_config.usageFlags->cbegin(); u != m_config.usageFlags->cend(); ++u) { const VkBufferUsageFlags infoUsageFlags = *(u->get()); DE_ASSERT(!m_config.extMemHandleFlags->empty()); for (auto m = m_config.extMemHandleFlags->cbegin(); m != m_config.extMemHandleFlags->cend(); ++m) { const VkExternalMemoryHandleTypeFlags handleFlags = *(m->get()); void* pNext = nullptr; if (m_config.fateBits->contains(BufferFateFlagBits::Video)) { pNext = chainVkStructure(pNext); } if (m_config.incExtMemTypeFlags) { pNext = chainVkStructure(pNext, handleFlags); } VkBufferCreateInfo createInfo { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; pNext, // const void* pNext; infoCreateFlags, // VkBufferCreateFlags flags; 4096u, // VkDeviceSize size; infoUsageFlags, // VkBufferUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // uint32_t queueFamilyIndexCount; &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices; }; if (m_config.testSizeRequirements) { VkPhysicalDeviceMaintenance4PropertiesKHR maintenance4Properties = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR, // VkStructureType sType; DE_NULL, // void* pNext; 0u // VkDeviceSize maxBufferSize; }; VkPhysicalDeviceProperties2 physicalDeviceProperties2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, // VkStructureType sType; &maintenance4Properties, // void* pNext; {}, // VkPhysicalDeviceProperties properties; }; m_context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &physicalDeviceProperties2); const VkDeviceSize maxBufferSize = maintenance4Properties.maxBufferSize; DE_ASSERT(maxBufferSize > 0); VkDeviceSize N = 0; while ((1ull << N) + 1 < maxBufferSize) { createInfo.size = (1ull << N) + 1; try { Move buffer = createBuffer(vkd, device, &createInfo); VkMemoryRequirements reqs{}; (this->*method)(reqs, vkd, device, *buffer); if (reqs.size <= static_cast(deAlign64(static_cast(createInfo.size), static_cast(reqs.alignment)))) { ++passCount; } else { ++failCount; failCreateBits.emplace_back(m_config.createBits); failUsageBits.emplace_back(*u); failExtMemHandleBits.emplace_back(*m); } N++; } catch (const vk::OutOfMemoryError&) { break; } } } else { Move buffer = createBuffer(vkd, device, &createInfo); VkMemoryRequirements reqs{}; (this->*method)(reqs, vkd, device, *buffer); if (reqs.memoryTypeBits) ++passCount; else { ++failCount; failCreateBits.emplace_back(m_config.createBits); failUsageBits.emplace_back(*u); failExtMemHandleBits.emplace_back(*m); } } } } } if (failCount) { logFailedSubtests(failCreateBits, failUsageBits, failExtMemHandleBits); return TestStatus::fail(std::to_string(failCount)); } return TestStatus::pass(std::to_string(passCount)); } } // unnamed namespace tcu::TestCaseGroup* createBufferMemoryRequirementsTests (tcu::TestContext& testCtx) { cstr nilstr = ""; struct { bool include; cstr name; } const extMemTypeFlags[] { { false, "ext_mem_flags_excluded" }, { true, "ext_mem_flags_included" } }; struct { bool method; cstr name; } const methods[] { { false, "method1" }, { true, "method2" } }; std::vector> createBitPtrs; { std::vector hints; std::vector createFlags; u::combine(createFlags, AvailableBufferCreateBits, hints); updateBufferCreateFlags(createFlags); createBitPtrs.resize(createFlags.size()); std::transform(createFlags.begin(), createFlags.end(), createBitPtrs.begin(), [](BufferCreateBits& bits) { return BufferCreateBits::makeShared(std::move(bits)); }); } std::vector> fateBitPtrs; { // An excerpt above has been disabled consciously for the sake of computational complexity. // Enabled block does the same things sequentially, it doesn't create cartesian product of combination of bits. #if 0 std::vector hints; std::vector bufferFateFlags; u::combine(bufferFateFlags, AvailableBufferFateBits, hints); fateBitPtrs.resize(bufferFateFlags.size()); std::transform(bufferFateFlags.begin(), bufferFateFlags.end(), fateBitPtrs.begin(), [](BufferFateBits& bits) { return BufferFateBits::makeShared(std::move(bits)); }); #else fateBitPtrs.resize(AvailableBufferFateBits.size()); std::transform(AvailableBufferFateBits.begin(), AvailableBufferFateBits.end(), fateBitPtrs.begin(), [](const typename BufferFateBits::value_type& bit) { return BufferFateBits::makeShared(bit); }); #endif } auto groupRoot = new TestCaseGroup(testCtx, "buffer_memory_requirements", "vkGetBufferMemoryRequirements*(...) routines tests."); for (const auto& createBits : createBitPtrs) { auto groupCreate = new TestCaseGroup(testCtx, bitsToString(*createBits, "create_").c_str(), nilstr); for (const auto& extMemTypeFlag : extMemTypeFlags) { auto groupExtMemTypeFlags = new TestCaseGroup(testCtx, extMemTypeFlag.name, nilstr); for (const auto& method : methods) { auto groupMethod = new TestCaseGroup(testCtx, method.name, nilstr); for (const auto& fateBits : fateBitPtrs) { for (const auto testSizeReq : {false, true}) { TestConfig config; config.fateBits = fateBits; config.incExtMemTypeFlags = extMemTypeFlag.include; config.createBits = createBits; config.useMethod2 = method.method; config.testSizeRequirements = testSizeReq; groupMethod->addChild(new MemoryRequirementsTest(testCtx, ((testSizeReq ? "size_req_" : "") + bitsToString(*fateBits)).c_str(), config)); } } groupExtMemTypeFlags->addChild(groupMethod); } groupCreate->addChild(groupExtMemTypeFlags); } groupRoot->addChild(groupCreate); } return groupRoot; } } // api } // vkt