blob: ebee391582f459164898a8dde5dde2c7fe9a54ab [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2019 Advanced Micro Devices, Inc.
* Copyright (c) 2019 The Khronos Group 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 VK_AMD_mixed_attachment_samples
*//*--------------------------------------------------------------------*/
#include "vktPipelineMultisampleMixedAttachmentSamplesTests.hpp"
#include "vktPipelineSampleLocationsUtil.hpp"
#include "vktPipelineMakeUtil.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkPlatform.hpp"
#include "vkMemUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkPrograms.hpp"
#include "vkImageUtil.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
#include "deRandom.hpp"
#include "deMath.h"
#include "tcuVector.hpp"
#include "tcuTestLog.hpp"
#include "tcuImageCompare.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuRGBA.hpp"
#include <string>
#include <vector>
namespace vkt
{
namespace pipeline
{
namespace
{
using namespace vk;
using de::UniquePtr;
using de::MovePtr;
using de::SharedPtr;
using tcu::UVec2;
using tcu::Vec2;
using tcu::Vec4;
bool compareGreenImage (tcu::TestLog& log, const char* name, const char* description, const tcu::ConstPixelBufferAccess& image)
{
tcu::TextureLevel greenImage(image.getFormat(), image.getWidth(), image.getHeight());
tcu::clear(greenImage.getAccess(), tcu::RGBA::green().toIVec());
return tcu::intThresholdCompare(log, name, description, greenImage.getAccess(), image, tcu::UVec4(2u), tcu::COMPARE_LOG_RESULT);
}
VkImageAspectFlags getImageAspectFlags (const VkFormat format)
{
const tcu::TextureFormat tcuFormat = mapVkFormat(format);
if (tcuFormat.order == tcu::TextureFormat::DS) return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
else if (tcuFormat.order == tcu::TextureFormat::D) return VK_IMAGE_ASPECT_DEPTH_BIT;
else if (tcuFormat.order == tcu::TextureFormat::S) return VK_IMAGE_ASPECT_STENCIL_BIT;
DE_ASSERT(false);
return 0u;
}
struct CompareData
{
Vec4 color;
float depth;
deUint32 stencil;
// Pad to 2*16 bytes, in the shader the base alignment of this structure is 16 due to vec4
deUint32 padding[2];
CompareData() : color(Vec4(0.0f)), depth(0.0f), stencil(0u)
{
padding[0] = 0u;
padding[1] = 0u;
static_assert(sizeof(CompareData) == (2 * 16), "Wrong structure size, expected 16 bytes");
}
};
//! Make a dummy sampler.
Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice device)
{
const VkSamplerCreateInfo samplerParams =
{
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags;
VK_FILTER_NEAREST, // VkFilter magFilter;
VK_FILTER_NEAREST, // VkFilter minFilter;
VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU;
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV;
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW;
0.0f, // float mipLodBias;
VK_FALSE, // VkBool32 anisotropyEnable;
1.0f, // float maxAnisotropy;
VK_FALSE, // VkBool32 compareEnable;
VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp;
0.0f, // float minLod;
0.0f, // float maxLod;
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
VK_FALSE, // VkBool32 unnormalizedCoordinates;
};
return createSampler(vk, device, &samplerParams);
}
Move<VkImage> makeImage (const DeviceInterface& vk,
const VkDevice device,
const VkFormat format,
const UVec2& size,
const VkSampleCountFlagBits samples,
const VkImageUsageFlags usage)
{
const VkImageCreateInfo imageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkImageCreateFlags)0, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
format, // VkFormat format;
makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
samples, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
usage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
0u, // deUint32 queueFamilyIndexCount;
DE_NULL, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
return createImage(vk, device, &imageParams);
}
inline bool isDepthFormat (const VkFormat format)
{
return (getImageAspectFlags(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
}
inline bool isStencilFormat (const VkFormat format)
{
return (getImageAspectFlags(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
}
//! Create a test-specific MSAA pipeline
Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk,
const VkDevice device,
const VkPipelineLayout pipelineLayout,
const VkRenderPass renderPass,
const VkShaderModule vertexModule,
const VkShaderModule fragmentModule,
const bool useVertexInput,
const deUint32 subpassNdx,
const UVec2& renderSize,
const VkImageAspectFlags depthStencilAspect, //!< Used to determine which D/S tests to turn on
const VkSampleCountFlagBits numSamples,
const bool sampleShadingEnable,
const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL)
{
std::vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
// Vertex attributes: position and color
if (useVertexInput)
{
vertexInputBindingDescriptions.push_back (makeVertexInputBindingDescription (0u, 2 * sizeof(Vec4), VK_VERTEX_INPUT_RATE_VERTEX));
vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u));
vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(Vec4)));
}
const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags;
static_cast<deUint32>(vertexInputBindingDescriptions.size()), // uint32_t vertexBindingDescriptionCount;
dataOrNullPtr(vertexInputBindingDescriptions), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount;
dataOrNullPtr(vertexInputAttributeDescriptions), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
};
const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags;
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology;
VK_FALSE, // VkBool32 primitiveRestartEnable;
};
const VkViewport viewport =
{
0.0f, 0.0f, // x, y
static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), // widht, height
0.0f, 1.0f // minDepth, maxDepth
};
const VkRect2D scissor =
{
makeOffset2D(0, 0),
makeExtent2D(renderSize.x(), renderSize.y()),
};
const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags;
1u, // uint32_t viewportCount;
&viewport, // const VkViewport* pViewports;
1u, // uint32_t scissorCount;
&scissor, // const VkRect2D* pScissors;
};
const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags;
VK_FALSE, // VkBool32 depthClampEnable;
VK_FALSE, // VkBool32 rasterizerDiscardEnable;
VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
VK_FALSE, // VkBool32 depthBiasEnable;
0.0f, // float depthBiasConstantFactor;
0.0f, // float depthBiasClamp;
0.0f, // float depthBiasSlopeFactor;
1.0f, // float lineWidth;
};
VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_TRUE, // VkBool32 sampleLocationsEnable;
VkSampleLocationsInfoEXT(), // VkSampleLocationsInfoEXT sampleLocationsInfo;
};
VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags;
numSamples, // VkSampleCountFlagBits rasterizationSamples;
sampleShadingEnable, // VkBool32 sampleShadingEnable;
1.0f, // float minSampleShading;
DE_NULL, // const VkSampleMask* pSampleMask;
VK_FALSE, // VkBool32 alphaToCoverageEnable;
VK_FALSE // VkBool32 alphaToOneEnable;
};
if (pSampleLocationsInfo)
{
pipelineSampleLocationsCreateInfo.sampleLocationsInfo = *pSampleLocationsInfo;
pipelineMultisampleStateInfo.pNext = &pipelineSampleLocationsCreateInfo;
}
// Simply increment the buffer
const VkStencilOpState stencilOpState = makeStencilOpState(
VK_STENCIL_OP_KEEP, // stencil fail
VK_STENCIL_OP_INCREMENT_AND_CLAMP, // depth & stencil pass
VK_STENCIL_OP_KEEP, // depth only fail
VK_COMPARE_OP_ALWAYS, // compare op
~0u, // compare mask
~0u, // write mask
0u); // reference
// Always pass the depth test
VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags;
(depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0u, // VkBool32 depthTestEnable;
VK_TRUE, // VkBool32 depthWriteEnable;
VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp;
VK_FALSE, // VkBool32 depthBoundsTestEnable;
(depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0u, // VkBool32 stencilTestEnable;
stencilOpState, // VkStencilOpState front;
stencilOpState, // VkStencilOpState back;
0.0f, // float minDepthBounds;
1.0f, // float maxDepthBounds;
};
const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
const VkPipelineColorBlendAttachmentState defaultBlendAttachmentState =
{
VK_FALSE, // VkBool32 blendEnable;
VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
colorComponentsAll, // VkColorComponentFlags colorWriteMask;
};
const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags;
VK_FALSE, // VkBool32 logicOpEnable;
VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
1u, // deUint32 attachmentCount;
&defaultBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
{ 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
};
const VkPipelineShaderStageCreateInfo pShaderStages[] =
{
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
vertexModule, // VkShaderModule module;
"main", // const char* pName;
DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
},
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
fragmentModule, // VkShaderModule module;
"main", // const char* pName;
DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
}
};
const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
DE_LENGTH_OF_ARRAY(pShaderStages), // deUint32 stageCount;
pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages;
&vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
&pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
&pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState;
&pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
&pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
&pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
&pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
pipelineLayout, // VkPipelineLayout layout;
renderPass, // VkRenderPass renderPass;
subpassNdx, // deUint32 subpass;
DE_NULL, // VkPipeline basePipelineHandle;
-1, // deInt32 basePipelineIndex;
};
return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
}
//! Wrap float after an increment
inline float wrapIncFloat (float a, float min, float max)
{
return deFloatMax(min, deFloatMod(a, max));
}
//! Generate expected data for color, depth, and stencil samples of a given image.
//! Samples are ordered starting at pixel (0, 0) - see compute shader source for reference.
std::vector<CompareData> generateCompareData (const deUint32 seed,
const UVec2& imageSize,
const deUint32 numCoverageSamples,
const deUint32 numColorSamples,
const deUint32 numDepthStencilSamples)
{
std::vector<CompareData> allData;
de::Random rng (seed);
for (deUint32 y = 0u; y < imageSize.y(); ++y)
for (deUint32 x = 0u; x < imageSize.x(); ++x)
for (deUint32 sample = 0u; sample < numCoverageSamples; ++sample)
{
CompareData cd;
if (sample < numColorSamples)
{
for (int i = 0; i < 3; ++i)
cd.color[i] = 0.1f * static_cast<float>(rng.getInt(1, 10));
cd.color.w() = 1.0f;
}
if (sample < numDepthStencilSamples)
{
const deUint32 globalSample = sample + numColorSamples * (x + imageSize.x() * y);
cd.depth = wrapIncFloat(0.05f * static_cast<float>(1 + globalSample), 0.05f, 1.0f);
cd.stencil = 1 + globalSample % numCoverageSamples;
}
allData.push_back(cd);
}
return allData;
}
//! NDC transformation algorithm for sample locations
template<typename SampleAccessor>
std::vector<Vec2> ndcTransformEachSampleInPixel (const UVec2& framebufferSize, const deUint32 numSamplesPerPixel, const SampleAccessor& access)
{
std::vector<Vec2> locations;
for (deUint32 y = 0; y < framebufferSize.y(); ++y)
for (deUint32 x = 0; x < framebufferSize.x(); ++x)
for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel; ++sampleNdx)
{
const Vec2& sp = access(x, y, sampleNdx);
const float globalX = sp.x() + static_cast<float>(x);
const float globalY = sp.y() + static_cast<float>(y);
// Transform to [-1, 1] space
locations.push_back(Vec2(-1.0f + 2.0f * (globalX / static_cast<float>(framebufferSize.x())),
-1.0f + 2.0f * (globalY / static_cast<float>(framebufferSize.y()))));
}
return locations;
}
class AccessStandardSampleLocationsArray
{
public:
AccessStandardSampleLocationsArray (const Vec2* ptr) : m_pData (ptr) {}
const Vec2& operator ()(const deUint32 x, const deUint32 y, const deUint32 sampleNdx) const
{
DE_UNREF(x);
DE_UNREF(y);
return m_pData[sampleNdx];
}
private:
const Vec2* m_pData;
};
class AccessMultisamplePixelGrid
{
public:
AccessMultisamplePixelGrid (const MultisamplePixelGrid* ptr) : m_pGrid (ptr) {}
Vec2 operator ()(const deUint32 x, const deUint32 y, const deUint32 sampleNdx) const
{
const VkSampleLocationEXT& sp = m_pGrid->getSample(x, y, sampleNdx);
return Vec2(sp.x, sp.y);
}
private:
const MultisamplePixelGrid* m_pGrid;
};
//! Generate NDC space standard sample locations at each framebuffer pixel
//! Data is filled starting at pixel (0,0) and for each pixel there are numSamples samples
std::vector<Vec2> genFramebufferStandardSampleLocations (const VkSampleCountFlagBits numSamples, const UVec2& framebufferSize)
{
static const Vec2 s_location_samples_1[] =
{
Vec2(0.5f, 0.5f),
};
static const Vec2 s_location_samples_2[] =
{
Vec2(0.75f, 0.75f),
Vec2(0.25f, 0.25f),
};
static const Vec2 s_location_samples_4[] =
{
Vec2(0.375f, 0.125f),
Vec2(0.875f, 0.375f),
Vec2(0.125f, 0.625f),
Vec2(0.625f, 0.875f),
};
static const Vec2 s_location_samples_8[] =
{
Vec2(0.5625f, 0.3125f),
Vec2(0.4375f, 0.6875f),
Vec2(0.8125f, 0.5625f),
Vec2(0.3125f, 0.1875f),
Vec2(0.1875f, 0.8125f),
Vec2(0.0625f, 0.4375f),
Vec2(0.6875f, 0.9375f),
Vec2(0.9375f, 0.0625f),
};
static const Vec2 s_location_samples_16[] =
{
Vec2(0.5625f, 0.5625f),
Vec2(0.4375f, 0.3125f),
Vec2(0.3125f, 0.6250f),
Vec2(0.7500f, 0.4375f),
Vec2(0.1875f, 0.3750f),
Vec2(0.6250f, 0.8125f),
Vec2(0.8125f, 0.6875f),
Vec2(0.6875f, 0.1875f),
Vec2(0.3750f, 0.8750f),
Vec2(0.5000f, 0.0625f),
Vec2(0.2500f, 0.1250f),
Vec2(0.1250f, 0.7500f),
Vec2(0.0000f, 0.5000f),
Vec2(0.9375f, 0.2500f),
Vec2(0.8750f, 0.9375f),
Vec2(0.0625f, 0.0000f),
};
const Vec2* pSampleLocation = DE_NULL;
switch (numSamples)
{
case VK_SAMPLE_COUNT_1_BIT: pSampleLocation = s_location_samples_1; break;
case VK_SAMPLE_COUNT_2_BIT: pSampleLocation = s_location_samples_2; break;
case VK_SAMPLE_COUNT_4_BIT: pSampleLocation = s_location_samples_4; break;
case VK_SAMPLE_COUNT_8_BIT: pSampleLocation = s_location_samples_8; break;
case VK_SAMPLE_COUNT_16_BIT: pSampleLocation = s_location_samples_16; break;
default:
DE_ASSERT(0);
return std::vector<Vec2>();
}
return ndcTransformEachSampleInPixel(framebufferSize, static_cast<deUint32>(numSamples), AccessStandardSampleLocationsArray(pSampleLocation));
}
//! Generate NDC space custom sample locations at each framebuffer pixel, based on the given pixel grid
std::vector<Vec2> getSampleLocations (const MultisamplePixelGrid& pixelGrid, const UVec2& framebufferSize)
{
return ndcTransformEachSampleInPixel(framebufferSize, pixelGrid.samplesPerPixel(), AccessMultisamplePixelGrid(&pixelGrid));
}
struct PositionColor
{
tcu::Vec4 position;
tcu::Vec4 color;
PositionColor (const tcu::Vec4& pos, const tcu::Vec4& col) : position(pos), color(col) {}
};
//! Generate subpixel triangles containing the sample position, based on compare data.
//! Stencil values are created by overlapping triangles, so the stencil pipeline state must be set up accordingly.
std::vector<PositionColor> generateSubpixelTriangles (const UVec2& renderSize,
const std::vector<CompareData>& compareData,
const std::vector<Vec2>& sampleLocations)
{
std::vector<PositionColor> vertices;
// For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it.
// NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution.
const Vec2 pixelSize = Vec2(2.0f) / renderSize.cast<float>();
const Vec2 offset = pixelSize / 16.0f; // 4 bits precision
// Surround with a roughly centered triangle
const float y1 = 0.5f * offset.y();
const float y2 = 0.35f * offset.y();
const float x1 = 0.5f * offset.x();
DE_ASSERT(compareData.size() == sampleLocations.size());
for (std::size_t globalSampleNdx = 0; globalSampleNdx < sampleLocations.size(); ++globalSampleNdx)
{
const Vec2& loc = sampleLocations[globalSampleNdx];
const CompareData& cd = compareData [globalSampleNdx];
// Overdraw at the same position to get the desired stencil
// Draw at least once, if stencil is 0
for (deUint32 i = 0; i < deMaxu32(1u, cd.stencil); ++i)
{
vertices.push_back(PositionColor(Vec4(loc.x(), loc.y() - y1, cd.depth, 1.0f), cd.color));
vertices.push_back(PositionColor(Vec4(loc.x() - x1, loc.y() + y2, cd.depth, 1.0f), cd.color));
vertices.push_back(PositionColor(Vec4(loc.x() + x1, loc.y() + y2, cd.depth, 1.0f), cd.color));
}
}
return vertices;
}
void reportSampleError (tcu::TestLog& log, const std::string& sampleDesc, UVec2& renderSize, const deUint32 numCoverageSamples, const deUint32 globalSampleNdx)
{
const deUint32 pixelNdx = globalSampleNdx / numCoverageSamples;
const deUint32 x = pixelNdx % renderSize.x();
const deUint32 y = pixelNdx / renderSize.x();
const deUint32 sample = globalSampleNdx % numCoverageSamples;
log << tcu::TestLog::Message << "Incorrect " << sampleDesc << " sample (" << sample << ") at pixel (" << x << ", " << y << ")" << tcu::TestLog::EndMessage;
}
void checkSampleRequirements (Context& context,
const VkSampleCountFlagBits numColorSamples,
const VkSampleCountFlagBits numDepthStencilSamples,
const bool requireStandardSampleLocations)
{
const VkPhysicalDeviceLimits& limits = context.getDeviceProperties().limits;
if ((limits.framebufferColorSampleCounts & numColorSamples) == 0u)
TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported");
if ((limits.framebufferDepthSampleCounts & numDepthStencilSamples) == 0u)
TCU_THROW(NotSupportedError, "framebufferDepthSampleCounts: sample count not supported");
if ((limits.framebufferStencilSampleCounts & numDepthStencilSamples) == 0u)
TCU_THROW(NotSupportedError, "framebufferStencilSampleCounts: sample count not supported");
if ((limits.sampledImageColorSampleCounts & numColorSamples) == 0u)
TCU_THROW(NotSupportedError, "sampledImageColorSampleCounts: sample count not supported");
if ((limits.sampledImageDepthSampleCounts & numDepthStencilSamples) == 0u)
TCU_THROW(NotSupportedError, "sampledImageDepthSampleCounts: sample count not supported");
if ((limits.sampledImageStencilSampleCounts & numDepthStencilSamples) == 0u)
TCU_THROW(NotSupportedError, "sampledImageStencilSampleCounts: sample count not supported");
// This is required to output geometry that is covering a specific sample
if (requireStandardSampleLocations && !limits.standardSampleLocations)
TCU_THROW(NotSupportedError, "standardSampleLocations: not supported");
}
void checkImageRequirements (Context& context,
const VkFormat format,
const VkFormatFeatureFlags requiredFeatureFlags,
const VkImageUsageFlags requiredUsageFlags,
const VkSampleCountFlagBits requiredSampleCount = VK_SAMPLE_COUNT_1_BIT)
{
const InstanceInterface& vki = context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
VkImageFormatProperties imageProperties;
const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, format);
if ((formatProperties.optimalTilingFeatures & requiredFeatureFlags) != requiredFeatureFlags)
TCU_THROW(NotSupportedError, (de::toString(format) + ": format features not supported").c_str());
const VkResult result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, requiredUsageFlags, (VkImageCreateFlags)0, &imageProperties);
if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
TCU_THROW(NotSupportedError, (de::toString(format) + ": format not supported").c_str());
if ((imageProperties.sampleCounts & requiredSampleCount) != requiredSampleCount)
TCU_THROW(NotSupportedError, (de::toString(format) + ": sample count not supported").c_str());
}
//! Used after a render pass color output (draw or resolve)
void recordCopyOutputImageToBuffer (const DeviceInterface& vk,
const VkCommandBuffer cmdBuffer,
const UVec2& imageSize,
const VkImage srcImage,
const VkBuffer dstBuffer)
{
// Image read barrier after color output
{
const VkImageMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout oldLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout;
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
srcImage, // VkImage image;
makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange;
};
vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier);
}
// Resolve image -> host buffer
{
const VkBufferImageCopy region =
{
0ull, // VkDeviceSize bufferOffset;
0u, // uint32_t bufferRowLength;
0u, // uint32_t bufferImageHeight;
makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource;
makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent;
};
vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, &region);
}
// Buffer write barrier
{
const VkBufferMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
dstBuffer, // VkBuffer buffer;
0ull, // VkDeviceSize offset;
VK_WHOLE_SIZE, // VkDeviceSize size;
};
vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0,
0u, DE_NULL, 1u, &barrier, DE_NULL, 0u);
}
}
namespace VerifySamples
{
//! The parameters that define a test case
struct TestParams
{
struct SampleCount
{
VkSampleCountFlagBits numCoverageSamples; //!< VkPipelineMultisampleStateCreateInfo::rasterizationSamples
VkSampleCountFlagBits numColorSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
VkSampleCountFlagBits numDepthStencilSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
};
VkFormat colorFormat; //!< Color attachment format
VkFormat depthStencilFormat; //!< D/S attachment format. Will test both aspects if it's a mixed format
bool useProgrammableSampleLocations; //!< Try to use VK_EXT_sample_locations if available
std::vector<SampleCount> perSubpassSamples; //!< Will use multiple subpasses if more than one element
TestParams (void)
: colorFormat ()
, depthStencilFormat ()
, useProgrammableSampleLocations ()
{
}
};
//! Common data used by the test
struct WorkingData
{
struct PerSubpass
{
deUint32 numVertices; //!< Number of vertices defined in the vertex buffer
Move<VkBuffer> vertexBuffer;
MovePtr<Allocation> vertexBufferAlloc;
Move<VkImage> colorImage; //!< Color image
Move<VkImageView> colorImageView; //!< Color attachment
MovePtr<Allocation> colorImageAlloc;
Move<VkImage> depthStencilImage; //!< Depth stencil image
Move<VkImageView> depthStencilImageView; //!< Depth stencil attachment
Move<VkImageView> depthOnlyImageView; //!< Depth aspect for shader read
Move<VkImageView> stencilOnlyImageView; //!< Stencil aspect for shader read
MovePtr<Allocation> depthStencilImageAlloc;
Move<VkBuffer> compareBuffer; //!< Buffer used to verify the images - comparison data
MovePtr<Allocation> compareBufferAlloc;
VkDeviceSize compareBufferSize;
Move<VkBuffer> resultBuffer; //!< Buffer used to verify the images - results
MovePtr<Allocation> resultBufferAlloc;
VkDeviceSize resultBufferSize;
deUint32 numResultElements; //!< Number of checksums in the result buffer
MovePtr<MultisamplePixelGrid> pixelGrid; //!< Programmable locations
PerSubpass (void)
: numVertices ()
, compareBufferSize ()
, resultBufferSize ()
, numResultElements ()
{
}
};
UVec2 renderSize; //!< Size of the framebuffer
VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties; //!< Used with VK_EXT_sample_locations
std::vector<de::SharedPtr<PerSubpass> > perSubpass; //!< Test may use more than one set of data
WorkingData (void)
: sampleLocationsProperties ()
{
}
};
void addVerificationComputeShader (SourceCollections& programCollection,
const VkSampleCountFlagBits numCoverageSamples,
const VkSampleCountFlagBits numColorSamples,
const VkSampleCountFlagBits numDepthStencilSamples,
const VkFormat depthStencilFormat,
const std::string& nameSuffix)
{
const bool isColorMS = (numColorSamples != VK_SAMPLE_COUNT_1_BIT);
const bool isDepthStencilMS = (numDepthStencilSamples != VK_SAMPLE_COUNT_1_BIT);
const std::string colorBit = de::toString(static_cast<deUint32>(VK_IMAGE_ASPECT_COLOR_BIT)) + "u";
const std::string depthBit = de::toString(static_cast<deUint32>(VK_IMAGE_ASPECT_DEPTH_BIT)) + "u";
const std::string stencilBit = de::toString(static_cast<deUint32>(VK_IMAGE_ASPECT_STENCIL_BIT)) + "u";
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "struct CompareData {\n"
<< " vec4 color;\n"
<< " float depth;\n"
<< " uint stencil;\n"
<< "};\n"
<< "\n"
<< "layout(local_size_x = " << static_cast<deUint32>(numCoverageSamples) << ") in;\n"
// Always use this descriptor layout and ignore unused bindings
<< "layout(set = 0, binding = 0, std430) writeonly buffer Output {\n"
<< " uint values[];\n"
<< "} sb_out;\n"
<< "layout(set = 0, binding = 1, std430) readonly buffer InputCompare {\n"
<< " CompareData data[];\n"
<< "} sb_cmp;\n"
<< "layout(set = 0, binding = 2) uniform sampler2D" << (isColorMS ? "MS" : "") << " colorImage;\n"
<< "layout(set = 0, binding = 3) uniform sampler2D" << (isDepthStencilMS ? "MS" : "") <<" depthImage;\n"
<< "layout(set = 0, binding = 4) uniform usampler2D" << (isDepthStencilMS ? "MS" : "") <<" stencilImage;\n"
<< "\n"
<< "void main (void)\n"
<< "{\n"
// Data for each sample in each pixel is laid out linearly (e.g 2 samples):
// [pixel(0, 0) sample(0)][pixel(0, 0) sample(1)][pixel(1, 0) sample(0)][pixel(1, 0) sample(1)]...
<< " uint globalIndex = gl_LocalInvocationID.x + gl_WorkGroupSize.x * (gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x);\n"
<< " ivec2 position = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n"
<< " int sampleNdx = int(gl_LocalInvocationID.x);\n"
<< " uint result = 0u;\n"
<< "\n"
<< " // Verify color samples\n"
<< " if (sampleNdx < " << static_cast<deUint32>(numColorSamples) << ")\n"
<< " {\n"
<< " vec4 color = texelFetch(colorImage, position, sampleNdx);\n" // for non-MS (1 sample) case, sampleNdx = 0 and will instead be LOD = 0
<< " vec4 diff = abs(color - sb_cmp.data[globalIndex].color);\n"
<< " vec4 threshold = vec4(0.02);\n"
<< "\n"
<< " if (all(lessThan(diff, threshold)))\n"
<< " result |= " << colorBit << ";\n"
<< " }\n"
<< " else\n"
<< " result |= " << colorBit << ";\n" // Pass, if sample doesn't exist
<< "\n";
if (isDepthFormat(depthStencilFormat))
{
src << " // Verify depth samples\n"
<< " if (sampleNdx < " << static_cast<deUint32>(numDepthStencilSamples) << ")\n"
<< " {\n"
<< " float depth = texelFetch(depthImage, position, sampleNdx).r;\n"
<< " float diff = abs(depth - sb_cmp.data[globalIndex].depth);\n"
<< " float threshold = 0.002;\n"
<< "\n"
<< " if (diff < threshold)\n"
<< " result |= " << depthBit << ";\n"
<< " }\n"
<< " else\n"
<< " result |= " << depthBit << ";\n"
<< "\n";
}
if (isStencilFormat(depthStencilFormat))
{
src << " // Verify stencil samples\n"
<< " if (sampleNdx < " << static_cast<deUint32>(numDepthStencilSamples) << ")\n"
<< " {\n"
<< " uint stencil = texelFetch(stencilImage, position, sampleNdx).r;\n"
<< " uint diff = stencil - sb_cmp.data[globalIndex].stencil;\n"
<< "\n"
<< " if (diff == 0u)\n"
<< " result |= " << stencilBit << ";\n"
<< " }\n"
<< " else\n"
<< " result |= " << stencilBit << ";\n"
<< "\n";
}
src << " sb_out.values[globalIndex] = result;\n"
<< "}\n";
programCollection.glslSources.add("comp" + nameSuffix) << glu::ComputeSource(src.str());
}
//! Get a compact sample count string in format X_Y_Z
std::string getSampleCountString (const TestParams::SampleCount& samples)
{
std::ostringstream str;
str << static_cast<deUint32>(samples.numCoverageSamples) << "_"
<< static_cast<deUint32>(samples.numColorSamples) << "_"
<< static_cast<deUint32>(samples.numDepthStencilSamples);
return str.str();
}
void initPrograms (SourceCollections& programCollection, const TestParams params)
{
// Vertex shader - position and color
{
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(location = 0) in vec4 in_position;\n"
<< "layout(location = 1) in vec4 in_color;\n"
<< "layout(location = 0) out vec4 o_color;\n"
<< "\n"
<< "out gl_PerVertex {\n"
<< " vec4 gl_Position;\n"
<< "};\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
<< " gl_Position = in_position;\n"
<< " o_color = in_color;\n"
<< "}\n";
programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
}
// Fragment shader - output color from VS
{
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(location = 0) in vec4 in_color;\n"
<< "layout(location = 0) out vec4 o_color;\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
<< " o_color = in_color;\n"
<< "}\n";
programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
}
// Compute shader - image verification
for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
{
const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
addVerificationComputeShader(programCollection,
samples.numCoverageSamples,
samples.numColorSamples,
samples.numDepthStencilSamples,
params.depthStencilFormat,
"_" + getSampleCountString(samples));
}
}
//! A simple color, depth/stencil draw. Subpasses (if more than one) are independent
void draw (Context& context, const TestParams& params, WorkingData& wd)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
const deUint32 numSubpasses = static_cast<deUint32>(wd.perSubpass.size());
Move<VkRenderPass> renderPass;
Move<VkFramebuffer> framebuffer;
std::vector<VkSampleLocationsInfoEXT> perSubpassSampleLocationsInfo;
std::vector<VkAttachmentSampleLocationsEXT> attachmentSampleLocations;
std::vector<VkSubpassSampleLocationsEXT> subpassSampleLocations;
if (params.useProgrammableSampleLocations)
for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
{
perSubpassSampleLocationsInfo.push_back(makeSampleLocationsInfo(*wd.perSubpass[subpassNdx]->pixelGrid));
}
// Create a render pass and a framebuffer
{
std::vector<VkSubpassDescription> subpasses;
std::vector<VkImageView> attachments;
std::vector<VkAttachmentDescription> attachmentDescriptions;
std::vector<VkAttachmentReference> attachmentReferences;
// Reserve capacity to avoid invalidating pointers to elements
attachmentReferences.reserve(numSubpasses * 2);
for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
{
attachments.push_back(wd.perSubpass[subpassNdx]->colorImageView.get());
attachments.push_back(wd.perSubpass[subpassNdx]->depthStencilImageView.get());
attachmentDescriptions.push_back(makeAttachmentDescription(
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
params.colorFormat, // VkFormat format;
params.perSubpassSamples[subpassNdx].numColorSamples, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
));
attachmentDescriptions.push_back(makeAttachmentDescription(
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
params.depthStencilFormat, // VkFormat format;
params.perSubpassSamples[subpassNdx].numDepthStencilSamples, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL // VkImageLayout finalLayout;
));
attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
const VkAttachmentReference* colorRef = &attachmentReferences.back();
attachmentReferences.push_back(makeAttachmentReference(static_cast<deUint32>(attachmentReferences.size()), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
const VkAttachmentReference* depthStencilRef = &attachmentReferences.back();
if (params.useProgrammableSampleLocations)
{
const VkAttachmentSampleLocationsEXT newAttachmentSampleLocations =
{
attachmentReferences.back().attachment, // uint32_t attachmentIndex;
perSubpassSampleLocationsInfo[subpassNdx], // VkSampleLocationsInfoEXT sampleLocationsInfo;
};
attachmentSampleLocations.push_back(newAttachmentSampleLocations);
const VkSubpassSampleLocationsEXT newSubpassSampleLocations =
{
subpassNdx, // uint32_t subpassIndex;
perSubpassSampleLocationsInfo[subpassNdx], // VkSampleLocationsInfoEXT sampleLocationsInfo;
};
subpassSampleLocations.push_back(newSubpassSampleLocations);
}
const VkSubpassDescription subpassDescription =
{
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // uint32_t inputAttachmentCount;
DE_NULL, // const VkAttachmentReference* pInputAttachments;
1u, // uint32_t colorAttachmentCount;
colorRef, // const VkAttachmentReference* pColorAttachments;
DE_NULL, // const VkAttachmentReference* pResolveAttachments;
depthStencilRef, // const VkAttachmentReference* pDepthStencilAttachment;
0u, // uint32_t preserveAttachmentCount;
DE_NULL, // const uint32_t* pPreserveAttachments;
};
subpasses.push_back(subpassDescription);
}
// Assume there are no dependencies between subpasses
const VkRenderPassCreateInfo renderPassInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
static_cast<deUint32>(subpasses.size()), // deUint32 subpassCount;
dataOrNullPtr(subpasses), // const VkSubpassDescription* pSubpasses;
0u, // deUint32 dependencyCount;
DE_NULL, // const VkSubpassDependency* pDependencies;
};
renderPass = createRenderPass(vk, device, &renderPassInfo);
framebuffer = makeFramebuffer (vk, device, *renderPass, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), wd.renderSize.x(), wd.renderSize.y());
}
const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u));
const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u));
const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
typedef SharedPtr<Unique<VkPipeline> > PipelineSp;
std::vector<PipelineSp> pipelines;
for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
{
const VkSampleLocationsInfoEXT* pSampleLocationsInfo = (params.useProgrammableSampleLocations ? &perSubpassSampleLocationsInfo[subpassNdx] : DE_NULL);
pipelines.push_back(PipelineSp(new Unique<VkPipeline>(
makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, /*use vertex input*/ true, subpassNdx,
wd.renderSize, getImageAspectFlags(params.depthStencilFormat), params.perSubpassSamples[subpassNdx].numCoverageSamples,
/*use sample shading*/ true, pSampleLocationsInfo))));
}
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
beginCommandBuffer(vk, *cmdBuffer);
{
std::vector<VkClearValue> clearValues;
for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
{
clearValues.push_back(makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f));
clearValues.push_back(makeClearValueDepthStencil(1.0f, 0u));
}
const VkRect2D renderArea =
{
{ 0u, 0u },
{ wd.renderSize.x(), wd.renderSize.y() }
};
VkRenderPassBeginInfo renderPassBeginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*renderPass, // VkRenderPass renderPass;
*framebuffer, // VkFramebuffer framebuffer;
renderArea, // VkRect2D renderArea;
static_cast<deUint32>(clearValues.size()), // uint32_t clearValueCount;
dataOrNullPtr(clearValues), // const VkClearValue* pClearValues;
};
if (params.useProgrammableSampleLocations)
{
const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, // VkStructureType sType;
DE_NULL, // const void* pNext;
static_cast<deUint32>(attachmentSampleLocations.size()), // uint32_t attachmentInitialSampleLocationsCount;
dataOrNullPtr(attachmentSampleLocations), // const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations;
static_cast<deUint32>(subpassSampleLocations.size()), // uint32_t postSubpassSampleLocationsCount;
dataOrNullPtr(subpassSampleLocations), // const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations;
};
renderPassBeginInfo.pNext = &renderPassSampleLocationsBeginInfo;
vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
else
vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx)
{
if (subpassNdx != 0)
vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
const VkDeviceSize vertexBufferOffset = 0ull;
vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.perSubpass[subpassNdx]->vertexBuffer.get(), &vertexBufferOffset);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]);
vk.cmdDraw(*cmdBuffer, wd.perSubpass[subpassNdx]->numVertices, 1u, 0u, 0u);
}
vk.cmdEndRenderPass(*cmdBuffer);
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer);
}
void dispatchImageCheck (Context& context, const TestParams& params, WorkingData& wd, const deUint32 subpassNdx)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
WorkingData::PerSubpass& subpassData = *wd.perSubpass[subpassNdx];
const Unique<VkSampler> defaultSampler (makeSampler(vk, device));
// Create descriptor set
const Unique<VkDescriptorSetLayout> descriptorSetLayout(
DescriptorSetLayoutBuilder()
.addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
.addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get())
.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get())
.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get())
.build(vk, device));
const Unique<VkDescriptorPool> descriptorPool(
DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3u)
.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
{
const VkDescriptorBufferInfo compareBufferInfo = makeDescriptorBufferInfo(*subpassData.compareBuffer, 0ull, subpassData.compareBufferSize);
const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(*subpassData.resultBuffer, 0ull, subpassData.resultBufferSize);
const VkDescriptorImageInfo colorImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
const VkDescriptorImageInfo depthImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.depthOnlyImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
const VkDescriptorImageInfo stencilImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.stencilOnlyImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
DescriptorSetUpdateBuilder builder;
builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo);
builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &compareBufferInfo);
builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo);
if (subpassData.depthOnlyImageView)
builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(3u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &depthImageInfo);
if (subpassData.stencilOnlyImageView)
builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(4u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &stencilImageInfo);
builder.update(vk, device);
}
// Pipeline
const std::string shaderName ("comp_" + getSampleCountString(params.perSubpassSamples[subpassNdx]));
const Unique<VkShaderModule> shaderModule (createShaderModule(vk, device, context.getBinaryCollection().get(shaderName), 0u));
const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, DE_NULL));
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
beginCommandBuffer(vk, *cmdBuffer);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
vk.cmdDispatch(*cmdBuffer, wd.renderSize.x(), wd.renderSize.y(), 1u);
{
const VkBufferMemoryBarrier barrier =
{
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
DE_NULL, // const void* pNext;
VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask;
VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
*subpassData.resultBuffer, // VkBuffer buffer;
0ull, // VkDeviceSize offset;
VK_WHOLE_SIZE, // VkDeviceSize size;
};
vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0,
(const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
}
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer);
invalidateMappedMemoryRange(vk, device, subpassData.resultBufferAlloc->getMemory(), subpassData.resultBufferAlloc->getOffset(), VK_WHOLE_SIZE);
}
void createPerSubpassData (Context& context, const TestParams& params, WorkingData& wd, const deUint32 subpassNdx)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
MovePtr<Allocator> allocator = MovePtr<Allocator>(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())));
const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
WorkingData::PerSubpass& subpassData = *wd.perSubpass[subpassNdx];
// Create images
{
const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
checkImageRequirements (context,
params.colorFormat,
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,
colorImageUsageFlags,
samples.numColorSamples);
subpassData.colorImage = makeImage(vk, device, params.colorFormat, wd.renderSize, samples.numColorSamples, colorImageUsageFlags);
subpassData.colorImageAlloc = bindImage(vk, device, *allocator, *subpassData.colorImage, MemoryRequirement::Any);
subpassData.colorImageView = makeImageView(vk, device, *subpassData.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
checkImageRequirements (context,
params.depthStencilFormat,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,
depthStencilImageUsageFlags,
samples.numDepthStencilSamples);
subpassData.depthStencilImage = makeImage(vk, device, params.depthStencilFormat, wd.renderSize, samples.numDepthStencilSamples, depthStencilImageUsageFlags);
subpassData.depthStencilImageAlloc = bindImage(vk, device, *allocator, *subpassData.depthStencilImage, MemoryRequirement::Any);
subpassData.depthStencilImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(getImageAspectFlags(params.depthStencilFormat), 0u, 1u, 0u, 1u));
if (isDepthFormat(params.depthStencilFormat))
subpassData.depthOnlyImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u));
if (isStencilFormat(params.depthStencilFormat))
subpassData.stencilOnlyImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u));
}
// Create vertex and comparison buffers
{
const deUint32 seed = 123 + 19 * subpassNdx;
const std::vector<CompareData> compareData = generateCompareData(seed, wd.renderSize, samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples);
subpassData.compareBufferSize = static_cast<VkDeviceSize>(sizeof(CompareData) * compareData.size());
subpassData.compareBuffer = makeBuffer(vk, device, subpassData.compareBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
subpassData.compareBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.compareBuffer, MemoryRequirement::HostVisible);
deMemcpy(subpassData.compareBufferAlloc->getHostPtr(), dataOrNullPtr(compareData), static_cast<std::size_t>(subpassData.compareBufferSize));
flushMappedMemoryRange(vk, device, subpassData.compareBufferAlloc->getMemory(), subpassData.compareBufferAlloc->getOffset(), VK_WHOLE_SIZE);
subpassData.numResultElements = static_cast<deUint32>(compareData.size());
subpassData.resultBufferSize = static_cast<VkDeviceSize>(sizeof(deUint32) * compareData.size());
subpassData.resultBuffer = makeBuffer(vk, device, subpassData.resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
subpassData.resultBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.resultBuffer, MemoryRequirement::HostVisible);
deMemset(subpassData.resultBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(subpassData.resultBufferSize));
flushMappedMemoryRange(vk, device, subpassData.resultBufferAlloc->getMemory(), subpassData.resultBufferAlloc->getOffset(), VK_WHOLE_SIZE);
std::vector<PositionColor> vertices;
if (params.useProgrammableSampleLocations)
{
subpassData.pixelGrid = MovePtr<MultisamplePixelGrid>(new MultisamplePixelGrid(UVec2(wd.sampleLocationsProperties.maxSampleLocationGridSize.width,
wd.sampleLocationsProperties.maxSampleLocationGridSize.height),
samples.numCoverageSamples));
const deUint32 locationsSeed = 211 + 4 * subpassNdx;
fillSampleLocationsRandom(*subpassData.pixelGrid, wd.sampleLocationsProperties.sampleLocationSubPixelBits, locationsSeed);
vertices = generateSubpixelTriangles(wd.renderSize, compareData, getSampleLocations(*subpassData.pixelGrid, wd.renderSize));
}
else
{
const std::vector<Vec2> locations = genFramebufferStandardSampleLocations(samples.numCoverageSamples, wd.renderSize);
vertices = generateSubpixelTriangles(wd.renderSize, compareData, locations);
}
const VkDeviceSize vertexBufferSize = static_cast<VkDeviceSize>(sizeof(vertices[0]) * vertices.size());
subpassData.numVertices = static_cast<deUint32>(vertices.size());
subpassData.vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
subpassData.vertexBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.vertexBuffer, MemoryRequirement::HostVisible);
deMemcpy(subpassData.vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast<std::size_t>(vertexBufferSize));
flushMappedMemoryRange(vk, device, subpassData.vertexBufferAlloc->getMemory(), subpassData.vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
}
}
void checkRequirements (Context& context, TestParams params)
{
context.requireDeviceFunctionality("VK_AMD_mixed_attachment_samples");
if (params.useProgrammableSampleLocations)
context.requireDeviceFunctionality("VK_EXT_sample_locations");
for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
{
const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
checkSampleRequirements(context, samples.numColorSamples, samples.numDepthStencilSamples, !params.useProgrammableSampleLocations);
}
}
//! Verify the values of all samples in all attachments.
tcu::TestStatus test (Context& context, const TestParams params)
{
WorkingData wd;
wd.renderSize = UVec2(2, 2); // Use a very small image, as we will verify all samples for all pixels
// Query state related to programmable sample locations
if (params.useProgrammableSampleLocations)
{
const InstanceInterface& vki = context.getInstanceInterface();
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
wd.sampleLocationsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
wd.sampleLocationsProperties.pNext = DE_NULL;
VkPhysicalDeviceProperties2 properties =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, // VkStructureType sType;
&wd.sampleLocationsProperties, // void* pNext;
VkPhysicalDeviceProperties(), // VkPhysicalDeviceProperties properties;
};
vki.getPhysicalDeviceProperties2(physicalDevice, &properties);
for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
{
if ((wd.sampleLocationsProperties.sampleLocationSampleCounts & params.perSubpassSamples[subpassNdx].numCoverageSamples) == 0u)
TCU_THROW(NotSupportedError, "VkSampleLocationsPropertiesAMD: sample count not supported");
}
}
// Create subpass data
for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
{
wd.perSubpass.push_back(SharedPtr<WorkingData::PerSubpass>(new WorkingData::PerSubpass()));
createPerSubpassData(context, params, wd, subpassNdx);
}
// Draw test geometry
draw (context, params, wd);
// Verify images with a compute shader
for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
dispatchImageCheck (context, params, wd, subpassNdx);
// Test checksums
for (deUint32 subpassNdx = 0; subpassNdx < static_cast<deUint32>(params.perSubpassSamples.size()); ++subpassNdx)
{
const deUint32* const pSampleChecksumBase = static_cast<deUint32*>(wd.perSubpass[subpassNdx]->resultBufferAlloc->getHostPtr());
const bool hasDepth = isDepthFormat(params.depthStencilFormat);
const bool hasStencil = isStencilFormat(params.depthStencilFormat);
bool allOk = true;
context.getTestContext().getLog() << tcu::TestLog::Message << "Verify images in subpass " << subpassNdx << tcu::TestLog::EndMessage;
for (deUint32 globalSampleNdx = 0; globalSampleNdx < wd.perSubpass[subpassNdx]->numResultElements; ++globalSampleNdx)
{
const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx];
const deUint32 checksum = pSampleChecksumBase[globalSampleNdx];
if ((checksum & VK_IMAGE_ASPECT_COLOR_BIT) == 0u)
{
reportSampleError(context.getTestContext().getLog(), "color", wd.renderSize, samples.numCoverageSamples, globalSampleNdx);
allOk = false;
}
if (hasDepth && ((checksum & VK_IMAGE_ASPECT_DEPTH_BIT) == 0u))
{
reportSampleError(context.getTestContext().getLog(), "depth", wd.renderSize, samples.numCoverageSamples, globalSampleNdx);
allOk = false;
}
if (hasStencil && ((checksum & VK_IMAGE_ASPECT_STENCIL_BIT) == 0u))
{
reportSampleError(context.getTestContext().getLog(), "stencil", wd.renderSize, samples.numCoverageSamples, globalSampleNdx);
allOk = false;
}
}
if (!allOk)
return tcu::TestStatus::fail("Multisampled image has incorrect samples");
}
return tcu::TestStatus::pass("Pass");
}
} // VerifySamples
namespace ShaderBuiltins
{
struct TestParams
{
VkSampleCountFlagBits numCoverageSamples; //!< VkPipelineMultisampleStateCreateInfo::rasterizationSamples
VkSampleCountFlagBits numColorSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
VkSampleCountFlagBits numDepthStencilSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples
VkFormat colorFormat; //!< Color attachment format
VkFormat depthStencilFormat; //!< D/S attachment format. Will test both aspects if it's a mixed format
};
struct WorkingData
{
UVec2 renderSize; //!< Size of the framebuffer
deUint32 numVertices; //!< Number of vertices defined in the vertex buffer
Move<VkBuffer> vertexBuffer;
MovePtr<Allocation> vertexBufferAlloc;
Move<VkImage> colorImage; //!< Color image
Move<VkImageView> colorImageView; //!< Color attachment
MovePtr<Allocation> colorImageAlloc;
Move<VkImage> depthStencilImage; //!< Depth stencil image
Move<VkImageView> depthStencilImageView; //!< Depth stencil attachment
Move<VkImageView> depthOnlyImageView; //!< Depth aspect for shader read
Move<VkImageView> stencilOnlyImageView; //!< Stencil aspect for shader read
MovePtr<Allocation> depthStencilImageAlloc;
Move<VkImage> resolveImage; //!< Resolve image
Move<VkImageView> resolveImageView; //!< Resolve attachment
MovePtr<Allocation> resolveImageAlloc;
Move<VkBuffer> colorBuffer; //!< Buffer used to copy resolve output
MovePtr<Allocation> colorBufferAlloc;
VkDeviceSize colorBufferSize;
WorkingData (void)
: numVertices ()
, colorBufferSize (0)
{
}
};
void initPrograms (SourceCollections& programCollection, const TestParams params)
{
// Vertex shader - no vertex data
{
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "out gl_PerVertex {\n"
<< " vec4 gl_Position;\n"
<< "};\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
// Specify an oversized triangle covering the whole viewport.
<< " switch (gl_VertexIndex)\n"
<< " {\n"
<< " case 0:\n"
<< " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
<< " break;\n"
<< " case 1:\n"
<< " gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n"
<< " break;\n"
<< " case 2:\n"
<< " gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n"
<< " break;\n"
<< " }\n"
<< "}\n";
programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
}
// Fragment shader
{
std::ostringstream src;
src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
<< "\n"
<< "layout(location = 0) out vec4 o_color;\n"
<< "\n"
<< "void main(void)\n"
<< "{\n"
<< " vec4 col = vec4(0.0, 0.0, 0.0, 1.0);\n"
<< "\n";
if (params.numColorSamples == VK_SAMPLE_COUNT_1_BIT)
{
const deUint32 expectedMask = ((1u << static_cast<deUint32>(params.numCoverageSamples)) - 1u);
// Expect all covered samples to be lit, the rest is zero
src << " if (gl_SampleMaskIn[0] == " << expectedMask << ")\n"
<< " col.g = 1.0;\n"
<< " else\n"
<< " col.r = 1.0;\n";
}
else
{
// Expect only a matching sample to be lit
src << " if (gl_SampleMaskIn[0] == (1 << gl_SampleID))\n"
<< " col.g = 1.0;\n"
<< " else\n"
<< " col.r = 1.0;\n"
<< "\n"
<< " if (gl_SampleID >= " << static_cast<deUint32>(params.numColorSamples) << ") // number of color samples, should not happen\n"
<< " col.b = 1.0;\n";
}
src << "\n"
<< " o_color = col;\n"
<< "}\n";
programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
}
}
//! A simple color, depth/stencil draw. Single subpass, no vertex input
void drawResolve (Context& context, const TestParams& params, WorkingData& wd)
{
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
const bool needResolve = (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT);
Move<VkRenderPass> renderPass;
Move<VkFramebuffer> framebuffer;
// Create a render pass and a framebuffer
{
std::vector<VkImageView> attachments;
std::vector<VkAttachmentDescription> attachmentDescriptions;
attachments.push_back(*wd.colorImageView);
attachments.push_back(*wd.depthStencilImageView);
attachmentDescriptions.push_back(makeAttachmentDescription(
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
params.colorFormat, // VkFormat format;
params.numColorSamples, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout;
));
attachmentDescriptions.push_back(makeAttachmentDescription(
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
params.depthStencilFormat, // VkFormat format;
params.numDepthStencilSamples, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
));
if (needResolve)
{
attachments.push_back(*wd.resolveImageView);
attachmentDescriptions.push_back(makeAttachmentDescription(
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
params.colorFormat, // VkFormat format;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp;
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout;
));
}
const VkAttachmentReference colorRef = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
const VkAttachmentReference depthStencilRef = makeAttachmentReference(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
const VkAttachmentReference resolveRef = makeAttachmentReference(2u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
const VkSubpassDescription subpassDescription =
{
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // uint32_t inputAttachmentCount;
DE_NULL, // const VkAttachmentReference* pInputAttachments;
1u, // uint32_t colorAttachmentCount;
&colorRef, // const VkAttachmentReference* pColorAttachments;
(needResolve ? &resolveRef : DE_NULL), // const VkAttachmentReference* pResolveAttachments;
&depthStencilRef, // const VkAttachmentReference* pDepthStencilAttachment;
0u, // uint32_t preserveAttachmentCount;
DE_NULL, // const uint32_t* pPreserveAttachments;
};
// Assume there are no dependencies between subpasses
VkRenderPassCreateInfo renderPassInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments;
1u, // deUint32 subpassCount;
&subpassDescription, // const VkSubpassDescription* pSubpasses;
0u, // deUint32 dependencyCount;
DE_NULL, // const VkSubpassDependency* pDependencies;
};
renderPass = createRenderPass(vk, device, &renderPassInfo);
framebuffer = makeFramebuffer (vk, device, *renderPass, static_cast<deUint32>(attachments.size()), dataOrNullPtr(attachments), wd.renderSize.x(), wd.renderSize.y());
}
const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u));
const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u));
const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device));
const bool useVertexInput = false;
const bool sampleShading = (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT);
const deUint32 subpassNdx = 0u;
const Unique<VkPipeline> pipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, useVertexInput, subpassNdx,
wd.renderSize, getImageAspectFlags(params.depthStencilFormat), params.numCoverageSamples, sampleShading));
const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex()));
const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(vk, device, *cmdPool));
beginCommandBuffer(vk, *cmdBuffer);
{
std::vector<VkClearValue> clearValues;
clearValues.push_back(makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f));
clearValues.push_back(makeClearValueDepthStencil(1.0f, 0u));
const VkRect2D renderArea =
{
{ 0u, 0u },
{ wd.renderSize.x(), wd.renderSize.y() }
};
const VkRenderPassBeginInfo renderPassBeginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*renderPass, // VkRenderPass renderPass;
*framebuffer, // VkFramebuffer framebuffer;
renderArea, // VkRect2D renderArea;
static_cast<deUint32>(clearValues.size()), // uint32_t clearValueCount;
dataOrNullPtr(clearValues), // const VkClearValue* pClearValues;
};
vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
}
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u);
vk.cmdEndRenderPass(*cmdBuffer);
if (needResolve)
recordCopyOutputImageToBuffer(vk, *cmdBuffer, wd.renderSize, *wd.resolveImage, *wd.colorBuffer);
else
recordCopyOutputImageToBuffer(vk, *cmdBuffer, wd.renderSize, *wd.colorImage, *wd.colorBuffer);
VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer);
}
void checkRequirements (Context& context, TestParams params)
{
context.requireDeviceFunctionality("VK_AMD_mixed_attachment_samples");
checkSampleRequirements(context, params.numColorSamples, params.numDepthStencilSamples, false /* require standard sample locations */);
}
//! Verify the values of shader builtins
tcu::TestStatus test (Context& context, const TestParams params)
{
WorkingData wd;
const DeviceInterface& vk = context.getDeviceInterface();
const VkDevice device = context.getDevice();
MovePtr<Allocator> allocator = MovePtr<Allocator>(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())));
wd.renderSize = UVec2(16, 16);
// Create images and a color buffer
{
const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
checkImageRequirements (context,
params.colorFormat,
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
colorImageUsageFlags,
params.numColorSamples);
wd.colorImage = makeImage(vk, device, params.colorFormat, wd.renderSize, params.numColorSamples, colorImageUsageFlags);
wd.colorImageAlloc = bindImage(vk, device, *allocator, *wd.colorImage, MemoryRequirement::Any);
wd.colorImageView = makeImageView(vk, device, *wd.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
if (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT)
{
wd.resolveImage = makeImage(vk, device, params.colorFormat, wd.renderSize, VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags);
wd.resolveImageAlloc = bindImage(vk, device, *allocator, *wd.resolveImage, MemoryRequirement::Any);
wd.resolveImageView = makeImageView(vk, device, *wd.resolveImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
}
// Resolve result
wd.colorBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(mapVkFormat(params.colorFormat)) * wd.renderSize.x() * wd.renderSize.y());
wd.colorBuffer = makeBuffer(vk, device, wd.colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
wd.colorBufferAlloc = bindBuffer(vk, device, *allocator, *wd.colorBuffer, MemoryRequirement::HostVisible);
deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast<std::size_t>(wd.colorBufferSize));
flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE);
checkImageRequirements (context,
params.depthStencilFormat,
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
depthStencilImageUsageFlags,
params.numDepthStencilSamples);
wd.depthStencilImage = makeImage(vk, device, params.depthStencilFormat, wd.renderSize, params.numDepthStencilSamples, depthStencilImageUsageFlags);
wd.depthStencilImageAlloc = bindImage(vk, device, *allocator, *wd.depthStencilImage, MemoryRequirement::Any);
wd.depthStencilImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(getImageAspectFlags(params.depthStencilFormat), 0u, 1u, 0u, 1u));
if (isDepthFormat(params.depthStencilFormat))
wd.depthOnlyImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u));
if (isStencilFormat(params.depthStencilFormat))
wd.stencilOnlyImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u));
}
// Draw, resolve, and copy to color buffer (see the fragment shader for details)
drawResolve(context, params, wd);
// Verify resolved image
{
const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(params.colorFormat), tcu::IVec3(wd.renderSize.x(), wd.renderSize.y(), 1),wd.colorBufferAlloc->getHostPtr()));
if (compareGreenImage(context.getTestContext().getLog(), "resolve0", "Resolved test image", image))
return tcu::TestStatus::pass("Pass");
else
return tcu::TestStatus::fail("Some samples were incorrect");
}
}
} // ShaderBuiltins
std::string getSampleCountGroupName(const VkSampleCountFlagBits coverageCount,
const VkSampleCountFlagBits colorCount,
const VkSampleCountFlagBits depthStencilCount)
{
std::ostringstream str;
str << "coverage_" << static_cast<deUint32>(coverageCount)
<< "_color_" << static_cast<deUint32>(colorCount)
<< "_depth_stencil_" << static_cast<deUint32>(depthStencilCount);
return str.str();
}
std::string getFormatShortString (const VkFormat format)
{
std::string s(de::toLower(getFormatName(format)));
return s.substr(10);
}
std::string getFormatCaseName (const VkFormat colorFormat,
const VkFormat depthStencilFormat)
{
std::ostringstream str;
str << getFormatShortString(colorFormat) << "_" << getFormatShortString(depthStencilFormat);
return str.str();
}
void createMixedAttachmentSamplesTestsInGroup (tcu::TestCaseGroup* rootGroup)
{
const VkFormat colorFormatRange[] =
{
VK_FORMAT_R8G8B8A8_UNORM,
// If you add more, make sure it is handled in the test/shader
};
const VkFormat depthStencilFormatRange[] =
{
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,
};
// Minimal set of formats to cover depth and stencil
const VkFormat depthStencilReducedFormatRange[] =
{
VK_FORMAT_D16_UNORM, //!< Must be supported
VK_FORMAT_D24_UNORM_S8_UINT, //!< Either this, or the next one must be supported
VK_FORMAT_D32_SFLOAT_S8_UINT,
};
struct SampleCase
{
VkSampleCountFlagBits colorSamples;
VkSampleCountFlagBits depthStencilSamples;
};
// Currently supported EQAA cases
static const SampleCase singlePassCases[] =
{
// Less color than depth/stencil
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_16_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_16_BIT },
{ VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_16_BIT },
{ VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT },
};
// Multi-subpass cases
static const SampleCase caseSubpassIncreaseColor_1[] =
{
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
};
static const SampleCase caseSubpassIncreaseColor_2[] =
{
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
};
static const SampleCase caseSubpassDecreaseColor_1[] =
{
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT },
};
static const SampleCase caseSubpassDecreaseColor_2[] =
{
{ VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT },
};
static const SampleCase caseSubpassIncreaseCoverage_1[] =
{
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
};
static const SampleCase caseSubpassIncreaseCoverage_2[] =
{
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
};
static const SampleCase caseSubpassDecreaseCoverage_1[] =
{
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
};
static const SampleCase caseSubpassDecreaseCoverage_2[] =
{
{ VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT },
{ VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT },
{ VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT },
};
static const struct
{
const char* const caseName;
const deUint32 numSampleCases;
const SampleCase* pSampleCase;
} subpassCases[] =
{
{ "multi_subpass_decrease_color_4", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseColor_1), caseSubpassDecreaseColor_1 },
{ "multi_subpass_decrease_color_8", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseColor_2), caseSubpassDecreaseColor_2 },
{ "multi_subpass_decrease_coverage_4", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseCoverage_1), caseSubpassDecreaseCoverage_1 },
{ "multi_subpass_decrease_coverage_8", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseCoverage_2), caseSubpassDecreaseCoverage_2 },
{ "multi_subpass_increase_color_4", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseColor_1), caseSubpassIncreaseColor_1 },
{ "multi_subpass_increase_color_8", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseColor_2), caseSubpassIncreaseColor_2 },
{ "multi_subpass_increase_coverage_4", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseCoverage_1), caseSubpassIncreaseCoverage_1 },
{ "multi_subpass_increase_coverage_8", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseCoverage_2), caseSubpassIncreaseCoverage_2 },
};
// Test 1: Per-sample expected value check
{
MovePtr<tcu::TestCaseGroup> standardLocationsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_standard_locations", ""));
MovePtr<tcu::TestCaseGroup> programmableLocationsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_programmable_locations", ""));
tcu::TestCaseGroup* locationsGroups[2] =
{
standardLocationsGroup.get(),
programmableLocationsGroup.get()
};
for (deUint32 groupNdx = 0u; groupNdx < DE_LENGTH_OF_ARRAY(locationsGroups); ++groupNdx)
{
// Single subpass cases
for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(singlePassCases); ++caseNdx)
{
VerifySamples::TestParams::SampleCount samples;
samples.numColorSamples = singlePassCases[caseNdx].colorSamples;
samples.numDepthStencilSamples = singlePassCases[caseNdx].depthStencilSamples;
samples.numCoverageSamples = de::max(samples.numColorSamples, samples.numDepthStencilSamples);
VerifySamples::TestParams params;
params.perSubpassSamples.push_back(samples);
params.useProgrammableSampleLocations = (locationsGroups[groupNdx] == programmableLocationsGroup.get());
MovePtr<tcu::TestCaseGroup> sampleCaseGroup(new tcu::TestCaseGroup(
rootGroup->getTestContext(), getSampleCountGroupName(samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples).c_str(), ""));
for (const VkFormat *pDepthStencilFormat = depthStencilFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilFormatRange); ++pDepthStencilFormat)
for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat)
{
params.colorFormat = *pColorFormat;
params.depthStencilFormat = *pDepthStencilFormat;
addFunctionCaseWithPrograms(
sampleCaseGroup.get(),
getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(),
"",
VerifySamples::checkRequirements,
VerifySamples::initPrograms,
VerifySamples::test, params);
}
locationsGroups[groupNdx]->addChild(sampleCaseGroup.release());
}
// Multi subpass cases
for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(subpassCases); ++caseNdx)
{
VerifySamples::TestParams params;
params.useProgrammableSampleLocations = (locationsGroups[groupNdx] == programmableLocationsGroup.get());
for (deUint32 subpassNdx = 0; subpassNdx < subpassCases[caseNdx].numSampleCases; ++subpassNdx)
{
VerifySamples::TestParams::SampleCount samples;
samples.numColorSamples = subpassCases[caseNdx].pSampleCase[subpassNdx].colorSamples;
samples.numDepthStencilSamples = subpassCases[caseNdx].pSampleCase[subpassNdx].depthStencilSamples;
samples.numCoverageSamples = de::max(samples.numColorSamples, samples.numDepthStencilSamples);
params.perSubpassSamples.push_back(samples);
}
MovePtr<tcu::TestCaseGroup> sampleCaseGroup(new tcu::TestCaseGroup(rootGroup->getTestContext(), subpassCases[caseNdx].caseName, ""));
for (const VkFormat *pDepthStencilFormat = depthStencilReducedFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilReducedFormatRange); ++pDepthStencilFormat)
for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat)
{
params.colorFormat = *pColorFormat;
params.depthStencilFormat = *pDepthStencilFormat;
addFunctionCaseWithPrograms(
sampleCaseGroup.get(),
getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(),
"",
VerifySamples::checkRequirements,
VerifySamples::initPrograms,
VerifySamples::test, params);
}
locationsGroups[groupNdx]->addChild(sampleCaseGroup.release());
}
}
rootGroup->addChild(standardLocationsGroup.release());
rootGroup->addChild(programmableLocationsGroup.release());
}
// Test 2: Shader built-ins check
{
MovePtr<tcu::TestCaseGroup> builtinsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "shader_builtins", ""));
for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(singlePassCases); ++caseNdx)
{
ShaderBuiltins::TestParams params;
params.numColorSamples = singlePassCases[caseNdx].colorSamples;
params.numDepthStencilSamples = singlePassCases[caseNdx].depthStencilSamples;
params.numCoverageSamples = de::max(params.numColorSamples, params.numDepthStencilSamples);
MovePtr<tcu::TestCaseGroup> sampleCaseGroup(new tcu::TestCaseGroup(
rootGroup->getTestContext(), getSampleCountGroupName(params.numCoverageSamples, params.numColorSamples, params.numDepthStencilSamples).c_str(), ""));
for (const VkFormat *pDepthStencilFormat = depthStencilReducedFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilReducedFormatRange); ++pDepthStencilFormat)
for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat)
{
params.colorFormat = *pColorFormat;
params.depthStencilFormat = *pDepthStencilFormat;
addFunctionCaseWithPrograms(
sampleCaseGroup.get(),
getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(),
"",
ShaderBuiltins::checkRequirements,
ShaderBuiltins::initPrograms,
ShaderBuiltins::test,
params);
}
builtinsGroup->addChild(sampleCaseGroup.release());
}
rootGroup->addChild(builtinsGroup.release());
}
}
} // anonymous ns
tcu::TestCaseGroup* createMultisampleMixedAttachmentSamplesTests (tcu::TestContext& testCtx)
{
return createTestGroup(testCtx, "mixed_attachment_samples", "Test a graphics pipeline with varying sample count per color and depth/stencil attachments", createMixedAttachmentSamplesTestsInGroup);
}
} // pipeline
} // vkt