blob: 5904a8c069c84873b2e3db4329051c9563738275 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 The Khronos Group Inc.
* Copyright (c) 2016 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 Fill Buffer Tests
*//*--------------------------------------------------------------------*/
#include "vktApiFillBufferTests.hpp"
#include "vktApiBufferAndImageAllocationUtil.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include "vkImageUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkCmdUtil.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorType.hpp"
#include "deSharedPtr.hpp"
namespace vkt
{
namespace api
{
using namespace vk;
namespace
{
struct TestParams
{
enum
{
TEST_DATA_SIZE = 256
};
VkDeviceSize dstSize;
VkDeviceSize dstOffset;
VkDeviceSize size;
deUint32 testData[TEST_DATA_SIZE];
de::SharedPtr<IBufferAllocator> bufferAllocator;
};
class FillBufferTestInstance : public vkt::TestInstance
{
public:
FillBufferTestInstance (Context& context,
TestParams testParams);
virtual tcu::TestStatus iterate (void);
protected:
const TestParams m_params;
Move<VkCommandPool> m_cmdPool;
Move<VkCommandBuffer> m_cmdBuffer;
de::MovePtr<tcu::TextureLevel> m_destinationTextureLevel;
de::MovePtr<tcu::TextureLevel> m_expectedTextureLevel;
VkCommandBufferBeginInfo m_cmdBufferBeginInfo;
Move<VkBuffer> m_destination;
de::MovePtr<Allocation> m_destinationBufferAlloc;
void generateBuffer (tcu::PixelBufferAccess buffer,
int width,
int height,
int depth = 1);
virtual void generateExpectedResult (void);
void uploadBuffer (tcu::ConstPixelBufferAccess
bufferAccess,
const Allocation& bufferAlloc);
virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess
result);
deUint32 calculateSize (tcu::ConstPixelBufferAccess
src) const
{
return src.getWidth() * src.getHeight() * src.getDepth() * tcu::getPixelSize(src.getFormat());
}
};
FillBufferTestInstance::FillBufferTestInstance
(Context& context,
TestParams testParams)
: vkt::TestInstance (context)
, m_params (testParams)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
// Create command pool
m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
// Create command buffer
m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
testParams.bufferAllocator->createTestBuffer(m_params.dstSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, context, memAlloc, m_destination, MemoryRequirement::HostVisible, m_destinationBufferAlloc);
}
tcu::TestStatus FillBufferTestInstance::iterate (void)
{
const int dstLevelWidth = (int)(m_params.dstSize / 4);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
generateExpectedResult();
uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const VkBufferMemoryBarrier dstBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*m_destination, // VkBuffer buffer;
m_params.dstOffset, // VkDeviceSize offset;
m_params.dstSize // VkDeviceSize size;
};
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdFillBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData[0]);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
// Read buffer data
de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset() + m_params.dstOffset, m_params.dstSize);
tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
return checkTestResult(resultLevel->getAccess());
}
void FillBufferTestInstance::generateBuffer
(tcu::PixelBufferAccess buffer,
int width,
int height,
int depth)
{
for (int z = 0; z < depth; z++)
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
buffer.setPixel(tcu::UVec4(x, y, z, 255), x, y, z);
}
}
}
void FillBufferTestInstance::uploadBuffer
(tcu::ConstPixelBufferAccess
bufferAccess,
const Allocation& bufferAlloc)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const deUint32 bufferSize = calculateSize(bufferAccess);
// Write buffer data
deMemcpy(bufferAlloc.getHostPtr(), bufferAccess.getDataPtr(), bufferSize);
flushMappedMemoryRange(vk, vkDevice, bufferAlloc.getMemory(), bufferAlloc.getOffset(), bufferSize);
}
tcu::TestStatus FillBufferTestInstance::checkTestResult
(tcu::ConstPixelBufferAccess
result)
{
const tcu::ConstPixelBufferAccess
expected = m_expectedTextureLevel->getAccess();
const tcu::UVec4 threshold (0, 0, 0, 0);
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparsion", expected, result, threshold, tcu::COMPARE_LOG_RESULT))
{
return tcu::TestStatus::fail("Fill and Update Buffer test");
}
return tcu::TestStatus::pass("Fill and Update Buffer test");
}
void FillBufferTestInstance::generateExpectedResult
(void)
{
const tcu::ConstPixelBufferAccess
dst = m_destinationTextureLevel->getAccess();
m_expectedTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
tcu::copy(m_expectedTextureLevel->getAccess(), dst);
deUint32* currentPtr = (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
deUint32* endPtr = currentPtr + m_params.size / 4;
while (currentPtr < endPtr)
{
*currentPtr = m_params.testData[0];
currentPtr++;
}
}
class FillBufferTestCase : public vkt::TestCase
{
public:
FillBufferTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const TestParams params)
: vkt::TestCase (testCtx, name, description)
, m_params (params)
{}
virtual TestInstance* createInstance (Context& context) const
{
return static_cast<TestInstance*>(new FillBufferTestInstance(context, m_params));
}
private:
const TestParams m_params;
};
// Update Buffer
class UpdateBufferTestInstance : public FillBufferTestInstance
{
public:
UpdateBufferTestInstance (Context& context,
TestParams testParams)
: FillBufferTestInstance (context, testParams)
{}
virtual tcu::TestStatus iterate (void);
protected:
virtual void generateExpectedResult (void);
};
tcu::TestStatus UpdateBufferTestInstance::iterate (void)
{
const int dstLevelWidth = (int)(m_params.dstSize / 4);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1));
generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1);
generateExpectedResult();
uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const VkBufferMemoryBarrier dstBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*m_destination, // VkBuffer buffer;
0u, // VkDeviceSize offset;
m_params.dstOffset // VkDeviceSize size;
};
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdUpdateBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
// Read buffer data
de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1));
invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_params.dstOffset);
tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
return checkTestResult(resultLevel->getAccess());
}
void UpdateBufferTestInstance::generateExpectedResult
(void)
{
const tcu::ConstPixelBufferAccess
dst = m_destinationTextureLevel->getAccess();
m_expectedTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
tcu::copy(m_expectedTextureLevel->getAccess(), dst);
deUint32* currentPtr = (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4;
deMemcpy(currentPtr, m_params.testData, (size_t)m_params.size);
}
class UpdateBufferTestCase : public vkt::TestCase
{
public:
UpdateBufferTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const TestParams params)
: vkt::TestCase (testCtx, name, description)
, m_params (params)
{}
virtual TestInstance* createInstance (Context& context) const
{
return (TestInstance*) new UpdateBufferTestInstance(context, m_params);
}
private:
TestParams m_params;
};
} // anonymous
tcu::TestCaseGroup* createFillAndUpdateBufferTests (tcu::TestContext& testCtx)
{
const de::SharedPtr<IBufferAllocator>
bufferAllocators[] =
{
de::SharedPtr<BufferSuballocation>(new BufferSuballocation()),
de::SharedPtr<BufferDedicatedAllocation>(new BufferDedicatedAllocation())
};
de::MovePtr<tcu::TestCaseGroup> fillAndUpdateBufferTests (new tcu::TestCaseGroup(testCtx, "fill_and_update_buffer", "Fill and Update Buffer Tests"));
tcu::TestCaseGroup* bufferViewAllocationGroupTests[]
=
{
new tcu::TestCaseGroup(testCtx, "suballocation", "BufferView Fill and Update Tests for Suballocated Objects"),
new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "BufferView Fill and Update Tests for Dedicatedly Allocated Objects")
};
for (deUint32 subgroupNdx = 0u; subgroupNdx < DE_LENGTH_OF_ARRAY(bufferViewAllocationGroupTests); ++subgroupNdx)
{
if (bufferViewAllocationGroupTests[subgroupNdx] == DE_NULL)
{
TCU_THROW(InternalError, "Could not create test subgroup.");
}
fillAndUpdateBufferTests->addChild(bufferViewAllocationGroupTests[subgroupNdx]);
}
TestParams params;
params.dstSize = TestParams::TEST_DATA_SIZE;
for (deUint32 buffersAllocationNdx = 0u; buffersAllocationNdx < DE_LENGTH_OF_ARRAY(bufferAllocators); ++buffersAllocationNdx)
{
DE_ASSERT(params.dstSize <= TestParams::TEST_DATA_SIZE);
deUint8* data = (deUint8*) params.testData;
for (deUint32 b = 0u; b < (params.dstSize * sizeof(params.testData[0])); b++)
data[b] = (deUint8) (b % 255);
params.bufferAllocator = bufferAllocators[buffersAllocationNdx];
const deUint32 testCaseGroupNdx = buffersAllocationNdx;
tcu::TestCaseGroup* currentTestsGroup = bufferViewAllocationGroupTests[testCaseGroupNdx];
{
const std::string description ("whole buffer");
const std::string testName ("buffer_whole");
params.dstOffset = 0;
params.size = params.dstSize;
currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
}
{
const std::string description ("first word in buffer");
const std::string testName ("buffer_first_one");
params.dstOffset = 0;
params.size = 4;
currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
}
{
const std::string description ("second word in buffer");
const std::string testName ("buffer_second_one");
params.dstOffset = 4;
params.size = 4;
currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
}
{
const std::string description ("buffer second part");
const std::string testName ("buffer_second_part");
params.dstOffset = params.dstSize / 2;
params.size = params.dstSize / 2;
currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params));
currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params));
}
}
return fillAndUpdateBufferTests.release();
}
} // api
} // vkt