| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2019 Google Inc. |
| * Copyright (c) 2019 The Khronos Group Inc. |
| * Copyright (c) 2014 The Android Open Source Project |
| * |
| * 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 Geometry shader layered rendering tests |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktGeometryLayeredRenderingTests.hpp" |
| #include "vktTestCase.hpp" |
| #include "vktTestCaseUtil.hpp" |
| #include "vktGeometryTestsUtil.hpp" |
| |
| #include "vkPrograms.hpp" |
| #include "vkStrUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkMemUtil.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkBarrierUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkObjUtil.hpp" |
| |
| #include "deStringUtil.hpp" |
| #include "deUniquePtr.hpp" |
| |
| #include "tcuTextureUtil.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "tcuTestLog.hpp" |
| |
| namespace vkt |
| { |
| namespace geometry |
| { |
| namespace |
| { |
| using namespace vk; |
| using de::MovePtr; |
| using de::UniquePtr; |
| using tcu::Vec4; |
| using tcu::IVec3; |
| |
| enum TestType |
| { |
| TEST_TYPE_DEFAULT_LAYER, // !< draw to default layer |
| TEST_TYPE_SINGLE_LAYER, // !< draw to single layer |
| TEST_TYPE_ALL_LAYERS, // !< draw all layers |
| TEST_TYPE_DIFFERENT_CONTENT, // !< draw different content to different layers |
| TEST_TYPE_LAYER_ID, // !< draw to all layers, verify gl_Layer fragment input |
| TEST_TYPE_INVOCATION_PER_LAYER, // !< draw to all layers, one invocation per layer |
| TEST_TYPE_MULTIPLE_LAYERS_PER_INVOCATION, // !< draw to all layers, multiple invocations write to multiple layers |
| TEST_TYPE_LAYERED_READBACK, // !< draw to two layers multiple times |
| TEST_TYPE_SECONDARY_CMD_BUFFER // !< layered rendering using secondary command buffer |
| }; |
| |
| struct ImageParams |
| { |
| VkImageViewType viewType; |
| VkExtent3D size; |
| deUint32 numLayers; |
| }; |
| |
| struct TestParams |
| { |
| TestType testType; |
| ImageParams image; |
| bool inheritFramebuffer; |
| }; |
| |
| const float s_colors[][4] = |
| { |
| { 1.0f, 1.0f, 1.0f, 1.0f }, // white |
| { 1.0f, 0.0f, 0.0f, 1.0f }, // red |
| { 0.0f, 1.0f, 0.0f, 1.0f }, // green |
| { 0.0f, 0.0f, 1.0f, 1.0f }, // blue |
| { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow |
| { 1.0f, 0.0f, 1.0f, 1.0f }, // magenta |
| }; |
| |
| const tcu::Vec4 secondaryCmdBufClearColors[] = |
| { |
| tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), |
| tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), |
| tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), |
| tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), |
| tcu::Vec4(0.0f, 1.0f, 1.0f, 1.0f), |
| tcu::Vec4(1.0f, 0.0f, 1.0f, 1.0f) |
| }; |
| |
| tcu::Vec4 scaleColor(const tcu::Vec4& color, float factor) |
| { |
| return tcu::Vec4(color[0] * factor, |
| color[1] * factor, |
| color[2] * factor, |
| color[3]); |
| } |
| |
| deUint32 getTargetLayer (const ImageParams& imageParams) |
| { |
| if (imageParams.viewType == VK_IMAGE_VIEW_TYPE_3D) |
| return imageParams.size.depth / 2; |
| else |
| return imageParams.numLayers / 2; |
| } |
| |
| std::string getShortImageViewTypeName (const VkImageViewType imageViewType) |
| { |
| std::string s(getImageViewTypeName(imageViewType)); |
| return de::toLower(s.substr(19)); |
| } |
| |
| VkImageType getImageType (const VkImageViewType viewType) |
| { |
| switch (viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_1D: |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| return VK_IMAGE_TYPE_1D; |
| |
| case VK_IMAGE_VIEW_TYPE_2D: |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| return VK_IMAGE_TYPE_2D; |
| |
| case VK_IMAGE_VIEW_TYPE_3D: |
| return VK_IMAGE_TYPE_3D; |
| |
| default: |
| DE_ASSERT(0); |
| return VK_IMAGE_TYPE_LAST; |
| } |
| } |
| |
| VkFormat getStencilBufferFormat(VkFormat depthStencilImageFormat) |
| { |
| const tcu::TextureFormat tcuFormat = mapVkFormat(depthStencilImageFormat); |
| const VkFormat result = (tcuFormat.order == tcu::TextureFormat::S || tcuFormat.order == tcu::TextureFormat::DS) ? VK_FORMAT_S8_UINT : VK_FORMAT_UNDEFINED; |
| |
| DE_ASSERT(result != VK_FORMAT_UNDEFINED); |
| |
| return result; |
| } |
| |
| inline bool isCubeImageViewType (const VkImageViewType viewType) |
| { |
| return viewType == VK_IMAGE_VIEW_TYPE_CUBE || viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; |
| } |
| |
| void checkImageFormatProperties (const InstanceInterface& vki, |
| const VkPhysicalDevice& physDevice, |
| const VkImageType& imageType, |
| const VkImageTiling& imageTiling, |
| const VkImageUsageFlags imageUsageFlags, |
| const VkImageCreateFlags imageCreateFlags, |
| const VkFormat format, |
| const VkExtent3D& requiredSize, |
| const deUint32 requiredLayers) |
| { |
| VkImageFormatProperties imageFormatProperties; |
| VkResult result; |
| |
| deMemset(&imageFormatProperties, 0, sizeof(imageFormatProperties)); |
| |
| result = vki.getPhysicalDeviceImageFormatProperties(physDevice, format, imageType, imageTiling, imageUsageFlags, imageCreateFlags, &imageFormatProperties); |
| |
| if (result != VK_SUCCESS || |
| imageFormatProperties.maxArrayLayers < requiredLayers || |
| imageFormatProperties.maxExtent.height < requiredSize.height || |
| imageFormatProperties.maxExtent.width < requiredSize.width || |
| imageFormatProperties.maxExtent.depth < requiredSize.depth) |
| { |
| TCU_THROW(NotSupportedError, "Depth/stencil format is not supported"); |
| } |
| } |
| |
| VkImageCreateInfo makeImageCreateInfo (const VkImageCreateFlags flags, const VkImageType type, const VkFormat format, const VkExtent3D size, const deUint32 numLayers, const VkImageUsageFlags usage) |
| { |
| const VkImageCreateInfo imageParams = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| flags, // VkImageCreateFlags flags; |
| type, // VkImageType imageType; |
| format, // VkFormat format; |
| size, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| numLayers, // deUint32 arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| usage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 0u, // deUint32 queueFamilyIndexCount; |
| DE_NULL, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| return imageParams; |
| } |
| |
| Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkFormat colorFormat, |
| const VkFormat dsFormat, |
| const bool useDepthStencil) |
| { |
| return vk::makeRenderPass(vk, device, colorFormat, useDepthStencil ? dsFormat : VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD); |
| } |
| |
| Move<VkRenderPass> makeRenderPassWithSelfDependency (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkFormat colorFormat) |
| { |
| const VkAttachmentDescription attachmentDescription = |
| { |
| (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags |
| colorFormat, // VkFormat format |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp |
| VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp |
| VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp |
| VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout |
| }; |
| |
| const VkAttachmentReference colorAttachmentRef = |
| { |
| 0u, // deUint32 attachment |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout |
| }; |
| |
| const VkSubpassDescription subpassDescription = |
| { |
| (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags |
| VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint |
| 0u, // deUint32 inputAttachmentCount |
| DE_NULL, // const VkAttachmentReference* pInputAttachments |
| 1u, // deUint32 colorAttachmentCount |
| &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments |
| DE_NULL, // const VkAttachmentReference* pResolveAttachments |
| DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment |
| 0u, // deUint32 preserveAttachmentCount |
| DE_NULL // const deUint32* pPreserveAttachments |
| }; |
| |
| const VkSubpassDependency subpassDependency = |
| { |
| 0u, // deUint32 srcSubpass |
| 0u, // deUint32 dstSubpass |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags srcStageMask |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask |
| VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask |
| 0u, // VkDependencyFlags dependencyFlags |
| }; |
| |
| const VkRenderPassCreateInfo renderPassInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags |
| 1u, // deUint32 attachmentCount |
| &attachmentDescription, // const VkAttachmentDescription* pAttachments |
| 1u, // deUint32 subpassCount |
| &subpassDescription, // const VkSubpassDescription* pSubpasses |
| 1u, // deUint32 dependencyCount |
| &subpassDependency // const VkSubpassDependency* pDependencies |
| }; |
| |
| return createRenderPass(vk, device, &renderPassInfo); |
| } |
| |
| Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkPipelineLayout pipelineLayout, |
| const VkRenderPass renderPass, |
| const VkShaderModule vertexModule, |
| const VkShaderModule geometryModule, |
| const VkShaderModule fragmentModule, |
| const VkExtent2D renderSize, |
| const bool useDepthStencil = false) |
| { |
| const std::vector<VkViewport> viewports (1, makeViewport(renderSize)); |
| const std::vector<VkRect2D> scissors (1, makeRect2D(renderSize)); |
| |
| const VkStencilOpState stencilOpState = makeStencilOpState( |
| VK_STENCIL_OP_KEEP, // stencil fail |
| VK_STENCIL_OP_INCREMENT_AND_CLAMP, // depth & stencil pass |
| VK_STENCIL_OP_KEEP, // depth only fail |
| VK_COMPARE_OP_ALWAYS, // compare op |
| ~0u, // compare mask |
| ~0u, // write mask |
| 0u); // reference |
| |
| const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags |
| useDepthStencil ? VK_TRUE : VK_FALSE, // VkBool32 depthTestEnable |
| useDepthStencil ? VK_TRUE : VK_FALSE, // VkBool32 depthWriteEnable |
| VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp |
| VK_FALSE, // VkBool32 depthBoundsTestEnable |
| useDepthStencil ? VK_TRUE : VK_FALSE, // VkBool32 stencilTestEnable |
| stencilOpState, // VkStencilOpState front |
| stencilOpState, // VkStencilOpState back |
| 0.0f, // float minDepthBounds |
| 1.0f // float maxDepthBounds |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkPipelineVertexInputStateCreateFlags flags |
| 0u, // deUint32 vertexBindingDescriptionCount |
| DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions |
| 0u, // deUint32 vertexAttributeDescriptionCount |
| DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions |
| }; |
| |
| return vk::makeGraphicsPipeline(vk, // const DeviceInterface& vk |
| device, // const VkDevice device |
| pipelineLayout, // const VkPipelineLayout pipelineLayout |
| vertexModule, // const VkShaderModule vertexShaderModule |
| DE_NULL, // const VkShaderModule tessellationControlModule |
| DE_NULL, // const VkShaderModule tessellationEvalModule |
| geometryModule, // const VkShaderModule geometryShaderModule |
| fragmentModule, // const VkShaderModule fragmentShaderModule |
| renderPass, // const VkRenderPass renderPass |
| viewports, // const std::vector<VkViewport>& viewports |
| scissors, // const std::vector<VkRect2D>& scissors |
| VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // const VkPrimitiveTopology topology |
| 0u, // const deUint32 subpass |
| 0u, // const deUint32 patchControlPoints |
| &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo |
| DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo |
| DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo |
| &pipelineDepthStencilStateInfo); // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo |
| } |
| |
| void copyLayeredImageToBuffer(const DeviceInterface& vk, VkCommandBuffer cmdBuffer, VkImage image, VkBuffer buffer, const ImageParams& imageParams) |
| { |
| // Image read barrier |
| { |
| const VkImageSubresourceRange colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, imageParams.numLayers); |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags outputMask |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags inputMask |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex |
| image, // VkImage image |
| colorSubresourceRange // VkImageSubresourceRange subresourceRange |
| }; |
| |
| vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); |
| } |
| // Color image -> host buffer |
| { |
| const VkBufferImageCopy region = |
| { |
| 0ull, // VkDeviceSize bufferOffset |
| 0u, // deUint32 bufferRowLength |
| 0u, // deUint32 bufferImageHeight |
| makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageParams.numLayers), // VkImageSubresourceLayers imageSubresource |
| makeOffset3D(0, 0, 0), // VkOffset3D imageOffset |
| imageParams.size // VkExtent3D imageExtent |
| }; |
| |
| vk.cmdCopyImageToBuffer(cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1u, ®ion); |
| } |
| // Buffer write barrier |
| { |
| const VkBufferMemoryBarrier barrier = |
| { |
| 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 |
| 0ull, // VkDeviceSize offset |
| VK_WHOLE_SIZE // VkDeviceSize size |
| }; |
| |
| vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u); |
| } |
| } |
| |
| //! Convenience wrapper to access 1D, 2D, and 3D image layers/slices in a uniform way. |
| class LayeredImageAccess |
| { |
| public: |
| static LayeredImageAccess create (const VkImageType type, const VkFormat format, const VkExtent3D size, const deUint32 numLayers, const void* pData) |
| { |
| if (type == VK_IMAGE_TYPE_1D) |
| return LayeredImageAccess(format, size.width, numLayers, pData); |
| else |
| return LayeredImageAccess(type, format, size, numLayers, pData); |
| } |
| |
| inline tcu::ConstPixelBufferAccess getLayer (const int layer) const |
| { |
| return tcu::getSubregion(m_wholeImage, 0, (m_1dModifier * layer), ((~m_1dModifier & 1) * layer), m_width, m_height, 1); |
| } |
| |
| inline int getNumLayersOrSlices (void) const |
| { |
| return m_layers; |
| } |
| |
| private: |
| // Specialized for 1D images. |
| LayeredImageAccess (const VkFormat format, const deUint32 width, const deUint32 numLayers, const void* pData) |
| : m_width (static_cast<int>(width)) |
| , m_height (1) |
| , m_1dModifier (1) |
| , m_layers (numLayers) |
| , m_wholeImage (tcu::ConstPixelBufferAccess(mapVkFormat(format), m_width, m_layers, 1, pData)) |
| { |
| } |
| |
| LayeredImageAccess (const VkImageType type, const VkFormat format, const VkExtent3D size, const deUint32 numLayers, const void* pData) |
| : m_width (static_cast<int>(size.width)) |
| , m_height (static_cast<int>(size.height)) |
| , m_1dModifier (0) |
| , m_layers (static_cast<int>(type == VK_IMAGE_TYPE_3D ? size.depth : numLayers)) |
| , m_wholeImage (tcu::ConstPixelBufferAccess(mapVkFormat(format), m_width, m_height, m_layers, pData)) |
| { |
| } |
| |
| const int m_width; |
| const int m_height; |
| const int m_1dModifier; |
| const int m_layers; |
| const tcu::ConstPixelBufferAccess m_wholeImage; |
| }; |
| |
| inline bool compareColors (const Vec4& colorA, const Vec4& colorB, const Vec4& threshold) |
| { |
| return tcu::allEqual( |
| tcu::lessThan(tcu::abs(colorA - colorB), threshold), |
| tcu::BVec4(true, true, true, true)); |
| } |
| |
| bool verifyImageSingleColoredRow (tcu::TestLog& log, const tcu::ConstPixelBufferAccess image, const float rowWidthRatio, const tcu::Vec4& barColor, bool topRightCleared = false, bool bottomRightCleared = false) |
| { |
| DE_ASSERT(rowWidthRatio > 0.0f); |
| |
| const Vec4 black (0.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); |
| const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 brown (0.5f, 0.25f, 0.0f, 1.0f); |
| const Vec4 threshold (0.02f); |
| const int barLength = static_cast<int>(rowWidthRatio * static_cast<float>(image.getWidth())); |
| const int barLengthThreshold = 1; |
| tcu::TextureLevel errorMask (image.getFormat(), image.getWidth(), image.getHeight()); |
| tcu::PixelBufferAccess errorMaskAccess = errorMask.getAccess(); |
| |
| tcu::clear(errorMask.getAccess(), green); |
| |
| log << tcu::TestLog::Message |
| << "Expecting all pixels with distance less or equal to (about) " << barLength |
| << " pixels from left border to be of color " << barColor.swizzle(0, 1, 2) << "." |
| << tcu::TestLog::EndMessage; |
| |
| bool allPixelsOk = true; |
| |
| for (int y = 0; y < image.getHeight(); ++y) |
| for (int x = 0; x < image.getWidth(); ++x) |
| { |
| const Vec4 color = image.getPixel(x, y); |
| const bool isBlack = compareColors(color, black, threshold); |
| const bool isBrown = compareColors(color, brown, threshold); |
| const bool isColor = compareColors(color, barColor, threshold); |
| const bool isOutsideColor = ((topRightCleared && y < image.getHeight() / 2) || (bottomRightCleared && y >= image.getHeight() / 2)) ? isBrown : isBlack; |
| |
| bool isOk; |
| |
| if (x <= barLength - barLengthThreshold) |
| isOk = isColor; |
| else if (x >= barLength + barLengthThreshold) |
| { |
| isOk = isOutsideColor; |
| } |
| else |
| isOk = isColor || isOutsideColor; |
| |
| allPixelsOk &= isOk; |
| |
| if (!isOk) |
| errorMaskAccess.setPixel(red, x, y); |
| } |
| |
| if (allPixelsOk) |
| { |
| log << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet("LayerContent", "Layer content") |
| << tcu::TestLog::Image("Layer", "Layer", image) |
| << tcu::TestLog::EndImageSet; |
| return true; |
| } |
| else |
| { |
| log << tcu::TestLog::Message << "Image verification failed. Got unexpected pixels." << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet("LayerContent", "Layer content") |
| << tcu::TestLog::Image("Layer", "Layer", image) |
| << tcu::TestLog::Image("ErrorMask", "Errors", errorMask) |
| << tcu::TestLog::EndImageSet; |
| return false; |
| } |
| |
| // Note: this is never reached |
| log << tcu::TestLog::Image("LayerContent", "Layer content", image); |
| |
| return allPixelsOk; |
| } |
| |
| static bool verifyImageMultipleBars (tcu::TestLog& log, |
| const tcu::ConstPixelBufferAccess image, |
| const float* barWidthRatios, |
| const tcu::Vec4* barValues, |
| const int barsCount, |
| const int numUsedChannels, |
| const std::string& imageTypeName) |
| { |
| const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); |
| const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 threshold (0.02f); |
| const tcu::TextureFormat errorMaskFormat (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)); |
| tcu::TextureLevel errorMask (errorMaskFormat, image.getWidth(), image.getHeight()); |
| tcu::PixelBufferAccess errorMaskAccess = errorMask.getAccess(); |
| bool allPixelsOk = true; |
| |
| DE_ASSERT(barsCount > 0); |
| |
| tcu::clear(errorMask.getAccess(), green); |
| |
| // Format information message |
| { |
| int leftBorder = 0; |
| int rightBorder = 0; |
| std::ostringstream str; |
| |
| for (int barNdx = 0; barNdx < barsCount; ++barNdx) |
| { |
| leftBorder = rightBorder; |
| rightBorder = static_cast<int>(barWidthRatios[barNdx] * static_cast<float>(image.getWidth())); |
| |
| DE_ASSERT(leftBorder < rightBorder); |
| |
| str << std::endl << " [" << leftBorder << "," <<rightBorder << "): "; |
| |
| switch (numUsedChannels) |
| { |
| case 1: str << barValues[barNdx][0]; break; |
| case 4: str << barValues[barNdx]; break; |
| default: DE_ASSERT(false); break; |
| } |
| } |
| |
| log << tcu::TestLog::Message |
| << "Expecting " + imageTypeName + " values depending x-axis position to be of following values: " |
| << str.str() |
| << tcu::TestLog::EndMessage; |
| } |
| |
| for (int x = 0; x < image.getWidth(); ++x) |
| { |
| tcu::Vec4 expectedValue = barValues[0]; |
| |
| for (int barNdx = 0; barNdx < barsCount; ++barNdx) |
| { |
| const int rightBorder = static_cast<int>(barWidthRatios[barNdx] * static_cast<float>(image.getWidth())); |
| |
| if (x < rightBorder) |
| { |
| expectedValue = barValues[barNdx]; |
| |
| break; |
| } |
| } |
| |
| for (int y = 0; y < image.getHeight(); ++y) |
| { |
| const tcu::Vec4 realValue = image.getPixel(x, y); |
| bool isOk = false; |
| |
| switch (numUsedChannels) |
| { |
| case 1: isOk = fabs(realValue[0] - expectedValue[0]) < threshold[0]; break; |
| case 4: isOk = compareColors(realValue, expectedValue, threshold); break; |
| default: DE_ASSERT(false); break; |
| } |
| |
| if (!isOk) |
| errorMaskAccess.setPixel(red, x, y); |
| |
| allPixelsOk = allPixelsOk && isOk; |
| } |
| } |
| |
| if (allPixelsOk) |
| { |
| log << tcu::TestLog::Message << "Image is valid." << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet(imageTypeName + "LayerContent", imageTypeName + " Layer Content") |
| << tcu::TestLog::Image("Layer", "Layer", image) |
| << tcu::TestLog::EndImageSet; |
| } |
| else |
| { |
| log << tcu::TestLog::Message << "Image verification failed. Got unexpected pixels." << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet(imageTypeName + "LayerContent", imageTypeName + " Layer Content") |
| << tcu::TestLog::Image("Layer", "Layer", image) |
| << tcu::TestLog::Image("ErrorMask", "Errors", errorMask) |
| << tcu::TestLog::EndImageSet; |
| } |
| |
| return allPixelsOk; |
| } |
| |
| static void convertDepthToColorBufferAccess (const tcu::ConstPixelBufferAccess& inputImage, tcu::PixelBufferAccess& outputImage) |
| { |
| for (int y = 0; y < inputImage.getHeight(); y++) |
| for (int x = 0; x < inputImage.getWidth(); x++) |
| { |
| const float depth = inputImage.getPixDepth(x, y); |
| const tcu::Vec4 color = tcu::Vec4(depth, depth, depth, 1.0f); |
| |
| outputImage.setPixel(color, x, y); |
| } |
| } |
| |
| static void convertStencilToColorBufferAccess (const tcu::ConstPixelBufferAccess& inputImage, tcu::PixelBufferAccess& outputImage, int maxValue) |
| { |
| for (int y = 0; y < inputImage.getHeight(); y++) |
| for (int x = 0; x < inputImage.getWidth(); x++) |
| { |
| const int stencilInt = inputImage.getPixStencil(x, y); |
| const float stencil = (stencilInt < maxValue) ? float(stencilInt) / float(maxValue) : 1.0f; |
| const tcu::Vec4 color = tcu::Vec4(stencil, stencil, stencil, 1.0f); |
| |
| outputImage.setPixel(color, x, y); |
| } |
| } |
| |
| bool verifyEmptyImage (tcu::TestLog& log, const tcu::ConstPixelBufferAccess image) |
| { |
| log << tcu::TestLog::Message << "Expecting empty image" << tcu::TestLog::EndMessage; |
| |
| const Vec4 black (0.0f, 0.0f, 0.0f, 1.0f); |
| const Vec4 threshold (0.02f); |
| |
| for (int y = 0; y < image.getHeight(); ++y) |
| for (int x = 0; x < image.getWidth(); ++x) |
| { |
| const Vec4 color = image.getPixel(x, y); |
| |
| if (!compareColors(color, black, threshold)) |
| { |
| log << tcu::TestLog::Message |
| << "Found (at least) one bad pixel at " << x << "," << y << ". Pixel color is not background color." |
| << tcu::TestLog::EndMessage |
| << tcu::TestLog::ImageSet("LayerContent", "Layer content") |
| << tcu::TestLog::Image("Layer", "Layer", image) |
| << tcu::TestLog::EndImageSet; |
| return false; |
| } |
| } |
| |
| log << tcu::TestLog::Message << "Image is valid" << tcu::TestLog::EndMessage; |
| |
| return true; |
| } |
| |
| bool verifyLayerContent (tcu::TestLog& log, const TestType testType, const tcu::ConstPixelBufferAccess image, const int layerNdx, const int numLayers, const bool depthCheck, const bool stencilCheck) |
| { |
| const Vec4 white (1.0f, 1.0f, 1.0f, 1.0f); |
| const int targetLayer = numLayers / 2; |
| const float variableBarRatio = static_cast<float>(layerNdx) / static_cast<float>(numLayers); |
| |
| switch (testType) |
| { |
| case TEST_TYPE_DEFAULT_LAYER: |
| if (layerNdx == 0) |
| return verifyImageSingleColoredRow(log, image, 0.5f, white); |
| else |
| return verifyEmptyImage(log, image); |
| |
| case TEST_TYPE_SINGLE_LAYER: |
| if (layerNdx == targetLayer) |
| return verifyImageSingleColoredRow(log, image, 0.5f, white); |
| else |
| return verifyEmptyImage(log, image); |
| |
| case TEST_TYPE_ALL_LAYERS: |
| case TEST_TYPE_INVOCATION_PER_LAYER: |
| return verifyImageSingleColoredRow(log, image, 0.5f, s_colors[layerNdx % DE_LENGTH_OF_ARRAY(s_colors)]); |
| |
| case TEST_TYPE_DIFFERENT_CONTENT: |
| case TEST_TYPE_MULTIPLE_LAYERS_PER_INVOCATION: |
| if (layerNdx == 0) |
| return verifyEmptyImage(log, image); |
| else |
| return verifyImageSingleColoredRow(log, image, variableBarRatio, white); |
| |
| case TEST_TYPE_LAYER_ID: |
| { |
| // This code must be in sync with the fragment shader. |
| const tcu::Vec4 layerColor( (layerNdx % 2) == 1 ? 1.0f : 0.5f, |
| ((layerNdx/2) % 2) == 1 ? 1.0f : 0.5f, |
| layerNdx == 0 ? 1.0f : 0.0f, |
| 1.0f); |
| return verifyImageSingleColoredRow(log, image, 0.5f, layerColor); |
| } |
| |
| case TEST_TYPE_LAYERED_READBACK: |
| { |
| const float barWidthRatios[] = { 0.25f, 0.5f, 1.0f }; |
| const int barsCount = DE_LENGTH_OF_ARRAY(barWidthRatios); |
| bool result = false; |
| |
| if (depthCheck) |
| { |
| const std::string checkType = "Depth"; |
| const float pass0depth = static_cast<float>(layerNdx + 1) / static_cast<float>(2 * numLayers); |
| const float pass1depth = static_cast<float>(layerNdx + 0) / static_cast<float>(2 * numLayers); |
| const tcu::Vec4 barDepths[barsCount] = { tcu::Vec4(pass1depth), tcu::Vec4(pass0depth), tcu::Vec4(1.0f) }; |
| tcu::TextureLevel depthAsColorBuffer (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), image.getWidth(), image.getHeight()); |
| tcu::PixelBufferAccess depthAsColor (depthAsColorBuffer); |
| const int numUsedChannels (tcu::getNumUsedChannels(depthAsColor.getFormat().order)); |
| |
| convertDepthToColorBufferAccess(image, depthAsColor); |
| |
| result = verifyImageMultipleBars(log, depthAsColor, barWidthRatios, barDepths, barsCount, numUsedChannels, checkType); |
| } |
| else if (stencilCheck) |
| { |
| const std::string checkType = "Stencil"; |
| const int maxStencilValue = 4; |
| const float pass0stencil = static_cast<float>(1.0f / maxStencilValue); |
| const float pass1stencil = static_cast<float>(2.0f / maxStencilValue); |
| const tcu::Vec4 barStencils[barsCount] = { tcu::Vec4(pass1stencil), tcu::Vec4(pass0stencil), tcu::Vec4(0.0f) }; |
| tcu::TextureLevel stencilAsColorBuffer (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), image.getWidth(), image.getHeight()); |
| tcu::PixelBufferAccess stencilAsColor (stencilAsColorBuffer); |
| const int numUsedChannels (tcu::getNumUsedChannels(stencilAsColor.getFormat().order)); |
| |
| convertStencilToColorBufferAccess(image, stencilAsColor, maxStencilValue); |
| |
| result = verifyImageMultipleBars(log, stencilAsColor, barWidthRatios, barStencils, barsCount, numUsedChannels, checkType); |
| } |
| else |
| { |
| const std::string checkType = "Color"; |
| const tcu::Vec4 baseColor (s_colors[layerNdx % DE_LENGTH_OF_ARRAY(s_colors)]); |
| const tcu::Vec4 barColors[barsCount] = { scaleColor(baseColor, 1.00f), scaleColor(baseColor, 0.50f), scaleColor(baseColor, 0.25f) }; |
| const int numUsedChannels (tcu::getNumUsedChannels(image.getFormat().order)); |
| |
| result = verifyImageMultipleBars(log, image, barWidthRatios, barColors, barsCount, numUsedChannels, checkType); |
| } |
| |
| return result; |
| } |
| |
| case TEST_TYPE_SECONDARY_CMD_BUFFER: |
| { |
| const tcu::Vec4 clearColor = secondaryCmdBufClearColors[layerNdx % DE_LENGTH_OF_ARRAY(secondaryCmdBufClearColors)]; |
| const tcu::Vec4 quadColor = s_colors[layerNdx % DE_LENGTH_OF_ARRAY(s_colors)]; |
| // The first draw: blend clearColor and quadColor |
| const tcu::Vec4 firstDraw = (clearColor + quadColor) * 0.5f; |
| // The second draw: blend previous result and quadColor |
| const tcu::Vec4 secondDraw = (firstDraw + quadColor) * 0.5f; |
| |
| return verifyImageSingleColoredRow(log, image, 0.5f, secondDraw, layerNdx < numLayers / 2, layerNdx >= numLayers / 2); |
| } |
| |
| default: |
| DE_ASSERT(0); |
| return false; |
| } |
| } |
| |
| std::string getLayerDescription (const VkImageViewType viewType, const int layer) |
| { |
| std::ostringstream str; |
| const int numCubeFaces = 6; |
| |
| if (isCubeImageViewType(viewType)) |
| str << "cube " << (layer / numCubeFaces) << ", face " << (layer % numCubeFaces); |
| else if (viewType == VK_IMAGE_VIEW_TYPE_3D) |
| str << "slice z = " << layer; |
| else |
| str << "layer " << layer; |
| |
| return str.str(); |
| } |
| |
| bool verifyResults (tcu::TestLog& log, const TestParams& params, const VkFormat imageFormat, const void* resultData, const bool depthCheck = false, const bool stencilCheck = false) |
| { |
| const LayeredImageAccess image = LayeredImageAccess::create(getImageType(params.image.viewType), imageFormat, params.image.size, params.image.numLayers, resultData); |
| |
| int numGoodLayers = 0; |
| |
| for (int layerNdx = 0; layerNdx < image.getNumLayersOrSlices(); ++layerNdx) |
| { |
| const tcu::ConstPixelBufferAccess layerImage = image.getLayer(layerNdx); |
| |
| log << tcu::TestLog::Message << "Verifying " << getLayerDescription(params.image.viewType, layerNdx) << tcu::TestLog::EndMessage; |
| |
| if (verifyLayerContent(log, params.testType, layerImage, layerNdx, image.getNumLayersOrSlices(), depthCheck, stencilCheck)) |
| ++numGoodLayers; |
| } |
| |
| return numGoodLayers == image.getNumLayersOrSlices(); |
| } |
| |
| std::string toGlsl (const Vec4& v) |
| { |
| std::ostringstream str; |
| str << "vec4("; |
| for (int i = 0; i < 4; ++i) |
| str << (i != 0 ? ", " : "") << de::floatToString(v[i], 1); |
| str << ")"; |
| return str.str(); |
| } |
| |
| void initPrograms (SourceCollections& programCollection, const TestParams params) |
| { |
| const bool geomOutputColor = (params.testType == TEST_TYPE_ALL_LAYERS || params.testType == TEST_TYPE_INVOCATION_PER_LAYER || params.testType == TEST_TYPE_LAYERED_READBACK || params.testType == TEST_TYPE_SECONDARY_CMD_BUFFER); |
| |
| // Vertex shader |
| { |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "void main(void)\n" |
| << "{\n" |
| << "}\n"; |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); |
| } |
| |
| // Geometry shader |
| { |
| const int numLayers = static_cast<int>(params.image.viewType == VK_IMAGE_VIEW_TYPE_3D ? params.image.size.depth : params.image.numLayers); |
| |
| const int maxVertices = (params.testType == TEST_TYPE_DIFFERENT_CONTENT) ? (numLayers + 1) * numLayers : |
| (params.testType == TEST_TYPE_ALL_LAYERS |
| || params.testType == TEST_TYPE_LAYER_ID |
| || params.testType == TEST_TYPE_LAYERED_READBACK |
| || params.testType == TEST_TYPE_SECONDARY_CMD_BUFFER) ? numLayers * 4 : |
| (params.testType == TEST_TYPE_MULTIPLE_LAYERS_PER_INVOCATION) ? 6 : 4; |
| |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n"; |
| |
| if (params.testType == TEST_TYPE_LAYERED_READBACK) |
| src << "layout(binding = 0) readonly uniform Input {\n" |
| << " int pass;\n" |
| << "} uInput;\n\n"; |
| |
| if (params.testType == TEST_TYPE_INVOCATION_PER_LAYER || params.testType == TEST_TYPE_MULTIPLE_LAYERS_PER_INVOCATION) |
| src << "layout(points, invocations = " << numLayers << ") in;\n"; |
| else |
| src << "layout(points) in;\n"; |
| |
| src << "layout(triangle_strip, max_vertices = " << maxVertices << ") out;\n" |
| << "\n" |
| << (geomOutputColor ? "layout(location = 0) out vec4 vert_color;\n\n" : "") |
| << "out gl_PerVertex {\n" |
| << " vec4 gl_Position;\n" |
| << " float gl_PointSize;\n" |
| << "};\n" |
| << "\n" |
| << "void main(void)\n" |
| << "{\n"; |
| |
| std::ostringstream colorTable; |
| { |
| const int numColors = DE_LENGTH_OF_ARRAY(s_colors); |
| |
| colorTable << " const vec4 colors[" << numColors << "] = vec4[" << numColors << "]("; |
| |
| const std::string padding(colorTable.str().length(), ' '); |
| |
| for (int i = 0; i < numColors; ++i) |
| colorTable << (i != 0 ? ",\n" + padding : "") << toGlsl(s_colors[i]); |
| |
| colorTable << ");\n"; |
| } |
| |
| if (params.testType == TEST_TYPE_DEFAULT_LAYER) |
| { |
| src << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, 1.0, 0.0, 1.0);\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n"; |
| } |
| else if (params.testType == TEST_TYPE_SINGLE_LAYER) |
| { |
| const deUint32 targetLayer = getTargetLayer(params.image); |
| |
| src << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = " << targetLayer << ";\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = " << targetLayer << ";\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = " << targetLayer << ";\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = " << targetLayer << ";\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n"; |
| } |
| else if (params.testType == TEST_TYPE_ALL_LAYERS || params.testType == TEST_TYPE_SECONDARY_CMD_BUFFER) |
| { |
| src << colorTable.str() |
| << "\n" |
| << " for (int layerNdx = 0; layerNdx < " << numLayers << "; ++layerNdx) {\n" |
| << " const int colorNdx = layerNdx % " << DE_LENGTH_OF_ARRAY(s_colors) << ";\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << " EndPrimitive();\n" |
| << " };\n"; |
| } |
| else if (params.testType == TEST_TYPE_LAYER_ID) |
| { |
| src << " for (int layerNdx = 0; layerNdx < " << numLayers << "; ++layerNdx) {\n" |
| << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << " EndPrimitive();\n" |
| << " };\n"; |
| } |
| else if (params.testType == TEST_TYPE_DIFFERENT_CONTENT) |
| { |
| src << " for (int layerNdx = 0; layerNdx < " << numLayers << "; ++layerNdx) {\n" |
| << " for (int colNdx = 0; colNdx <= layerNdx; ++colNdx) {\n" |
| << " const float posX = float(colNdx) / float(" << numLayers << ") * 2.0 - 1.0;\n" |
| << "\n" |
| << " gl_Position = vec4(posX, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(posX, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << " }\n" |
| << " EndPrimitive();\n" |
| << " }\n"; |
| } |
| else if (params.testType == TEST_TYPE_INVOCATION_PER_LAYER) |
| { |
| src << colorTable.str() |
| << " const int colorNdx = gl_InvocationID % " << DE_LENGTH_OF_ARRAY(s_colors) << ";\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = gl_InvocationID;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = gl_InvocationID;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = gl_InvocationID;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4( 0.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = gl_InvocationID;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = colors[colorNdx];\n" |
| << " EmitVertex();\n" |
| << " EndPrimitive();\n"; |
| } |
| else if (params.testType == TEST_TYPE_MULTIPLE_LAYERS_PER_INVOCATION) |
| { |
| src << " const int layerA = gl_InvocationID;\n" |
| << " const int layerB = (gl_InvocationID + 1) % " << numLayers << ";\n" |
| << " const float aEnd = float(layerA) / float(" << numLayers << ") * 2.0 - 1.0;\n" |
| << " const float bEnd = float(layerB) / float(" << numLayers << ") * 2.0 - 1.0;\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerA;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerA;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(aEnd, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerA;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << " EndPrimitive();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerB;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(bEnd, 1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerB;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(bEnd, -1.0, 0.0, 1.0);\n" |
| << " gl_Layer = layerB;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " EmitVertex();\n" |
| << " EndPrimitive();\n"; |
| } |
| else if (params.testType == TEST_TYPE_LAYERED_READBACK) |
| { |
| src << colorTable.str() |
| << " for (int layerNdx = 0; layerNdx < " << numLayers << "; ++layerNdx) {\n" |
| << " const int colorNdx = layerNdx % " << DE_LENGTH_OF_ARRAY(s_colors) << ";\n" |
| << " const vec3 passColor0 = (uInput.pass == 0 ? 0.5 : 1.0) * vec3(colors[colorNdx]);\n" |
| << " const vec4 passColor = vec4(passColor0, 1.0);\n" |
| << " const float posX = (uInput.pass == 0 ? 0.0 : -0.5);\n" |
| << " const float posZ = float(layerNdx + 1 - uInput.pass) / float(" << 2*numLayers << ");\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, -1.0, posZ, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = passColor;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(-1.0, 1.0, posZ, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = passColor;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(posX, -1.0, posZ, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = passColor;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " gl_Position = vec4(posX, 1.0, posZ, 1.0);\n" |
| << " gl_Layer = layerNdx;\n" |
| << " gl_PointSize = 1.0;\n" |
| << " vert_color = passColor;\n" |
| << " EmitVertex();\n" |
| << "\n" |
| << " EndPrimitive();\n" |
| << " }\n"; |
| } |
| else |
| DE_ASSERT(0); |
| |
| src << "}\n"; // end main |
| |
| programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()); |
| } |
| |
| // Fragment shader |
| { |
| std::string imageViewString; |
| |
| switch (params.image.viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| imageViewString = "image1DArray"; |
| break; |
| case VK_IMAGE_VIEW_TYPE_2D_ARRAY: |
| imageViewString = "image2DArray"; |
| break; |
| case VK_IMAGE_VIEW_TYPE_CUBE: |
| imageViewString = "imageCube"; |
| break; |
| case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: |
| imageViewString = "imageCubeArray"; |
| break; |
| default: |
| DE_ASSERT(params.image.viewType == VK_IMAGE_VIEW_TYPE_3D); |
| imageViewString = "image3D"; |
| break; |
| } |
| |
| std::ostringstream src; |
| src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" |
| << "\n" |
| << "layout(location = 0) out vec4 o_color;\n" |
| << (geomOutputColor ? "layout(location = 0) in vec4 vert_color;\n" : "") |
| << (params.testType == TEST_TYPE_SECONDARY_CMD_BUFFER ? std::string("layout(set = 0, binding = 0, rgba8) uniform " + imageViewString + " storageImage;\n") : std::string("")) |
| << "\n" |
| << "void main(void)\n" |
| << "{\n"; |
| |
| if (params.testType == TEST_TYPE_LAYER_ID) |
| { |
| // This code must be in sync with verifyLayerContent() |
| src << " o_color = vec4( (gl_Layer % 2) == 1 ? 1.0 : 0.5,\n" |
| << " ((gl_Layer/2) % 2) == 1 ? 1.0 : 0.5,\n" |
| << " gl_Layer == 0 ? 1.0 : 0.0,\n" |
| << " 1.0);\n"; |
| } |
| else if (params.testType == TEST_TYPE_SECONDARY_CMD_BUFFER) |
| { |
| switch (params.image.viewType) |
| { |
| case VK_IMAGE_VIEW_TYPE_1D_ARRAY: |
| src << " ivec2 coord = ivec2(int(gl_FragCoord.x), gl_Layer);\n"; |
| break; |
| default: |
| src << " ivec3 coord = ivec3(int(gl_FragCoord.x), int(gl_FragCoord.y), gl_Layer);\n"; |
| break; |
| } |
| |
| src << " vec4 src_color = imageLoad(storageImage, coord);\n" |
| << " o_color = (vert_color + src_color) / 2.0;\n" |
| << " imageStore(storageImage, coord, o_color);\n"; |
| } |
| else if (geomOutputColor) |
| src << " o_color = vert_color;\n"; |
| else |
| src << " o_color = vec4(1.0);\n"; |
| |
| src << "}\n"; |
| |
| programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); |
| } |
| } |
| |
| tcu::TestStatus test (Context& context, const TestParams params) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| const VkQueue queue = context.getUniversalQueue(); |
| Allocator& allocator = context.getDefaultAllocator(); |
| VkDeviceSize nonCoherentAtomSize = vk::getPhysicalDeviceProperties(vki, physDevice).limits.nonCoherentAtomSize; |
| VkDeviceSize alignmentSize = std::max<VkDeviceSize>(nonCoherentAtomSize, 4u); |
| |
| const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| const deUint32 numLayers = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? params.image.size.depth : params.image.numLayers); |
| const Vec4 clearColor = Vec4(0.0f, 0.0f, 0.0f, 1.0f); |
| const deUint32 colorImagePixelSize = static_cast<deUint32>(tcu::getPixelSize(mapVkFormat(colorFormat))); |
| const VkDeviceSize colorBufferSize = static_cast<VkDeviceSize>(deAlignSize(params.image.size.width * params.image.size.height * colorImagePixelSize, static_cast<std::size_t>(alignmentSize)) * params.image.size.depth * params.image.numLayers); |
| const VkImageCreateFlags imageCreateFlags = (isCubeImageViewType(params.image.viewType) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (VkImageCreateFlagBits)0) | |
| (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR : (VkImageCreateFlagBits)0); |
| const VkImageViewType viewType = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : params.image.viewType); |
| |
| const Unique<VkImage> colorImage (makeImage (vk, device, makeImageCreateInfo(imageCreateFlags, getImageType(params.image.viewType), colorFormat, params.image.size, |
| params.image.numLayers, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT))); |
| const UniquePtr<Allocation> colorImageAlloc (bindImage (vk, device, allocator, *colorImage, MemoryRequirement::Any)); |
| const Unique<VkImageView> colorAttachment (makeImageView (vk, device, *colorImage, viewType, colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers))); |
| |
| const Unique<VkBuffer> colorBuffer (makeBuffer (vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> colorBufferAlloc (bindBuffer (vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible)); |
| |
| const Unique<VkShaderModule> vertexModule (createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> geometryModule (createShaderModule (vk, device, context.getBinaryCollection().get("geom"), 0u)); |
| const Unique<VkShaderModule> fragmentModule (createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u)); |
| |
| const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, colorFormat)); |
| const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, *colorAttachment, params.image.size.width, params.image.size.height, numLayers)); |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout (vk, device)); |
| const Unique<VkPipeline> pipeline (makeGraphicsPipeline (vk, device, *pipelineLayout, *renderPass, *vertexModule, *geometryModule, *fragmentModule, |
| makeExtent2D(params.image.size.width, params.image.size.height))); |
| const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| |
| zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, params.image.size.width, params.image.size.height), clearColor); |
| |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u); |
| endRenderPass(vk, *cmdBuffer); |
| |
| // Copy color image to buffer |
| copyLayeredImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, params.image); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| |
| invalidateAlloc(vk, device, *colorBufferAlloc); |
| |
| if (!verifyResults(context.getTestContext().getLog(), params, colorFormat, colorBufferAlloc->getHostPtr())) |
| return tcu::TestStatus::fail("Rendered images are incorrect"); |
| else |
| return tcu::TestStatus::pass("OK"); |
| } |
| |
| tcu::TestStatus testLayeredReadBack (Context& context, const TestParams params) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| const VkQueue queue = context.getUniversalQueue(); |
| Allocator& allocator = context.getDefaultAllocator(); |
| VkDeviceSize nonCoherentAtomSize = vk::getPhysicalDeviceProperties(vki, physDevice).limits.nonCoherentAtomSize; |
| VkDeviceSize alignmentSize = std::max<VkDeviceSize>(nonCoherentAtomSize, 4u); |
| |
| const size_t passCount = 2; |
| const deUint32 numLayers = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? params.image.size.depth : params.image.numLayers); |
| const VkImageCreateFlags imageCreateFlags = (isCubeImageViewType(params.image.viewType) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (VkImageCreateFlagBits)0) | |
| (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR : (VkImageCreateFlagBits)0); |
| const VkImageViewType viewType = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : params.image.viewType); |
| const VkImageType imageType = getImageType(params.image.viewType); |
| const VkExtent2D imageExtent2D = makeExtent2D(params.image.size.width, params.image.size.height); |
| |
| const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| const deUint32 colorImagePixelSize = static_cast<deUint32>(tcu::getPixelSize(mapVkFormat(colorFormat))); |
| const VkDeviceSize colorBufferSize = static_cast<VkDeviceSize>( deAlignSize(params.image.size.width * params.image.size.height * colorImagePixelSize, static_cast<std::size_t>(alignmentSize)) * params.image.size.depth * params.image.numLayers ); |
| const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| |
| const bool dsUsed = true; |
| const VkFormat dsFormat = VK_FORMAT_D24_UNORM_S8_UINT; |
| const VkImageType dsImageType = (imageType == VK_IMAGE_TYPE_3D ? VK_IMAGE_TYPE_2D : imageType); // depth/stencil 2D_ARRAY attachments cannot be taken from 3D image, use 2D_ARRAY image instead. |
| const VkExtent3D dsImageSize = makeExtent3D(params.image.size.width, params.image.size.height, 1u); |
| const VkImageCreateFlags dsImageCreateFlags = (isCubeImageViewType(params.image.viewType) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (VkImageCreateFlagBits)0); |
| const deUint32 dsImagePixelSize = static_cast<deUint32>(tcu::getPixelSize(mapVkFormat(dsFormat))); |
| const VkImageUsageFlags dsImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
| const VkImageAspectFlags dsAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; |
| const VkDeviceSize depthBufferSize = static_cast<VkDeviceSize>(deAlignSize(params.image.size.width * params.image.size.height * dsImagePixelSize, static_cast<std::size_t>(alignmentSize)) * params.image.size.depth * params.image.numLayers); |
| |
| const VkFormat stencilBufferFormat = getStencilBufferFormat(dsFormat); |
| const deUint32 stencilPixelSize = static_cast<deUint32>(tcu::getPixelSize(mapVkFormat(stencilBufferFormat))); |
| const VkDeviceSize stencilBufferSize = static_cast<VkDeviceSize>(deAlignSize( params.image.size.width * params.image.size.height * stencilPixelSize, static_cast<std::size_t>(alignmentSize)) * params.image.size.depth * params.image.numLayers); |
| |
| checkImageFormatProperties(vki, physDevice, imageType, VK_IMAGE_TILING_OPTIMAL, dsImageUsage, imageCreateFlags, dsFormat, params.image.size, params.image.numLayers); |
| |
| const Unique<VkImage> colorImage (makeImage (vk, device, makeImageCreateInfo(imageCreateFlags, imageType, colorFormat, params.image.size, params.image.numLayers, colorImageUsage))); |
| const UniquePtr<Allocation> colorImageAlloc (bindImage (vk, device, allocator, *colorImage, MemoryRequirement::Any)); |
| const Unique<VkImageView> colorAttachment (makeImageView (vk, device, *colorImage, viewType, colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers))); |
| const Unique<VkBuffer> colorBuffer (makeBuffer (vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> colorBufferAlloc (bindBuffer (vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible)); |
| |
| const Unique<VkImage> dsImage (makeImage (vk, device, makeImageCreateInfo(dsImageCreateFlags, dsImageType, dsFormat, dsImageSize, numLayers, dsImageUsage))); |
| const UniquePtr<Allocation> dsImageAlloc (bindImage (vk, device, allocator, *dsImage, MemoryRequirement::Any)); |
| const Unique<VkImageView> dsAttachment (makeImageView (vk, device, *dsImage, viewType, dsFormat, makeImageSubresourceRange(dsAspectFlags, 0u, 1u, 0u, numLayers))); |
| const Unique<VkBuffer> depthBuffer (makeBuffer (vk, device, depthBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> depthBufferAlloc (bindBuffer (vk, device, allocator, *depthBuffer, MemoryRequirement::HostVisible)); |
| const Unique<VkBuffer> stencilBuffer (makeBuffer (vk, device, stencilBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> stencilBufferAlloc (bindBuffer (vk, device, allocator, *stencilBuffer, MemoryRequirement::HostVisible)); |
| |
| const VkImageView attachments[] = {*colorAttachment, *dsAttachment}; |
| const deUint32 attachmentsCount = dsUsed ? DE_LENGTH_OF_ARRAY(attachments) : 1u; |
| |
| const Unique<VkShaderModule> vertexModule (createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> geometryModule (createShaderModule (vk, device, context.getBinaryCollection().get("geom"), 0u)); |
| const Unique<VkShaderModule> fragmentModule (createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u)); |
| |
| const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, colorFormat, dsFormat, dsUsed)); |
| const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, attachmentsCount, attachments, params.image.size.width, params.image.size.height, numLayers)); |
| |
| const Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, passCount) |
| .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, passCount); |
| const Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT) |
| .build(vk, device); |
| const Move<VkDescriptorSet> descriptorSet[] = |
| { |
| makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout), |
| makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout), |
| }; |
| |
| const size_t uniformBufSize = sizeof(deUint32); |
| const VkBufferCreateInfo uniformBufCI = makeBufferCreateInfo(uniformBufSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); |
| const Move<VkBuffer> uniformBuf[] = { createBuffer(vk, device, &uniformBufCI), createBuffer(vk, device, &uniformBufCI) }; |
| const MovePtr<Allocation> uniformBufAlloc[] = |
| { |
| allocator.allocate(getBufferMemoryRequirements(vk, device, *uniformBuf[0]), MemoryRequirement::HostVisible), |
| allocator.allocate(getBufferMemoryRequirements(vk, device, *uniformBuf[1]), MemoryRequirement::HostVisible), |
| }; |
| const VkDescriptorBufferInfo uniformBufDesc[] = |
| { |
| makeDescriptorBufferInfo(*uniformBuf[0], 0ull, uniformBufSize), |
| makeDescriptorBufferInfo(*uniformBuf[1], 0ull, uniformBufSize), |
| }; |
| |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout (vk, device, *descriptorSetLayout)); |
| const Unique<VkPipeline> pipeline (makeGraphicsPipeline (vk, device, *pipelineLayout, *renderPass, *vertexModule, *geometryModule, *fragmentModule, imageExtent2D, dsUsed)); |
| const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer (vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const VkImageSubresourceRange colorSubresRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, params.image.numLayers); |
| const VkImageSubresourceRange dsSubresRange = makeImageSubresourceRange(dsAspectFlags, 0u, 1u, 0u, numLayers); |
| std::string result; |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| { |
| // Transition the images to new layouts |
| const VkImageMemoryBarrier colorBarrier = makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, *colorImage, colorSubresRange); |
| const VkImageMemoryBarrier dsBarrier = makeImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, *dsImage, dsSubresRange); |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &colorBarrier); |
| |
| if (dsUsed) |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &dsBarrier); |
| |
| for (deUint32 layerNdx = 0; layerNdx < numLayers; ++layerNdx) |
| { |
| const VkExtent3D imageExtent = makeExtent3D(params.image.size.width, params.image.size.height, 1u); |
| |
| // Clear color image with initial value |
| { |
| const deUint32 layer = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType) ? 0u : layerNdx; |
| const deUint32 imageDepth = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType) ? layerNdx : 0u; |
| const VkOffset3D imageOffset = makeOffset3D(0u, 0u, imageDepth); |
| |
| const tcu::Vec4 clearColor = scaleColor(s_colors[layerNdx % DE_LENGTH_OF_ARRAY(s_colors)], 0.25f); |
| const deUint32 bufferSliceSize = deAlign32( params.image.size.width * params.image.size.height * colorImagePixelSize, static_cast<deInt32>(alignmentSize)); |
| const VkDeviceSize bufferOffset = layerNdx * bufferSliceSize; |
| const VkImageSubresourceLayers imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layer, 1u); |
| const VkBufferImageCopy bufferImageCopyRegion = makeBufferImageCopy(bufferOffset, imageSubresource, imageOffset, imageExtent); |
| |
| fillBuffer(vk, device, *colorBufferAlloc, bufferOffset, bufferSliceSize, colorFormat, clearColor); |
| vk.cmdCopyBufferToImage(*cmdBuffer, *colorBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferImageCopyRegion); |
| } |
| |
| // Clear depth image with initial value |
| if (dsUsed) |
| { |
| const float depthValue = 1.0f; |
| const deUint32 bufferSliceSize = deAlign32( params.image.size.width * params.image.size.height * dsImagePixelSize, static_cast<deInt32>(alignmentSize)); |
| const VkDeviceSize bufferOffset = layerNdx * bufferSliceSize; |
| const VkImageSubresourceLayers imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, layerNdx, 1u); |
| const VkBufferImageCopy bufferImageCopyRegion = makeBufferImageCopy(bufferOffset, imageSubresource, makeOffset3D(0u, 0u, 0u), imageExtent); |
| |
| fillBuffer(vk, device, *depthBufferAlloc, bufferOffset, bufferSliceSize, dsFormat, depthValue); |
| vk.cmdCopyBufferToImage(*cmdBuffer, *depthBuffer, *dsImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferImageCopyRegion); |
| } |
| |
| // Clear stencil image with initial value |
| if (dsUsed) |
| { |
| const deUint8 stencilValue = 0; |
| const deUint32 bufferSliceSize = deAlign32( params.image.size.width * params.image.size.height * stencilPixelSize, static_cast<deInt32>(alignmentSize)); |
| const VkDeviceSize bufferOffset = layerNdx * bufferSliceSize; |
| const VkImageSubresourceLayers imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, layerNdx, 1u); |
| const VkBufferImageCopy bufferImageCopyRegion = makeBufferImageCopy(bufferOffset, imageSubresource, makeOffset3D(0u, 0u, 0u), imageExtent); |
| deUint8* bufferStart = static_cast<deUint8*>((*stencilBufferAlloc).getHostPtr()); |
| deUint8* bufferLayerStart = &bufferStart[bufferOffset]; |
| |
| deMemset(bufferLayerStart, stencilValue, bufferSliceSize); |
| flushMappedMemoryRange(vk, device, stencilBufferAlloc->getMemory(), stencilBufferAlloc->getOffset() + bufferOffset, bufferSliceSize); |
| vk.cmdCopyBufferToImage(*cmdBuffer, *stencilBuffer, *dsImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferImageCopyRegion); |
| } |
| } |
| } |
| // Change images layouts |
| { |
| // VK_ATTACHMENT_LOAD_OP_LOAD is used for both color and D/S attachments. Thus, |
| // VK_ACCESS_COLOR_ATTACHMENT_READ_BIT and VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
| // bits must be included in the destination access mask of the color and depth barriers |
| // respectively. |
| const VkImageMemoryBarrier colorBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, *colorImage, colorSubresRange); |
| const VkImageMemoryBarrier dsBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, |
| VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, *dsImage, dsSubresRange); |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &colorBarrier); |
| |
| if (dsUsed) |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &dsBarrier); |
| } |
| |
| { |
| // These barriers are inserted between each pair of renderpasses in the following |
| // loop. Note that VK_ATTACHMENT_LOAD_OP_LOAD is used for color and D/S attachments |
| // hence VK_ACCESS_COLOR_ATTACHMENT_READ_BIT and VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
| // bits are included in src and dst access mask of the color and depth barriers. |
| const VkImageMemoryBarrier colorPassBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, |
| VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, *colorImage, colorSubresRange); |
| const VkImageMemoryBarrier dsPassBarrier = makeImageMemoryBarrier(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, |
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, |
| VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, *dsImage, dsSubresRange); |
| for (deUint32 pass = 0; pass < passCount; ++pass) |
| { |
| DE_ASSERT(sizeof(pass) == uniformBufSize); |
| |
| VK_CHECK(vk.bindBufferMemory(device, *uniformBuf[pass], uniformBufAlloc[pass]->getMemory(), uniformBufAlloc[pass]->getOffset())); |
| deMemcpy(uniformBufAlloc[pass]->getHostPtr(), &pass, uniformBufSize); |
| flushMappedMemoryRange(vk, device, uniformBufAlloc[pass]->getMemory(), uniformBufAlloc[pass]->getOffset(), VK_WHOLE_SIZE); |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet[pass], DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &uniformBufDesc[pass]) |
| .update(vk, device); |
| |
| vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet[pass], 0u, DE_NULL); |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(imageExtent2D)); |
| vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u); |
| endRenderPass(vk, *cmdBuffer); |
| |
| // Don't add the barrier after the last renderpass |
| if (pass < passCount - 1) |
| { |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &colorPassBarrier); |
| |
| if (dsUsed) |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &dsPassBarrier); |
| } |
| } |
| } |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| |
| zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize); |
| zeroBuffer(vk, device, *depthBufferAlloc, depthBufferSize); |
| zeroBuffer(vk, device, *stencilBufferAlloc, stencilBufferSize); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| { |
| // Copy color image |
| { |
| const VkImageMemoryBarrier preCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, |
| VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorImage, colorSubresRange); |
| const VkBufferImageCopy region = makeBufferImageCopy(params.image.size, makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, params.image.numLayers)); |
| const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, VK_WHOLE_SIZE); |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyBarrier); |
| vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, ®ion); |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &postCopyBarrier, DE_NULL, 0u); |
| } |
| |
| // Depth/Stencil image copy |
| if (dsUsed) |
| { |
| const VkImageMemoryBarrier preCopyBarrier = makeImageMemoryBarrier(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, |
| VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *dsImage, dsSubresRange); |
| const VkBufferImageCopy depthCopyRegion = makeBufferImageCopy(dsImageSize, makeImageSubresourceLayers(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 0u, numLayers)); |
| const VkBufferImageCopy stencilCopyRegion = makeBufferImageCopy(dsImageSize, makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 0u, numLayers)); |
| const VkBufferMemoryBarrier postCopyBarriers[] = |
| { |
| makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *depthBuffer, 0ull, VK_WHOLE_SIZE), |
| makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *stencilBuffer, 0ull, VK_WHOLE_SIZE), |
| }; |
| |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyBarrier); |
| vk.cmdCopyImageToBuffer(*cmdBuffer, *dsImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *depthBuffer, 1u, &depthCopyRegion); |
| vk.cmdCopyImageToBuffer(*cmdBuffer, *dsImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *stencilBuffer, 1u, &stencilCopyRegion); |
| vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(postCopyBarriers), postCopyBarriers, DE_NULL, 0u); |
| } |
| } |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| |
| invalidateAlloc(vk, device, *colorBufferAlloc); |
| invalidateAlloc(vk, device, *depthBufferAlloc); |
| invalidateAlloc(vk, device, *stencilBufferAlloc); |
| |
| if (!verifyResults(context.getTestContext().getLog(), params, colorFormat, colorBufferAlloc->getHostPtr())) |
| result += " Color"; |
| |
| if (dsUsed) |
| { |
| if (!verifyResults(context.getTestContext().getLog(), params, dsFormat, depthBufferAlloc->getHostPtr(), true, false)) |
| result += " Depth"; |
| |
| if (!verifyResults(context.getTestContext().getLog(), params, stencilBufferFormat, stencilBufferAlloc->getHostPtr(), false, true)) |
| result += " Stencil"; |
| } |
| |
| if (result.empty()) |
| return tcu::TestStatus::pass("OK"); |
| else |
| return tcu::TestStatus::fail("Following parts of image are incorrect:" + result); |
| } |
| |
| tcu::TestStatus testSecondaryCmdBuffer (Context& context, const TestParams params) |
| { |
| const DeviceInterface& vk = context.getDeviceInterface(); |
| const InstanceInterface& vki = context.getInstanceInterface(); |
| const VkDevice device = context.getDevice(); |
| const VkPhysicalDevice physDevice = context.getPhysicalDevice(); |
| const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); |
| const VkQueue queue = context.getUniversalQueue(); |
| Allocator& allocator = context.getDefaultAllocator(); |
| VkDeviceSize nonCoherentAtomSize = vk::getPhysicalDeviceProperties(vki, physDevice).limits.nonCoherentAtomSize; |
| VkDeviceSize alignmentSize = std::max<VkDeviceSize>(nonCoherentAtomSize, 4u); |
| |
| const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| const deUint32 numLayers = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? params.image.size.depth : params.image.numLayers); |
| const Vec4 clearColor = Vec4(0.0f, 0.0f, 0.0f, 1.0f); |
| const deUint32 colorImagePixelSize = static_cast<deUint32>(tcu::getPixelSize(mapVkFormat(colorFormat))); |
| const VkDeviceSize colorBufferSize = static_cast<VkDeviceSize>(deAlignSize(params.image.size.width * params.image.size.height * colorImagePixelSize, static_cast<std::size_t>(alignmentSize)) * params.image.size.depth * params.image.numLayers); |
| |
| const VkImageCreateFlags imageCreateFlags = (isCubeImageViewType(params.image.viewType) ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (VkImageCreateFlagBits)0) | |
| (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR : (VkImageCreateFlagBits)0); |
| const VkImageViewType viewType = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : params.image.viewType); |
| |
| const Unique<VkImage> colorImage (makeImage(vk, device, makeImageCreateInfo(imageCreateFlags, getImageType(params.image.viewType), colorFormat, params.image.size, |
| params.image.numLayers, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT))); |
| const UniquePtr<Allocation> colorImageAlloc (bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any)); |
| const Unique<VkImageView> colorImageView (makeImageView(vk, device, *colorImage, viewType, colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, numLayers))); |
| |
| const Unique<VkImage> offscreenImage (makeImage(vk, device, makeImageCreateInfo(imageCreateFlags, getImageType(params.image.viewType), colorFormat, params.image.size, |
| params.image.numLayers, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT))); |
| const UniquePtr<Allocation> offscreenImageAlloc (bindImage(vk, device, allocator, *offscreenImage, MemoryRequirement::Any)); |
| const Unique<VkImageView> offscreenImageView (makeImageView(vk, device, *offscreenImage, params.image.viewType, colorFormat, |
| makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, params.image.numLayers))); |
| |
| const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)); |
| const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible)); |
| |
| const Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| const Move<VkDescriptorSetLayout> descriptorSetLayout = DescriptorSetLayoutBuilder() .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT) .build(vk, device); |
| const Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout); |
| |
| const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> geometryModule (createShaderModule(vk, device, context.getBinaryCollection().get("geom"), 0u)); |
| const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u)); |
| |
| const Unique<VkRenderPass> renderPass (makeRenderPassWithSelfDependency(vk, device, colorFormat)); |
| const Unique<VkFramebuffer> framebuffer (makeFramebuffer(vk, device, *renderPass, *colorImageView, params.image.size.width, params.image.size.height, numLayers)); |
| const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); |
| const Unique<VkPipeline> pipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *geometryModule, *fragmentModule, |
| makeExtent2D(params.image.size.width, params.image.size.height))); |
| |
| const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const Unique<VkCommandBuffer> secondaryCmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY)); |
| |
| zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize); |
| |
| const VkDescriptorImageInfo imageDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *offscreenImageView, VK_IMAGE_LAYOUT_GENERAL); |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageDescriptorInfo) |
| .update(vk, device); |
| |
| // Clear each layer of storage image |
| { |
| vk::Unique<vk::VkCommandBuffer> clearCmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| beginCommandBuffer(vk, *clearCmdBuffer); |
| |
| const vk::VkImageSubresourceRange subresourceRange = |
| { |
| vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 baseMipLevel |
| 1u, // deUint32 levelCount |
| 0u, // deUint32 baseArrayLayer |
| params.image.numLayers // deUint32 layerCount |
| }; |
| |
| const vk::VkImageMemoryBarrier preImageBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkAccessFlags srcAccessMask |
| vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask |
| vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout |
| vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout |
| queueFamilyIndex, // deUint32 srcQueueFamilyIndex |
| queueFamilyIndex, // deUint32 dstQueueFamilyIndex |
| *offscreenImage, // VkImage image |
| subresourceRange // VkImageSubresourceRange subresourceRange |
| }; |
| |
| const vk::VkImageMemoryBarrier postImageBarrier = |
| { |
| vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask |
| vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout |
| vk::VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout |
| queueFamilyIndex, // deUint32 srcQueueFamilyIndex |
| queueFamilyIndex, // deUint32 dstQueueFamilyIndex |
| *offscreenImage, // VkImage image |
| subresourceRange // VkImageSubresourceRange subresourceRange |
| }; |
| |
| vk.cmdPipelineBarrier(*clearCmdBuffer, |
| vk::VK_PIPELINE_STAGE_HOST_BIT, |
| vk::VK_PIPELINE_STAGE_TRANSFER_BIT, |
| (vk::VkDependencyFlags)0, |
| 0, (const vk::VkMemoryBarrier*)DE_NULL, |
| 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, |
| 1, &preImageBarrier); |
| |
| for (deUint32 layerNdx = 0; layerNdx < numLayers; ++layerNdx) |
| { |
| const deUint32 imageDepth = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType) ? layerNdx : 0u; |
| const deUint32 layer = (VK_IMAGE_VIEW_TYPE_3D == params.image.viewType) ? 0u : layerNdx; |
| const VkOffset3D imageOffset = makeOffset3D(0u, 0u, imageDepth); |
| const VkExtent3D imageExtent = makeExtent3D(params.image.size.width, params.image.size.height, 1u); |
| |
| { |
| const tcu::Vec4 storageImageClearColor = secondaryCmdBufClearColors[layerNdx % DE_LENGTH_OF_ARRAY(secondaryCmdBufClearColors)]; |
| const deUint32 bufferSliceSize = deAlign32(params.image.size.width * params.image.size.height * colorImagePixelSize, static_cast<deInt32>(alignmentSize)); |
| const VkDeviceSize bufferOffset = layerNdx * bufferSliceSize; |
| const VkImageSubresourceLayers imageSubresource = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layer, 1u); |
| const VkBufferImageCopy bufferImageCopyRegion = makeBufferImageCopy(bufferOffset, imageSubresource, imageOffset, imageExtent); |
| |
| fillBuffer(vk, device, *colorBufferAlloc, bufferOffset, bufferSliceSize, colorFormat, storageImageClearColor); |
| vk.cmdCopyBufferToImage(*clearCmdBuffer, *colorBuffer, *offscreenImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &bufferImageCopyRegion); |
| } |
| } |
| |
| vk.cmdPipelineBarrier(*clearCmdBuffer, |
| vk::VK_PIPELINE_STAGE_TRANSFER_BIT, |
| vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| (vk::VkDependencyFlags)0, |
| 0, (const vk::VkMemoryBarrier*)DE_NULL, |
| 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, |
| 1, &postImageBarrier); |
| |
| endCommandBuffer(vk, *clearCmdBuffer); |
| |
| submitCommandsAndWait(vk, device, queue, *clearCmdBuffer); |
| } |
| |
| // Begin secondary command buffer |
| { |
| const VkCommandBufferInheritanceInfo commandBufferInheritanceInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| *renderPass, // VkRenderPass renderPass |
| 0u, // deUint32 subpass |
| params.inheritFramebuffer ? *framebuffer : (VkFramebuffer)0, // VkFramebuffer framebuffer |
| VK_FALSE, // VkBool32 occlusionQueryEnable |
| 0u, // VkQueryControlFlags queryFlags |
| 0u // VkQueryPipelineStatisticFlags pipelineStatistics |
| }; |
| |
| const VkCommandBufferBeginInfo commandBufferBeginInfo = |
| { |
| VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT |
| | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, // VkCommandBufferUsageFlags flags |
| &commandBufferInheritanceInfo // const VkCommandBufferInheritanceInfo* pInheritanceInfo |
| }; |
| |
| VK_CHECK(vk.beginCommandBuffer(*secondaryCmdBuffer, &commandBufferBeginInfo)); |
| } |
| |
| vk.cmdBindDescriptorSets(*secondaryCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); |
| |
| // Clear framebuffer: upper right corner for half of the layers and bottom right for the others. |
| { |
| const VkClearAttachment clearAttachment = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 colorAttachment |
| makeClearValueColorF32(0.5f, 0.25, 0.0f, 1.0f) // VkClearValue clearValue |
| }; |
| |
| const VkOffset2D offsetTop = { (deInt32)params.image.size.width / 2, 0 }; |
| const VkOffset2D offsetBottom = { (deInt32)params.image.size.width / 2, (deInt32)params.image.size.height / 2 }; |
| const VkExtent2D extentTop = { params.image.size.width / 2, params.image.size.height / 2 }; |
| const VkExtent2D extentBottom = { params.image.size.width / 2, de::max(params.image.size.height / 2, 1u) }; |
| const VkRect2D rectRightTop = { offsetTop, extentTop }; |
| const VkRect2D rectRightBottom = { offsetBottom, extentBottom }; |
| |
| const VkClearRect rects[] = |
| { |
| { |
| rectRightBottom, // VkRect2D rect |
| numLayers / 2, // deUint32 baseArrayLayer |
| numLayers / 2 // deUint32 layerCount |
| }, |
| { |
| rectRightTop, // VkRect2D rect |
| 0u, // deUint32 baseArrayLayer |
| numLayers / 2 // deUint32 layerCount |
| } |
| }; |
| |
| vk.cmdClearAttachments(*secondaryCmdBuffer, 1u, &clearAttachment, extentTop.height > 0 ? 2u : 1u, rects); |
| } |
| |
| vk.cmdBindPipeline(*secondaryCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); |
| vk.cmdDraw(*secondaryCmdBuffer, 1u, 1u, 0u, 0u); |
| // Barrier between draws |
| { |
| const VkMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_SHADER_READ_BIT // VkAccessFlags dstAccessMask |
| }; |
| |
| vk.cmdPipelineBarrier(*secondaryCmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u, &barrier, 0u, DE_NULL, 0u, DE_NULL); |
| } |
| vk.cmdDraw(*secondaryCmdBuffer, 1u, 1u, 0u, 0u); |
| endCommandBuffer(vk, *secondaryCmdBuffer); |
| |
| beginCommandBuffer(vk, *cmdBuffer); |
| beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, params.image.size.width, params.image.size.height), clearColor, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); |
| vk.cmdExecuteCommands(*cmdBuffer, 1u, &(*secondaryCmdBuffer)); |
| endRenderPass(vk, *cmdBuffer); |
| |
| copyLayeredImageToBuffer(vk, *cmdBuffer, *colorImage, *colorBuffer, params.image); |
| |
| endCommandBuffer(vk, *cmdBuffer); |
| submitCommandsAndWait(vk, device, queue, *cmdBuffer); |
| |
| invalidateAlloc(vk, device, *colorBufferAlloc); |
| |
| if (!verifyResults(context.getTestContext().getLog(), params, colorFormat, colorBufferAlloc->getHostPtr())) |
| return tcu::TestStatus::fail("Rendered images are incorrect"); |
| else |
| return tcu::TestStatus::pass("OK"); |
| } |
| |
| void checkSupport (Context& context, const TestParams params) |
| { |
| context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); |
| |
| if (params.image.viewType == VK_IMAGE_VIEW_TYPE_3D) |
| { |
| context.requireDeviceFunctionality("VK_KHR_maintenance1"); |
| |
| if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && |
| !context.getPortabilitySubsetFeatures().imageView2DOn3DImage) |
| { |
| TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Implementation does not support 2D or 2D array image view to be created on a 3D VkImage"); |
| } |
| } |
| |
| if (params.testType == TEST_TYPE_SECONDARY_CMD_BUFFER) |
| context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS); |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createLayeredRenderingTests (tcu::TestContext& testCtx) |
| { |
| MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "layered", "Layered rendering tests.")); |
| |
| const struct |
| { |
| TestType test; |
| const char* name; |
| const char* description; |
| } testTypes[] = |
| { |
| { TEST_TYPE_DEFAULT_LAYER, "render_to_default_layer", "Render to the default layer" }, |
| { TEST_TYPE_SINGLE_LAYER, "render_to_one", "Render to one layer" }, |
| { TEST_TYPE_ALL_LAYERS, "render_to_all", "Render to all layers" }, |
| { TEST_TYPE_DIFFERENT_CONTENT, "render_different_content", "Render different data to different layers" }, |
| { TEST_TYPE_LAYER_ID, "fragment_layer", "Read gl_Layer in fragment shader" }, |
| { TEST_TYPE_INVOCATION_PER_LAYER, "invocation_per_layer", "Render to multiple layers with multiple invocations, one invocation per layer" }, |
| { TEST_TYPE_MULTIPLE_LAYERS_PER_INVOCATION, "multiple_layers_per_invocation", "Render to multiple layers with multiple invocations, multiple layers per invocation", }, |
| { TEST_TYPE_LAYERED_READBACK, "readback", "Render to multiple layers with two passes to check LOAD_OP_LOAD capability" }, |
| { TEST_TYPE_SECONDARY_CMD_BUFFER, "secondary_cmd_buffer", "Layered rendering using secondary command buffer" } |
| }; |
| |
| const struct |
| { |
| VkImageViewType viewType; |
| ImageParams imageParams[2]; |
| } imageParamGroups[] = |
| { |
| { VK_IMAGE_VIEW_TYPE_1D_ARRAY, { { VK_IMAGE_VIEW_TYPE_1D_ARRAY, { 64, 1, 1 }, 4 }, { VK_IMAGE_VIEW_TYPE_1D_ARRAY, { 12, 1, 1 }, 6 } } }, |
| { VK_IMAGE_VIEW_TYPE_2D_ARRAY, { { VK_IMAGE_VIEW_TYPE_2D_ARRAY, { 64, 64, 1 }, 4 }, { VK_IMAGE_VIEW_TYPE_2D_ARRAY, { 12, 36, 1 }, 6 } } }, |
| { VK_IMAGE_VIEW_TYPE_CUBE, { { VK_IMAGE_VIEW_TYPE_CUBE, { 64, 64, 1 }, 6 }, { VK_IMAGE_VIEW_TYPE_CUBE, { 36, 36, 1 }, 6 } } }, |
| { VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, { { VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, { 64, 64, 1 }, 2*6 }, { VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, { 36, 36, 1 }, 2*6 } } }, |
| { VK_IMAGE_VIEW_TYPE_3D, { { VK_IMAGE_VIEW_TYPE_3D, { 64, 64, 8 }, 1 }, { VK_IMAGE_VIEW_TYPE_3D, { 12, 36, 6 }, 1 } } } |
| }; |
| |
| for (int imageParamGroupNdx = 0; imageParamGroupNdx < DE_LENGTH_OF_ARRAY(imageParamGroups); ++imageParamGroupNdx) |
| { |
| MovePtr<tcu::TestCaseGroup> viewTypeMainGroup(new tcu::TestCaseGroup(testCtx, getShortImageViewTypeName(imageParamGroups[imageParamGroupNdx].viewType).c_str(), "")); |
| |
| for (int imageParamNdx = 0; imageParamNdx < 2; imageParamNdx++) |
| { |
| std::ostringstream viewTypeGroupName; |
| viewTypeGroupName << imageParamGroups[imageParamGroupNdx].imageParams[imageParamNdx].size.width << "_" << imageParamGroups[imageParamGroupNdx].imageParams[imageParamNdx].size.height << "_"; |
| if (imageParamGroups[imageParamGroupNdx].imageParams[imageParamNdx].viewType == VK_IMAGE_VIEW_TYPE_3D) |
| viewTypeGroupName << imageParamGroups[imageParamGroupNdx].imageParams[imageParamNdx].size.depth; |
| else |
| viewTypeGroupName << imageParamGroups[imageParamGroupNdx].imageParams[imageParamNdx].numLayers; |
| MovePtr<tcu::TestCaseGroup> viewTypeGroup(new tcu::TestCaseGroup(testCtx, viewTypeGroupName.str().c_str(), "")); |
| |
| for (int testTypeNdx = 0; testTypeNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypeNdx) |
| { |
| TestParams params = |
| { |
| testTypes[testTypeNdx].test, |
| imageParamGroups[imageParamGroupNdx].imageParams[imageParamNdx], |
| false |
| }; |
| |
| if (testTypes[testTypeNdx].test == TEST_TYPE_LAYERED_READBACK) |
| addFunctionCaseWithPrograms(viewTypeGroup.get(), testTypes[testTypeNdx].name, testTypes[testTypeNdx].description, checkSupport, initPrograms, testLayeredReadBack, params); |
| else if (testTypes[testTypeNdx].test == TEST_TYPE_SECONDARY_CMD_BUFFER) |
| { |
| addFunctionCaseWithPrograms(viewTypeGroup.get(), "secondary_cmd_buffer", testTypes[testTypeNdx].description, checkSupport, initPrograms, testSecondaryCmdBuffer, params); |
| params.inheritFramebuffer = true; |
| addFunctionCaseWithPrograms(viewTypeGroup.get(), "secondary_cmd_buffer_inherit_framebuffer", testTypes[testTypeNdx].description, checkSupport, initPrograms, testSecondaryCmdBuffer, params); |
| } |
| else |
| addFunctionCaseWithPrograms(viewTypeGroup.get(), testTypes[testTypeNdx].name, testTypes[testTypeNdx].description, checkSupport, initPrograms, test, params); |
| } |
| viewTypeMainGroup->addChild(viewTypeGroup.release()); |
| } |
| group->addChild(viewTypeMainGroup.release()); |
| } |
| |
| return group.release(); |
| } |
| |
| } // geometry |
| } // vkt |