blob: 9234111684be19d893f725836b3cfd5e11de74f0 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 The Khronos Group Inc.
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
*
* 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 Vulkan Buffers Tests
*//*--------------------------------------------------------------------*/
#include "vktApiBufferTests.hpp"
#include "deStringUtil.hpp"
#include "gluVarType.hpp"
#include "tcuTestLog.hpp"
#include "vkPrograms.hpp"
#include "vkQueryUtil.hpp"
#include "vkRefUtil.hpp"
#include "vktTestCase.hpp"
namespace vkt
{
using namespace vk;
namespace api
{
namespace
{
static const deUint32 MAX_BUFFER_SIZE_DIVISOR = 16;
struct BufferCaseParameters
{
VkBufferUsageFlags usage;
VkBufferCreateFlags flags;
VkSharingMode sharingMode;
};
class BufferTestInstance : public TestInstance
{
public:
BufferTestInstance (Context& ctx,
BufferCaseParameters testCase)
: TestInstance (ctx)
, m_testCase (testCase)
{}
virtual tcu::TestStatus iterate (void);
tcu::TestStatus bufferCreateAndAllocTest (VkDeviceSize size);
private:
BufferCaseParameters m_testCase;
};
class BuffersTestCase : public TestCase
{
public:
BuffersTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
BufferCaseParameters testCase)
: TestCase(testCtx, name, description)
, m_testCase(testCase)
{}
virtual ~BuffersTestCase (void) {}
virtual TestInstance* createInstance (Context& ctx) const
{
tcu::TestLog& log = m_testCtx.getLog();
log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage;
return new BufferTestInstance(ctx, m_testCase);
}
private:
BufferCaseParameters m_testCase;
};
tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size)
{
const VkPhysicalDevice vkPhysicalDevice = m_context.getPhysicalDevice();
const InstanceInterface& vkInstance = m_context.getInstanceInterface();
const VkDevice vkDevice = m_context.getDevice();
const DeviceInterface& vk = m_context.getDeviceInterface();
Move<VkBuffer> testBuffer;
VkMemoryRequirements memReqs;
Move<VkDeviceMemory> memory;
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice);
// Create buffer
{
VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
m_testCase.flags,
size,
m_testCase.usage,
m_testCase.sharingMode,
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex,
};
try
{
testBuffer = createBuffer(vk, vkDevice, &bufferParams);
}
catch (const vk::Error& error)
{
return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
}
vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
const deUint32 heapTypeIndex = (deUint32)deCtz32(memReqs.memoryTypeBits);
const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex];
const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex];
const VkDeviceSize maxBufferSize = memoryHeap.size / MAX_BUFFER_SIZE_DIVISOR;
// If the requested size is too large, clamp it based on the selected heap size
if (size > maxBufferSize)
{
size = maxBufferSize;
bufferParams.size = size;
try
{
// allocate a new buffer with the adjusted size, the old one will be destroyed by the smart pointer
testBuffer = createBuffer(vk, vkDevice, &bufferParams);
}
catch (const vk::Error& error)
{
return tcu::TestStatus::fail("Buffer creation failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
}
vk.getBufferMemoryRequirements(vkDevice, *testBuffer, &memReqs);
}
if (size > memReqs.size)
{
std::ostringstream errorMsg;
errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!";
return tcu::TestStatus::fail(errorMsg.str());
}
}
// Allocate and bind memory
{
const VkMemoryAllocateInfo memAlloc =
{
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
NULL,
memReqs.size,
(deUint32)deCtz32(memReqs.memoryTypeBits) // deUint32 memoryTypeIndex
};
try
{
memory = allocateMemory(vk, vkDevice, &memAlloc, (const VkAllocationCallbacks*)DE_NULL);
}
catch (const vk::Error& error)
{
return tcu::TestStatus::fail("Alloc memory failed! (requested memory size: " + de::toString(size) + ", Error code: " + de::toString(error.getMessage()) + ")");
}
if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) ||
(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) ||
(m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT))
{
VkQueue queue = 0;
vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue);
const VkSparseMemoryBind sparseMemoryBind =
{
0, // VkDeviceSize resourceOffset;
memReqs.size, // VkDeviceSize size;
*memory, // VkDeviceMemory memory;
0, // VkDeviceSize memoryOffset;
0 // VkSparseMemoryBindFlags flags;
};
const VkSparseBufferMemoryBindInfo sparseBufferMemoryBindInfo =
{
*testBuffer, // VkBuffer buffer;
1u, // deUint32 bindCount;
&sparseMemoryBind // const VkSparseMemoryBind* pBinds;
};
const VkBindSparseInfo bindSparseInfo =
{
VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // deUint32 waitSemaphoreCount;
DE_NULL, // const VkSemaphore* pWaitSemaphores;
1u, // deUint32 bufferBindCount;
&sparseBufferMemoryBindInfo, // const VkSparseBufferMemoryBindInfo* pBufferBinds;
0, // deUint32 imageOpaqueBindCount;
DE_NULL, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds;
0, // deUint32 imageBindCount;
DE_NULL, // const VkSparseImageMemoryBindInfo* pImageBinds;
0, // deUint32 signalSemaphoreCount;
DE_NULL, // const VkSemaphore* pSignalSemaphores;
};
const VkFenceCreateInfo fenceParams =
{
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u // VkFenceCreateFlags flags;
};
const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams));
if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS)
return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")");
VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */));
}
else
{
if (vk.bindBufferMemory(vkDevice, *testBuffer, *memory, 0) != VK_SUCCESS)
return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")");
}
}
return tcu::TestStatus::pass("Buffer test");
}
tcu::TestStatus BufferTestInstance::iterate (void)
{
const VkPhysicalDeviceFeatures& physicalDeviceFeatures = m_context.getDeviceFeatures();
if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding)
TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported");
if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer)
TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported");
if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased)
TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported");
const VkDeviceSize testSizes[] =
{
1,
1181,
15991,
16384
};
tcu::TestStatus testStatus = tcu::TestStatus::pass("Buffer test");
for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); i++)
{
if ((testStatus = bufferCreateAndAllocTest(testSizes[i])).getCode() != QP_TEST_RESULT_PASS)
return testStatus;
}
if (m_testCase.usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT))
{
const VkPhysicalDevice vkPhysicalDevice = m_context.getPhysicalDevice();
const InstanceInterface& vkInstance = m_context.getInstanceInterface();
VkPhysicalDeviceProperties props;
vkInstance.getPhysicalDeviceProperties(vkPhysicalDevice, &props);
testStatus = bufferCreateAndAllocTest((VkDeviceSize) props.limits.maxTexelBufferElements);
}
return testStatus;
}
} // anonymous
tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx)
{
const VkBufferUsageFlags bufferUsageModes[] =
{
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT
};
// \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag.
const VkBufferCreateFlags bufferCreateFlags[] =
{
0,
VK_BUFFER_CREATE_SPARSE_BINDING_BIT,
VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,
VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT,
};
de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests"));
const deUint32 maximumValueOfBufferUsageFlags = (1u << (DE_LENGTH_OF_ARRAY(bufferUsageModes) - 1)) - 1u;
for (deUint32 bufferCreateFlagsNdx = 0u; bufferCreateFlagsNdx < DE_LENGTH_OF_ARRAY(bufferCreateFlags); bufferCreateFlagsNdx++)
for (deUint32 combinedBufferUsageFlags = 1u; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++)
{
const BufferCaseParameters testParams =
{
combinedBufferUsageFlags,
bufferCreateFlags[bufferCreateFlagsNdx],
VK_SHARING_MODE_EXCLUSIVE
};
std::ostringstream testName;
std::ostringstream testDescription;
testName << "createBuffer_" << combinedBufferUsageFlags << "_" << testParams.flags;
testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << testParams.flags;
buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams));
}
return buffersTests.release();
}
} // api
} // vk