Added test for color attachments with different sizes.
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / pipeline / vktPipelineFramebufferAttachmentTests.cpp
index 71efb0b..c932d90 100644 (file)
@@ -192,7 +192,7 @@ Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&               vk,
                                                                           const IVec3                                  renderSize,
                                                                           const VkPrimitiveTopology    topology,
                                                                           const deUint32                               subpass,
-                                                                          const bool                                   hasAttachments,
+                                                                          const deUint32                               numAttachments,
                                                                           const bool                                   multisample)
 {
        const VkVertexInputBindingDescription vertexInputBindingDescription =
@@ -327,16 +327,20 @@ Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&             vk,
                colorComponentsAll,                     // VkColorComponentFlags        colorWriteMask;
        };
 
+       std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachmentStates;
+       for (deUint32 attachmentIdx = 0; attachmentIdx < numAttachments; attachmentIdx++)
+               colorBlendAttachmentStates.push_back(pipelineColorBlendAttachmentState);
+
        const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
        {
-               VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,       // VkStructureType                                                              sType;
-               DE_NULL,                                                                                                        // const void*                                                                  pNext;
-               (VkPipelineColorBlendStateCreateFlags)0,                                        // VkPipelineColorBlendStateCreateFlags                 flags;
-               VK_FALSE,                                                                                                       // VkBool32                                                                             logicOpEnable;
-               VK_LOGIC_OP_COPY,                                                                                       // VkLogicOp                                                                    logicOp;
-               hasAttachments ? 1u : 0u,                                                                       // deUint32                                                                             attachmentCount;
-               &pipelineColorBlendAttachmentState,                                                     // const VkPipelineColorBlendAttachmentState*   pAttachments;
-               { 0.0f, 0.0f, 0.0f, 0.0f },                                                                     // float                                                                                blendConstants[4];
+               VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,               // VkStructureType                                                              sType;
+               DE_NULL,                                                                                                                // const void*                                                                  pNext;
+               (VkPipelineColorBlendStateCreateFlags)0,                                                // VkPipelineColorBlendStateCreateFlags                 flags;
+               VK_FALSE,                                                                                                               // VkBool32                                                                             logicOpEnable;
+               VK_LOGIC_OP_COPY,                                                                                               // VkLogicOp                                                                    logicOp;
+               numAttachments,                                                                                                 // deUint32                                                                             attachmentCount;
+               numAttachments == 0 ? DE_NULL : &colorBlendAttachmentStates[0], // const VkPipelineColorBlendAttachmentState*   pAttachments;
+               { 0.0f, 0.0f, 0.0f, 0.0f },                                                                             // float                                                                                blendConstants[4];
        };
 
        const VkPipelineShaderStageCreateInfo pShaderStages[] =
@@ -589,7 +593,7 @@ tcu::TestStatus test (Context& context, const CaseDef caseDef)
                attachmentHandles.push_back(**colorAttachments.back());
 
                pipeline.push_back(makeSharedPtr(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
-                       caseDef.renderSize, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, layerNdx, true, caseDef.multisample)));
+                       caseDef.renderSize, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, layerNdx, 1u, caseDef.multisample)));
        }
 
        // create framebuffer
@@ -988,7 +992,7 @@ tcu::TestStatus testNoAtt (Context& context, const bool multisample)
 
        // Create render pass and pipeline
        pipeline.push_back(makeSharedPtr(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
-               renderSize, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, false, multisample)));
+               renderSize, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, 0u, multisample)));
        framebuffer = makeFramebuffer(vk, device, *renderPass, 0, DE_NULL, renderSize.x(), renderSize.y());
 
        // Record command buffer
@@ -1105,6 +1109,442 @@ tcu::TestStatus testNoAtt (Context& context, const bool multisample)
        return tcu::TestStatus::pass("Pass");
 }
 
+//! Make a render pass with three color attachments
+Move<VkRenderPass> makeRenderPassDifferentAttachmentSizes      (const DeviceInterface& vk,
+                                                                                                                        const VkDevice                 device,
+                                                                                                                        const VkFormat                 colorFormat,
+                                                                                                                        deUint32                               numAttachments,
+                                                                                                                        const bool                             multisample)
+{
+       vector<VkAttachmentDescription> attachmentDescriptions          (numAttachments);
+       vector<VkAttachmentReference>   colorAttachmentReferences       (numAttachments);
+
+       for (deUint32 i = 0; i < numAttachments; i++)
+       {
+               VkAttachmentDescription colorAttachmentDescription =
+               {
+                       (VkAttachmentDescriptionFlags)0,                                                                // VkAttachmentDescriptionFla   flags;
+                       colorFormat,                                                                                                    // VkFormat                                             format;
+                       !multisample ? VK_SAMPLE_COUNT_1_BIT : VK_SAMPLE_COUNT_4_BIT,   // VkSampleCountFlagBits                samples;
+                       VK_ATTACHMENT_LOAD_OP_LOAD,                                                                             // 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_GENERAL,                                                                                // VkImageLayout                                initialLayout;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                               // VkImageLayout                                finalLayout;
+               };
+               attachmentDescriptions[i] = colorAttachmentDescription;
+
+               const VkAttachmentReference attachmentRef =
+               {
+                       i,                                                                                      // deUint32                     attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL        // VkImageLayout        layout;
+               };
+               colorAttachmentReferences[i] = attachmentRef;
+       }
+
+       const VkSubpassDescription subpassDescription =
+       {
+               (VkSubpassDescriptionFlags)0,           // VkSubpassDescriptionFlags            flags;
+               VK_PIPELINE_BIND_POINT_GRAPHICS,        // VkPipelineBindPoint                          pipelineBindPoint;
+               0u,                                                                     // deUint32                                                     inputAttachmentCount;
+               DE_NULL,                                                        // const VkAttachmentReference*         pInputAttachments;
+               numAttachments,                                         // deUint32                                                     colorAttachmentCount;
+               &colorAttachmentReferences[0],          // const VkAttachmentReference*         pColorAttachments;
+               DE_NULL,                                                        // const VkAttachmentReference*         pResolveAttachments;
+               DE_NULL,                                                        // const VkAttachmentReference*         pDepthStencilAttachment;
+               0u,                                                                     // deUint32                                                     preserveAttachmentCount;
+               DE_NULL                                                         // const deUint32*                                      pPreserveAttachments;
+       };
+
+       const VkRenderPassCreateInfo renderPassInfo =
+       {
+               VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,      // VkStructureType                                      sType;
+               DE_NULL,                                                                        // const void*                                          pNext;
+               (VkRenderPassCreateFlags)0,                                     // VkRenderPassCreateFlags                      flags;
+               numAttachments,                                                         // deUint32                                                     attachmentCount;
+               &attachmentDescriptions[0],                                     // const VkAttachmentDescription*       pAttachments;
+               1u,                                                                                     // deUint32                                                     subpassCount;
+               &subpassDescription,                                            // const VkSubpassDescription*          pSubpasses;
+               0u,                                                                                     // deUint32                                                     dependencyCount;
+               DE_NULL                                                                         // const VkSubpassDependency*           pDependencies;
+       };
+
+       return createRenderPass(vk, device, &renderPassInfo);
+}
+
+// Tests framebuffer with attachments of different sizes
+tcu::TestStatus testDifferentAttachmentSizes (Context& context, const CaseDef caseDef)
+{
+       const DeviceInterface&                  vk                                      = context.getDeviceInterface();
+       const VkDevice                                  device                          = context.getDevice();
+       const VkQueue                                   queue                           = context.getUniversalQueue();
+       const deUint32                                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
+       Allocator&                                              allocator                       = context.getDefaultAllocator();
+       const deUint32                                  numRenderTargets        = 3;
+
+       // Color images for rendering in single-sample tests or resolve targets for multi-sample tests
+       Move<VkImage>                                   colorImages[numRenderTargets];
+       MovePtr<Allocation>                             colorImageAllocs[numRenderTargets];
+
+       // For multisampled tests, these are the rendering targets
+       Move<VkImage>                                   msColorImages[numRenderTargets];
+       MovePtr<Allocation>                             msColorImageAllocs[numRenderTargets];
+
+       Move<VkBuffer>                                  colorBuffers[numRenderTargets];
+       MovePtr<Allocation>                             colorBufferAllocs[numRenderTargets];
+
+       // Vary attachment sizes by adding an offset to the base size.
+       const IVec3                                             attachmentSizes[]       =
+       {
+               caseDef.attachmentSize,
+               caseDef.attachmentSize + IVec3(10, caseDef.attachmentSize.y() == 1 ? 0 : 15, 0),
+               caseDef.attachmentSize + IVec3(27, caseDef.attachmentSize.y() == 1 ? 0 : 4, 0)
+       };
+
+       // Use unique clear color for each render target to verify no leaking happens between render target clears.
+       const VkClearColorValue                 clearColors[]           =
+       {
+               {{1.0f, 0.0f, 0.0f, 1.0f}},
+               {{0.0f, 1.0f, 0.0f, 1.0f}},
+               {{0.0f, 0.0f, 1.0f, 1.0f}}
+       };
+
+       Move<VkBuffer>                                  vertexBuffer;
+       MovePtr<Allocation>                             vertexBufferAlloc;
+
+       vector<SharedPtrVkImageView>    colorAttachments;
+       vector<VkImageView>                             attachmentHandles;
+
+       const Unique<VkPipelineLayout>  pipelineLayout          (makePipelineLayout(vk, device));
+       Move<VkPipeline>                                pipeline;
+       const Unique<VkRenderPass>              renderPass                      (makeRenderPassDifferentAttachmentSizes(vk, device, COLOR_FORMAT, numRenderTargets, caseDef.multisample));
+       Move<VkFramebuffer>                             framebuffer;
+
+       const Unique<VkShaderModule>    vertexModule            (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u));
+       const Unique<VkShaderModule>    fragmentModule          (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u));
+
+       const Unique<VkCommandPool>             cmdPool                         (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
+       const Unique<VkCommandBuffer>   cmdBuffer                       (makeCommandBuffer(vk, device, *cmdPool));
+
+       const VkImageViewType                   imageViewType           = caseDef.imageType == VK_IMAGE_VIEW_TYPE_CUBE || caseDef.imageType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY
+               ? VK_IMAGE_VIEW_TYPE_2D : caseDef.imageType;
+
+       const VkImageSubresourceRange   range                           = makeColorSubresourceRange(0, 1);
+
+       // create color buffers
+       for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+       {
+               // Host memory buffer where we will copy the rendered image for verification
+               const deUint32                                  att_size_x                      = attachmentSizes[renderTargetIdx].x();
+               const deUint32                                  att_size_y                      = attachmentSizes[renderTargetIdx].y();
+               const deUint32                                  att_size_z                      = attachmentSizes[renderTargetIdx].z();
+               const VkDeviceSize                              colorBufferSize         = att_size_x * att_size_y * att_size_z * tcu::getPixelSize(mapVkFormat(COLOR_FORMAT));
+               colorBuffers[renderTargetIdx]                                           = makeBuffer(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+               colorBufferAllocs[renderTargetIdx]                                      = bindBuffer(vk, device, allocator, *colorBuffers[renderTargetIdx], MemoryRequirement::HostVisible);
+       }
+
+       // create vertexBuffer
+       {
+               const vector<tcu::Vec4> vertices                        = genFullQuadVertices(1);
+               const VkDeviceSize              vertexBufferSize        = sizeInBytes(vertices);
+
+               vertexBuffer                                                            = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+               vertexBufferAlloc                                                       = bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
+
+               deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
+               flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
+       }
+
+       // create colorImages (and msColorImages) using the configured attachmentsize
+       for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+       {
+               const VkImageUsageFlags colorImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+               colorImages[renderTargetIdx]                    = makeImage(vk, device, VkImageViewCreateFlags(0), getImageType(caseDef.imageType), COLOR_FORMAT,
+                       attachmentSizes[renderTargetIdx], 1, colorImageUsage, false);
+               colorImageAllocs[renderTargetIdx]               = bindImage(vk, device, allocator, *colorImages[renderTargetIdx], MemoryRequirement::Any);
+
+               if (caseDef.multisample)
+               {
+                       const VkImageUsageFlags msImageUsage    = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+
+                       msColorImages[renderTargetIdx]                  = makeImage(vk, device, VkImageViewCreateFlags(0), getImageType(caseDef.imageType), COLOR_FORMAT, attachmentSizes[renderTargetIdx], 1, msImageUsage, true);
+                       msColorImageAllocs[renderTargetIdx]             = bindImage(vk, device, allocator, *msColorImages[renderTargetIdx], MemoryRequirement::Any);
+               }
+       }
+
+       // create attachmentHandles. We use the renderSize for viewport and scissor
+       for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+       {
+               colorAttachments.push_back(makeSharedPtr(makeImageView(vk, device, ! caseDef.multisample ? *colorImages[renderTargetIdx] : *msColorImages[renderTargetIdx], imageViewType, COLOR_FORMAT, range)));
+               attachmentHandles.push_back(**colorAttachments.back());
+       }
+
+       pipeline = makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, caseDef.renderSize, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0, numRenderTargets, caseDef.multisample);
+
+       // create framebuffer
+       framebuffer = makeFramebuffer(vk, device, *renderPass, numRenderTargets, &attachmentHandles[0], static_cast<deUint32>(caseDef.renderSize.x()), static_cast<deUint32>(caseDef.renderSize.y()));
+
+       // record command buffer
+       beginCommandBuffer(vk, *cmdBuffer);
+
+       // Clear image attachments
+       for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+       {
+               {
+                       const VkImageMemoryBarrier      imageLayoutBarriers[]   =
+                       {
+                               {
+                                       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                                     destQueueFamilyIndex;
+                                       caseDef.multisample ? *msColorImages[renderTargetIdx] : *colorImages[renderTargetIdx],  // VkImage                                      image;
+                                       range                                                                                                                                                                   // VkImageSubresourceRange      subresourceRange;
+                               },
+                       };
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0u,
+                               0u, DE_NULL, 0u, DE_NULL, 1u, imageLayoutBarriers);
+
+                       vk.cmdClearColorImage(*cmdBuffer, caseDef.multisample ? *msColorImages[renderTargetIdx] : *colorImages[renderTargetIdx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColors[renderTargetIdx], 1u, &range);
+
+                       const VkImageMemoryBarrier      imageClearBarriers[]    =
+                       {
+                               {
+                                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                                                                                 // VkStructureType                      sType;
+                                       DE_NULL,                                                                                                                                                                // const void*                          pNext;
+                                       VK_ACCESS_TRANSFER_WRITE_BIT,                                                                                                                   // VkAccessFlags                        srcAccessMask;
+                                       VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,                                                                                                    // VkAccessFlags                        dstAccessMask;
+                                       VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,                                                                                                   // VkImageLayout                        oldLayout;
+                                       VK_IMAGE_LAYOUT_GENERAL,                                                                                                                                // VkImageLayout                        newLayout;
+                                       VK_QUEUE_FAMILY_IGNORED,                                                                                                                                // deUint32                                     srcQueueFamilyIndex;
+                                       VK_QUEUE_FAMILY_IGNORED,                                                                                                                                // deUint32                                     destQueueFamilyIndex;
+                                       caseDef.multisample ? *msColorImages[renderTargetIdx] : *colorImages[renderTargetIdx],  // VkImage                                      image;
+                                       range                                                                                                                                                                   // VkImageSubresourceRange      subresourceRange;
+                               },
+                       };
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, imageClearBarriers);
+               }
+       }
+
+       // Render pass: this should render only to the area defined by renderSize (smaller than the size of the attachment)
+       {
+               const VkRect2D                          renderArea                      =
+               {
+                       makeOffset2D(0, 0),
+                       makeExtent2D(caseDef.renderSize.x(), caseDef.renderSize.y()),
+               };
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,       // VkStructureType         sType;
+                       DE_NULL,                                                                        // const void*             pNext;
+                       *renderPass,                                                            // VkRenderPass            renderPass;
+                       *framebuffer,                                                           // VkFramebuffer           framebuffer;
+                       renderArea,                                                                     // VkRect2D                renderArea;
+                       0,                                                                                      // uint32_t                clearValueCount;
+                       DE_NULL,                                                                        // const VkClearValue*     pClearValues;
+               };
+               const VkDeviceSize                      vertexBufferOffset      = 0ull;
+
+               vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+               {
+                       vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
+                       vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+                       vk.cmdDraw(*cmdBuffer, 4u, 1u, 0u, 0u);
+               }
+               vk.cmdEndRenderPass(*cmdBuffer);
+       }
+
+       // If we are using a multi-sampled render target (msColorImage), resolve it now (to colorImage)
+       if (caseDef.multisample)
+       {
+               for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+               {
+                       // Transition msColorImage (from layout COLOR_ATTACHMENT_OPTIMAL) and colorImage (from layout UNDEFINED) to layout GENERAL before resolving
+                       const VkImageMemoryBarrier      imageBarriers[] =
+                       {
+                               {
+                                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,         // VkStructureType                      sType;
+                                       DE_NULL,                                                                        // const void*                          pNext;
+                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,           // VkAccessFlags                        srcAccessMask;
+                                       VK_ACCESS_TRANSFER_READ_BIT,                            // VkAccessFlags                        dstAccessMask;
+                                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,       // VkImageLayout                        oldLayout;
+                                       VK_IMAGE_LAYOUT_GENERAL,                                        // VkImageLayout                        newLayout;
+                                       VK_QUEUE_FAMILY_IGNORED,                                        // deUint32                                     srcQueueFamilyIndex;
+                                       VK_QUEUE_FAMILY_IGNORED,                                        // deUint32                                     destQueueFamilyIndex;
+                                       *msColorImages[renderTargetIdx],                        // VkImage                                      image;
+                                       range                                                                           // VkImageSubresourceRange      subresourceRange;
+                               },
+                               {
+                                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType                      sType;
+                                       DE_NULL,                                                                // const void*                          pNext;
+                                       (VkAccessFlags)0,                                               // VkAccessFlags                        srcAccessMask;
+                                       VK_ACCESS_TRANSFER_WRITE_BIT,                   // VkAccessFlags                        dstAccessMask;
+                                       VK_IMAGE_LAYOUT_UNDEFINED,                              // VkImageLayout                        oldLayout;
+                                       VK_IMAGE_LAYOUT_GENERAL,                                // VkImageLayout                        newLayout;
+                                       VK_QUEUE_FAMILY_IGNORED,                                // deUint32                                     srcQueueFamilyIndex;
+                                       VK_QUEUE_FAMILY_IGNORED,                                // deUint32                                     destQueueFamilyIndex;
+                                       *colorImages[renderTargetIdx],                  // VkImage                                      image;
+                                       range                                                                   // VkImageSubresourceRange      subresourceRange;
+                               }
+                       };
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
+                               0u, DE_NULL, 0u, DE_NULL, 2u, imageBarriers);
+
+                       const VkImageResolve    region  =
+                       {
+                               makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1), // VkImageSubresourceLayers    srcSubresource;
+                               makeOffset3D(0, 0, 0),                                                                                  // VkOffset3D                  srcOffset;
+                               makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1), // VkImageSubresourceLayers    dstSubresource;
+                               makeOffset3D(0, 0, 0),                                                                                  // VkOffset3D                  dstOffset;
+                               makeExtent3D(attachmentSizes[renderTargetIdx])                                  // VkExtent3D                  extent;
+                       };
+
+                       vk.cmdResolveImage(*cmdBuffer, *msColorImages[renderTargetIdx], VK_IMAGE_LAYOUT_GENERAL, *colorImages[renderTargetIdx], VK_IMAGE_LAYOUT_GENERAL, 1, &region);
+               }
+       }
+
+       for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+       {
+               // copy colorImage to host visible colorBuffer
+               const VkImageMemoryBarrier      imageBarrier            =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                                                                                         // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                                                        // const void*                          pNext;
+                       (vk::VkAccessFlags)(caseDef.multisample ? VK_ACCESS_TRANSFER_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
+                       VK_ACCESS_TRANSFER_READ_BIT,                                                                                                                            // VkAccessFlags                        dstAccessMask;
+                       caseDef.multisample ? VK_IMAGE_LAYOUT_GENERAL : 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;
+                       *colorImages[renderTargetIdx],                                                                                                                          // VkImage                                      image;
+                       range                                                                                                                                                                           // VkImageSubresourceRange      subresourceRange;
+               };
+
+               vk.cmdPipelineBarrier(*cmdBuffer, caseDef.multisample ? VK_PIPELINE_STAGE_TRANSFER_BIT : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
+                       0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
+
+               const VkBufferImageCopy         region                          =
+               {
+                       0ull,                                                                                                                           // VkDeviceSize                bufferOffset;
+                       0u,                                                                                                                                     // uint32_t                    bufferRowLength;
+                       0u,                                                                                                                                     // uint32_t                    bufferImageHeight;
+                       makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),      // VkImageSubresourceLayers    imageSubresource;
+                       makeOffset3D(0, 0, 0),                                                                                          // VkOffset3D                  imageOffset;
+                       makeExtent3D(attachmentSizes[renderTargetIdx]),                                         // VkExtent3D                  imageExtent;
+               };
+
+               vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImages[renderTargetIdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffers[renderTargetIdx], 1u, &region);
+
+               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,                                        // uint32_t           srcQueueFamilyIndex;
+                       VK_QUEUE_FAMILY_IGNORED,                                        // uint32_t           dstQueueFamilyIndex;
+                       *colorBuffers[renderTargetIdx],                         // 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, &bufferBarrier, 0u, DE_NULL);
+       }
+
+       VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
+       submitCommandsAndWait(vk, device, queue, *cmdBuffer);
+
+       // Verify results
+       for (deUint32 renderTargetIdx = 0; renderTargetIdx < numRenderTargets; renderTargetIdx++)
+       {
+               const tcu::TextureFormat                        format                          = mapVkFormat(COLOR_FORMAT);
+               const IVec3                                                     size                            = attachmentSizes[renderTargetIdx];
+               tcu::TextureLevel                                       textureLevel            (format, size.x(), size.y(), size.z());
+               const tcu::PixelBufferAccess            expectedImage           (textureLevel);
+
+               const tcu::Vec4                                         expectedColors[]        =
+               {
+                       tcu::Vec4(1.0f, 0.5f, 0.25f, 1.0f),
+                       tcu::Vec4(0.5f, 1.0f, 0.25f, 1.0f),
+                       tcu::Vec4(0.25f, 0.5f, 1.0, 1.0f)
+               };
+
+               invalidateMappedMemoryRange(vk, device, colorBufferAllocs[renderTargetIdx]->getMemory(), colorBufferAllocs[renderTargetIdx]->getOffset(), VK_WHOLE_SIZE);
+
+               for (int z = 0; z < expectedImage.getDepth(); ++z)
+               {
+                       for (int y = 0; y < expectedImage.getHeight(); ++y)
+                       {
+                               for (int x = 0; x < expectedImage.getWidth(); ++x)
+                               {
+                                       if (x < caseDef.renderSize.x() && y < caseDef.renderSize.y() && z < caseDef.renderSize.z())
+                                               expectedImage.setPixel(expectedColors[renderTargetIdx], x, y, z);
+                                       else
+                                               expectedImage.setPixel(tcu::Vec4(clearColors[renderTargetIdx].float32), x, y, z);
+                               }
+                       }
+               }
+               const tcu::ConstPixelBufferAccess       resultImage             (format, size.x(), size.y(), size.z(), colorBufferAllocs[renderTargetIdx]->getHostPtr());
+
+               if (!tcu::intThresholdCompare(context.getTestContext().getLog(), (std::string("Image Comparison of render target ") + de::toString(renderTargetIdx)).c_str(), "", expectedImage, resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT))
+                       return tcu::TestStatus::fail("Fail");
+       }
+
+       return tcu::TestStatus::pass("Pass");
+}
+
+void initDifferentAttachmentSizesPrograms (SourceCollections& programCollection, const CaseDef caseDef)
+{
+       DE_UNREF(caseDef);
+
+       // Vertex shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
+                       << "\n"
+                       << "layout(location = 0) in vec4 in_position;\n"
+                       << "\n"
+                       << "out gl_PerVertex {\n"
+                       << "    vec4 gl_Position;\n"
+                       << "};\n"
+                       << "\n"
+                       << "void main(void)\n"
+                       << "{\n"
+                       << "    gl_Position     = in_position;\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
+       }
+
+       // Fragment shader
+       {
+               std::ostringstream src;
+               src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
+                       << "\n"
+                       << "layout(location = 0) out vec4 o_color0;\n"
+                       << "layout(location = 1) out vec4 o_color1;\n"
+                       << "layout(location = 2) out vec4 o_color2;\n"
+                       << "\n"
+                       << "void main(void)\n"
+                       << "{\n"
+                       << "    o_color0 = vec4(1.0,  0.5, 0.25, 1.0);\n"
+                       << "    o_color1 = vec4(0.5,  1.0, 0.25, 1.0);\n"
+                       << "    o_color2 = vec4(0.25, 0.5, 1.0,  1.0);\n"
+                       << "}\n";
+
+               programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
+       }
+}
+
 std::string getShortImageViewTypeName (const VkImageViewType imageViewType)
 {
        std::string     s       (getImageViewTypeName(imageViewType));
@@ -1198,6 +1638,29 @@ void addAttachmentTestCasesWithFunctions (tcu::TestCaseGroup* group)
        // fragment shader writes to an image via imageStore().
        addFunctionCaseWithPrograms(group, "no_attachments", "", initImagePrograms, testNoAtt, false);
        addFunctionCaseWithPrograms(group, "no_attachments_ms", "", initImagePrograms, testNoAtt, true);
+
+       const CaseDef   differentAttachmentSizesCaseDef[]       =
+       {
+               // Single-sample test cases
+               { VK_IMAGE_VIEW_TYPE_1D,        IVec3(32, 1, 1),        IVec3(64, 1, 1),        1,      false },
+               { VK_IMAGE_VIEW_TYPE_1D,        IVec3(32, 1, 1),        IVec3(48, 1, 1),        1,      false },
+               { VK_IMAGE_VIEW_TYPE_1D,        IVec3(32, 1, 1),        IVec3(39, 1, 1),        1,      false },
+               { VK_IMAGE_VIEW_TYPE_1D,        IVec3(19, 1, 1),        IVec3(32, 1, 1),        1,      false },
+
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(32, 32, 1),       IVec3(64, 64, 1),       1,      false },
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(32, 32, 1),       IVec3(48, 48, 1),       1,      false },
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(32, 32, 1),       IVec3(39, 41, 1),       1,      false },
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(19, 27, 1),       IVec3(32, 32, 1),       1,      false },
+
+               // Multi-sample test cases
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(32, 32, 1),       IVec3(64, 64, 1),       1,      true },
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(32, 32, 1),       IVec3(48, 48, 1),       1,      true },
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(32, 32, 1),       IVec3(39, 41, 1),       1,      true },
+               { VK_IMAGE_VIEW_TYPE_2D,        IVec3(19, 27, 1),       IVec3(32, 32, 1),       1,      true }
+       };
+
+       for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(differentAttachmentSizesCaseDef); ++sizeNdx)
+               addFunctionCaseWithPrograms(group, (std::string("diff_attachments_") + getTestCaseString(differentAttachmentSizesCaseDef[sizeNdx])).c_str(), "", initDifferentAttachmentSizesPrograms, testDifferentAttachmentSizes, differentAttachmentSizesCaseDef[sizeNdx]);
 }
 
 } // anonymous ns