blob: 21bd29eb6f686696ff0a32f7925d00b35a4ccf83 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* 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 fragment density map extension ( VK_EXT_fragment_density_map )
*//*--------------------------------------------------------------------*/
#include "vktRenderPassFragmentDensityMapTests.hpp"
#include "pipeline/vktPipelineImageUtil.hpp"
#include "deMath.h"
#include "vktTestCase.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkObjUtil.hpp"
#include "tcuTestLog.hpp"
#include <sstream>
#include <vector>
// Each test generates an image with a color gradient where all colors should be unique when rendered without density map
// ( the number of each color in a histogram should be 1 ).
// The whole density map has the same values defined by input fragment area ( one of the test input parameters ).
// With density map enabled - the number of each color in a histogram should be [ fragmentArea.x * fragmentArea.y ].
//
// Additionally test checks if gl_FragSizeEXT shader variable has proper value ( as defined by fragmentArea input parameter ).
//
// static_* tests use density map loaded from CPU.
// dynamic_* tests use density map rendered on a GPU in a separate render pass
// *_nonsubsampled tests check if it's possible to use nonsubsampled images instead of subsampled ones
// There are 3 render passes performed during the test:
// - render pass that produces density map ( this rp is skipped when density map is static )
// - render pass that produces subsampled image using density map
// - render pass that copies subsampled image to traditional image using sampler with VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT flag.
// ( because subsampled images cannot be retrieved to CPU in any other way ).
namespace vkt
{
namespace renderpass
{
using namespace vk;
namespace
{
// set value of DRY_RUN_WITHOUT_FDM_EXTENSION to 1 if you want to check the correctness of the code without using VK_EXT_fragment_density_map extension
#define DRY_RUN_WITHOUT_FDM_EXTENSION 0
struct TestParams
{
TestParams(bool dynamicDensity, bool nonSubsampled, const tcu::UVec2& area)
: dynamicDensityMap{ dynamicDensity }, nonSubsampledImages{ nonSubsampled }, fragmentArea{ area }, densityMapFormat{ VK_FORMAT_R8G8_UNORM }
{}
bool dynamicDensityMap;
bool nonSubsampledImages;
tcu::UVec2 fragmentArea;
VkFormat densityMapFormat;
};
struct Vertex4RGBA
{
tcu::Vec4 position;
tcu::Vec4 color;
};
std::vector<Vertex4RGBA> createFullscreenQuadRG(void)
{
const Vertex4RGBA lowerLeftVertex = { tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f) };
const Vertex4RGBA upperLeftVertex = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) };
const Vertex4RGBA lowerRightVertex = { tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f) };
const Vertex4RGBA upperRightVertex = { tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f) };
return
{
lowerLeftVertex, lowerRightVertex, upperLeftVertex,
upperLeftVertex, lowerRightVertex, upperRightVertex
};
}
std::vector<Vertex4RGBA> createFullscreenQuadDensity(float densityX, float densityY)
{
const Vertex4RGBA lowerLeftVertex = { tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(densityX, densityY, 0.0f, 1.0f) };
const Vertex4RGBA upperLeftVertex = { tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec4(densityX, densityY, 0.0f, 1.0f) };
const Vertex4RGBA lowerRightVertex = { tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec4(densityX, densityY, 0.0f, 1.0f) };
const Vertex4RGBA upperRightVertex = { tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), tcu::Vec4(densityX, densityY, 0.0f, 1.0f) };
return
{
lowerLeftVertex, lowerRightVertex, upperLeftVertex,
upperLeftVertex, lowerRightVertex, upperRightVertex
};
};
template <typename T>
void createVertexBuffer(const DeviceInterface& vk,
VkDevice vkDevice,
const deUint32& queueFamilyIndex,
SimpleAllocator& memAlloc,
const std::vector<T>& vertices,
Move<VkBuffer>& vertexBuffer,
de::MovePtr<Allocation>& vertexAlloc)
{
const VkBufferCreateInfo vertexBufferParams =
{
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkBufferCreateFlags flags;
(VkDeviceSize)(sizeof(T) * vertices.size()), // VkDeviceSize size;
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex // const deUint32* pQueueFamilyIndices;
};
vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
vertexAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexAlloc->getMemory(), vertexAlloc->getOffset()));
// Upload vertex data
deMemcpy(vertexAlloc->getHostPtr(), vertices.data(), vertices.size() * sizeof(T));
flushAlloc(vk, vkDevice, *vertexAlloc);
}
template<typename AttachmentDesc, typename AttachmentRef, typename SubpassDesc, typename SubpassDep, typename RenderPassCreateInfo>
Move<VkRenderPass> createRenderPassProduceDynamicDensityMap(const DeviceInterface& vk,
VkDevice vkDevice,
const TestParams& testParams)
{
VkImageLayout densityPassFinalLayout = testParams.dynamicDensityMap ? VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
std::vector<AttachmentDesc> attachmentDescriptions =
{
{
DE_NULL, // const void* pNext
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
testParams.densityMapFormat, // VkFormat format
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
densityPassFinalLayout // VkImageLayout finalLayout
}
};
std::vector<AttachmentRef> colorAttachmentRefs
{
{ DE_NULL, 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
};
std::vector<SubpassDesc> subpassDescriptions
{
{
DE_NULL,
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
0u, // deUint32 viewMask
0u, // deUint32 inputAttachmentCount
DE_NULL, // const VkAttachmentReference* pInputAttachments
static_cast<deUint32>(colorAttachmentRefs.size()), // deUint32 colorAttachmentCount
colorAttachmentRefs.data(), // const VkAttachmentReference* pColorAttachments
DE_NULL, // const VkAttachmentReference* pResolveAttachments
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
0u, // deUint32 preserveAttachmentCount
DE_NULL // const deUint32* pPreserveAttachments
}
};
std::vector<SubpassDep> subpassDependencies;
if ( testParams.dynamicDensityMap )
{
subpassDependencies.emplace_back(
SubpassDep(
DE_NULL, // const void* pNext
0u, // uint32_t srcSubpass
VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT, // VkPipelineStageFlags dstStageMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT, // VkAccessFlags dstAccessMask
VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags
0u // deInt32 viewOffset
)
);
};
const RenderPassCreateInfo renderPassInfo(
DE_NULL, // const void* pNext
(VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount
(!testParams.dynamicDensityMap) ? DE_NULL : subpassDependencies.data(), // const VkSubpassDependency* pDependencies
0u, // deUint32 correlatedViewMaskCount
DE_NULL // const deUint32* pCorrelatedViewMasks
);
return renderPassInfo.createRenderPass(vk, vkDevice);
}
template<typename AttachmentDesc, typename AttachmentRef, typename SubpassDesc, typename SubpassDep, typename RenderPassCreateInfo>
Move<VkRenderPass> createRenderPassProduceSubsampledImage(const DeviceInterface& vk,
VkDevice vkDevice,
const TestParams& testParams)
{
DE_UNREF(testParams);
std::vector<AttachmentDesc> attachmentDescriptions
{
// Output color attachment
{
DE_NULL, // const void* pNext
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout
}
};
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
{
attachmentDescriptions.emplace_back(
AttachmentDesc(
DE_NULL, // const void* pNext
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
testParams.densityMapFormat, // VkFormat format
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, // VkImageLayout initialLayout
VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT // VkImageLayout finalLayout
)
);
}
#endif
std::vector<AttachmentRef> colorAttachmentRefs
{
{ DE_NULL, 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
};
std::vector<SubpassDesc> subpassDescriptions
{
{
DE_NULL,
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
0u, // deUint32 viewMask
0u, // deUint32 inputAttachmentCount
DE_NULL, // const VkAttachmentReference* pInputAttachments
static_cast<deUint32>(colorAttachmentRefs.size()), // deUint32 colorAttachmentCount
colorAttachmentRefs.data(), // const VkAttachmentReference* pColorAttachments
DE_NULL, // const VkAttachmentReference* pResolveAttachments
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
0u, // deUint32 preserveAttachmentCount
DE_NULL // const deUint32* pPreserveAttachments
}
};
std::vector<SubpassDep> subpassDependencies
{
{
DE_NULL, // const void* pNext
0u, // uint32_t srcSubpass
VK_SUBPASS_EXTERNAL, // uint32_t dstSubpass
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask
VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask
VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags
0u // deInt32 viewOffset
}
};
VkRenderPassFragmentDensityMapCreateInfoEXT renderPassFragmentDensityMap;
renderPassFragmentDensityMap.sType = VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT;
renderPassFragmentDensityMap.pNext = DE_NULL;
renderPassFragmentDensityMap.fragmentDensityMapAttachment = { 1, VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT };
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
const void* renderPassInfoPNext = (const void*)&renderPassFragmentDensityMap;
#else
const void* renderPassInfoPNext = DE_NULL;
#endif
const RenderPassCreateInfo renderPassInfo(
renderPassInfoPNext, // const void* pNext
(VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
static_cast<deUint32>(subpassDependencies.size()), // deUint32 dependencyCount
subpassDependencies.data(), // const VkSubpassDependency* pDependencies
0u, // deUint32 correlatedViewMaskCount
DE_NULL // const deUint32* pCorrelatedViewMasks
);
return renderPassInfo.createRenderPass(vk, vkDevice);
}
template<typename AttachmentDesc, typename AttachmentRef, typename SubpassDesc, typename SubpassDep, typename RenderPassCreateInfo>
Move<VkRenderPass> createRenderPassOutputSubsampledImage(const DeviceInterface& vk,
VkDevice vkDevice,
const TestParams& testParams)
{
DE_UNREF(testParams);
// copy subsampled image to ordinary image - you cannot retrieve subsampled image to CPU in any way. You must first convert it into plain image through rendering
std::vector<AttachmentDesc> attachmentDescriptions =
{
// output attachment
AttachmentDesc(
DE_NULL, // const void* pNext
(VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags
VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
),
};
std::vector<AttachmentRef> colorAttachmentRefs
{
{ DE_NULL, 0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_ASPECT_COLOR_BIT }
};
std::vector<SubpassDesc> subpassDescriptions =
{
{
DE_NULL,
(VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
0u, // deUint32 viewMask
0u, // deUint32 inputAttachmentCount
DE_NULL, // const VkAttachmentReference* pInputAttachments
static_cast<deUint32>(colorAttachmentRefs.size()), // deUint32 colorAttachmentCount
colorAttachmentRefs.data(), // const VkAttachmentReference* pColorAttachments
DE_NULL, // const VkAttachmentReference* pResolveAttachments
DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment
0u, // deUint32 preserveAttachmentCount
DE_NULL // const deUint32* pPreserveAttachments
}
};
const RenderPassCreateInfo renderPassInfo(
DE_NULL, // const void* pNext
(VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags
static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments
static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
subpassDescriptions.data(), // const VkSubpassDescription* pSubpasses
0, // deUint32 dependencyCount
DE_NULL, // const VkSubpassDependency* pDependencies
0u, // deUint32 correlatedViewMaskCount
DE_NULL // const deUint32* pCorrelatedViewMasks
);
return renderPassInfo.createRenderPass(vk, vkDevice);
}
Move<VkFramebuffer> createFrameBuffer( const DeviceInterface& vk, VkDevice vkDevice, VkRenderPass renderPass, const tcu::UVec2& renderSize, const std::vector<VkImageView>& imageViews)
{
const VkFramebufferCreateInfo framebufferParams =
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkFramebufferCreateFlags flags;
renderPass, // VkRenderPass renderPass;
static_cast<deUint32>(imageViews.size()), // deUint32 attachmentCount;
imageViews.data(), // const VkImageView* pAttachments;
renderSize.x(), // deUint32 width;
renderSize.y(), // deUint32 height;
1u // deUint32 layers;
};
return createFramebuffer(vk, vkDevice, &framebufferParams);
}
class FragmentDensityMapTest : public vkt::TestCase
{
public:
FragmentDensityMapTest (tcu::TestContext& testContext,
const std::string& name,
const std::string& description,
const TestParams& testParams);
virtual void initPrograms (SourceCollections& sourceCollections) const;
virtual TestInstance* createInstance (Context& context) const;
virtual void checkSupport (Context& context) const;
private:
const TestParams m_testParams;
};
class FragmentDensityMapTestInstance : public vkt::TestInstance
{
public:
FragmentDensityMapTestInstance (Context& context,
const TestParams& testParams);
virtual tcu::TestStatus iterate (void);
private:
tcu::TestStatus verifyImage (void);
TestParams m_testParams;
const tcu::UVec2 m_renderSize;
const tcu::UVec2 m_densityMapSize;
VkPhysicalDeviceFragmentDensityMapPropertiesEXT m_fragmentDensityMapProperties;
Move<VkCommandPool> m_cmdPool;
Move<VkImage> m_densityMapImage;
de::MovePtr<Allocation> m_densityMapImageAlloc;
Move<VkImageView> m_densityMapImageView;
Move<VkImage> m_colorImage;
de::MovePtr<Allocation> m_colorImageAlloc;
Move<VkImageView> m_colorImageView;
Move<VkImage> m_outputImage;
de::MovePtr<Allocation> m_outputImageAlloc;
Move<VkImageView> m_outputImageView;
Move<VkSampler> m_colorSampler;
Move<VkRenderPass> m_renderPassProduceDynamicDensityMap;
Move<VkRenderPass> m_renderPassProduceSubsampledImage;
Move<VkRenderPass> m_renderPassOutputSubsampledImage;
Move<VkFramebuffer> m_framebufferProduceDynamicDensityMap;
Move<VkFramebuffer> m_framebufferProduceSubsampledImage;
Move<VkFramebuffer> m_framebufferOutputSubsampledImage;
Move<VkDescriptorSetLayout> m_descriptorSetLayoutProduceSubsampled;
Move<VkDescriptorSetLayout> m_descriptorSetLayoutOutputSubsampledImage;
Move<VkDescriptorPool> m_descriptorPoolOutputSubsampledImage;
Move<VkDescriptorSet> m_descriptorSetOutputSubsampledImage;
Move<VkShaderModule> m_vertexCommonShaderModule;
Move<VkShaderModule> m_fragmentShaderModuleProduceSubsampledImage;
Move<VkShaderModule> m_fragmentShaderModuleOutputSubsampledImage;
Move<VkBuffer> m_vertexBuffer;
std::vector<Vertex4RGBA> m_vertices;
de::MovePtr<Allocation> m_vertexBufferAlloc;
Move<VkBuffer> m_vertexBufferDDM;
std::vector<Vertex4RGBA> m_verticesDDM;
de::MovePtr<Allocation> m_vertexBufferAllocDDM;
Move<VkPipelineLayout> m_pipelineLayoutProduceSubsampledImage;
Move<VkPipelineLayout> m_pipelineLayoutOutputSubsampledImage;
Move<VkPipeline> m_graphicsPipelineProduceDynamicDensityMap;
Move<VkPipeline> m_graphicsPipelineProduceSubsampledImage;
Move<VkPipeline> m_graphicsPipelineOutputSubsampledImage;
Move<VkCommandBuffer> m_cmdBuffer;
};
FragmentDensityMapTest::FragmentDensityMapTest (tcu::TestContext& testContext,
const std::string& name,
const std::string& description,
const TestParams& testParams)
: vkt::TestCase (testContext, name, description)
, m_testParams (testParams)
{
}
void FragmentDensityMapTest::initPrograms(SourceCollections& sourceCollections) const
{
std::ostringstream densityVertexGLSL;
densityVertexGLSL <<
"#version 450\n"
"layout(location = 0) in vec4 inPosition;\n"
"layout(location = 1) in vec4 inColor;\n"
"layout(location = 0) out vec4 outColor;\n"
"layout(location = 1) out vec2 outUV;\n"
"void main(void)\n"
"{\n"
" gl_Position = inPosition;\n"
" outColor = inColor;\n"
" outUV = 0.5 * inPosition.xy + vec2(0.5);\n"
"}\n";
sourceCollections.glslSources.add("densitymap_vert") << glu::VertexSource(densityVertexGLSL.str());
std::ostringstream densityFragmentProduceGLSL;
densityFragmentProduceGLSL <<
"#version 450\n"
"#extension GL_EXT_fragment_invocation_density : enable\n"
"layout(location = 0) in vec4 inColor;\n"
"layout(location = 1) in vec2 inUV;\n"
"layout(location = 0) out vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" fragColor = vec4(inColor.x, inColor.y, 1.0/float(gl_FragSizeEXT.x), 1.0/(gl_FragSizeEXT.y));\n"
"}\n";
sourceCollections.glslSources.add("densitymap_frag_produce") << glu::FragmentSource(densityFragmentProduceGLSL.str());
std::ostringstream densityFragmentOutputGLSL;
densityFragmentOutputGLSL <<
"#version 450\n"
"layout(location = 0) in vec4 inColor;\n"
"layout(location = 1) in vec2 inUV;\n"
"layout(binding = 0) uniform sampler2D subsampledImage;\n"
"layout(location = 0) out vec4 fragColor;\n"
"void main(void)\n"
"{\n"
" fragColor = texture(subsampledImage, inUV);\n"
"}\n";
sourceCollections.glslSources.add("densitymap_frag_output") << glu::FragmentSource(densityFragmentOutputGLSL.str());
}
TestInstance* FragmentDensityMapTest::createInstance(Context& context) const
{
return new FragmentDensityMapTestInstance(context, m_testParams);
}
void FragmentDensityMapTest::checkSupport(Context& context) const
{
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
context.requireDeviceFunctionality("VK_EXT_fragment_density_map");
VkPhysicalDeviceFeatures2 features;
deMemset(&features, 0, sizeof(VkPhysicalDeviceFeatures2));
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
VkPhysicalDeviceFragmentDensityMapFeaturesEXT fragmentDensityMapFeatures;
deMemset(&fragmentDensityMapFeatures, 0, sizeof(VkPhysicalDeviceFragmentDensityMapFeaturesEXT));
fragmentDensityMapFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT;
features.pNext = &fragmentDensityMapFeatures;
context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features);
if (!fragmentDensityMapFeatures.fragmentDensityMap)
TCU_THROW(NotSupportedError, "fragmentDensityMap feature is not supported");
if (m_testParams.dynamicDensityMap && !fragmentDensityMapFeatures.fragmentDensityMapDynamic)
TCU_THROW(NotSupportedError, "fragmentDensityMapDynamic feature is not supported");
if (m_testParams.nonSubsampledImages && !fragmentDensityMapFeatures.fragmentDensityMapNonSubsampledImages)
TCU_THROW(NotSupportedError, "fragmentDensityMapNonSubsampledImages feature is not supported");
#else
DE_UNREF(context);
#endif
}
FragmentDensityMapTestInstance::FragmentDensityMapTestInstance(Context& context,
const TestParams& testParams)
: vkt::TestInstance ( context )
, m_testParams ( testParams )
, m_renderSize ( 32u, 32u )
, m_densityMapSize ( 16u, 16u )
, m_vertices ( createFullscreenQuadRG() )
, m_verticesDDM ( createFullscreenQuadDensity(1.0f / static_cast<float>(testParams.fragmentArea.x()), 1.0f / static_cast<float>(testParams.fragmentArea.y())) )
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
{
VkPhysicalDeviceProperties2 properties;
deMemset(&properties, 0, sizeof(VkPhysicalDeviceProperties2));
properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
deMemset(&m_fragmentDensityMapProperties, 0, sizeof(VkPhysicalDeviceFragmentDensityMapPropertiesEXT));
m_fragmentDensityMapProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT;
properties.pNext = &m_fragmentDensityMapProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
}
#else
{
m_fragmentDensityMapProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT;
m_fragmentDensityMapProperties.minFragmentDensityTexelSize.width = 1u;
m_fragmentDensityMapProperties.maxFragmentDensityTexelSize.width = 1u;
m_fragmentDensityMapProperties.minFragmentDensityTexelSize.height = 1u;
m_fragmentDensityMapProperties.maxFragmentDensityTexelSize.height = 1u;
m_fragmentDensityMapProperties.fragmentDensityInvocations = DE_FALSE;
m_testParams.fragmentArea.x() = 1u;
m_testParams.fragmentArea.y() = 1u;
}
#endif
// Create density map image
{
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
vk::VkImageUsageFlags densityMapImageUsage = m_testParams.dynamicDensityMap ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT : VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT;
#else
vk::VkImageUsageFlags densityMapImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
#endif
const VkImageCreateInfo densityMapImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
m_testParams.densityMapFormat, // VkFormat format;
{ m_densityMapSize.x(), m_densityMapSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
densityMapImageUsage, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_densityMapImage = createImage(vk, vkDevice, &densityMapImageParams);
// Allocate and bind density map image memory
VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vk, vkDevice, *m_densityMapImage);
m_densityMapImageAlloc = memAlloc.allocate(memoryRequirements, MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_densityMapImage, m_densityMapImageAlloc->getMemory(), m_densityMapImageAlloc->getOffset()));
// create and fill staging buffer, copy its data to density map image
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
tcu::TextureFormat densityMapTextureFormat = vk::mapVkFormat(m_testParams.densityMapFormat);
if ( !m_testParams.dynamicDensityMap )
{
VkDeviceSize stagingBufferSize = tcu::getPixelSize(densityMapTextureFormat) * m_densityMapSize.x() * m_densityMapSize.y() * 1;
const vk::VkBufferCreateInfo stagingBufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
stagingBufferSize, // size
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
vk::Move<vk::VkBuffer> stagingBuffer = vk::createBuffer(vk, vkDevice, &stagingBufferCreateInfo);
const vk::VkMemoryRequirements stagingRequirements = vk::getBufferMemoryRequirements(vk, vkDevice, *stagingBuffer);
de::MovePtr<vk::Allocation> stagingAllocation = memAlloc.allocate(stagingRequirements, MemoryRequirement::HostVisible);
VK_CHECK(vk.bindBufferMemory(vkDevice, *stagingBuffer, stagingAllocation->getMemory(), stagingAllocation->getOffset()));
tcu::PixelBufferAccess stagingBufferAccess = tcu::PixelBufferAccess(densityMapTextureFormat, m_densityMapSize.x(), m_densityMapSize.y(), 1, stagingAllocation->getHostPtr());
tcu::Vec4 fragmentArea { 1.0f / static_cast<float>(testParams.fragmentArea.x()), 1.0f / static_cast<float>(testParams.fragmentArea.y()), 0.0f, 1.0f };
for (int y = 0; y < stagingBufferAccess.getHeight(); y++)
for (int x = 0; x < stagingBufferAccess.getWidth(); x++)
stagingBufferAccess.setPixel(fragmentArea, x, y);
flushAlloc(vk, vkDevice, *stagingAllocation);
std::vector<VkBufferImageCopy> copyRegions =
{
{
0, // VkDeviceSize bufferOffset
0, // deUint32 bufferRowLength
0, // deUint32 bufferImageHeight
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }, // VkImageSubresourceLayers imageSubresource
{ 0, 0, 0 }, // VkOffset3D imageOffset
{ m_densityMapSize.x(), m_densityMapSize.y(), 1u } // VkExtent3D imageExtent
}
};
vk::copyBufferToImage
(
vk,
vkDevice,
m_context.getUniversalQueue(),
queueFamilyIndex,
*stagingBuffer,
stagingBufferSize,
copyRegions,
DE_NULL,
VK_IMAGE_ASPECT_COLOR_BIT,
1,
1,
*m_densityMapImage,
VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT,
VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT
);
}
#endif
//create image view for fragment density map
deUint32 densityMapImageViewCreateFlags = m_testParams.dynamicDensityMap ? (deUint32)VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT : 0u;
const VkImageViewCreateInfo densityMapImageViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkImageViewCreateFlags)densityMapImageViewCreateFlags, // VkImageViewCreateFlags flags;
*m_densityMapImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
m_testParams.densityMapFormat, // VkFormat format;
componentMappingRGBA, // VkChannelMapping channels;
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
};
m_densityMapImageView = createImageView(vk, vkDevice, &densityMapImageViewParams);
}
// Create subsampled color image
{
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
deUint32 colorImageCreateFlags = m_testParams.nonSubsampledImages ? 0u : (deUint32)VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT;
#else
deUint32 colorImageCreateFlags = 0u;
#endif
const VkImageCreateInfo colorImageParams
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkImageCreateFlags)colorImageCreateFlags, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format;
{ m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_colorImage = createImage(vk, vkDevice, &colorImageParams);
// Allocate and bind color image memory
m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
// create image view for subsampled image
const VkImageViewCreateInfo colorImageViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_colorImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format;
componentMappingRGBA, // VkChannelMapping channels;
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
};
m_colorImageView = createImageView(vk, vkDevice, &colorImageViewParams);
}
// Create output image ( data from subsampled color image will be copied into it using sampler with VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT )
{
const VkImageCreateInfo outputImageParams =
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format;
{ m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
m_outputImage = createImage(vk, vkDevice, &outputImageParams);
// Allocate and bind input image memory
m_outputImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_outputImage), MemoryRequirement::Any);
VK_CHECK(vk.bindImageMemory(vkDevice, *m_outputImage, m_outputImageAlloc->getMemory(), m_outputImageAlloc->getOffset()));
// create image view for output image
const VkImageViewCreateInfo outputImageViewParams =
{
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkImageViewCreateFlags flags;
*m_outputImage, // VkImage image;
VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format;
componentMappingRGBA, // VkChannelMapping channels;
{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange;
};
m_outputImageView = createImageView(vk, vkDevice, &outputImageViewParams);
}
// create a sampler that is able to read from subsampled image
{
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
deUint32 samplerCreateFlags = m_testParams.nonSubsampledImages ? 0u : (deUint32)VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT;
#else
deUint32 samplerCreateFlags = 0u;
#endif
const struct VkSamplerCreateInfo samplerInfo
{
VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // sType
DE_NULL, // pNext
(VkSamplerCreateFlags)samplerCreateFlags, // flags
VK_FILTER_NEAREST, // magFilter
VK_FILTER_NEAREST, // minFilter
VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
0.0f, // mipLodBias
VK_FALSE, // anisotropyEnable
1.0f, // maxAnisotropy
DE_FALSE, // compareEnable
VK_COMPARE_OP_ALWAYS, // compareOp
0.0f, // minLod
0.0f, // maxLod
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
VK_FALSE, // unnormalizedCoords
};
m_colorSampler = createSampler(vk, vkDevice, &samplerInfo);
}
// Create render passes
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
if ( testParams.dynamicDensityMap )
#endif
m_renderPassProduceDynamicDensityMap = createRenderPassProduceDynamicDensityMap<AttachmentDescription2, AttachmentReference2, SubpassDescription2, SubpassDependency2, RenderPassCreateInfo2>(vk, vkDevice, testParams);
m_renderPassProduceSubsampledImage = createRenderPassProduceSubsampledImage<AttachmentDescription2, AttachmentReference2, SubpassDescription2, SubpassDependency2, RenderPassCreateInfo2>(vk, vkDevice, testParams);
m_renderPassOutputSubsampledImage = createRenderPassOutputSubsampledImage<AttachmentDescription2, AttachmentReference2, SubpassDescription2, SubpassDependency2, RenderPassCreateInfo2>(vk, vkDevice, testParams);
// Create framebuffers
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
if ( testParams.dynamicDensityMap )
#endif
m_framebufferProduceDynamicDensityMap = createFrameBuffer(vk, vkDevice, *m_renderPassProduceDynamicDensityMap, m_densityMapSize, { *m_densityMapImageView });
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
m_framebufferProduceSubsampledImage = createFrameBuffer(vk, vkDevice, *m_renderPassProduceSubsampledImage, m_renderSize, { *m_colorImageView, *m_densityMapImageView });
#else
m_framebufferProduceSubsampledImage = createFrameBuffer(vk, vkDevice, *m_renderPassProduceSubsampledImage, m_renderSize, { *m_colorImageView });
#endif
m_framebufferOutputSubsampledImage = createFrameBuffer( vk, vkDevice, *m_renderPassOutputSubsampledImage, m_renderSize, { *m_outputImageView } );
// Create pipeline layout for first two render passes that do not use any descriptors
{
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineLayoutCreateFlags flags;
0u, // deUint32 setLayoutCount;
DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
m_pipelineLayoutProduceSubsampledImage = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
}
// Create pipeline layout for last render pass ( output subsampled image )
{
std::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings =
{
{
0, // deUint32 binding;
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // VkDescriptorType descriptorType;
1, // deUint32 descriptorCount;
VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags;
&(m_colorSampler.get()) // const VkSampler* pImmutableSamplers;
},
};
const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutParams =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkDescriptorSetLayoutCreateFlags flags
static_cast<deUint32>(descriptorSetLayoutBindings.size()), // deUint32 bindingCount
descriptorSetLayoutBindings.data() // const VkDescriptorSetLayoutBinding* pBindings
};
m_descriptorSetLayoutOutputSubsampledImage = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutParams);
const VkPipelineLayoutCreateInfo pipelineLayoutParams =
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineLayoutCreateFlags flags;
1u, // deUint32 setLayoutCount;
&m_descriptorSetLayoutOutputSubsampledImage.get(), // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
m_pipelineLayoutOutputSubsampledImage = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
}
// Update descriptor set
{
{
std::vector<VkDescriptorPoolSize> poolSizes =
{
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u }
};
const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // VkDescriptorPoolCreateFlags flags
1u, // deUint32 maxSets
static_cast<deUint32>(poolSizes.size()), // deUint32 poolSizeCount
poolSizes.data() // const VkDescriptorPoolSize* pPoolSizes
};
m_descriptorPoolOutputSubsampledImage = createDescriptorPool(vk, vkDevice, &descriptorPoolCreateInfo);
}
{
const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
*m_descriptorPoolOutputSubsampledImage, // VkDescriptorPool descriptorPool
1u, // deUint32 descriptorSetCount
&m_descriptorSetLayoutOutputSubsampledImage.get(), // const VkDescriptorSetLayout* pSetLayouts
};
m_descriptorSetOutputSubsampledImage = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocateInfo);
const VkDescriptorImageInfo inputImageInfo =
{
DE_NULL, // VkSampleri sampler;
*m_colorImageView, // VkImageView imageView;
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout;
};
std::vector<VkWriteDescriptorSet> descriptorWrite =
{
{
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_descriptorSetOutputSubsampledImage, // VkDescriptorSet dstSet;
0u, // deUint32 dstBinding;
0u, // deUint32 dstArrayElement;
1u, // deUint32 descriptorCount;
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // VkDescriptorType descriptorType;
&inputImageInfo, // const VkDescriptorImageInfo* pImageInfo;
DE_NULL, // const VkDescriptorBufferInfo* pBufferInfo;
DE_NULL // const VkBufferView* pTexelBufferView;
}
};
vk.updateDescriptorSets(vkDevice, static_cast<deUint32>(descriptorWrite.size()), descriptorWrite.data(), 0u, DE_NULL);
}
}
m_vertexCommonShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("densitymap_vert"), 0);
m_fragmentShaderModuleProduceSubsampledImage = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("densitymap_frag_produce"), 0);
m_fragmentShaderModuleOutputSubsampledImage = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("densitymap_frag_output"), 0);
// Create pipelines
{
const VkVertexInputBindingDescription vertexInputBindingDescription =
{
0u, // deUint32 binding;
sizeof(Vertex4RGBA), // deUint32 strideInBytes;
VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate;
};
std::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions =
{
{ 0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u },
{ 1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, (deUint32)(sizeof(float) * 4) }
};
const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineVertexInputStateCreateFlags flags;
1u, // deUint32 vertexBindingDescriptionCount;
&vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
static_cast<deUint32>(vertexInputAttributeDescriptions.size()), // deUint32 vertexAttributeDescriptionCount;
vertexInputAttributeDescriptions.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
};
const std::vector<VkViewport> viewportsDDM { makeViewport(m_densityMapSize) };
const std::vector<VkRect2D> scissorsDDM { makeRect2D(m_densityMapSize) };
const std::vector<VkViewport> viewports { makeViewport(m_renderSize) };
const std::vector<VkRect2D> scissors { makeRect2D(m_renderSize) };
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
if (testParams.dynamicDensityMap)
#endif
m_graphicsPipelineProduceDynamicDensityMap = makeGraphicsPipeline(vk, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayoutProduceSubsampledImage, // const VkPipelineLayout pipelineLayout
*m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlModule
DE_NULL, // const VkShaderModule tessellationEvalModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModuleProduceSubsampledImage, // const VkShaderModule fragmentShaderModule
*m_renderPassProduceDynamicDensityMap, // const VkRenderPass renderPass
viewportsDDM, // const std::vector<VkViewport>& viewports
scissorsDDM, // const std::vector<VkRect2D>& scissors
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
0u, // const deUint32 subpass
0u, // const deUint32 patchControlPoints
&vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
m_graphicsPipelineProduceSubsampledImage = makeGraphicsPipeline(vk, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayoutProduceSubsampledImage, // const VkPipelineLayout pipelineLayout
*m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlModule
DE_NULL, // const VkShaderModule tessellationEvalModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModuleProduceSubsampledImage, // const VkShaderModule fragmentShaderModule
*m_renderPassProduceSubsampledImage, // 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
&vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
m_graphicsPipelineOutputSubsampledImage = makeGraphicsPipeline(vk, // const DeviceInterface& vk
vkDevice, // const VkDevice device
*m_pipelineLayoutOutputSubsampledImage, // const VkPipelineLayout pipelineLayout
*m_vertexCommonShaderModule, // const VkShaderModule vertexShaderModule
DE_NULL, // const VkShaderModule tessellationControlModule
DE_NULL, // const VkShaderModule tessellationEvalModule
DE_NULL, // const VkShaderModule geometryShaderModule
*m_fragmentShaderModuleOutputSubsampledImage, // const VkShaderModule fragmentShaderModule
*m_renderPassOutputSubsampledImage, // 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
&vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
}
// Create vertex buffers
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
if (testParams.dynamicDensityMap)
#endif
createVertexBuffer(vk, vkDevice, queueFamilyIndex, memAlloc, m_verticesDDM, m_vertexBufferDDM, m_vertexBufferAllocDDM);
createVertexBuffer(vk, vkDevice, queueFamilyIndex, memAlloc, m_vertices, m_vertexBuffer, m_vertexBufferAlloc);
// Create command pool and command buffer
m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
const typename RenderpassSubpass2::SubpassBeginInfo subpassBeginInfo(DE_NULL, VK_SUBPASS_CONTENTS_INLINE);
const typename RenderpassSubpass2::SubpassEndInfo subpassEndInfo(DE_NULL);
const VkDeviceSize vertexBufferOffset = 0;
std::vector<VkClearValue> attachmentClearValuesDDM = { makeClearValueColorF32(1.0f, 1.0f, 1.0f, 1.0f) };
std::vector<VkClearValue> attachmentClearValues = { makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f) };
beginCommandBuffer(vk, *m_cmdBuffer, 0u);
// first render pass - render dynamic density map
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
if ( testParams.dynamicDensityMap )
#endif
{
const VkRenderPassBeginInfo renderPassBeginInfoProduceDynamicDensityMap =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_renderPassProduceDynamicDensityMap, // VkRenderPass renderPass;
*m_framebufferProduceDynamicDensityMap, // VkFramebuffer framebuffer;
makeRect2D(m_densityMapSize), // VkRect2D renderArea;
static_cast<deUint32>(attachmentClearValuesDDM.size()), // uint32_t clearValueCount;
attachmentClearValuesDDM.data() // const VkClearValue* pClearValues;
};
RenderpassSubpass2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoProduceDynamicDensityMap, &subpassBeginInfo);
vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineProduceDynamicDensityMap);
vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBufferDDM.get(), &vertexBufferOffset);
vk.cmdDraw(*m_cmdBuffer, (deUint32)m_verticesDDM.size(), 1, 0, 0);
RenderpassSubpass2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
}
// render subsampled image
const VkRenderPassBeginInfo renderPassBeginInfoProduceSubsampledImage =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_renderPassProduceSubsampledImage, // VkRenderPass renderPass;
*m_framebufferProduceSubsampledImage, // VkFramebuffer framebuffer;
makeRect2D(m_renderSize), // VkRect2D renderArea;
static_cast<deUint32>(attachmentClearValues.size()), // uint32_t clearValueCount;
attachmentClearValues.data() // const VkClearValue* pClearValues;
};
RenderpassSubpass2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoProduceSubsampledImage, &subpassBeginInfo);
vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineProduceSubsampledImage);
vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
RenderpassSubpass2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
// copy subsampled image to ordinary image using sampler that is able to read from subsampled images( subsampled image cannot be copied using vkCmdCopyImageToBuffer )
const VkRenderPassBeginInfo renderPassBeginInfoOutputSubsampledImage =
{
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
*m_renderPassOutputSubsampledImage, // VkRenderPass renderPass;
*m_framebufferOutputSubsampledImage, // VkFramebuffer framebuffer;
makeRect2D(m_renderSize), // VkRect2D renderArea;
static_cast<deUint32>(attachmentClearValues.size()), // uint32_t clearValueCount;
attachmentClearValues.data() // const VkClearValue* pClearValues;
};
RenderpassSubpass2::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfoOutputSubsampledImage, &subpassBeginInfo);
vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineOutputSubsampledImage);
vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutOutputSubsampledImage, 0, 1, &m_descriptorSetOutputSubsampledImage.get(), 0, DE_NULL);
vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0);
RenderpassSubpass2::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo);
endCommandBuffer(vk, *m_cmdBuffer);
}
tcu::TestStatus FragmentDensityMapTestInstance::iterate (void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
return verifyImage();
}
struct Vec4Sorter
{
bool operator()(const tcu::Vec4& lhs, const tcu::Vec4& rhs) const
{
if (lhs.x() != rhs.x())
return lhs.x() < rhs.x();
if (lhs.y() != rhs.y())
return lhs.y() < rhs.y();
if (lhs.z() != rhs.z())
return lhs.z() < rhs.z();
return lhs.w() < rhs.w();
}
};
tcu::TestStatus FragmentDensityMapTestInstance::verifyImage (void)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
const VkDevice vkDevice = m_context.getDevice();
const VkQueue queue = m_context.getUniversalQueue();
const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
de::UniquePtr<tcu::TextureLevel> outputImage (pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_outputImage, VK_FORMAT_R8G8B8A8_UNORM, m_renderSize).release());
const tcu::ConstPixelBufferAccess& outputAccess = outputImage->getAccess();
tcu::TestLog& log = m_context.getTestContext().getLog();
// log images
log << tcu::TestLog::ImageSet("Result", "Result images")
<< tcu::TestLog::Image("Rendered", "Rendered output image", outputAccess)
<< tcu::TestLog::EndImageSet;
#if !DRY_RUN_WITHOUT_FDM_EXTENSION
deUint32 estimatedColorCount = m_testParams.fragmentArea.x() * m_testParams.fragmentArea.y();
#else
deUint32 estimatedColorCount = 1u;
#endif
tcu::Vec2 density{
1.0f / static_cast<float>(m_testParams.fragmentArea.x()),
1.0f / static_cast<float>(m_testParams.fragmentArea.y())
};
float densityMult = density.x() * density.y();
// create histogram of all image colors, check the value of inverted FragSizeEXT
std::map<tcu::Vec4, deUint32, Vec4Sorter> colorCount;
for (int y = 0; y < outputAccess.getHeight(); y++)
{
for (int x = 0; x < outputAccess.getWidth(); x++)
{
tcu::Vec4 outputColor = outputAccess.getPixel(x, y);
float densityClamped = outputColor.z() * outputColor.w();
if ((densityClamped + 0.01) < densityMult)
return tcu::TestStatus::fail("Wrong value of FragSizeEXT variable");
auto it = colorCount.find(outputColor);
if (it == end(colorCount))
it = colorCount.insert({ outputColor, 0u }).first;
it->second++;
}
}
// check if color count is the same as estimated one
for (const auto& color : colorCount)
{
if (color.second > estimatedColorCount)
return tcu::TestStatus::fail("Wrong color count");
}
return tcu::TestStatus::pass("Pass");
}
} // anonymous
tcu::TestCaseGroup* createFragmentDensityMapTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> fdmTests (new tcu::TestCaseGroup(testCtx, "fragment_density_map", "VK_EXT_fragment_density_map extension tests"));
std::vector<tcu::UVec2> fragmentArea
{
{ 1, 2 },
{ 2, 1 },
{ 2, 2 }
};
for (const auto& area : fragmentArea)
{
std::stringstream str;
str << "_" << area.x() << "_" << area.y();
fdmTests->addChild(new FragmentDensityMapTest(testCtx, std::string("static_subsampled") + str.str(), "", TestParams(false, false, area)));
fdmTests->addChild(new FragmentDensityMapTest(testCtx, std::string("dynamic_subsampled") + str.str(), "", TestParams(true, false, area)));
fdmTests->addChild(new FragmentDensityMapTest(testCtx, std::string("static_nonsubsampled") + str.str(), "", TestParams(false, true, area)));
fdmTests->addChild(new FragmentDensityMapTest(testCtx, std::string("dynamic_nonsubsampled") + str.str(), "", TestParams(true, true, area)));
}
return fdmTests.release();
}
} // renderpass
} // vkt