blob: f383a5467d65e8572eb0c7605cc2bec057dfc95e [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015-2016 The Khronos Group Inc.
* Copyright (c) 2015-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 Copies And Blitting Tests
*//*--------------------------------------------------------------------*/
#include "vktApiCopiesAndBlittingTests.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorType.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuTexLookupVerifier.hpp"
#include "vkImageUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkPrograms.hpp"
#include "vkQueryUtil.hpp"
#include "vkRefUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include <set>
namespace vkt
{
namespace api
{
namespace
{
enum MirrorMode
{
MIRROR_MODE_NONE = 0,
MIRROR_MODE_X = (1<<0),
MIRROR_MODE_Y = (1<<1),
MIRROR_MODE_XY = MIRROR_MODE_X | MIRROR_MODE_Y,
MIRROR_MODE_LAST
};
enum AllocationKind
{
ALLOCATION_KIND_SUBALLOCATED,
ALLOCATION_KIND_DEDICATED,
};
template <typename Type>
class BinaryCompare
{
public:
bool operator() (const Type& a, const Type& b) const
{
return deMemCmp(&a, &b, sizeof(Type)) < 0;
}
};
typedef std::set<vk::VkFormat, BinaryCompare<vk::VkFormat> > FormatSet;
FormatSet dedicatedAllocationImageToImageFormatsToTestSet;
FormatSet dedicatedAllocationBlittingFormatsToTestSet;
using namespace vk;
VkImageAspectFlags getAspectFlags (tcu::TextureFormat format)
{
VkImageAspectFlags aspectFlag = 0;
aspectFlag |= (tcu::hasDepthComponent(format.order)? VK_IMAGE_ASPECT_DEPTH_BIT : 0);
aspectFlag |= (tcu::hasStencilComponent(format.order)? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
if (!aspectFlag)
aspectFlag = VK_IMAGE_ASPECT_COLOR_BIT;
return aspectFlag;
}
VkImageAspectFlags getAspectFlags (VkFormat format)
{
if (isCompressedFormat(format))
return VK_IMAGE_ASPECT_COLOR_BIT;
else
return getAspectFlags(mapVkFormat(format));
}
tcu::TextureFormat getSizeCompatibleTcuTextureFormat (VkFormat format)
{
if (isCompressedFormat(format))
return (getBlockSizeInBytes(format) == 8) ? mapVkFormat(VK_FORMAT_R16G16B16A16_UINT) : mapVkFormat(VK_FORMAT_R32G32B32A32_UINT);
else
return mapVkFormat(format);
}
// This is effectively same as vk::isFloatFormat(mapTextureFormat(format))
// except that it supports some formats that are not mappable to VkFormat.
// When we are checking combined depth and stencil formats, each aspect is
// checked separately, and in some cases we construct PBA with a format that
// is not mappable to VkFormat.
bool isFloatFormat (tcu::TextureFormat format)
{
return tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
}
union CopyRegion
{
VkBufferCopy bufferCopy;
VkImageCopy imageCopy;
VkBufferImageCopy bufferImageCopy;
VkImageBlit imageBlit;
VkImageResolve imageResolve;
};
struct ImageParms
{
VkImageType imageType;
VkFormat format;
VkExtent3D extent;
VkImageTiling tiling;
VkImageLayout operationLayout;
};
struct TestParams
{
union Data
{
struct Buffer
{
VkDeviceSize size;
} buffer;
ImageParms image;
} src, dst;
std::vector<CopyRegion> regions;
union
{
VkFilter filter;
VkSampleCountFlagBits samples;
};
AllocationKind allocationKind;
deUint32 mipLevels;
deBool singleCommand;
deUint32 barrierCount;
deBool separateDepthStencilLayouts;
TestParams (void)
{
mipLevels = 1u;
singleCommand = DE_TRUE;
barrierCount = 1u;
separateDepthStencilLayouts = DE_FALSE;
}
};
de::MovePtr<Allocation> allocateBuffer (const InstanceInterface& vki,
const DeviceInterface& vkd,
const VkPhysicalDevice& physDevice,
const VkDevice device,
const VkBuffer& buffer,
const MemoryRequirement requirement,
Allocator& allocator,
AllocationKind allocationKind)
{
switch (allocationKind)
{
case ALLOCATION_KIND_SUBALLOCATED:
{
const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vkd, device, buffer);
return allocator.allocate(memoryRequirements, requirement);
}
case ALLOCATION_KIND_DEDICATED:
{
return allocateDedicated(vki, vkd, physDevice, device, buffer, requirement);
}
default:
{
TCU_THROW(InternalError, "Invalid allocation kind");
}
}
}
de::MovePtr<Allocation> allocateImage (const InstanceInterface& vki,
const DeviceInterface& vkd,
const VkPhysicalDevice& physDevice,
const VkDevice device,
const VkImage& image,
const MemoryRequirement requirement,
Allocator& allocator,
AllocationKind allocationKind)
{
switch (allocationKind)
{
case ALLOCATION_KIND_SUBALLOCATED:
{
const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vkd, device, image);
return allocator.allocate(memoryRequirements, requirement);
}
case ALLOCATION_KIND_DEDICATED:
{
return allocateDedicated(vki, vkd, physDevice, device, image, requirement);
}
default:
{
TCU_THROW(InternalError, "Invalid allocation kind");
}
}
}
inline deUint32 getArraySize(const ImageParms& parms)
{
return (parms.imageType != VK_IMAGE_TYPE_3D) ? parms.extent.depth : 1u;
}
inline VkImageCreateFlags getCreateFlags(const ImageParms& parms)
{
return parms.imageType == VK_IMAGE_TYPE_2D && parms.extent.depth % 6 == 0 ?
VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0;
}
inline VkExtent3D getExtent3D(const ImageParms& parms, deUint32 mipLevel = 0u)
{
const bool isCompressed = isCompressedFormat(parms.format);
const deUint32 blockWidth = (isCompressed) ? getBlockWidth(parms.format) : 1u;
const deUint32 blockHeight = (isCompressed) ? getBlockHeight(parms.format) : 1u;
if (isCompressed && mipLevel != 0u)
DE_FATAL("Not implemented");
const VkExtent3D extent =
{
(parms.extent.width >> mipLevel) * blockWidth,
(parms.imageType != VK_IMAGE_TYPE_1D) ? ((parms.extent.height >> mipLevel) * blockHeight) : 1u,
(parms.imageType == VK_IMAGE_TYPE_3D) ? parms.extent.depth : 1u,
};
return extent;
}
const tcu::TextureFormat mapCombinedToDepthTransferFormat (const tcu::TextureFormat& combinedFormat)
{
tcu::TextureFormat format;
switch (combinedFormat.type)
{
case tcu::TextureFormat::UNORM_INT16:
case tcu::TextureFormat::UNSIGNED_INT_16_8_8:
format = tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
break;
case tcu::TextureFormat::UNSIGNED_INT_24_8_REV:
format = tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNSIGNED_INT_24_8_REV);
break;
case tcu::TextureFormat::FLOAT_UNSIGNED_INT_24_8_REV:
case tcu::TextureFormat::FLOAT:
format = tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
break;
default:
DE_ASSERT(false);
break;
}
return format;
}
class CopiesAndBlittingTestInstance : public vkt::TestInstance
{
public:
CopiesAndBlittingTestInstance (Context& context,
TestParams testParams);
virtual tcu::TestStatus iterate (void) = 0;
enum FillMode
{
FILL_MODE_GRADIENT = 0,
FILL_MODE_WHITE,
FILL_MODE_RED,
FILL_MODE_MULTISAMPLE,
FILL_MODE_LAST
};
protected:
const TestParams m_params;
Move<VkCommandPool> m_cmdPool;
Move<VkCommandBuffer> m_cmdBuffer;
Move<VkFence> m_fence;
de::MovePtr<tcu::TextureLevel> m_sourceTextureLevel;
de::MovePtr<tcu::TextureLevel> m_destinationTextureLevel;
de::MovePtr<tcu::TextureLevel> m_expectedTextureLevel[16];
VkCommandBufferBeginInfo m_cmdBufferBeginInfo;
void generateBuffer (tcu::PixelBufferAccess buffer, int width, int height, int depth = 1, FillMode = FILL_MODE_GRADIENT);
virtual void generateExpectedResult (void);
void uploadBuffer (tcu::ConstPixelBufferAccess bufferAccess, const Allocation& bufferAlloc);
void uploadImage (const tcu::ConstPixelBufferAccess& src, VkImage dst, const ImageParms& parms, const deUint32 mipLevels = 1u);
virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess result);
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel = 0u) = 0;
deUint32 calculateSize (tcu::ConstPixelBufferAccess src) const
{
return src.getWidth() * src.getHeight() * src.getDepth() * tcu::getPixelSize(src.getFormat());
}
de::MovePtr<tcu::TextureLevel> readImage (vk::VkImage image,
const ImageParms& imageParms,
const deUint32 mipLevel = 0u);
private:
void uploadImageAspect (const tcu::ConstPixelBufferAccess& src,
const VkImage& dst,
const ImageParms& parms,
const deUint32 mipLevels = 1u);
void readImageAspect (vk::VkImage src,
const tcu::PixelBufferAccess& dst,
const ImageParms& parms,
const deUint32 mipLevel = 0u);
};
CopiesAndBlittingTestInstance::CopiesAndBlittingTestInstance (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();
// Create command pool
m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
// Create command buffer
m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
// Create fence
m_fence = createFence(vk, vkDevice);
}
void CopiesAndBlittingTestInstance::generateBuffer (tcu::PixelBufferAccess buffer, int width, int height, int depth, FillMode mode)
{
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(buffer.getFormat().type);
tcu::Vec4 maxValue (1.0f);
if (buffer.getFormat().order == tcu::TextureFormat::S)
{
// Stencil-only is stored in the first component. Stencil is always 8 bits.
maxValue.x() = 1 << 8;
}
else if (buffer.getFormat().order == tcu::TextureFormat::DS)
{
// In a combined format, fillWithComponentGradients expects stencil in the fourth component.
maxValue.w() = 1 << 8;
}
else if (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER)
{
// The tcu::Vectors we use as pixels are 32-bit, so clamp to that.
const tcu::IVec4 bits = tcu::min(tcu::getTextureFormatBitDepth(buffer.getFormat()), tcu::IVec4(32));
const int signBit = (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ? 1 : 0);
for (int i = 0; i < 4; ++i)
{
if (bits[i] != 0)
maxValue[i] = static_cast<float>((deUint64(1) << (bits[i] - signBit)) - 1);
}
}
if (mode == FILL_MODE_GRADIENT)
{
tcu::fillWithComponentGradients(buffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), maxValue);
return;
}
const tcu::Vec4 redColor (maxValue.x(), 0.0, 0.0, maxValue.w());
const tcu::Vec4 greenColor (0.0, maxValue.y(), 0.0, maxValue.w());
const tcu::Vec4 blueColor (0.0, 0.0, maxValue.z(), maxValue.w());
const tcu::Vec4 whiteColor (maxValue.x(), maxValue.y(), maxValue.z(), maxValue.w());
for (int z = 0; z < depth; ++z)
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
switch (mode)
{
case FILL_MODE_WHITE:
if (tcu::isCombinedDepthStencilType(buffer.getFormat().type))
{
buffer.setPixDepth(1.0f, x, y, z);
if (tcu::hasStencilComponent(buffer.getFormat().order))
buffer.setPixStencil(255, x, y, z);
}
else
buffer.setPixel(whiteColor, x, y, z);
break;
case FILL_MODE_RED:
if (tcu::isCombinedDepthStencilType(buffer.getFormat().type))
{
buffer.setPixDepth(redColor[0], x, y, z);
if (tcu::hasStencilComponent(buffer.getFormat().order))
buffer.setPixStencil((int)redColor[3], x, y, z);
}
else
buffer.setPixel(redColor, x, y, z);
break;
case FILL_MODE_MULTISAMPLE:
{
float xScaled = static_cast<float>(x) / static_cast<float>(width);
float yScaled = static_cast<float>(y) / static_cast<float>(height);
buffer.setPixel((xScaled == yScaled) ? tcu::Vec4(0.0, 0.5, 0.5, 1.0) : ((xScaled > yScaled) ? greenColor : blueColor), x, y, z);
break;
}
default:
break;
}
}
}
void CopiesAndBlittingTestInstance::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);
flushAlloc(vk, vkDevice, bufferAlloc);
}
void CopiesAndBlittingTestInstance::uploadImageAspect (const tcu::ConstPixelBufferAccess& imageAccess, const VkImage& image, const ImageParms& parms, const deUint32 mipLevels)
{
const InstanceInterface& vki = m_context.getInstanceInterface();
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = m_context.getPhysicalDevice();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = m_context.getDefaultAllocator();
Move<VkBuffer> buffer;
const deUint32 bufferSize = calculateSize(imageAccess);
de::MovePtr<Allocation> bufferAlloc;
const deUint32 arraySize = getArraySize(parms);
const VkExtent3D imageExtent = getExtent3D(parms);
std::vector <VkBufferImageCopy> copyRegions;
// Create source buffer
{
const VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
bufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
buffer = createBuffer(vk, vkDevice, &bufferParams);
bufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *buffer, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
}
// Barriers for copying buffer to image
const VkBufferMemoryBarrier preBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*buffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
bufferSize // VkDeviceSize size;
};
const VkImageAspectFlags formatAspect = (m_params.separateDepthStencilLayouts) ? getAspectFlags(imageAccess.getFormat()) : getAspectFlags(parms.format);
const bool skipPreImageBarrier = (m_params.separateDepthStencilLayouts) ? false : ((formatAspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) &&
getAspectFlags(imageAccess.getFormat()) == VK_IMAGE_ASPECT_STENCIL_BIT));
const VkImageMemoryBarrier preImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
image, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
formatAspect, // VkImageAspectFlags aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arraySize, // deUint32 arraySize;
}
};
const VkImageMemoryBarrier postImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
image, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
formatAspect, // VkImageAspectFlags aspect;
0u, // deUint32 baseMipLevel;
mipLevels, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
arraySize, // deUint32 arraySize;
}
};
for (deUint32 mipLevelNdx = 0; mipLevelNdx < mipLevels; mipLevelNdx++)
{
const VkExtent3D copyExtent =
{
imageExtent.width >> mipLevelNdx,
imageExtent.height >> mipLevelNdx,
imageExtent.depth
};
const VkBufferImageCopy copyRegion =
{
0u, // VkDeviceSize bufferOffset;
copyExtent.width, // deUint32 bufferRowLength;
copyExtent.height, // deUint32 bufferImageHeight;
{
getAspectFlags(imageAccess.getFormat()), // VkImageAspectFlags aspect;
mipLevelNdx, // deUint32 mipLevel;
0u, // deUint32 baseArrayLayer;
arraySize, // deUint32 layerCount;
}, // VkImageSubresourceLayers imageSubresource;
{ 0, 0, 0 }, // VkOffset3D imageOffset;
copyExtent // VkExtent3D imageExtent;
};
copyRegions.push_back(copyRegion);
}
// Write buffer data
deMemcpy(bufferAlloc->getHostPtr(), imageAccess.getDataPtr(), bufferSize);
flushAlloc(vk, vkDevice, *bufferAlloc);
// Copy buffer to image
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL,
1, &preBufferBarrier, (skipPreImageBarrier ? 0 : 1), (skipPreImageBarrier ? DE_NULL : &preImageBarrier));
vk.cmdCopyBufferToImage(*m_cmdBuffer, *buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)copyRegions.size(), &copyRegions[0]);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, *m_cmdBuffer);
}
void CopiesAndBlittingTestInstance::uploadImage (const tcu::ConstPixelBufferAccess& src, VkImage dst, const ImageParms& parms, const deUint32 mipLevels)
{
if (tcu::isCombinedDepthStencilType(src.getFormat().type))
{
if (tcu::hasDepthComponent(src.getFormat().order))
{
tcu::TextureLevel depthTexture (mapCombinedToDepthTransferFormat(src.getFormat()), src.getWidth(), src.getHeight(), src.getDepth());
tcu::copy(depthTexture.getAccess(), tcu::getEffectiveDepthStencilAccess(src, tcu::Sampler::MODE_DEPTH));
uploadImageAspect(depthTexture.getAccess(), dst, parms);
}
if (tcu::hasStencilComponent(src.getFormat().order))
{
tcu::TextureLevel stencilTexture (tcu::getEffectiveDepthStencilTextureFormat(src.getFormat(), tcu::Sampler::MODE_STENCIL), src.getWidth(), src.getHeight(), src.getDepth());
tcu::copy(stencilTexture.getAccess(), tcu::getEffectiveDepthStencilAccess(src, tcu::Sampler::MODE_STENCIL));
uploadImageAspect(stencilTexture.getAccess(), dst, parms);
}
}
else
uploadImageAspect(src, dst, parms, mipLevels);
}
tcu::TestStatus CopiesAndBlittingTestInstance::checkTestResult (tcu::ConstPixelBufferAccess result)
{
const tcu::ConstPixelBufferAccess expected = m_expectedTextureLevel[0]->getAccess();
if (isFloatFormat(result.getFormat()))
{
const tcu::Vec4 threshold (0.0f);
if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expected, result, threshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
else
{
const tcu::UVec4 threshold (0u);
if (tcu::hasDepthComponent(result.getFormat().order) || tcu::hasStencilComponent(result.getFormat().order))
{
if (!tcu::dsThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expected, result, 0.1f, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
else
{
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expected, result, threshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
}
return tcu::TestStatus::pass("CopiesAndBlitting test");
}
void CopiesAndBlittingTestInstance::generateExpectedResult (void)
{
const tcu::ConstPixelBufferAccess src = m_sourceTextureLevel->getAccess();
const tcu::ConstPixelBufferAccess dst = m_destinationTextureLevel->getAccess();
m_expectedTextureLevel[0] = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth()));
tcu::copy(m_expectedTextureLevel[0]->getAccess(), dst);
for (deUint32 i = 0; i < m_params.regions.size(); i++)
copyRegionToTextureLevel(src, m_expectedTextureLevel[0]->getAccess(), m_params.regions[i]);
}
class CopiesAndBlittingTestCase : public vkt::TestCase
{
public:
CopiesAndBlittingTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description)
: vkt::TestCase (testCtx, name, description)
{}
virtual TestInstance* createInstance (Context& context) const = 0;
};
void CopiesAndBlittingTestInstance::readImageAspect (vk::VkImage image,
const tcu::PixelBufferAccess& dst,
const ImageParms& imageParms,
const deUint32 mipLevel)
{
const InstanceInterface& vki = m_context.getInstanceInterface();
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkPhysicalDevice physDevice = m_context.getPhysicalDevice();
const VkDevice device = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
Allocator& allocator = m_context.getDefaultAllocator();
Move<VkBuffer> buffer;
de::MovePtr<Allocation> bufferAlloc;
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
const VkDeviceSize pixelDataSize = calculateSize(dst);
const VkExtent3D imageExtent = getExtent3D(imageParms, mipLevel);
// Create destination buffer
{
const VkBufferCreateInfo bufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
pixelDataSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
buffer = createBuffer(vk, device, &bufferParams);
bufferAlloc = allocateBuffer(vki, vk, physDevice, device, *buffer, MemoryRequirement::HostVisible, allocator, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(device, *buffer, bufferAlloc->getMemory(), bufferAlloc->getOffset()));
deMemset(bufferAlloc->getHostPtr(), 0, static_cast<size_t>(pixelDataSize));
flushAlloc(vk, device, *bufferAlloc);
}
// Barriers for copying image to buffer
const VkImageAspectFlags formatAspect = getAspectFlags(imageParms.format);
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
imageParms.operationLayout, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
image, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
formatAspect, // VkImageAspectFlags aspectMask;
mipLevel, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
getArraySize(imageParms)// deUint32 arraySize;
}
};
const VkBufferMemoryBarrier bufferBarrier =
{
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;
*buffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
pixelDataSize // VkDeviceSize size;
};
const VkImageMemoryBarrier postImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout oldLayout;
imageParms.operationLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
image, // VkImage image;
{
formatAspect, // VkImageAspectFlags aspectMask;
mipLevel, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
getArraySize(imageParms) // deUint32 arraySize;
} // VkImageSubresourceRange subresourceRange;
};
// Copy image to buffer
const VkImageAspectFlags aspect = getAspectFlags(dst.getFormat());
const VkBufferImageCopy copyRegion =
{
0u, // VkDeviceSize bufferOffset;
imageExtent.width, // deUint32 bufferRowLength;
imageExtent.height, // deUint32 bufferImageHeight;
{
aspect, // VkImageAspectFlags aspect;
mipLevel, // deUint32 mipLevel;
0u, // deUint32 baseArrayLayer;
getArraySize(imageParms), // deUint32 layerCount;
}, // VkImageSubresourceLayers imageSubresource;
{ 0, 0, 0 }, // VkOffset3D imageOffset;
imageExtent // VkExtent3D imageExtent;
};
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
vk.cmdCopyImageToBuffer(*m_cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *buffer, 1u, &copyRegion);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT|VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &bufferBarrier, 1, &postImageBarrier);
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
// Read buffer data
invalidateAlloc(vk, device, *bufferAlloc);
tcu::copy(dst, tcu::ConstPixelBufferAccess(dst.getFormat(), dst.getSize(), bufferAlloc->getHostPtr()));
}
de::MovePtr<tcu::TextureLevel> CopiesAndBlittingTestInstance::readImage (vk::VkImage image,
const ImageParms& parms,
const deUint32 mipLevel)
{
const tcu::TextureFormat imageFormat = getSizeCompatibleTcuTextureFormat(parms.format);
de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(imageFormat, parms.extent.width >> mipLevel, parms.extent.height >> mipLevel, parms.extent.depth));
if (tcu::isCombinedDepthStencilType(imageFormat.type))
{
if (tcu::hasDepthComponent(imageFormat.order))
{
tcu::TextureLevel depthTexture (mapCombinedToDepthTransferFormat(imageFormat), parms.extent.width, parms.extent.height, parms.extent.depth);
readImageAspect(image, depthTexture.getAccess(), parms);
tcu::copy(tcu::getEffectiveDepthStencilAccess(resultLevel->getAccess(), tcu::Sampler::MODE_DEPTH), depthTexture.getAccess());
}
if (tcu::hasStencilComponent(imageFormat.order))
{
tcu::TextureLevel stencilTexture (tcu::getEffectiveDepthStencilTextureFormat(imageFormat, tcu::Sampler::MODE_STENCIL), parms.extent.width, parms.extent.height, parms.extent.depth);
readImageAspect(image, stencilTexture.getAccess(), parms);
tcu::copy(tcu::getEffectiveDepthStencilAccess(resultLevel->getAccess(), tcu::Sampler::MODE_STENCIL), stencilTexture.getAccess());
}
}
else
readImageAspect(image, resultLevel->getAccess(), parms, mipLevel);
return resultLevel;
}
// Copy from image to image.
class CopyImageToImage : public CopiesAndBlittingTestInstance
{
public:
CopyImageToImage (Context& context,
TestParams params);
virtual tcu::TestStatus iterate (void);
protected:
virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess result = tcu::ConstPixelBufferAccess());
private:
Move<VkImage> m_source;
de::MovePtr<Allocation> m_sourceImageAlloc;
Move<VkImage> m_destination;
de::MovePtr<Allocation> m_destinationImageAlloc;
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel = 0u);
};
CopyImageToImage::CopyImageToImage (Context& context, TestParams params)
: CopiesAndBlittingTestInstance(context, params)
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
// Create source image
{
const VkImageCreateInfo sourceImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.src.image), // VkImageCreateFlags flags;
m_params.src.image.imageType, // VkImageType imageType;
m_params.src.image.format, // VkFormat format;
getExtent3D(m_params.src.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.src.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_source = createImage(vk, vkDevice, &sourceImageParams);
m_sourceImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_source, m_sourceImageAlloc->getMemory(), m_sourceImageAlloc->getOffset()));
}
// Create destination image
{
const VkImageCreateInfo destinationImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.dst.image), // VkImageCreateFlags flags;
m_params.dst.image.imageType, // VkImageType imageType;
m_params.dst.image.format, // VkFormat format;
getExtent3D(m_params.dst.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.dst.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_destination = createImage(vk, vkDevice, &destinationImageParams);
m_destinationImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_destination, m_destinationImageAlloc->getMemory(), m_destinationImageAlloc->getOffset()));
}
}
tcu::TestStatus CopyImageToImage::iterate (void)
{
const bool srcCompressed = isCompressedFormat(m_params.src.image.format);
const bool dstCompressed = isCompressedFormat(m_params.dst.image.format);
const tcu::TextureFormat srcTcuFormat = getSizeCompatibleTcuTextureFormat(m_params.src.image.format);
const tcu::TextureFormat dstTcuFormat = getSizeCompatibleTcuTextureFormat(m_params.dst.image.format);
m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(srcTcuFormat,
(int)m_params.src.image.extent.width,
(int)m_params.src.image.extent.height,
(int)m_params.src.image.extent.depth));
generateBuffer(m_sourceTextureLevel->getAccess(), m_params.src.image.extent.width, m_params.src.image.extent.height, m_params.src.image.extent.depth, FILL_MODE_GRADIENT);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dstTcuFormat,
(int)m_params.dst.image.extent.width,
(int)m_params.dst.image.extent.height,
(int)m_params.dst.image.extent.depth));
generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth, FILL_MODE_GRADIENT);
generateExpectedResult();
uploadImage(m_sourceTextureLevel->getAccess(), m_source.get(), m_params.src.image);
uploadImage(m_destinationTextureLevel->getAccess(), m_destination.get(), m_params.dst.image);
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
std::vector<VkImageCopy> imageCopies;
for (deUint32 i = 0; i < m_params.regions.size(); i++)
{
VkImageCopy imageCopy = m_params.regions[i].imageCopy;
// When copying between compressed and uncompressed formats the extent
// members represent the texel dimensions of the source image.
if (srcCompressed)
{
const deUint32 blockWidth = getBlockWidth(m_params.src.image.format);
const deUint32 blockHeight = getBlockHeight(m_params.src.image.format);
imageCopy.srcOffset.x *= blockWidth;
imageCopy.srcOffset.y *= blockHeight;
imageCopy.extent.width *= blockWidth;
imageCopy.extent.height *= blockHeight;
}
if (dstCompressed)
{
const deUint32 blockWidth = getBlockWidth(m_params.dst.image.format);
const deUint32 blockHeight = getBlockHeight(m_params.dst.image.format);
imageCopy.dstOffset.x *= blockWidth;
imageCopy.dstOffset.y *= blockHeight;
}
imageCopies.push_back(imageCopy);
}
const VkImageMemoryBarrier imageBarriers[] =
{
// source image
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
m_params.src.image.operationLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
m_source.get(), // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(srcTcuFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
getArraySize(m_params.src.image)// deUint32 arraySize;
}
},
// destination image
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
m_params.dst.image.operationLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
m_destination.get(), // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(dstTcuFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
getArraySize(m_params.dst.image)// deUint32 arraySize;
}
},
};
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers);
vk.cmdCopyImage(*m_cmdBuffer, m_source.get(), m_params.src.image.operationLayout, m_destination.get(), m_params.dst.image.operationLayout, (deUint32)imageCopies.size(), imageCopies.data());
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait (vk, vkDevice, queue, *m_cmdBuffer);
de::MovePtr<tcu::TextureLevel> resultTextureLevel = readImage(*m_destination, m_params.dst.image);
return checkTestResult(resultTextureLevel->getAccess());
}
tcu::TestStatus CopyImageToImage::checkTestResult (tcu::ConstPixelBufferAccess result)
{
const tcu::Vec4 fThreshold (0.0f);
const tcu::UVec4 uThreshold (0u);
if (tcu::isCombinedDepthStencilType(result.getFormat().type))
{
if (tcu::hasDepthComponent(result.getFormat().order))
{
const tcu::Sampler::DepthStencilMode mode = tcu::Sampler::MODE_DEPTH;
const tcu::ConstPixelBufferAccess depthResult = tcu::getEffectiveDepthStencilAccess(result, mode);
const tcu::ConstPixelBufferAccess expectedResult = tcu::getEffectiveDepthStencilAccess(m_expectedTextureLevel[0]->getAccess(), mode);
if (isFloatFormat(result.getFormat()))
{
if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expectedResult, depthResult, fThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
else
{
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expectedResult, depthResult, uThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
}
if (tcu::hasStencilComponent(result.getFormat().order))
{
const tcu::Sampler::DepthStencilMode mode = tcu::Sampler::MODE_STENCIL;
const tcu::ConstPixelBufferAccess stencilResult = tcu::getEffectiveDepthStencilAccess(result, mode);
const tcu::ConstPixelBufferAccess expectedResult = tcu::getEffectiveDepthStencilAccess(m_expectedTextureLevel[0]->getAccess(), mode);
if (isFloatFormat(result.getFormat()))
{
if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expectedResult, stencilResult, fThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
else
{
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expectedResult, stencilResult, uThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
}
}
else
{
if (isFloatFormat(result.getFormat()))
{
if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", m_expectedTextureLevel[0]->getAccess(), result, fThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
else if (isSnormFormat(mapTextureFormat(result.getFormat())))
{
// There may be an ambiguity between two possible binary representations of 1.0.
// Get rid of that by expanding the data to floats and re-normalizing again.
tcu::TextureLevel resultSnorm (result.getFormat(), result.getWidth(), result.getHeight(), result.getDepth());
{
tcu::TextureLevel resultFloat (tcu::TextureFormat(resultSnorm.getFormat().order, tcu::TextureFormat::FLOAT), resultSnorm.getWidth(), resultSnorm.getHeight(), resultSnorm.getDepth());
tcu::copy(resultFloat.getAccess(), result);
tcu::copy(resultSnorm, resultFloat.getAccess());
}
tcu::TextureLevel expectedSnorm (m_expectedTextureLevel[0]->getFormat(), m_expectedTextureLevel[0]->getWidth(), m_expectedTextureLevel[0]->getHeight(), m_expectedTextureLevel[0]->getDepth());
{
tcu::TextureLevel expectedFloat (tcu::TextureFormat(expectedSnorm.getFormat().order, tcu::TextureFormat::FLOAT), expectedSnorm.getWidth(), expectedSnorm.getHeight(), expectedSnorm.getDepth());
tcu::copy(expectedFloat.getAccess(), m_expectedTextureLevel[0]->getAccess());
tcu::copy(expectedSnorm, expectedFloat.getAccess());
}
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", expectedSnorm.getAccess(), resultSnorm.getAccess(), uThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
else
{
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", m_expectedTextureLevel[0]->getAccess(), result, uThreshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("CopiesAndBlitting test");
}
}
return tcu::TestStatus::pass("CopiesAndBlitting test");
}
void CopyImageToImage::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel)
{
DE_UNREF(mipLevel);
VkOffset3D srcOffset = region.imageCopy.srcOffset;
VkOffset3D dstOffset = region.imageCopy.dstOffset;
VkExtent3D extent = region.imageCopy.extent;
if (m_params.src.image.imageType == VK_IMAGE_TYPE_3D && m_params.dst.image.imageType == VK_IMAGE_TYPE_2D)
{
dstOffset.z = srcOffset.z;
extent.depth = std::max(region.imageCopy.extent.depth, region.imageCopy.dstSubresource.layerCount);
}
if (m_params.src.image.imageType == VK_IMAGE_TYPE_2D && m_params.dst.image.imageType == VK_IMAGE_TYPE_3D)
{
srcOffset.z = dstOffset.z;
extent.depth = std::max(region.imageCopy.extent.depth, region.imageCopy.srcSubresource.layerCount);
}
if (tcu::isCombinedDepthStencilType(src.getFormat().type))
{
DE_ASSERT(src.getFormat() == dst.getFormat());
// Copy depth.
if (tcu::hasDepthComponent(src.getFormat().order))
{
const tcu::ConstPixelBufferAccess srcSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(src, srcOffset.x, srcOffset.y, srcOffset.z, extent.width, extent.height, extent.depth), tcu::Sampler::MODE_DEPTH);
const tcu::PixelBufferAccess dstSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(dst, dstOffset.x, dstOffset.y, dstOffset.z, extent.width, extent.height, extent.depth), tcu::Sampler::MODE_DEPTH);
tcu::copy(dstSubRegion, srcSubRegion);
}
// Copy stencil.
if (tcu::hasStencilComponent(src.getFormat().order))
{
const tcu::ConstPixelBufferAccess srcSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(src, srcOffset.x, srcOffset.y, srcOffset.z, extent.width, extent.height, extent.depth), tcu::Sampler::MODE_STENCIL);
const tcu::PixelBufferAccess dstSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(dst, dstOffset.x, dstOffset.y, dstOffset.z, extent.width, extent.height, extent.depth), tcu::Sampler::MODE_STENCIL);
tcu::copy(dstSubRegion, srcSubRegion);
}
}
else
{
const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, srcOffset.x, srcOffset.y, srcOffset.z, extent.width, extent.height, extent.depth);
// CopyImage acts like a memcpy. Replace the destination format with the srcformat to use a memcpy.
const tcu::PixelBufferAccess dstWithSrcFormat (srcSubRegion.getFormat(), dst.getSize(), dst.getDataPtr());
const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dstWithSrcFormat, dstOffset.x, dstOffset.y, dstOffset.z, extent.width, extent.height, extent.depth);
tcu::copy(dstSubRegion, srcSubRegion);
}
}
class CopyImageToImageTestCase : public vkt::TestCase
{
public:
CopyImageToImageTestCase (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 new CopyImageToImage(context, m_params);
}
virtual void checkSupport (Context& context) const
{
if (m_params.allocationKind == ALLOCATION_KIND_DEDICATED)
{
if (!context.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation"))
TCU_THROW(NotSupportedError, "VK_KHR_dedicated_allocation is not supported");
}
if (m_params.separateDepthStencilLayouts)
if (!context.isDeviceFunctionalitySupported("VK_KHR_separate_depth_stencil_layouts"))
TCU_THROW(NotSupportedError, "VK_KHR_separate_depth_stencil_layouts is not supported");
if ((m_params.dst.image.imageType == VK_IMAGE_TYPE_3D && m_params.src.image.imageType == VK_IMAGE_TYPE_2D) ||
(m_params.dst.image.imageType == VK_IMAGE_TYPE_2D && m_params.src.image.imageType == VK_IMAGE_TYPE_3D))
{
if (!context.isDeviceFunctionalitySupported("VK_KHR_maintenance1"))
TCU_THROW(NotSupportedError, "Extension VK_KHR_maintenance1 not supported");
}
const VkPhysicalDeviceLimits limits = context.getDeviceProperties().limits;
VkImageFormatProperties properties;
if ((context.getInstanceInterface().getPhysicalDeviceImageFormatProperties (context.getPhysicalDevice(),
m_params.src.image.format,
m_params.src.image.imageType,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
0,
&properties) == VK_ERROR_FORMAT_NOT_SUPPORTED) ||
(context.getInstanceInterface().getPhysicalDeviceImageFormatProperties (context.getPhysicalDevice(),
m_params.dst.image.format,
m_params.dst.image.imageType,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT,
0,
&properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
{
TCU_THROW(NotSupportedError, "Format not supported");
}
// Check maxImageDimension2D
{
if (m_params.src.image.imageType == VK_IMAGE_TYPE_2D && (m_params.src.image.extent.width > limits.maxImageDimension2D
|| m_params.src.image.extent.height > limits.maxImageDimension2D))
{
TCU_THROW(NotSupportedError, "Requested 2D src image dimensions not supported");
}
if (m_params.dst.image.imageType == VK_IMAGE_TYPE_2D && (m_params.dst.image.extent.width > limits.maxImageDimension2D
|| m_params.dst.image.extent.height > limits.maxImageDimension2D))
{
TCU_THROW(NotSupportedError, "Requested 2D dst image dimensions not supported");
}
}
// Check maxImageDimension3D
{
if (m_params.src.image.imageType == VK_IMAGE_TYPE_3D && (m_params.src.image.extent.width > limits.maxImageDimension3D
|| m_params.src.image.extent.height > limits.maxImageDimension3D
|| m_params.src.image.extent.depth > limits.maxImageDimension3D))
{
TCU_THROW(NotSupportedError, "Requested 3D src image dimensions not supported");
}
if (m_params.dst.image.imageType == VK_IMAGE_TYPE_3D && (m_params.dst.image.extent.width > limits.maxImageDimension3D
|| m_params.dst.image.extent.height > limits.maxImageDimension3D
|| m_params.src.image.extent.depth > limits.maxImageDimension3D))
{
TCU_THROW(NotSupportedError, "Requested 3D dst image dimensions not supported");
}
}
}
private:
TestParams m_params;
};
// Copy from buffer to buffer.
class CopyBufferToBuffer : public CopiesAndBlittingTestInstance
{
public:
CopyBufferToBuffer (Context& context, TestParams params);
virtual tcu::TestStatus iterate (void);
private:
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess, tcu::PixelBufferAccess, CopyRegion, deUint32 mipLevel = 0u);
Move<VkBuffer> m_source;
de::MovePtr<Allocation> m_sourceBufferAlloc;
Move<VkBuffer> m_destination;
de::MovePtr<Allocation> m_destinationBufferAlloc;
};
CopyBufferToBuffer::CopyBufferToBuffer (Context& context, TestParams params)
: CopiesAndBlittingTestInstance (context, params)
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
// Create source buffer
{
const VkBufferCreateInfo sourceBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_params.src.buffer.size, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
m_source = createBuffer(vk, vkDevice, &sourceBufferParams);
m_sourceBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_source, m_sourceBufferAlloc->getMemory(), m_sourceBufferAlloc->getOffset()));
}
// Create destination buffer
{
const VkBufferCreateInfo destinationBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_params.dst.buffer.size, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
m_destination = createBuffer(vk, vkDevice, &destinationBufferParams);
m_destinationBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_destination, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset()));
}
}
tcu::TestStatus CopyBufferToBuffer::iterate (void)
{
const int srcLevelWidth = (int)(m_params.src.buffer.size/4); // Here the format is VK_FORMAT_R32_UINT, we need to divide the buffer size by 4
m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R32_UINT), srcLevelWidth, 1));
generateBuffer(m_sourceTextureLevel->getAccess(), srcLevelWidth, 1, 1, FILL_MODE_RED);
const int dstLevelWidth = (int)(m_params.dst.buffer.size/4);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R32_UINT), dstLevelWidth, 1));
generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1, FILL_MODE_WHITE);
generateExpectedResult();
uploadBuffer(m_sourceTextureLevel->getAccess(), *m_sourceBufferAlloc);
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 srcBufferBarrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*m_source, // VkBuffer buffer;
0u, // VkDeviceSize offset;
m_params.src.buffer.size // VkDeviceSize size;
};
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.dst.buffer.size // VkDeviceSize size;
};
std::vector<VkBufferCopy> bufferCopies;
for (deUint32 i = 0; i < m_params.regions.size(); i++)
bufferCopies.push_back(m_params.regions[i].bufferCopy);
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &srcBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
vk.cmdCopyBuffer(*m_cmdBuffer, m_source.get(), m_destination.get(), (deUint32)m_params.regions.size(), &bufferCopies[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);
// Read buffer data
de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R32_UINT), dstLevelWidth, 1));
invalidateAlloc(vk, vkDevice, *m_destinationBufferAlloc);
tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
return checkTestResult(resultLevel->getAccess());
}
void CopyBufferToBuffer::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel)
{
DE_UNREF(mipLevel);
deMemcpy((deUint8*) dst.getDataPtr() + region.bufferCopy.dstOffset,
(deUint8*) src.getDataPtr() + region.bufferCopy.srcOffset,
(size_t)region.bufferCopy.size);
}
class BufferToBufferTestCase : public vkt::TestCase
{
public:
BufferToBufferTestCase (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 new CopyBufferToBuffer(context, m_params);
}
private:
TestParams m_params;
};
// Copy from image to buffer.
class CopyImageToBuffer : public CopiesAndBlittingTestInstance
{
public:
CopyImageToBuffer (Context& context,
TestParams testParams);
virtual tcu::TestStatus iterate (void);
private:
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel = 0u);
tcu::TextureFormat m_textureFormat;
VkDeviceSize m_bufferSize;
Move<VkImage> m_source;
de::MovePtr<Allocation> m_sourceImageAlloc;
Move<VkBuffer> m_destination;
de::MovePtr<Allocation> m_destinationBufferAlloc;
};
CopyImageToBuffer::CopyImageToBuffer (Context& context, TestParams testParams)
: CopiesAndBlittingTestInstance(context, testParams)
, m_textureFormat(mapVkFormat(testParams.src.image.format))
, m_bufferSize(m_params.dst.buffer.size * tcu::getPixelSize(m_textureFormat))
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
// Create source image
{
const VkImageCreateInfo sourceImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.src.image), // VkImageCreateFlags flags;
m_params.src.image.imageType, // VkImageType imageType;
m_params.src.image.format, // VkFormat format;
getExtent3D(m_params.src.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.src.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_source = createImage(vk, vkDevice, &sourceImageParams);
m_sourceImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_source, m_sourceImageAlloc->getMemory(), m_sourceImageAlloc->getOffset()));
}
// Create destination buffer
{
const VkBufferCreateInfo destinationBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_bufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
m_destination = createBuffer(vk, vkDevice, &destinationBufferParams);
m_destinationBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_destination, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset()));
}
}
tcu::TestStatus CopyImageToBuffer::iterate (void)
{
m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat,
m_params.src.image.extent.width,
m_params.src.image.extent.height,
m_params.src.image.extent.depth));
generateBuffer(m_sourceTextureLevel->getAccess(), m_params.src.image.extent.width, m_params.src.image.extent.height, m_params.src.image.extent.depth);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, (int)m_params.dst.buffer.size, 1));
generateBuffer(m_destinationTextureLevel->getAccess(), (int)m_params.dst.buffer.size, 1, 1);
generateExpectedResult();
uploadImage(m_sourceTextureLevel->getAccess(), *m_source, m_params.src.image);
uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc);
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
// Barriers for copying image to buffer
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*m_source, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(m_textureFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
1u // deUint32 arraySize;
}
};
const VkBufferMemoryBarrier bufferBarrier =
{
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_bufferSize // VkDeviceSize size;
};
// Copy from image to buffer
std::vector<VkBufferImageCopy> bufferImageCopies;
for (deUint32 i = 0; i < m_params.regions.size(); i++)
bufferImageCopies.push_back(m_params.regions[i].bufferImageCopy);
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
vk.cmdCopyImageToBuffer(*m_cmdBuffer, m_source.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_destination.get(), (deUint32)m_params.regions.size(), &bufferImageCopies[0]);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &bufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait (vk, vkDevice, queue, *m_cmdBuffer);
// Read buffer data
de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_textureFormat, (int)m_params.dst.buffer.size, 1));
invalidateAlloc(vk, vkDevice, *m_destinationBufferAlloc);
tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr()));
return checkTestResult(resultLevel->getAccess());
}
class CopyImageToBufferTestCase : public vkt::TestCase
{
public:
CopyImageToBufferTestCase (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 new CopyImageToBuffer(context, m_params);
}
private:
TestParams m_params;
};
void CopyImageToBuffer::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel)
{
DE_UNREF(mipLevel);
deUint32 rowLength = region.bufferImageCopy.bufferRowLength;
if (!rowLength)
rowLength = region.bufferImageCopy.imageExtent.width;
deUint32 imageHeight = region.bufferImageCopy.bufferImageHeight;
if (!imageHeight)
imageHeight = region.bufferImageCopy.imageExtent.height;
const int texelSize = src.getFormat().getPixelSize();
const VkExtent3D extent = region.bufferImageCopy.imageExtent;
const VkOffset3D srcOffset = region.bufferImageCopy.imageOffset;
const int texelOffset = (int) region.bufferImageCopy.bufferOffset / texelSize;
for (deUint32 z = 0; z < extent.depth; z++)
{
for (deUint32 y = 0; y < extent.height; y++)
{
int texelIndex = texelOffset + (z * imageHeight + y) * rowLength;
const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, srcOffset.x, srcOffset.y + y, srcOffset.z + z,
region.bufferImageCopy.imageExtent.width, 1, 1);
const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dst, texelIndex, 0, region.bufferImageCopy.imageExtent.width, 1);
tcu::copy(dstSubRegion, srcSubRegion);
}
}
}
// Copy from buffer to image.
class CopyBufferToImage : public CopiesAndBlittingTestInstance
{
public:
CopyBufferToImage (Context& context,
TestParams testParams);
virtual tcu::TestStatus iterate (void);
private:
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel = 0u);
tcu::TextureFormat m_textureFormat;
VkDeviceSize m_bufferSize;
Move<VkBuffer> m_source;
de::MovePtr<Allocation> m_sourceBufferAlloc;
Move<VkImage> m_destination;
de::MovePtr<Allocation> m_destinationImageAlloc;
};
CopyBufferToImage::CopyBufferToImage (Context& context, TestParams testParams)
: CopiesAndBlittingTestInstance(context, testParams)
, m_textureFormat(mapVkFormat(testParams.dst.image.format))
, m_bufferSize(m_params.src.buffer.size * tcu::getPixelSize(m_textureFormat))
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
// Create source buffer
{
const VkBufferCreateInfo sourceBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_bufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
m_source = createBuffer(vk, vkDevice, &sourceBufferParams);
m_sourceBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_source, m_sourceBufferAlloc->getMemory(), m_sourceBufferAlloc->getOffset()));
}
// Create destination image
{
const VkImageCreateInfo destinationImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.dst.image), // VkImageCreateFlags flags;
m_params.dst.image.imageType, // VkImageType imageType;
m_params.dst.image.format, // VkFormat format;
getExtent3D(m_params.dst.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.dst.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_destination = createImage(vk, vkDevice, &destinationImageParams);
m_destinationImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_destination, m_destinationImageAlloc->getMemory(), m_destinationImageAlloc->getOffset()));
}
}
tcu::TestStatus CopyBufferToImage::iterate (void)
{
m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, (int)m_params.src.buffer.size, 1));
generateBuffer(m_sourceTextureLevel->getAccess(), (int)m_params.src.buffer.size, 1, 1);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat,
m_params.dst.image.extent.width,
m_params.dst.image.extent.height,
m_params.dst.image.extent.depth));
generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth);
generateExpectedResult();
uploadBuffer(m_sourceTextureLevel->getAccess(), *m_sourceBufferAlloc);
uploadImage(m_destinationTextureLevel->getAccess(), *m_destination, m_params.dst.image);
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*m_destination, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(m_textureFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
1u // deUint32 arraySize;
}
};
// Copy from buffer to image
std::vector<VkBufferImageCopy> bufferImageCopies;
for (deUint32 i = 0; i < m_params.regions.size(); i++)
bufferImageCopies.push_back(m_params.regions[i].bufferImageCopy);
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
vk.cmdCopyBufferToImage(*m_cmdBuffer, m_source.get(), m_destination.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)m_params.regions.size(), bufferImageCopies.data());
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait (vk, vkDevice, queue, *m_cmdBuffer);
de::MovePtr<tcu::TextureLevel> resultLevel = readImage(*m_destination, m_params.dst.image);
return checkTestResult(resultLevel->getAccess());
}
class CopyBufferToImageTestCase : public vkt::TestCase
{
public:
CopyBufferToImageTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const TestParams params)
: vkt::TestCase (testCtx, name, description)
, m_params (params)
{}
virtual ~CopyBufferToImageTestCase (void) {}
virtual TestInstance* createInstance (Context& context) const
{
return new CopyBufferToImage(context, m_params);
}
private:
TestParams m_params;
};
void CopyBufferToImage::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel)
{
DE_UNREF(mipLevel);
deUint32 rowLength = region.bufferImageCopy.bufferRowLength;
if (!rowLength)
rowLength = region.bufferImageCopy.imageExtent.width;
deUint32 imageHeight = region.bufferImageCopy.bufferImageHeight;
if (!imageHeight)
imageHeight = region.bufferImageCopy.imageExtent.height;
const int texelSize = dst.getFormat().getPixelSize();
const VkExtent3D extent = region.bufferImageCopy.imageExtent;
const VkOffset3D dstOffset = region.bufferImageCopy.imageOffset;
const int texelOffset = (int) region.bufferImageCopy.bufferOffset / texelSize;
for (deUint32 z = 0; z < extent.depth; z++)
{
for (deUint32 y = 0; y < extent.height; y++)
{
int texelIndex = texelOffset + (z * imageHeight + y) * rowLength;
const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, texelIndex, 0, region.bufferImageCopy.imageExtent.width, 1);
const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dst, dstOffset.x, dstOffset.y + y, dstOffset.z + z,
region.bufferImageCopy.imageExtent.width, 1, 1);
tcu::copy(dstSubRegion, srcSubRegion);
}
}
}
class CopyBufferToDepthStencil : public CopiesAndBlittingTestInstance
{
public:
CopyBufferToDepthStencil (Context& context,
TestParams testParams);
virtual tcu::TestStatus iterate (void);
private:
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel = 0u);
tcu::TextureFormat m_textureFormat;
VkDeviceSize m_bufferSize;
Move<VkBuffer> m_source;
de::MovePtr<Allocation> m_sourceBufferAlloc;
Move<VkImage> m_destination;
de::MovePtr<Allocation> m_destinationImageAlloc;
};
void CopyBufferToDepthStencil::copyRegionToTextureLevel(tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel)
{
DE_UNREF(mipLevel);
deUint32 rowLength = region.bufferImageCopy.bufferRowLength;
if (!rowLength)
rowLength = region.bufferImageCopy.imageExtent.width;
deUint32 imageHeight = region.bufferImageCopy.bufferImageHeight;
if (!imageHeight)
imageHeight = region.bufferImageCopy.imageExtent.height;
const int texelSize = dst.getFormat().getPixelSize();
const VkExtent3D extent = region.bufferImageCopy.imageExtent;
const VkOffset3D dstOffset = region.bufferImageCopy.imageOffset;
const int texelOffset = (int)region.bufferImageCopy.bufferOffset / texelSize;
for (deUint32 z = 0; z < extent.depth; z++)
{
for (deUint32 y = 0; y < extent.height; y++)
{
int texelIndex = texelOffset + (z * imageHeight + y) * rowLength;
const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, texelIndex, 0, region.bufferImageCopy.imageExtent.width, 1);
const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dst, dstOffset.x, dstOffset.y + y, dstOffset.z + z,
region.bufferImageCopy.imageExtent.width, 1, 1);
if (region.bufferImageCopy.imageSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)
{
tcu::copy(dstSubRegion, tcu::getEffectiveDepthStencilAccess(srcSubRegion, tcu::Sampler::MODE_DEPTH), DE_FALSE);
}
else
{
tcu::copy(dstSubRegion, tcu::getEffectiveDepthStencilAccess(srcSubRegion, tcu::Sampler::MODE_STENCIL), DE_FALSE);
}
}
}
}
bool isSupportedDepthStencilFormat(const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkFormat format)
{
VkFormatProperties formatProps;
vki.getPhysicalDeviceFormatProperties(physDevice, format, &formatProps);
return (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0;
}
CopyBufferToDepthStencil::CopyBufferToDepthStencil(Context& context, TestParams testParams)
: CopiesAndBlittingTestInstance(context, testParams)
, m_textureFormat(mapVkFormat(testParams.dst.image.format))
, m_bufferSize(0)
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
const bool hasDepth = tcu::hasDepthComponent(mapVkFormat(m_params.dst.image.format).order);
const bool hasStencil = tcu::hasStencilComponent(mapVkFormat(m_params.dst.image.format).order);
if (!isSupportedDepthStencilFormat(vki, vkPhysDevice, testParams.dst.image.format))
{
TCU_THROW(NotSupportedError, "Image format not supported.");
}
if (hasDepth)
{
glw::GLuint texelSize = m_textureFormat.getPixelSize();
if (texelSize > sizeof(float))
{
// We must have D32F_S8 format, depth must be packed so we only need
// to allocate space for the D32F part. Stencil will be separate
texelSize = sizeof(float);
}
m_bufferSize += static_cast<VkDeviceSize>(m_params.dst.image.extent.width) * static_cast<VkDeviceSize>(m_params.dst.image.extent.height) * static_cast<VkDeviceSize>(texelSize);
}
if (hasStencil)
{
// Stencil is always 8bits and packed.
m_bufferSize += static_cast<VkDeviceSize>(m_params.dst.image.extent.width) * static_cast<VkDeviceSize>(m_params.dst.image.extent.height);
}
// Create source buffer, this is where the depth & stencil data will go that's used by test's regions.
{
const VkBufferCreateInfo sourceBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
m_bufferSize, // VkDeviceSize size;
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
};
m_source = createBuffer(vk, vkDevice, &sourceBufferParams);
m_sourceBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindBufferMemory(vkDevice, *m_source, m_sourceBufferAlloc->getMemory(), m_sourceBufferAlloc->getOffset()));
}
// Create destination image
{
const VkImageCreateInfo destinationImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.dst.image), // VkImageCreateFlags flags;
m_params.dst.image.imageType, // VkImageType imageType;
m_params.dst.image.format, // VkFormat format;
getExtent3D(m_params.dst.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.dst.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_destination = createImage(vk, vkDevice, &destinationImageParams);
m_destinationImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_destination, m_destinationImageAlloc->getMemory(), m_destinationImageAlloc->getOffset()));
}
}
tcu::TestStatus CopyBufferToDepthStencil::iterate(void)
{
// Create source depth/stencil content. Treat as 1D texture to get different pattern
m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, (int)m_params.src.buffer.size, 1));
// Fill buffer with linear gradiant
generateBuffer(m_sourceTextureLevel->getAccess(), (int)m_params.src.buffer.size, 1, 1);
// Create image layer for depth/stencil
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat,
m_params.dst.image.extent.width,
m_params.dst.image.extent.height,
m_params.dst.image.extent.depth));
// Fill image layer with 2D gradiant
generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth);
// Fill m_extendedTextureLevel with copy of m_destinationTextureLevel
// Then iterate over each of the regions given in m_params.regions and copy m_sourceTextureLevel content to m_extendedTextureLevel
// This emulates what the HW will be doing.
generateExpectedResult();
// Upload our source depth/stencil content to the source buffer
// This is the buffer that will be used by region commands
std::vector<VkBufferImageCopy> bufferImageCopies;
VkDeviceSize bufferOffset = 0;
const VkDevice vkDevice = m_context.getDevice();
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkQueue queue = m_context.getUniversalQueue();
char* dstPtr = reinterpret_cast<char*>(m_sourceBufferAlloc->getHostPtr());
bool depthLoaded = DE_FALSE;
bool stencilLoaded = DE_FALSE;
VkDeviceSize depthOffset = 0;
VkDeviceSize stencilOffset = 0;
// To be able to test ordering depth & stencil differently
// we take the given copy regions and use that as the desired order
// and copy the appropriate data into place and compute the appropriate
// data offsets to be used in the copy command.
for (deUint32 i = 0; i < m_params.regions.size(); i++)
{
tcu::ConstPixelBufferAccess bufferAccess = m_sourceTextureLevel->getAccess();
deUint32 bufferSize = bufferAccess.getWidth() * bufferAccess.getHeight() * bufferAccess.getDepth();
VkBufferImageCopy copyData = m_params.regions[i].bufferImageCopy;
char* srcPtr;
if (copyData.imageSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT && !depthLoaded)
{
// Create level that is same component as depth buffer (e.g. D16, D24, D32F)
tcu::TextureLevel depthTexture(mapCombinedToDepthTransferFormat(bufferAccess.getFormat()), bufferAccess.getWidth(), bufferAccess.getHeight(), bufferAccess.getDepth());
bufferSize *= tcu::getPixelSize(depthTexture.getFormat());
// Copy depth component only from source data. This gives us packed depth-only data.
tcu::copy(depthTexture.getAccess(), tcu::getEffectiveDepthStencilAccess(bufferAccess, tcu::Sampler::MODE_DEPTH));
srcPtr = (char*)depthTexture.getAccess().getDataPtr();
// Copy packed depth-only data to output buffer
deMemcpy(dstPtr, srcPtr, bufferSize);
depthLoaded = DE_TRUE;
depthOffset = bufferOffset;
dstPtr += bufferSize;
bufferOffset += bufferSize;
copyData.bufferOffset += depthOffset;
}
else if (!stencilLoaded)
{
// Create level that is same component as stencil buffer (always 8-bits)
tcu::TextureLevel stencilTexture(tcu::getEffectiveDepthStencilTextureFormat(bufferAccess.getFormat(), tcu::Sampler::MODE_STENCIL), bufferAccess.getWidth(), bufferAccess.getHeight(), bufferAccess.getDepth());
// Copy stencil component only from source data. This gives us packed stencil-only data.
tcu::copy(stencilTexture.getAccess(), tcu::getEffectiveDepthStencilAccess(bufferAccess, tcu::Sampler::MODE_STENCIL));
srcPtr = (char*)stencilTexture.getAccess().getDataPtr();
// Copy packed stencil-only data to output buffer
deMemcpy(dstPtr, srcPtr, bufferSize);
stencilLoaded = DE_TRUE;
stencilOffset = bufferOffset;
dstPtr += bufferSize;
bufferOffset += bufferSize;
// Reference image generation uses pixel offsets based on buffer offset.
// We need to adjust the offset now that the stencil data is not interleaved.
copyData.bufferOffset /= tcu::getPixelSize(m_textureFormat);
copyData.bufferOffset += stencilOffset;
}
bufferImageCopies.push_back(copyData);
}
flushAlloc(vk, vkDevice, *m_sourceBufferAlloc);
// Upload the depth/stencil data from m_destinationTextureLevel to initialize
// depth and stencil to known values.
// Uses uploadImageAspect so makes its own buffers for depth and stencil
// aspects (as needed) and copies them with independent vkCmdCopyBufferToImage commands.
uploadImage(m_destinationTextureLevel->getAccess(), *m_destination, m_params.dst.image);
const VkImageMemoryBarrier imageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
*m_destination, // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(m_textureFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
1u // deUint32 arraySize;
}
};
// Copy from buffer to depth/stencil image
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
if (m_params.singleCommand)
{
// Issue a single copy command with regions defined by the test.
vk.cmdCopyBufferToImage(*m_cmdBuffer, m_source.get(), m_destination.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)m_params.regions.size(), bufferImageCopies.data());
}
else
{
// Issue a a copy command per region defined by the test.
for (deUint32 i = 0; i < bufferImageCopies.size(); i++)
{
vk.cmdCopyBufferToImage(*m_cmdBuffer, m_source.get(), m_destination.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferImageCopies[i]);
}
}
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, *m_cmdBuffer);
de::MovePtr<tcu::TextureLevel> resultLevel = readImage(*m_destination, m_params.dst.image);
// For combined depth/stencil formats both aspects are checked even when the test only
// copies one. Clear such aspects here for both the result and the reference.
if (tcu::hasDepthComponent(m_textureFormat.order) && !depthLoaded)
{
tcu::clearDepth(m_expectedTextureLevel[0]->getAccess(), 0.0f);
tcu::clearDepth(resultLevel->getAccess(), 0.0f);
}
if (tcu::hasStencilComponent(m_textureFormat.order) && !stencilLoaded)
{
tcu::clearStencil(m_expectedTextureLevel[0]->getAccess(), 0);
tcu::clearStencil(resultLevel->getAccess(), 0);
}
return checkTestResult(resultLevel->getAccess());
}
class CopyBufferToDepthStencilTestCase : public vkt::TestCase
{
public:
CopyBufferToDepthStencilTestCase (tcu::TestContext& testCtx,
const std::string& name,
const std::string& description,
const TestParams params)
: vkt::TestCase(testCtx, name, description)
, m_params(params)
{}
virtual ~CopyBufferToDepthStencilTestCase (void) {}
virtual TestInstance* createInstance (Context& context) const
{
return new CopyBufferToDepthStencil(context, m_params);
}
private:
TestParams m_params;
};
// Copy from image to image with scaling.
class BlittingImages : public CopiesAndBlittingTestInstance
{
public:
BlittingImages (Context& context,
TestParams params);
virtual tcu::TestStatus iterate (void);
protected:
virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess result);
virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region, deUint32 mipLevel = 0u);
virtual void generateExpectedResult (void);
private:
bool checkNonNearestFilteredResult (const tcu::ConstPixelBufferAccess& result,
const tcu::ConstPixelBufferAccess& clampedReference,
const tcu::ConstPixelBufferAccess& unclampedReference,
const tcu::TextureFormat& sourceFormat);
bool checkNearestFilteredResult (const tcu::ConstPixelBufferAccess& result,
const tcu::ConstPixelBufferAccess& source);
Move<VkImage> m_source;
de::MovePtr<Allocation> m_sourceImageAlloc;
Move<VkImage> m_destination;
de::MovePtr<Allocation> m_destinationImageAlloc;
de::MovePtr<tcu::TextureLevel> m_unclampedExpectedTextureLevel;
};
BlittingImages::BlittingImages (Context& context, TestParams params)
: CopiesAndBlittingTestInstance(context, params)
{
const InstanceInterface& vki = context.getInstanceInterface();
const DeviceInterface& vk = context.getDeviceInterface();
const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice();
const VkDevice vkDevice = context.getDevice();
const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
Allocator& memAlloc = context.getDefaultAllocator();
// Create source image
{
const VkImageCreateInfo sourceImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.src.image), // VkImageCreateFlags flags;
m_params.src.image.imageType, // VkImageType imageType;
m_params.src.image.format, // VkFormat format;
getExtent3D(m_params.src.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.src.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
m_params.src.image.tiling, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_source = createImage(vk, vkDevice, &sourceImageParams);
m_sourceImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_source, m_sourceImageAlloc->getMemory(), m_sourceImageAlloc->getOffset()));
}
// Create destination image
{
const VkImageCreateInfo destinationImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
getCreateFlags(m_params.dst.image), // VkImageCreateFlags flags;
m_params.dst.image.imageType, // VkImageType imageType;
m_params.dst.image.format, // VkFormat format;
getExtent3D(m_params.dst.image), // VkExtent3D extent;
1u, // deUint32 mipLevels;
getArraySize(m_params.dst.image), // deUint32 arraySize;
VK_SAMPLE_COUNT_1_BIT, // deUint32 samples;
m_params.dst.image.tiling, // VkImageTiling tiling;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
m_destination = createImage(vk, vkDevice, &destinationImageParams);
m_destinationImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::Any, memAlloc, m_params.allocationKind);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_destination, m_destinationImageAlloc->getMemory(), m_destinationImageAlloc->getOffset()));
}
}
tcu::TestStatus BlittingImages::iterate (void)
{
const tcu::TextureFormat srcTcuFormat = mapVkFormat(m_params.src.image.format);
const tcu::TextureFormat dstTcuFormat = mapVkFormat(m_params.dst.image.format);
m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(srcTcuFormat,
m_params.src.image.extent.width,
m_params.src.image.extent.height,
m_params.src.image.extent.depth));
generateBuffer(m_sourceTextureLevel->getAccess(), m_params.src.image.extent.width, m_params.src.image.extent.height, m_params.src.image.extent.depth, FILL_MODE_GRADIENT);
m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dstTcuFormat,
(int)m_params.dst.image.extent.width,
(int)m_params.dst.image.extent.height,
(int)m_params.dst.image.extent.depth));
generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth, FILL_MODE_WHITE);
generateExpectedResult();
uploadImage(m_sourceTextureLevel->getAccess(), m_source.get(), m_params.src.image);
uploadImage(m_destinationTextureLevel->getAccess(), m_destination.get(), m_params.dst.image);
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
std::vector<VkImageBlit> regions;
for (deUint32 i = 0; i < m_params.regions.size(); i++)
regions.push_back(m_params.regions[i].imageBlit);
// Barriers for copying image to buffer
const VkImageMemoryBarrier srcImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
m_params.src.image.operationLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
m_source.get(), // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(srcTcuFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
1u // deUint32 arraySize;
}
};
const VkImageMemoryBarrier dstImageBarrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout;
m_params.dst.image.operationLayout, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex;
m_destination.get(), // VkImage image;
{ // VkImageSubresourceRange subresourceRange;
getAspectFlags(dstTcuFormat), // VkImageAspectFlags aspectMask;
0u, // deUint32 baseMipLevel;
1u, // deUint32 mipLevels;
0u, // deUint32 baseArraySlice;
1u // deUint32 arraySize;
}
};
beginCommandBuffer(vk, *m_cmdBuffer);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &srcImageBarrier);
vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &dstImageBarrier);
vk.cmdBlitImage(*m_cmdBuffer, m_source.get(), m_params.src.image.operationLayout, m_destination.get(), m_params.dst.image.operationLayout, (deUint32)m_params.regions.size(), &regions[0], m_params.filter);
endCommandBuffer(vk, *m_cmdBuffer);
submitCommandsAndWait(vk, vkDevice, queue, *m_cmdBuffer);
de::MovePtr<tcu::TextureLevel> resultTextureLevel = readImage(*m_destination, m_params.dst.image);
return checkTestResult(resultTextureLevel->getAccess());
}
static float calculateFloatConversionError (int srcBits)
{
if (srcBits > 0)
{
const int clampedBits = de::clamp<int>(srcBits, 0, 32);
const float srcMaxValue = de::max((float)(1ULL<<clampedBits) - 1.0f, 1.0f);
const float error = 1.0f / srcMaxValue;
return de::clamp<float>(error, 0.0f, 1.0f);
}
else
return 1.0f;
}
tcu::Vec4 getFormatThreshold (const tcu::TextureFormat& format)
{
tcu::Vec4 threshold(0.01f);
switch (format.type)
{
case tcu::TextureFormat::HALF_FLOAT:
threshold = tcu::Vec4(0.005f);
break;
case tcu::TextureFormat::FLOAT:
case tcu::TextureFormat::FLOAT64:
threshold = tcu::Vec4(0.001f);
break;
case tcu::TextureFormat::UNSIGNED_INT_11F_11F_10F_REV:
threshold = tcu::Vec4(0.02f, 0.02f, 0.0625f, 1.0f);
break;
case tcu::TextureFormat::UNSIGNED_INT_999_E5_REV:
threshold = tcu::Vec4(0.05f, 0.05f, 0.05f, 1.0f);
break;
case tcu::TextureFormat::UNORM_INT_1010102_REV:
threshold = tcu::Vec4(0.002f, 0.002f, 0.002f, 0.3f);
break;
case tcu:: TextureFormat::UNORM_INT8:
threshold = tcu::Vec4(0.008f, 0.008f, 0.008f, 0.008f);
break;
default:
const tcu::IVec4 bits = tcu::getTextureFormatMantissaBitDepth(format);
threshold = tcu::Vec4(calculateFloatConversionError(bits.x()),
calculateFloatConversionError(bits.y()),
calculateFloatConversionError(bits.z()),
calculateFloatConversionError(bits.w()));
}
// Return value matching the channel order specified by the format
if (format.order == tcu::TextureFormat::BGR || format.order == tcu::TextureFormat::BGRA)
return threshold.swizzle(2, 1, 0, 3);
else
return threshold;
}
bool BlittingImages::checkNonNearestFilteredResult (const tcu::ConstPixelBufferAccess& result,
const tcu::ConstPixelBufferAccess& clampedExpected,
const tcu::ConstPixelBufferAccess& unclampedExpected,
const tcu::TextureFormat& srcFormat)
{
tcu::TestLog& log (m_context.getTestContext().getLog());
const tcu::TextureFormat dstFormat = result.getFormat();
const tcu::TextureChannelClass dstChannelClass = tcu::getTextureChannelClass(dstFormat.type);
const tcu::TextureChannelClass srcChannelClass = tcu::getTextureChannelClass(srcFormat.type);
bool isOk = false;
log << tcu::TestLog::Section("ClampedSourceImage", "Region with clamped edges on source image.");
// if either of srcImage or dstImage stores values as a signed/unsigned integer,
// the other must also store values a signed/unsigned integer
// e.g. blit unorm to uscaled is not allowed as uscaled formats store data as integers
// despite the fact that both formats are sampled as floats
bool dstImageIsIntClass = dstChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ||
dstChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
bool srcImageIsIntClass = srcChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER ||
srcChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER;
if (dstImageIsIntClass != srcImageIsIntClass)
{
log << tcu::TestLog::EndSection;
return false;
}
if (isFloatFormat(dstFormat))
{
const bool srcIsSRGB = tcu::isSRGB(srcFormat);
const tcu::Vec4 srcMaxDiff = getFormatThreshold(srcFormat) * tcu::Vec4(srcIsSRGB ? 2.0f : 1.0f);
const tcu::Vec4 dstMaxDiff = getFormatThreshold(dstFormat);
const tcu::Vec4 threshold = ( srcMaxDiff + dstMaxDiff ) * ((m_params.filter == VK_FILTER_CUBIC_EXT) ? 1.5f : 1.0f);
isOk = tcu::floatThresholdCompare(log, "Compare", "Result comparsion", clampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT);
log << tcu::TestLog::EndSection;
if (!isOk)
{
log << tcu::TestLog::Section("NonClampedSourceImage", "Region with non-clamped edges on source image.");
isOk = tcu::floatThresholdCompare(log, "Compare", "Result comparsion", unclampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT);
log << tcu::TestLog::EndSection;
}
}
else
{
tcu::UVec4 threshold;
// Calculate threshold depending on channel width of destination format.
const tcu::IVec4 dstBitDepth = tcu::getTextureFormatBitDepth(dstFormat);
const tcu::IVec4 srcBitDepth = tcu::getTextureFormatBitDepth(srcFormat);
for (deUint32 i = 0; i < 4; ++i)
threshold[i] = 1 + de::max( ( ( 1 << dstBitDepth[i] ) - 1 ) / de::clamp((1 << srcBitDepth[i]) - 1, 1, 256), 1);
isOk = tcu::intThresholdCompare(log, "Compare", "Result comparsion", clampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT);
log << tcu::TestLog::EndSection;
if (!isOk)
{
log << tcu::TestLog::Section("NonClampedSourceImage", "Region with non-clamped edges on source image.");
isOk = tcu::intThresholdCompare(log, "Compare", "Result comparsion", unclampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT);
log << tcu::TestLog::EndSection;
}
}
return isOk;
}
//! Utility to encapsulate coordinate computation and loops.
struct CompareEachPixelInEachRegion
{
virtual ~CompareEachPixelInEachRegion (void) {}
virtual bool compare (const void* pUserData, const int x, const int y, const int z, const tcu::Vec3& srcNormCoord) const = 0;
bool forEach (const void* pUserData,
const std::vector<CopyRegion>& regions,
const int sourceWidth,
const int sourceHeight,
const int sourceDepth,
const tcu::PixelBufferAccess& errorMask) const
{
bool compareOk = true;
for (std::vector<CopyRegion>::const_iterator regionIter = regions.begin(); regionIter != regions.end(); ++regionIter)
{
const VkImageBlit& blit = regionIter->imageBlit;
const int xStart = deMin32(blit.dstOffsets[0].x, blit.dstOffsets[1].x);
const int yStart = deMin32(blit.dstOffsets[0].y, blit.dstOffsets[1].y);
const int zStart = deMin32(blit.dstOffsets[0].z, blit.dstOffsets[1].z);
const int xEnd = deMax32(blit.dstOffsets[0].x, blit.dstOffsets[1].x);
const int yEnd = deMax32(blit.dstOffsets[0].y, blit.dstOffsets[1].y);
const int zEnd = deMax32(blit.dstOffsets[0].z, blit.dstOffsets[1].z);
const float xScale = static_cast<float>(blit.srcOffsets[1].x - blit.srcOffsets[0].x) / static_cast<float>(blit.dstOffsets[1].x - blit.dstOffsets[0].x);
const float yScale = static_cast<float>(blit.srcOffsets[1].y - blit.srcOffsets[0].y) / static_cast<float>(blit.dstOffsets[1].y - blit.dstOffsets[0].y);
const float zScale = static_cast<float>(blit.srcOffsets[1].z - blit.srcOffsets[0].z) / static_cast<float>(blit.dstOffsets[1].z - blit.dstOffsets[0].z);
const float srcInvW = 1.0f / static_cast<float>(sourceWidth);
const float srcInvH = 1.0f / static_cast<float>(sourceHeight);
const float srcInvD = 1.0f / static_cast<float>(sourceDepth);
for (int z = zStart; z < zEnd; z++)
for (int y = yStart; y < yEnd; y++)
for (int x = xStart; x < xEnd; x++)
{
const tcu::Vec3 srcNormCoord
(
(xScale * (static_cast<float>(x - blit.dstOffsets[0].x) + 0.5f) + static_cast<float>(blit.srcOffsets[0].x)) * srcInvW,
(yScale * (static_cast<float>(y - blit.dstOffsets[0].y) + 0.5f) + static_cast<float>(blit.srcOffsets[0].y)) * srcInvH,
(zScale * (static_cast<float>(z - blit.dstOffsets[0].z) + 0.5f) + static_cast<float>(blit.srcOffsets[0].z)) * srcInvD
);
if (!compare(pUserData, x, y, z, srcNormCoord))
{
errorMask.setPixel(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y, z);
compareOk = false;
}
}
}
return compareOk;
}
};
tcu::Vec4 getFloatOrFixedPointFormatThreshold (const tcu::TextureFormat& format)
{
const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type);
const tcu::IVec4 bitDepth = tcu::getTextureFormatBitDepth(format);
if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
{
return getFormatThreshold(format);
}
else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT)
{
const bool isSigned = (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT);
const float range = isSigned ? 1.0f - (-1.0f)
: 1.0f - 0.0f;
tcu::Vec4 v;
for (int i = 0; i < 4; ++i)
{
if (bitDepth[i] == 0)
v[i] = 1.0f;
else
v[i] = range / static_cast<float>((1 << bitDepth[i]) - 1);
}
return v;
}
else
{
DE_ASSERT(0);
return tcu::Vec4();
}
}
bool floatNearestBlitCompare (const tcu::ConstPixelBufferAccess& source,
const tcu::ConstPixelBufferAccess& result,
const tcu::PixelBufferAccess& errorMask,
const std::vector<CopyRegion>& regions)
{
const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST);
tcu::LookupPrecision precision;
{
const tcu::IVec4 dstBitDepth = tcu::getTextureFormatBitDepth(result.getFormat());
const tcu::Vec4 srcMaxDiff = getFloatOrFixedPointFormatThreshold(source.getFormat());
const tcu::Vec4 dstMaxDiff = getFloatOrFixedPointFormatThreshold(result.getFormat());
precision.colorMask = tcu::notEqual(dstBitDepth, tcu::IVec4(0));
precision.colorThreshold = tcu::max(srcMaxDiff, dstMaxDiff);
}
const struct Capture
{
const tcu::ConstPixelBufferAccess& source;
const tcu::ConstPixelBufferAccess& result;
const tcu::Sampler& sampler;
const tcu::LookupPrecision& precision;
const bool isSRGB;
} capture =
{
source, result, sampler, precision, tcu::isSRGB(result.getFormat())
};
const struct Loop : CompareEachPixelInEachRegion
{
Loop (void) {}
bool compare (const void* pUserData, const int x, const int y, const int z, const tcu::Vec3& srcNormCoord) const
{
const Capture& c = *static_cast<const Capture*>(pUserData);
const tcu::TexLookupScaleMode lookupScaleDontCare = tcu::TEX_LOOKUP_SCALE_MINIFY;
tcu::Vec4 dstColor = c.result.getPixel(x, y, z);
// TexLookupVerifier performs a conversion to linear space, so we have to as well
if (c.isSRGB)
dstColor = tcu::sRGBToLinear(dstColor);
return tcu::isLevel3DLookupResultValid(c.source, c.sampler, lookupScaleDontCare, c.precision, srcNormCoord, dstColor);
}
} loop;
return loop.forEach(&capture, regions, source.getWidth(), source.getHeight(), source.getDepth(), errorMask);
}
bool intNearestBlitCompare (const tcu::ConstPixelBufferAccess& source,
const tcu::ConstPixelBufferAccess& result,
const tcu::PixelBufferAccess& errorMask,
const std::vector<CopyRegion>& regions)
{
const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST);
tcu::IntLookupPrecision precision;
{
const tcu::IVec4 srcBitDepth = tcu::getTextureFormatBitDepth(source.getFormat());
const tcu::IVec4 dstBitDepth = tcu::getTextureFormatBitDepth(result.