| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2015-2016 The Khronos Group Inc. |
| * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Vulkan Copies And Blitting Tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktApiCopiesAndBlittingTests.hpp" |
| |
| #include "deStringUtil.hpp" |
| #include "deUniquePtr.hpp" |
| |
| #include "tcuImageCompare.hpp" |
| #include "tcuTexture.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuVectorType.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTexLookupVerifier.hpp" |
| |
| #include "vkImageUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkPrograms.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vktTestCase.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| |
| #include <set> |
| |
| namespace vkt |
| { |
| |
| namespace api |
| { |
| |
| namespace |
| { |
| enum MirrorMode |
| { |
| MIRROR_MODE_NONE = 0, |
| MIRROR_MODE_X = (1<<0), |
| MIRROR_MODE_Y = (1<<1), |
| MIRROR_MODE_XY = MIRROR_MODE_X | MIRROR_MODE_Y, |
| |
| MIRROR_MODE_LAST |
| }; |
| |
| enum AllocationKind |
| { |
| ALLOCATION_KIND_SUBALLOCATED, |
| ALLOCATION_KIND_DEDICATED, |
| }; |
| |
| template <typename Type> |
| class BinaryCompare |
| { |
| public: |
| bool operator() (const Type& a, const Type& b) const |
| { |
| return deMemCmp(&a, &b, sizeof(Type)) < 0; |
| } |
| }; |
| |
| typedef std::set<vk::VkFormat, BinaryCompare<vk::VkFormat> > FormatSet; |
| |
| FormatSet dedicatedAllocationImageToImageFormatsToTestSet; |
| FormatSet dedicatedAllocationBlittingFormatsToTestSet; |
| |
| using namespace vk; |
| |
| VkImageAspectFlags getAspectFlags (tcu::TextureFormat format) |
| { |
| VkImageAspectFlags aspectFlag = 0; |
| aspectFlag |= (tcu::hasDepthComponent(format.order)? VK_IMAGE_ASPECT_DEPTH_BIT : 0); |
| aspectFlag |= (tcu::hasStencilComponent(format.order)? VK_IMAGE_ASPECT_STENCIL_BIT : 0); |
| |
| if (!aspectFlag) |
| aspectFlag = VK_IMAGE_ASPECT_COLOR_BIT; |
| |
| return aspectFlag; |
| } |
| |
| // 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; |
| VkImageLayout operationLayout; |
| }; |
| |
| struct TestParams |
| { |
| union Data |
| { |
| struct Buffer |
| { |
| VkDeviceSize size; |
| } buffer; |
| |
| ImageParms image; |
| } src, dst; |
| |
| std::vector<CopyRegion> regions; |
| |
| union |
| { |
| VkFilter filter; |
| VkSampleCountFlagBits samples; |
| }; |
| |
| AllocationKind allocationKind; |
| }; |
| |
| 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_2D) ? parms.extent.depth : 1u; |
| } |
| |
| inline VkExtent3D getExtent3D(const ImageParms& parms) |
| { |
| const VkExtent3D extent = |
| { |
| parms.extent.width, |
| parms.extent.height, |
| (parms.imageType == VK_IMAGE_TYPE_2D) ? 1u : parms.extent.depth |
| }; |
| return extent; |
| } |
| |
| const tcu::TextureFormat mapCombinedToDepthTransferFormat (const tcu::TextureFormat& combinedFormat) |
| { |
| tcu::TextureFormat format; |
| switch (combinedFormat.type) |
| { |
| 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: |
| format = tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT); |
| break; |
| default: |
| DE_ASSERT(false); |
| break; |
| } |
| return format; |
| } |
| |
| class CopiesAndBlittingTestInstance : public vkt::TestInstance |
| { |
| public: |
| CopiesAndBlittingTestInstance (Context& context, |
| TestParams testParams); |
| virtual tcu::TestStatus iterate (void) = 0; |
| |
| enum FillMode |
| { |
| FILL_MODE_GRADIENT = 0, |
| FILL_MODE_WHITE, |
| FILL_MODE_RED, |
| FILL_MODE_MULTISAMPLE, |
| |
| FILL_MODE_LAST |
| }; |
| |
| protected: |
| const TestParams m_params; |
| |
| Move<VkCommandPool> m_cmdPool; |
| Move<VkCommandBuffer> m_cmdBuffer; |
| Move<VkFence> m_fence; |
| de::MovePtr<tcu::TextureLevel> m_sourceTextureLevel; |
| de::MovePtr<tcu::TextureLevel> m_destinationTextureLevel; |
| de::MovePtr<tcu::TextureLevel> m_expectedTextureLevel; |
| |
| 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); |
| virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess result); |
| virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region) = 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); |
| void submitCommandsAndWait (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkQueue queue, |
| const VkCommandBuffer& cmdBuffer); |
| |
| private: |
| void uploadImageAspect (const tcu::ConstPixelBufferAccess& src, |
| const VkImage& dst, |
| const ImageParms& parms); |
| void readImageAspect (vk::VkImage src, |
| const tcu::PixelBufferAccess& dst, |
| const ImageParms& parms); |
| }; |
| |
| 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(); |
| |
| if (m_params.allocationKind == ALLOCATION_KIND_DEDICATED) |
| { |
| const std::string extensionName("VK_KHR_dedicated_allocation"); |
| |
| if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName)) |
| TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str()); |
| } |
| |
| // 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>((1 << (bits[i] - signBit)) - 1); |
| } |
| } |
| |
| if (mode == FILL_MODE_GRADIENT) |
| { |
| tcu::fillWithComponentGradients(buffer, tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), maxValue); |
| return; |
| } |
| |
| const tcu::Vec4 redColor (maxValue.x(), 0.0, 0.0, maxValue.w()); |
| const tcu::Vec4 greenColor (0.0, maxValue.y(), 0.0, maxValue.w()); |
| const tcu::Vec4 blueColor (0.0, 0.0, maxValue.z(), maxValue.w()); |
| const tcu::Vec4 whiteColor (maxValue.x(), maxValue.y(), maxValue.z(), maxValue.w()); |
| |
| for (int z = 0; z < depth; ++z) |
| for (int y = 0; y < height; ++y) |
| for (int x = 0; x < width; ++x) |
| { |
| switch (mode) |
| { |
| case FILL_MODE_WHITE: |
| if (tcu::isCombinedDepthStencilType(buffer.getFormat().type)) |
| { |
| buffer.setPixDepth(1.0f, x, y, z); |
| if (tcu::hasStencilComponent(buffer.getFormat().order)) |
| buffer.setPixStencil(255, x, y, z); |
| } |
| else |
| buffer.setPixel(whiteColor, x, y, z); |
| break; |
| |
| case FILL_MODE_RED: |
| if (tcu::isCombinedDepthStencilType(buffer.getFormat().type)) |
| { |
| buffer.setPixDepth(redColor[x % 4], x, y, z); |
| if (tcu::hasStencilComponent(buffer.getFormat().order)) |
| buffer.setPixStencil(255 * (int)redColor[y % 4], x, y, z); |
| } |
| else |
| buffer.setPixel(redColor, x, y, z); |
| break; |
| |
| case FILL_MODE_MULTISAMPLE: |
| buffer.setPixel((x == y) ? tcu::Vec4(0.0, 0.5, 0.5, 1.0) : ((x > y) ? 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); |
| flushMappedMemoryRange(vk, vkDevice, bufferAlloc.getMemory(), bufferAlloc.getOffset(), bufferSize); |
| } |
| |
| void CopiesAndBlittingTestInstance::uploadImageAspect (const tcu::ConstPixelBufferAccess& imageAccess, const VkImage& image, const ImageParms& parms) |
| { |
| 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); |
| |
| // 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 = getAspectFlags(mapVkFormat(parms.format)); |
| const bool skipPreImageBarrier = 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; |
| 1u, // 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; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| arraySize, // deUint32 arraySize; |
| } |
| }; |
| |
| const VkBufferImageCopy copyRegion = |
| { |
| 0u, // VkDeviceSize bufferOffset; |
| (deUint32)imageAccess.getWidth(), // deUint32 bufferRowLength; |
| (deUint32)imageAccess.getHeight(), // deUint32 bufferImageHeight; |
| { |
| getAspectFlags(imageAccess.getFormat()), // VkImageAspectFlags aspect; |
| 0u, // deUint32 mipLevel; |
| 0u, // deUint32 baseArrayLayer; |
| arraySize, // deUint32 layerCount; |
| }, // VkImageSubresourceLayers imageSubresource; |
| { 0, 0, 0 }, // VkOffset3D imageOffset; |
| imageExtent // VkExtent3D imageExtent; |
| }; |
| |
| // Write buffer data |
| deMemcpy(bufferAlloc->getHostPtr(), imageAccess.getDataPtr(), bufferSize); |
| flushMappedMemoryRange(vk, vkDevice, bufferAlloc->getMemory(), bufferAlloc->getOffset(), bufferSize); |
| |
| // Copy buffer to image |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| 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, 1u, ©Region); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier); |
| VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); |
| |
| submitCommandsAndWait(vk, vkDevice, queue, *m_cmdBuffer); |
| } |
| |
| void CopiesAndBlittingTestInstance::uploadImage (const tcu::ConstPixelBufferAccess& src, VkImage dst, const ImageParms& parms) |
| { |
| 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); |
| } |
| |
| tcu::TestStatus CopiesAndBlittingTestInstance::checkTestResult (tcu::ConstPixelBufferAccess result) |
| { |
| const tcu::ConstPixelBufferAccess expected = m_expectedTextureLevel->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::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 = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth())); |
| tcu::copy(m_expectedTextureLevel->getAccess(), dst); |
| |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| copyRegionToTextureLevel(src, m_expectedTextureLevel->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 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); |
| |
| // 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)); |
| flushMappedMemoryRange(vk, device, bufferAlloc->getMemory(), bufferAlloc->getOffset(), pixelDataSize); |
| } |
| |
| // Barriers for copying image to buffer |
| const VkImageAspectFlags formatAspect = getAspectFlags(mapVkFormat(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; |
| 0u, // 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; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| getArraySize(imageParms) // deUint32 arraySize; |
| } // VkImageSubresourceRange subresourceRange; |
| }; |
| |
| // Copy image to buffer |
| const VkImageAspectFlags aspect = getAspectFlags(dst.getFormat()); |
| const VkBufferImageCopy copyRegion = |
| { |
| 0u, // VkDeviceSize bufferOffset; |
| (deUint32)dst.getWidth(), // deUint32 bufferRowLength; |
| (deUint32)dst.getHeight(), // deUint32 bufferImageHeight; |
| { |
| aspect, // VkImageAspectFlags aspect; |
| 0u, // deUint32 mipLevel; |
| 0u, // deUint32 baseArrayLayer; |
| getArraySize(imageParms), // deUint32 layerCount; |
| }, // VkImageSubresourceLayers imageSubresource; |
| { 0, 0, 0 }, // VkOffset3D imageOffset; |
| imageExtent // VkExtent3D imageExtent; |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| 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); |
| VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); |
| |
| submitCommandsAndWait(vk, device, queue, *m_cmdBuffer); |
| |
| // Read buffer data |
| invalidateMappedMemoryRange(vk, device, bufferAlloc->getMemory(), bufferAlloc->getOffset(), pixelDataSize); |
| tcu::copy(dst, tcu::ConstPixelBufferAccess(dst.getFormat(), dst.getSize(), bufferAlloc->getHostPtr())); |
| } |
| |
| void CopiesAndBlittingTestInstance::submitCommandsAndWait (const DeviceInterface& vk, const VkDevice device, const VkQueue queue, const VkCommandBuffer& cmdBuffer) |
| { |
| const VkSubmitInfo submitInfo = |
| { |
| VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // deUint32 waitSemaphoreCount; |
| DE_NULL, // const VkSemaphore* pWaitSemaphores; |
| (const VkPipelineStageFlags*)DE_NULL, |
| 1u, // deUint32 commandBufferCount; |
| &cmdBuffer, // const VkCommandBuffer* pCommandBuffers; |
| 0u, // deUint32 signalSemaphoreCount; |
| DE_NULL // const VkSemaphore* pSignalSemaphores; |
| }; |
| |
| VK_CHECK(vk.resetFences(device, 1, &m_fence.get())); |
| VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence)); |
| VK_CHECK(vk.waitForFences(device, 1, &m_fence.get(), true, ~(0ull) /* infinity */)); |
| } |
| |
| de::MovePtr<tcu::TextureLevel> CopiesAndBlittingTestInstance::readImage (vk::VkImage image, |
| const ImageParms& parms) |
| { |
| const tcu::TextureFormat imageFormat = mapVkFormat(parms.format); |
| de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(imageFormat, parms.extent.width, parms.extent.height, 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); |
| |
| 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); |
| |
| 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); |
| }; |
| |
| 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(); |
| |
| 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 (std::find(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), "VK_KHR_maintenance1") == context.getDeviceExtensions().end()) |
| TCU_THROW(NotSupportedError, "Extension VK_KHR_maintenance1 not supported"); |
| } |
| |
| 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"); |
| } |
| |
| // Create source image |
| { |
| const VkImageCreateInfo sourceImageParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // 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; |
| 0u, // 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 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, |
| (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_RED); |
| m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dstTcuFormat, |
| (int)m_params.dst.image.extent.width, |
| (int)m_params.dst.image.extent.height, |
| (int)m_params.dst.image.extent.depth)); |
| generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth, FILL_MODE_GRADIENT); |
| generateExpectedResult(); |
| |
| uploadImage(m_sourceTextureLevel->getAccess(), m_source.get(), m_params.src.image); |
| uploadImage(m_destinationTextureLevel->getAccess(), m_destination.get(), m_params.dst.image); |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| |
| std::vector<VkImageCopy> imageCopies; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| imageCopies.push_back(m_params.regions[i].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; |
| } |
| }, |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, DE_LENGTH_OF_ARRAY(imageBarriers), imageBarriers); |
| vk.cmdCopyImage(*m_cmdBuffer, m_source.get(), m_params.src.image.operationLayout, m_destination.get(), m_params.dst.image.operationLayout, (deUint32)m_params.regions.size(), imageCopies.data()); |
| VK_CHECK(vk.endCommandBuffer(*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->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->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->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->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) |
| { |
| 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; |
| 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); |
| } |
| 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); |
| Move<VkBuffer> m_source; |
| de::MovePtr<Allocation> m_sourceBufferAlloc; |
| Move<VkBuffer> m_destination; |
| de::MovePtr<Allocation> m_destinationBufferAlloc; |
| }; |
| |
| CopyBufferToBuffer::CopyBufferToBuffer (Context& context, TestParams params) |
| : CopiesAndBlittingTestInstance (context, params) |
| { |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const VkPhysicalDevice vkPhysDevice = context.getPhysicalDevice(); |
| const VkDevice vkDevice = context.getDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| Allocator& memAlloc = context.getDefaultAllocator(); |
| |
| // Create source buffer |
| { |
| const VkBufferCreateInfo sourceBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| m_params.src.buffer.size, // VkDeviceSize size; |
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyIndexCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| m_source = createBuffer(vk, vkDevice, &sourceBufferParams); |
| m_sourceBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind); |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *m_source, m_sourceBufferAlloc->getMemory(), m_sourceBufferAlloc->getOffset())); |
| } |
| |
| // Create destination buffer |
| { |
| const VkBufferCreateInfo destinationBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| m_params.dst.buffer.size, // VkDeviceSize size; |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyIndexCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| m_destination = createBuffer(vk, vkDevice, &destinationBufferParams); |
| m_destinationBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind); |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *m_destination, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset())); |
| } |
| } |
| |
| tcu::TestStatus CopyBufferToBuffer::iterate (void) |
| { |
| const int srcLevelWidth = (int)(m_params.src.buffer.size/4); // Here the format is VK_FORMAT_R32_UINT, we need to divide the buffer size by 4 |
| m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R32_UINT), srcLevelWidth, 1)); |
| generateBuffer(m_sourceTextureLevel->getAccess(), srcLevelWidth, 1, 1, FILL_MODE_RED); |
| |
| const int dstLevelWidth = (int)(m_params.dst.buffer.size/4); |
| m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R32_UINT), dstLevelWidth, 1)); |
| generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1, FILL_MODE_WHITE); |
| |
| generateExpectedResult(); |
| |
| uploadBuffer(m_sourceTextureLevel->getAccess(), *m_sourceBufferAlloc); |
| uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc); |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| |
| const VkBufferMemoryBarrier srcBufferBarrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_source, // VkBuffer buffer; |
| 0u, // VkDeviceSize offset; |
| m_params.src.buffer.size // VkDeviceSize size; |
| }; |
| |
| const VkBufferMemoryBarrier dstBufferBarrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_destination, // VkBuffer buffer; |
| 0u, // VkDeviceSize offset; |
| m_params.dst.buffer.size // VkDeviceSize size; |
| }; |
| |
| std::vector<VkBufferCopy> bufferCopies; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| bufferCopies.push_back(m_params.regions[i].bufferCopy); |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &srcBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL); |
| vk.cmdCopyBuffer(*m_cmdBuffer, m_source.get(), m_destination.get(), (deUint32)m_params.regions.size(), &bufferCopies[0]); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL); |
| VK_CHECK(vk.endCommandBuffer(*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)); |
| invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_params.dst.buffer.size); |
| 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) |
| { |
| deMemcpy((deUint8*) dst.getDataPtr() + region.bufferCopy.dstOffset, |
| (deUint8*) src.getDataPtr() + region.bufferCopy.srcOffset, |
| (size_t)region.bufferCopy.size); |
| } |
| |
| class BufferToBufferTestCase : public vkt::TestCase |
| { |
| public: |
| BufferToBufferTestCase (tcu::TestContext& testCtx, |
| const std::string& name, |
| const std::string& description, |
| const TestParams params) |
| : vkt::TestCase (testCtx, name, description) |
| , m_params (params) |
| {} |
| |
| virtual TestInstance* createInstance (Context& context) const |
| { |
| return new CopyBufferToBuffer(context, m_params); |
| } |
| private: |
| TestParams m_params; |
| }; |
| |
| // Copy from image to buffer. |
| |
| class CopyImageToBuffer : public CopiesAndBlittingTestInstance |
| { |
| public: |
| CopyImageToBuffer (Context& context, |
| TestParams testParams); |
| virtual tcu::TestStatus iterate (void); |
| private: |
| virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region); |
| |
| 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; |
| 0u, // VkImageCreateFlags flags; |
| m_params.src.image.imageType, // VkImageType imageType; |
| m_params.src.image.format, // VkFormat format; |
| getExtent3D(m_params.src.image), // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| getArraySize(m_params.src.image), // deUint32 arraySize; |
| VK_SAMPLE_COUNT_1_BIT, // deUint32 samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| m_source = createImage(vk, vkDevice, &sourceImageParams); |
| m_sourceImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_source, MemoryRequirement::Any, memAlloc, m_params.allocationKind); |
| VK_CHECK(vk.bindImageMemory(vkDevice, *m_source, m_sourceImageAlloc->getMemory(), m_sourceImageAlloc->getOffset())); |
| } |
| |
| // Create destination buffer |
| { |
| const VkBufferCreateInfo destinationBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| m_bufferSize, // VkDeviceSize size; |
| VK_BUFFER_USAGE_TRANSFER_DST_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyIndexCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| m_destination = createBuffer(vk, vkDevice, &destinationBufferParams); |
| m_destinationBufferAlloc = allocateBuffer(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::HostVisible, memAlloc, m_params.allocationKind); |
| VK_CHECK(vk.bindBufferMemory(vkDevice, *m_destination, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset())); |
| } |
| } |
| |
| tcu::TestStatus CopyImageToBuffer::iterate (void) |
| { |
| m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, |
| m_params.src.image.extent.width, |
| m_params.src.image.extent.height, |
| m_params.src.image.extent.depth)); |
| generateBuffer(m_sourceTextureLevel->getAccess(), m_params.src.image.extent.width, m_params.src.image.extent.height, m_params.src.image.extent.depth); |
| m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, (int)m_params.dst.buffer.size, 1)); |
| generateBuffer(m_destinationTextureLevel->getAccess(), (int)m_params.dst.buffer.size, 1, 1); |
| |
| generateExpectedResult(); |
| |
| uploadImage(m_sourceTextureLevel->getAccess(), *m_source, m_params.src.image); |
| uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc); |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| |
| // Barriers for copying image to buffer |
| const VkImageMemoryBarrier imageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_source, // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| getAspectFlags(m_textureFormat), // VkImageAspectFlags aspectMask; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| 1u // deUint32 arraySize; |
| } |
| }; |
| |
| const VkBufferMemoryBarrier bufferBarrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_destination, // VkBuffer buffer; |
| 0u, // VkDeviceSize offset; |
| m_bufferSize // VkDeviceSize size; |
| }; |
| |
| // Copy from image to buffer |
| std::vector<VkBufferImageCopy> bufferImageCopies; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| bufferImageCopies.push_back(m_params.regions[i].bufferImageCopy); |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier); |
| vk.cmdCopyImageToBuffer(*m_cmdBuffer, m_source.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_destination.get(), (deUint32)m_params.regions.size(), &bufferImageCopies[0]); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &bufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL); |
| VK_CHECK(vk.endCommandBuffer(*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)); |
| invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_bufferSize); |
| tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr())); |
| |
| return checkTestResult(resultLevel->getAccess()); |
| } |
| |
| class CopyImageToBufferTestCase : public vkt::TestCase |
| { |
| public: |
| CopyImageToBufferTestCase (tcu::TestContext& testCtx, |
| const std::string& name, |
| const std::string& description, |
| const TestParams params) |
| : vkt::TestCase (testCtx, name, description) |
| , m_params (params) |
| {} |
| |
| virtual TestInstance* createInstance (Context& context) const |
| { |
| return new CopyImageToBuffer(context, m_params); |
| } |
| private: |
| TestParams m_params; |
| }; |
| |
| void CopyImageToBuffer::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region) |
| { |
| deUint32 rowLength = region.bufferImageCopy.bufferRowLength; |
| if (!rowLength) |
| rowLength = region.bufferImageCopy.imageExtent.width; |
| |
| deUint32 imageHeight = region.bufferImageCopy.bufferImageHeight; |
| if (!imageHeight) |
| imageHeight = region.bufferImageCopy.imageExtent.height; |
| |
| const int texelSize = src.getFormat().getPixelSize(); |
| const VkExtent3D extent = region.bufferImageCopy.imageExtent; |
| const VkOffset3D srcOffset = region.bufferImageCopy.imageOffset; |
| const int texelOffset = (int) region.bufferImageCopy.bufferOffset / texelSize; |
| |
| for (deUint32 z = 0; z < extent.depth; z++) |
| { |
| for (deUint32 y = 0; y < extent.height; y++) |
| { |
| int texelIndex = texelOffset + (z * imageHeight + y) * rowLength; |
| const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, srcOffset.x, srcOffset.y + y, srcOffset.z + z, |
| region.bufferImageCopy.imageExtent.width, 1, 1); |
| const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dst, texelIndex, 0, region.bufferImageCopy.imageExtent.width, 1); |
| tcu::copy(dstSubRegion, srcSubRegion); |
| } |
| } |
| } |
| |
| // Copy from buffer to image. |
| |
| class CopyBufferToImage : public CopiesAndBlittingTestInstance |
| { |
| public: |
| CopyBufferToImage (Context& context, |
| TestParams testParams); |
| virtual tcu::TestStatus iterate (void); |
| private: |
| virtual void copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region); |
| |
| 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; |
| 0u, // VkImageCreateFlags flags; |
| m_params.dst.image.imageType, // VkImageType imageType; |
| m_params.dst.image.format, // VkFormat format; |
| getExtent3D(m_params.dst.image), // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| getArraySize(m_params.dst.image), // deUint32 arraySize; |
| VK_SAMPLE_COUNT_1_BIT, // deUint32 samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT | |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| m_destination = createImage(vk, vkDevice, &destinationImageParams); |
| m_destinationImageAlloc = allocateImage(vki, vk, vkPhysDevice, vkDevice, *m_destination, MemoryRequirement::Any, memAlloc, m_params.allocationKind); |
| VK_CHECK(vk.bindImageMemory(vkDevice, *m_destination, m_destinationImageAlloc->getMemory(), m_destinationImageAlloc->getOffset())); |
| } |
| } |
| |
| tcu::TestStatus CopyBufferToImage::iterate (void) |
| { |
| m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, (int)m_params.src.buffer.size, 1)); |
| generateBuffer(m_sourceTextureLevel->getAccess(), (int)m_params.src.buffer.size, 1, 1); |
| m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(m_textureFormat, |
| m_params.dst.image.extent.width, |
| m_params.dst.image.extent.height, |
| m_params.dst.image.extent.depth)); |
| |
| generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth); |
| |
| generateExpectedResult(); |
| |
| uploadBuffer(m_sourceTextureLevel->getAccess(), *m_sourceBufferAlloc); |
| uploadImage(m_destinationTextureLevel->getAccess(), *m_destination, m_params.dst.image); |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| |
| const VkImageMemoryBarrier imageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| *m_destination, // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| getAspectFlags(m_textureFormat), // VkImageAspectFlags aspectMask; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| 1u // deUint32 arraySize; |
| } |
| }; |
| |
| // Copy from buffer to image |
| std::vector<VkBufferImageCopy> bufferImageCopies; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| bufferImageCopies.push_back(m_params.regions[i].bufferImageCopy); |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier); |
| vk.cmdCopyBufferToImage(*m_cmdBuffer, m_source.get(), m_destination.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (deUint32)m_params.regions.size(), bufferImageCopies.data()); |
| VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); |
| |
| submitCommandsAndWait (vk, vkDevice, queue, *m_cmdBuffer); |
| |
| de::MovePtr<tcu::TextureLevel> resultLevel = readImage(*m_destination, m_params.dst.image); |
| |
| return checkTestResult(resultLevel->getAccess()); |
| } |
| |
| class CopyBufferToImageTestCase : public vkt::TestCase |
| { |
| public: |
| CopyBufferToImageTestCase (tcu::TestContext& testCtx, |
| const std::string& name, |
| const std::string& description, |
| const TestParams params) |
| : vkt::TestCase (testCtx, name, description) |
| , m_params (params) |
| {} |
| |
| virtual ~CopyBufferToImageTestCase (void) {} |
| |
| virtual TestInstance* createInstance (Context& context) const |
| { |
| return new CopyBufferToImage(context, m_params); |
| } |
| private: |
| TestParams m_params; |
| }; |
| |
| void CopyBufferToImage::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region) |
| { |
| deUint32 rowLength = region.bufferImageCopy.bufferRowLength; |
| if (!rowLength) |
| rowLength = region.bufferImageCopy.imageExtent.width; |
| |
| deUint32 imageHeight = region.bufferImageCopy.bufferImageHeight; |
| if (!imageHeight) |
| imageHeight = region.bufferImageCopy.imageExtent.height; |
| |
| const int texelSize = dst.getFormat().getPixelSize(); |
| const VkExtent3D extent = region.bufferImageCopy.imageExtent; |
| const VkOffset3D dstOffset = region.bufferImageCopy.imageOffset; |
| const int texelOffset = (int) region.bufferImageCopy.bufferOffset / texelSize; |
| |
| for (deUint32 z = 0; z < extent.depth; z++) |
| { |
| for (deUint32 y = 0; y < extent.height; y++) |
| { |
| int texelIndex = texelOffset + (z * imageHeight + y) * rowLength; |
| const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, texelIndex, 0, region.bufferImageCopy.imageExtent.width, 1); |
| const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dst, dstOffset.x, dstOffset.y + y, dstOffset.z + z, |
| region.bufferImageCopy.imageExtent.width, 1, 1); |
| tcu::copy(dstSubRegion, srcSubRegion); |
| } |
| } |
| } |
| |
| // 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); |
| virtual void generateExpectedResult (void); |
| private: |
| bool checkLinearFilteredResult (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(); |
| |
| VkImageFormatProperties properties; |
| if ((context.getInstanceInterface().getPhysicalDeviceImageFormatProperties (context.getPhysicalDevice(), |
| m_params.src.image.format, |
| VK_IMAGE_TYPE_2D, |
| 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, |
| VK_IMAGE_TYPE_2D, |
| VK_IMAGE_TILING_OPTIMAL, |
| VK_IMAGE_USAGE_TRANSFER_DST_BIT, |
| 0, |
| &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED)) |
| { |
| TCU_THROW(NotSupportedError, "Format not supported"); |
| } |
| |
| VkFormatProperties srcFormatProperties; |
| context.getInstanceInterface().getPhysicalDeviceFormatProperties(context.getPhysicalDevice(), m_params.src.image.format, &srcFormatProperties); |
| if (!(srcFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) |
| { |
| TCU_THROW(NotSupportedError, "Format feature blit source not supported"); |
| } |
| |
| VkFormatProperties dstFormatProperties; |
| context.getInstanceInterface().getPhysicalDeviceFormatProperties(context.getPhysicalDevice(), m_params.dst.image.format, &dstFormatProperties); |
| if (!(dstFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) |
| { |
| TCU_THROW(NotSupportedError, "Format feature blit destination not supported"); |
| } |
| |
| if (m_params.filter == VK_FILTER_LINEAR) |
| { |
| if (!(srcFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) |
| TCU_THROW(NotSupportedError, "Source format feature sampled image filter linear not supported"); |
| if (!(dstFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) |
| TCU_THROW(NotSupportedError, "Destination format feature sampled image filter linear not supported"); |
| } |
| |
| // Create source image |
| { |
| const VkImageCreateInfo sourceImageParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // 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; |
| 0u, // 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 BlittingImages::iterate (void) |
| { |
| const tcu::TextureFormat srcTcuFormat = mapVkFormat(m_params.src.image.format); |
| const tcu::TextureFormat dstTcuFormat = mapVkFormat(m_params.dst.image.format); |
| m_sourceTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(srcTcuFormat, |
| m_params.src.image.extent.width, |
| m_params.src.image.extent.height, |
| m_params.src.image.extent.depth)); |
| generateBuffer(m_sourceTextureLevel->getAccess(), m_params.src.image.extent.width, m_params.src.image.extent.height, m_params.src.image.extent.depth, FILL_MODE_GRADIENT); |
| m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dstTcuFormat, |
| (int)m_params.dst.image.extent.width, |
| (int)m_params.dst.image.extent.height, |
| (int)m_params.dst.image.extent.depth)); |
| generateBuffer(m_destinationTextureLevel->getAccess(), m_params.dst.image.extent.width, m_params.dst.image.extent.height, m_params.dst.image.extent.depth, FILL_MODE_WHITE); |
| generateExpectedResult(); |
| |
| uploadImage(m_sourceTextureLevel->getAccess(), m_source.get(), m_params.src.image); |
| uploadImage(m_destinationTextureLevel->getAccess(), m_destination.get(), m_params.dst.image); |
| |
| const DeviceInterface& vk = m_context.getDeviceInterface(); |
| const VkDevice vkDevice = m_context.getDevice(); |
| const VkQueue queue = m_context.getUniversalQueue(); |
| |
| std::vector<VkImageBlit> regions; |
| for (deUint32 i = 0; i < m_params.regions.size(); i++) |
| regions.push_back(m_params.regions[i].imageBlit); |
| |
| // Barriers for copying image to buffer |
| const VkImageMemoryBarrier srcImageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout; |
| m_params.src.image.operationLayout, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| m_source.get(), // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| getAspectFlags(srcTcuFormat), // VkImageAspectFlags aspectMask; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| 1u // deUint32 arraySize; |
| } |
| }; |
| |
| const VkImageMemoryBarrier dstImageBarrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask; |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout; |
| m_params.dst.image.operationLayout, // VkImageLayout newLayout; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; |
| m_destination.get(), // VkImage image; |
| { // VkImageSubresourceRange subresourceRange; |
| getAspectFlags(dstTcuFormat), // VkImageAspectFlags aspectMask; |
| 0u, // deUint32 baseMipLevel; |
| 1u, // deUint32 mipLevels; |
| 0u, // deUint32 baseArraySlice; |
| 1u // deUint32 arraySize; |
| } |
| }; |
| |
| const VkCommandBufferBeginInfo cmdBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; |
| (const VkCommandBufferInheritanceInfo*)DE_NULL, |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &srcImageBarrier); |
| vk.cmdBlitImage(*m_cmdBuffer, m_source.get(), m_params.src.image.operationLayout, m_destination.get(), m_params.dst.image.operationLayout, (deUint32)m_params.regions.size(), ®ions[0], m_params.filter); |
| vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &dstImageBarrier); |
| VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); |
| submitCommandsAndWait(vk, vkDevice, queue, *m_cmdBuffer); |
| |
| de::MovePtr<tcu::TextureLevel> resultTextureLevel = readImage(*m_destination, m_params.dst.image); |
| |
| return checkTestResult(resultTextureLevel->getAccess()); |
| } |
| |
| static float calculateFloatConversionError (int srcBits) |
| { |
| if (srcBits > 0) |
| { |
| const int clampedBits = de::clamp<int>(srcBits, 0, 32); |
| const float srcMaxValue = de::max((float)(1ULL<<clampedBits) - 1.0f, 1.0f); |
| const float error = 1.0f / srcMaxValue; |
| |
| return de::clamp<float>(error, 0.0f, 1.0f); |
| } |
| else |
| return 1.0f; |
| } |
| |
| tcu::Vec4 getFormatThreshold (const tcu::TextureFormat& format) |
| { |
| tcu::Vec4 threshold(0.01f); |
| |
| switch (format.type) |
| { |
| case tcu::TextureFormat::HALF_FLOAT: |
| threshold = tcu::Vec4(0.005f); |
| break; |
| |
| case tcu::TextureFormat::FLOAT: |
| case tcu::TextureFormat::FLOAT64: |
| threshold = tcu::Vec4(0.001f); |
| break; |
| |
| case tcu::TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: |
| threshold = tcu::Vec4(0.02f, 0.02f, 0.0625f, 1.0f); |
| break; |
| |
| case tcu::TextureFormat::UNSIGNED_INT_999_E5_REV: |
| threshold = tcu::Vec4(0.05f, 0.05f, 0.05f, 1.0f); |
| break; |
| |
| default: |
| const tcu::IVec4 bits = tcu::getTextureFormatMantissaBitDepth(format); |
| threshold = tcu::Vec4(calculateFloatConversionError(bits.x()), |
| calculateFloatConversionError(bits.y()), |
| calculateFloatConversionError(bits.z()), |
| calculateFloatConversionError(bits.w())); |
| } |
| |
| // Return value matching the channel order specified by the format |
| if (format.order == tcu::TextureFormat::BGR || format.order == tcu::TextureFormat::BGRA) |
| return threshold.swizzle(2, 1, 0, 3); |
| else |
| return threshold; |
| } |
| |
| bool BlittingImages::checkLinearFilteredResult (const tcu::ConstPixelBufferAccess& result, |
| const tcu::ConstPixelBufferAccess& clampedExpected, |
| const tcu::ConstPixelBufferAccess& unclampedExpected, |
| const tcu::TextureFormat& srcFormat) |
| { |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| const tcu::TextureFormat dstFormat = result.getFormat(); |
| bool isOk = false; |
| |
| log << tcu::TestLog::Section("ClampedSourceImage", "Region with clamped edges on source image."); |
| |
| if (isFloatFormat(dstFormat)) |
| { |
| const bool srcIsSRGB = tcu::isSRGB(srcFormat); |
| const tcu::Vec4 srcMaxDiff = getFormatThreshold(srcFormat) * tcu::Vec4(srcIsSRGB ? 2.0f : 1.0f); |
| const tcu::Vec4 dstMaxDiff = getFormatThreshold(dstFormat); |
| const tcu::Vec4 threshold = tcu::max(srcMaxDiff, dstMaxDiff); |
| |
| isOk = tcu::floatThresholdCompare(log, "Compare", "Result comparsion", clampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT); |
| log << tcu::TestLog::EndSection; |
| |
| if (!isOk) |
| { |
| log << tcu::TestLog::Section("NonClampedSourceImage", "Region with non-clamped edges on source image."); |
| isOk = tcu::floatThresholdCompare(log, "Compare", "Result comparsion", unclampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT); |
| log << tcu::TestLog::EndSection; |
| } |
| } |
| else |
| { |
| tcu::UVec4 threshold; |
| // Calculate threshold depending on channel width of destination format. |
| const tcu::IVec4 bitDepth = tcu::getTextureFormatBitDepth(dstFormat); |
| for (deUint32 i = 0; i < 4; ++i) |
| threshold[i] = de::max( (0x1 << bitDepth[i]) / 256, 1); |
| |
| isOk = tcu::intThresholdCompare(log, "Compare", "Result comparsion", clampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT); |
| log << tcu::TestLog::EndSection; |
| |
| if (!isOk) |
| { |
| log << tcu::TestLog::Section("NonClampedSourceImage", "Region with non-clamped edges on source image."); |
| isOk = tcu::intThresholdCompare(log, "Compare", "Result comparsion", unclampedExpected, result, threshold, tcu::COMPARE_LOG_RESULT); |
| log << tcu::TestLog::EndSection; |
| } |
| } |
| |
| return isOk; |
| } |
| |
| //! Utility to encapsulate coordinate computation and loops. |
| struct CompareEachPixelInEachRegion |
| { |
| virtual ~CompareEachPixelInEachRegion (void) {} |
| virtual bool compare (const void* pUserData, const int x, const int y, const tcu::Vec2& srcNormCoord) const = 0; |
| |
| bool forEach (const void* pUserData, |
| const std::vector<CopyRegion>& regions, |
| const int sourceWidth, |
| const int sourceHeight, |
| const tcu::PixelBufferAccess& errorMask) const |
| { |
| bool compareOk = true; |
| |
| for (std::vector<CopyRegion>::const_iterator regionIter = regions.begin(); regionIter != regions.end(); ++regionIter) |
| { |
| const VkImageBlit& blit = regionIter->imageBlit; |
| |
| const int dx = deSign32(blit.dstOffsets[1].x - blit.dstOffsets[0].x); |
| const int dy = deSign32(blit.dstOffsets[1].y - blit.dstOffsets[0].y); |
| const float xScale = static_cast<float>(blit.srcOffsets[1].x - blit.srcOffsets[0].x) / static_cast<float>(blit.dstOffsets[1].x - blit.dstOffsets[0].x); |
| const float yScale = static_cast<float>(blit.srcOffsets[1].y - blit.srcOffsets[0].y) / static_cast<float>(blit.dstOffsets[1].y - blit.dstOffsets[0].y); |
| const float srcInvW = 1.0f / static_cast<float>(sourceWidth); |
| const float srcInvH = 1.0f / static_cast<float>(sourceHeight); |
| |
| for (int y = blit.dstOffsets[0].y; y < blit.dstOffsets[1].y; y += dy) |
| for (int x = blit.dstOffsets[0].x; x < blit.dstOffsets[1].x; x += dx) |
| { |
| const tcu::Vec2 srcNormCoord |
| ( |
| (xScale * (static_cast<float>(x - blit.dstOffsets[0].x) + 0.5f) + static_cast<float>(blit.srcOffsets[0].x)) * srcInvW, |
| (yScale * (static_cast<float>(y - blit.dstOffsets[0].y) + 0.5f) + static_cast<float>(blit.srcOffsets[0].y)) * srcInvH |
| ); |
| |
| if (!compare(pUserData, x, y, srcNormCoord)) |
| { |
| errorMask.setPixel(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y); |
| compareOk = false; |
| } |
| } |
| } |
| return compareOk; |
| } |
| }; |
| |
| tcu::Vec4 getFloatOrFixedPointFormatThreshold (const tcu::TextureFormat& format) |
| { |
| const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); |
| const tcu::IVec4 bitDepth = tcu::getTextureFormatBitDepth(format); |
| |
| if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) |
| { |
| return getFormatThreshold(format); |
| } |
| else if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT || |
| channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT) |
| { |
| const bool isSigned = (channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT); |
| const float range = isSigned ? 1.0f - (-1.0f) |
| : 1.0f - 0.0f; |
| |
| tcu::Vec4 v; |
| for (int i = 0; i < 4; ++i) |
| { |
| if (bitDepth[i] == 0) |
| v[i] = 1.0f; |
| else |
| v[i] = range / static_cast<float>((1 << bitDepth[i]) - 1); |
| } |
| return v; |
| } |
| else |
| { |
| DE_ASSERT(0); |
| return tcu::Vec4(); |
| } |
| } |
| |
| bool floatNearestBlitCompare (const tcu::ConstPixelBufferAccess& source, |
| const tcu::ConstPixelBufferAccess& result, |
| const tcu::PixelBufferAccess& errorMask, |
| const std::vector<CopyRegion>& regions) |
| { |
| const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST); |
| tcu::LookupPrecision precision; |
| |
| { |
| const tcu::IVec4 dstBitDepth = tcu::getTextureFormatBitDepth(result.getFormat()); |
| const tcu::Vec4 srcMaxDiff = getFloatOrFixedPointFormatThreshold(source.getFormat()); |
| const tcu::Vec4 dstMaxDiff = getFloatOrFixedPointFormatThreshold(result.getFormat()); |
| |
| precision.colorMask = tcu::notEqual(dstBitDepth, tcu::IVec4(0)); |
| precision.colorThreshold = tcu::max(srcMaxDiff, dstMaxDiff); |
| } |
| |
| const struct Capture |
| { |
| const tcu::ConstPixelBufferAccess& source; |
| const tcu::ConstPixelBufferAccess& result; |
| const tcu::Sampler& sampler; |
| const tcu::LookupPrecision& precision; |
| const bool isSRGB; |
| } capture = |
| { |
| source, result, sampler, precision, tcu::isSRGB(result.getFormat()) |
| }; |
| |
| const struct Loop : CompareEachPixelInEachRegion |
| { |
| Loop (void) {} |
| |
| bool compare (const void* pUserData, const int x, const int y, const tcu::Vec2& srcNormCoord) const |
| { |
| const Capture& c = *static_cast<const Capture*>(pUserData); |
| const tcu::TexLookupScaleMode lookupScaleDontCare = tcu::TEX_LOOKUP_SCALE_MINIFY; |
| tcu::Vec4 dstColor = c.result.getPixel(x, y); |
| |
| // TexLookupVerifier performs a conversion to linear space, so we have to as well |
| if (c.isSRGB) |
| dstColor = tcu::sRGBToLinear(dstColor); |
| |
| return tcu::isLevel2DLookupResultValid(c.source, c.sampler, lookupScaleDontCare, c.precision, srcNormCoord, 0, dstColor); |
| } |
| } loop; |
| |
| return loop.forEach(&capture, regions, source.getWidth(), source.getHeight(), errorMask); |
| } |
| |
| bool intNearestBlitCompare (const tcu::ConstPixelBufferAccess& source, |
| const tcu::ConstPixelBufferAccess& result, |
| const tcu::PixelBufferAccess& errorMask, |
| const std::vector<CopyRegion>& regions) |
| { |
| const tcu::Sampler sampler (tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST); |
| tcu::IntLookupPrecision precision; |
| |
| { |
| const tcu::IVec4 srcBitDepth = tcu::getTextureFormatBitDepth(source.getFormat()); |
| const tcu::IVec4 dstBitDepth = tcu::getTextureFormatBitDepth(result.getFormat()); |
| |
| for (deUint32 i = 0; i < 4; ++i) { |
| precision.colorThreshold[i] = de::max(de::max(srcBitDepth[i] / 8, dstBitDepth[i] / 8), 1); |
| precision.colorMask[i] = dstBitDepth[i] != 0; |
| } |
| } |
| |
| // Prepare a source image with a matching (converted) pixel format. Ideally, we would've used a wrapper that |
| // does the conversion on the fly without wasting memory, but this approach is more straightforward. |
| tcu::TextureLevel convertedSourceTexture (result.getFormat(), source.getWidth(), source.getHeight()); |
| const tcu::PixelBufferAccess convertedSource = convertedSourceTexture.getAccess(); |
| |
| for (int y = 0; y < source.getHeight(); ++y) |
| for (int x = 0; x < source.getWidth(); ++x) |
| convertedSource.setPixel(source.getPixelInt(x, y), x, y); // will be clamped to max. representable value |
| |
| const struct Capture |
| { |
| const tcu::ConstPixelBufferAccess& source; |
| const tcu::ConstPixelBufferAccess& result; |
| const tcu::Sampler& sampler; |
| const tcu::IntLookupPrecision& precision; |
| } capture = |
| { |
| convertedSource, result, sampler, precision |
| }; |
| |
| const struct Loop : CompareEachPixelInEachRegion |
| { |
| Loop (void) {} |
| |
| bool compare (const void* pUserData, const int x, const int y, const tcu::Vec2& srcNormCoord) const |
| { |
| const Capture& c = *static_cast<const Capture*>(pUserData); |
| const tcu::TexLookupScaleMode lookupScaleDontCare = tcu::TEX_LOOKUP_SCALE_MINIFY; |
| const tcu::IVec4 dstColor = c.result.getPixelInt(x, y); |
| |
| return tcu::isLevel2DLookupResultValid(c.source, c.sampler, lookupScaleDontCare, c.precision, srcNormCoord, 0, dstColor); |
| } |
| } loop; |
| |
| return loop.forEach(&capture, regions, source.getWidth(), source.getHeight(), errorMask); |
| } |
| |
| bool BlittingImages::checkNearestFilteredResult (const tcu::ConstPixelBufferAccess& result, |
| const tcu::ConstPixelBufferAccess& source) |
| { |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| const tcu::TextureFormat dstFormat = result.getFormat(); |
| const tcu::TextureChannelClass dstChannelClass = tcu::getTextureChannelClass(dstFormat.type); |
| |
| tcu::TextureLevel errorMaskStorage (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), result.getWidth(), result.getHeight()); |
| tcu::PixelBufferAccess errorMask = errorMaskStorage.getAccess(); |
| tcu::Vec4 pixelBias (0.0f, 0.0f, 0.0f, 0.0f); |
| tcu::Vec4 pixelScale (1.0f, 1.0f, 1.0f, 1.0f); |
| bool ok = false; |
| |
| tcu::clear(errorMask, tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0)); |
| |
| if (dstChannelClass == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER || |
| dstChannelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER) |
| { |
| ok = intNearestBlitCompare(source, result, errorMask, m_params.regions); |
| } |
| else |
| ok = floatNearestBlitCompare(source, result, errorMask, m_params.regions); |
| |
| if (result.getFormat() != tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)) |
| tcu::computePixelScaleBias(result, pixelScale, pixelBias); |
| |
| if (!ok) |
| { |
| log << tcu::TestLog::ImageSet("Compare", "Result comparsion") |
| << tcu::TestLog::Image("Result", "Result", result, pixelScale, pixelBias) |
| << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask) |
| << tcu::TestLog::EndImageSet; |
| } |
| else |
| { |
| log << tcu::TestLog::ImageSet("Compare", "Result comparsion") |
| << tcu::TestLog::Image("Result", "Result", result, pixelScale, pixelBias) |
| << tcu::TestLog::EndImageSet; |
| } |
| |
| return ok; |
| } |
| |
| tcu::TestStatus BlittingImages::checkTestResult (tcu::ConstPixelBufferAccess result) |
| { |
| DE_ASSERT(m_params.filter == VK_FILTER_NEAREST || m_params.filter == VK_FILTER_LINEAR); |
| const std::string failMessage("Result image is incorrect"); |
| |
| if (m_params.filter == VK_FILTER_LINEAR) |
| { |
| 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 clampedExpected = tcu::getEffectiveDepthStencilAccess(m_expectedTextureLevel->getAccess(), mode); |
| const tcu::ConstPixelBufferAccess unclampedExpected = tcu::getEffectiveDepthStencilAccess(m_unclampedExpectedTextureLevel->getAccess(), mode); |
| const tcu::TextureFormat sourceFormat = tcu::getEffectiveDepthStencilTextureFormat(mapVkFormat(m_params.src.image.format), mode); |
| |
| if (!checkLinearFilteredResult(depthResult, clampedExpected, unclampedExpected, sourceFormat)) |
| return tcu::TestStatus::fail(failMessage); |
| } |
| |
| 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 clampedExpected = tcu::getEffectiveDepthStencilAccess(m_expectedTextureLevel->getAccess(), mode); |
| const tcu::ConstPixelBufferAccess unclampedExpected = tcu::getEffectiveDepthStencilAccess(m_unclampedExpectedTextureLevel->getAccess(), mode); |
| const tcu::TextureFormat sourceFormat = tcu::getEffectiveDepthStencilTextureFormat(mapVkFormat(m_params.src.image.format), mode); |
| |
| if (!checkLinearFilteredResult(stencilResult, clampedExpected, unclampedExpected, sourceFormat)) |
| return tcu::TestStatus::fail(failMessage); |
| } |
| } |
| else |
| { |
| const tcu::TextureFormat sourceFormat = mapVkFormat(m_params.src.image.format); |
| |
| if (!checkLinearFilteredResult(result, m_expectedTextureLevel->getAccess(), m_unclampedExpectedTextureLevel->getAccess(), sourceFormat)) |
| return tcu::TestStatus::fail(failMessage); |
| } |
| } |
| else // NEAREST filtering |
| { |
| 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 depthSource = tcu::getEffectiveDepthStencilAccess(m_sourceTextureLevel->getAccess(), mode); |
| |
| if (!checkNearestFilteredResult(depthResult, depthSource)) |
| return tcu::TestStatus::fail(failMessage); |
| } |
| |
| 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 stencilSource = tcu::getEffectiveDepthStencilAccess(m_sourceTextureLevel->getAccess(), mode); |
| |
| if (!checkNearestFilteredResult(stencilResult, stencilSource)) |
| return tcu::TestStatus::fail(failMessage); |
| } |
| } |
| else |
| { |
| if (!checkNearestFilteredResult(result, m_sourceTextureLevel->getAccess())) |
| return tcu::TestStatus::fail(failMessage); |
| } |
| } |
| |
| return tcu::TestStatus::pass("Pass"); |
| } |
| |
| tcu::Vec4 linearToSRGBIfNeeded (const tcu::TextureFormat& format, const tcu::Vec4& color) |
| { |
| return isSRGB(format) ? linearToSRGB(color) : color; |
| } |
| |
| void scaleFromWholeSrcBuffer (const tcu::PixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const VkOffset3D regionOffset, const VkOffset3D regionExtent, tcu::Sampler::FilterMode filter) |
| { |
| DE_ASSERT(filter == tcu::Sampler::LINEAR); |
| DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); |
| |
| tcu::Sampler sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, |
| filter, filter, 0.0f, false); |
| |
| float sX = (float)regionExtent.x / (float)dst.getWidth(); |
| float sY = (float)regionExtent.y / (float)dst.getHeight(); |
| |
| for (int y = 0; y < dst.getHeight(); y++) |
| for (int x = 0; x < dst.getWidth(); x++) |
| dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample2D(sampler, filter, (float)regionOffset.x + ((float)x+0.5f)*sX, (float)regionOffset.y + ((float)y+0.5f)*sY, 0)), x, y); |
| } |
| |
| void blit (const tcu::PixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::Sampler::FilterMode filter, const MirrorMode mirrorMode) |
| { |
| DE_ASSERT(filter == tcu::Sampler::NEAREST || filter == tcu::Sampler::LINEAR); |
| |
| tcu::Sampler sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, |
| filter, filter, 0.0f, false); |
| |
| const float sX = (float)src.getWidth() / (float)dst.getWidth(); |
| const float sY = (float)src.getHeight() / (float)dst.getHeight(); |
| const float sZ = (float)src.getDepth() / (float)dst.getDepth(); |
| |
| tcu::Mat2 rotMatrix; |
| rotMatrix(0,0) = (mirrorMode & MIRROR_MODE_X) ? -1.0f : 1.0f; |
| rotMatrix(0,1) = 0.0f; |
| rotMatrix(1,0) = 0.0f; |
| rotMatrix(1,1) = (mirrorMode & MIRROR_MODE_Y) ? -1.0f : 1.0f; |
| |
| const int xOffset = (mirrorMode & MIRROR_MODE_X) ? dst.getWidth() - 1 : 0; |
| const int yOffset = (mirrorMode & MIRROR_MODE_Y) ? dst.getHeight() - 1 : 0; |
| |
| if (dst.getDepth() == 1 && src.getDepth() == 1) |
| { |
| for (int y = 0; y < dst.getHeight(); ++y) |
| for (int x = 0; x < dst.getWidth(); ++x) |
| { |
| const tcu::Vec2 xy = rotMatrix * tcu::Vec2((float)x,(float)y); |
| dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample2D(sampler, filter, ((float)x+0.5f)*sX, ((float)y+0.5f)*sY, 0)), (int)round(xy[0]) + xOffset, (int)round(xy[1]) + yOffset); |
| } |
| } |
| else |
| { |
| for (int z = 0; z < dst.getDepth(); ++z) |
| for (int y = 0; y < dst.getHeight(); ++y) |
| for (int x = 0; x < dst.getWidth(); ++x) |
| { |
| const tcu::Vec2 xy = rotMatrix * tcu::Vec2((float)x,(float)y); |
| dst.setPixel(linearToSRGBIfNeeded(dst.getFormat(), src.sample3D(sampler, filter, ((float)x+0.5f)*sX, ((float)y+0.5f)*sY, ((float)z+0.5f)*sZ)), (int)round(xy[0]) + xOffset, (int)round(xy[1]) + yOffset, z); |
| } |
| } |
| } |
| |
| void flipCoordinates (CopyRegion& region, const MirrorMode mirrorMode) |
| { |
| const VkOffset3D dstOffset0 = region.imageBlit.dstOffsets[0]; |
| const VkOffset3D dstOffset1 = region.imageBlit.dstOffsets[1]; |
| const VkOffset3D srcOffset0 = region.imageBlit.srcOffsets[0]; |
| const VkOffset3D srcOffset1 = region.imageBlit.srcOffsets[1]; |
| |
| if (mirrorMode > MIRROR_MODE_NONE && mirrorMode < MIRROR_MODE_LAST) |
| { |
| //sourceRegion |
| region.imageBlit.srcOffsets[0].x = std::min(srcOffset0.x, srcOffset1.x); |
| region.imageBlit.srcOffsets[0].y = std::min(srcOffset0.y, srcOffset1.y); |
| |
| region.imageBlit.srcOffsets[1].x = std::max(srcOffset0.x, srcOffset1.x); |
| region.imageBlit.srcOffsets[1].y = std::max(srcOffset0.y, srcOffset1.y); |
| |
| //destinationRegion |
| region.imageBlit.dstOffsets[0].x = std::min(dstOffset0.x, dstOffset1.x); |
| region.imageBlit.dstOffsets[0].y = std::min(dstOffset0.y, dstOffset1.y); |
| |
| region.imageBlit.dstOffsets[1].x = std::max(dstOffset0.x, dstOffset1.x); |
| region.imageBlit.dstOffsets[1].y = std::max(dstOffset0.y, dstOffset1.y); |
| } |
| } |
| |
| MirrorMode getMirrorMode(const VkOffset3D x1, const VkOffset3D x2) |
| { |
| if (x1.x >= x2.x && x1.y >= x2.y) |
| { |
| return MIRROR_MODE_XY; |
| } |
| else if (x1.x <= x2.x && x1.y <= x2.y) |
| { |
| return MIRROR_MODE_NONE; |
| } |
| else if (x1.x <= x2.x && x1.y >= x2.y) |
| { |
| return MIRROR_MODE_Y; |
| } |
| else if (x1.x >= x2.x && x1.y <= x2.y) |
| { |
| return MIRROR_MODE_X; |
| } |
| return MIRROR_MODE_LAST; |
| } |
| |
| MirrorMode getMirrorMode(const VkOffset3D s1, const VkOffset3D s2, const VkOffset3D d1, const VkOffset3D d2) |
| { |
| const MirrorMode source = getMirrorMode(s1, s2); |
| const MirrorMode destination = getMirrorMode(d1, d2); |
| |
| if (source == destination) |
| { |
| return MIRROR_MODE_NONE; |
| } |
| else if ((source == MIRROR_MODE_XY && destination == MIRROR_MODE_X) || (destination == MIRROR_MODE_XY && source == MIRROR_MODE_X) || |
| (source == MIRROR_MODE_Y && destination == MIRROR_MODE_NONE) || (destination == MIRROR_MODE_Y && source == MIRROR_MODE_NONE)) |
| { |
| return MIRROR_MODE_Y; |
| } |
| else if ((source == MIRROR_MODE_XY && destination == MIRROR_MODE_Y) || (destination == MIRROR_MODE_XY && source == MIRROR_MODE_Y) || |
| (source == MIRROR_MODE_X && destination == MIRROR_MODE_NONE) || (destination == MIRROR_MODE_X && source == MIRROR_MODE_NONE)) |
| { |
| return MIRROR_MODE_X; |
| } |
| else if ((source == MIRROR_MODE_XY && destination == MIRROR_MODE_NONE) || (destination == MIRROR_MODE_XY && source == MIRROR_MODE_NONE)) |
| { |
| return MIRROR_MODE_XY; |
| } |
| return MIRROR_MODE_LAST; |
| } |
| |
| void BlittingImages::copyRegionToTextureLevel (tcu::ConstPixelBufferAccess src, tcu::PixelBufferAccess dst, CopyRegion region) |
| { |
| const MirrorMode mirrorMode = getMirrorMode(region.imageBlit.srcOffsets[0], |
| region.imageBlit.srcOffsets[1], |
| region.imageBlit.dstOffsets[0], |
| region.imageBlit.dstOffsets[1]); |
| |
| flipCoordinates(region, mirrorMode); |
| |
| const VkOffset3D srcOffset = region.imageBlit.srcOffsets[0]; |
| const VkOffset3D srcExtent = |
| { |
| region.imageBlit.srcOffsets[1].x - srcOffset.x, |
| region.imageBlit.srcOffsets[1].y - srcOffset.y, |
| region.imageBlit.srcOffsets[1].z - srcOffset.z |
| }; |
| const VkOffset3D dstOffset = region.imageBlit.dstOffsets[0]; |
| const VkOffset3D dstExtent = |
| { |
| region.imageBlit.dstOffsets[1].x - dstOffset.x, |
| region.imageBlit.dstOffsets[1].y - dstOffset.y, |
| region.imageBlit.dstOffsets[1].z - dstOffset.z |
| }; |
| const tcu::Sampler::FilterMode filter = (m_params.filter == VK_FILTER_LINEAR) ? tcu::Sampler::LINEAR : tcu::Sampler::NEAREST; |
| |
| if (tcu::isCombinedDepthStencilType(src.getFormat().type)) |
| { |
| DE_ASSERT(src.getFormat() == dst.getFormat()); |
| // Scale depth. |
| if (tcu::hasDepthComponent(src.getFormat().order)) |
| { |
| const tcu::ConstPixelBufferAccess srcSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(src, srcOffset.x, srcOffset.y, srcExtent.x, srcExtent.y), tcu::Sampler::MODE_DEPTH); |
| const tcu::PixelBufferAccess dstSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(dst, dstOffset.x, dstOffset.y, dstExtent.x, dstExtent.y), tcu::Sampler::MODE_DEPTH); |
| tcu::scale(dstSubRegion, srcSubRegion, filter); |
| |
| if (filter == tcu::Sampler::LINEAR) |
| { |
| const tcu::ConstPixelBufferAccess depthSrc = getEffectiveDepthStencilAccess(src, tcu::Sampler::MODE_DEPTH); |
| const tcu::PixelBufferAccess unclampedSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(m_unclampedExpectedTextureLevel->getAccess(), dstOffset.x, dstOffset.y, dstExtent.x, dstExtent.y), tcu::Sampler::MODE_DEPTH); |
| scaleFromWholeSrcBuffer(unclampedSubRegion, depthSrc, srcOffset, srcExtent, filter); |
| } |
| } |
| |
| // Scale stencil. |
| if (tcu::hasStencilComponent(src.getFormat().order)) |
| { |
| const tcu::ConstPixelBufferAccess srcSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(src, srcOffset.x, srcOffset.y, srcExtent.x, srcExtent.y), tcu::Sampler::MODE_STENCIL); |
| const tcu::PixelBufferAccess dstSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(dst, dstOffset.x, dstOffset.y, dstExtent.x, dstExtent.y), tcu::Sampler::MODE_STENCIL); |
| blit(dstSubRegion, srcSubRegion, filter, mirrorMode); |
| |
| if (filter == tcu::Sampler::LINEAR) |
| { |
| const tcu::ConstPixelBufferAccess stencilSrc = getEffectiveDepthStencilAccess(src, tcu::Sampler::MODE_STENCIL); |
| const tcu::PixelBufferAccess unclampedSubRegion = getEffectiveDepthStencilAccess(tcu::getSubregion(m_unclampedExpectedTextureLevel->getAccess(), dstOffset.x, dstOffset.y, dstExtent.x, dstExtent.y), tcu::Sampler::MODE_STENCIL); |
| scaleFromWholeSrcBuffer(unclampedSubRegion, stencilSrc, srcOffset, srcExtent, filter); |
| } |
| } |
| } |
| else |
| { |
| const tcu::ConstPixelBufferAccess srcSubRegion = tcu::getSubregion(src, srcOffset.x, srcOffset.y, srcExtent.x, srcExtent.y); |
| const tcu::PixelBufferAccess dstSubRegion = tcu::getSubregion(dst, dstOffset.x, dstOffset.y, dstExtent.x, dstExtent.y); |
| blit(dstSubRegion, srcSubRegion, filter, mirrorMode); |
| |
| if (filter == tcu::Sampler::LINEAR) |
| { |
| const tcu::PixelBufferAccess unclampedSubRegion = tcu::getSubregion(m_unclampedExpectedTextureLevel->getAccess(), dstOffset.x, dstOffset.y, dstExtent.x, dstExtent.y); |
| scaleFromWholeSrcBuffer(unclampedSubRegion, src, srcOffset, srcExtent, filter); |
| } |
| } |
| } |
| |
| void BlittingImages::generateExpectedResult (void) |
| { |
| const tcu:: |