Extend dEQP-VK.api.image_clearing tests to cover layered images
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / api / vktApiImageClearingTests.cpp
index 00fb35e..f69600b 100644 (file)
@@ -109,15 +109,61 @@ std::vector<deUint32> getImageMipLevelSizes (const deUint32 pixelSize, const VkE
        return results;
 }
 
-//! Check if a point lies in a cross-like area.
-inline bool isInClearRange (const UVec4& clearCoords, const deUint32 x, const deUint32 y)
+struct LayerRange
 {
+       deUint32 baseArrayLayer;
+       deUint32 layerCount;
+};
+
+inline bool isInClearRange (const UVec4& clearCoords, const deUint32 x, const deUint32 y, deUint32 arrayLayer = 0, tcu::Maybe<LayerRange> imageViewLayerRange = tcu::Maybe<LayerRange>(), tcu::Maybe<LayerRange> attachmentClearLayerRange = tcu::Maybe<LayerRange>())
+{
+       if (attachmentClearLayerRange)
+       {
+               // Only layers in range passed to clear command are cleared
+
+               const deUint32 clearBaseLayer = (imageViewLayerRange ? imageViewLayerRange->baseArrayLayer : 0) + attachmentClearLayerRange->baseArrayLayer;
+
+               if ((arrayLayer < clearBaseLayer) || (arrayLayer >= (clearBaseLayer + attachmentClearLayerRange->layerCount)))
+               {
+                       return false;
+               }
+       }
+
+       if (clearCoords == UVec4())
+       {
+               return true;
+       }
+
+       //! Check if a point lies in a cross-like area.
        return !((x <  clearCoords[0] && y <  clearCoords[1]) ||
                         (x <  clearCoords[0] && y >= clearCoords[3]) ||
                         (x >= clearCoords[2] && y <  clearCoords[1]) ||
                         (x >= clearCoords[2] && y >= clearCoords[3]));
 }
 
+inline bool isInInitialClearRange (bool isAttachmentformat, deUint32 mipLevel, deUint32 arrayLayer, LayerRange imageViewLayerRange)
+{
+       if (!isAttachmentformat)
+       {
+               // initial clear is done using renderpass load op - does not apply for non-renderable formats
+               return false;
+       }
+
+       if (mipLevel > 0)
+       {
+               // intial clear is done using FB bound to level 0 only
+               return false;
+       }
+
+       // Only layers in range bound to framebuffer are cleared to initial color
+       if ((arrayLayer < imageViewLayerRange.baseArrayLayer) || (arrayLayer >= (imageViewLayerRange.baseArrayLayer + imageViewLayerRange.layerCount)))
+       {
+               return false;
+       }
+
+       return true;
+}
+
 // This method is copied from the vktRenderPassTests.cpp. It should be moved to a common place.
 int calcFloatDiff (float a, float b)
 {
@@ -345,8 +391,11 @@ struct TestParams
        VkImageType             imageType;
        VkFormat                imageFormat;
        VkExtent3D              imageExtent;
+       deUint32        imageLayerCount;
+       LayerRange      imageViewLayerRange;
        VkClearValue    initValue;
        VkClearValue    clearValue[2];          //!< the second value is used with more than one mip map
+       LayerRange              clearLayerRange;
 };
 
 class ImageClearingTestInstance : public vkt::TestInstance
@@ -357,10 +406,10 @@ public:
 
        Move<VkCommandPool>                                     createCommandPool                               (VkCommandPoolCreateFlags commandPoolCreateFlags) const;
        Move<VkCommandBuffer>                           allocatePrimaryCommandBuffer    (VkCommandPool commandPool) const;
-       Move<VkImage>                                           createImage                                             (VkImageType imageType, VkFormat format, VkExtent3D extent, VkImageUsageFlags usage) const;
-       Move<VkImageView>                                       createImageView                                 (VkImage image, VkImageViewType viewType, VkFormat format, VkImageAspectFlags aspectMask) const;
+       Move<VkImage>                                           createImage                                             (VkImageType imageType, VkFormat format, VkExtent3D extent, deUint32 arrayLayerCount, VkImageUsageFlags usage) const;
+       Move<VkImageView>                                       createImageView                                 (VkImage image, VkImageViewType viewType, VkFormat format, VkImageAspectFlags aspectMask, LayerRange layerRange) const;
        Move<VkRenderPass>                                      createRenderPass                                (VkFormat format) const;
-       Move<VkFramebuffer>                                     createFrameBuffer                               (VkImageView imageView, VkRenderPass renderPass, deUint32 imageWidth, deUint32 imageHeight) const;
+       Move<VkFramebuffer>                                     createFrameBuffer                               (VkImageView imageView, VkRenderPass renderPass, deUint32 imageWidth, deUint32 imageHeight, deUint32 imageLayersCount) const;
 
        void                                                            beginCommandBuffer                              (VkCommandBufferUsageFlags usageFlags) const;
        void                                                            endCommandBuffer                                (void) const;
@@ -368,11 +417,16 @@ public:
        void                                                            beginRenderPass                                 (VkSubpassContents content, VkClearValue clearValue) const;
 
        void                                                            pipelineImageBarrier                    (VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const;
-       de::MovePtr<TextureLevelPyramid>        readImage                                               (VkImageAspectFlags aspectMask) const;
+       de::MovePtr<TextureLevelPyramid>        readImage                                               (VkImageAspectFlags aspectMask, deUint32 baseLayer) const;
        tcu::TestStatus                                         verifyResultImage                               (const std::string& successMessage, const UVec4& clearCoords = UVec4()) const;
 
 protected:
-       VkImageViewType                                         getCorrespondingImageViewType   (VkImageType imageType) const;
+       enum ViewType
+       {
+               VIEW_TYPE_SINGLE,
+               VIEW_TYPE_ARRAY
+       };
+       VkImageViewType                                         getCorrespondingImageViewType   (VkImageType imageType, ViewType viewType) const;
        VkImageUsageFlags                                       getImageUsageFlags                              (VkFormat format) const;
        VkImageAspectFlags                                      getImageAspectFlags                             (VkFormat format) const;
        bool                                                            getIsAttachmentFormat                   (VkFormat format) const;
@@ -427,31 +481,37 @@ ImageClearingTestInstance::ImageClearingTestInstance (Context& context, const Te
        , m_image                                       (createImage(params.imageType,
                                                                                         params.imageFormat,
                                                                                         params.imageExtent,
+                                                                                        params.imageLayerCount,
                                                                                         m_imageUsageFlags))
 
        , m_imageMemory                         (allocateAndBindImageMemory(*m_image))
        , m_imageView                           (m_isAttachmentFormat ? createImageView(*m_image,
-                                                                                                getCorrespondingImageViewType(params.imageType),
+                                                                                                getCorrespondingImageViewType(params.imageType, params.imageLayerCount > 1u ? VIEW_TYPE_ARRAY : VIEW_TYPE_SINGLE),
                                                                                                 params.imageFormat,
-                                                                                                m_imageAspectFlags) : vk::Move<VkImageView>())
+                                                                                                m_imageAspectFlags,
+                                                                                                params.imageViewLayerRange) : vk::Move<VkImageView>())
 
        , m_renderPass                          (m_isAttachmentFormat ? createRenderPass(params.imageFormat) : vk::Move<vk::VkRenderPass>())
-       , m_frameBuffer                         (m_isAttachmentFormat ? createFrameBuffer(*m_imageView, *m_renderPass, params.imageExtent.width, params.imageExtent.height) : vk::Move<vk::VkFramebuffer>())
+       , m_frameBuffer                         (m_isAttachmentFormat ? createFrameBuffer(*m_imageView, *m_renderPass, params.imageExtent.width, params.imageExtent.height, params.imageViewLayerRange.layerCount) : vk::Move<vk::VkFramebuffer>())
 {
 }
 
-VkImageViewType ImageClearingTestInstance::getCorrespondingImageViewType (VkImageType imageType) const
+VkImageViewType ImageClearingTestInstance::getCorrespondingImageViewType (VkImageType imageType, ViewType viewType) const
 {
        switch (imageType)
        {
-               case VK_IMAGE_TYPE_1D:
-                       return VK_IMAGE_VIEW_TYPE_1D;
-               case VK_IMAGE_TYPE_2D:
-                       return VK_IMAGE_VIEW_TYPE_2D;
-               case VK_IMAGE_TYPE_3D:
-                       return VK_IMAGE_VIEW_TYPE_3D;
-               default:
-                       DE_FATAL("Unknown image type!");
+       case VK_IMAGE_TYPE_1D:
+               return (viewType == VIEW_TYPE_ARRAY) ?  VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
+       case VK_IMAGE_TYPE_2D:
+               return (viewType == VIEW_TYPE_ARRAY) ?  VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
+       case VK_IMAGE_TYPE_3D:
+               if (viewType != VIEW_TYPE_SINGLE)
+               {
+                       DE_FATAL("Cannot have 3D image array");
+               }
+               return VK_IMAGE_VIEW_TYPE_3D;
+       default:
+               DE_FATAL("Unknown image type!");
        }
 
        return VK_IMAGE_VIEW_TYPE_2D;
@@ -543,7 +603,7 @@ Move<VkCommandBuffer> ImageClearingTestInstance::allocatePrimaryCommandBuffer (V
        return vk::allocateCommandBuffer(m_vkd, m_device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
 }
 
-Move<VkImage> ImageClearingTestInstance::createImage (VkImageType imageType, VkFormat format, VkExtent3D extent, VkImageUsageFlags usage) const
+Move<VkImage> ImageClearingTestInstance::createImage (VkImageType imageType, VkFormat format, VkExtent3D extent, deUint32 arrayLayerCount, VkImageUsageFlags usage) const
 {
        const VkImageCreateInfo                                 imageCreateInfo                 =
        {
@@ -554,7 +614,7 @@ Move<VkImage> ImageClearingTestInstance::createImage (VkImageType imageType, VkF
                format,                                                                         // VkFormat                                     format;
                extent,                                                                         // VkExtent3D                           extent;
                m_imageMipLevels,                                                       // deUint32                                     mipLevels;
-               1u,                                                                                     // deUint32                                     arrayLayers;
+               arrayLayerCount,                                                        // deUint32                                     arrayLayers;
                VK_SAMPLE_COUNT_1_BIT,                                          // VkSampleCountFlagBits        samples;
                VK_IMAGE_TILING_OPTIMAL,                                        // VkImageTiling                        tiling;
                usage,                                                                          // VkImageUsageFlags            usage;
@@ -567,7 +627,7 @@ Move<VkImage> ImageClearingTestInstance::createImage (VkImageType imageType, VkF
        return vk::createImage(m_vkd, m_device, &imageCreateInfo, DE_NULL);
 }
 
-Move<VkImageView> ImageClearingTestInstance::createImageView (VkImage image, VkImageViewType viewType, VkFormat format, VkImageAspectFlags aspectMask) const
+Move<VkImageView> ImageClearingTestInstance::createImageView (VkImage image, VkImageViewType viewType, VkFormat format, VkImageAspectFlags aspectMask, LayerRange layerRange) const
 {
        const VkImageViewCreateInfo                             imageViewCreateInfo             =
        {
@@ -587,9 +647,9 @@ Move<VkImageView> ImageClearingTestInstance::createImageView (VkImage image, VkI
                        aspectMask,                                                                     // VkImageAspectFlags                   aspectMask;
                        0u,                                                                                     // deUint32                                             baseMipLevel;
                        1u,                                                                                     // deUint32                                             mipLevels;
-                       0u,                                                                                     // deUint32                                             baseArrayLayer;
-                       1u,                                                                                     // deUint32                                             arraySize;
-               },                                                                                      // VkImageSubresourceRange              subresourceRange;
+                       layerRange.baseArrayLayer,                                      // deUint32                                             baseArrayLayer;
+                       layerRange.layerCount,                                          // deUint32                                             arraySize;
+               },                                                                                              // VkImageSubresourceRange              subresourceRange;
        };
 
        return vk::createImageView(m_vkd, m_device, &imageViewCreateInfo, DE_NULL);
@@ -675,7 +735,7 @@ Move<VkRenderPass> ImageClearingTestInstance::createRenderPass (VkFormat format)
        return vk::createRenderPass(m_vkd, m_device, &renderPassCreateInfo, DE_NULL);
 }
 
-Move<VkFramebuffer> ImageClearingTestInstance::createFrameBuffer (VkImageView imageView, VkRenderPass renderPass, deUint32 imageWidth, deUint32 imageHeight) const
+Move<VkFramebuffer> ImageClearingTestInstance::createFrameBuffer (VkImageView imageView, VkRenderPass renderPass, deUint32 imageWidth, deUint32 imageHeight, deUint32 imageLayersCount) const
 {
        const VkImageView                                               attachmentViews[1]              =
        {
@@ -692,7 +752,7 @@ Move<VkFramebuffer> ImageClearingTestInstance::createFrameBuffer (VkImageView im
                attachmentViews,                                                        // const VkImageView*           pAttachments;
                imageWidth,                                                                     // deUint32                                     width;
                imageHeight,                                                            // deUint32                                     height;
-               1u,                                                                                     // deUint32                                     layers;
+               imageLayersCount,                                                       // deUint32                                     layers;
        };
 
        return createFramebuffer(m_vkd, m_device, &framebufferCreateInfo, DE_NULL);
@@ -756,14 +816,14 @@ void ImageClearingTestInstance::pipelineImageBarrier(VkPipelineStageFlags srcSta
                        0u,                                                                                     // deUint32                             baseMipLevel;
                        VK_REMAINING_MIP_LEVELS,                                        // deUint32                             levelCount;
                        0u,                                                                                     // deUint32                             baseArrayLayer;
-                       1u,                                                                                     // deUint32                             layerCount;
+                       VK_REMAINING_ARRAY_LAYERS,                                      // deUint32                             layerCount;
                },                                                                                      // VkImageSubresourceRange      subresourceRange;
        };
 
        m_vkd.cmdPipelineBarrier(*m_commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &imageBarrier);
 }
 
-de::MovePtr<TextureLevelPyramid> ImageClearingTestInstance::readImage (VkImageAspectFlags aspectMask) const
+de::MovePtr<TextureLevelPyramid> ImageClearingTestInstance::readImage (VkImageAspectFlags aspectMask, deUint32 arrayLayer) const
 {
        const TextureFormat                                     tcuFormat               = aspectMask == VK_IMAGE_ASPECT_COLOR_BIT ? mapVkFormat(m_params.imageFormat) :
                                                                                                                  aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT ? getDepthCopyFormat(m_params.imageFormat) :
@@ -825,12 +885,12 @@ de::MovePtr<TextureLevelPyramid> ImageClearingTestInstance::readImage (VkImageAs
                        const VkExtent3D                extent  = getMipLevelExtent(m_params.imageExtent, mipLevel);
                        const VkBufferImageCopy region  =
                        {
-                               offset,                                                                 // VkDeviceSize                         bufferOffset;
-                               0u,                                                                             // deUint32                                     bufferRowLength;
-                               0u,                                                                             // deUint32                                     bufferImageHeight;
-                               { aspectMask, mipLevel, 0u, 1u },               // VkImageSubresourceLayers     imageSubresource;
-                               { 0, 0, 0 },                                                    // VkOffset3D                           imageOffset;
-                               extent                                                                  // VkExtent3D                           imageExtent;
+                               offset,                                                                         // VkDeviceSize                         bufferOffset;
+                               0u,                                                                                     // deUint32                                     bufferRowLength;
+                               0u,                                                                                     // deUint32                                     bufferImageHeight;
+                               { aspectMask, mipLevel, arrayLayer, 1u },       // VkImageSubresourceLayers     imageSubresource;
+                               { 0, 0, 0 },                                                            // VkOffset3D                           imageOffset;
+                               extent                                                                          // VkExtent3D                           imageExtent;
                        };
                        copyRegions.push_back(region);
                        offset += mipLevelSizes[mipLevel];
@@ -880,27 +940,34 @@ de::MovePtr<TextureLevelPyramid> ImageClearingTestInstance::readImage (VkImageAs
 
 tcu::TestStatus ImageClearingTestInstance::verifyResultImage (const std::string& successMessage, const UVec4& clearCoords) const
 {
-       const bool useClearRange = clearCoords != UVec4();
-       DE_ASSERT(!useClearRange || m_params.imageExtent.depth == 1u);
+       DE_ASSERT((clearCoords == UVec4()) || m_params.imageExtent.depth == 1u);
 
        if (getIsDepthFormat(m_params.imageFormat))
        {
                DE_ASSERT(m_imageMipLevels == 1u);
 
-               de::MovePtr<TextureLevelPyramid>        image                   = readImage(VK_IMAGE_ASPECT_DEPTH_BIT);
-               std::string                                                     message;
-               float                                                           depthValue;
-
-               for (deUint32 y = 0; y < m_params.imageExtent.height; ++y)
-               for (deUint32 x = 0; x < m_params.imageExtent.width; ++x)
+               for (deUint32 arrayLayer = 0; arrayLayer < m_params.imageLayerCount; ++arrayLayer)
                {
-                       if (!useClearRange || isInClearRange(clearCoords, x, y))
-                               depthValue = m_params.clearValue[0].depthStencil.depth;
-                       else
-                               depthValue = m_params.initValue.depthStencil.depth;
+                       de::MovePtr<TextureLevelPyramid>        image                   = readImage(VK_IMAGE_ASPECT_DEPTH_BIT, arrayLayer);
+                       std::string                                                     message;
+                       float                                                           depthValue;
 
-                       if (!comparePixelToDepthClearValue(image->getLevel(0), x, y, depthValue, message))
-                               return TestStatus::fail("Depth value mismatch! " + message);
+                       for (deUint32 y = 0; y < m_params.imageExtent.height; ++y)
+                       for (deUint32 x = 0; x < m_params.imageExtent.width; ++x)
+                       {
+                               if (isInClearRange(clearCoords, x, y, arrayLayer, m_params.imageViewLayerRange, m_params.clearLayerRange))
+                                       depthValue = m_params.clearValue[0].depthStencil.depth;
+                               else
+                               if (isInInitialClearRange(m_isAttachmentFormat, 0u /* mipLevel */, arrayLayer, m_params.imageViewLayerRange))
+                               {
+                                       depthValue = m_params.initValue.depthStencil.depth;
+                               }
+                               else
+                                       continue;
+
+                               if (!comparePixelToDepthClearValue(image->getLevel(0), x, y, depthValue, message))
+                                       return TestStatus::fail("Depth value mismatch! " + message);
+                       }
                }
        }
 
@@ -908,45 +975,62 @@ tcu::TestStatus ImageClearingTestInstance::verifyResultImage (const std::string&
        {
                DE_ASSERT(m_imageMipLevels == 1u);
 
-               de::MovePtr<TextureLevelPyramid>        image                   = readImage(VK_IMAGE_ASPECT_STENCIL_BIT);
-               std::string                                                     message;
-               deUint32                                                        stencilValue;
-
-               for (deUint32 y = 0; y < m_params.imageExtent.height; ++y)
-               for (deUint32 x = 0; x < m_params.imageExtent.width; ++x)
+               for (deUint32 arrayLayer = 0; arrayLayer < m_params.imageLayerCount; ++arrayLayer)
                {
-                       if (!useClearRange || isInClearRange(clearCoords, x, y))
-                               stencilValue = m_params.clearValue[0].depthStencil.stencil;
-                       else
-                               stencilValue = m_params.initValue.depthStencil.stencil;
+                       de::MovePtr<TextureLevelPyramid>        image                   = readImage(VK_IMAGE_ASPECT_STENCIL_BIT, arrayLayer);
+                       std::string                                                     message;
+                       deUint32                                                        stencilValue;
+
+                       for (deUint32 y = 0; y < m_params.imageExtent.height; ++y)
+                       for (deUint32 x = 0; x < m_params.imageExtent.width; ++x)
+                       {
+                               if (isInClearRange(clearCoords, x, y, arrayLayer, m_params.imageViewLayerRange, m_params.clearLayerRange))
+                                       stencilValue = m_params.clearValue[0].depthStencil.stencil;
+                               else
+                               if (isInInitialClearRange(m_isAttachmentFormat, 0u /* mipLevel */, arrayLayer, m_params.imageViewLayerRange))
+                               {
+                                       stencilValue = m_params.initValue.depthStencil.stencil;
+                               }
+                               else
+                                       continue;
 
-                       if (!comparePixelToStencilClearValue(image->getLevel(0), x, y, stencilValue, message))
-                               return TestStatus::fail("Stencil value mismatch! " + message);
+                               if (!comparePixelToStencilClearValue(image->getLevel(0), x, y, stencilValue, message))
+                                       return TestStatus::fail("Stencil value mismatch! " + message);
+                       }
                }
        }
 
        if (!isDepthStencilFormat(m_params.imageFormat))
        {
-               de::MovePtr<TextureLevelPyramid>        image                   = readImage(VK_IMAGE_ASPECT_COLOR_BIT);
-               std::string                                                     message;
-               const VkClearColorValue*                        pColorValue;
-
-               for (deUint32 mipLevel = 0; mipLevel < m_imageMipLevels; ++mipLevel)
+               for (deUint32 arrayLayer = 0; arrayLayer < m_params.imageLayerCount; ++arrayLayer)
                {
-                       const int                       clearColorNdx   = (mipLevel < m_thresholdMipLevel ? 0 : 1);
-                       const VkExtent3D        extent                  = getMipLevelExtent(m_params.imageExtent, mipLevel);
+                       de::MovePtr<TextureLevelPyramid>        image                   = readImage(VK_IMAGE_ASPECT_COLOR_BIT, arrayLayer);
+                       std::string                                                     message;
+                       const VkClearColorValue*                        pColorValue;
 
-                       for (deUint32 z = 0; z < extent.depth;  ++z)
-                       for (deUint32 y = 0; y < extent.height; ++y)
-                       for (deUint32 x = 0; x < extent.width;  ++x)
+                       for (deUint32 mipLevel = 0; mipLevel < m_imageMipLevels; ++mipLevel)
                        {
-                               if (!useClearRange || isInClearRange(clearCoords, x, y))
-                                       pColorValue = &m_params.clearValue[clearColorNdx].color;
-                               else
-                                       pColorValue = &m_params.initValue.color;
+                               const int                       clearColorNdx   = (mipLevel < m_thresholdMipLevel ? 0 : 1);
+                               const VkExtent3D        extent                  = getMipLevelExtent(m_params.imageExtent, mipLevel);
 
-                               if (!comparePixelToColorClearValue(image->getLevel(mipLevel), x, y, z, *pColorValue, message))
-                                       return TestStatus::fail("Color value mismatch! " + message);
+                               for (deUint32 z = 0; z < extent.depth;  ++z)
+                               for (deUint32 y = 0; y < extent.height; ++y)
+                               for (deUint32 x = 0; x < extent.width;  ++x)
+                               {
+                                       if (isInClearRange(clearCoords, x, y, arrayLayer, m_params.imageViewLayerRange, m_params.clearLayerRange))
+                                               pColorValue = &m_params.clearValue[clearColorNdx].color;
+                                       else
+                                       {
+                                               if (isInInitialClearRange(m_isAttachmentFormat, mipLevel, arrayLayer, m_params.imageViewLayerRange))
+                                               {
+                                                       pColorValue = &m_params.initValue.color;
+                                               }
+                                               else
+                                                       continue;
+                                       }
+                                       if (!comparePixelToColorClearValue(image->getLevel(mipLevel), x, y, z, *pColorValue, message))
+                                               return TestStatus::fail("Color value mismatch! " + message);
+                               }
                        }
                }
        }
@@ -988,11 +1072,11 @@ TestStatus ClearColorImageTestInstance::iterate (void)
        std::vector<VkImageSubresourceRange> subresourceRanges;
 
        if (m_imageMipLevels == 1)
-               subresourceRanges.push_back(makeImageSubresourceRange(m_imageAspectFlags, 0u, 1u, 0u, 1u));
+               subresourceRanges.push_back(makeImageSubresourceRange(m_imageAspectFlags, 0u, 1u, m_params.clearLayerRange.baseArrayLayer, m_params.clearLayerRange.layerCount));
        else
        {
-               subresourceRanges.push_back(makeImageSubresourceRange(m_imageAspectFlags,       0u,                                             m_thresholdMipLevel,            0u, 1u));
-               subresourceRanges.push_back(makeImageSubresourceRange(m_imageAspectFlags,       m_thresholdMipLevel,    VK_REMAINING_MIP_LEVELS,        0u, 1u));
+               subresourceRanges.push_back(makeImageSubresourceRange(m_imageAspectFlags,       0u,                                             m_thresholdMipLevel,            m_params.clearLayerRange.baseArrayLayer, m_params.clearLayerRange.layerCount));
+               subresourceRanges.push_back(makeImageSubresourceRange(m_imageAspectFlags,       m_thresholdMipLevel,    VK_REMAINING_MIP_LEVELS,        m_params.clearLayerRange.baseArrayLayer, m_params.clearLayerRange.layerCount));
        }
 
        beginCommandBuffer(0);
@@ -1047,7 +1131,7 @@ public:
 
 TestStatus ClearDepthStencilImageTestInstance::iterate (void)
 {
-       const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(m_imageAspectFlags, 0u, 1u, 0u, 1u);
+       const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(m_imageAspectFlags, 0u, 1u, m_params.clearLayerRange.baseArrayLayer, m_params.clearLayerRange.layerCount);
 
        beginCommandBuffer(0);
 
@@ -1127,8 +1211,8 @@ public:
                                        { 0, 0 },                                                                                                                                       // VkOffset2D    offset;
                                        { m_params.imageExtent.width, m_params.imageExtent.height }                                     // VkExtent2D    extent;
                                },                                                                                                                                                      // VkRect2D     rect;
-                               0u,                                                                                                                                                     // deUint32     baseArrayLayer;
-                               1u                                                                                                                                                      // deUint32     layerCount;
+                               m_params.clearLayerRange.baseArrayLayer,                                                                // deUint32     baseArrayLayer;
+                               m_params.clearLayerRange.layerCount,                                                                    // deUint32     layerCount;
                        };
 
                        clearRects.push_back(rect);
@@ -1150,16 +1234,16 @@ public:
                                                { 0,                                                    static_cast<deInt32>(clearY)    },              // VkOffset2D    offset;
                                                { m_params.imageExtent.width,   clearHeight                                             }               // VkExtent2D    extent;
                                        },                                                                                                                                              // VkRect2D     rect;
-                                       0u,                                                                                                                                             // deUint32     baseArrayLayer;
-                                       1u                                                                                                                                              // deUint32     layerCount;
+                                       m_params.clearLayerRange.baseArrayLayer,                                                                // deUint32     baseArrayLayer;
+                                       m_params.clearLayerRange.layerCount                                                                             // deUint32     layerCount;
                                },
                                {
                                        {
                                                { static_cast<deInt32>(clearX), 0                                                       },                      // VkOffset2D    offset;
                                                { clearWidth,                                   m_params.imageExtent.height     }                       // VkExtent2D    extent;
                                        },                                                                                                                                              // VkRect2D     rect;
-                                       0u,                                                                                                                                             // deUint32     baseArrayLayer;
-                                       1u                                                                                                                                              // deUint32     layerCount;
+                                       m_params.clearLayerRange.baseArrayLayer,                                                                // deUint32     baseArrayLayer;
+                                       m_params.clearLayerRange.layerCount                                                                             // deUint32     layerCount;
                                }
                        };
 
@@ -1470,6 +1554,31 @@ TestCaseGroup* createImageClearingTests (TestContext& testCtx)
        };
        const size_t    numOfDepthStencilImageFormatsToTest             = DE_LENGTH_OF_ARRAY(depthStencilImageFormatsToTest);
 
+       struct ImageLayerParams
+       {
+               deUint32                imageLayerCount;
+               LayerRange              imageViewRange;
+               LayerRange              clearLayerRange;
+               const char*             testName;
+       };
+       const ImageLayerParams imageLayerParamsToTest[] =
+       {
+               {
+                       1u,                                     // imageLayerCount
+                       {0u, 1u},                       // imageViewRange
+                       {0u, 1u},                       // clearLayerRange
+                       DE_NULL                         // testName
+               },
+               {
+                       16u,                            // imageLayerCount
+                       {3u, 12u},                      // imageViewRange
+                       {2u, 5u},                       // clearLayerRange
+                       "multiple_layers"       // testName
+               },
+       };
+
+       const size_t    numOfImageLayerParamsToTest                             = DE_LENGTH_OF_ARRAY(imageLayerParamsToTest);
+
        // Clear color image
        {
                const VkImageType                       imageTypesToTest[]              =
@@ -1489,23 +1598,39 @@ TestCaseGroup* createImageClearingTests (TestContext& testCtx)
 
                for (size_t     imageTypeIndex = 0; imageTypeIndex < numOfImageTypesToTest; ++imageTypeIndex)
                for (size_t imageFormatIndex = 0; imageFormatIndex < numOfColorImageFormatsToTest; ++imageFormatIndex)
+               for (size_t imageLayerParamsIndex = 0; imageLayerParamsIndex < numOfImageLayerParamsToTest; ++imageLayerParamsIndex)
                {
+
+                       if (imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount > 1u && imageTypesToTest[imageTypeIndex] == VK_IMAGE_TYPE_3D)
+                       {
+                               // 3D ARRAY images are not supported
+                               continue;
+                       }
+
                        const VkFormat          format          = colorImageFormatsToTest[imageFormatIndex];
                        const TestParams        testParams      =
                        {
-                               false,                                                                                                          // bool                         useSingleMipLevel;
-                               imageTypesToTest[imageTypeIndex],                                                       // VkImageType          imageType;
-                               format,                                                                                                         // VkFormat                     imageFormat;
-                               imageDimensionsByType[imageTypeIndex],                                          // VkExtent3D           imageExtent;
-                               makeClearColorValue(format, 0.2f, 0.1f, 0.7f, 0.8f),            // VkClearValue         initValue;
+                               false,                                                                                                                          // bool                         useSingleMipLevel;
+                               imageTypesToTest[imageTypeIndex],                                                                       // VkImageType          imageType;
+                               format,                                                                                                                         // VkFormat                     imageFormat;
+                               imageDimensionsByType[imageTypeIndex],                                                          // VkExtent3D           imageExtent;
+                               imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount,          // deUint32         imageLayerCount;
                                {
-                                       makeClearColorValue(format, 0.1f, 0.5f, 0.3f, 0.9f),    // VkClearValue         clearValue[0];
-                                       makeClearColorValue(format, 0.3f, 0.6f, 0.2f, 0.7f),    // VkClearValue         clearValue[1];
-                               }
+                                       0u,
+                                       imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount
+                               },                                                                                                                                      // LayerRange           imageViewLayerRange;
+                               makeClearColorValue(format, 0.2f, 0.1f, 0.7f, 0.8f),                            // VkClearValue         initValue;
+                               {
+                                       makeClearColorValue(format, 0.1f, 0.5f, 0.3f, 0.9f),                            // VkClearValue         clearValue[0];
+                                       makeClearColorValue(format, 0.3f, 0.6f, 0.2f, 0.7f),                            // VkClearValue         clearValue[1];
+                               },
+                               imageLayerParamsToTest[imageLayerParamsIndex].clearLayerRange,          // LayerRange       clearLayerRange;
                        };
 
                        std::ostringstream      testCaseName;
                        testCaseName << getImageTypeCaseName(testParams.imageType) << "_" << getFormatCaseName(format);
+                       if (imageLayerParamsToTest[imageLayerParamsIndex].testName != DE_NULL)
+                               testCaseName << "_" << imageLayerParamsToTest[imageLayerParamsIndex].testName;
 
                        colorImageClearTests->addChild(new InstanceFactory1<ClearColorImageTestInstance, TestParams>(testCtx, NODETYPE_SELF_VALIDATE, testCaseName.str(), "Clear Color Image", testParams));
                }
@@ -1515,25 +1640,32 @@ TestCaseGroup* createImageClearingTests (TestContext& testCtx)
 
        // Clear depth/stencil image
        {
-               TestParams testParams =
-               {
-                       true,                                                                                   // bool                         useSingleMipLevel;
-                       VK_IMAGE_TYPE_2D,                                                               // VkImageType          imageType;
-                       VK_FORMAT_UNDEFINED,                                                    // VkFormat                     format;
-                       { 256, 256, 1 },                                                                // VkExtent3D           extent;
-                       makeClearValueDepthStencil(0.5f, 0x03),                 // VkClearValue         initValue
-                       {
-                               makeClearValueDepthStencil(0.1f, 0x06),         // VkClearValue         clearValue[0];
-                               makeClearValueDepthStencil(0.3f, 0x04),         // VkClearValue         clearValue[1];
-                       }
-               };
-
                for (size_t imageFormatIndex = 0; imageFormatIndex < numOfDepthStencilImageFormatsToTest; ++imageFormatIndex)
+               for (size_t imageLayerParamsIndex = 0; imageLayerParamsIndex < numOfImageLayerParamsToTest; ++imageLayerParamsIndex)
                {
-                       testParams.imageFormat = depthStencilImageFormatsToTest[imageFormatIndex];
+                       const TestParams testParams =
+                       {
+                               true,                                                                                                                           // bool                         useSingleMipLevel;
+                               VK_IMAGE_TYPE_2D,                                                                                                       // VkImageType          imageType;
+                               depthStencilImageFormatsToTest[imageFormatIndex],                                       // VkFormat                     format;
+                               { 256, 256, 1 },                                                                                                        // VkExtent3D           extent;
+                               imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount,          // deUint32         imageLayerCount;
+                               {
+                                       0u,
+                                       imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount
+                               },                                                                                                                                      // LayerRange           imageViewLayerRange;
+                               makeClearValueDepthStencil(0.5f, 0x03),                                                         // VkClearValue         initValue
+                               {
+                                       makeClearValueDepthStencil(0.1f, 0x06),                                                         // VkClearValue         clearValue[0];
+                                       makeClearValueDepthStencil(0.3f, 0x04),                                                         // VkClearValue         clearValue[1];
+                               },
+                               imageLayerParamsToTest[imageLayerParamsIndex].clearLayerRange,          // LayerRange       clearLayerRange;
+                       };
 
                        std::ostringstream      testCaseName;
                        testCaseName << getImageTypeCaseName(testParams.imageType) << "_" << getFormatCaseName(testParams.imageFormat);
+                       if (imageLayerParamsToTest[imageLayerParamsIndex].testName != DE_NULL)
+                               testCaseName << "_" << imageLayerParamsToTest[imageLayerParamsIndex].testName;
 
                        depthStencilImageClearTests->addChild(new InstanceFactory1<ClearDepthStencilImageTestInstance, TestParams>(testCtx, NODETYPE_SELF_VALIDATE, testCaseName.str(), "Clear Depth/Stencil Image", testParams));
                }
@@ -1544,23 +1676,30 @@ TestCaseGroup* createImageClearingTests (TestContext& testCtx)
        // Clear color attachment
        {
                for (size_t imageFormatIndex = 0; imageFormatIndex < numOfColorImageFormatsToTest; ++imageFormatIndex)
+               for (size_t imageLayerParamsIndex = 0; imageLayerParamsIndex < numOfImageLayerParamsToTest; ++imageLayerParamsIndex)
                {
                        const VkFormat          format          = colorImageFormatsToTest[imageFormatIndex];
-                       const TestParams        testParams      =
+
+                       const TestParams        testParams =
                        {
-                               true,                                                                                                           // bool                         useSingleMipLevel;
-                               VK_IMAGE_TYPE_2D,                                                                                       // VkImageType          imageType;
-                               format,                                                                                                         // VkFormat                     format;
-                               { 256, 256, 1 },                                                                                        // VkExtent3D           extent;
-                               makeClearColorValue(format, 0.2f, 0.1f, 0.7f, 0.8f),            // VkClearValue         initValue
+                               true,                                                                                                                   // bool                         useSingleMipLevel;
+                               VK_IMAGE_TYPE_2D,                                                                                               // VkImageType          imageType;
+                               format,                                                                                                                 // VkFormat                     format;
+                               { 256, 256, 1 },                                                                                                // VkExtent3D           extent;
+                               imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount,  // deUint32         imageLayerCount;
+                               imageLayerParamsToTest[imageLayerParamsIndex].imageViewRange,   // LayerRange           imageViewLayerRange;
+                               makeClearColorValue(format, 0.2f, 0.1f, 0.7f, 0.8f),                    // VkClearValue         initValue
                                {
-                                       makeClearColorValue(format, 0.1f, 0.5f, 0.3f, 0.9f),    // VkClearValue         clearValue[0];
-                                       makeClearColorValue(format, 0.3f, 0.6f, 0.2f, 0.7f),    // VkClearValue         clearValue[1];
-                               }
+                                       makeClearColorValue(format, 0.1f, 0.5f, 0.3f, 0.9f),                    // VkClearValue         clearValue[0];
+                                       makeClearColorValue(format, 0.3f, 0.6f, 0.2f, 0.7f),                    // VkClearValue         clearValue[1];
+                               },
+                               imageLayerParamsToTest[imageLayerParamsIndex].clearLayerRange,  // LayerRange       clearLayerRange;
                        };
 
                        std::ostringstream      testCaseName;
                        testCaseName << getImageTypeCaseName(testParams.imageType) << "_" << getFormatCaseName(format);
+                       if (imageLayerParamsToTest[imageLayerParamsIndex].testName != DE_NULL)
+                               testCaseName << "_" << imageLayerParamsToTest[imageLayerParamsIndex].testName;
 
                        colorAttachmentClearTests->addChild(new InstanceFactory1<ClearAttachmentTestInstance, TestParams>(testCtx, NODETYPE_SELF_VALIDATE, testCaseName.str(), "Clear Color Attachment", testParams));
                        partialColorAttachmentClearTests->addChild(new InstanceFactory1<PartialClearAttachmentTestInstance, TestParams>(testCtx, NODETYPE_SELF_VALIDATE, testCaseName.str(), "Partial Clear Color Attachment", testParams));
@@ -1572,25 +1711,29 @@ TestCaseGroup* createImageClearingTests (TestContext& testCtx)
 
        // Clear depth/stencil attachment
        {
-               TestParams testParams =
-               {
-                       true,                                                                                   // bool                         useSingleMipLevel;
-                       VK_IMAGE_TYPE_2D,                                                               // VkImageType          imageType;
-                       VK_FORMAT_UNDEFINED,                                                    // VkFormat                     format;
-                       { 256, 256, 1 },                                                                // VkExtent3D           extent;
-                       makeClearValueDepthStencil(0.5f, 0x03),                 // VkClearValue         initValue
-                       {
-                               makeClearValueDepthStencil(0.1f, 0x06),         // VkClearValue         clearValue[0];
-                               makeClearValueDepthStencil(0.3f, 0x04),         // VkClearValue         clearValue[1];
-                       }
-               };
-
                for (size_t imageFormatIndex = 0; imageFormatIndex < numOfDepthStencilImageFormatsToTest; ++imageFormatIndex)
+               for (size_t imageLayerParamsIndex = 0; imageLayerParamsIndex < numOfImageLayerParamsToTest; ++imageLayerParamsIndex)
                {
-                       testParams.imageFormat = depthStencilImageFormatsToTest[imageFormatIndex];
+                       const TestParams testParams =
+                       {
+                               true,                                                                                                                   // bool                         useSingleMipLevel;
+                               VK_IMAGE_TYPE_2D,                                                                                               // VkImageType          imageType;
+                               depthStencilImageFormatsToTest[imageFormatIndex],                               // VkFormat                     format;
+                               { 256, 256, 1 },                                                                                                // VkExtent3D           extent;
+                               imageLayerParamsToTest[imageLayerParamsIndex].imageLayerCount,  // deUint32         imageLayerCount;
+                               imageLayerParamsToTest[imageLayerParamsIndex].imageViewRange,   // LayerRange           imageViewLayerRange;
+                               makeClearValueDepthStencil(0.5f, 0x03),                                                 // VkClearValue         initValue
+                               {
+                                       makeClearValueDepthStencil(0.1f, 0x06),                                                 // VkClearValue         clearValue[0];
+                                       makeClearValueDepthStencil(0.3f, 0x04),                                                 // VkClearValue         clearValue[1];
+                               },
+                               imageLayerParamsToTest[imageLayerParamsIndex].clearLayerRange,  // LayerRange       clearLayerRange;
+                       };
 
                        std::ostringstream      testCaseName;
                        testCaseName << getImageTypeCaseName(testParams.imageType) << "_" << getFormatCaseName(testParams.imageFormat);
+                       if (imageLayerParamsToTest[imageLayerParamsIndex].testName != DE_NULL)
+                               testCaseName << "_" << imageLayerParamsToTest[imageLayerParamsIndex].testName;
 
                        depthStencilAttachmentClearTests->addChild(new InstanceFactory1<ClearAttachmentTestInstance, TestParams>(testCtx, NODETYPE_SELF_VALIDATE, testCaseName.str(), "Clear Depth/Stencil Attachment", testParams));
                        partialDepthStencilAttachmentClearTests->addChild(new InstanceFactory1<PartialClearAttachmentTestInstance, TestParams>(testCtx, NODETYPE_SELF_VALIDATE, testCaseName.str(), "Parital Clear Depth/Stencil Attachment", testParams));