blob: aef4625dea21bc629f97187e01ac405d38135332 [file] [log] [blame]
/*------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2021 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_KHR_fragment_shading_rate
*//*--------------------------------------------------------------------*/
#include "vktAttachmentRateTests.hpp"
#include "vkBufferWithMemory.hpp"
#include "vkImageWithMemory.hpp"
#include "vkQueryUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkPlatform.hpp"
#include "vkBuilderUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktTestCase.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "deDefs.h"
#include "deMath.h"
#include "deSharedPtr.hpp"
#include "deString.h"
#include "deSTLUtil.hpp"
#include "tcuTestCase.hpp"
#include "tcuTestLog.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuStringTemplate.hpp"
#include <string>
#include <vector>
#include <limits>
#include <map>
namespace vkt
{
namespace FragmentShadingRate
{
namespace
{
using namespace vk;
// flag used to test TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER;
// when it is 1 instead of using atomic operations to fill image
// plain store will be used as it is always supported
#define DEBUG_USE_STORE_INSTEAD_OF_ATOMICS 0
enum TestMode
{
TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER = 0,
TM_SETUP_RATE_WITH_FRAGMENT_SHADER,
TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE,
TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE,
TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE,
TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE,
TM_TWO_SUBPASS
};
struct TestParams
{
TestMode mode;
VkFormat srFormat;
VkExtent2D srRate;
bool useImagelessFramebuffer;
};
deUint32 calculateRate(deUint32 rateWidth, deUint32 rateHeight)
{
return (deCtz32(rateWidth) << 2u) | deCtz32(rateHeight);
}
class AttachmentRateInstance : public TestInstance
{
public:
AttachmentRateInstance (Context& context, const de::SharedPtr<TestParams> params);
tcu::TestStatus iterate (void);
private:
// Helper structure used by buildFramebuffer method.
// It is used to build regular or imageless framebuffer.
struct FBAttachmentInfo
{
VkFormat format;
VkImageUsageFlags usage;
deUint32 width;
deUint32 height;
VkImageView view;
};
private:
de::MovePtr<ImageWithMemory> buildImageWithMemory (VkFormat format,
deUint32 width,
deUint32 height,
VkImageUsageFlags usage,
VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL,
std::vector<deUint32> queueFamilies = std::vector<deUint32>());
de::MovePtr<BufferWithMemory> buildBufferWithMemory (deUint32 size,
VkBufferUsageFlags usage);
Move<VkImageView> buildImageView (VkFormat format,
VkImage image);
void buildColorBufferObjects (deUint32 cbIindex,
VkImageUsageFlags cbUsage);
void buildShadingRateObjects (deUint32 srIndex,
deUint32 width,
deUint32 height,
VkImageUsageFlags srUsage,
VkImageTiling srTiling = VK_IMAGE_TILING_OPTIMAL);
void buildCounterBufferObjects ();
Move<VkRenderPass> buildRenderPass (VkFormat cbFormat,
deUint32 sr1TileWidth = 0,
deUint32 sr1TileHeight = 0,
deUint32 sr2TileWidth = 0,
deUint32 sr2TileHeight = 0) const;
Move<VkFramebuffer> buildFramebuffer (VkRenderPass renderPass,
const std::vector<FBAttachmentInfo>& attachmentInfo) const;
Move<VkPipelineLayout> buildPipelineLayout (const VkDescriptorSetLayout* setLayouts = DE_NULL) const;
Move<VkPipeline> buildGraphicsPipeline (deUint32 subpass,
VkRenderPass renderPass,
VkPipelineLayout layout,
VkShaderModule vertShader,
VkShaderModule fragShader,
bool useShadingRate = VK_TRUE) const;
Move<VkPipeline> buildComputePipeline (VkShaderModule compShader,
VkPipelineLayout pipelineLayout) const;
VkDescriptorSetAllocateInfo makeDescriptorSetAllocInfo (VkDescriptorPool descriptorPool,
const VkDescriptorSetLayout* pSetLayouts) const;
void startRendering (const VkCommandBuffer commandBuffer,
const VkRenderPass renderPass,
const VkFramebuffer framebuffer,
const VkRect2D& renderArea,
const std::vector<FBAttachmentInfo>& attachmentInfo) const;
void finishRendering (const VkCommandBuffer commandBuffer) const;
bool verifyUsingAtomicChecks (deUint32 tileWidth,
deUint32 tileHeight,
deUint32 rateWidth,
deUint32 rateHeight,
deUint32* outBufferPtr) const;
bool runComputeShaderMode (void);
bool runFragmentShaderMode (void);
bool runCopyMode (void);
bool runCopyModeOnTransferQueue (void);
bool runFillLinearTiledImage (void);
bool runTwoSubpassMode (void);
private:
// When custom device is used then m_device and m_allocator are used in all
// helper methods. Otherwise default device and allocator from context are used.
// Those objects are used only by tests from runCopyModeOnTransferQueue.
Move<VkDevice> m_device;
de::MovePtr<Allocator> m_allocator;
const de::SharedPtr<TestParams> m_params;
const deUint32 m_cbWidth;
const deUint32 m_cbHeight;
VkFormat m_cbFormat;
VkImageUsageFlags m_cbUsage;
VkImageUsageFlags m_srUsage;
// structures commonly used by most of tests
const VkImageSubresourceLayers m_defaultImageSubresourceLayers;
const VkImageSubresourceRange m_defaultImageSubresourceRange;
const VkBufferImageCopy m_defaultBufferImageCopy;
// objects commonly used by most of tests
de::MovePtr<ImageWithMemory> m_cbImage[2];
Move<VkImageView> m_cbImageView[2];
de::MovePtr<BufferWithMemory> m_cbReadBuffer[2];
de::MovePtr<ImageWithMemory> m_srImage[2];
Move<VkImageView> m_srImageView[2];
Move<VkDescriptorSetLayout> m_counterBufferDescriptorSetLayout;
Move<VkDescriptorPool> m_counterBufferDescriptorPool;
Move<VkDescriptorSet> m_counterBufferDescriptorSet;
de::MovePtr<BufferWithMemory> m_counterBuffer;
// properties commonly used by most of tests
VkExtent2D m_minTileSize;
VkExtent2D m_maxTileSize;
deUint32 m_maxAspectRatio;
};
AttachmentRateInstance::AttachmentRateInstance(Context& context, const de::SharedPtr<TestParams> params)
: vkt::TestInstance (context)
, m_params (params)
, m_cbWidth (60)
, m_cbHeight (60)
, m_cbFormat (VK_FORMAT_R32G32B32A32_UINT)
, m_cbUsage (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
, m_srUsage (VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT)
, m_defaultImageSubresourceLayers (makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u))
, m_defaultImageSubresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u))
, m_defaultBufferImageCopy (makeBufferImageCopy({ m_cbWidth, m_cbHeight, 1u }, m_defaultImageSubresourceLayers))
{
// prepare data needed to calculate tile sizes
const auto& srProperties = m_context.getFragmentShadingRateProperties();
m_minTileSize = srProperties.minFragmentShadingRateAttachmentTexelSize;
m_maxTileSize = srProperties.maxFragmentShadingRateAttachmentTexelSize;
m_maxAspectRatio = srProperties.maxFragmentShadingRateAttachmentTexelSizeAspectRatio;
}
de::MovePtr<ImageWithMemory> AttachmentRateInstance::buildImageWithMemory (VkFormat format,
deUint32 width,
deUint32 height,
VkImageUsageFlags usage,
VkImageTiling tiling,
std::vector<deUint32> queueFamilies)
{
VkImageCreateInfo imageCreateInfo
{
VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkImageCreateFlags)0u, // VkImageCreateFlags flags;
VK_IMAGE_TYPE_2D, // VkImageType imageType;
format, // VkFormat format;
{
width, // deUint32 width;
height, // deUint32 height;
1u // deUint32 depth;
}, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
tiling, // VkImageTiling tiling;
usage, // VkImageUsageFlags usage;
queueFamilies.empty() ?
VK_SHARING_MODE_EXCLUSIVE :
VK_SHARING_MODE_CONCURRENT, // VkSharingMode sharingMode;
(deUint32)queueFamilies.size(), // deUint32 queueFamilyIndexCount;
queueFamilies.data(), // const deUint32* pQueueFamilyIndices;
VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout;
};
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
vk::Allocator& allocator = m_allocator.get() ? *m_allocator : m_context.getDefaultAllocator();
vk::MemoryRequirement memoryRequirement = (tiling == VK_IMAGE_TILING_LINEAR) ? MemoryRequirement::HostVisible : MemoryRequirement::Any;
return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, imageCreateInfo, memoryRequirement));
}
de::MovePtr<BufferWithMemory> AttachmentRateInstance::buildBufferWithMemory(deUint32 size, VkBufferUsageFlags usage)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
vk::Allocator& allocator = m_allocator.get() ? *m_allocator : m_context.getDefaultAllocator();
const VkBufferCreateInfo readBufferInfo = makeBufferCreateInfo(size, usage);
return de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, allocator, readBufferInfo, MemoryRequirement::HostVisible));
}
Move<VkImageView> AttachmentRateInstance::buildImageView (VkFormat format, VkImage image)
{
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
return makeImageView(vk, device, image, VK_IMAGE_VIEW_TYPE_2D, format, subresourceRange);
};
void AttachmentRateInstance::buildColorBufferObjects(deUint32 cbIndex, VkImageUsageFlags cbUsage)
{
DE_ASSERT(cbIndex < 2);
m_cbImage[cbIndex] = buildImageWithMemory(m_cbFormat, m_cbWidth, m_cbHeight, cbUsage);
m_cbImageView[cbIndex] = buildImageView(m_cbFormat, m_cbImage[cbIndex]->get());
m_cbReadBuffer[cbIndex] = buildBufferWithMemory(m_cbWidth * m_cbHeight * deUint32(sizeof(int)) * 4u, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
}
void AttachmentRateInstance::buildShadingRateObjects(deUint32 srIndex, deUint32 width, deUint32 height, VkImageUsageFlags srUsage, VkImageTiling srTiling)
{
DE_ASSERT(srIndex < 2);
m_srImage[srIndex] = buildImageWithMemory(m_params->srFormat, width, height, srUsage, srTiling);
m_srImageView[srIndex] = buildImageView(m_params->srFormat, m_srImage[srIndex]->get());
}
void AttachmentRateInstance::buildCounterBufferObjects()
{
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
m_counterBufferDescriptorPool = DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
m_counterBufferDescriptorSetLayout = DescriptorSetLayoutBuilder()
.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
.build(vk, device);
const VkDescriptorSetAllocateInfo descriptorSetAllocInfo = makeDescriptorSetAllocInfo(*m_counterBufferDescriptorPool,
&(*m_counterBufferDescriptorSetLayout));
m_counterBufferDescriptorSet = allocateDescriptorSet(vk, device, &descriptorSetAllocInfo);
// create ssbo buffer for atomic counter
deUint32 ssboSize = deUint32(sizeof(deUint32));
m_counterBuffer = buildBufferWithMemory(ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
const VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(**m_counterBuffer, 0, ssboSize);
DescriptorSetUpdateBuilder()
.writeSingle(*m_counterBufferDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
.update(vk, device);
// reset counter
*((deUint32*)m_counterBuffer->getAllocation().getHostPtr()) = 0u;
flushAlloc(vk, device, m_counterBuffer->getAllocation());
}
Move<VkRenderPass> AttachmentRateInstance::buildRenderPass(VkFormat cbFormat,
deUint32 sr0TileWidth, deUint32 sr0TileHeight,
deUint32 sr1TileWidth, deUint32 sr1TileHeight) const
{
const bool useShadingRate0 = (sr0TileWidth * sr0TileHeight > 0);
const bool useShadingRate1 = (sr1TileWidth * sr1TileHeight > 0);
deUint32 attachmentCount = 1;
const deUint32 subpassCount = 1 + useShadingRate1;
std::vector<VkAttachmentReference2> colorAttachmentReferences(subpassCount, {
VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
DE_NULL, // const void* pNext;
0, // uint32_t attachment;
VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout layout;
0, // VkImageAspectFlags aspectMask;
});
std::vector<VkAttachmentReference2> fragmentShadingRateAttachments(subpassCount, {
VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
DE_NULL, // const void* pNext;
1, // uint32_t attachment;
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout layout;
0, // VkImageAspectFlags aspectMask;
});
std::vector<VkFragmentShadingRateAttachmentInfoKHR> shadingRateAttachmentInfos(subpassCount, {
VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
&fragmentShadingRateAttachments[0], // const VkAttachmentReference2* pFragmentShadingRateAttachment;
{ sr0TileWidth, sr0TileHeight }, // VkExtent2D shadingRateAttachmentTexelSize;
});
std::vector<VkSubpassDescription2> subpassDescriptions(subpassCount, {
VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, // VkStructureType sType;
DE_NULL, // const void* pNext;
(vk::VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
0u, // uint32_t viewMask;
0u, // uint32_t inputAttachmentCount;
DE_NULL, // const VkAttachmentReference2* pInputAttachments;
1, // uint32_t colorAttachmentCount;
&colorAttachmentReferences[0], // const VkAttachmentReference2* pColorAttachments;
DE_NULL, // const VkAttachmentReference2* pResolveAttachments;
DE_NULL, // const VkAttachmentReference2* pDepthStencilAttachment;
0u, // uint32_t preserveAttachmentCount;
DE_NULL, // const uint32_t* pPreserveAttachments;
});
std::vector<VkAttachmentDescription2> attachmentDescriptions(2 * subpassCount, {
VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
cbFormat, // 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_GENERAL, // VkImageLayout initialLayout;
VK_IMAGE_LAYOUT_GENERAL // VkImageLayout finalLayout;
});
if (useShadingRate0)
{
attachmentCount = 2;
subpassDescriptions[0].pNext = &shadingRateAttachmentInfos[0];
attachmentDescriptions[1].format = m_params->srFormat;
attachmentDescriptions[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachmentDescriptions[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
}
if (useShadingRate1)
{
attachmentCount = 4;
colorAttachmentReferences[1].attachment = 2;
fragmentShadingRateAttachments[1].attachment = 3;
shadingRateAttachmentInfos[1].pFragmentShadingRateAttachment = &fragmentShadingRateAttachments[1];
shadingRateAttachmentInfos[1].shadingRateAttachmentTexelSize = { sr1TileWidth, sr1TileHeight };
subpassDescriptions[1].pNext = &shadingRateAttachmentInfos[1];
subpassDescriptions[1].pColorAttachments = &colorAttachmentReferences[1];
attachmentDescriptions[3].format = m_params->srFormat;
attachmentDescriptions[3].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachmentDescriptions[3].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDescriptions[3].initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
}
const VkRenderPassCreateInfo2 renderPassParams
{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, // VkStructureType sType;
DE_NULL, // const void* pNext;
(vk::VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
attachmentCount, // uint32_t attachmentCount;
attachmentDescriptions.data(), // const VkAttachmentDescription2* pAttachments;
subpassCount, // uint32_t subpassCount;
subpassDescriptions.data(), // const VkSubpassDescription2* pSubpasses;
0u, // uint32_t dependencyCount;
DE_NULL, // const VkSubpassDependency2* pDependencies;
0u, // uint32_t correlatedViewMaskCount;
DE_NULL, // const uint32_t* pCorrelatedViewMasks;
};
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
return createRenderPass2(m_context.getDeviceInterface(), device, &renderPassParams);
}
Move<VkFramebuffer> AttachmentRateInstance::buildFramebuffer(VkRenderPass renderPass, const std::vector<FBAttachmentInfo>& attachmentInfo) const
{
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
VkFramebufferCreateInfo framebufferParams
{
vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(vk::VkFramebufferCreateFlags)0u, // VkFramebufferCreateFlags flags;
renderPass, // VkRenderPass renderPass;
(deUint32)attachmentInfo.size(), // uint32_t attachmentCount;
DE_NULL, // const VkImageView* pAttachments;
attachmentInfo[0].width, // uint32_t width;
attachmentInfo[0].height, // uint32_t height;
1u, // uint32_t layers;
};
if (m_params->useImagelessFramebuffer)
{
std::vector<VkFramebufferAttachmentImageInfo> framebufferAttachmentImageInfo(attachmentInfo.size(),
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkImageCreateFlags)0u, // VkImageCreateFlags flags;
0u, // VkImageUsageFlags usage;
0u, // deUint32 width;
0u, // deUint32 height;
1u, // deUint32 layerCount;
1u, // deUint32 viewFormatCount;
DE_NULL // const VkFormat* pViewFormats;
}
);
for (deUint32 i = 0; i < (deUint32)attachmentInfo.size(); ++i)
{
const auto& src = attachmentInfo[i];
auto& dst = framebufferAttachmentImageInfo[i];
dst.usage = src.usage;
dst.width = src.width;
dst.height = src.height;
dst.pViewFormats = &src.format;
}
VkFramebufferAttachmentsCreateInfo framebufferAttachmentsCreateInfo
{
VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(deUint32)framebufferAttachmentImageInfo.size(), // deUint32 attachmentImageInfoCount;
framebufferAttachmentImageInfo.data() // const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos;
};
framebufferParams.pNext = &framebufferAttachmentsCreateInfo;
framebufferParams.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
return createFramebuffer(m_context.getDeviceInterface(), device, &framebufferParams);
}
// create array containing just attachment views
std::vector<VkImageView> attachments(attachmentInfo.size(), 0);
for (deUint32 i = 0; i < (deUint32)attachmentInfo.size(); ++i)
attachments[i] = attachmentInfo[i].view;
framebufferParams.pAttachments = attachments.data();
return createFramebuffer(m_context.getDeviceInterface(), device, &framebufferParams);
}
Move<VkPipelineLayout> AttachmentRateInstance::buildPipelineLayout(const VkDescriptorSetLayout* setLayouts) const
{
const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags;
(setLayouts != DE_NULL), // uint32_t setLayoutCount;
setLayouts, // const VkDescriptorSetLayout* pSetLayouts;
0u, // uint32_t pushConstantRangeCount;
DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
};
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
return createPipelineLayout(m_context.getDeviceInterface(), device, &pipelineLayoutCreateInfo, NULL);
}
Move<VkPipeline> AttachmentRateInstance::buildGraphicsPipeline(deUint32 subpass, VkRenderPass renderPass, VkPipelineLayout pipelineLayout,
VkShaderModule vertShader, VkShaderModule fragShader, bool useShadingRate) const
{
std::vector<VkPipelineShaderStageCreateInfo> pipelineShaderStageParams(2,
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineShaderStageCreateFlags flags
VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage
vertShader, // VkShaderModule module
"main", // const char* pName
DE_NULL // const VkSpecializationInfo* pSpecializationInfo
});
pipelineShaderStageParams[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
pipelineShaderStageParams[1].module = fragShader;
const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
(VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags
0u, // deUint32 vertexBindingDescriptionCount
DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
0u, // deUint32 vertexAttributeDescriptionCount
DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
};
const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineInputAssemblyStateCreateFlags flags
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology topology
VK_FALSE // VkBool32 primitiveRestartEnable
};
tcu::UVec2 size (m_cbWidth, m_cbHeight);
VkViewport viewport = makeViewport (size);
VkRect2D scissor = makeRect2D (size);
const VkPipelineViewportStateCreateInfo viewportStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
(VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags
1u, // deUint32 viewportCount
&viewport, // const VkViewport* pViewports
1u, // deUint32 scissorCount
&scissor // const VkRect2D* pScissors
};
const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // 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
};
const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineMultisampleStateCreateFlags flags
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples
VK_FALSE, // VkBool32 sampleShadingEnable
1.0f, // float minSampleShading
DE_NULL, // const VkSampleMask* pSampleMask
VK_FALSE, // VkBool32 alphaToCoverageEnable
VK_FALSE // VkBool32 alphaToOneEnable
};
const VkStencilOpState stencilOpState
{
VK_STENCIL_OP_KEEP, // VkStencilOp failOp
VK_STENCIL_OP_KEEP, // VkStencilOp passOp
VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp
VK_COMPARE_OP_NEVER, // VkCompareOp compareOp
0, // deUint32 compareMask
0, // deUint32 writeMask
0 // deUint32 reference
};
const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineDepthStencilStateCreateFlags flags
VK_FALSE, // VkBool32 depthTestEnable
VK_FALSE, // VkBool32 depthWriteEnable
VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp
VK_FALSE, // VkBool32 depthBoundsTestEnable
VK_FALSE, // VkBool32 stencilTestEnable
stencilOpState, // VkStencilOpState front
stencilOpState, // VkStencilOpState back
0.0f, // float minDepthBounds
1.0f, // float maxDepthBounds
};
const VkPipelineColorBlendAttachmentState colorBlendAttachmentState
{
VK_FALSE, // VkBool32 blendEnable
VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask
| VK_COLOR_COMPONENT_G_BIT
| VK_COLOR_COMPONENT_B_BIT
| VK_COLOR_COMPONENT_A_BIT
};
const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineColorBlendStateCreateFlags flags
VK_FALSE, // VkBool32 logicOpEnable
VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp
1u, // deUint32 attachmentCount
&colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments
{ 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4]
};
const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
0u, // VkPipelineDynamicStateCreateFlags flags
0u, // deUint32 dynamicStateCount
DE_NULL // const VkDynamicState* pDynamicStates
};
VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
DE_NULL, // const void* pNext;
{ 1, 1 }, // VkExtent2D fragmentSize;
{ VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR } // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
};
const VkGraphicsPipelineCreateInfo pipelineCreateInfo
{
VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType
useShadingRate ? &shadingRateStateCreateInfo : DE_NULL, // const void* pNext
0u, // VkPipelineCreateFlags flags
(deUint32)pipelineShaderStageParams.size(), // deUint32 stageCount
&pipelineShaderStageParams[0], // const VkPipelineShaderStageCreateInfo* pStages
&vertexInputStateCreateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState
&inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState
DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState
&viewportStateCreateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState
&rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState
&multisampleStateCreateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState
&depthStencilStateCreateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState
&colorBlendStateCreateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState
&dynamicStateCreateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState
pipelineLayout, // VkPipelineLayout layout
renderPass, // VkRenderPass renderPass
subpass, // deUint32 subpass
DE_NULL, // VkPipeline basePipelineHandle
0 // deInt32 basePipelineIndex;
};
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
return createGraphicsPipeline(m_context.getDeviceInterface(), device, DE_NULL, &pipelineCreateInfo);
}
Move<VkPipeline> AttachmentRateInstance::buildComputePipeline(VkShaderModule compShader, VkPipelineLayout pipelineLayout) const
{
const VkPipelineShaderStageCreateInfo stageCreateInfo
{
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineShaderStageCreateFlags flags;
VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
compShader, // VkShaderModule module;
"main", // const char* pName;
DE_NULL // const VkSpecializationInfo* pSpecializationInfo;
};
const VkComputePipelineCreateInfo createInfo
{
VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // VkPipelineCreateFlags flags;
stageCreateInfo, // VkPipelineShaderStageCreateInfo stage;
pipelineLayout, // VkPipelineLayout layout;
(VkPipeline)0, // VkPipeline basePipelineHandle;
0u, // int32_t basePipelineIndex;
};
VkDevice device = m_device.get() ? *m_device : m_context.getDevice();
return createComputePipeline(m_context.getDeviceInterface(), device, (vk::VkPipelineCache)0u, &createInfo);
}
VkDescriptorSetAllocateInfo AttachmentRateInstance::makeDescriptorSetAllocInfo(VkDescriptorPool descriptorPool, const VkDescriptorSetLayout* pSetLayouts) const
{
return
{
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
descriptorPool, // VkDescriptorPool descriptorPool;
1u, // uint32_t setLayoutCount;
pSetLayouts, // const VkDescriptorSetLayout* pSetLayouts;
};
}
void AttachmentRateInstance::startRendering(const VkCommandBuffer commandBuffer,
const VkRenderPass renderPass,
const VkFramebuffer framebuffer,
const VkRect2D& renderArea,
const std::vector<FBAttachmentInfo>& attachmentInfo) const
{
const DeviceInterface& vk (m_context.getDeviceInterface());
std::vector<VkClearValue> clearColor (attachmentInfo.size(), makeClearValueColorU32(0, 0, 0, 0));
std::vector<VkImageView> attachments (attachmentInfo.size(), 0);
VkRenderPassAttachmentBeginInfo renderPassAttachmentBeginInfo;
void* pNext (DE_NULL);
if (m_params->useImagelessFramebuffer)
{
// create array containing attachment views
for (deUint32 i = 0; i < (deUint32)attachmentInfo.size(); ++i)
attachments[i] = attachmentInfo[i].view;
renderPassAttachmentBeginInfo =
{
VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(deUint32)attachments.size(), // deUint32 attachmentCount;
attachments.data() // const VkImageView* pAttachments;
};
pNext = &renderPassAttachmentBeginInfo;
}
beginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea,
(deUint32)clearColor.size(), clearColor.data(), VK_SUBPASS_CONTENTS_INLINE, pNext);
}
void AttachmentRateInstance::finishRendering(const VkCommandBuffer commandBuffer) const
{
const DeviceInterface& vk = m_context.getDeviceInterface();
endRenderPass(vk, commandBuffer);
}
tcu::TestStatus AttachmentRateInstance::iterate(void)
{
// instead of creating many classes that derive from large common class
// each test mode is defined in separate run* method, those methods
// then use same helper methods defined in this class
typedef bool (AttachmentRateInstance::*MethodPtr)();
const std::map<TestMode, MethodPtr> modeFuncMap
{
{ TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER, &AttachmentRateInstance::runComputeShaderMode },
{ TM_SETUP_RATE_WITH_FRAGMENT_SHADER, &AttachmentRateInstance::runFragmentShaderMode },
{ TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE, &AttachmentRateInstance::runCopyMode },
{ TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE, &AttachmentRateInstance::runCopyModeOnTransferQueue },
{ TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE, &AttachmentRateInstance::runCopyModeOnTransferQueue },
{ TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE, &AttachmentRateInstance::runFillLinearTiledImage },
{ TM_TWO_SUBPASS, &AttachmentRateInstance::runTwoSubpassMode },
};
if ((this->*modeFuncMap.at(m_params->mode))())
return tcu::TestStatus::pass("Pass");
return tcu::TestStatus::fail("Fail");
}
bool AttachmentRateInstance::verifyUsingAtomicChecks(deUint32 tileWidth, deUint32 tileHeight,
deUint32 rateWidth, deUint32 rateHeight,
deUint32* outBufferPtr) const
{
tcu::TestLog& log (m_context.getTestContext().getLog());
tcu::TextureLevel errorMaskStorage (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_cbWidth, m_cbHeight, 1u);
tcu::PixelBufferAccess errorMaskAccess (errorMaskStorage.getAccess());
deUint32 wrongFragments = 0;
const deUint32 fragmentsWithSameAtomicValueCount = rateWidth * rateHeight;
// map that uses atomic value as a kay and maps it to all fragments sharing same atomic
std::map<deUint32, std::vector<tcu::UVec2> > fragmentsWithSameAtomicValueMap;
// this method asumes that top and left edge of triangle are parallel to axes
// and we can store just single coordinate for those edges
deUint32 triangleLeftEdgeX = 0;
deUint32 triangleTopEdgeY = 0;
// this method assumes that greatest angle in the triangle points to the top-left corner of FB;
// this vector will then store fragments on the right edge of triangle; vector index represents y coordinate and value is x
std::vector<deUint32> fragmentsOnTheRightTriangleEdgeVect(m_cbHeight, 0);
tcu::clear(errorMaskAccess, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0));
// loop over all fragments and validate the output
for (deUint32 cbFragmentY = 0; cbFragmentY < m_cbHeight; ++cbFragmentY)
for (deUint32 cbFragmentX = 0; cbFragmentX < m_cbWidth; ++cbFragmentX)
{
deUint32* fragmentColor = &outBufferPtr[4 * (cbFragmentY * m_cbWidth + cbFragmentX)];
// fragment not covered by primitive, skip it
if (fragmentColor[2] == 0)
continue;
// first fragment we hit will define top and left triangle edges
if ((triangleTopEdgeY + triangleLeftEdgeX) == 0)
{
triangleLeftEdgeX = cbFragmentX;
triangleTopEdgeY = cbFragmentY;
}
// constantly overwrite coordinate on right edge so that we are left with the farthest one
fragmentsOnTheRightTriangleEdgeVect[cbFragmentY] = cbFragmentX;
// make sure that fragment g and a components are 0
if ((fragmentColor[1] != 0) || (fragmentColor[3] != 0))
{
++wrongFragments;
continue;
}
deUint32 rate = fragmentColor[0];
deUint32 fragmentRateX = 1 << ((rate / 4) & 3);
deUint32 fragmentRateY = 1 << (rate & 3);
// check if proper rate was used for fragment
if ((fragmentRateX != rateWidth) ||
(fragmentRateY != rateHeight))
{
++wrongFragments;
errorMaskAccess.setPixel(tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f), cbFragmentX, cbFragmentY, 0u);
continue;
}
// mark correct fragments using few green shades so rates are visible
deUint32 atomicValue = fragmentColor[2];
errorMaskAccess.setPixel(tcu::Vec4(0.0f, 1.0f - float(atomicValue % 7) * 0.1f, 0.0f, 1.0f), cbFragmentX, cbFragmentY, 0u);
// find proper set in map and add value to it after doing verification with existing items
auto fragmentsSetMapIt = fragmentsWithSameAtomicValueMap.find(atomicValue);
if (fragmentsSetMapIt == fragmentsWithSameAtomicValueMap.end())
{
fragmentsWithSameAtomicValueMap[atomicValue] = { tcu::UVec2(cbFragmentX, cbFragmentY) };
fragmentsWithSameAtomicValueMap[atomicValue].reserve(fragmentsWithSameAtomicValueCount);
}
else
{
// make sure that fragments added to set are near the top-left fragment
auto& fragmentsSet = fragmentsSetMapIt->second;
if (((cbFragmentX - fragmentsSet[0].x()) > rateWidth) ||
((cbFragmentY - fragmentsSet[0].y()) > rateHeight))
{
++wrongFragments;
errorMaskAccess.setPixel(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), cbFragmentX, cbFragmentY, 0u);
}
fragmentsWithSameAtomicValueMap[atomicValue].emplace_back(cbFragmentX, cbFragmentY);
}
}
// check if there are no valid fragmenst at all
if ((triangleTopEdgeY + triangleLeftEdgeX) == 0)
{
log << tcu::TestLog::Message
<< "No valid fragments."
<< tcu::TestLog::EndMessage;
return false;
}
// if checks failed skip checking other tile sizes
if (wrongFragments)
{
log << tcu::TestLog::Message
<< "Failed " << wrongFragments << " fragments for tileWidth: " << tileWidth << ", tileHeight: " << tileHeight
<< tcu::TestLog::EndMessage
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMaskAccess);
return false;
}
// do additional checks
tcu::Vec4 fragmentColor(0.0f, 1.0f, 0.0f, 1.0f);
tcu::clear(errorMaskAccess, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0));
// make sure that there is same number of fragments that share same atomic value
for (auto& fragmentsSetMapIt : fragmentsWithSameAtomicValueMap)
{
// mark correct fragments using few green shades so rates are visible
fragmentColor = tcu::Vec4(0.0f, 1.0f - float(fragmentsSetMapIt.first % 7) * 0.1f, 0.0f, 1.0f);
const auto& fragmentSet = fragmentsSetMapIt.second;;
if (fragmentSet.size() != fragmentsWithSameAtomicValueCount)
{
const auto& topLeftFragment = fragmentSet[0];
deUint32 triangleRightEdgeX = fragmentsOnTheRightTriangleEdgeVect[topLeftFragment.y()];
// we can only count this as an error if set is fully inside of triangle, sets on
// edges may not have same number of fragments as sets fully located in the triangle
if ((topLeftFragment.y() > (triangleTopEdgeY)) &&
(topLeftFragment.x() > (triangleLeftEdgeX)) &&
(topLeftFragment.x() < (triangleRightEdgeX - rateWidth)))
{
wrongFragments += (deUint32)fragmentSet.size();
fragmentColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
}
// mark all fragmens from set with proper color
for (auto& fragment : fragmentSet)
errorMaskAccess.setPixel(fragmentColor, fragment.x(), fragment.y(), 0u);
}
if (wrongFragments)
{
log << tcu::TestLog::Message
<< "Wrong number of fragments with same atomic value (" << wrongFragments << ") for tileWidth: " << tileWidth << ", tileHeight: " << tileHeight
<< tcu::TestLog::EndMessage
<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMaskAccess);
return false;
}
return true;
}
bool AttachmentRateInstance::runComputeShaderMode(void)
{
// clear the shading rate attachment, then using a compute shader, set the shading rate attachment
// values to the desired rate using various atomic operations, then use it to draw a basic triangle
// and do basic checks
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_context.getDevice();
deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
VkMemoryBarrier memoryBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u };
Move<VkShaderModule> compShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0);
Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
// setup descriptor set with storage image for compute pipeline
Move<VkDescriptorSetLayout> computeDescriptorSetLayout = DescriptorSetLayoutBuilder()
.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
.build(vk, device);
Move<VkDescriptorPool> computeDescriptorPool = DescriptorPoolBuilder()
.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
const VkDescriptorSetAllocateInfo computeDescriptorSetAllocInfo = makeDescriptorSetAllocInfo(*computeDescriptorPool, &(*computeDescriptorSetLayout));
Move<VkDescriptorSet> computeDescriptorSet = allocateDescriptorSet(vk, device, &computeDescriptorSetAllocInfo);
m_srUsage |= VK_IMAGE_USAGE_STORAGE_BIT;
buildCounterBufferObjects();
buildColorBufferObjects(0, m_cbUsage);
// iterate over all possible tile sizes
for (deUint32 tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
for (deUint32 tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
{
// skip tile sizes that have unsuported aspect ratio
deUint32 aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
if (aspectRatio > m_maxAspectRatio)
continue;
// calculate size of shading rate attachment
deUint32 srWidth = (m_cbWidth + tileWidth - 1) / tileWidth;
deUint32 srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
buildShadingRateObjects(0, srWidth, srHeight, m_srUsage);
const VkDescriptorImageInfo computeDescriptorInfo = makeDescriptorImageInfo(DE_NULL, *m_srImageView[0], VK_IMAGE_LAYOUT_GENERAL);
DescriptorSetUpdateBuilder()
.writeSingle(*computeDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &computeDescriptorInfo)
.update(vk, device);
Move<VkPipelineLayout> computePipelineLayout = buildPipelineLayout(&(*computeDescriptorSetLayout));
Move<VkPipelineLayout> graphicsPipelineLayout = buildPipelineLayout(&(*m_counterBufferDescriptorSetLayout));
Move<VkPipeline> computePipeline = buildComputePipeline(*compShader, *computePipelineLayout);
Move<VkRenderPass> renderPass = buildRenderPass(m_cbFormat, tileWidth, tileHeight);
Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(0, *renderPass, *graphicsPipelineLayout, *vertShader, *fragShader);
std::vector<FBAttachmentInfo> attachmentInfo
{
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0] },
{ m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0] }
};
Move<VkFramebuffer> framebuffer = buildFramebuffer(*renderPass, attachmentInfo);
beginCommandBuffer(vk, *cmdBuffer, 0u);
// wait till sr image layout is changed
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
VkImageMemoryBarrier srImageBarrierGeneral =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_NONE_KHR,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierGeneral);
// fill sr image using compute shader
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0, 1, &(*computeDescriptorSet), 0, DE_NULL);
vk.cmdDispatch(*cmdBuffer, srWidth, srHeight, 1);
// wait till sr image is ready and change sr images layout
srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
VkImageMemoryBarrier srImageBarrierShadingRate =
makeImageMemoryBarrier(
VK_ACCESS_SHADER_WRITE_BIT,
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 1, &srImageBarrierShadingRate);
// wait till cb image layout is changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier cbImageBarrier =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_cbImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &cbImageBarrier);
startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo);
// draw single triangle to cb
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1, &(*m_counterBufferDescriptorSet), 0, DE_NULL);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*cmdBuffer);
// wait till color attachment is fully written
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// read back color buffer image
vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u, &m_defaultBufferImageCopy);
endCommandBuffer(vk, *cmdBuffer);
// submit commands and wait
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
if (!verifyUsingAtomicChecks(tileWidth, tileHeight,
m_params->srRate.width, m_params->srRate.height,
(deUint32*)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
return false;
} // iterate over all possible tile sizes
return true;
}
bool AttachmentRateInstance::runFragmentShaderMode(void)
{
// Set up the image as a color attachment, and render rate to it,
// then use it to draw a basic triangle and do basic checks
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_context.getDevice();
deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
VkMemoryBarrier memoryBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u };
Move<VkShaderModule> vertSetupShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert_setup"), 0);
Move<VkShaderModule> fragSetupShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag_setup"), 0);
Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
m_srUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
buildCounterBufferObjects();
buildColorBufferObjects(0, m_cbUsage);
// iterate over all possible tile sizes
for (deUint32 tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
for (deUint32 tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
{
// skip tile sizes that have unsuported aspect ratio
deUint32 aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
if (aspectRatio > m_maxAspectRatio)
continue;
// calculate size of shading rate attachment
deUint32 srWidth = (m_cbWidth + tileWidth - 1) / tileWidth;
deUint32 srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
buildShadingRateObjects(0, srWidth, srHeight, m_srUsage);
Move<VkPipelineLayout> setupPipelineLayout = buildPipelineLayout();
Move<VkPipelineLayout> ratePipelineLayout = buildPipelineLayout(&(*m_counterBufferDescriptorSetLayout));
Move<VkRenderPass> setupRenderPass = buildRenderPass(m_params->srFormat);
Move<VkRenderPass> rateRenderPass = buildRenderPass(m_cbFormat, tileWidth, tileHeight);
Move<VkPipeline> setupPipeline = buildGraphicsPipeline(0, *setupRenderPass, *setupPipelineLayout, *vertSetupShader, *fragSetupShader, DE_FALSE);
Move<VkPipeline> ratePipeline = buildGraphicsPipeline(0, *rateRenderPass, *ratePipelineLayout, *vertShader, *fragShader);
std::vector<FBAttachmentInfo> setupAttachmentInfo
{
{ m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0] }
};
std::vector<FBAttachmentInfo> rateAttachmentInfo
{
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0] },
{ m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0] }
};
Move<VkFramebuffer> setupFramebuffer = buildFramebuffer(*setupRenderPass, setupAttachmentInfo);
Move<VkFramebuffer> rateFramebuffer = buildFramebuffer(*rateRenderPass, rateAttachmentInfo);
beginCommandBuffer(vk, *cmdBuffer, 0u);
// wait till sr image layout is changed
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier srImageBarrierGeneral =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierGeneral);
// render rate to sr image
startRendering(*cmdBuffer, *setupRenderPass, *setupFramebuffer, makeRect2D(srWidth, srHeight), setupAttachmentInfo);
// draw single triangle to cb
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *setupPipeline);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*cmdBuffer);
// wait till sr image is ready and change sr images layout
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
VkImageMemoryBarrier srImageBarrierShadingRate =
makeImageMemoryBarrier(
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierShadingRate);
// wait till cb image layout is changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier cbImageBarrier =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_cbImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &cbImageBarrier);
startRendering(*cmdBuffer, *rateRenderPass, *rateFramebuffer, makeRect2D(m_cbWidth, m_cbHeight), rateAttachmentInfo);
// draw single triangle to cb
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *ratePipelineLayout, 0, 1, &(*m_counterBufferDescriptorSet), 0, DE_NULL);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *ratePipeline);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*cmdBuffer);
// wait till color attachment is fully written
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// read back color buffer image
vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u, &m_defaultBufferImageCopy);
endCommandBuffer(vk, *cmdBuffer);
// submit commands and wait
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
if (!verifyUsingAtomicChecks(tileWidth, tileHeight,
m_params->srRate.width, m_params->srRate.height,
(deUint32*)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
return false;
} // iterate over all possible tile sizes
return true;
}
bool AttachmentRateInstance::runCopyMode (void)
{
// Clear a separate image of the same format to that rate, copy it to
// the shading rate image, then use it to draw a basic triangle and do basic checks
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_context.getDevice();
deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
VkMemoryBarrier memoryBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u };
Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
buildCounterBufferObjects();
buildColorBufferObjects(0, m_cbUsage);
// iterate over all possible tile sizes
for (deUint32 tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
for (deUint32 tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
{
// skip tile sizes that have unsuported aspect ratio
deUint32 aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
if (aspectRatio > m_maxAspectRatio)
continue;
// calculate size of shading rate attachment
deUint32 srWidth = (m_cbWidth + tileWidth - 1) / tileWidth;
deUint32 srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
buildShadingRateObjects(0, srWidth, srHeight, m_srUsage);
// create image that will be source for shading rate image
de::MovePtr<ImageWithMemory> srSrcImage = buildImageWithMemory(m_params->srFormat, srWidth, srHeight, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
Move<VkPipelineLayout> graphicsPipelineLayout = buildPipelineLayout(&(*m_counterBufferDescriptorSetLayout));
Move<VkRenderPass> renderPass = buildRenderPass(m_cbFormat, tileWidth, tileHeight);
Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(0, *renderPass, *graphicsPipelineLayout, *vertShader, *fragShader);
std::vector<FBAttachmentInfo> attachmentInfo
{
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0] },
{ m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0] }
};
Move<VkFramebuffer> framebuffer = buildFramebuffer(*renderPass, attachmentInfo);
beginCommandBuffer(vk, *cmdBuffer, 0u);
// wait till sr images layout are changed
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
std::vector<VkImageMemoryBarrier> srImageBarrierGeneral(2,
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_NONE_KHR,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_srImage[0],
m_defaultImageSubresourceRange));
srImageBarrierGeneral[1].image = **srSrcImage;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 2, srImageBarrierGeneral.data());
// clear source sr image with proper rate
VkClearColorValue clearValue = { { 0, 0, 0, 0 } };
clearValue.uint32[0] = calculateRate(m_params->srRate.width, m_params->srRate.height);
vk.cmdClearColorImage(*cmdBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &m_defaultImageSubresourceRange);
// wait till sr source image is ready
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// copy sr source image to sr image used during rendering
VkImageCopy imageCopyRegion
{
m_defaultImageSubresourceLayers, // VkImageSubresourceLayers srcSubresource;
{0, 0, 0}, // VkOffset3D srcOffset;
m_defaultImageSubresourceLayers, // VkImageSubresourceLayers dstSubresource;
{0, 0, 0}, // VkOffset3D dstOffset;
{ srWidth, srHeight, 1u } // VkExtent3D extent;
};
vk.cmdCopyImage(*cmdBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0], VK_IMAGE_LAYOUT_GENERAL, 1, &imageCopyRegion);
// wait till sr image is ready and change sr images layout
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
VkImageMemoryBarrier srImageBarrierShadingRate =
makeImageMemoryBarrier(
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 1, &srImageBarrierShadingRate);
// wait till cb image layout is changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier cbImageBarrier =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_cbImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &cbImageBarrier);
startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo);
// draw single triangle to cb
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1, &(*m_counterBufferDescriptorSet), 0, DE_NULL);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*cmdBuffer);
// wait till color attachment is fully written
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// read back color buffer image
vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u, &m_defaultBufferImageCopy);
endCommandBuffer(vk, *cmdBuffer);
// submit commands and wait
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
if (!verifyUsingAtomicChecks(tileWidth, tileHeight,
m_params->srRate.width, m_params->srRate.height,
(deUint32*)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
return false;
} // iterate over all possible tile sizes
return true;
}
bool AttachmentRateInstance::runCopyModeOnTransferQueue(void)
{
// Clear a separate image of the same format to that rate, copy it to
// the shading rate image on separate transfer queue and then use copied
// image to draw a basic triangle and do basic checks
const DeviceInterface& vk = m_context.getDeviceInterface();
const PlatformInterface& vkp = m_context.getPlatformInterface();
const InstanceInterface& vki = m_context.getInstanceInterface();
VkPhysicalDevice pd = m_context.getPhysicalDevice();
deUint32 transferQueueFamilyIndex = std::numeric_limits<deUint32>::max();
deUint32 graphicsQueueFamilyIndex = std::numeric_limits<deUint32>::max();
VkMemoryBarrier memoryBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u };
std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(vki, pd);
// find graphics and transfer queue families
for (deUint32 queueNdx = 0; queueNdx < queueFamilyProperties.size(); queueNdx++)
{
VkQueueFlags queueFlags = queueFamilyProperties[queueNdx].queueFlags;
if ((graphicsQueueFamilyIndex == std::numeric_limits<deUint32>::max()) && (queueFlags & VK_QUEUE_GRAPHICS_BIT))
graphicsQueueFamilyIndex = queueNdx;
else if ((queueNdx != graphicsQueueFamilyIndex) && (queueFlags & VK_QUEUE_TRANSFER_BIT))
transferQueueFamilyIndex = queueNdx;
}
if (transferQueueFamilyIndex == std::numeric_limits<deUint32>::max())
TCU_THROW(NotSupportedError, "No separate transfer queue");
// using queueFamilies vector to determine if sr image uses exclusiv or concurrent sharing
std::vector<deUint32> queueFamilies;
if (m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE)
queueFamilies = { graphicsQueueFamilyIndex, transferQueueFamilyIndex };
// create custom device
{
const float queuePriorities = 1.0f;
std::vector<VkDeviceQueueCreateInfo> queueInfo(2,
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
(VkDeviceQueueCreateFlags)0u, // VkDeviceQueueCreateFlags flags;
transferQueueFamilyIndex, // uint32_t queueFamilyIndex;
1u, // uint32_t queueCount;
&queuePriorities // const float* pQueuePriorities;
});
queueInfo[1].queueFamilyIndex = graphicsQueueFamilyIndex;
VkPhysicalDeviceFeatures deviceFeatures;
vki.getPhysicalDeviceFeatures(pd, &deviceFeatures);
VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsrFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR, DE_NULL, DE_FALSE, DE_FALSE, DE_TRUE };
VkPhysicalDeviceImagelessFramebufferFeatures ifbFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, DE_NULL, DE_TRUE };
VkPhysicalDeviceFeatures2 createPhysicalFeature { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &fsrFeatures, deviceFeatures };
std::vector<const char*> enabledExtensions = { "VK_KHR_fragment_shading_rate" };
if (m_params->useImagelessFramebuffer)
{
enabledExtensions.push_back("VK_KHR_imageless_framebuffer");
fsrFeatures.pNext = &ifbFeatures;
}
std::vector<const char*> enabledLayers = getValidationLayers(vki, pd);
VkDeviceCreateInfo deviceInfo
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType;
&createPhysicalFeature, // const void* pNext;
(VkDeviceCreateFlags)0u, // VkDeviceCreateFlags flags;
2u, // uint32_t queueCreateInfoCount;
queueInfo.data(), // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
static_cast<deUint32>(enabledLayers.size()), // uint32_t enabledLayerCount;
de::dataOrNull(enabledLayers), // const char* const* ppEnabledLayerNames;
static_cast<deUint32>(enabledExtensions.size()), // uint32_t enabledExtensionCount;
enabledExtensions.data(), // const char* const* ppEnabledExtensionNames;
DE_NULL // const VkPhysicalDeviceFeatures* pEnabledFeatures;
};
m_device = createDevice(vkp, m_context.getInstance(), vki, pd, &deviceInfo);
m_allocator = de::MovePtr<Allocator>(new SimpleAllocator(m_context.getDeviceInterface(), *m_device, getPhysicalDeviceMemoryProperties(vki, pd)));
}
VkQueue transferQueue;
vk.getDeviceQueue(*m_device, transferQueueFamilyIndex, 0u, &transferQueue);
VkQueue graphicsQueue;
vk.getDeviceQueue(*m_device, graphicsQueueFamilyIndex, 0u, &graphicsQueue);
// create transfer and graphics command buffers
Move<VkCommandPool> transferCmdPool = createCommandPool(vk, *m_device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, transferQueueFamilyIndex);
Move<VkCommandBuffer> transferCmdBuffer = allocateCommandBuffer(vk, *m_device, *transferCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
Move<VkCommandPool> graphicsCmdPool = createCommandPool(vk, *m_device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, graphicsQueueFamilyIndex);
Move<VkCommandBuffer> graphicsCmdBuffer = allocateCommandBuffer(vk, *m_device, *graphicsCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
Move<VkShaderModule> vertShader = createShaderModule(vk, *m_device, m_context.getBinaryCollection().get("vert"), 0);
Move<VkShaderModule> fragShader = createShaderModule(vk, *m_device, m_context.getBinaryCollection().get("frag"), 0);
buildColorBufferObjects(0, m_cbUsage);
buildCounterBufferObjects();
// iterate over all possible tile sizes
for (deUint32 tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
for (deUint32 tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
{
// skip tile sizes that have unsuported aspect ratio
deUint32 aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
if (aspectRatio > m_maxAspectRatio)
continue;
// calculate size of shading rate attachment
deUint32 srWidth = (m_cbWidth + tileWidth - 1) / tileWidth;
deUint32 srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
// create image that will be source for shading rate image
de::MovePtr<ImageWithMemory> srSrcImage = buildImageWithMemory(m_params->srFormat, srWidth, srHeight,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
// create buffer that will contain shading rate source data
tcu::TextureFormat srTextureFormat = mapVkFormat(m_params->srFormat);
deUint32 srWriteBufferSize = srWidth * srHeight * getNumUsedChannels(srTextureFormat.order) * getChannelSize(srTextureFormat.type);
de::MovePtr<BufferWithMemory> srSrcBuffer = buildBufferWithMemory(srWriteBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
// fill buffer with tested shading rate
deUint8* srWriteBufferHostPtr = (deUint8*)srSrcBuffer->getAllocation().getHostPtr();
deUint8 value = (deUint8)calculateRate(m_params->srRate.width, m_params->srRate.height);
deMemset(srWriteBufferHostPtr, value, (size_t)srWriteBufferSize);
flushAlloc(vk, *m_device, srSrcBuffer->getAllocation());
// create shading rate iamge
m_srImage[0] = buildImageWithMemory(m_params->srFormat, srWidth, srHeight,
VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
VK_IMAGE_TILING_OPTIMAL, queueFamilies);
m_srImageView[0] = buildImageView(m_params->srFormat, m_srImage[0]->get());
Move<VkPipelineLayout> graphicsPipelineLayout = buildPipelineLayout(&(*m_counterBufferDescriptorSetLayout));
Move<VkRenderPass> renderPass = buildRenderPass(m_cbFormat, tileWidth, tileHeight);
Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(0, *renderPass, *graphicsPipelineLayout, *vertShader, *fragShader);
std::vector<FBAttachmentInfo> attachmentInfo
{
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0] },
{ m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0] }
};
Move<VkFramebuffer> framebuffer = buildFramebuffer(*renderPass, attachmentInfo);
beginCommandBuffer(vk, *transferCmdBuffer, 0u);
// wait till sr data is ready in buffer and change sr image layouts to general
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
std::vector<VkImageMemoryBarrier> srImageBarrierGeneral(2,
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_NONE_KHR,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_srImage[0],
m_defaultImageSubresourceRange));
srImageBarrierGeneral[1].image = **srSrcImage;
vk.cmdPipelineBarrier(*transferCmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 2, srImageBarrierGeneral.data());
// copy sr data to images
const VkBufferImageCopy srCopyBuffer = makeBufferImageCopy({ srWidth, srHeight, 1u }, m_defaultImageSubresourceLayers);
vk.cmdCopyBufferToImage(*transferCmdBuffer, **srSrcBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, 1, &srCopyBuffer);
// wait till sr source image is ready
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*transferCmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// copy sr source image to sr image used during rendering
VkImageCopy imageCopyRegion
{
m_defaultImageSubresourceLayers, // VkImageSubresourceLayers srcSubresource;
{0, 0, 0}, // VkOffset3D srcOffset;
m_defaultImageSubresourceLayers, // VkImageSubresourceLayers dstSubresource;
{0, 0, 0}, // VkOffset3D dstOffset;
{ srWidth, srHeight, 1u } // VkExtent3D extent;
};
vk.cmdCopyImage(*transferCmdBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0], VK_IMAGE_LAYOUT_GENERAL, 1, &imageCopyRegion);
// release exclusive ownership from the transfer queue family
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkImageMemoryBarrier srImageBarrierOwnershipTransfer =
makeImageMemoryBarrier(
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_NONE_KHR,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_GENERAL,
**m_srImage[0], m_defaultImageSubresourceRange);
if (m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE)
{
srImageBarrierOwnershipTransfer.srcQueueFamilyIndex = transferQueueFamilyIndex;
srImageBarrierOwnershipTransfer.dstQueueFamilyIndex = graphicsQueueFamilyIndex;
}
vk.cmdPipelineBarrier(*transferCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierOwnershipTransfer);
endCommandBuffer(vk, *transferCmdBuffer);
beginCommandBuffer(vk, *graphicsCmdBuffer, 0u);
// acquire exclusive ownership for the graphics queue family - while changing sr images layout
vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierOwnershipTransfer);
// wait till sr image layout is changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
VkImageMemoryBarrier srImageBarrierShadingRate =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierShadingRate);
// wait till cb image layout is changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier cbImageBarrier =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_cbImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &cbImageBarrier);
startRendering(*graphicsCmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo);
// draw single triangle to cb
vk.cmdBindDescriptorSets(*graphicsCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1, &(*m_counterBufferDescriptorSet), 0, DE_NULL);
vk.cmdBindPipeline(*graphicsCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
vk.cmdDraw(*graphicsCmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*graphicsCmdBuffer);
// wait till color attachment is fully written
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// read back color buffer image
vk.cmdCopyImageToBuffer(*graphicsCmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u, &m_defaultBufferImageCopy);
endCommandBuffer(vk, *graphicsCmdBuffer);
// create synchronization objects
Move<VkSemaphore> semaphore = createSemaphore(vk, *m_device);
Move<VkFence> transferFence = createFence(vk, *m_device);
Move<VkFence> graphicsFence = createFence(vk, *m_device);
const VkSubmitInfo transferSubmitInfo
{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
0u, // deUint32 waitSemaphoreCount;
DE_NULL, // const VkSemaphore* pWaitSemaphores;
DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask;
1u, // deUint32 commandBufferCount;
&*transferCmdBuffer, // const VkCommandBuffer* pCommandBuffers;
1u, // deUint32 signalSemaphoreCount;
&*semaphore, // const VkSemaphore* pSignalSemaphores;
};
const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
const VkSubmitInfo graphicsSubmitInfo
{
VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
DE_NULL, // const void* pNext;
1u, // deUint32 waitSemaphoreCount;
&*semaphore, // const VkSemaphore* pWaitSemaphores;
&waitDstStageMask, // const VkPipelineStageFlags* pWaitDstStageMask;
1u, // deUint32 commandBufferCount;
&*graphicsCmdBuffer, // const VkCommandBuffer* pCommandBuffers;
0u, // deUint32 signalSemaphoreCount;
DE_NULL, // const VkSemaphore* pSignalSemaphores;
};
// submit commands to both queues
VK_CHECK(vk.queueSubmit(transferQueue, 1u, &transferSubmitInfo, *transferFence));
VK_CHECK(vk.queueSubmit(graphicsQueue, 1u, &graphicsSubmitInfo, *graphicsFence));
VkFence fences[] = { *graphicsFence, *transferFence };
VK_CHECK(vk.waitForFences(*m_device, 2u, fences, DE_TRUE, ~0ull));
invalidateAlloc(vk, *m_device, m_cbReadBuffer[0]->getAllocation());
if (!verifyUsingAtomicChecks(tileWidth, tileHeight,
m_params->srRate.width, m_params->srRate.height,
(deUint32*)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
return false;
} // iterate over all possible tile sizes
return true;
}
bool AttachmentRateInstance::runFillLinearTiledImage(void)
{
// Create a linear tiled fragment shading rate attachment image and set
// its data on the host, then draw a basic triangle and do basic checks
const DeviceInterface& vk = m_context.getDeviceInterface();
VkDevice device = m_context.getDevice();
deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
VkImageSubresource imageSubresource = makeImageSubresource(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u);
VkMemoryBarrier memoryBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u };
VkSubresourceLayout srImageLayout;
Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
buildCounterBufferObjects();
buildColorBufferObjects(0, m_cbUsage);
// iterate over all possible tile sizes
for (deUint32 tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
for (deUint32 tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
{
// skip tile sizes that have unsuported aspect ratio
deUint32 aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
if (aspectRatio > m_maxAspectRatio)
continue;
// calculate size of shading rate attachment
deUint32 srWidth = (m_cbWidth + tileWidth - 1) / tileWidth;
deUint32 srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
buildShadingRateObjects(0, srWidth, srHeight, m_srUsage, VK_IMAGE_TILING_LINEAR);
deUint8* imagePtr = reinterpret_cast<deUint8*>(m_srImage[0]->getAllocation().getHostPtr());
deUint8 value = (deUint8)calculateRate(m_params->srRate.width, m_params->srRate.height);
// fill sr image on the host row by row
vk.getImageSubresourceLayout(device, **m_srImage[0], &imageSubresource, &srImageLayout);
for (deUint32 srTexelRow = 0; srTexelRow < srHeight; srTexelRow++)
{
deUint8* rowDst = imagePtr + srImageLayout.offset + srImageLayout.rowPitch * srTexelRow;
deMemset(rowDst, value, (size_t)srWidth);
}
Move<VkPipelineLayout> graphicsPipelineLayout = buildPipelineLayout(&(*m_counterBufferDescriptorSetLayout));
Move<VkRenderPass> renderPass = buildRenderPass(m_cbFormat, tileWidth, tileHeight);
Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(0, *renderPass, *graphicsPipelineLayout, *vertShader, *fragShader);
std::vector<FBAttachmentInfo> attachmentInfo
{
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0] },
{ m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0] }
};
Move<VkFramebuffer> framebuffer = buildFramebuffer(*renderPass, attachmentInfo);
beginCommandBuffer(vk, *cmdBuffer, 0u);
// wait till sr image layout is changed
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
VkImageMemoryBarrier srImageBarrierAttachment =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
**m_srImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &srImageBarrierAttachment);
// wait till cb image layout is changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier cbImageBarrier =
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_cbImage[0],
m_defaultImageSubresourceRange);
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &cbImageBarrier);
startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo);
// draw single triangle to cb
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1, &(*m_counterBufferDescriptorSet), 0, DE_NULL);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*cmdBuffer);
// wait till color attachment is fully written
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// read back color buffer image
vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u, &m_defaultBufferImageCopy);
endCommandBuffer(vk, *cmdBuffer);
// submit commands and wait
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
if (!verifyUsingAtomicChecks(tileWidth, tileHeight,
m_params->srRate.width, m_params->srRate.height,
(deUint32*)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
return false;
} // iterate over all possible tile sizes
return true;
}
bool AttachmentRateInstance::runTwoSubpassMode(void)
{
// Set up a two-subpass render pass with different shading rate attachments used in each subpass.
// Then draw a basic triangle in each subpass and do basic checks.
const InstanceInterface& vki = m_context.getInstanceInterface();
const DeviceInterface& vk = m_context.getDeviceInterface();
VkPhysicalDevice pd = m_context.getPhysicalDevice();
VkDevice device = m_context.getDevice();
deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
VkMemoryBarrier memoryBarrier { VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u };
Move<VkShaderModule> vertShader0 = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert0"), 0);
Move<VkShaderModule> vertShader1 = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert1"), 0);
Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
// fetch information about supported rates
deUint32 supportedFragmentShadingRateCount;
std::vector<VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates;
vki.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount, DE_NULL);
supportedFragmentShadingRates.resize(supportedFragmentShadingRateCount, {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, // VkStructureType sType;
DE_NULL, // void* pNext;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlags sampleCounts;
{ 0, 0 } // VkExtent2D fragmentSize;
});
vki.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount, &supportedFragmentShadingRates[0]);
// grab min and max tile sieze and biggest and smallest rate
deUint32 sr0Width = (m_cbWidth + m_minTileSize.width - 1) / m_minTileSize.width;
deUint32 sr0Height = (m_cbHeight + m_minTileSize.height - 1) / m_minTileSize.height;
deUint32 sr1Width = (m_cbWidth + m_maxTileSize.width - 1) / m_maxTileSize.width;
deUint32 sr1Height = (m_cbHeight + m_maxTileSize.height - 1) / m_maxTileSize.height;
deUint32 sr0RateWidth = supportedFragmentShadingRates[0].fragmentSize.width; // bigets supported rate
deUint32 sr0RateHeight = supportedFragmentShadingRates[0].fragmentSize.height;
deUint32 sr1RateWidth = supportedFragmentShadingRates[supportedFragmentShadingRateCount - 2].fragmentSize.width; // smallest supported rate excluding {1, 1}
deUint32 sr1RateHeight = supportedFragmentShadingRates[supportedFragmentShadingRateCount - 2].fragmentSize.height;
buildColorBufferObjects(0, m_cbUsage);
buildColorBufferObjects(1, m_cbUsage);
buildShadingRateObjects(0, sr0Width, sr0Height, m_srUsage);
buildShadingRateObjects(1, sr1Width, sr1Height, m_srUsage);
buildCounterBufferObjects();
Move<VkRenderPass> renderPass = buildRenderPass(m_cbFormat, m_minTileSize.width, m_minTileSize.height, m_maxTileSize.width, m_maxTileSize.height);
Move<VkPipelineLayout> pipelineLayout = buildPipelineLayout(&(*m_counterBufferDescriptorSetLayout));
Move<VkPipeline> graphicsPipeline0 = buildGraphicsPipeline(0, *renderPass, *pipelineLayout, *vertShader0, *fragShader);
Move<VkPipeline> graphicsPipeline1 = buildGraphicsPipeline(1, *renderPass, *pipelineLayout, *vertShader1, *fragShader);
std::vector<FBAttachmentInfo> attachmentInfo
{
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0] },
{ m_params->srFormat, m_srUsage, sr0Width, sr0Height, *m_srImageView[0] },
{ m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[1] },
{ m_params->srFormat, m_srUsage, sr1Width, sr1Height, *m_srImageView[1] }
};
Move<VkFramebuffer> framebuffer = buildFramebuffer(*renderPass, attachmentInfo);
beginCommandBuffer(vk, *cmdBuffer, 0u);
// change sr image layouts to general
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
std::vector<VkImageMemoryBarrier> srImageBarrierGeneral(2,
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_NONE_KHR,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_srImage[0],
m_defaultImageSubresourceRange));
srImageBarrierGeneral[1].image = **m_srImage[1];
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 2, srImageBarrierGeneral.data());
VkClearColorValue clearValues[2] = { { { 0, 0, 0, 0 } }, { { 0, 0, 0, 0 } } };
clearValues[0].uint32[0] = calculateRate(sr0RateWidth, sr0RateHeight);
clearValues[1].uint32[0] = calculateRate(sr1RateWidth, sr1RateHeight);
vk.cmdClearColorImage(*cmdBuffer, **m_srImage[0], VK_IMAGE_LAYOUT_GENERAL, &clearValues[0], 1, &m_defaultImageSubresourceRange);
vk.cmdClearColorImage(*cmdBuffer, **m_srImage[1], VK_IMAGE_LAYOUT_GENERAL, &clearValues[1], 1, &m_defaultImageSubresourceRange);
// wait till sr data is ready and change sr images layout
srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
std::vector<VkImageMemoryBarrier> srImageBarrierShadingRate(2,
makeImageMemoryBarrier(
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
**m_srImage[0],
m_defaultImageSubresourceRange));
srImageBarrierShadingRate[1].image = **m_srImage[1];
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 2, srImageBarrierShadingRate.data());
// wait till cb image layouts are changed
srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
std::vector<VkImageMemoryBarrier> cbImageBarrier(2,
makeImageMemoryBarrier(
VK_ACCESS_NONE_KHR,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL,
**m_cbImage[0],
m_defaultImageSubresourceRange));
cbImageBarrier[1].image = **m_cbImage[1];
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 2, cbImageBarrier.data());
startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo);
// draw single triangle to first cb
vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0, 1, &(*m_counterBufferDescriptorSet), 0, DE_NULL);
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline0);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
// draw single triangle to second cb
vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline1);
vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
finishRendering(*cmdBuffer);
// wait till color attachments are fully written
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
// read back color buffer images
vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u, &m_defaultBufferImageCopy);
vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[1], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[1], 1u, &m_defaultBufferImageCopy);
endCommandBuffer(vk, *cmdBuffer);
// submit commands and wait
const VkQueue queue = m_context.getUniversalQueue();
submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
// read back buffer with color attachment 1 data
Allocation& cb0BuffAlloc = m_cbReadBuffer[0]->getAllocation();
invalidateAlloc(vk, device, cb0BuffAlloc);
// read back buffer with color attachment 2 data
Allocation& cb1BuffAlloc = m_cbReadBuffer[1]->getAllocation();
invalidateAlloc(vk, device, cb1BuffAlloc);
// validate both attachemtns triangle
return (verifyUsingAtomicChecks(m_minTileSize.width, m_minTileSize.height,
sr0RateWidth, sr0RateHeight,
(deUint32*)m_cbReadBuffer[0]->getAllocation().getHostPtr()) &&
verifyUsingAtomicChecks(m_maxTileSize.width, m_maxTileSize.height,
sr1RateWidth, sr1RateHeight,
(deUint32*)m_cbReadBuffer[1]->getAllocation().getHostPtr()));
}
class AttachmentRateTestCase : public TestCase
{
public:
AttachmentRateTestCase (tcu::TestContext& context, const char* name, de::SharedPtr<TestParams> params);
~AttachmentRateTestCase (void) = default;
void initPrograms (SourceCollections& programCollection) const override;
TestInstance* createInstance (Context& context) const override;
void checkSupport (Context& context) const override;
private:
const de::SharedPtr<TestParams> m_params;
};
AttachmentRateTestCase::AttachmentRateTestCase(tcu::TestContext& context, const char* name, de::SharedPtr<TestParams> params)
: vkt::TestCase (context, name, "")
, m_params (params)
{
}
void AttachmentRateTestCase::checkSupport(Context& context) const
{
context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
if (m_params->useImagelessFramebuffer)
context.requireDeviceFunctionality("VK_KHR_imageless_framebuffer");
if (!context.getFragmentShadingRateFeatures().attachmentFragmentShadingRate)
TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported");
const vk::InstanceInterface& vk = context.getInstanceInterface();
const vk::VkPhysicalDevice pd = context.getPhysicalDevice();
VkImageFormatProperties imageProperties;
VkImageUsageFlags srUsage = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkResult result = vk.getPhysicalDeviceImageFormatProperties(pd, m_params->srFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, srUsage, 0, &imageProperties);
if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
TCU_THROW(NotSupportedError, "Format not supported");
if (m_params->mode != TM_TWO_SUBPASS)
{
deUint32 supportedFragmentShadingRateCount;
VkExtent2D testedRate = m_params->srRate;
std::vector<VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates;
// fetch information about supported rates
vk.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount, DE_NULL);
supportedFragmentShadingRates.resize(supportedFragmentShadingRateCount, {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, // VkStructureType sType;
DE_NULL, // void* pNext;
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlags sampleCounts;
{ 0, 0 } // VkExtent2D fragmentSize;
});
vk.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount, &supportedFragmentShadingRates[0]);
// check if rate required by test is not supported
if (std::none_of(supportedFragmentShadingRates.begin(), supportedFragmentShadingRates.end(),
[&testedRate](const VkPhysicalDeviceFragmentShadingRateKHR& r)
{ return (r.fragmentSize.width == testedRate.width && r.fragmentSize.height == testedRate.height); }))
{
TCU_THROW(NotSupportedError, "Rate not supported");
}
}
VkFormatFeatureFlags requiredFeatures = 0;
if (m_params->mode == TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER)
requiredFeatures = VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
else if ((m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE) ||
(m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE) ||
(m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE) ||
(m_params->mode == TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE))
requiredFeatures = VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
else if (m_params->mode == TM_SETUP_RATE_WITH_FRAGMENT_SHADER)
requiredFeatures = VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
#if DEBUG_USE_STORE_INSTEAD_OF_ATOMICS == 1
if (m_params->mode == TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER)
requiredFeatures = VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
#endif
if (requiredFeatures)
{
const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vk, pd, m_params->srFormat);
if (m_params->mode == TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE)
{
if ((formatProperties.linearTilingFeatures & requiredFeatures) != requiredFeatures)
TCU_THROW(NotSupportedError, "Required format feature bits not supported");
}
else if ((formatProperties.optimalTilingFeatures & requiredFeatures) != requiredFeatures)
TCU_THROW(NotSupportedError, "Required format feature bits not supported");
}
}
void AttachmentRateTestCase::initPrograms(SourceCollections& programCollection) const
{
deUint32 rateValue = calculateRate(m_params->srRate.width, m_params->srRate.height);
if (m_params->mode == TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER)
{
std::stringstream compStream;
compStream <<
"#version 450\n"
"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
"layout(r32ui, binding = 0) coherent uniform highp uimage2D srImage;\n"
"void main (void)\n"
"{\n"
#if DEBUG_USE_STORE_INSTEAD_OF_ATOMICS == 1
" imageStore(srImage, ivec2(gl_GlobalInvocationID.xy), uvec4(" << rateValue << "));\n"
#else
" imageAtomicAdd(srImage, ivec2(gl_GlobalInvocationID.xy), " << rateValue << ");\n"
#endif
"}\n";
programCollection.glslSources.add("comp") << glu::ComputeSource(compStream.str());
}
tcu::StringTemplate vertTemplate(
"#version 450 core\n"
"out gl_PerVertex\n"
"{\n"
" vec4 gl_Position;\n"
"};\n"
"void main()\n"
"{\n"
" gl_Position = vec4(float(1.0 - 2.0 * int(gl_VertexIndex != 1)) * ${SCALE} + ${TRANSLATE},\n"
" float(1.0 - 2.0 * int(gl_VertexIndex > 0)) * ${SCALE} + ${TRANSLATE}, 0.0, 1.0);\n"
"}\n");
std::map<std::string, std::string> specializationMap
{
{"SCALE", "0.8" },
{"TRANSLATE", "0.0" },
};
if (m_params->mode == TM_TWO_SUBPASS)
{
specializationMap["SCALE"] = "0.4";
specializationMap["TRANSLATE"] = "-0.5";
programCollection.glslSources.add("vert0") << glu::VertexSource(vertTemplate.specialize(specializationMap));
specializationMap["SCALE"] = "0.4";
specializationMap["TRANSLATE"] = "0.5";
programCollection.glslSources.add("vert1") << glu::VertexSource(vertTemplate.specialize(specializationMap));
}
else
{
programCollection.glslSources.add("vert") << glu::VertexSource(vertTemplate.specialize(specializationMap));
}
if (m_params->mode == TM_SETUP_RATE_WITH_FRAGMENT_SHADER)
{
// use large triangle that will cover whole color buffer
specializationMap["SCALE"] = "9.0";
specializationMap["TRANSLATE"] = "0.0";
programCollection.glslSources.add("vert_setup") << glu::VertexSource(vertTemplate.specialize(specializationMap));
std::stringstream fragStream;
fragStream <<
"#version 450 core\n"
"layout(location = 0) out uint outColor;\n"
"void main()\n"
"{\n"
" outColor.x = " << rateValue << ";\n"
"}\n";
programCollection.glslSources.add("frag_setup") << glu::FragmentSource(fragStream.str());
}
std::string frag =
"#version 450 core\n"
"#extension GL_EXT_fragment_shading_rate : enable\n"
"layout(set = 0, binding = 0) buffer Block { uint counter; } buf;\n"
"layout(location = 0) out uvec4 outColor;\n"
"void main()\n"
"{\n"
" outColor.x = gl_ShadingRateEXT;\n"
" outColor.y = 0;\n"
" outColor.z = atomicAdd(buf.counter, 1);\n"
" outColor.w = 0;\n"
"}\n";
programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
}
TestInstance* AttachmentRateTestCase::createInstance(Context& context) const
{
return new AttachmentRateInstance(context, m_params);
}
} // anonymous
void createAttachmentRateTests(tcu::TestContext& testCtx, tcu::TestCaseGroup* parentGroup)
{
struct SRFormat
{
VkFormat format;
const char* name;
};
const std::vector<SRFormat> srFormats
{
{ VK_FORMAT_R8_UINT, "r8_uint" },
{ VK_FORMAT_R8G8_UINT, "r8g8_uint" },
{ VK_FORMAT_R8G8B8_UINT, "r8g8b8_uint" },
{ VK_FORMAT_R8G8B8A8_UINT, "r8g8b8a8_uint" },
{ VK_FORMAT_R16_UINT, "r16_uint" },
{ VK_FORMAT_R16G16_UINT, "r16g16_uint" },
{ VK_FORMAT_R16G16B16_UINT, "r16g16b16_uint" },
{ VK_FORMAT_R16G16B16A16_UINT, "r16g16b16a16_uint" },
{ VK_FORMAT_R32_UINT, "r32_uint" },
{ VK_FORMAT_R32G32_UINT, "r32g32_uint" },
{ VK_FORMAT_R32G32B32_UINT, "r32g32b32_uint" },
{ VK_FORMAT_R32G32B32A32_UINT, "r32g32b32a32_uint" },
{ VK_FORMAT_R64_UINT, "r64_uint" },
{ VK_FORMAT_R64G64_UINT, "r64g64_uint" },
{ VK_FORMAT_R64G64B64_UINT, "r64g64b64_uint" },
{ VK_FORMAT_R64G64B64A64_UINT, "r64g64b64a64_uint" },
};
struct SRRate
{
VkExtent2D count;
const char* name;
};
const std::vector<SRRate> srRates
{
{ {1, 1}, "rate_1x1" },
{ {1, 2}, "rate_1x2" },
{ {1, 4}, "rate_1x4" },
{ {2, 1}, "rate_2x1" },
{ {2, 2}, "rate_2x2" },
{ {2, 4}, "rate_2x4" },
{ {4, 1}, "rate_4x1" },
{ {4, 2}, "rate_4x2" },
{ {4, 4}, "rate_4x4" },
};
struct TestModeParam
{
TestMode mode;
const char* name;
};
const std::vector<TestModeParam> testModeParams
{
{ TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER, "setup_with_atomics" },
{ TM_SETUP_RATE_WITH_FRAGMENT_SHADER, "setup_with_fragment" },
{ TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE, "setup_with_copying" },
{ TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE, "setup_with_copying_using_transfer_queue_concurent" },
{ TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE, "setup_with_copying_using_transfer_queue_exclusive" },
{ TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE, "setup_with_linear_tiled_image" },
};
de::MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, "attachment_rate", ""));
for (const auto& testModeParam : testModeParams)
{
de::MovePtr<tcu::TestCaseGroup> testModeGroup(new tcu::TestCaseGroup(testCtx, testModeParam.name, ""));
for (const auto& srFormat : srFormats)
{
de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, srFormat.name, ""));
for (const auto& srRate : srRates)
{
formatGroup->addChild(new AttachmentRateTestCase(testCtx, srRate.name, de::SharedPtr<TestParams>(
new TestParams
{
testModeParam.mode, // TestMode mode;
srFormat.format, // VkFormat srFormat;
srRate.count, // VkExtent2D srRate;
false // bool useImagelessFramebuffer;
}
)));
// duplicate all tests for imageless framebuffer
std::string imagelessName = std::string(srRate.name) + "_imageless";
formatGroup->addChild(new AttachmentRateTestCase(testCtx, imagelessName.c_str(), de::SharedPtr<TestParams>(
new TestParams
{
testModeParam.mode, // TestMode mode;
srFormat.format, // VkFormat srFormat;
srRate.count, // VkExtent2D srRate;
true // bool useImagelessFramebuffer;
}
)));
}
testModeGroup->addChild(formatGroup.release());
}
mainGroup->addChild(testModeGroup.release());
}
de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testCtx, "misc", ""));
miscGroup->addChild(new AttachmentRateTestCase(testCtx, "two_subpass", de::SharedPtr<TestParams>(
new TestParams
{
TM_TWO_SUBPASS, // TestMode mode;
VK_FORMAT_R8_UINT, // VkFormat srFormat;
{0, 0}, // VkExtent2D srRate; // not used in TM_TWO_SUBPASS
false // bool useImagelessFramebuffer;
}
)));
mainGroup->addChild(miscGroup.release());
parentGroup->addChild(mainGroup.release());
}
} // FragmentShadingRage
} // vkt