blob: 28dd49c9617be11fc63f5d023f8cea2056913fdb [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Tests for render passses with multisample attachments
*//*--------------------------------------------------------------------*/
#include "vktRenderPassMultisampleTests.hpp"
#include "vktRenderPassTestsUtil.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vkDefs.hpp"
#include "vkDeviceUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkQueryUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "tcuFloat.hpp"
#include "tcuImageCompare.hpp"
#include "tcuFormatUtil.hpp"
#include "tcuMaybe.hpp"
#include "tcuResultCollector.hpp"
#include "tcuTestLog.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuVectorUtil.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
using namespace vk;
using tcu::BVec4;
using tcu::IVec2;
using tcu::IVec4;
using tcu::UVec2;
using tcu::UVec4;
using tcu::Vec2;
using tcu::Vec4;
using tcu::Maybe;
using tcu::just;
using tcu::nothing;
using tcu::ConstPixelBufferAccess;
using tcu::PixelBufferAccess;
using tcu::TestLog;
using std::pair;
using std::string;
using std::vector;
typedef de::SharedPtr<vk::Unique<VkImage> > VkImageSp;
typedef de::SharedPtr<vk::Unique<VkImageView> > VkImageViewSp;
typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp;
typedef de::SharedPtr<vk::Unique<VkPipeline> > VkPipelineSp;
namespace vkt
{
namespace
{
using namespace renderpass;
enum
{
MAX_COLOR_ATTACHMENT_COUNT = 4u
};
enum TestSeparateUsage
{
TEST_DEPTH = (1 << 0),
TEST_STENCIL = (1 << 1)
};
template<typename T>
de::SharedPtr<T> safeSharedPtr (T* ptr)
{
try
{
return de::SharedPtr<T>(ptr);
}
catch (...)
{
delete ptr;
throw;
}
}
VkImageAspectFlags getImageAspectFlags (VkFormat vkFormat)
{
const tcu::TextureFormat format (mapVkFormat(vkFormat));
const bool hasDepth (tcu::hasDepthComponent(format.order));
const bool hasStencil (tcu::hasStencilComponent(format.order));
if (hasDepth || hasStencil)
{
return (hasDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : (VkImageAspectFlagBits)0u)
| (hasStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : (VkImageAspectFlagBits)0u);
}
else
return VK_IMAGE_ASPECT_COLOR_BIT;
}
void bindBufferMemory (const DeviceInterface& vk, VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset)
{
VK_CHECK(vk.bindBufferMemory(device, buffer, mem, memOffset));
}
void bindImageMemory (const DeviceInterface& vk, VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset)
{
VK_CHECK(vk.bindImageMemory(device, image, mem, memOffset));
}
de::MovePtr<Allocation> createBufferMemory (const DeviceInterface& vk,
VkDevice device,
Allocator& allocator,
VkBuffer buffer)
{
de::MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vk, device, buffer), MemoryRequirement::HostVisible));
bindBufferMemory(vk, device, buffer, allocation->getMemory(), allocation->getOffset());
return allocation;
}
de::MovePtr<Allocation> createImageMemory (const DeviceInterface& vk,
VkDevice device,
Allocator& allocator,
VkImage image)
{
de::MovePtr<Allocation> allocation (allocator.allocate(getImageMemoryRequirements(vk, device, image), MemoryRequirement::Any));
bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset());
return allocation;
}
Move<VkImage> createImage (const DeviceInterface& vk,
VkDevice device,
VkImageCreateFlags flags,
VkImageType imageType,
VkFormat format,
VkExtent3D extent,
deUint32 mipLevels,
deUint32 arrayLayers,
VkSampleCountFlagBits samples,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkSharingMode sharingMode,
deUint32 queueFamilyCount,
const deUint32* pQueueFamilyIndices,
VkImageLayout initialLayout,
TestSeparateUsage separateStencilUsage)
{
VkImageUsageFlags depthUsage = (separateStencilUsage == TEST_DEPTH) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
VkImageUsageFlags stencilUsage = (separateStencilUsage == TEST_STENCIL) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
const VkImageStencilUsageCreateInfo stencilUsageInfo =
{
VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO,
DE_NULL,
stencilUsage
};
const VkImageCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
separateStencilUsage ? &stencilUsageInfo : DE_NULL,
flags,
imageType,
format,
extent,
mipLevels,
arrayLayers,
samples,
tiling,
separateStencilUsage ? depthUsage : usage,
sharingMode,
queueFamilyCount,
pQueueFamilyIndices,
initialLayout
};
return createImage(vk, device, &pCreateInfo);
}
Move<VkImageView> createImageView (const DeviceInterface& vk,
VkDevice device,
VkImageViewCreateFlags flags,
VkImage image,
VkImageViewType viewType,
VkFormat format,
VkComponentMapping components,
VkImageSubresourceRange subresourceRange)
{
const VkImageViewCreateInfo pCreateInfo =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
DE_NULL,
flags,
image,
viewType,
format,
components,
subresourceRange,
};
return createImageView(vk, device, &pCreateInfo);
}
Move<VkImage> createImage (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
const DeviceInterface& vkd,
VkDevice device,
VkFormat vkFormat,
VkSampleCountFlagBits sampleCountBit,
VkImageUsageFlags usage,
deUint32 width,
deUint32 height,
TestSeparateUsage separateStencilUsage = (TestSeparateUsage)0u)
{
try
{
const tcu::TextureFormat format (mapVkFormat(vkFormat));
const VkImageType imageType (VK_IMAGE_TYPE_2D);
const VkImageTiling imageTiling (VK_IMAGE_TILING_OPTIMAL);
const VkFormatProperties formatProperties (getPhysicalDeviceFormatProperties(vki, physicalDevice, vkFormat));
const VkImageFormatProperties imageFormatProperties (getPhysicalDeviceImageFormatProperties(vki, physicalDevice, vkFormat, imageType, imageTiling, usage, 0u));
const VkImageUsageFlags depthUsage = (separateStencilUsage == TEST_DEPTH) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
const VkImageUsageFlags stencilUsage = (separateStencilUsage == TEST_STENCIL) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
const VkExtent3D imageExtent =
{
width,
height,
1u
};
if ((tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
&& (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)
TCU_THROW(NotSupportedError, "Format can't be used as depth stencil attachment");
if (!(tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
&& (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)
TCU_THROW(NotSupportedError, "Format can't be used as color attachment");
if (imageFormatProperties.maxExtent.width < imageExtent.width
|| imageFormatProperties.maxExtent.height < imageExtent.height
|| ((imageFormatProperties.sampleCounts & sampleCountBit) == 0))
{
TCU_THROW(NotSupportedError, "Image type not supported");
}
if (separateStencilUsage)
{
const VkImageStencilUsageCreateInfo stencilUsageInfo =
{
VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
stencilUsage // VkImageUsageFlags stencilUsage
};
const VkPhysicalDeviceImageFormatInfo2 formatInfo2 =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // VkStructureType sType
&stencilUsageInfo, // const void* pNext
vkFormat, // VkFormat format
imageType, // VkImageType type
imageTiling, // VkImageTiling tiling
depthUsage, // VkImageUsageFlags usage
(VkImageCreateFlags)0u // VkImageCreateFlags flags
};
VkImageFormatProperties2 extProperties =
{
VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
DE_NULL,
{
{
0, // width
0, // height
0, // depth
},
0u, // maxMipLevels
0u, // maxArrayLayers
0, // sampleCounts
0u, // maxResourceSize
},
};
if ((vki.getPhysicalDeviceImageFormatProperties2(physicalDevice, &formatInfo2, &extProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED)
|| extProperties.imageFormatProperties.maxExtent.width < imageExtent.width
|| extProperties.imageFormatProperties.maxExtent.height < imageExtent.height
|| ((extProperties.imageFormatProperties.sampleCounts & sampleCountBit) == 0))
{
TCU_THROW(NotSupportedError, "Image format not supported");
}
}
return createImage(vkd, device, 0u, imageType, vkFormat, imageExtent, 1u, 1u, sampleCountBit, imageTiling, usage, VK_SHARING_MODE_EXCLUSIVE, 0u, DE_NULL, VK_IMAGE_LAYOUT_UNDEFINED, separateStencilUsage);
}
catch (const vk::Error& error)
{
if (error.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED)
TCU_THROW(NotSupportedError, "Image format not supported");
throw;
}
}
Move<VkImageView> createImageAttachmentView (const DeviceInterface& vkd,
VkDevice device,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect)
{
const VkImageSubresourceRange range =
{
aspect,
0u,
1u,
0u,
1u
};
return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range);
}
Move<VkImageView> createSrcPrimaryInputImageView (const DeviceInterface& vkd,
VkDevice device,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect,
TestSeparateUsage testSeparateUsage)
{
VkImageAspectFlags primaryDepthStencilAspect = (testSeparateUsage == TEST_STENCIL) ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT;
const VkImageSubresourceRange range =
{
aspect == (VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)
? primaryDepthStencilAspect
: aspect,
0u,
1u,
0u,
1u
};
return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range);
}
Move<VkImageView> createSrcSecondaryInputImageView (const DeviceInterface& vkd,
VkDevice device,
VkImage image,
VkFormat format,
VkImageAspectFlags aspect,
TestSeparateUsage separateStencilUsage)
{
if ((aspect == (VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)) && !separateStencilUsage)
{
const VkImageSubresourceRange range =
{
VK_IMAGE_ASPECT_STENCIL_BIT,
0u,
1u,
0u,
1u
};
return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range);
}
else
return Move<VkImageView>();
}
VkDeviceSize getPixelSize (VkFormat vkFormat)
{
const tcu::TextureFormat format (mapVkFormat(vkFormat));
return format.getPixelSize();
}
Move<VkBuffer> createBuffer (const DeviceInterface& vkd,
VkDevice device,
VkFormat format,
deUint32 width,
deUint32 height)
{
const VkBufferUsageFlags bufferUsage (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const VkDeviceSize pixelSize (getPixelSize(format));
const VkBufferCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u,
width * height * pixelSize,
bufferUsage,
VK_SHARING_MODE_EXCLUSIVE,
0u,
DE_NULL
};
return createBuffer(vkd, device, &createInfo);
}
VkSampleCountFlagBits sampleCountBitFromomSampleCount (deUint32 count)
{
switch (count)
{
case 1: return VK_SAMPLE_COUNT_1_BIT;
case 2: return VK_SAMPLE_COUNT_2_BIT;
case 4: return VK_SAMPLE_COUNT_4_BIT;
case 8: return VK_SAMPLE_COUNT_8_BIT;
case 16: return VK_SAMPLE_COUNT_16_BIT;
case 32: return VK_SAMPLE_COUNT_32_BIT;
case 64: return VK_SAMPLE_COUNT_64_BIT;
default:
DE_FATAL("Invalid sample count");
return (VkSampleCountFlagBits)(0x1u << count);
}
}
std::vector<VkImageSp> createMultisampleImages (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
const DeviceInterface& vkd,
VkDevice device,
VkFormat format,
deUint32 sampleCount,
deUint32 width,
deUint32 height)
{
std::vector<VkImageSp> images (sampleCount);
for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++)
images[imageNdx] = safeSharedPtr(new vk::Unique<VkImage>(createImage(vki, physicalDevice, vkd, device, format, sampleCountBitFromomSampleCount(sampleCount), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, width, height)));
return images;
}
std::vector<VkImageSp> createSingleSampleImages (const InstanceInterface& vki,
VkPhysicalDevice physicalDevice,
const DeviceInterface& vkd,
VkDevice device,
VkFormat format,
deUint32 sampleCount,
deUint32 width,
deUint32 height)
{
std::vector<VkImageSp> images (sampleCount);
for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++)
images[imageNdx] = safeSharedPtr(new vk::Unique<VkImage>(createImage(vki, physicalDevice, vkd, device, format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, width, height)));
return images;
}
std::vector<de::SharedPtr<Allocation> > createImageMemory (const DeviceInterface& vkd,
VkDevice device,
Allocator& allocator,
const std::vector<VkImageSp> images)
{
std::vector<de::SharedPtr<Allocation> > memory (images.size());
for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++)
memory[memoryNdx] = safeSharedPtr(createImageMemory(vkd, device, allocator, **images[memoryNdx]).release());
return memory;
}
std::vector<VkImageViewSp> createImageAttachmentViews (const DeviceInterface& vkd,
VkDevice device,
const std::vector<VkImageSp>& images,
VkFormat format,
VkImageAspectFlagBits aspect)
{
std::vector<VkImageViewSp> views (images.size());
for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++)
views[imageNdx] = safeSharedPtr(new vk::Unique<VkImageView>(createImageAttachmentView(vkd, device, **images[imageNdx], format, aspect)));
return views;
}
std::vector<VkBufferSp> createBuffers (const DeviceInterface& vkd,
VkDevice device,
VkFormat format,
deUint32 sampleCount,
deUint32 width,
deUint32 height)
{
std::vector<VkBufferSp> buffers (sampleCount);
for (size_t bufferNdx = 0; bufferNdx < buffers.size(); bufferNdx++)
buffers[bufferNdx] = safeSharedPtr(new vk::Unique<VkBuffer>(createBuffer(vkd, device, format, width, height)));
return buffers;
}
std::vector<de::SharedPtr<Allocation> > createBufferMemory (const DeviceInterface& vkd,
VkDevice device,
Allocator& allocator,
const std::vector<VkBufferSp> buffers)
{
std::vector<de::SharedPtr<Allocation> > memory (buffers.size());
for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++)
memory[memoryNdx] = safeSharedPtr(createBufferMemory(vkd, device, allocator, **buffers[memoryNdx]).release());
return memory;
}
template<typename AttachmentDesc, typename AttachmentRef, typename SubpassDesc, typename SubpassDep, typename RenderPassCreateInfo>
Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd,
VkDevice device,
VkFormat srcFormat,
VkFormat dstFormat,
deUint32 sampleCount,
RenderPassType renderPassType,
TestSeparateUsage separateStencilUsage)
{
const VkSampleCountFlagBits samples (sampleCountBitFromomSampleCount(sampleCount));
const deUint32 splitSubpassCount (deDivRoundUp32(sampleCount, MAX_COLOR_ATTACHMENT_COUNT));
const tcu::TextureFormat format (mapVkFormat(srcFormat));
const bool isDepthStencilFormat (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order));
const VkImageAspectFlags inputAspect (separateStencilUsage == TEST_DEPTH ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT
: separateStencilUsage == TEST_STENCIL ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT
: getImageAspectFlags(srcFormat));
vector<SubpassDesc> subpasses;
vector<vector<AttachmentRef> > dstAttachmentRefs (splitSubpassCount);
vector<vector<AttachmentRef> > dstResolveAttachmentRefs (splitSubpassCount);
vector<AttachmentDesc> attachments;
vector<SubpassDep> dependencies;
const AttachmentRef srcAttachmentRef // VkAttachmentReference || VkAttachmentReference2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
0u, // deUint32 attachment; || deUint32 attachment;
isDepthStencilFormat // VkImageLayout layout; || VkImageLayout layout;
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
0u // || VkImageAspectFlags aspectMask;
);
const AttachmentRef srcAttachmentInputRef // VkAttachmentReference || VkAttachmentReference2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
0u, // deUint32 attachment; || deUint32 attachment;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout layout; || VkImageLayout layout;
(renderPassType == RENDERPASS_TYPE_RENDERPASS2) // || VkImageAspectFlags aspectMask;
? inputAspect
: 0u
);
{
const AttachmentDesc srcAttachment // VkAttachmentDescription || VkAttachmentDescription2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags;
srcFormat, // VkFormat format; || VkFormat format;
samples, // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; || VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_GENERAL // VkImageLayout finalLayout; || VkImageLayout finalLayout;
);
attachments.push_back(srcAttachment);
}
for (deUint32 splitSubpassIndex = 0; splitSubpassIndex < splitSubpassCount; splitSubpassIndex++)
{
for (deUint32 sampleNdx = 0; sampleNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, sampleCount - splitSubpassIndex * MAX_COLOR_ATTACHMENT_COUNT); sampleNdx++)
{
// Multisample color attachment
{
const AttachmentDesc dstAttachment // VkAttachmentDescription || VkAttachmentDescription2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags;
dstFormat, // VkFormat format; || VkFormat format;
samples, // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; || VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; || VkImageLayout finalLayout;
);
const AttachmentRef dstAttachmentRef // VkAttachmentReference || VkAttachmentReference2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
(deUint32)attachments.size(), // deUint32 attachment; || deUint32 attachment;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout; || VkImageLayout layout;
0u // || VkImageAspectFlags aspectMask;
);
attachments.push_back(dstAttachment);
dstAttachmentRefs[splitSubpassIndex].push_back(dstAttachmentRef);
}
// Resolve attachment
{
const AttachmentDesc dstAttachment // VkAttachmentDescription || VkAttachmentDescription2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags;
dstFormat, // VkFormat format; || VkFormat format;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; || VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout; || VkImageLayout finalLayout;
);
const AttachmentRef dstAttachmentRef // VkAttachmentReference || VkAttachmentReference2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
(deUint32)attachments.size(), // deUint32 attachment; || deUint32 attachment;
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout; || VkImageLayout layout;
0u // || VkImageAspectFlags aspectMask;
);
attachments.push_back(dstAttachment);
dstResolveAttachmentRefs[splitSubpassIndex].push_back(dstAttachmentRef);
}
}
}
{
{
const SubpassDesc subpass // VkSubpassDescription || VkSubpassDescription2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; || VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; || VkPipelineBindPoint pipelineBindPoint;
0u, // || deUint32 viewMask;
0u, // deUint32 inputAttachmentCount; || deUint32 inputAttachmentCount;
DE_NULL, // const VkAttachmentReference* pInputAttachments; || const VkAttachmentReference2KHR* pInputAttachments;
isDepthStencilFormat ? 0u : 1u, // deUint32 colorAttachmentCount; || deUint32 colorAttachmentCount;
isDepthStencilFormat ? DE_NULL : &srcAttachmentRef, // const VkAttachmentReference* pColorAttachments; || const VkAttachmentReference2KHR* pColorAttachments;
DE_NULL, // const VkAttachmentReference* pResolveAttachments; || const VkAttachmentReference2KHR* pResolveAttachments;
isDepthStencilFormat ? &srcAttachmentRef : DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; || const VkAttachmentReference2KHR* pDepthStencilAttachment;
0u, // deUint32 preserveAttachmentCount; || deUint32 preserveAttachmentCount;
DE_NULL // const deUint32* pPreserveAttachments; || const deUint32* pPreserveAttachments;
);
subpasses.push_back(subpass);
}
for (deUint32 splitSubpassIndex = 0; splitSubpassIndex < splitSubpassCount; splitSubpassIndex++)
{
{
const SubpassDesc subpass // VkSubpassDescription || VkSubpassDescription2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; || VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; || VkPipelineBindPoint pipelineBindPoint;
0u, // || deUint32 viewMask;
1u, // deUint32 inputAttachmentCount; || deUint32 inputAttachmentCount;
&srcAttachmentInputRef, // const VkAttachmentReference* pInputAttachments; || const VkAttachmentReference2KHR* pInputAttachments;
(deUint32)dstAttachmentRefs[splitSubpassIndex].size(), // deUint32 colorAttachmentCount; || deUint32 colorAttachmentCount;
&dstAttachmentRefs[splitSubpassIndex][0], // const VkAttachmentReference* pColorAttachments; || const VkAttachmentReference2KHR* pColorAttachments;
&dstResolveAttachmentRefs[splitSubpassIndex][0], // const VkAttachmentReference* pResolveAttachments; || const VkAttachmentReference2KHR* pResolveAttachments;
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; || const VkAttachmentReference2KHR* pDepthStencilAttachment;
0u, // deUint32 preserveAttachmentCount; || deUint32 preserveAttachmentCount;
DE_NULL // const deUint32* pPreserveAttachments; || const deUint32* pPreserveAttachments;
);
subpasses.push_back(subpass);
}
{
const SubpassDep dependency // VkSubpassDependency || VkSubpassDependency2KHR
(
// || VkStructureType sType;
DE_NULL, // || const void* pNext;
0u, // deUint32 srcSubpass; || deUint32 srcSubpass;
splitSubpassIndex + 1, // deUint32 dstSubpass; || deUint32 dstSubpass;
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask; || VkPipelineStageFlags srcStageMask;
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask; || VkPipelineStageFlags dstStageMask;
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask; || VkAccessFlags srcAccessMask;
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask; || VkAccessFlags dstAccessMask;
VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags; || VkDependencyFlags dependencyFlags;
0u // || deInt32 viewOffset;
);
dependencies.push_back(dependency);
}
};
const RenderPassCreateInfo renderPassCreator // VkRenderPassCreateInfo || VkRenderPassCreateInfo2KHR
(
// VkStructureType sType; || VkStructureType sType;
DE_NULL, // const void* pNext; || const void* pNext;
(VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags; || VkRenderPassCreateFlags flags;
(deUint32)attachments.size(), // deUint32 attachmentCount; || deUint32 attachmentCount;
&attachments[0], // const VkAttachmentDescription* pAttachments; || const VkAttachmentDescription2KHR* pAttachments;
(deUint32)subpasses.size(), // deUint32 subpassCount; || deUint32 subpassCount;
&subpasses[0], // const VkSubpassDescription* pSubpasses; || const VkSubpassDescription2KHR* pSubpasses;
(deUint32)dependencies.size(), // deUint32 dependencyCount; || deUint32 dependencyCount;
&dependencies[0], // const VkSubpassDependency* pDependencies; || const VkSubpassDependency2KHR* pDependencies;
0u, // || deUint32 correlatedViewMaskCount;
DE_NULL // || const deUint32* pCorrelatedViewMasks;
);
return renderPassCreator.createRenderPass(vkd, device);
}
}
Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd,
VkDevice device,
VkFormat srcFormat,
VkFormat dstFormat,
deUint32 sampleCount,
const RenderPassType renderPassType,
const TestSeparateUsage separateStencilUsage)
{
switch (renderPassType)
{
case RENDERPASS_TYPE_LEGACY:
return createRenderPass<AttachmentDescription1, AttachmentReference1, SubpassDescription1, SubpassDependency1, RenderPassCreateInfo1>(vkd, device, srcFormat, dstFormat, sampleCount, renderPassType, separateStencilUsage);
case RENDERPASS_TYPE_RENDERPASS2:
return createRenderPass<AttachmentDescription2, AttachmentReference2, SubpassDescription2, SubpassDependency2, RenderPassCreateInfo2>(vkd, device, srcFormat, dstFormat, sampleCount, renderPassType, separateStencilUsage);
default:
TCU_THROW(InternalError, "Impossible");
}
}
Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd,
VkDevice device,
VkRenderPass renderPass,
VkImageView srcImageView,
const std::vector<VkImageViewSp>& dstMultisampleImageViews,
const std::vector<VkImageViewSp>& dstSinglesampleImageViews,
deUint32 width,
deUint32 height)
{
std::vector<VkImageView> attachments;
attachments.reserve(dstMultisampleImageViews.size() + dstSinglesampleImageViews.size() + 1u);
attachments.push_back(srcImageView);
DE_ASSERT(dstMultisampleImageViews.size() == dstSinglesampleImageViews.size());
for (size_t ndx = 0; ndx < dstMultisampleImageViews.size(); ndx++)
{
attachments.push_back(**dstMultisampleImageViews[ndx]);
attachments.push_back(**dstSinglesampleImageViews[ndx]);
}
const VkFramebufferCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
DE_NULL,
0u,
renderPass,
(deUint32)attachments.size(),
&attachments[0],
width,
height,
1u
};
return createFramebuffer(vkd, device, &createInfo);
}
Move<VkPipelineLayout> createRenderPipelineLayout (const DeviceInterface& vkd,
VkDevice device)
{
const VkPushConstantRange pushConstant =
{
VK_SHADER_STAGE_FRAGMENT_BIT,
0u,
4u
};
const VkPipelineLayoutCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
0u,
DE_NULL,
1u,
&pushConstant
};
return createPipelineLayout(vkd, device, &createInfo);
}
Move<VkPipeline> createRenderPipeline (const DeviceInterface& vkd,
VkDevice device,
VkFormat srcFormat,
VkRenderPass renderPass,
VkPipelineLayout pipelineLayout,
const vk::BinaryCollection& binaryCollection,
deUint32 width,
deUint32 height,
deUint32 sampleCount)
{
const tcu::TextureFormat format (mapVkFormat(srcFormat));
const bool isDepthStencilFormat (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order));
const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u));
const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-frag"), 0u));
// Disable blending
const VkPipelineColorBlendAttachmentState attachmentBlendState =
{
VK_FALSE,
VK_BLEND_FACTOR_SRC_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ONE,
VK_BLEND_OP_ADD,
VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT
};
const VkPipelineVertexInputStateCreateInfo vertexInputState =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineVertexInputStateCreateFlags)0u,
0u,
DE_NULL,
0u,
DE_NULL
};
const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(width, height)));
const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(width, height)));
const VkPipelineMultisampleStateCreateInfo multisampleState =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineMultisampleStateCreateFlags)0u,
sampleCountBitFromomSampleCount(sampleCount),
VK_FALSE,
0.0f,
DE_NULL,
VK_FALSE,
VK_FALSE,
};
const VkPipelineDepthStencilStateCreateInfo depthStencilState =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineDepthStencilStateCreateFlags)0u,
VK_TRUE,
VK_TRUE,
VK_COMPARE_OP_ALWAYS,
VK_FALSE,
VK_TRUE,
{
VK_STENCIL_OP_KEEP,
VK_STENCIL_OP_INCREMENT_AND_WRAP,
VK_STENCIL_OP_KEEP,
VK_COMPARE_OP_ALWAYS,
~0u,
~0u,
0xFFu / (sampleCount + 1)
},
{
VK_STENCIL_OP_KEEP,
VK_STENCIL_OP_INCREMENT_AND_WRAP,
VK_STENCIL_OP_KEEP,
VK_COMPARE_OP_ALWAYS,
~0u,
~0u,
0xFFu / (sampleCount + 1)
},
0.0f,
1.0f
};
const VkPipelineColorBlendStateCreateInfo blendState =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineColorBlendStateCreateFlags)0u,
VK_FALSE,
VK_LOGIC_OP_COPY,
(isDepthStencilFormat ? 0u : 1u),
(isDepthStencilFormat ? DE_NULL : &attachmentBlendState),
{ 0.0f, 0.0f, 0.0f, 0.0f }
};
return makeGraphicsPipeline(vkd, // const DeviceInterface& vk
device, // const VkDevice device
pipelineLayout, // const VkPipelineLayout pipelineLayout
*vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*fragmentShaderModule, // const VkShaderModule fragmentShaderModule
renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
&multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
&depthStencilState, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
&blendState); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
}
Move<VkDescriptorSetLayout> createSplitDescriptorSetLayout (const DeviceInterface& vkd,
VkDevice device,
VkFormat vkFormat)
{
const tcu::TextureFormat format (mapVkFormat(vkFormat));
const bool hasDepth (tcu::hasDepthComponent(format.order));
const bool hasStencil (tcu::hasStencilComponent(format.order));
const VkDescriptorSetLayoutBinding bindings[] =
{
{
0u,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
1u,
VK_SHADER_STAGE_FRAGMENT_BIT,
DE_NULL
},
{
1u,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
1u,
VK_SHADER_STAGE_FRAGMENT_BIT,
DE_NULL
}
};
const VkDescriptorSetLayoutCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
DE_NULL,
0u,
hasDepth && hasStencil ? 2u : 1u,
bindings
};
return createDescriptorSetLayout(vkd, device, &createInfo);
}
Move<VkPipelineLayout> createSplitPipelineLayout (const DeviceInterface& vkd,
VkDevice device,
VkDescriptorSetLayout descriptorSetLayout)
{
const VkPushConstantRange pushConstant =
{
VK_SHADER_STAGE_FRAGMENT_BIT,
0u,
4u
};
const VkPipelineLayoutCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
1u,
&descriptorSetLayout,
1u,
&pushConstant
};
return createPipelineLayout(vkd, device, &createInfo);
}
Move<VkPipeline> createSplitPipeline (const DeviceInterface& vkd,
VkDevice device,
VkRenderPass renderPass,
deUint32 subpassIndex,
VkPipelineLayout pipelineLayout,
const vk::BinaryCollection& binaryCollection,
deUint32 width,
deUint32 height,
deUint32 sampleCount)
{
const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u));
const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-split-frag"), 0u));
// Disable blending
const VkPipelineColorBlendAttachmentState attachmentBlendState =
{
VK_FALSE,
VK_BLEND_FACTOR_SRC_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
VK_BLEND_OP_ADD,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ONE,
VK_BLEND_OP_ADD,
VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT
};
const std::vector<VkPipelineColorBlendAttachmentState> attachmentBlendStates (de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, sampleCount), attachmentBlendState);
const VkPipelineVertexInputStateCreateInfo vertexInputState =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineVertexInputStateCreateFlags)0u,
0u,
DE_NULL,
0u,
DE_NULL
};
const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(width, height)));
const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(width, height)));
const VkPipelineMultisampleStateCreateInfo multisampleState =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineMultisampleStateCreateFlags)0u,
sampleCountBitFromomSampleCount(sampleCount),
VK_FALSE,
0.0f,
DE_NULL,
VK_FALSE,
VK_FALSE,
};
const VkPipelineColorBlendStateCreateInfo blendState =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
DE_NULL,
(VkPipelineColorBlendStateCreateFlags)0u,
VK_FALSE,
VK_LOGIC_OP_COPY,
(deUint32)attachmentBlendStates.size(),
&attachmentBlendStates[0],
{ 0.0f, 0.0f, 0.0f, 0.0f }
};
return makeGraphicsPipeline(vkd, // const DeviceInterface& vk
device, // const VkDevice device
pipelineLayout, // const VkPipelineLayout pipelineLayout
*vertexShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlShaderModule
DE_NULL, // const VkShaderModule tessellationEvalShaderModule
DE_NULL, // const VkShaderModule geometryShaderModule
*fragmentShaderModule, // const VkShaderModule fragmentShaderModule
renderPass, // const VkRenderPass renderPass
viewports, // const std::vector<VkViewport>& viewports
scissors, // const std::vector<VkRect2D>& scissors
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
subpassIndex, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
&multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
&blendState); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
}
vector<VkPipelineSp> createSplitPipelines (const DeviceInterface& vkd,
VkDevice device,
VkRenderPass renderPass,
VkPipelineLayout pipelineLayout,
const vk::BinaryCollection& binaryCollection,
deUint32 width,
deUint32 height,
deUint32 sampleCount)
{
std::vector<VkPipelineSp> pipelines (deDivRoundUp32(sampleCount, MAX_COLOR_ATTACHMENT_COUNT), (VkPipelineSp)0u);
for (size_t ndx = 0; ndx < pipelines.size(); ndx++)
pipelines[ndx] = safeSharedPtr(new Unique<VkPipeline>(createSplitPipeline(vkd, device, renderPass, (deUint32)(ndx + 1), pipelineLayout, binaryCollection, width, height, sampleCount)));
return pipelines;
}
Move<VkDescriptorPool> createSplitDescriptorPool (const DeviceInterface& vkd,
VkDevice device)
{
const VkDescriptorPoolSize size =
{
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 2u
};
const VkDescriptorPoolCreateInfo createInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
DE_NULL,
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
2u,
1u,
&size
};
return createDescriptorPool(vkd, device, &createInfo);
}
Move<VkDescriptorSet> createSplitDescriptorSet (const DeviceInterface& vkd,
VkDevice device,
VkDescriptorPool pool,
VkDescriptorSetLayout layout,
VkImageView primaryImageView,
VkImageView secondaryImageView)
{
const VkDescriptorSetAllocateInfo allocateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
Move<VkDescriptorSet> set (allocateDescriptorSet(vkd, device, &allocateInfo));
{
const VkDescriptorImageInfo imageInfos[] =
{
{
(VkSampler)0u,
primaryImageView,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
},
{
(VkSampler)0u,
secondaryImageView,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
}
};
const VkWriteDescriptorSet writes[] =
{
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
DE_NULL,
*set,
0u,
0u,
1u,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
&imageInfos[0],
DE_NULL,
DE_NULL
},
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
DE_NULL,
*set,
1u,
0u,
1u,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
&imageInfos[1],
DE_NULL,
DE_NULL
}
};
const deUint32 count = secondaryImageView != (VkImageView)0
? 2u
: 1u;
vkd.updateDescriptorSets(device, count, writes, 0u, DE_NULL);
}
return set;
}
struct TestConfig
{
TestConfig (VkFormat format_,
deUint32 sampleCount_,
RenderPassType renderPassType_,
TestSeparateUsage separateStencilUsage_ = (TestSeparateUsage)0u)
: format (format_)
, sampleCount (sampleCount_)
, renderPassType (renderPassType_)
, separateStencilUsage(separateStencilUsage_)
{
}
VkFormat format;
deUint32 sampleCount;
RenderPassType renderPassType;
TestSeparateUsage separateStencilUsage;
};
VkImageUsageFlags getSrcImageUsage (VkFormat vkFormat)
{
const tcu::TextureFormat format (mapVkFormat(vkFormat));
const bool hasDepth (tcu::hasDepthComponent(format.order));
const bool hasStencil (tcu::hasStencilComponent(format.order));
if (hasDepth || hasStencil)
return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
else
return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
VkFormat getDstFormat (VkFormat vkFormat, TestSeparateUsage separateStencilUsage)
{
const tcu::TextureFormat format (mapVkFormat(vkFormat));
const bool hasDepth (tcu::hasDepthComponent(format.order));
const bool hasStencil (tcu::hasStencilComponent(format.order));
if (hasDepth && hasStencil && !separateStencilUsage)
return VK_FORMAT_R32G32_SFLOAT;
else if (hasDepth || hasStencil)
return VK_FORMAT_R32_SFLOAT;
else
return vkFormat;
}
bool isExtensionSupported(Context& context, RenderPassType renderPassType, TestSeparateUsage separateStencilUsage)
{
if (renderPassType == RENDERPASS_TYPE_RENDERPASS2)
context.requireDeviceFunctionality("VK_KHR_create_renderpass2");
if (separateStencilUsage)
{
context.requireDeviceFunctionality ("VK_EXT_separate_stencil_usage");
context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
}
return true;
}
class MultisampleRenderPassTestInstance : public TestInstance
{
public:
MultisampleRenderPassTestInstance (Context& context, TestConfig config);
~MultisampleRenderPassTestInstance (void);
tcu::TestStatus iterate (void);
template<typename RenderpassSubpass>
tcu::TestStatus iterateInternal (void);
private:
const bool m_extensionSupported;
const RenderPassType m_renderPassType;
const TestSeparateUsage m_separateStencilUsage;
const VkFormat m_srcFormat;
const VkFormat m_dstFormat;
const deUint32 m_sampleCount;
const deUint32 m_width;
const deUint32 m_height;
const VkImageAspectFlags m_srcImageAspect;
const VkImageUsageFlags m_srcImageUsage;
const Unique<VkImage> m_srcImage;
const de::UniquePtr<Allocation> m_srcImageMemory;
const Unique<VkImageView> m_srcImageView;
const Unique<VkImageView> m_srcPrimaryInputImageView;
const Unique<VkImageView> m_srcSecondaryInputImageView;
const std::vector<VkImageSp> m_dstMultisampleImages;
const std::vector<de::SharedPtr<Allocation> > m_dstMultisampleImageMemory;
const std::vector<VkImageViewSp> m_dstMultisampleImageViews;
const std::vector<VkImageSp> m_dstSinglesampleImages;
const std::vector<de::SharedPtr<Allocation> > m_dstSinglesampleImageMemory;
const std::vector<VkImageViewSp> m_dstSinglesampleImageViews;
const std::vector<VkBufferSp> m_dstBuffers;
const std::vector<de::SharedPtr<Allocation> > m_dstBufferMemory;
const Unique<VkRenderPass> m_renderPass;
const Unique<VkFramebuffer> m_framebuffer;
const Unique<VkPipelineLayout> m_renderPipelineLayout;
const Unique<VkPipeline> m_renderPipeline;
const Unique<VkDescriptorSetLayout> m_splitDescriptorSetLayout;
const Unique<VkPipelineLayout> m_splitPipelineLayout;
const std::vector<VkPipelineSp> m_splitPipelines;
const Unique<VkDescriptorPool> m_splitDescriptorPool;
const Unique<VkDescriptorSet> m_splitDescriptorSet;
const Unique<VkCommandPool> m_commandPool;
tcu::ResultCollector m_resultCollector;
};
MultisampleRenderPassTestInstance::MultisampleRenderPassTestInstance (Context& context, TestConfig config)
: TestInstance (context)
, m_extensionSupported (isExtensionSupported(context, config.renderPassType, config.separateStencilUsage))
, m_renderPassType (config.renderPassType)
, m_separateStencilUsage (config.separateStencilUsage)
, m_srcFormat (config.format)
, m_dstFormat (getDstFormat(config.format, config.separateStencilUsage))
, m_sampleCount (config.sampleCount)
, m_width (32u)
, m_height (32u)
, m_srcImageAspect (getImageAspectFlags(m_srcFormat))
, m_srcImageUsage (getSrcImageUsage(m_srcFormat))
, m_srcImage (createImage(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_srcFormat, sampleCountBitFromomSampleCount(m_sampleCount), m_srcImageUsage, m_width, m_height, m_separateStencilUsage))
, m_srcImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), *m_srcImage))
, m_srcImageView (createImageAttachmentView(context.getDeviceInterface(), context.getDevice(), *m_srcImage, m_srcFormat, m_srcImageAspect))
, m_srcPrimaryInputImageView (createSrcPrimaryInputImageView(context.getDeviceInterface(), context.getDevice(), *m_srcImage, m_srcFormat, m_srcImageAspect, m_separateStencilUsage))
, m_srcSecondaryInputImageView (createSrcSecondaryInputImageView(context.getDeviceInterface(), context.getDevice(), *m_srcImage, m_srcFormat, m_srcImageAspect, m_separateStencilUsage))
, m_dstMultisampleImages (createMultisampleImages(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_dstFormat, m_sampleCount, m_width, m_height))
, m_dstMultisampleImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_dstMultisampleImages))
, m_dstMultisampleImageViews (createImageAttachmentViews(context.getDeviceInterface(), context.getDevice(), m_dstMultisampleImages, m_dstFormat, VK_IMAGE_ASPECT_COLOR_BIT))
, m_dstSinglesampleImages (createSingleSampleImages(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_dstFormat, m_sampleCount, m_width, m_height))
, m_dstSinglesampleImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_dstSinglesampleImages))
, m_dstSinglesampleImageViews (createImageAttachmentViews(context.getDeviceInterface(), context.getDevice(), m_dstSinglesampleImages, m_dstFormat, VK_IMAGE_ASPECT_COLOR_BIT))
, m_dstBuffers (createBuffers(context.getDeviceInterface(), context.getDevice(), m_dstFormat, m_sampleCount, m_width, m_height))
, m_dstBufferMemory (createBufferMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_dstBuffers))
, m_renderPass (createRenderPass(context.getDeviceInterface(), context.getDevice(), m_srcFormat, m_dstFormat, m_sampleCount, config.renderPassType, m_separateStencilUsage))
, m_framebuffer (createFramebuffer(context.getDeviceInterface(), context.getDevice(), *m_renderPass, *m_srcImageView, m_dstMultisampleImageViews, m_dstSinglesampleImageViews, m_width, m_height))
, m_renderPipelineLayout (createRenderPipelineLayout(context.getDeviceInterface(), context.getDevice()))
, m_renderPipeline (createRenderPipeline(context.getDeviceInterface(), context.getDevice(), m_srcFormat, *m_renderPass, *m_renderPipelineLayout, context.getBinaryCollection(), m_width, m_height, m_sampleCount))
, m_splitDescriptorSetLayout (createSplitDescriptorSetLayout(context.getDeviceInterface(), context.getDevice(), m_srcFormat))
, m_splitPipelineLayout (createSplitPipelineLayout(context.getDeviceInterface(), context.getDevice(), *m_splitDescriptorSetLayout))
, m_splitPipelines (createSplitPipelines(context.getDeviceInterface(), context.getDevice(), *m_renderPass, *m_splitPipelineLayout, context.getBinaryCollection(), m_width, m_height, m_sampleCount))
, m_splitDescriptorPool (createSplitDescriptorPool(context.getDeviceInterface(), context.getDevice()))
, m_splitDescriptorSet (createSplitDescriptorSet(context.getDeviceInterface(), context.getDevice(), *m_splitDescriptorPool, *m_splitDescriptorSetLayout, *m_srcPrimaryInputImageView, *m_srcSecondaryInputImageView))
, m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex()))
{
}
MultisampleRenderPassTestInstance::~MultisampleRenderPassTestInstance (void)
{
}
tcu::TestStatus MultisampleRenderPassTestInstance::iterate (void)
{
switch (m_renderPassType)
{
case RENDERPASS_TYPE_LEGACY:
return iterateInternal<RenderpassSubpass1>();
case RENDERPASS_TYPE_RENDERPASS2:
return iterateInternal<RenderpassSubpass2>();
default:
TCU_THROW(InternalError, "Impossible");
}
}
template<typename RenderpassSubpass>
tcu::TestStatus MultisampleRenderPassTestInstance::iterateInternal (void)
{
const DeviceInterface& vkd (m_context.getDeviceInterface());
const VkDevice device (m_context.getDevice());
const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL);
beginCommandBuffer(vkd, *commandBuffer);
{
const VkRenderPassBeginInfo beginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
DE_NULL,
*m_renderPass,
*m_framebuffer,
{
{ 0u, 0u },
{ m_width, m_height }
},
0u,
DE_NULL
};
RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo);
// Stencil needs to be cleared if it exists.
if (tcu::hasStencilComponent(mapVkFormat(m_srcFormat).order))
{
const VkClearAttachment clearAttachment =
{
VK_IMAGE_ASPECT_STENCIL_BIT, // VkImageAspectFlags aspectMask;
0, // deUint32 colorAttachment;
makeClearValueDepthStencil(0, 0) // VkClearValue clearValue;
};
const VkClearRect clearRect =
{
{
{ 0u, 0u },
{ m_width, m_height }
},
0, // deUint32 baseArrayLayer;
1 // deUint32 layerCount;
};
vkd.cmdClearAttachments(*commandBuffer, 1, &clearAttachment, 1, &clearRect);
}
}
vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline);
for (deUint32 sampleNdx = 0; sampleNdx < m_sampleCount; sampleNdx++)
{
vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(sampleNdx), &sampleNdx);
vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
}
for (deUint32 splitPipelineNdx = 0; splitPipelineNdx < m_splitPipelines.size(); splitPipelineNdx++)
{
RenderpassSubpass::cmdNextSubpass(vkd, *commandBuffer, &subpassBeginInfo, &subpassEndInfo);
vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_splitPipelines[splitPipelineNdx]);
vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_splitPipelineLayout, 0u, 1u, &*m_splitDescriptorSet, 0u, DE_NULL);
vkd.cmdPushConstants(*commandBuffer, *m_splitPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(splitPipelineNdx), &splitPipelineNdx);
vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u);
}
RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo);
for (size_t dstNdx = 0; dstNdx < m_dstSinglesampleImages.size(); dstNdx++)
copyImageToBuffer(vkd, *commandBuffer, **m_dstSinglesampleImages[dstNdx], **m_dstBuffers[dstNdx], tcu::IVec2(m_width, m_height), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
endCommandBuffer(vkd, *commandBuffer);
submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer);
{
const tcu::TextureFormat format (mapVkFormat(m_dstFormat));
const tcu::TextureFormat srcFormat (mapVkFormat(m_srcFormat));
const bool verifyDepth (m_separateStencilUsage ? (m_separateStencilUsage == TEST_DEPTH) : tcu::hasDepthComponent(srcFormat.order));
const bool verifyStencil (m_separateStencilUsage ? (m_separateStencilUsage == TEST_STENCIL) : tcu::hasStencilComponent(srcFormat.order));
for (deUint32 sampleNdx = 0; sampleNdx < m_sampleCount; sampleNdx++)
{
Allocation *dstBufMem = m_dstBufferMemory[sampleNdx].get();
invalidateAlloc(vkd, device, *dstBufMem);
const std::string name ("Sample" + de::toString(sampleNdx));
const void* const ptr (dstBufMem->getHostPtr());
const tcu::ConstPixelBufferAccess access (format, m_width, m_height, 1, ptr);
tcu::TextureLevel reference (format, m_width, m_height);
if (verifyDepth || verifyStencil)
{
if (verifyDepth)
{
for (deUint32 y = 0; y < m_height; y++)
for (deUint32 x = 0; x < m_width; x++)
{
const deUint32 x1 = x ^ sampleNdx;
const deUint32 y1 = y ^ sampleNdx;
const float range = 1.0f;
float depth = 0.0f;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
for (size_t bitNdx = 0; bitNdx < 10; bitNdx++)
{
depth += (range / (float)divider)
* (((bitNdx % 2 == 0 ? x1 : y1) & (0x1u << (bitNdx / 2u))) == 0u ? 0u : 1u);
divider *= 2;
}
reference.getAccess().setPixel(Vec4(depth, 0.0f, 0.0f, 0.0f), x, y);
}
}
if (verifyStencil)
{
for (deUint32 y = 0; y < m_height; y++)
for (deUint32 x = 0; x < m_width; x++)
{
const deUint32 stencil = sampleNdx + 1u;
if (verifyDepth)
{
const Vec4 src (reference.getAccess().getPixel(x, y));
reference.getAccess().setPixel(Vec4(src.x(), (float)stencil, 0.0f, 0.0f), x, y);
}
else
reference.getAccess().setPixel(Vec4((float)stencil, 0.0f, 0.0f, 0.0f), x, y);
}
}
{
const Vec4 threshold (verifyDepth ? (1.0f / 1024.0f) : 0.0f, 0.0f, 0.0f, 0.0f);
if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR))
m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx));
}
}
else
{
const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type));
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
{
const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast<deUint32>());
const UVec4 minValue (0);
const UVec4 range (UVec4(1u) << tcu::min(bits, UVec4(31)));
const int componentCount (tcu::getNumUsedChannels(format.order));
const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]);
for (deUint32 y = 0; y < m_height; y++)
for (deUint32 x = 0; x < m_width; x++)
{
const deUint32 x1 = x ^ sampleNdx;
const deUint32 y1 = y ^ sampleNdx;
UVec4 color (minValue);
deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u };
deUint32 nextSrcBit = 0;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
while (nextSrcBit < de::min(bitSize, 10u))
{
for (int compNdx = 0; compNdx < componentCount; compNdx++)
{
if (dstBitsUsed[compNdx] > bits[compNdx])
continue;
color[compNdx] += (range[compNdx] / divider)
* (((nextSrcBit % 2 == 0 ? x1 : y1) & (0x1u << (nextSrcBit / 2u))) == 0u ? 0u : 1u);
nextSrcBit++;
dstBitsUsed[compNdx]++;
}
divider *= 2;
}
reference.getAccess().setPixel(color, x, y);
}
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, UVec4(0u), tcu::COMPARE_LOG_ON_ERROR))
m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx));
break;
}
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
{
const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast<deUint32>());
const IVec4 minValue (0);
const IVec4 range ((UVec4(1u) << tcu::min(bits, UVec4(30))).cast<deInt32>());
const int componentCount (tcu::getNumUsedChannels(format.order));
const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]);
for (deUint32 y = 0; y < m_height; y++)
for (deUint32 x = 0; x < m_width; x++)
{
const deUint32 x1 = x ^ sampleNdx;
const deUint32 y1 = y ^ sampleNdx;
IVec4 color (minValue);
deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u };
deUint32 nextSrcBit = 0;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
while (nextSrcBit < de::min(bitSize, 10u))
{
for (int compNdx = 0; compNdx < componentCount; compNdx++)
{
if (dstBitsUsed[compNdx] > bits[compNdx])
continue;
color[compNdx] += (range[compNdx] / divider)
* (((nextSrcBit % 2 == 0 ? x1 : y1) & (0x1u << (nextSrcBit / 2u))) == 0u ? 0u : 1u);
nextSrcBit++;
dstBitsUsed[compNdx]++;
}
divider *= 2;
}
reference.getAccess().setPixel(color, x, y);
}
if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, UVec4(0u), tcu::COMPARE_LOG_ON_ERROR))
m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx));
break;
}
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
const tcu::TextureFormatInfo info (tcu::getTextureFormatInfo(format));
const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast<deUint32>());
const Vec4 minLimit (-65536.0);
const Vec4 maxLimit (65536.0);
const Vec4 minValue (tcu::max(info.valueMin, minLimit));
const Vec4 range (tcu::min(info.valueMax, maxLimit) - minValue);
const int componentCount (tcu::getNumUsedChannels(format.order));
const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]);
for (deUint32 y = 0; y < m_height; y++)
for (deUint32 x = 0; x < m_width; x++)
{
const deUint32 x1 = x ^ sampleNdx;
const deUint32 y1 = y ^ sampleNdx;
Vec4 color (minValue);
deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u };
deUint32 nextSrcBit = 0;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
while (nextSrcBit < de::min(bitSize, 10u))
{
for (int compNdx = 0; compNdx < componentCount; compNdx++)
{
if (dstBitsUsed[compNdx] > bits[compNdx])
continue;
color[compNdx] += (range[compNdx] / (float)divider)
* (((nextSrcBit % 2 == 0 ? x1 : y1) & (0x1u << (nextSrcBit / 2u))) == 0u ? 0u : 1u);
nextSrcBit++;
dstBitsUsed[compNdx]++;
}
divider *= 2;
}
if (tcu::isSRGB(format))
reference.getAccess().setPixel(tcu::linearToSRGB(color), x, y);
else
reference.getAccess().setPixel(color, x, y);
}
if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT)
{
// Convert target format ulps to float ulps and allow 64ulp differences
const UVec4 threshold (64u * (UVec4(1u) << (UVec4(23) - tcu::getTextureFormatMantissaBitDepth(format).cast<deUint32>())));
if (!tcu::floatUlpThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR))
m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx));
}
else
{
// Allow error of 4 times the minimum presentable difference
const Vec4 threshold (4.0f * 1.0f / ((UVec4(1u) << tcu::getTextureFormatMantissaBitDepth(format).cast<deUint32>()) - 1u).cast<float>());
if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR))
m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx));
}
break;
}
default:
DE_FATAL("Unknown channel class");
}
}
}
}
return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
}
struct Programs
{
void init (vk::SourceCollections& dst, TestConfig config) const
{
const tcu::TextureFormat format (mapVkFormat(config.format));
const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type));
const bool testDepth (config.separateStencilUsage ? (config.separateStencilUsage == TEST_DEPTH) : tcu::hasDepthComponent(format.order));
const bool testStencil (config.separateStencilUsage ? (config.separateStencilUsage == TEST_STENCIL) : tcu::hasStencilComponent(format.order));
dst.glslSources.add("quad-vert") << glu::VertexSource(
"#version 450\n"
"out gl_PerVertex {\n"
"\tvec4 gl_Position;\n"
"};\n"
"highp float;\n"
"void main (void) {\n"
"\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
"\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
"}\n");
if (testDepth)
{
const Vec4 minValue (0.0f);
const Vec4 range (1.0f);
std::ostringstream fragmentShader;
fragmentShader <<
"#version 450\n"
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint sampleIndex;\n"
"} pushConstants;\n"
"void main (void)\n"
"{\n"
"\thighp uint sampleIndex = pushConstants.sampleIndex;\n"
"\tgl_SampleMask[0] = int((~0x0u) << sampleIndex);\n"
"\thighp float depth;\n"
"\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n"
"\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n";
fragmentShader << "\tdepth = " << minValue[0] << ";\n";
{
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
for (size_t bitNdx = 0; bitNdx < 10; bitNdx++)
{
fragmentShader <<
"\tdepth += " << (range[0] / (float)divider)
<< " * float(bitfieldExtract(" << (bitNdx % 2 == 0 ? "x" : "y") << ", " << (bitNdx / 2) << ", 1));\n";
divider *= 2;
}
}
fragmentShader <<
"\tgl_FragDepth = depth;\n"
"}\n";
dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str());
}
else if (testStencil)
{
dst.glslSources.add("quad-frag") << glu::FragmentSource(
"#version 450\n"
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint sampleIndex;\n"
"} pushConstants;\n"
"void main (void)\n"
"{\n"
"\thighp uint sampleIndex = pushConstants.sampleIndex;\n"
"\tgl_SampleMask[0] = int((~0x0u) << sampleIndex);\n"
"}\n");
}
else
{
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
{
const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast<deUint32>());
const UVec4 minValue (0);
const UVec4 range (UVec4(1u) << tcu::min(bits, UVec4(31)));
std::ostringstream fragmentShader;
fragmentShader <<
"#version 450\n"
"layout(location = 0) out highp uvec4 o_color;\n"
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint sampleIndex;\n"
"} pushConstants;\n"
"void main (void)\n"
"{\n"
"\thighp uint sampleIndex = pushConstants.sampleIndex;\n"
"\tgl_SampleMask[0] = int(0x1u << sampleIndex);\n"
"\thighp uint color[4];\n"
"\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n"
"\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n";
for (int ndx = 0; ndx < 4; ndx++)
fragmentShader << "\tcolor[" << ndx << "] = " << minValue[ndx] << ";\n";
{
const int componentCount = tcu::getNumUsedChannels(format.order);
const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]);
deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u };
deUint32 nextSrcBit = 0;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
while (nextSrcBit < de::min(bitSize, 10u))
{
for (int compNdx = 0; compNdx < componentCount; compNdx++)
{
if (dstBitsUsed[compNdx] > bits[compNdx])
continue;
fragmentShader <<
"\tcolor[" << compNdx << "] += " << (range[compNdx] / divider)
<< " * bitfieldExtract(" << (nextSrcBit % 2 == 0 ? "x" : "y") << ", " << (nextSrcBit / 2) << ", 1);\n";
nextSrcBit++;
dstBitsUsed[compNdx]++;
}
divider *= 2;
}
}
fragmentShader <<
"\to_color = uvec4(color[0], color[1], color[2], color[3]);\n"
"}\n";
dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str());
break;
}
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
{
const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast<deUint32>());
const IVec4 minValue (0);
const IVec4 range ((UVec4(1u) << tcu::min(bits, UVec4(30))).cast<deInt32>());
const IVec4 maxV ((UVec4(1u) << (bits - UVec4(1u))).cast<deInt32>());
const IVec4 clampMax (maxV - 1);
const IVec4 clampMin (-maxV);
std::ostringstream fragmentShader;
fragmentShader <<
"#version 450\n"
"layout(location = 0) out highp ivec4 o_color;\n"
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint sampleIndex;\n"
"} pushConstants;\n"
"void main (void)\n"
"{\n"
"\thighp uint sampleIndex = pushConstants.sampleIndex;\n"
"\tgl_SampleMask[0] = int(0x1u << sampleIndex);\n"
"\thighp int color[4];\n"
"\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n"
"\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n";
for (int ndx = 0; ndx < 4; ndx++)
fragmentShader << "\tcolor[" << ndx << "] = " << minValue[ndx] << ";\n";
{
const int componentCount = tcu::getNumUsedChannels(format.order);
const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]);
deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u };
deUint32 nextSrcBit = 0;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
while (nextSrcBit < de::min(bitSize, 10u))
{
for (int compNdx = 0; compNdx < componentCount; compNdx++)
{
if (dstBitsUsed[compNdx] > bits[compNdx])
continue;
fragmentShader <<
"\tcolor[" << compNdx << "] += " << (range[compNdx] / divider)
<< " * int(bitfieldExtract(" << (nextSrcBit % 2 == 0 ? "x" : "y") << ", " << (nextSrcBit / 2) << ", 1));\n";
nextSrcBit++;
dstBitsUsed[compNdx]++;
}
divider *= 2;
}
}
// The spec doesn't define whether signed-integers are clamped on output,
// so we'll clamp them explicitly to have well-defined outputs.
fragmentShader <<
"\to_color = clamp(ivec4(color[0], color[1], color[2], color[3]), " <<
"ivec4" << clampMin << ", ivec4" << clampMax << ");\n" <<
"}\n";
dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str());
break;
}
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
{
const tcu::TextureFormatInfo info (tcu::getTextureFormatInfo(format));
const UVec4 bits (tcu::getTextureFormatMantissaBitDepth(format).cast<deUint32>());
const Vec4 minLimit (-65536.0);
const Vec4 maxLimit (65536.0);
const Vec4 minValue (tcu::max(info.valueMin, minLimit));
const Vec4 range (tcu::min(info.valueMax, maxLimit) - minValue);
std::ostringstream fragmentShader;
fragmentShader <<
"#version 450\n"
"layout(location = 0) out highp vec4 o_color;\n"
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint sampleIndex;\n"
"} pushConstants;\n"
"void main (void)\n"
"{\n"
"\thighp uint sampleIndex = pushConstants.sampleIndex;\n"
"\tgl_SampleMask[0] = int(0x1u << sampleIndex);\n"
"\thighp float color[4];\n"
"\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n"
"\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n";
for (int ndx = 0; ndx < 4; ndx++)
fragmentShader << "\tcolor[" << ndx << "] = " << minValue[ndx] << ";\n";
{
const int componentCount = tcu::getNumUsedChannels(format.order);
const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]);
deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u };
deUint32 nextSrcBit = 0;
deUint32 divider = 2;
// \note Limited to ten bits since the target is 32x32, so there are 10 input bits
while (nextSrcBit < de::min(bitSize, 10u))
{
for (int compNdx = 0; compNdx < componentCount; compNdx++)
{
if (dstBitsUsed[compNdx] > bits[compNdx])
continue;
fragmentShader <<
"\tcolor[" << compNdx << "] += " << (range[compNdx] / (float)divider)
<< " * float(bitfieldExtract(" << (nextSrcBit % 2 == 0 ? "x" : "y") << ", " << (nextSrcBit / 2) << ", 1));\n";
nextSrcBit++;
dstBitsUsed[compNdx]++;
}
divider *= 2;
}
}
fragmentShader <<
"\to_color = vec4(color[0], color[1], color[2], color[3]);\n"
"}\n";
dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str());
break;
}
default:
DE_FATAL("Unknown channel class");
}
}
if (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order))
{
std::ostringstream splitShader;
splitShader <<
"#version 450\n";
if (testDepth && testStencil)
{
splitShader << "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInputMS i_depth;\n"
<< "layout(input_attachment_index = 0, set = 0, binding = 1) uniform highp usubpassInputMS i_stencil;\n";
}
else if (testDepth)
splitShader << "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInputMS i_depth;\n";
else if (testStencil)
splitShader << "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp usubpassInputMS i_stencil;\n";
splitShader <<
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint splitSubpassIndex;\n"
"} pushConstants;\n";
for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++)
{
if (testDepth && testStencil)
splitShader << "layout(location = " << attachmentNdx << ") out highp vec2 o_color" << attachmentNdx << ";\n";
else
splitShader << "layout(location = " << attachmentNdx << ") out highp float o_color" << attachmentNdx << ";\n";
}
splitShader <<
"void main (void)\n"
"{\n";
for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++)
{
if (testDepth)
splitShader << "\thighp float depth" << attachmentNdx << " = subpassLoad(i_depth, int(" << MAX_COLOR_ATTACHMENT_COUNT << " * pushConstants.splitSubpassIndex + " << attachmentNdx << "u)).x;\n";
if (testStencil)
splitShader << "\thighp uint stencil" << attachmentNdx << " = subpassLoad(i_stencil, int(" << MAX_COLOR_ATTACHMENT_COUNT << " * pushConstants.splitSubpassIndex + " << attachmentNdx << "u)).x;\n";
if (testDepth && testStencil)
splitShader << "\to_color" << attachmentNdx << " = vec2(depth" << attachmentNdx << ", float(stencil" << attachmentNdx << "));\n";
else if (testDepth)
splitShader << "\to_color" << attachmentNdx << " = float(depth" << attachmentNdx << ");\n";
else if (testStencil)
splitShader << "\to_color" << attachmentNdx << " = float(stencil" << attachmentNdx << ");\n";
}
splitShader <<
"}\n";
dst.glslSources.add("quad-split-frag") << glu::FragmentSource(splitShader.str());
}
else
{
std::string subpassType;
std::string outputType;
switch (channelClass)
{
case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
subpassType = "usubpassInputMS";
outputType = "uvec4";
break;
case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
subpassType = "isubpassInputMS";
outputType = "ivec4";
break;
case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
subpassType = "subpassInputMS";
outputType = "vec4";
break;
default:
DE_FATAL("Unknown channel class");
}
std::ostringstream splitShader;
splitShader <<
"#version 450\n"
"layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp " << subpassType << " i_color;\n"
"layout(push_constant) uniform PushConstant {\n"
"\thighp uint splitSubpassIndex;\n"
"} pushConstants;\n";
for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++)
splitShader << "layout(location = " << attachmentNdx << ") out highp " << outputType << " o_color" << attachmentNdx << ";\n";
splitShader <<
"void main (void)\n"
"{\n";
for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++)
splitShader << "\to_color" << attachmentNdx << " = subpassLoad(i_color, int(" << MAX_COLOR_ATTACHMENT_COUNT << " * pushConstants.splitSubpassIndex + " << attachmentNdx << "u));\n";
splitShader <<
"}\n";
dst.glslSources.add("quad-split-frag") << glu::FragmentSource(splitShader.str());
}
}
};
std::string formatToName (VkFormat format)
{
const std::string formatStr = de::toString(format);
const std::string prefix = "VK_FORMAT_";
DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix);
return de::toLower(formatStr.substr(prefix.length()));
}
void initTests (tcu::TestCaseGroup* group, RenderPassType renderPassType)
{
static const VkFormat formats[] =
{
VK_FORMAT_R5G6B5_UNORM_PACK16,
VK_FORMAT_R8_UNORM,
VK_FORMAT_R8_SNORM,
VK_FORMAT_R8_UINT,
VK_FORMAT_R8_SINT,
VK_FORMAT_R8G8_UNORM,
VK_FORMAT_R8G8_SNORM,
VK_FORMAT_R8G8_UINT,
VK_FORMAT_R8G8_SINT,
VK_FORMAT_R8G8B8A8_UNORM,
VK_FORMAT_R8G8B8A8_SNORM,
VK_FORMAT_R8G8B8A8_UINT,
VK_FORMAT_R8G8B8A8_SINT,
VK_FORMAT_R8G8B8A8_SRGB,
VK_FORMAT_A8B8G8R8_UNORM_PACK32,
VK_FORMAT_A8B8G8R8_SNORM_PACK32,
VK_FORMAT_A8B8G8R8_UINT_PACK32,
VK_FORMAT_A8B8G8R8_SINT_PACK32,
VK_FORMAT_A8B8G8R8_SRGB_PACK32,
VK_FORMAT_B8G8R8A8_UNORM,
VK_FORMAT_B8G8R8A8_SRGB,
VK_FORMAT_A2R10G10B10_UNORM_PACK32,
VK_FORMAT_A2B10G10R10_UNORM_PACK32,
VK_FORMAT_A2B10G10R10_UINT_PACK32,
VK_FORMAT_R16_UNORM,
VK_FORMAT_R16_SNORM,
VK_FORMAT_R16_UINT,
VK_FORMAT_R16_SINT,
VK_FORMAT_R16_SFLOAT,
VK_FORMAT_R16G16_UNORM,
VK_FORMAT_R16G16_SNORM,
VK_FORMAT_R16G16_UINT,
VK_FORMAT_R16G16_SINT,
VK_FORMAT_R16G16_SFLOAT,
VK_FORMAT_R16G16B16A16_UNORM,
VK_FORMAT_R16G16B16A16_SNORM,
VK_FORMAT_R16G16B16A16_UINT,
VK_FORMAT_R16G16B16A16_SINT,
VK_FORMAT_R16G16B16A16_SFLOAT,
VK_FORMAT_R32_UINT,
VK_FORMAT_R32_SINT,
VK_FORMAT_R32_SFLOAT,
VK_FORMAT_R32G32_UINT,
VK_FORMAT_R32G32_SINT,
VK_FORMAT_R32G32_SFLOAT,
VK_FORMAT_R32G32B32A32_UINT,
VK_FORMAT_R32G32B32A32_SINT,
VK_FORMAT_R32G32B32A32_SFLOAT,
VK_FORMAT_D16_UNORM,
VK_FORMAT_X8_D24_UNORM_PACK32,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D32_SFLOAT_S8_UINT
};
const deUint32 sampleCounts[] =
{
2u, 4u, 8u, 16u, 32u
};
tcu::TestContext& testCtx (group->getTestContext());
de::MovePtr<tcu::TestCaseGroup> extGroup (new tcu::TestCaseGroup(testCtx, "separate_stencil_usage", "test VK_EXT_separate_stencil_usage"));
for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++)
{
const VkFormat format (formats[formatNdx]);
const std::string formatName (formatToName(format));
de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), formatName.c_str()));
de::MovePtr<tcu::TestCaseGroup> extFormatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), formatName.c_str()));
for (size_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountNdx++)
{
const deUint32 sampleCount (sampleCounts[sampleCountNdx]);
const TestConfig testConfig (format, sampleCount, renderPassType);
const std::string testName ("samples_" + de::toString(sampleCount));
formatGroup->addChild(new InstanceFactory1<MultisampleRenderPassTestInstance, TestConfig, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName.c_str(), testName.c_str(), testConfig));
// create tests for VK_EXT_separate_stencil_usage
if (tcu::hasDepthComponent(mapVkFormat(format).order) && tcu::hasStencilComponent(mapVkFormat(format).order))
{
de::MovePtr<tcu::TestCaseGroup> sampleGroup (new tcu::TestCaseGroup(testCtx, testName.c_str(), testName.c_str()));
{
const TestConfig separateUsageDepthTestConfig (format, sampleCount, renderPassType, TEST_DEPTH);
sampleGroup->addChild(new InstanceFactory1<MultisampleRenderPassTestInstance, TestConfig, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "test_depth", "depth with input attachment bit", separateUsageDepthTestConfig));
const TestConfig separateUsageStencilTestConfig (format, sampleCount, renderPassType, TEST_STENCIL);
sampleGroup->addChild(new InstanceFactory1<MultisampleRenderPassTestInstance, TestConfig, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "test_stencil", "stencil with input attachment bit", separateUsageStencilTestConfig));
}
extFormatGroup->addChild(sampleGroup.release());
}
}
group->addChild(formatGroup.release());
extGroup->addChild(extFormatGroup.release());
}
group->addChild(extGroup.release());
}
} // anonymous
tcu::TestCaseGroup* createRenderPassMultisampleTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "multisample", "Multisample render pass tests", initTests, RENDERPASS_TYPE_LEGACY);
}
tcu::TestCaseGroup* createRenderPass2MultisampleTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "multisample", "Multisample render pass tests", initTests, RENDERPASS_TYPE_RENDERPASS2);
}
} // vkt