| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2015-2020 The Khronos Group Inc. |
| * Copyright (c) 2020 Google 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 "vkBuilderUtil.hpp" |
| #include "vkBufferWithMemory.hpp" |
| #include "vkBarrierUtil.hpp" |
| |
| #include <set> |
| #include <array> |
| #include <algorithm> |
| #include <iterator> |
| #include <sstream> |
| |
| namespace vkt |
| { |
| |
| namespace api |
| { |
| |
| namespace |
| { |
| |
| enum FillMode |
| { |
| FILL_MODE_GRADIENT = 0, |
| FILL_MODE_WHITE, |
| FILL_MODE_RED, |
| FILL_MODE_MULTISAMPLE, |
| FILL_MODE_BLUE_RED_X, |
| FILL_MODE_BLUE_RED_Y, |
| FILL_MODE_BLUE_RED_Z, |
| |
| FILL_MODE_LAST |
| }; |
| |
| enum MirrorModeBits |
| { |
| MIRROR_MODE_X = (1<<0), |
| MIRROR_MODE_Y = (1<<1), |
| MIRROR_MODE_Z = (1<<2), |
| MIRROR_MODE_LAST = (1<<3), |
| }; |
| |
| using MirrorMode = deUint32; |
| |
| enum AllocationKind |
| { |
| ALLOCATION_KIND_SUBALLOCATED, |
| ALLOCATION_KIND_DEDICATED, |
| }; |
| |
| enum ExtensionUse |
| { |
| EXTENSION_USE_NONE, |
| EXTENSION_USE_COPY_COMMANDS2, |
| }; |
| |
| 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; |
| |
| VkImageCopy2KHR convertvkImageCopyTovkImageCopy2KHR(VkImageCopy imageCopy) |
| { |
| const VkImageCopy2KHR imageCopy2 = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| imageCopy.srcSubresource, // VkImageSubresourceLayers srcSubresource; |
| imageCopy.srcOffset, // VkOffset3D srcOffset; |
| imageCopy.dstSubresource, // VkImageSubresourceLayers dstSubresource; |
| imageCopy.dstOffset, // VkOffset3D dstOffset; |
| imageCopy.extent // VkExtent3D extent; |
| }; |
| return imageCopy2; |
| } |
| VkBufferCopy2KHR convertvkBufferCopyTovkBufferCopy2KHR(VkBufferCopy bufferCopy) |
| { |
| const VkBufferCopy2KHR bufferCopy2 = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| bufferCopy.srcOffset, // VkDeviceSize srcOffset; |
| bufferCopy.dstOffset, // VkDeviceSize dstOffset; |
| bufferCopy.size, // VkDeviceSize size; |
| }; |
| return bufferCopy2; |
| } |
| |
| VkBufferImageCopy2KHR convertvkBufferImageCopyTovkBufferImageCopy2KHR(VkBufferImageCopy bufferImageCopy) |
| { |
| const VkBufferImageCopy2KHR bufferImageCopy2 = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| bufferImageCopy.bufferOffset, // VkDeviceSize bufferOffset; |
| bufferImageCopy.bufferRowLength, // uint32_t bufferRowLength; |
| bufferImageCopy.bufferImageHeight, // uint32_t bufferImageHeight; |
| bufferImageCopy.imageSubresource, // VkImageSubresourceLayers imageSubresource; |
| bufferImageCopy.imageOffset, // VkOffset3D imageOffset; |
| bufferImageCopy.imageExtent // VkExtent3D imageExtent; |
| }; |
| return bufferImageCopy2; |
| } |
| |
| VkImageBlit2KHR convertvkImageBlitTovkImageBlit2KHR(VkImageBlit imageBlit) |
| { |
| const VkImageBlit2KHR imageBlit2 = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| imageBlit.srcSubresource, // VkImageSubresourceLayers srcSubresource; |
| { // VkOffset3D srcOffsets[2]; |
| { |
| imageBlit.srcOffsets[0].x, // VkOffset3D srcOffsets[0].x; |
| imageBlit.srcOffsets[0].y, // VkOffset3D srcOffsets[0].y; |
| imageBlit.srcOffsets[0].z // VkOffset3D srcOffsets[0].z; |
| }, |
| { |
| imageBlit.srcOffsets[1].x, // VkOffset3D srcOffsets[1].x; |
| imageBlit.srcOffsets[1].y, // VkOffset3D srcOffsets[1].y; |
| imageBlit.srcOffsets[1].z // VkOffset3D srcOffsets[1].z; |
| } |
| }, |
| imageBlit.dstSubresource, // VkImageSubresourceLayers dstSubresource; |
| { // VkOffset3D srcOffsets[2]; |
| { |
| imageBlit.dstOffsets[0].x, // VkOffset3D dstOffsets[0].x; |
| imageBlit.dstOffsets[0].y, // VkOffset3D dstOffsets[0].y; |
| imageBlit.dstOffsets[0].z // VkOffset3D dstOffsets[0].z; |
| }, |
| { |
| imageBlit.dstOffsets[1].x, // VkOffset3D dstOffsets[1].x; |
| imageBlit.dstOffsets[1].y, // VkOffset3D dstOffsets[1].y; |
| imageBlit.dstOffsets[1].z // VkOffset3D dstOffsets[1].z; |
| } |
| } |
| }; |
| return imageBlit2; |
| } |
| |
| VkImageResolve2KHR convertvkImageResolveTovkImageResolve2KHR(VkImageResolve imageResolve) |
| { |
| const VkImageResolve2KHR imageResolve2 = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| imageResolve.srcSubresource, // VkImageSubresourceLayers srcSubresource; |
| imageResolve.srcOffset, // VkOffset3D srcOffset; |
| imageResolve.dstSubresource, // VkImageSubresourceLayers dstSubresource; |
| imageResolve.dstOffset, // VkOffset3D dstOffset; |
| imageResolve.extent // VkExtent3D extent; |
| }; |
| return imageResolve2; |
| } |
| |
| 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; |
| VkImageCreateFlags createFlags; |
| FillMode fillMode; |
| }; |
| |
| struct TestParams |
| { |
| union Data |
| { |
| struct Buffer |
| { |
| VkDeviceSize size; |
| } buffer; |
| |
| ImageParms image; |
| } src, dst; |
| |
| std::vector<CopyRegion> regions; |
| |
| union |
| { |
| VkFilter filter; |
| VkSampleCountFlagBits samples; |
| }; |
| |
| AllocationKind allocationKind; |
| ExtensionUse extensionUse; |
| deUint32 mipLevels; |
| deBool singleCommand; |
| deUint32 barrierCount; |
| deBool separateDepthStencilLayouts; |
| deBool clearDestination; |
| |
| TestParams (void) |
| { |
| allocationKind = ALLOCATION_KIND_DEDICATED; |
| extensionUse = EXTENSION_USE_NONE; |
| mipLevels = 1u; |
| singleCommand = DE_TRUE; |
| barrierCount = 1u; |
| separateDepthStencilLayouts = DE_FALSE; |
| src.image.createFlags = VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM; |
| dst.image.createFlags = VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM; |
| src.image.fillMode = FILL_MODE_GRADIENT; |
| dst.image.fillMode = FILL_MODE_WHITE; |
| clearDestination = 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) |
| { |
| if (parms.createFlags == VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM) |
| return parms.imageType == VK_IMAGE_TYPE_2D && parms.extent.depth % 6 == 0 ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; |
| else |
| return parms.createFlags; |
| } |
| |
| 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; |
| |
| 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::fillWithComponentGradients2(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_BLUE_RED_X: |
| case FILL_MODE_BLUE_RED_Y: |
| case FILL_MODE_BLUE_RED_Z: |
| bool useBlue; |
| switch (mode) |
| { |
| case FILL_MODE_BLUE_RED_X: useBlue = (x & 1); break; |
| case FILL_MODE_BLUE_RED_Y: useBlue = (y & 1); break; |
| case FILL_MODE_BLUE_RED_Z: useBlue = (z & 1); break; |
| default: DE_ASSERT(false); break; |
| } |
| if (tcu::isCombinedDepthStencilType(buffer.getFormat().type)) |
| { |
| buffer.setPixDepth((useBlue ? blueColor[0] : redColor[0]), x, y, z); |
| if (tcu::hasStencilComponent(buffer.getFormat().order)) |
| buffer.setPixStencil((useBlue ? (int) blueColor[3] : (int)redColor[3]), x, y, z); |
| } |
| else |
| buffer.setPixel((useBlue ? blueColor : 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 bool isCompressed = isCompressedFormat(parms.format); |
| const deUint32 blockWidth = (isCompressed) ? getBlockWidth(parms.format) : 1u; |
| const deUint32 blockHeight = (isCompressed) ? getBlockHeight(parms.format) : 1u; |
| deUint32 rowLength = ((copyExtent.width + blockWidth-1) / blockWidth) * blockWidth; |
| deUint32 imageHeight = ((copyExtent.height + blockHeight-1) / blockHeight) * blockHeight; |
| |
| const VkBufferImageCopy copyRegion = |
| { |
| 0u, // VkDeviceSize bufferOffset; |
| rowLength, // deUint32 bufferRowLength; |
| imageHeight, // 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(), ©Regions[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 bool isCompressed = isCompressedFormat(imageParms.format); |
| const deUint32 blockWidth = (isCompressed) ? getBlockWidth(imageParms.format) : 1u; |
| const deUint32 blockHeight = (isCompressed) ? getBlockHeight(imageParms.format) : 1u; |
| deUint32 rowLength = ((imageExtent.width + blockWidth-1) / blockWidth) * blockWidth; |
| deUint32 imageHeight = ((imageExtent.height + blockHeight-1) / blockHeight) * blockHeight; |
| |
| const VkImageAspectFlags aspect = getAspectFlags(dst.getFormat()); |
| const VkBufferImageCopy copyRegion = |
| { |
| 0u, // VkDeviceSize bufferOffset; |
| rowLength, // deUint32 bufferRowLength; |
| imageHeight, // 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, ©Region); |
| 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, m_params.clearDestination ? FILL_MODE_WHITE : 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; |
| std::vector<VkImageCopy2KHR> imageCopies2KHR; |
| 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; |
| } |
| |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| imageCopies.push_back(imageCopy); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| imageCopies2KHR.push_back(convertvkImageCopyTovkImageCopy2KHR(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); |
| |
| if (m_params.clearDestination) |
| { |
| VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }; |
| VkClearColorValue clearColor; |
| |
| clearColor.float32[0] = 1.0f; |
| clearColor.float32[1] = 1.0f; |
| clearColor.float32[2] = 1.0f; |
| clearColor.float32[3] = 1.0f; |
| vk.cmdClearColorImage(*m_cmdBuffer, m_destination.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1u, &range); |
| } |
| |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| 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()); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| const VkCopyImageInfo2KHR copyImageInfo2KHR = |
| { |
| VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| m_source.get(), // VkImage srcImage; |
| m_params.src.image.operationLayout, // VkImageLayout srcImageLayout; |
| m_destination.get(), // VkImage dstImage; |
| m_params.dst.image.operationLayout, // VkImageLayout dstImageLayout; |
| (deUint32)imageCopies2KHR.size(), // uint32_t regionCount; |
| imageCopies2KHR.data() // const VkImageCopy2KHR* pRegions; |
| }; |
| |
| vk.cmdCopyImage2KHR(*m_cmdBuffer, ©ImageInfo2KHR); |
| } |
| |
| 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 (!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.extensionUse == EXTENSION_USE_COPY_COMMANDS2) |
| { |
| if (!context.isDeviceFunctionalitySupported("VK_KHR_copy_commands2")) |
| TCU_THROW(NotSupportedError, "VK_KHR_copy_commands2 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 maxImageDimension1D |
| { |
| if (m_params.src.image.imageType == VK_IMAGE_TYPE_1D && m_params.src.image.extent.width > limits.maxImageDimension1D) |
| TCU_THROW(NotSupportedError, "Requested 1D src image dimensions not supported"); |
| |
| if (m_params.dst.image.imageType == VK_IMAGE_TYPE_1D && m_params.dst.image.extent.width > limits.maxImageDimension1D) |
| TCU_THROW(NotSupportedError, "Requested 1D dst image dimensions 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; |
| std::vector<VkBufferCopy2KHR> bufferCopies2KHR; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| { |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| bufferCopies.push_back(m_params.regions[i].bufferCopy); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| bufferCopies2KHR.push_back(convertvkBufferCopyTovkBufferCopy2KHR(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); |
| |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| vk.cmdCopyBuffer(*m_cmdBuffer, m_source.get(), m_destination.get(), (deUint32)m_params.regions.size(), &bufferCopies[0]); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| const VkCopyBufferInfo2KHR copyBufferInfo2KHR = |
| { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| m_source.get(), // VkBuffer srcBuffer; |
| m_destination.get(), // VkBuffer dstBuffer; |
| (deUint32)m_params.regions.size(), // uint32_t regionCount; |
| &bufferCopies2KHR[0] // const VkBufferCopy2KHR* pRegions; |
| }; |
| |
| vk.cmdCopyBuffer2KHR(*m_cmdBuffer, ©BufferInfo2KHR); |
| } |
| |
| 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); |
| } |
| |
| virtual void checkSupport(Context& context) const |
| { |
| if (m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2) |
| { |
| if (!context.isDeviceFunctionalitySupported("VK_KHR_copy_commands2")) |
| { |
| TCU_THROW(NotSupportedError, "VK_KHR_copy_commands2 is not supported"); |
| } |
| } |
| } |
| |
| 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; |
| getArraySize(m_params.src.image) // 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; |
| std::vector<VkBufferImageCopy2KHR> bufferImageCopies2KHR; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| { |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| bufferImageCopies.push_back(m_params.regions[i].bufferImageCopy); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| bufferImageCopies2KHR.push_back(convertvkBufferImageCopyTovkBufferImageCopy2KHR(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); |
| |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| vk.cmdCopyImageToBuffer(*m_cmdBuffer, m_source.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_destination.get(), (deUint32)m_params.regions.size(), &bufferImageCopies[0]); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| const VkCopyImageToBufferInfo2KHR copyImageToBufferInfo2KHR = |
| { |
| VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| m_source.get(), // VkImage srcImage; |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout srcImageLayout; |
| m_destination.get(), // VkBuffer dstBuffer; |
| (deUint32)m_params.regions.size(), // uint32_t regionCount; |
| &bufferImageCopies2KHR[0] // const VkBufferImageCopy2KHR* pRegions; |
| }; |
| |
| vk.cmdCopyImageToBuffer2KHR(*m_cmdBuffer, ©ImageToBufferInfo2KHR); |
| } |
| |
| 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); |
| } |
| |
| virtual void checkSupport (Context& context) const |
| { |
| if ((m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2) && |
| (!context.isDeviceFunctionalitySupported("VK_KHR_copy_commands2"))) |
| { |
| TCU_THROW(NotSupportedError, "VK_KHR_copy_commands2 is not supported"); |
| } |
| } |
| |
| 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; |
| const deUint32 baseArrayLayer = region.bufferImageCopy.imageSubresource.baseArrayLayer; |
| |
| 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 + baseArrayLayer, |
| 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; |
| getArraySize(m_params.dst.image) // deUint32 arraySize; |
| } |
| }; |
| |
| // Copy from buffer to image |
| std::vector<VkBufferImageCopy> bufferImageCopies; |
| std::vector<VkBufferImageCopy2KHR> bufferImageCopies2KHR; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| { |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| bufferImageCopies.push_back(m_params.regions[i].bufferImageCopy); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| bufferImageCopies2KHR.push_back(convertvkBufferImageCopyTovkBufferImageCopy2KHR(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); |
| |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| vk.cmdCopyBufferToImage(*m_cmdBuffer, m_source.get(), m_destination.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)m_params.regions.size(), bufferImageCopies.data()); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| const VkCopyBufferToImageInfo2KHR copyBufferToImageInfo2KHR = |
| { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| m_source.get(), // VkBuffer srcBuffer; |
| m_destination.get(), // VkImage dstImage; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout dstImageLayout; |
| (deUint32)m_params.regions.size(), // uint32_t regionCount; |
| bufferImageCopies2KHR.data() // const VkBufferImageCopy2KHR* pRegions; |
| }; |
| |
| vk.cmdCopyBufferToImage2KHR(*m_cmdBuffer, ©BufferToImageInfo2KHR); |
| } |
| |
| |
| 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); |
| } |
| |
| virtual void checkSupport (Context& context) const |
| { |
| if ((m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2) && |
| (!context.isDeviceFunctionalitySupported("VK_KHR_copy_commands2"))) |
| { |
| TCU_THROW(NotSupportedError, "VK_KHR_copy_commands2 is not supported"); |
| } |
| } |
| |
| |
| 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; |
| const deUint32 baseArrayLayer = region.bufferImageCopy.imageSubresource.baseArrayLayer; |
| |
| 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 + baseArrayLayer, |
| 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; |
| std::vector<VkBufferImageCopy2KHR> bufferImageCopies2KHR; |
| 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; |
| } |
| |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| bufferImageCopies.push_back(copyData); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| bufferImageCopies2KHR.push_back(convertvkBufferImageCopyTovkBufferImageCopy2KHR(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.extensionUse == EXTENSION_USE_NONE) |
| { |
| 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]); |
| } |
| } |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| |
| if (m_params.singleCommand) |
| { |
| // Issue a single copy command with regions defined by the test. |
| const VkCopyBufferToImageInfo2KHR copyBufferToImageInfo2KHR = |
| { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| m_source.get(), // VkBuffer srcBuffer; |
| m_destination.get(), // VkImage dstImage; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout dstImageLayout; |
| (deUint32)m_params.regions.size(), // uint32_t regionCount; |
| bufferImageCopies2KHR.data() // const VkBufferImageCopy2KHR* pRegions; |
| }; |
| vk.cmdCopyBufferToImage2KHR(*m_cmdBuffer, ©BufferToImageInfo2KHR); |
| } |
| else |
| { |
| // Issue a a copy command per region defined by the test. |
| for (deUint32 i = 0; i < bufferImageCopies2KHR.size(); i++) |
| { |
| const VkCopyBufferToImageInfo2KHR copyBufferToImageInfo2KHR = |
| { |
| VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| m_source.get(), // VkBuffer srcBuffer; |
| m_destination.get(), // VkImage dstImage; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout dstImageLayout; |
| 1, // uint32_t regionCount; |
| &bufferImageCopies2KHR[i] // const VkBufferImageCopy2KHR* pRegions; |
| }; |
| // Issue a single copy command with regions defined by the test. |
| vk.cmdCopyBufferToImage2KHR(*m_cmdBuffer, ©BufferToImageInfo2KHR); |
| } |
| } |
| } |
| 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); |
| } |
| |
| virtual void checkSupport (Context& context) const |
| { |
| if ((m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2) && |
| (!context.isDeviceFunctionalitySupported("VK_KHR_copy_commands2"))) |
| { |
| TCU_THROW(NotSupportedError, "VK_KHR_copy_commands2 is not supported"); |
| } |
| } |
| |
| 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, m_params.src.image.fillMode); |
| 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, m_params.dst.image.fillMode); |
| 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; |
| std::vector<VkImageBlit2KHR> regions2KHR; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| { |
| if (m_params.extensionUse == EXTENSION_USE_NONE) |
| { |
| regions.push_back(m_params.regions[i].imageBlit); |
| } |
| else |
| { |
| DE_ASSERT(m_params.extensionUse == EXTENSION_USE_COPY_COMMANDS2); |
| regions2KHR.push_back(convertvkImageBlitTovkImageBlit2KHR(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 |