blob: d9a2f4dfafd30c893da6c081070ea8a7e03fa16b [file] [log] [blame]
/*------------------------------------------------------------------------
* 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 <algorithm>
#include <array>
#include <functional>
#include <iostream>
#include <set>
#include <sstream>
#include <tuple>
#include <vector>
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<typename std::add_const<char>::type>::type cstr;
typedef u::BitsSet<BufferFateFlags, BufferFateFlagBits, cstr> 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<VkBufferCreateFlags, VkBufferCreateFlagBits, cstr> BufferCreateBits;
typedef u::BitsSet<VkBufferUsageFlags, VkBufferUsageFlagBits, BufferFateFlagBits> BufferUsageBits;
typedef u::BitsSet<VkExternalMemoryHandleTypeFlags,
VkExternalMemoryHandleTypeFlagBits, cstr, bool> ExternalMemoryHandleBits;
typedef SharedPtr<BufferCreateBits> BufferCreateBitsPtr;
typedef SharedPtr<BufferUsageBits> BufferUsageBitsPtr;
typedef SharedPtr<ExternalMemoryHandleBits> ExternalMemoryHandleBitsPtr;
struct TestConfig
{
bool useMethod2;
SharedPtr<BufferCreateBits> createBits;
SharedPtr<BufferFateBits> 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<BufferCreateBits> createBits;
SharedPtr<BufferFateBits> fateBits;
SharedPtr<std::vector<BufferUsageBitsPtr>> usageFlags;
bool incExtMemTypeFlags;
SharedPtr<std::vector<ExternalMemoryHandleBitsPtr>> extMemHandleFlags;
bool testSizeRequirements;
InstanceConfig(const TestConfig& conf)
: useMethod2 (conf.useMethod2)
, createBits (conf.createBits)
, fateBits (conf.fateBits)
, usageFlags (new std::vector<SharedPtr<BufferUsageBits>>)
, incExtMemTypeFlags (conf.incExtMemTypeFlags)
, extMemHandleFlags (new std::vector<SharedPtr<ExternalMemoryHandleBits>>)
, 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<class Flag, class Bit, class Str, class... Ignored>
std::string bitsToString (const u::BitsSet<Flag, Bit, Str, Ignored...>& 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<BufferCreateBits>& 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<class T, class... AddArgs>
void* chainVkStructure (void* pNext,
const AddArgs&... addArgs) const;
private:
void logFailedSubtests (const std::vector<BufferCreateBitsPtr>& failCreateBits,
const std::vector<BufferUsageBitsPtr>& failUsageBits,
const std::vector<ExternalMemoryHandleBitsPtr>& 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<class Msg> 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__)
#ifndef VK_KHR_VIDEO_QUEUE_EXTENSION_NAME
#define VK_KHR_VIDEO_QUEUE_EXTENSION_NAME "VK_KHR_video_queue"
#endif
#ifndef VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME
#define VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME "VK_EXT_video_encode_h264"
#endif
#ifndef VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME
#define VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME "VK_EXT_video_decode_h264"
#endif
VkVideoCodecOperationFlagsKHR readVideoCodecOperationFlagsKHR (const InstanceInterface& vki, const VkPhysicalDevice& device)
{
uint32_t queueFamilyPropertyCount = 0;
vki.getPhysicalDeviceQueueFamilyProperties2(device, &queueFamilyPropertyCount, nullptr);
DE_ASSERT(queueFamilyPropertyCount);
std::vector<VkVideoQueueFamilyProperties2KHR> videoQueueFamilyProperties(
queueFamilyPropertyCount,
{
VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR, // VkStructureType sType
nullptr, // void* pNext
0 // VkVideoCodecOperationFlagsKHR videoCodecOperations
});
std::vector<VkQueueFamilyProperties2> queueFamilyProperties(
queueFamilyPropertyCount,
{
VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2, // VkStructureType sType
nullptr, // void* pNext
{} // VkQueueFamilyProperties queueFamilyProperties
});
for (auto begin = queueFamilyProperties.begin(), i = begin, end = queueFamilyProperties.end(); i != end; ++i)
{
i->pNext = &videoQueueFamilyProperties.data()[std::distance(begin, i)];
}
vki.getPhysicalDeviceQueueFamilyProperties2(device, &queueFamilyPropertyCount, queueFamilyProperties.data());
VkVideoCodecOperationFlagsKHR codecOperationFlags = VK_VIDEO_CODEC_OPERATION_INVALID_BIT_KHR;
for (const VkVideoQueueFamilyProperties2KHR& props : videoQueueFamilyProperties)
{
codecOperationFlags |= props.videoCodecOperations;
}
return codecOperationFlags;
}
void MemoryRequirementsTest::checkSupport (Context& context) const
{
const InstanceInterface& intf = context.getInstanceInterface();
const VkPhysicalDevice physDevice = context.getPhysicalDevice();
if (m_testConfig.useMethod2)
context.requireDeviceFunctionality(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
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))
{
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<BufferUsageBits> usageFlags;
for (const auto& bit : *m_testConfig.fateBits)
{
auto fate = m_testConfig.fateBits->extract(bit);
std::vector<VkBufferUsageFlags> usageHints;
std::vector<BufferUsageBits> usageFlagsTmp;
u::combine(usageFlagsTmp, AvailableBufferUsageBits.select<1>(fate), usageHints);
u::mergeFlags(usageFlags, usageFlagsTmp);
}
std::ostringstream str;
std::array<bool, 7> 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})
&& !context.isDeviceFunctionalitySupported("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)
&& !context.isBufferDeviceAddressSupported())
{
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_ENCODE_SRC_BIT_KHR, VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR,
VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR}))
{
if (!context.isDeviceFunctionalitySupported(VK_KHR_VIDEO_QUEUE_EXTENSION_NAME))
{
if (!msgs[2])
{
if (entryCount++) str << std::endl;
str << INFOUSAGE("VK_EXT_video_queue not supported by device");
msgs[2] = true;
}
notSupported = true;
}
else
{
const VkVideoCodecOperationFlagsKHR videoFlags = readVideoCodecOperationFlagsKHR(intf, physDevice);
if (i->any({VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR, VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR}))
{
if (!context.isDeviceFunctionalitySupported(VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME))
{
if (!msgs[3])
{
if (entryCount++) str << std::endl;
str << INFOUSAGE("VK_EXT_video_encode_h264 not supported by device");
msgs[3] = true;
}
notSupported = true;
}
if (!(videoFlags & VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT))
{
if (!msgs[4])
{
if (entryCount++) str << std::endl;
str << INFOUSAGE("Could not find a queue that supports VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT on device");
msgs[4] = true;
}
notSupported = true;
}
}
if (i->any({VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR, VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR}))
{
if (!context.isDeviceFunctionalitySupported(VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME))
{
if (!msgs[5])
{
if (entryCount++) str << std::endl;
str << INFOUSAGE("VK_EXT_video_decode_h264 not supported by device");
msgs[5] = true;
}
notSupported = true;
}
if (!(videoFlags & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT))
{
if (!msgs[6])
{
if (entryCount++) str << std::endl;
str << INFOUSAGE("Could not find a queue that supports VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT on device");
msgs[6] = true;
}
notSupported = true;
}
}
}
}
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<ExternalMemoryHandleBits> extMemHandleFlags;
if (m_testConfig.incExtMemTypeFlags)
extMemHandleFlags.push_back({AvailableExternalMemoryHandleBits.get(INTERNALTEST_EXTERNAL_MEMORY_HANDLE_TYPE_NO_BITS)});
else
{
std::vector<VkExternalMemoryHandleTypeFlags> handleHints;
std::vector<ExternalMemoryHandleBits> 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<BufferCreateBitsPtr>& failCreateBits,
const std::vector<BufferUsageBitsPtr>& failUsageBits,
const std::vector<ExternalMemoryHandleBitsPtr>& 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<VkExternalMemoryBufferCreateInfo> (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<VkVideoProfilesKHR> (void* pNext, const VkBufferUsageFlags& videoCodecUsage) const
{
const bool encode = (videoCodecUsage & VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR) || (videoCodecUsage & VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR);
const bool decode = (videoCodecUsage & VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR) || (videoCodecUsage & VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR);
static VkVideoEncodeH264ProfileEXT encodeProfile
{
VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT, // VkStructureType sType;
nullptr, // const void* pNext;
STD_VIDEO_H264_PROFILE_IDC_BASELINE // StdVideoH264ProfileIdc stdProfileIdc;
};
static VkVideoDecodeH264ProfileEXT decodeProfile
{
VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT, // VkStructureType sType;
nullptr, // const void* pNext;
STD_VIDEO_H264_PROFILE_IDC_BASELINE, // StdVideoH264ProfileIdc stdProfileIdc;
VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_EXT // VkVideoDecodeH264FieldLayoutFlagsEXT fieldLayout;
};
static const VkVideoProfileKHR videoProfiles[]
{
// encode profile
{
VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR, // VkStructureType sType;
&encodeProfile, // void* pNext;
VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT, // 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;
},
// decode profile
{
VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR, // VkStructureType sType;
&decodeProfile, // void* pNext;
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT, // 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;
if (encode && decode)
{
profiles.profileCount = 2u;
profiles.pProfiles = videoProfiles;
}
else if (encode)
{
profiles.profileCount = 1u;
profiles.pProfiles = &videoProfiles[0];
}
else
{
profiles.profileCount = 1u;
profiles.pProfiles = &videoProfiles[1];
}
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<BufferCreateBitsPtr> failCreateBits;
std::vector<BufferUsageBitsPtr> failUsageBits;
std::vector<ExternalMemoryHandleBitsPtr> 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<VkVideoProfilesKHR>(pNext, infoUsageFlags);
}
if (m_config.incExtMemTypeFlags)
{
pNext = chainVkStructure<VkExternalMemoryBufferCreateInfo>(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<VkBuffer> buffer = createBuffer(vkd, device, &createInfo);
VkMemoryRequirements reqs{};
(this->*method)(reqs, vkd, device, *buffer);
if (reqs.size <= static_cast<VkDeviceSize>(deAlign64(static_cast<deInt64>(createInfo.size), static_cast<deInt64>(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;
}
}
if (m_context.getTestContext().getWatchDog())
qpWatchDog_reset(m_context.getTestContext().getWatchDog());
}
else
{
Move<VkBuffer> 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<SharedPtr<BufferCreateBits>> createBitPtrs;
{
std::vector<VkBufferCreateFlags> hints;
std::vector<BufferCreateBits> 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<SharedPtr<BufferFateBits>> 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<BufferFateFlags> hints;
std::vector<BufferFateBits> 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