• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Tests for VK_KHR_fragment_shading_rate
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktAttachmentRateTests.hpp"
25 
26 #include "vkBufferWithMemory.hpp"
27 #include "vkImageWithMemory.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkBarrierUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkPlatform.hpp"
36 #include "vkBuilderUtil.hpp"
37 
38 #include "vktTestGroupUtil.hpp"
39 #include "vktTestCase.hpp"
40 #include "vktCustomInstancesDevices.hpp"
41 
42 #include "deDefs.h"
43 #include "deMath.h"
44 #include "deSharedPtr.hpp"
45 #include "deString.h"
46 #include "deSTLUtil.hpp"
47 
48 #include "tcuTestCase.hpp"
49 #include "tcuTestLog.hpp"
50 #include "tcuTextureUtil.hpp"
51 #include "tcuStringTemplate.hpp"
52 
53 #include <string>
54 #include <vector>
55 #include <limits>
56 #include <map>
57 
58 namespace vkt
59 {
60 namespace FragmentShadingRate
61 {
62 namespace
63 {
64 
65 using namespace vk;
66 
67 // flag used to test TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER;
68 // when it is 1 instead of using atomic operations to fill image
69 // plain store will be used as it is always supported
70 #define DEBUG_USE_STORE_INSTEAD_OF_ATOMICS 0
71 
72 enum TestMode
73 {
74     TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER = 0,
75     TM_SETUP_RATE_WITH_FRAGMENT_SHADER,
76     TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE,
77     TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE,
78     TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE,
79     TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE,
80 
81     TM_TWO_SUBPASS,
82     TM_MEMORY_ACCESS,
83     TM_MAINTENANCE_5
84 };
85 
86 struct DepthStencilParams
87 {
88     const VkFormat format;
89     const VkImageLayout layout;
90 
DepthStencilParamsvkt::FragmentShadingRate::__anon16891c1b0111::DepthStencilParams91     DepthStencilParams(VkFormat format_, VkImageLayout layout_) : format(format_), layout(layout_)
92     {
93         DE_ASSERT(format != VK_FORMAT_UNDEFINED);
94     }
95 };
96 
97 using OptDSParams = tcu::Maybe<DepthStencilParams>;
98 
99 struct TestParams
100 {
101     TestMode mode;
102 
103     VkFormat srFormat;
104     VkExtent2D srRate;
105 
106     bool useDynamicRendering;
107     bool useImagelessFramebuffer;
108     bool useNullShadingRateImage;
109     OptDSParams dsParams;
110 
useDepthStencilvkt::FragmentShadingRate::__anon16891c1b0111::TestParams111     bool useDepthStencil(void) const
112     {
113         return (hasDSParams() && dsParams->format != VK_FORMAT_UNDEFINED);
114     }
115 
116     // Returns depth/stencil format, or VK_FORMAT_UNDEFINED if not present.
getDSFormatvkt::FragmentShadingRate::__anon16891c1b0111::TestParams117     VkFormat getDSFormat(void) const
118     {
119         return (hasDSParams() ? dsParams->format : VK_FORMAT_UNDEFINED);
120     }
121 
122     // Returns depth/stencil layout, or VK_IMAGE_LAYOUT_UNDEFINED if not present.
getDSLayoutvkt::FragmentShadingRate::__anon16891c1b0111::TestParams123     VkImageLayout getDSLayout(void) const
124     {
125         return (hasDSParams() ? dsParams->layout : VK_IMAGE_LAYOUT_UNDEFINED);
126     }
127 
128 private:
hasDSParamsvkt::FragmentShadingRate::__anon16891c1b0111::TestParams129     inline bool hasDSParams(void) const
130     {
131         return static_cast<bool>(dsParams);
132     }
133 };
134 
135 constexpr VkImageUsageFlags kDSUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
136 
getFormatAspectFlags(const VkFormat format)137 VkImageAspectFlags getFormatAspectFlags(const VkFormat format)
138 {
139     if (format == VK_FORMAT_UNDEFINED)
140         return 0u;
141 
142     const auto order = mapVkFormat(format).order;
143 
144     switch (order)
145     {
146     case tcu::TextureFormat::DS:
147         return (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
148     case tcu::TextureFormat::D:
149         return VK_IMAGE_ASPECT_DEPTH_BIT;
150     case tcu::TextureFormat::S:
151         return VK_IMAGE_ASPECT_STENCIL_BIT;
152     default:
153         return VK_IMAGE_ASPECT_COLOR_BIT;
154     }
155 
156     DE_ASSERT(false);
157     return 0u;
158 }
159 
calculateRate(uint32_t rateWidth,uint32_t rateHeight)160 uint32_t calculateRate(uint32_t rateWidth, uint32_t rateHeight)
161 {
162     return (deCtz32(rateWidth) << 2u) | deCtz32(rateHeight);
163 }
164 
165 class DeviceHolder
166 {
167 public:
168     DeviceHolder(Move<VkDevice> device, de::MovePtr<DeviceDriver> vk, de::MovePtr<Allocator> allocator);
169 
170 private:
171     Move<VkDevice> m_device;
172     de::MovePtr<DeviceDriver> m_vk;
173     de::MovePtr<Allocator> m_allocator;
174 };
175 
DeviceHolder(Move<VkDevice> device,de::MovePtr<DeviceDriver> vk,de::MovePtr<Allocator> allocator)176 DeviceHolder::DeviceHolder(Move<VkDevice> device, de::MovePtr<DeviceDriver> vk, de::MovePtr<Allocator> allocator)
177     : m_device(device)
178     , m_vk(vk)
179     , m_allocator(allocator)
180 {
181 }
182 
183 class AttachmentRateInstance : public TestInstance
184 {
185 public:
186     AttachmentRateInstance(Context &context, const de::SharedPtr<TestParams> params);
187     tcu::TestStatus iterate(void);
188 
189 private:
190     // Helper structure used by buildFramebuffer method.
191     // It is used to build regular or imageless framebuffer.
192     struct FBAttachmentInfo
193     {
194         VkFormat format;
195         VkImageUsageFlags usage;
196         uint32_t width;
197         uint32_t height;
198         VkImageView view;
199     };
200 
201 private:
202     de::MovePtr<ImageWithMemory> buildImageWithMemory(VkDevice device, const DeviceInterface &vk,
203                                                       vk::Allocator &allocator, VkFormat format, uint32_t width,
204                                                       uint32_t height, VkImageUsageFlags usage,
205                                                       VkImageTiling tiling                = VK_IMAGE_TILING_OPTIMAL,
206                                                       std::vector<uint32_t> queueFamilies = std::vector<uint32_t>());
207     de::MovePtr<BufferWithMemory> buildBufferWithMemory(VkDevice device, const DeviceInterface &vk,
208                                                         vk::Allocator &allocator, uint32_t size,
209                                                         VkBufferUsageFlags usage);
210     Move<VkImageView> buildImageView(VkDevice device, const DeviceInterface &vk, VkFormat format, VkImage image);
211 
212     void buildColorBufferObjects(VkDevice device, const DeviceInterface &vk, vk::Allocator &allocator,
213                                  uint32_t cbIindex, VkImageUsageFlags cbUsage);
214     void buildShadingRateObjects(VkDevice device, const DeviceInterface &vk, vk::Allocator &allocator, uint32_t srIndex,
215                                  uint32_t width, uint32_t height, VkImageUsageFlags srUsage,
216                                  VkImageTiling srTiling = VK_IMAGE_TILING_OPTIMAL);
217     void buildCounterBufferObjects(VkDevice device, const DeviceInterface &vk, vk::Allocator &allocator);
218 
219     Move<VkRenderPass> buildRenderPass(VkDevice device, const DeviceInterface &vk, VkFormat cbFormat, VkFormat dsFormat,
220                                        uint32_t sr1TileWidth = 0, uint32_t sr1TileHeight = 0, uint32_t sr2TileWidth = 0,
221                                        uint32_t sr2TileHeight = 0) const;
222     Move<VkFramebuffer> buildFramebuffer(VkDevice device, const DeviceInterface &vk, VkRenderPass renderPass,
223                                          const std::vector<FBAttachmentInfo> &attachmentInfo) const;
224     Move<VkPipelineLayout> buildPipelineLayout(VkDevice device, const DeviceInterface &vk,
225                                                const VkDescriptorSetLayout *setLayouts = DE_NULL) const;
226     Move<VkPipeline> buildGraphicsPipeline(VkDevice device, const DeviceInterface &vk, uint32_t subpass,
227                                            VkRenderPass renderPass, VkFormat cbFormat, VkFormat dsFormat,
228                                            VkPipelineLayout layout, VkShaderModule vertShader,
229                                            VkShaderModule fragShader, bool useShadingRate = VK_TRUE) const;
230     Move<VkPipeline> buildComputePipeline(VkDevice device, const DeviceInterface &vk, VkShaderModule compShader,
231                                           VkPipelineLayout pipelineLayout) const;
232     VkDescriptorSetAllocateInfo makeDescriptorSetAllocInfo(VkDescriptorPool descriptorPool,
233                                                            const VkDescriptorSetLayout *pSetLayouts) const;
234 
235     void startRendering(const VkCommandBuffer commandBuffer, const VkRenderPass renderPass,
236                         const VkFramebuffer framebuffer, const VkRect2D &renderArea,
237                         const std::vector<FBAttachmentInfo> &attachmentInfo, const uint32_t srTileWidth = 0,
238                         const uint32_t srTileHeight = 0) const;
239     void finishRendering(const VkCommandBuffer commandBuffer) const;
240 
241     bool verifyUsingAtomicChecks(uint32_t tileWidth, uint32_t tileHeight, uint32_t rateWidth, uint32_t rateHeight,
242                                  uint32_t *outBufferPtr) const;
243 
244     bool runComputeShaderMode(void);
245     bool runFragmentShaderMode(void);
246     bool runCopyMode(void);
247     bool runCopyModeOnTransferQueue(void);
248     bool runFillLinearTiledImage(void);
249     bool runTwoSubpassMode(void);
250 
251 private:
252     // A custom device is by tests from runCopyModeOnTransferQueue.
253     // In this test the device is passed to various utils, that create
254     // Vulkan objects later assigned to various members below. To guarantee
255     // proper destruction order, below variable acts as an owner of this custom device
256     // - however, it is not to be used (the device is not accessible directly from this object
257     //   to avoid misusages of the framework device vs custom device).
258     de::MovePtr<DeviceHolder> m_customDeviceHolder;
259 
260     const de::SharedPtr<TestParams> m_params;
261     const uint32_t m_cbWidth;
262     const uint32_t m_cbHeight;
263     VkFormat m_cbFormat;
264     VkImageUsageFlags m_cbUsage;
265     VkImageUsageFlags m_srUsage;
266 
267     // structures commonly used by most of tests
268     const VkImageSubresourceLayers m_defaultImageSubresourceLayers;
269     const VkImageSubresourceRange m_defaultImageSubresourceRange;
270     const VkImageSubresourceRange m_dsImageSubresourceRange;
271     const VkBufferImageCopy m_defaultBufferImageCopy;
272 
273     // objects commonly used by most of tests
274     de::MovePtr<ImageWithMemory> m_cbImage[2];
275     Move<VkImageView> m_cbImageView[2];
276     de::MovePtr<BufferWithMemory> m_cbReadBuffer[2];
277 
278     de::MovePtr<ImageWithMemory> m_dsImage;
279     Move<VkImageView> m_dsImageView;
280 
281     de::MovePtr<ImageWithMemory> m_srImage[2];
282     Move<VkImageView> m_srImageView[2];
283 
284     Move<VkDescriptorSetLayout> m_counterBufferDescriptorSetLayout;
285     Move<VkDescriptorPool> m_counterBufferDescriptorPool;
286     Move<VkDescriptorSet> m_counterBufferDescriptorSet;
287     de::MovePtr<BufferWithMemory> m_counterBuffer;
288 
289     // properties commonly used by most of tests
290     VkExtent2D m_minTileSize;
291     VkExtent2D m_maxTileSize;
292     uint32_t m_maxAspectRatio;
293 };
294 
AttachmentRateInstance(Context & context,const de::SharedPtr<TestParams> params)295 AttachmentRateInstance::AttachmentRateInstance(Context &context, const de::SharedPtr<TestParams> params)
296     : vkt::TestInstance(context)
297     , m_params(params)
298     , m_cbWidth(60)
299     , m_cbHeight(60)
300     , m_cbFormat(VK_FORMAT_R32G32B32A32_UINT)
301     , m_cbUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
302     , m_srUsage(VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT)
303     , m_defaultImageSubresourceLayers(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u))
304     , m_defaultImageSubresourceRange(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0, 1u))
305     , m_dsImageSubresourceRange(makeImageSubresourceRange(getFormatAspectFlags(m_params->getDSFormat()), 0u, 1u, 0, 1u))
306     , m_defaultBufferImageCopy(makeBufferImageCopy({m_cbWidth, m_cbHeight, 1u}, m_defaultImageSubresourceLayers))
307 {
308     // prepare data needed to calculate tile sizes
309     const auto &srProperties = m_context.getFragmentShadingRateProperties();
310     m_minTileSize            = srProperties.minFragmentShadingRateAttachmentTexelSize;
311     m_maxTileSize            = srProperties.maxFragmentShadingRateAttachmentTexelSize;
312     m_maxAspectRatio         = srProperties.maxFragmentShadingRateAttachmentTexelSizeAspectRatio;
313 }
314 
buildImageWithMemory(VkDevice device,const DeviceInterface & vk,vk::Allocator & allocator,VkFormat format,uint32_t width,uint32_t height,VkImageUsageFlags usage,VkImageTiling tiling,std::vector<uint32_t> queueFamilies)315 de::MovePtr<ImageWithMemory> AttachmentRateInstance::buildImageWithMemory(VkDevice device, const DeviceInterface &vk,
316                                                                           vk::Allocator &allocator, VkFormat format,
317                                                                           uint32_t width, uint32_t height,
318                                                                           VkImageUsageFlags usage, VkImageTiling tiling,
319                                                                           std::vector<uint32_t> queueFamilies)
320 {
321     VkImageCreateInfo imageCreateInfo{
322         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
323         DE_NULL,                             // const void* pNext;
324         (VkImageCreateFlags)0u,              // VkImageCreateFlags flags;
325         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
326         format,                              // VkFormat format;
327         {
328             width,             // uint32_t width;
329             height,            // uint32_t height;
330             1u                 // uint32_t depth;
331         },                     // VkExtent3D extent;
332         1u,                    // uint32_t mipLevels;
333         1u,                    // uint32_t arrayLayers;
334         VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
335         tiling,                // VkImageTiling tiling;
336         usage,                 // VkImageUsageFlags usage;
337         queueFamilies.empty() ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT, // VkSharingMode sharingMode;
338         (uint32_t)queueFamilies.size(), // uint32_t queueFamilyIndexCount;
339         queueFamilies.data(),           // const uint32_t* pQueueFamilyIndices;
340         VK_IMAGE_LAYOUT_UNDEFINED       // VkImageLayout initialLayout;
341     };
342 
343     vk::MemoryRequirement memoryRequirement =
344         (tiling == VK_IMAGE_TILING_LINEAR) ? MemoryRequirement::HostVisible : MemoryRequirement::Any;
345     return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vk, device, allocator, imageCreateInfo, memoryRequirement));
346 }
347 
buildBufferWithMemory(VkDevice device,const DeviceInterface & vk,vk::Allocator & allocator,uint32_t size,VkBufferUsageFlags usage)348 de::MovePtr<BufferWithMemory> AttachmentRateInstance::buildBufferWithMemory(VkDevice device, const DeviceInterface &vk,
349                                                                             vk::Allocator &allocator, uint32_t size,
350                                                                             VkBufferUsageFlags usage)
351 {
352     const VkBufferCreateInfo readBufferInfo = makeBufferCreateInfo(size, usage);
353 
354     return de::MovePtr<BufferWithMemory>(
355         new BufferWithMemory(vk, device, allocator, readBufferInfo, MemoryRequirement::HostVisible));
356 }
357 
buildImageView(VkDevice device,const DeviceInterface & vk,VkFormat format,VkImage image)358 Move<VkImageView> AttachmentRateInstance::buildImageView(VkDevice device, const DeviceInterface &vk, VkFormat format,
359                                                          VkImage image)
360 {
361     const auto aspect           = getFormatAspectFlags(format);
362     const auto subresourceRange = makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u);
363 
364     return makeImageView(vk, device, image, VK_IMAGE_VIEW_TYPE_2D, format, subresourceRange);
365 };
366 
buildColorBufferObjects(VkDevice device,const DeviceInterface & vk,vk::Allocator & allocator,uint32_t cbIndex,VkImageUsageFlags cbUsage)367 void AttachmentRateInstance::buildColorBufferObjects(VkDevice device, const DeviceInterface &vk,
368                                                      vk::Allocator &allocator, uint32_t cbIndex,
369                                                      VkImageUsageFlags cbUsage)
370 {
371     DE_ASSERT(cbIndex < 2);
372 
373     m_cbImage[cbIndex]      = buildImageWithMemory(device, vk, allocator, m_cbFormat, m_cbWidth, m_cbHeight, cbUsage);
374     m_cbImageView[cbIndex]  = buildImageView(device, vk, m_cbFormat, m_cbImage[cbIndex]->get());
375     m_cbReadBuffer[cbIndex] = buildBufferWithMemory(
376         device, vk, allocator, m_cbWidth * m_cbHeight * uint32_t(sizeof(int)) * 4u, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
377 
378     if (m_params->useDepthStencil() && m_dsImage.get() == nullptr)
379     {
380         const auto dsFormat = m_params->getDSFormat();
381         m_dsImage           = buildImageWithMemory(device, vk, allocator, dsFormat, m_cbWidth, m_cbHeight, kDSUsage);
382         m_dsImageView       = buildImageView(device, vk, dsFormat, m_dsImage->get());
383     }
384 }
385 
buildShadingRateObjects(VkDevice device,const DeviceInterface & vk,vk::Allocator & allocator,uint32_t srIndex,uint32_t width,uint32_t height,VkImageUsageFlags srUsage,VkImageTiling srTiling)386 void AttachmentRateInstance::buildShadingRateObjects(VkDevice device, const DeviceInterface &vk,
387                                                      vk::Allocator &allocator, uint32_t srIndex, uint32_t width,
388                                                      uint32_t height, VkImageUsageFlags srUsage, VkImageTiling srTiling)
389 {
390     DE_ASSERT(srIndex < 2);
391 
392     m_srImage[srIndex] =
393         buildImageWithMemory(device, vk, allocator, m_params->srFormat, width, height, srUsage, srTiling);
394     m_srImageView[srIndex] = buildImageView(device, vk, m_params->srFormat, m_srImage[srIndex]->get());
395 }
396 
buildCounterBufferObjects(VkDevice device,const vk::DeviceInterface & vk,vk::Allocator & allocator)397 void AttachmentRateInstance::buildCounterBufferObjects(VkDevice device, const vk::DeviceInterface &vk,
398                                                        vk::Allocator &allocator)
399 {
400     m_counterBufferDescriptorPool = DescriptorPoolBuilder()
401                                         .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
402                                         .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
403     m_counterBufferDescriptorSetLayout =
404         DescriptorSetLayoutBuilder()
405             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT)
406             .build(vk, device);
407 
408     const VkDescriptorSetAllocateInfo descriptorSetAllocInfo =
409         makeDescriptorSetAllocInfo(*m_counterBufferDescriptorPool, &(*m_counterBufferDescriptorSetLayout));
410     m_counterBufferDescriptorSet = allocateDescriptorSet(vk, device, &descriptorSetAllocInfo);
411 
412     // create ssbo buffer for atomic counter
413     uint32_t ssboSize = uint32_t(sizeof(uint32_t));
414     m_counterBuffer   = buildBufferWithMemory(device, vk, allocator, ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
415 
416     const VkDescriptorBufferInfo descriptorInfo = makeDescriptorBufferInfo(**m_counterBuffer, 0, ssboSize);
417     DescriptorSetUpdateBuilder()
418         .writeSingle(*m_counterBufferDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
419                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
420         .update(vk, device);
421 
422     // reset counter
423     *((uint32_t *)m_counterBuffer->getAllocation().getHostPtr()) = 0u;
424     flushAlloc(vk, device, m_counterBuffer->getAllocation());
425 }
426 
buildRenderPass(VkDevice device,const vk::DeviceInterface & vk,VkFormat cbFormat,VkFormat dsFormat,uint32_t sr0TileWidth,uint32_t sr0TileHeight,uint32_t sr1TileWidth,uint32_t sr1TileHeight) const427 Move<VkRenderPass> AttachmentRateInstance::buildRenderPass(VkDevice device, const vk::DeviceInterface &vk,
428                                                            VkFormat cbFormat, VkFormat dsFormat, uint32_t sr0TileWidth,
429                                                            uint32_t sr0TileHeight, uint32_t sr1TileWidth,
430                                                            uint32_t sr1TileHeight) const
431 {
432     if (m_params->useDynamicRendering)
433         return Move<VkRenderPass>();
434 
435     const bool useShadingRate0 = (sr0TileWidth * sr0TileHeight > 0);
436     const bool useShadingRate1 = (sr1TileWidth * sr1TileHeight > 0);
437 
438     uint32_t attachmentCount    = 1;
439     const uint32_t subpassCount = 1 + useShadingRate1;
440 
441     std::vector<VkAttachmentReference2> colorAttachmentReferences(
442         subpassCount, {
443                           VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
444                           DE_NULL,                                  // const void* pNext;
445                           0,                                        // uint32_t attachment;
446                           VK_IMAGE_LAYOUT_GENERAL,                  // VkImageLayout layout;
447                           0,                                        // VkImageAspectFlags aspectMask;
448                       });
449 
450     std::vector<VkAttachmentReference2> fragmentShadingRateAttachments(
451         subpassCount,
452         {
453             VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,                     // VkStructureType sType;
454             DE_NULL,                                                      // const void* pNext;
455             1,                                                            // uint32_t attachment;
456             VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, // VkImageLayout layout;
457             0,                                                            // VkImageAspectFlags aspectMask;
458         });
459 
460     std::vector<VkFragmentShadingRateAttachmentInfoKHR> shadingRateAttachmentInfos(
461         subpassCount,
462         {
463             VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, // VkStructureType sType;
464             DE_NULL,                                                     // const void* pNext;
465             &fragmentShadingRateAttachments[0], // const VkAttachmentReference2* pFragmentShadingRateAttachment;
466             {sr0TileWidth, sr0TileHeight},      // VkExtent2D shadingRateAttachmentTexelSize;
467         });
468 
469     std::vector<VkSubpassDescription2> subpassDescriptions(
470         subpassCount, {
471                           VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2, // VkStructureType sType;
472                           DE_NULL,                                 // const void* pNext;
473                           (vk::VkSubpassDescriptionFlags)0,        // VkSubpassDescriptionFlags flags;
474                           vk::VK_PIPELINE_BIND_POINT_GRAPHICS,     // VkPipelineBindPoint pipelineBindPoint;
475                           0u,                                      // uint32_t viewMask;
476                           0u,                                      // uint32_t inputAttachmentCount;
477                           DE_NULL,                                 // const VkAttachmentReference2* pInputAttachments;
478                           1,                                       // uint32_t colorAttachmentCount;
479                           &colorAttachmentReferences[0],           // const VkAttachmentReference2* pColorAttachments;
480                           DE_NULL,                                 // const VkAttachmentReference2* pResolveAttachments;
481                           DE_NULL, // const VkAttachmentReference2* pDepthStencilAttachment;
482                           0u,      // uint32_t preserveAttachmentCount;
483                           DE_NULL, // const uint32_t* pPreserveAttachments;
484                       });
485 
486     std::vector<VkAttachmentDescription2> attachmentDescriptions(
487         2 * subpassCount, {
488                               VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
489                               DE_NULL,                                    // const void* pNext;
490                               (VkAttachmentDescriptionFlags)0u,           // VkAttachmentDescriptionFlags flags;
491                               cbFormat,                                   // VkFormat format;
492                               VK_SAMPLE_COUNT_1_BIT,                      // VkSampleCountFlagBits samples;
493                               VK_ATTACHMENT_LOAD_OP_CLEAR,                // VkAttachmentLoadOp loadOp;
494                               VK_ATTACHMENT_STORE_OP_STORE,               // VkAttachmentStoreOp storeOp;
495                               VK_ATTACHMENT_LOAD_OP_DONT_CARE,            // VkAttachmentLoadOp stencilLoadOp;
496                               VK_ATTACHMENT_STORE_OP_DONT_CARE,           // VkAttachmentStoreOp stencilStoreOp;
497                               VK_IMAGE_LAYOUT_GENERAL,                    // VkImageLayout initialLayout;
498                               VK_IMAGE_LAYOUT_GENERAL                     // VkImageLayout finalLayout;
499                           });
500 
501     if (useShadingRate0)
502     {
503         attachmentCount                         = 2;
504         subpassDescriptions[0].pNext            = &shadingRateAttachmentInfos[0];
505         attachmentDescriptions[1].format        = m_params->srFormat;
506         attachmentDescriptions[1].loadOp        = VK_ATTACHMENT_LOAD_OP_LOAD;
507         attachmentDescriptions[1].storeOp       = VK_ATTACHMENT_STORE_OP_DONT_CARE;
508         attachmentDescriptions[1].initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
509     }
510 
511     if (useShadingRate1)
512     {
513         attachmentCount                                              = 4;
514         colorAttachmentReferences[1].attachment                      = 2;
515         fragmentShadingRateAttachments[1].attachment                 = 3;
516         shadingRateAttachmentInfos[1].pFragmentShadingRateAttachment = &fragmentShadingRateAttachments[1];
517         shadingRateAttachmentInfos[1].shadingRateAttachmentTexelSize = {sr1TileWidth, sr1TileHeight};
518         subpassDescriptions[1].pNext                                 = &shadingRateAttachmentInfos[1];
519         subpassDescriptions[1].pColorAttachments                     = &colorAttachmentReferences[1];
520 
521         attachmentDescriptions[3].format        = m_params->srFormat;
522         attachmentDescriptions[3].loadOp        = VK_ATTACHMENT_LOAD_OP_LOAD;
523         attachmentDescriptions[3].storeOp       = VK_ATTACHMENT_STORE_OP_DONT_CARE;
524         attachmentDescriptions[3].initialLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
525     }
526 
527     std::vector<VkAttachmentReference2> dsAttachmentReferences;
528 
529     if (dsFormat != VK_FORMAT_UNDEFINED)
530     {
531         const auto dsLayout       = m_params->getDSLayout();
532         const auto dsAspects      = getFormatAspectFlags(dsFormat);
533         const auto hasDepth       = ((dsAspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0);
534         const auto hasStencil     = ((dsAspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
535         const auto depthLoadOp    = (hasDepth ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE);
536         const auto depthStoreOp   = (hasDepth ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE);
537         const auto stencilLoadOp  = (hasStencil ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE);
538         const auto stencilStoreOp = (hasStencil ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE);
539 
540         ++attachmentCount;
541         attachmentDescriptions.push_back(VkAttachmentDescription2{
542             VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2, // VkStructureType sType;
543             nullptr,                                    // const void* pNext;
544             0u,                                         // VkAttachmentDescriptionFlags flags;
545             dsFormat,                                   // VkFormat format;
546             VK_SAMPLE_COUNT_1_BIT,                      // VkSampleCountFlagBits samples;
547             depthLoadOp,                                // VkAttachmentLoadOp loadOp;
548             depthStoreOp,                               // VkAttachmentStoreOp storeOp;
549             stencilLoadOp,                              // VkAttachmentLoadOp stencilLoadOp;
550             stencilStoreOp,                             // VkAttachmentStoreOp stencilStoreOp;
551             dsLayout,                                   // VkImageLayout initialLayout;
552             dsLayout,                                   // VkImageLayout finalLayout;
553         });
554 
555         dsAttachmentReferences.push_back(VkAttachmentReference2{
556             VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, // VkStructureType sType;
557             nullptr,                                  // const void* pNext;
558             attachmentCount - 1u,                     // uint32_t attachment;
559             dsLayout,                                 // VkImageLayout layout;
560             0u,                                       // VkImageAspectFlags aspectMask;
561         });
562 
563         for (auto &desc : subpassDescriptions)
564             desc.pDepthStencilAttachment = &dsAttachmentReferences.back();
565     }
566 
567     const VkRenderPassCreateInfo2 renderPassParams{
568         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2, // VkStructureType sType;
569         nullptr,                                     // const void* pNext;
570         (vk::VkRenderPassCreateFlags)0,              // VkRenderPassCreateFlags flags;
571         attachmentCount,                             // uint32_t attachmentCount;
572         attachmentDescriptions.data(),               // const VkAttachmentDescription2* pAttachments;
573         subpassCount,                                // uint32_t subpassCount;
574         subpassDescriptions.data(),                  // const VkSubpassDescription2* pSubpasses;
575         0u,                                          // uint32_t dependencyCount;
576         nullptr,                                     // const VkSubpassDependency2* pDependencies;
577         0u,                                          // uint32_t correlatedViewMaskCount;
578         nullptr,                                     // const uint32_t* pCorrelatedViewMasks;
579     };
580 
581     return createRenderPass2(vk, device, &renderPassParams);
582 }
583 
buildFramebuffer(VkDevice device,const vk::DeviceInterface & vk,VkRenderPass renderPass,const std::vector<FBAttachmentInfo> & attachmentInfo) const584 Move<VkFramebuffer> AttachmentRateInstance::buildFramebuffer(VkDevice device, const vk::DeviceInterface &vk,
585                                                              VkRenderPass renderPass,
586                                                              const std::vector<FBAttachmentInfo> &attachmentInfo) const
587 {
588     if (m_params->useDynamicRendering)
589         return Move<VkFramebuffer>();
590 
591     VkFramebufferCreateInfo framebufferParams{
592         vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
593         DE_NULL,                                       // const void* pNext;
594         (vk::VkFramebufferCreateFlags)0u,              // VkFramebufferCreateFlags flags;
595         renderPass,                                    // VkRenderPass renderPass;
596         (uint32_t)attachmentInfo.size(),               // uint32_t attachmentCount;
597         DE_NULL,                                       // const VkImageView* pAttachments;
598         attachmentInfo[0].width,                       // uint32_t width;
599         attachmentInfo[0].height,                      // uint32_t height;
600         1u,                                            // uint32_t layers;
601     };
602 
603     if (m_params->useImagelessFramebuffer)
604     {
605         std::vector<VkFramebufferAttachmentImageInfo> framebufferAttachmentImageInfo(
606             attachmentInfo.size(),
607             {
608                 VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO, // VkStructureType sType;
609                 DE_NULL,                                             // const void* pNext;
610                 (VkImageCreateFlags)0u,                              // VkImageCreateFlags flags;
611                 0u,                                                  // VkImageUsageFlags usage;
612                 0u,                                                  // uint32_t width;
613                 0u,                                                  // uint32_t height;
614                 1u,                                                  // uint32_t layerCount;
615                 1u,                                                  // uint32_t viewFormatCount;
616                 DE_NULL                                              // const VkFormat* pViewFormats;
617             });
618 
619         for (uint32_t i = 0; i < (uint32_t)attachmentInfo.size(); ++i)
620         {
621             const auto &src = attachmentInfo[i];
622             auto &dst       = framebufferAttachmentImageInfo[i];
623 
624             dst.usage        = src.usage;
625             dst.width        = src.width;
626             dst.height       = src.height;
627             dst.pViewFormats = &src.format;
628         }
629 
630         VkFramebufferAttachmentsCreateInfo framebufferAttachmentsCreateInfo{
631             VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO, // VkStructureType sType;
632             DE_NULL,                                               // const void* pNext;
633             (uint32_t)framebufferAttachmentImageInfo.size(),       // uint32_t attachmentImageInfoCount;
634             framebufferAttachmentImageInfo.data() // const VkFramebufferAttachmentImageInfo* pAttachmentImageInfos;
635         };
636 
637         framebufferParams.pNext = &framebufferAttachmentsCreateInfo;
638         framebufferParams.flags = VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
639 
640         return createFramebuffer(vk, device, &framebufferParams);
641     }
642 
643     // create array containing just attachment views
644     std::vector<VkImageView> attachments(attachmentInfo.size(), 0);
645     for (uint32_t i = 0; i < (uint32_t)attachmentInfo.size(); ++i)
646         attachments[i] = attachmentInfo[i].view;
647 
648     framebufferParams.pAttachments = attachments.data();
649 
650     return createFramebuffer(vk, device, &framebufferParams);
651 }
652 
buildPipelineLayout(VkDevice device,const vk::DeviceInterface & vk,const VkDescriptorSetLayout * setLayouts) const653 Move<VkPipelineLayout> AttachmentRateInstance::buildPipelineLayout(VkDevice device, const vk::DeviceInterface &vk,
654                                                                    const VkDescriptorSetLayout *setLayouts) const
655 {
656     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
657         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
658         DE_NULL,                                       // const void* pNext;
659         (VkPipelineLayoutCreateFlags)0,                // VkPipelineLayoutCreateFlags flags;
660         (setLayouts != DE_NULL),                       // uint32_t setLayoutCount;
661         setLayouts,                                    // const VkDescriptorSetLayout* pSetLayouts;
662         0u,                                            // uint32_t pushConstantRangeCount;
663         DE_NULL,                                       // const VkPushConstantRange* pPushConstantRanges;
664     };
665 
666     return createPipelineLayout(vk, device, &pipelineLayoutCreateInfo, NULL);
667 }
668 
buildGraphicsPipeline(VkDevice device,const vk::DeviceInterface & vk,uint32_t subpass,VkRenderPass renderPass,VkFormat cbFormat,VkFormat dsFormat,VkPipelineLayout pipelineLayout,VkShaderModule vertShader,VkShaderModule fragShader,bool useShadingRate) const669 Move<VkPipeline> AttachmentRateInstance::buildGraphicsPipeline(VkDevice device, const vk::DeviceInterface &vk,
670                                                                uint32_t subpass, VkRenderPass renderPass,
671                                                                VkFormat cbFormat, VkFormat dsFormat,
672                                                                VkPipelineLayout pipelineLayout,
673                                                                VkShaderModule vertShader, VkShaderModule fragShader,
674                                                                bool useShadingRate) const
675 {
676     const auto dsAspects        = getFormatAspectFlags(dsFormat);
677     const auto hasDepth         = ((dsAspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0);
678     const auto hasStencil       = ((dsAspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
679     const auto depthCompareOp   = (hasDepth ? VK_COMPARE_OP_ALWAYS : VK_COMPARE_OP_LESS_OR_EQUAL);
680     const auto stencilCompareOp = (hasStencil ? VK_COMPARE_OP_ALWAYS : VK_COMPARE_OP_NEVER);
681 
682     std::vector<VkPipelineShaderStageCreateInfo> pipelineShaderStageParams(
683         2,
684         {
685             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType                                sType
686             DE_NULL,                                             // const void*                                    pNext
687             0u,                         // VkPipelineShaderStageCreateFlags                flags
688             VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits                        stage
689             vertShader,                 // VkShaderModule                                module
690             "main",                     // const char*                                    pName
691             DE_NULL                     // const VkSpecializationInfo*                    pSpecializationInfo
692         });
693 
694     pipelineShaderStageParams[1].stage  = VK_SHADER_STAGE_FRAGMENT_BIT;
695     pipelineShaderStageParams[1].module = fragShader;
696 
697     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{
698         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType                                sType
699         DE_NULL,                                  // const void*                                    pNext
700         (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags        flags
701         0u,      // uint32_t                                        vertexBindingDescriptionCount
702         DE_NULL, // const VkVertexInputBindingDescription*        pVertexBindingDescriptions
703         0u,      // uint32_t                                        vertexAttributeDescriptionCount
704         DE_NULL  // const VkVertexInputAttributeDescription*        pVertexAttributeDescriptions
705     };
706 
707     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{
708         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType                                sType
709         DE_NULL,                              // const void*                                    pNext
710         0u,                                   // VkPipelineInputAssemblyStateCreateFlags        flags
711         VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, // VkPrimitiveTopology                            topology
712         VK_FALSE                              // VkBool32                                        primitiveRestartEnable
713     };
714 
715     tcu::UVec2 size(m_cbWidth, m_cbHeight);
716     VkViewport viewport = makeViewport(size);
717     VkRect2D scissor    = makeRect2D(size);
718 
719     const VkPipelineViewportStateCreateInfo viewportStateCreateInfo{
720         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType                                sType
721         DE_NULL,                                               // const void*                                    pNext
722         (VkPipelineViewportStateCreateFlags)0,                 // VkPipelineViewportStateCreateFlags            flags
723         1u,        // uint32_t                                        viewportCount
724         &viewport, // const VkViewport*                            pViewports
725         1u,        // uint32_t                                        scissorCount
726         &scissor   // const VkRect2D*                                pScissors
727     };
728 
729     const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo{
730         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType                                sType
731         DE_NULL,                         // const void*                                    pNext
732         0u,                              // VkPipelineRasterizationStateCreateFlags        flags
733         VK_FALSE,                        // VkBool32                                        depthClampEnable
734         VK_FALSE,                        // VkBool32                                        rasterizerDiscardEnable
735         VK_POLYGON_MODE_FILL,            // VkPolygonMode                                polygonMode
736         VK_CULL_MODE_NONE,               // VkCullModeFlags                                cullMode
737         VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace                                    frontFace
738         VK_FALSE,                        // VkBool32                                        depthBiasEnable
739         0.0f,                            // float                                        depthBiasConstantFactor
740         0.0f,                            // float                                        depthBiasClamp
741         0.0f,                            // float                                        depthBiasSlopeFactor
742         1.0f                             // float                                        lineWidth
743     };
744 
745     const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{
746         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType                                sType
747         DE_NULL,               // const void*                                    pNext
748         0u,                    // VkPipelineMultisampleStateCreateFlags        flags
749         VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits                        rasterizationSamples
750         VK_FALSE,              // VkBool32                                        sampleShadingEnable
751         1.0f,                  // float                                        minSampleShading
752         DE_NULL,               // const VkSampleMask*                            pSampleMask
753         VK_FALSE,              // VkBool32                                        alphaToCoverageEnable
754         VK_FALSE               // VkBool32                                        alphaToOneEnable
755     };
756 
757     const VkStencilOpState stencilOpState{
758         VK_STENCIL_OP_KEEP, // VkStencilOp                                    failOp
759         VK_STENCIL_OP_KEEP, // VkStencilOp                                    passOp
760         VK_STENCIL_OP_KEEP, // VkStencilOp                                    depthFailOp
761         stencilCompareOp,   // VkCompareOp                                    compareOp
762         0,                  // uint32_t                                        compareMask
763         0,                  // uint32_t                                        writeMask
764         0                   // uint32_t                                        reference
765     };
766 
767     const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo{
768         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType                                sType
769         DE_NULL,        // const void*                                    pNext
770         0u,             // VkPipelineDepthStencilStateCreateFlags        flags
771         hasDepth,       // VkBool32                                        depthTestEnable
772         VK_FALSE,       // VkBool32                                        depthWriteEnable
773         depthCompareOp, // VkCompareOp                                    depthCompareOp
774         VK_FALSE,       // VkBool32                                        depthBoundsTestEnable
775         hasStencil,     // VkBool32                                        stencilTestEnable
776         stencilOpState, // VkStencilOpState                                front
777         stencilOpState, // VkStencilOpState                                back
778         0.0f,           // float                                        minDepthBounds
779         1.0f,           // float                                        maxDepthBounds
780     };
781 
782     const VkPipelineColorBlendAttachmentState colorBlendAttachmentState{
783         VK_FALSE,                // VkBool32                                        blendEnable
784         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor                                srcColorBlendFactor
785         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor                                dstColorBlendFactor
786         VK_BLEND_OP_ADD,         // VkBlendOp                                    colorBlendOp
787         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor                                srcAlphaBlendFactor
788         VK_BLEND_FACTOR_ZERO,    // VkBlendFactor                                dstAlphaBlendFactor
789         VK_BLEND_OP_ADD,         // VkBlendOp                                    alphaBlendOp
790         VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags                        colorWriteMask
791             | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
792 
793     const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo{
794         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType                                sType
795         DE_NULL,                    // const void*                                    pNext
796         0u,                         // VkPipelineColorBlendStateCreateFlags            flags
797         VK_FALSE,                   // VkBool32                                        logicOpEnable
798         VK_LOGIC_OP_CLEAR,          // VkLogicOp                                    logicOp
799         1u,                         // uint32_t                                        attachmentCount
800         &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState*    pAttachments
801         {0.0f, 0.0f, 0.0f, 0.0f}    // float                                        blendConstants[4]
802     };
803 
804     const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{
805         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType                                sType
806         DE_NULL,                                              // const void*                                    pNext
807         0u,                                                   // VkPipelineDynamicStateCreateFlags            flags
808         0u,     // uint32_t                                        dynamicStateCount
809         DE_NULL // const VkDynamicState*                        pDynamicStates
810     };
811 
812     VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo{
813         VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType;
814         DE_NULL,                                                                // const void* pNext;
815         {1, 1},                                                                 // VkExtent2D fragmentSize;
816         {VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR,
817          VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR} // VkFragmentShadingRateCombinerOpKHR combinerOps[2];
818     };
819 
820     void *pNext = useShadingRate ? &shadingRateStateCreateInfo : DE_NULL;
821 #ifndef CTS_USES_VULKANSC
822     VkPipelineRenderingCreateInfoKHR renderingCreateInfo{
823         VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, pNext, 0u, 1u, &cbFormat, dsFormat, VK_FORMAT_UNDEFINED};
824 
825     if (m_params->useDynamicRendering)
826         pNext = &renderingCreateInfo;
827 #else
828     DE_UNREF(cbFormat);
829 #endif // CTS_USES_VULKANSC
830 
831     VkGraphicsPipelineCreateInfo pipelineCreateInfo{
832         VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType                                    sType
833         pNext,                                           // const void*                                        pNext
834         0u,                                              // VkPipelineCreateFlags                            flags
835         (uint32_t)pipelineShaderStageParams.size(), // uint32_t                                            stageCount
836         &pipelineShaderStageParams[0],              // const VkPipelineShaderStageCreateInfo*            pStages
837         &vertexInputStateCreateInfo,   // const VkPipelineVertexInputStateCreateInfo*        pVertexInputState
838         &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo*    pInputAssemblyState
839         DE_NULL,                       // const VkPipelineTessellationStateCreateInfo*        pTessellationState
840         &viewportStateCreateInfo,      // const VkPipelineViewportStateCreateInfo*            pViewportState
841         &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo*    pRasterizationState
842         &multisampleStateCreateInfo,   // const VkPipelineMultisampleStateCreateInfo*        pMultisampleState
843         &depthStencilStateCreateInfo,  // const VkPipelineDepthStencilStateCreateInfo*        pDepthStencilState
844         &colorBlendStateCreateInfo,    // const VkPipelineColorBlendStateCreateInfo*        pColorBlendState
845         &dynamicStateCreateInfo,       // const VkPipelineDynamicStateCreateInfo*            pDynamicState
846         pipelineLayout,                // VkPipelineLayout                                    layout
847         renderPass,                    // VkRenderPass                                        renderPass
848         subpass,                       // uint32_t                                            subpass
849         DE_NULL,                       // VkPipeline                                        basePipelineHandle
850         0                              // int32_t basePipelineIndex;
851     };
852 
853 #ifndef CTS_USES_VULKANSC
854     VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo = initVulkanStructure(pNext);
855     if (useShadingRate && m_params->useDynamicRendering)
856     {
857         if (m_params->mode == TM_MAINTENANCE_5)
858         {
859             pipelineFlags2CreateInfo.flags = VK_PIPELINE_CREATE_2_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
860             pipelineCreateInfo.pNext       = &pipelineFlags2CreateInfo;
861         }
862         else
863             pipelineCreateInfo.flags |= VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
864     }
865 #endif // CTS_USES_VULKANSC
866 
867     return createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
868 }
869 
buildComputePipeline(VkDevice device,const vk::DeviceInterface & vk,VkShaderModule compShader,VkPipelineLayout pipelineLayout) const870 Move<VkPipeline> AttachmentRateInstance::buildComputePipeline(VkDevice device, const vk::DeviceInterface &vk,
871                                                               VkShaderModule compShader,
872                                                               VkPipelineLayout pipelineLayout) const
873 {
874     const VkPipelineShaderStageCreateInfo stageCreateInfo{
875         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
876         DE_NULL,                                             // const void* pNext;
877         0u,                                                  // VkPipelineShaderStageCreateFlags flags;
878         VK_SHADER_STAGE_COMPUTE_BIT,                         // VkShaderStageFlagBits stage;
879         compShader,                                          // VkShaderModule module;
880         "main",                                              // const char* pName;
881         DE_NULL                                              // const VkSpecializationInfo* pSpecializationInfo;
882     };
883 
884     const VkComputePipelineCreateInfo createInfo{
885         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
886         DE_NULL,                                        // const void* pNext;
887         0u,                                             // VkPipelineCreateFlags flags;
888         stageCreateInfo,                                // VkPipelineShaderStageCreateInfo stage;
889         pipelineLayout,                                 // VkPipelineLayout layout;
890         (VkPipeline)0,                                  // VkPipeline basePipelineHandle;
891         0u,                                             // int32_t basePipelineIndex;
892     };
893 
894     return createComputePipeline(vk, device, (vk::VkPipelineCache)0u, &createInfo);
895 }
896 
makeDescriptorSetAllocInfo(VkDescriptorPool descriptorPool,const VkDescriptorSetLayout * pSetLayouts) const897 VkDescriptorSetAllocateInfo AttachmentRateInstance::makeDescriptorSetAllocInfo(
898     VkDescriptorPool descriptorPool, const VkDescriptorSetLayout *pSetLayouts) const
899 {
900     return {
901         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
902         DE_NULL,                                        // const void* pNext;
903         descriptorPool,                                 // VkDescriptorPool descriptorPool;
904         1u,                                             // uint32_t setLayoutCount;
905         pSetLayouts,                                    // const VkDescriptorSetLayout* pSetLayouts;
906     };
907 }
908 
startRendering(const VkCommandBuffer commandBuffer,const VkRenderPass renderPass,const VkFramebuffer framebuffer,const VkRect2D & renderArea,const std::vector<FBAttachmentInfo> & attachmentInfo,const uint32_t srTileWidth,const uint32_t srTileHeight) const909 void AttachmentRateInstance::startRendering(const VkCommandBuffer commandBuffer, const VkRenderPass renderPass,
910                                             const VkFramebuffer framebuffer, const VkRect2D &renderArea,
911                                             const std::vector<FBAttachmentInfo> &attachmentInfo,
912                                             const uint32_t srTileWidth, const uint32_t srTileHeight) const
913 {
914     const DeviceInterface &vk(m_context.getDeviceInterface());
915     std::vector<VkClearValue> clearColor(attachmentInfo.size(), makeClearValueColorU32(0, 0, 0, 0));
916 
917 #ifndef CTS_USES_VULKANSC
918     if (m_params->useDynamicRendering)
919     {
920         VkRenderingFragmentShadingRateAttachmentInfoKHR shadingRateAttachmentInfo{
921             VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, // VkStructureType sType;
922             DE_NULL,                                                               // const void* pNext;
923             DE_NULL,                                                               // VkImageView imageView;
924             VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,          // VkImageLayout imageLayout;
925             {0, 0} // VkExtent2D shadingRateAttachmentTexelSize;
926         };
927 
928         VkRenderingAttachmentInfoKHR colorAttachment{
929             vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType;
930             DE_NULL,                                             // const void* pNext;
931             attachmentInfo[0].view,                              // VkImageView imageView;
932             VK_IMAGE_LAYOUT_GENERAL,                             // VkImageLayout imageLayout;
933             VK_RESOLVE_MODE_NONE,                                // VkResolveModeFlagBits resolveMode;
934             DE_NULL,                                             // VkImageView resolveImageView;
935             VK_IMAGE_LAYOUT_UNDEFINED,                           // VkImageLayout resolveImageLayout;
936             VK_ATTACHMENT_LOAD_OP_CLEAR,                         // VkAttachmentLoadOp loadOp;
937             VK_ATTACHMENT_STORE_OP_STORE,                        // VkAttachmentStoreOp storeOp;
938             clearColor[0]                                        // VkClearValue clearValue;
939         };
940 
941         VkRenderingInfoKHR renderingInfo{
942             vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
943             DE_NULL,
944             0,                // VkRenderingFlagsKHR flags;
945             renderArea,       // VkRect2D renderArea;
946             1u,               // uint32_t layerCount;
947             0u,               // uint32_t viewMask;
948             1u,               // uint32_t colorAttachmentCount;
949             &colorAttachment, // const VkRenderingAttachmentInfoKHR* pColorAttachments;
950             DE_NULL,          // const VkRenderingAttachmentInfoKHR* pDepthAttachment;
951             DE_NULL,          // const VkRenderingAttachmentInfoKHR* pStencilAttachment;
952         };
953 
954         // when shading rate is used it is defined as a second entry in attachmentInfo
955         if ((attachmentInfo.size() == 2) &&
956             (attachmentInfo[1].usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR))
957         {
958             if (!m_params->useNullShadingRateImage)
959             {
960                 shadingRateAttachmentInfo.imageView = attachmentInfo[1].view;
961             }
962 
963             shadingRateAttachmentInfo.shadingRateAttachmentTexelSize = {srTileWidth, srTileHeight};
964             renderingInfo.pNext                                      = &shadingRateAttachmentInfo;
965         }
966 
967         vk.cmdBeginRendering(commandBuffer, &renderingInfo);
968 
969         return;
970     }
971 #else
972     DE_UNREF(srTileWidth);
973     DE_UNREF(srTileHeight);
974 #endif // CTS_USES_VULKANSC
975 
976     std::vector<VkImageView> attachments(attachmentInfo.size(), 0);
977     VkRenderPassAttachmentBeginInfo renderPassAttachmentBeginInfo;
978     void *pNext(DE_NULL);
979 
980     if (m_params->useImagelessFramebuffer)
981     {
982         // create array containing attachment views
983         for (uint32_t i = 0; i < (uint32_t)attachmentInfo.size(); ++i)
984             attachments[i] = attachmentInfo[i].view;
985 
986         renderPassAttachmentBeginInfo = {
987             VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO, // VkStructureType sType;
988             DE_NULL,                                             // const void* pNext;
989             (uint32_t)attachments.size(),                        // uint32_t attachmentCount;
990             attachments.data()                                   // const VkImageView* pAttachments;
991         };
992 
993         pNext = &renderPassAttachmentBeginInfo;
994     }
995 
996     beginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea, (uint32_t)clearColor.size(),
997                     clearColor.data(), VK_SUBPASS_CONTENTS_INLINE, pNext);
998 }
999 
finishRendering(const VkCommandBuffer commandBuffer) const1000 void AttachmentRateInstance::finishRendering(const VkCommandBuffer commandBuffer) const
1001 {
1002     const DeviceInterface &vk = m_context.getDeviceInterface();
1003 
1004 #ifndef CTS_USES_VULKANSC
1005     if (m_params->useDynamicRendering)
1006         endRendering(vk, commandBuffer);
1007     else
1008 #endif // CTS_USES_VULKANSC
1009         endRenderPass(vk, commandBuffer);
1010 }
1011 
iterate(void)1012 tcu::TestStatus AttachmentRateInstance::iterate(void)
1013 {
1014     // instead of creating many classes that derive from large common class
1015     // each test mode is defined in separate run* method, those methods
1016     // then use same helper methods defined in this class
1017 
1018     typedef bool (AttachmentRateInstance::*MethodPtr)();
1019     const std::map<TestMode, MethodPtr> modeFuncMap{
1020         {TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER, &AttachmentRateInstance::runComputeShaderMode},
1021         {TM_SETUP_RATE_WITH_FRAGMENT_SHADER, &AttachmentRateInstance::runFragmentShaderMode},
1022         {TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE, &AttachmentRateInstance::runCopyMode},
1023         {TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE,
1024          &AttachmentRateInstance::runCopyModeOnTransferQueue},
1025         {TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE,
1026          &AttachmentRateInstance::runCopyModeOnTransferQueue},
1027         {TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE, &AttachmentRateInstance::runFillLinearTiledImage},
1028         {TM_TWO_SUBPASS, &AttachmentRateInstance::runTwoSubpassMode},
1029         {TM_MEMORY_ACCESS, &AttachmentRateInstance::runFragmentShaderMode},
1030         {TM_MAINTENANCE_5, &AttachmentRateInstance::runFragmentShaderMode},
1031     };
1032 
1033     if ((this->*modeFuncMap.at(m_params->mode))())
1034         return tcu::TestStatus::pass("Pass");
1035 
1036     return tcu::TestStatus::fail("Fail");
1037 }
1038 
verifyUsingAtomicChecks(uint32_t tileWidth,uint32_t tileHeight,uint32_t rateWidth,uint32_t rateHeight,uint32_t * outBufferPtr) const1039 bool AttachmentRateInstance::verifyUsingAtomicChecks(uint32_t tileWidth, uint32_t tileHeight, uint32_t rateWidth,
1040                                                      uint32_t rateHeight, uint32_t *outBufferPtr) const
1041 {
1042     tcu::TestLog &log(m_context.getTestContext().getLog());
1043     tcu::TextureLevel errorMaskStorage(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8),
1044                                        m_cbWidth, m_cbHeight, 1u);
1045     tcu::PixelBufferAccess errorMaskAccess(errorMaskStorage.getAccess());
1046 
1047     uint32_t wrongFragments                          = 0;
1048     const uint32_t fragmentsWithSameAtomicValueCount = rateWidth * rateHeight;
1049 
1050     // map that uses atomic value as a kay and maps it to all fragments sharing same atomic
1051     std::map<uint32_t, std::vector<tcu::UVec2>> fragmentsWithSameAtomicValueMap;
1052 
1053     // this method asumes that top and left edge of triangle are parallel to axes
1054     // and we can store just single coordinate for those edges
1055     uint32_t triangleLeftEdgeX = 0;
1056     uint32_t triangleTopEdgeY  = 0;
1057 
1058     // this method assumes that greatest angle in the triangle points to the top-left corner of FB;
1059     // these vectors will then store fragments on the right and bottom edges of triangle respectively;
1060     // for the right edge vector, the index represents y coordinate and value is x;
1061     // for the bottom edge vector, the index represents x coordinate and value is y
1062     std::vector<uint32_t> fragmentsOnTheRightTriangleEdgeVect(m_cbHeight, 0);
1063     std::vector<uint32_t> fragmentsOnTheBottomTriangleEdgeVect(m_cbWidth, 0);
1064 
1065     tcu::clear(errorMaskAccess, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0));
1066 
1067     // loop over all fragments and validate the output
1068     for (uint32_t cbFragmentY = 0; cbFragmentY < m_cbHeight; ++cbFragmentY)
1069         for (uint32_t cbFragmentX = 0; cbFragmentX < m_cbWidth; ++cbFragmentX)
1070         {
1071             uint32_t *fragmentColor = &outBufferPtr[4 * (cbFragmentY * m_cbWidth + cbFragmentX)];
1072 
1073             // fragment not covered by primitive, skip it
1074             if (fragmentColor[2] == 0)
1075                 continue;
1076 
1077             // first fragment we hit will define top and left triangle edges
1078             if ((triangleTopEdgeY + triangleLeftEdgeX) == 0)
1079             {
1080                 triangleLeftEdgeX = cbFragmentX;
1081                 triangleTopEdgeY  = cbFragmentY;
1082             }
1083 
1084             // constantly overwrite coordinate on right edge so that we are left with the farthest one
1085             fragmentsOnTheRightTriangleEdgeVect[cbFragmentY] = cbFragmentX;
1086 
1087             // constantly overwrite coordinate on bottom edge so that we are left with the farthest one
1088             fragmentsOnTheBottomTriangleEdgeVect[cbFragmentX] = cbFragmentY;
1089 
1090             // make sure that fragment g and a components are 0
1091             if ((fragmentColor[1] != 0) || (fragmentColor[3] != 0))
1092             {
1093                 ++wrongFragments;
1094                 continue;
1095             }
1096 
1097             uint32_t rate          = fragmentColor[0];
1098             uint32_t fragmentRateX = 1 << ((rate / 4) & 3);
1099             uint32_t fragmentRateY = 1 << (rate & 3);
1100 
1101             // check if proper rate was used for fragment
1102             if ((fragmentRateX != rateWidth) || (fragmentRateY != rateHeight))
1103             {
1104                 ++wrongFragments;
1105                 errorMaskAccess.setPixel(tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f), cbFragmentX, cbFragmentY, 0u);
1106                 continue;
1107             }
1108 
1109             // mark correct fragments using few green shades so rates are visible
1110             uint32_t atomicValue = fragmentColor[2];
1111             errorMaskAccess.setPixel(tcu::Vec4(0.0f, 1.0f - float(atomicValue % 7) * 0.1f, 0.0f, 1.0f), cbFragmentX,
1112                                      cbFragmentY, 0u);
1113 
1114             // find proper set in map and add value to it after doing verification with existing items
1115             auto fragmentsSetMapIt = fragmentsWithSameAtomicValueMap.find(atomicValue);
1116             if (fragmentsSetMapIt == fragmentsWithSameAtomicValueMap.end())
1117             {
1118                 fragmentsWithSameAtomicValueMap[atomicValue] = {tcu::UVec2(cbFragmentX, cbFragmentY)};
1119                 fragmentsWithSameAtomicValueMap[atomicValue].reserve(fragmentsWithSameAtomicValueCount);
1120             }
1121             else
1122             {
1123                 // make sure that fragments added to set are near the top-left fragment
1124                 auto &fragmentsSet = fragmentsSetMapIt->second;
1125                 if (((cbFragmentX - fragmentsSet[0].x()) > rateWidth) ||
1126                     ((cbFragmentY - fragmentsSet[0].y()) > rateHeight))
1127                 {
1128                     ++wrongFragments;
1129                     errorMaskAccess.setPixel(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), cbFragmentX, cbFragmentY, 0u);
1130                 }
1131 
1132                 fragmentsWithSameAtomicValueMap[atomicValue].emplace_back(cbFragmentX, cbFragmentY);
1133             }
1134         }
1135 
1136     // check if there are no valid fragmenst at all
1137     if ((triangleTopEdgeY + triangleLeftEdgeX) == 0)
1138     {
1139         log << tcu::TestLog::Message << "No valid fragments." << tcu::TestLog::EndMessage;
1140         return false;
1141     }
1142 
1143     // if checks failed skip checking other tile sizes
1144     if (wrongFragments)
1145     {
1146         log << tcu::TestLog::Message << "Failed " << wrongFragments << " fragments for tileWidth: " << tileWidth
1147             << ", tileHeight: " << tileHeight << tcu::TestLog::EndMessage
1148             << tcu::TestLog::Image("ErrorMask", "Error mask", errorMaskAccess);
1149         return false;
1150     }
1151 
1152     // do additional checks
1153     tcu::Vec4 fragmentColor(0.0f, 1.0f, 0.0f, 1.0f);
1154 
1155     tcu::clear(errorMaskAccess, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0));
1156 
1157     // make sure that there is same number of fragments that share same atomic value
1158     for (auto &fragmentsSetMapIt : fragmentsWithSameAtomicValueMap)
1159     {
1160         // mark correct fragments using few green shades so rates are visible
1161         fragmentColor = tcu::Vec4(0.0f, 1.0f - float(fragmentsSetMapIt.first % 7) * 0.1f, 0.0f, 1.0f);
1162 
1163         const auto &fragmentSet = fragmentsSetMapIt.second;
1164         ;
1165         if (fragmentSet.size() != fragmentsWithSameAtomicValueCount)
1166         {
1167             const auto &topLeftFragment  = fragmentSet[0];
1168             uint32_t triangleRightEdgeX  = fragmentsOnTheRightTriangleEdgeVect[topLeftFragment.y()];
1169             uint32_t triangleBottomEdgeY = fragmentsOnTheBottomTriangleEdgeVect[topLeftFragment.x()];
1170 
1171             // we can only count this as an error if set is fully inside of triangle, sets on
1172             // edges may not have same number of fragments as sets fully located in the triangle
1173             if ((topLeftFragment.y() > (triangleTopEdgeY)) && (topLeftFragment.x() > (triangleLeftEdgeX)) &&
1174                 (topLeftFragment.x() < (triangleRightEdgeX - rateWidth)) &&
1175                 (topLeftFragment.y() < (triangleBottomEdgeY - rateHeight)))
1176             {
1177                 wrongFragments += (uint32_t)fragmentSet.size();
1178                 fragmentColor = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1179             }
1180         }
1181 
1182         // mark all fragmens from set with proper color
1183         for (auto &fragment : fragmentSet)
1184             errorMaskAccess.setPixel(fragmentColor, fragment.x(), fragment.y(), 0u);
1185     }
1186 
1187     if (wrongFragments)
1188     {
1189         log << tcu::TestLog::Message << "Wrong number of fragments with same atomic value (" << wrongFragments
1190             << ") for tileWidth: " << tileWidth << ", tileHeight: " << tileHeight << tcu::TestLog::EndMessage
1191             << tcu::TestLog::Image("ErrorMask", "Error mask", errorMaskAccess);
1192         return false;
1193     }
1194 
1195     return true;
1196 }
1197 
runComputeShaderMode(void)1198 bool AttachmentRateInstance::runComputeShaderMode(void)
1199 {
1200     // clear the shading rate attachment, then using a compute shader, set the shading rate attachment
1201     // values to the desired rate using various atomic operations, then use it to draw a basic triangle
1202     // and do basic checks
1203 
1204     const DeviceInterface &vk = m_context.getDeviceInterface();
1205     VkDevice device           = m_context.getDevice();
1206     uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1207     VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u};
1208 
1209     Move<VkShaderModule> compShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0);
1210     Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
1211     Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
1212 
1213     Move<VkCommandPool> cmdPool =
1214         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
1215     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1216 
1217     // setup descriptor set with storage image for compute pipeline
1218     Move<VkDescriptorSetLayout> computeDescriptorSetLayout =
1219         DescriptorSetLayoutBuilder()
1220             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1221             .build(vk, device);
1222     Move<VkDescriptorPool> computeDescriptorPool =
1223         DescriptorPoolBuilder()
1224             .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
1225             .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1226     const VkDescriptorSetAllocateInfo computeDescriptorSetAllocInfo =
1227         makeDescriptorSetAllocInfo(*computeDescriptorPool, &(*computeDescriptorSetLayout));
1228     Move<VkDescriptorSet> computeDescriptorSet = allocateDescriptorSet(vk, device, &computeDescriptorSetAllocInfo);
1229 
1230     m_srUsage |= VK_IMAGE_USAGE_STORAGE_BIT;
1231 
1232     buildCounterBufferObjects(device, vk, m_context.getDefaultAllocator());
1233     buildColorBufferObjects(device, vk, m_context.getDefaultAllocator(), 0, m_cbUsage);
1234 
1235     // iterate over all possible tile sizes
1236     for (uint32_t tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
1237         for (uint32_t tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
1238         {
1239             // skip tile sizes that have unsuported aspect ratio
1240             uint32_t aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
1241             if (aspectRatio > m_maxAspectRatio)
1242                 continue;
1243 
1244             // calculate size of shading rate attachment
1245             uint32_t srWidth  = (m_cbWidth + tileWidth - 1) / tileWidth;
1246             uint32_t srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
1247 
1248             buildShadingRateObjects(device, vk, m_context.getDefaultAllocator(), 0, srWidth, srHeight, m_srUsage);
1249 
1250             const VkDescriptorImageInfo computeDescriptorInfo =
1251                 makeDescriptorImageInfo(DE_NULL, *m_srImageView[0], VK_IMAGE_LAYOUT_GENERAL);
1252             DescriptorSetUpdateBuilder()
1253                 .writeSingle(*computeDescriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1254                              VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &computeDescriptorInfo)
1255                 .update(vk, device);
1256 
1257             const auto dsFormat = m_params->getDSFormat();
1258             Move<VkPipelineLayout> computePipelineLayout =
1259                 buildPipelineLayout(device, vk, &(*computeDescriptorSetLayout));
1260             Move<VkPipelineLayout> graphicsPipelineLayout =
1261                 buildPipelineLayout(device, vk, &(*m_counterBufferDescriptorSetLayout));
1262             Move<VkPipeline> computePipeline = buildComputePipeline(device, vk, *compShader, *computePipelineLayout);
1263             Move<VkRenderPass> renderPass    = buildRenderPass(device, vk, m_cbFormat, dsFormat, tileWidth, tileHeight);
1264             Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(
1265                 device, vk, 0, *renderPass, m_cbFormat, dsFormat, *graphicsPipelineLayout, *vertShader, *fragShader);
1266 
1267             std::vector<FBAttachmentInfo> attachmentInfo{
1268                 {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0]},
1269                 {m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0]},
1270             };
1271             // This would need an additional attachment with m_dsImageView and a barrier to transition the DS layout.
1272             // See runFragmentShaderMode for more details.
1273             DE_ASSERT(!m_params->useDepthStencil());
1274 
1275             Move<VkFramebuffer> framebuffer = buildFramebuffer(device, vk, *renderPass, attachmentInfo);
1276 
1277             beginCommandBuffer(vk, *cmdBuffer, 0u);
1278 
1279             // wait till sr image layout is changed
1280             VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1281             VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1282             VkImageMemoryBarrier srImageBarrierGeneral =
1283                 makeImageMemoryBarrier(VK_ACCESS_NONE_KHR, VK_ACCESS_NONE_KHR, VK_IMAGE_LAYOUT_UNDEFINED,
1284                                        VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0], m_defaultImageSubresourceRange);
1285             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1286                                   &srImageBarrierGeneral);
1287 
1288             // fill sr image using compute shader
1289             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
1290             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0, 1,
1291                                      &(*computeDescriptorSet), 0, DE_NULL);
1292             vk.cmdDispatch(*cmdBuffer, srWidth, srHeight, 1);
1293 
1294             // wait till sr image is ready and change sr images layout
1295             srcStageMask                                   = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
1296             dstStageMask                                   = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
1297             memoryBarrier.srcAccessMask                    = VK_ACCESS_SHADER_WRITE_BIT;
1298             memoryBarrier.dstAccessMask                    = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
1299             VkImageMemoryBarrier srImageBarrierShadingRate = makeImageMemoryBarrier(
1300                 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
1301                 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, **m_srImage[0],
1302                 m_defaultImageSubresourceRange);
1303             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 1,
1304                                   &srImageBarrierShadingRate);
1305 
1306             // wait till cb image layout is changed
1307             srcStageMask                        = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1308             dstStageMask                        = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1309             VkImageMemoryBarrier cbImageBarrier = makeImageMemoryBarrier(
1310                 VK_ACCESS_NONE_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1311                 VK_IMAGE_LAYOUT_GENERAL, **m_cbImage[0], m_defaultImageSubresourceRange);
1312             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1313                                   &cbImageBarrier);
1314 
1315             startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo,
1316                            tileWidth, tileHeight);
1317 
1318             // draw single triangle to cb
1319             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1,
1320                                      &(*m_counterBufferDescriptorSet), 0, DE_NULL);
1321             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
1322             vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
1323 
1324             finishRendering(*cmdBuffer);
1325 
1326             // wait till color attachment is fully written
1327             srcStageMask                = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1328             dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1329             memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1330             memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1331             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
1332 
1333             // read back color buffer image
1334             vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u,
1335                                     &m_defaultBufferImageCopy);
1336 
1337             endCommandBuffer(vk, *cmdBuffer);
1338 
1339             // submit commands and wait
1340             const VkQueue queue = m_context.getUniversalQueue();
1341             submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
1342 
1343             invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
1344             if (!verifyUsingAtomicChecks(tileWidth, tileHeight, m_params->srRate.width, m_params->srRate.height,
1345                                          (uint32_t *)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
1346                 return false;
1347 
1348         } // iterate over all possible tile sizes
1349 
1350     return true;
1351 }
1352 
runFragmentShaderMode(void)1353 bool AttachmentRateInstance::runFragmentShaderMode(void)
1354 {
1355     // Set up the image as a color attachment, and render rate to it,
1356     // then use it to draw a basic triangle and do basic checks
1357 
1358     const DeviceInterface &vk = m_context.getDeviceInterface();
1359     VkDevice device           = m_context.getDevice();
1360     uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1361     VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u};
1362     const bool useMemoryAccess = (m_params->mode == TM_MEMORY_ACCESS);
1363 
1364     Move<VkShaderModule> vertSetupShader =
1365         createShaderModule(vk, device, m_context.getBinaryCollection().get("vert_setup"), 0);
1366     Move<VkShaderModule> fragSetupShader =
1367         createShaderModule(vk, device, m_context.getBinaryCollection().get("frag_setup"), 0);
1368     Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
1369     Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
1370 
1371     Move<VkCommandPool> cmdPool =
1372         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
1373     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1374 
1375     m_srUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1376 
1377     buildCounterBufferObjects(device, vk, m_context.getDefaultAllocator());
1378     buildColorBufferObjects(device, vk, m_context.getDefaultAllocator(), 0, m_cbUsage);
1379 
1380     // iterate over all possible tile sizes
1381     for (uint32_t tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
1382         for (uint32_t tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
1383         {
1384             // skip tile sizes that have unsuported aspect ratio
1385             uint32_t aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
1386             if (aspectRatio > m_maxAspectRatio)
1387                 continue;
1388 
1389             // calculate size of shading rate attachment
1390             uint32_t srWidth  = (m_cbWidth + tileWidth - 1) / tileWidth;
1391             uint32_t srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
1392 
1393             buildShadingRateObjects(device, vk, m_context.getDefaultAllocator(), 0, srWidth, srHeight, m_srUsage);
1394 
1395             const auto dsFormat                        = m_params->getDSFormat();
1396             Move<VkPipelineLayout> setupPipelineLayout = buildPipelineLayout(device, vk);
1397             Move<VkPipelineLayout> ratePipelineLayout =
1398                 buildPipelineLayout(device, vk, &(*m_counterBufferDescriptorSetLayout));
1399             Move<VkRenderPass> setupRenderPass = buildRenderPass(device, vk, m_params->srFormat, VK_FORMAT_UNDEFINED);
1400             Move<VkRenderPass> rateRenderPass =
1401                 buildRenderPass(device, vk, m_cbFormat, dsFormat, tileWidth, tileHeight);
1402             Move<VkPipeline> setupPipeline =
1403                 buildGraphicsPipeline(device, vk, 0, *setupRenderPass, m_params->srFormat, VK_FORMAT_UNDEFINED,
1404                                       *setupPipelineLayout, *vertSetupShader, *fragSetupShader, false);
1405             Move<VkPipeline> ratePipeline = buildGraphicsPipeline(device, vk, 0, *rateRenderPass, m_cbFormat, dsFormat,
1406                                                                   *ratePipelineLayout, *vertShader, *fragShader);
1407 
1408             std::vector<FBAttachmentInfo> setupAttachmentInfo{
1409                 {m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0]}};
1410             std::vector<FBAttachmentInfo> rateAttachmentInfo{
1411                 {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0]},
1412                 {m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0]},
1413             };
1414             if (m_params->useDepthStencil())
1415                 rateAttachmentInfo.push_back(
1416                     FBAttachmentInfo{dsFormat, kDSUsage, m_cbWidth, m_cbHeight, *m_dsImageView});
1417 
1418             Move<VkFramebuffer> setupFramebuffer = buildFramebuffer(device, vk, *setupRenderPass, setupAttachmentInfo);
1419             Move<VkFramebuffer> rateFramebuffer  = buildFramebuffer(device, vk, *rateRenderPass, rateAttachmentInfo);
1420 
1421             beginCommandBuffer(vk, *cmdBuffer, 0u);
1422 
1423             // wait till sr image layout is changed
1424             VkPipelineStageFlags srcStageMask          = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1425             VkPipelineStageFlags dstStageMask          = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1426             VkImageMemoryBarrier srImageBarrierGeneral = makeImageMemoryBarrier(
1427                 VK_ACCESS_NONE_KHR, useMemoryAccess ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1428                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0], m_defaultImageSubresourceRange);
1429             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1430                                   &srImageBarrierGeneral);
1431 
1432             if (m_params->useDepthStencil())
1433             {
1434                 const VkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1435                 const VkPipelineStageFlags dstStage =
1436                     (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
1437                 VkImageMemoryBarrier depthImageReadOnlyBarrier = makeImageMemoryBarrier(
1438                     VK_ACCESS_NONE_KHR, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1439                     m_params->getDSLayout(), **m_dsImage, m_dsImageSubresourceRange);
1440                 vk.cmdPipelineBarrier(*cmdBuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1,
1441                                       &depthImageReadOnlyBarrier);
1442             }
1443 
1444             // render rate to sr image
1445             startRendering(*cmdBuffer, *setupRenderPass, *setupFramebuffer, makeRect2D(srWidth, srHeight),
1446                            setupAttachmentInfo);
1447 
1448             // draw single triangle to cb
1449             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *setupPipeline);
1450             vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
1451 
1452             finishRendering(*cmdBuffer);
1453 
1454             // wait till sr image is ready and change sr images layout
1455             srcStageMask                                   = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1456             dstStageMask                                   = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
1457             VkImageMemoryBarrier srImageBarrierShadingRate = makeImageMemoryBarrier(
1458                 useMemoryAccess ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1459                 useMemoryAccess ? VK_ACCESS_MEMORY_READ_BIT : VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
1460                 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, **m_srImage[0],
1461                 m_defaultImageSubresourceRange);
1462             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1463                                   &srImageBarrierShadingRate);
1464 
1465             // wait till cb image layout is changed
1466             srcStageMask                        = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1467             dstStageMask                        = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1468             VkImageMemoryBarrier cbImageBarrier = makeImageMemoryBarrier(
1469                 VK_ACCESS_NONE_KHR, useMemoryAccess ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
1470                 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **m_cbImage[0], m_defaultImageSubresourceRange);
1471             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1472                                   &cbImageBarrier);
1473 
1474             startRendering(*cmdBuffer, *rateRenderPass, *rateFramebuffer, makeRect2D(m_cbWidth, m_cbHeight),
1475                            rateAttachmentInfo, tileWidth, tileHeight);
1476 
1477             // draw single triangle to cb
1478             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *ratePipelineLayout, 0, 1,
1479                                      &(*m_counterBufferDescriptorSet), 0, DE_NULL);
1480             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *ratePipeline);
1481             vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
1482 
1483             finishRendering(*cmdBuffer);
1484 
1485             // wait till color attachment is fully written
1486             srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1487             dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
1488             memoryBarrier.srcAccessMask =
1489                 useMemoryAccess ? VK_ACCESS_MEMORY_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1490             memoryBarrier.dstAccessMask = useMemoryAccess ? VK_ACCESS_MEMORY_READ_BIT : VK_ACCESS_TRANSFER_READ_BIT;
1491             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
1492 
1493             // read back color buffer image
1494             vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u,
1495                                     &m_defaultBufferImageCopy);
1496 
1497             endCommandBuffer(vk, *cmdBuffer);
1498 
1499             // submit commands and wait
1500             const VkQueue queue = m_context.getUniversalQueue();
1501             submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
1502 
1503             invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
1504             if (!verifyUsingAtomicChecks(tileWidth, tileHeight, m_params->srRate.width, m_params->srRate.height,
1505                                          (uint32_t *)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
1506                 return false;
1507 
1508         } // iterate over all possible tile sizes
1509 
1510     return true;
1511 }
1512 
runCopyMode(void)1513 bool AttachmentRateInstance::runCopyMode(void)
1514 {
1515     // Clear a separate image of the same format to that rate, copy it to
1516     // the shading rate image, then use it to draw a basic triangle and do basic checks
1517 
1518     const DeviceInterface &vk = m_context.getDeviceInterface();
1519     VkDevice device           = m_context.getDevice();
1520     uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1521     VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u};
1522 
1523     Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
1524     Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
1525 
1526     Move<VkCommandPool> cmdPool =
1527         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
1528     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1529 
1530     buildCounterBufferObjects(device, vk, m_context.getDefaultAllocator());
1531     buildColorBufferObjects(device, vk, m_context.getDefaultAllocator(), 0, m_cbUsage);
1532 
1533     // iterate over all possible tile sizes
1534     for (uint32_t tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
1535         for (uint32_t tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
1536         {
1537             // skip tile sizes that have unsuported aspect ratio
1538             uint32_t aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
1539             if (aspectRatio > m_maxAspectRatio)
1540                 continue;
1541 
1542             // calculate size of shading rate attachment
1543             uint32_t srWidth  = (m_cbWidth + tileWidth - 1) / tileWidth;
1544             uint32_t srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
1545 
1546             buildShadingRateObjects(device, vk, m_context.getDefaultAllocator(), 0, srWidth, srHeight, m_srUsage);
1547 
1548             // create image that will be source for shading rate image
1549             de::MovePtr<ImageWithMemory> srSrcImage =
1550                 buildImageWithMemory(device, vk, m_context.getDefaultAllocator(), m_params->srFormat, srWidth, srHeight,
1551                                      VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1552 
1553             const auto dsFormat = m_params->getDSFormat();
1554             Move<VkPipelineLayout> graphicsPipelineLayout =
1555                 buildPipelineLayout(device, vk, &(*m_counterBufferDescriptorSetLayout));
1556             Move<VkRenderPass> renderPass = buildRenderPass(device, vk, m_cbFormat, dsFormat, tileWidth, tileHeight);
1557             Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(
1558                 device, vk, 0, *renderPass, m_cbFormat, dsFormat, *graphicsPipelineLayout, *vertShader, *fragShader);
1559 
1560             std::vector<FBAttachmentInfo> attachmentInfo{
1561                 {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0]},
1562                 {m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0]},
1563             };
1564             // This would need an additional attachment with m_dsImageView and a barrier to transition the DS layout.
1565             // See runFragmentShaderMode for more details.
1566             DE_ASSERT(!m_params->useDepthStencil());
1567 
1568             Move<VkFramebuffer> framebuffer = buildFramebuffer(device, vk, *renderPass, attachmentInfo);
1569 
1570             beginCommandBuffer(vk, *cmdBuffer, 0u);
1571 
1572             // wait till sr images layout are changed
1573             VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1574             VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
1575             std::vector<VkImageMemoryBarrier> srImageBarrierGeneral(
1576                 2,
1577                 makeImageMemoryBarrier(VK_ACCESS_NONE_KHR, (VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT),
1578                                        VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0],
1579                                        m_defaultImageSubresourceRange));
1580             srImageBarrierGeneral[1].image = **srSrcImage;
1581             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 2,
1582                                   srImageBarrierGeneral.data());
1583 
1584             // clear source sr image with proper rate
1585             VkClearColorValue clearValue = {{0, 0, 0, 0}};
1586             clearValue.uint32[0]         = calculateRate(m_params->srRate.width, m_params->srRate.height);
1587             vk.cmdClearColorImage(*cmdBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1,
1588                                   &m_defaultImageSubresourceRange);
1589 
1590             // wait till sr source image is ready
1591             srcStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1592             dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1593             memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1594             memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1595             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
1596 
1597             // copy sr source image to sr image used during rendering
1598             VkImageCopy imageCopyRegion{
1599                 m_defaultImageSubresourceLayers, // VkImageSubresourceLayers srcSubresource;
1600                 {0, 0, 0},                       // VkOffset3D srcOffset;
1601                 m_defaultImageSubresourceLayers, // VkImageSubresourceLayers dstSubresource;
1602                 {0, 0, 0},                       // VkOffset3D dstOffset;
1603                 {srWidth, srHeight, 1u}          // VkExtent3D extent;
1604             };
1605             vk.cmdCopyImage(*cmdBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0], VK_IMAGE_LAYOUT_GENERAL,
1606                             1, &imageCopyRegion);
1607 
1608             // wait till sr image is ready and change sr images layout
1609             srcStageMask                                   = VK_PIPELINE_STAGE_TRANSFER_BIT;
1610             dstStageMask                                   = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
1611             memoryBarrier.srcAccessMask                    = VK_ACCESS_TRANSFER_WRITE_BIT;
1612             memoryBarrier.dstAccessMask                    = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
1613             VkImageMemoryBarrier srImageBarrierShadingRate = makeImageMemoryBarrier(
1614                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
1615                 VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, **m_srImage[0],
1616                 m_defaultImageSubresourceRange);
1617             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 1,
1618                                   &srImageBarrierShadingRate);
1619 
1620             // wait till cb image layout is changed
1621             srcStageMask                        = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1622             dstStageMask                        = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1623             VkImageMemoryBarrier cbImageBarrier = makeImageMemoryBarrier(
1624                 VK_ACCESS_NONE_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1625                 VK_IMAGE_LAYOUT_GENERAL, **m_cbImage[0], m_defaultImageSubresourceRange);
1626             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1627                                   &cbImageBarrier);
1628 
1629             startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo,
1630                            tileWidth, tileHeight);
1631 
1632             // draw single triangle to cb
1633             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1,
1634                                      &(*m_counterBufferDescriptorSet), 0, DE_NULL);
1635             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
1636             vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
1637 
1638             finishRendering(*cmdBuffer);
1639 
1640             // wait till color attachment is fully written
1641             srcStageMask                = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1642             dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1643             memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1644             memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1645             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
1646 
1647             // read back color buffer image
1648             vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u,
1649                                     &m_defaultBufferImageCopy);
1650 
1651             endCommandBuffer(vk, *cmdBuffer);
1652 
1653             // submit commands and wait
1654             const VkQueue queue = m_context.getUniversalQueue();
1655             submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
1656 
1657             invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
1658             if (!verifyUsingAtomicChecks(tileWidth, tileHeight, m_params->srRate.width, m_params->srRate.height,
1659                                          (uint32_t *)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
1660                 return false;
1661 
1662         } // iterate over all possible tile sizes
1663 
1664     return true;
1665 }
1666 
runCopyModeOnTransferQueue(void)1667 bool AttachmentRateInstance::runCopyModeOnTransferQueue(void)
1668 {
1669     // Clear a separate image of the same format to that rate, copy it to
1670     // the shading rate image on separate transfer queue and then use copied
1671     // image to draw a basic triangle and do basic checks
1672 
1673     const PlatformInterface &vkp      = m_context.getPlatformInterface();
1674     const InstanceInterface &vki      = m_context.getInstanceInterface();
1675     VkPhysicalDevice pd               = m_context.getPhysicalDevice();
1676     uint32_t transferQueueFamilyIndex = std::numeric_limits<uint32_t>::max();
1677     uint32_t graphicsQueueFamilyIndex = std::numeric_limits<uint32_t>::max();
1678     VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u};
1679     std::vector<VkQueueFamilyProperties> queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(vki, pd);
1680 
1681     // find graphics and transfer queue families
1682     for (uint32_t queueNdx = 0; queueNdx < queueFamilyProperties.size(); queueNdx++)
1683     {
1684         VkQueueFlags queueFlags = queueFamilyProperties[queueNdx].queueFlags;
1685         if ((graphicsQueueFamilyIndex == std::numeric_limits<uint32_t>::max()) && (queueFlags & VK_QUEUE_GRAPHICS_BIT))
1686             graphicsQueueFamilyIndex = queueNdx;
1687         else if ((queueNdx != graphicsQueueFamilyIndex) && (queueFlags & VK_QUEUE_TRANSFER_BIT))
1688             transferQueueFamilyIndex = queueNdx;
1689     }
1690     if (transferQueueFamilyIndex == std::numeric_limits<uint32_t>::max())
1691         TCU_THROW(NotSupportedError, "No separate transfer queue");
1692 
1693     if (graphicsQueueFamilyIndex == std::numeric_limits<uint32_t>::max())
1694         TCU_THROW(NotSupportedError, "No separate graphics queue");
1695     // using queueFamilies vector to determine if sr image uses exclusiv or concurrent sharing
1696     std::vector<uint32_t> queueFamilies;
1697     if (m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE)
1698         queueFamilies = {graphicsQueueFamilyIndex, transferQueueFamilyIndex};
1699 
1700     // create custom device
1701     VkDevice device;
1702     DeviceInterface *driver;
1703     Allocator *allocator;
1704 
1705     {
1706         const float queuePriorities = 1.0f;
1707         std::vector<VkDeviceQueueCreateInfo> queueInfo(
1708             2,
1709             {
1710                 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
1711                 DE_NULL,                                    // const void* pNext;
1712                 (VkDeviceQueueCreateFlags)0u,               // VkDeviceQueueCreateFlags flags;
1713                 transferQueueFamilyIndex,                   // uint32_t queueFamilyIndex;
1714                 1u,                                         // uint32_t queueCount;
1715                 &queuePriorities                            // const float* pQueuePriorities;
1716             });
1717         queueInfo[1].queueFamilyIndex = graphicsQueueFamilyIndex;
1718 
1719         VkPhysicalDeviceFeatures deviceFeatures;
1720         vki.getPhysicalDeviceFeatures(pd, &deviceFeatures);
1721 
1722         VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsrFeatures{
1723             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR, DE_NULL, false, false, true};
1724 #ifndef CTS_USES_VULKANSC
1725         VkPhysicalDeviceDynamicRenderingFeaturesKHR drFeatures{
1726             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, DE_NULL, true};
1727 #endif // CTS_USES_VULKANSC
1728         VkPhysicalDeviceImagelessFramebufferFeatures ifbFeatures{
1729             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES, DE_NULL, true};
1730         VkPhysicalDeviceFeatures2 createPhysicalFeature{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &fsrFeatures,
1731                                                         deviceFeatures};
1732 
1733         void *pNext                                 = DE_NULL;
1734         std::vector<const char *> enabledExtensions = {"VK_KHR_fragment_shading_rate"};
1735 #ifndef CTS_USES_VULKANSC
1736         if (m_params->useDynamicRendering)
1737         {
1738             pNext = &drFeatures;
1739         }
1740 #endif // CTS_USES_VULKANSC
1741         if (m_params->useImagelessFramebuffer)
1742         {
1743             enabledExtensions.push_back("VK_KHR_imageless_framebuffer");
1744             ifbFeatures.pNext = pNext;
1745             pNext             = &ifbFeatures;
1746         }
1747         fsrFeatures.pNext = pNext;
1748 
1749         std::vector<const char *> enabledLayers = getValidationLayers(vki, pd);
1750         VkDeviceCreateInfo deviceInfo{
1751             VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,            // VkStructureType sType;
1752             &createPhysicalFeature,                          // const void* pNext;
1753             (VkDeviceCreateFlags)0u,                         // VkDeviceCreateFlags flags;
1754             2u,                                              // uint32_t queueCreateInfoCount;
1755             queueInfo.data(),                                // const VkDeviceQueueCreateInfo* pQueueCreateInfos;
1756             static_cast<uint32_t>(enabledLayers.size()),     // uint32_t enabledLayerCount;
1757             de::dataOrNull(enabledLayers),                   // const char* const* ppEnabledLayerNames;
1758             static_cast<uint32_t>(enabledExtensions.size()), // uint32_t enabledExtensionCount;
1759             enabledExtensions.data(),                        // const char* const* ppEnabledExtensionNames;
1760             DE_NULL                                          // const VkPhysicalDeviceFeatures* pEnabledFeatures;
1761         };
1762 
1763         vk::Move<VkDevice> customDevice        = createDevice(vkp, m_context.getInstance(), vki, pd, &deviceInfo);
1764         de::MovePtr<DeviceDriver> customDriver = de::MovePtr<DeviceDriver>(
1765             new DeviceDriver(vkp, m_context.getInstance(), *customDevice, m_context.getUsedApiVersion(),
1766                              m_context.getTestContext().getCommandLine()));
1767         de::MovePtr<Allocator> customAllocator = de::MovePtr<Allocator>(
1768             new SimpleAllocator(*customDriver, *customDevice, getPhysicalDeviceMemoryProperties(vki, pd)));
1769 
1770         device    = *customDevice;
1771         driver    = &*customDriver;
1772         allocator = &*customAllocator;
1773 
1774         m_customDeviceHolder = de::MovePtr<DeviceHolder>(new DeviceHolder(customDevice, customDriver, customAllocator));
1775     }
1776 
1777     DeviceInterface &vk = *driver;
1778 
1779     VkQueue transferQueue;
1780     vk.getDeviceQueue(device, transferQueueFamilyIndex, 0u, &transferQueue);
1781     VkQueue graphicsQueue;
1782     vk.getDeviceQueue(device, graphicsQueueFamilyIndex, 0u, &graphicsQueue);
1783 
1784     // create transfer and graphics command buffers
1785     Move<VkCommandPool> transferCmdPool =
1786         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, transferQueueFamilyIndex);
1787     Move<VkCommandBuffer> transferCmdBuffer =
1788         allocateCommandBuffer(vk, device, *transferCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1789     Move<VkCommandPool> graphicsCmdPool =
1790         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, graphicsQueueFamilyIndex);
1791     Move<VkCommandBuffer> graphicsCmdBuffer =
1792         allocateCommandBuffer(vk, device, *graphicsCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1793 
1794     Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
1795     Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
1796 
1797     buildColorBufferObjects(device, vk, *allocator, 0, m_cbUsage);
1798     buildCounterBufferObjects(device, vk, *allocator);
1799 
1800     // iterate over all possible tile sizes
1801     for (uint32_t tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
1802         for (uint32_t tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
1803         {
1804             // skip tile sizes that have unsuported aspect ratio
1805             uint32_t aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
1806             if (aspectRatio > m_maxAspectRatio)
1807                 continue;
1808 
1809             // calculate size of shading rate attachment
1810             uint32_t srWidth  = (m_cbWidth + tileWidth - 1) / tileWidth;
1811             uint32_t srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
1812 
1813             // create image that will be source for shading rate image
1814             de::MovePtr<ImageWithMemory> srSrcImage =
1815                 buildImageWithMemory(device, vk, *allocator, m_params->srFormat, srWidth, srHeight,
1816                                      VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1817 
1818             // create buffer that will contain shading rate source data
1819             tcu::TextureFormat srTextureFormat = mapVkFormat(m_params->srFormat);
1820             uint32_t srWriteBufferSize =
1821                 srWidth * srHeight * getNumUsedChannels(srTextureFormat.order) * getChannelSize(srTextureFormat.type);
1822             de::MovePtr<BufferWithMemory> srSrcBuffer =
1823                 buildBufferWithMemory(device, vk, *allocator, srWriteBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
1824 
1825             // fill buffer with tested shading rate
1826             uint8_t *srWriteBufferHostPtr = (uint8_t *)srSrcBuffer->getAllocation().getHostPtr();
1827             uint8_t value                 = (uint8_t)calculateRate(m_params->srRate.width, m_params->srRate.height);
1828             deMemset(srWriteBufferHostPtr, value, (size_t)srWriteBufferSize);
1829             flushAlloc(vk, device, srSrcBuffer->getAllocation());
1830 
1831             // create shading rate iamge
1832             m_srImage[0]     = buildImageWithMemory(device, vk, *allocator, m_params->srFormat, srWidth, srHeight,
1833                                                     VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR |
1834                                                         VK_IMAGE_USAGE_TRANSFER_DST_BIT,
1835                                                     VK_IMAGE_TILING_OPTIMAL, queueFamilies);
1836             m_srImageView[0] = buildImageView(device, vk, m_params->srFormat, m_srImage[0]->get());
1837 
1838             const auto dsFormat = m_params->getDSFormat();
1839             Move<VkPipelineLayout> graphicsPipelineLayout =
1840                 buildPipelineLayout(device, vk, &(*m_counterBufferDescriptorSetLayout));
1841             Move<VkRenderPass> renderPass = buildRenderPass(device, vk, m_cbFormat, dsFormat, tileWidth, tileHeight);
1842             Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(
1843                 device, vk, 0, *renderPass, m_cbFormat, dsFormat, *graphicsPipelineLayout, *vertShader, *fragShader);
1844 
1845             std::vector<FBAttachmentInfo> attachmentInfo{
1846                 {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0]},
1847                 {m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0]},
1848             };
1849             // This would need an additional attachment with m_dsImageView and a barrier to transition the DS layout.
1850             // See runFragmentShaderMode for more details.
1851             DE_ASSERT(!m_params->useDepthStencil());
1852 
1853             Move<VkFramebuffer> framebuffer = buildFramebuffer(device, vk, *renderPass, attachmentInfo);
1854 
1855             beginCommandBuffer(vk, *transferCmdBuffer, 0u);
1856 
1857             // wait till sr data is ready in buffer and change sr image layouts to general
1858             VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1859             VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
1860             std::vector<VkImageMemoryBarrier> srImageBarrierGeneral(
1861                 2,
1862                 makeImageMemoryBarrier(VK_ACCESS_NONE_KHR, (VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
1863                                        VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0],
1864                                        m_defaultImageSubresourceRange));
1865             srImageBarrierGeneral[1].image = **srSrcImage;
1866             vk.cmdPipelineBarrier(*transferCmdBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, DE_NULL, 2,
1867                                   srImageBarrierGeneral.data());
1868 
1869             // copy sr data to images
1870             const VkBufferImageCopy srCopyBuffer =
1871                 makeBufferImageCopy({srWidth, srHeight, 1u}, m_defaultImageSubresourceLayers);
1872             vk.cmdCopyBufferToImage(*transferCmdBuffer, **srSrcBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, 1,
1873                                     &srCopyBuffer);
1874 
1875             // wait till sr source image is ready
1876             srcStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1877             dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1878             memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1879             memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1880             vk.cmdPipelineBarrier(*transferCmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0,
1881                                   DE_NULL);
1882 
1883             // copy sr source image to sr image used during rendering
1884             VkImageCopy imageCopyRegion{
1885                 m_defaultImageSubresourceLayers, // VkImageSubresourceLayers srcSubresource;
1886                 {0, 0, 0},                       // VkOffset3D srcOffset;
1887                 m_defaultImageSubresourceLayers, // VkImageSubresourceLayers dstSubresource;
1888                 {0, 0, 0},                       // VkOffset3D dstOffset;
1889                 {srWidth, srHeight, 1u}          // VkExtent3D extent;
1890             };
1891             vk.cmdCopyImage(*transferCmdBuffer, **srSrcImage, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0],
1892                             VK_IMAGE_LAYOUT_GENERAL, 1, &imageCopyRegion);
1893 
1894             // release exclusive ownership from the transfer queue family
1895             srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
1896             dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1897             VkImageMemoryBarrier srImageBarrierOwnershipTransfer =
1898                 makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_NONE_KHR, VK_IMAGE_LAYOUT_GENERAL,
1899                                        VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0], m_defaultImageSubresourceRange);
1900             if (m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE)
1901             {
1902                 srImageBarrierOwnershipTransfer.srcQueueFamilyIndex = transferQueueFamilyIndex;
1903                 srImageBarrierOwnershipTransfer.dstQueueFamilyIndex = graphicsQueueFamilyIndex;
1904             }
1905             vk.cmdPipelineBarrier(*transferCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1906                                   &srImageBarrierOwnershipTransfer);
1907 
1908             endCommandBuffer(vk, *transferCmdBuffer);
1909 
1910             beginCommandBuffer(vk, *graphicsCmdBuffer, 0u);
1911 
1912             // acquire exclusive ownership for the graphics queue family - while changing sr images layout
1913             vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1914                                   &srImageBarrierOwnershipTransfer);
1915 
1916             // wait till sr image layout is changed
1917             srcStageMask                                   = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1918             dstStageMask                                   = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
1919             VkImageMemoryBarrier srImageBarrierShadingRate = makeImageMemoryBarrier(
1920                 VK_ACCESS_NONE_KHR, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR, VK_IMAGE_LAYOUT_GENERAL,
1921                 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, **m_srImage[0],
1922                 m_defaultImageSubresourceRange);
1923             vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1924                                   &srImageBarrierShadingRate);
1925 
1926             // wait till cb image layout is changed
1927             srcStageMask                        = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
1928             dstStageMask                        = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1929             VkImageMemoryBarrier cbImageBarrier = makeImageMemoryBarrier(
1930                 VK_ACCESS_NONE_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1931                 VK_IMAGE_LAYOUT_GENERAL, **m_cbImage[0], m_defaultImageSubresourceRange);
1932             vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
1933                                   &cbImageBarrier);
1934 
1935             startRendering(*graphicsCmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight),
1936                            attachmentInfo, tileWidth, tileHeight);
1937 
1938             // draw single triangle to cb
1939             vk.cmdBindDescriptorSets(*graphicsCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1,
1940                                      &(*m_counterBufferDescriptorSet), 0, DE_NULL);
1941             vk.cmdBindPipeline(*graphicsCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
1942             vk.cmdDraw(*graphicsCmdBuffer, 3u, 1, 0u, 0u);
1943 
1944             finishRendering(*graphicsCmdBuffer);
1945 
1946             // wait till color attachment is fully written
1947             srcStageMask                = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1948             dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
1949             memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1950             memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1951             vk.cmdPipelineBarrier(*graphicsCmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0,
1952                                   DE_NULL);
1953 
1954             // read back color buffer image
1955             vk.cmdCopyImageToBuffer(*graphicsCmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0],
1956                                     1u, &m_defaultBufferImageCopy);
1957 
1958             endCommandBuffer(vk, *graphicsCmdBuffer);
1959 
1960             // create synchronization objects
1961             Move<VkSemaphore> semaphore = createSemaphore(vk, device);
1962             Move<VkFence> transferFence = createFence(vk, device);
1963             Move<VkFence> graphicsFence = createFence(vk, device);
1964 
1965             const VkSubmitInfo transferSubmitInfo{
1966                 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
1967                 DE_NULL,                       // const void* pNext;
1968                 0u,                            // uint32_t waitSemaphoreCount;
1969                 DE_NULL,                       // const VkSemaphore* pWaitSemaphores;
1970                 DE_NULL,                       // const VkPipelineStageFlags* pWaitDstStageMask;
1971                 1u,                            // uint32_t commandBufferCount;
1972                 &*transferCmdBuffer,           // const VkCommandBuffer* pCommandBuffers;
1973                 1u,                            // uint32_t signalSemaphoreCount;
1974                 &*semaphore,                   // const VkSemaphore* pSignalSemaphores;
1975             };
1976             const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
1977             const VkSubmitInfo graphicsSubmitInfo{
1978                 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
1979                 DE_NULL,                       // const void* pNext;
1980                 1u,                            // uint32_t waitSemaphoreCount;
1981                 &*semaphore,                   // const VkSemaphore* pWaitSemaphores;
1982                 &waitDstStageMask,             // const VkPipelineStageFlags* pWaitDstStageMask;
1983                 1u,                            // uint32_t commandBufferCount;
1984                 &*graphicsCmdBuffer,           // const VkCommandBuffer* pCommandBuffers;
1985                 0u,                            // uint32_t signalSemaphoreCount;
1986                 DE_NULL,                       // const VkSemaphore* pSignalSemaphores;
1987             };
1988 
1989             // submit commands to both queues
1990             VK_CHECK(vk.queueSubmit(transferQueue, 1u, &transferSubmitInfo, *transferFence));
1991             VK_CHECK(vk.queueSubmit(graphicsQueue, 1u, &graphicsSubmitInfo, *graphicsFence));
1992 
1993             VkFence fences[] = {*graphicsFence, *transferFence};
1994             VK_CHECK(vk.waitForFences(device, 2u, fences, true, ~0ull));
1995 
1996             invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
1997             if (!verifyUsingAtomicChecks(tileWidth, tileHeight, m_params->srRate.width, m_params->srRate.height,
1998                                          (uint32_t *)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
1999                 return false;
2000 
2001         } // iterate over all possible tile sizes
2002 
2003     return true;
2004 }
2005 
runFillLinearTiledImage(void)2006 bool AttachmentRateInstance::runFillLinearTiledImage(void)
2007 {
2008     // Create a linear tiled fragment shading rate attachment image and set
2009     // its data on the host, then draw a basic triangle and do basic checks
2010 
2011     const DeviceInterface &vk           = m_context.getDeviceInterface();
2012     VkDevice device                     = m_context.getDevice();
2013     uint32_t queueFamilyIndex           = m_context.getUniversalQueueFamilyIndex();
2014     VkImageSubresource imageSubresource = makeImageSubresource(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u);
2015     VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u};
2016     VkSubresourceLayout srImageLayout;
2017 
2018     Move<VkShaderModule> vertShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
2019     Move<VkShaderModule> fragShader = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
2020 
2021     Move<VkCommandPool> cmdPool =
2022         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
2023     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2024 
2025     buildCounterBufferObjects(device, vk, m_context.getDefaultAllocator());
2026     buildColorBufferObjects(device, vk, m_context.getDefaultAllocator(), 0, m_cbUsage);
2027 
2028     // iterate over all possible tile sizes
2029     for (uint32_t tileWidth = m_minTileSize.width; tileWidth <= m_maxTileSize.width; tileWidth *= 2)
2030         for (uint32_t tileHeight = m_minTileSize.height; tileHeight <= m_maxTileSize.height; tileHeight *= 2)
2031         {
2032             // skip tile sizes that have unsuported aspect ratio
2033             uint32_t aspectRatio = (tileHeight > tileWidth) ? (tileHeight / tileWidth) : (tileWidth / tileHeight);
2034             if (aspectRatio > m_maxAspectRatio)
2035                 continue;
2036 
2037             // calculate size of shading rate attachment
2038             uint32_t srWidth  = (m_cbWidth + tileWidth - 1) / tileWidth;
2039             uint32_t srHeight = (m_cbHeight + tileHeight - 1) / tileHeight;
2040 
2041             buildShadingRateObjects(device, vk, m_context.getDefaultAllocator(), 0, srWidth, srHeight, m_srUsage,
2042                                     VK_IMAGE_TILING_LINEAR);
2043 
2044             uint8_t *imagePtr = reinterpret_cast<uint8_t *>(m_srImage[0]->getAllocation().getHostPtr());
2045             uint8_t value     = (uint8_t)calculateRate(m_params->srRate.width, m_params->srRate.height);
2046 
2047             // fill sr image on the host row by row
2048             vk.getImageSubresourceLayout(device, **m_srImage[0], &imageSubresource, &srImageLayout);
2049             for (uint32_t srTexelRow = 0; srTexelRow < srHeight; srTexelRow++)
2050             {
2051                 uint8_t *rowDst = imagePtr + srImageLayout.offset + srImageLayout.rowPitch * srTexelRow;
2052                 deMemset(rowDst, value, (size_t)srWidth);
2053             }
2054 
2055             const auto dsFormat = m_params->getDSFormat();
2056             Move<VkPipelineLayout> graphicsPipelineLayout =
2057                 buildPipelineLayout(device, vk, &(*m_counterBufferDescriptorSetLayout));
2058             Move<VkRenderPass> renderPass = buildRenderPass(device, vk, m_cbFormat, dsFormat, tileWidth, tileHeight);
2059             Move<VkPipeline> graphicsPipeline = buildGraphicsPipeline(
2060                 device, vk, 0, *renderPass, m_cbFormat, dsFormat, *graphicsPipelineLayout, *vertShader, *fragShader);
2061 
2062             std::vector<FBAttachmentInfo> attachmentInfo{
2063                 {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0]},
2064                 {m_params->srFormat, m_srUsage, srWidth, srHeight, *m_srImageView[0]},
2065             };
2066             // This would need an additional attachment with m_dsImageView and a barrier to transition the DS layout.
2067             // See runFragmentShaderMode for more details.
2068             DE_ASSERT(!m_params->useDepthStencil());
2069 
2070             Move<VkFramebuffer> framebuffer = buildFramebuffer(device, vk, *renderPass, attachmentInfo);
2071 
2072             beginCommandBuffer(vk, *cmdBuffer, 0u);
2073 
2074             // wait till sr image layout is changed
2075             VkPipelineStageFlags srcStageMask             = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2076             VkPipelineStageFlags dstStageMask             = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
2077             VkImageMemoryBarrier srImageBarrierAttachment = makeImageMemoryBarrier(
2078                 VK_ACCESS_NONE_KHR, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR, VK_IMAGE_LAYOUT_UNDEFINED,
2079                 VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, **m_srImage[0],
2080                 m_defaultImageSubresourceRange);
2081             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
2082                                   &srImageBarrierAttachment);
2083 
2084             // wait till cb image layout is changed
2085             srcStageMask                        = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2086             dstStageMask                        = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2087             VkImageMemoryBarrier cbImageBarrier = makeImageMemoryBarrier(
2088                 VK_ACCESS_NONE_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
2089                 VK_IMAGE_LAYOUT_GENERAL, **m_cbImage[0], m_defaultImageSubresourceRange);
2090             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
2091                                   &cbImageBarrier);
2092 
2093             startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo,
2094                            tileWidth, tileHeight);
2095 
2096             // draw single triangle to cb
2097             vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipelineLayout, 0, 1,
2098                                      &(*m_counterBufferDescriptorSet), 0, DE_NULL);
2099             vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
2100             vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
2101 
2102             finishRendering(*cmdBuffer);
2103 
2104             // wait till color attachment is fully written
2105             srcStageMask                = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2106             dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
2107             memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2108             memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2109             vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
2110 
2111             // read back color buffer image
2112             vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u,
2113                                     &m_defaultBufferImageCopy);
2114 
2115             endCommandBuffer(vk, *cmdBuffer);
2116 
2117             // submit commands and wait
2118             const VkQueue queue = m_context.getUniversalQueue();
2119             submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
2120 
2121             invalidateAlloc(vk, device, m_cbReadBuffer[0]->getAllocation());
2122             if (!verifyUsingAtomicChecks(tileWidth, tileHeight, m_params->srRate.width, m_params->srRate.height,
2123                                          (uint32_t *)m_cbReadBuffer[0]->getAllocation().getHostPtr()))
2124                 return false;
2125 
2126         } // iterate over all possible tile sizes
2127 
2128     return true;
2129 }
2130 
runTwoSubpassMode(void)2131 bool AttachmentRateInstance::runTwoSubpassMode(void)
2132 {
2133     // Set up a two-subpass render pass with different shading rate attachments used in each subpass.
2134     // Then draw a basic triangle in each subpass and do basic checks.
2135 
2136     const InstanceInterface &vki = m_context.getInstanceInterface();
2137     const DeviceInterface &vk    = m_context.getDeviceInterface();
2138     VkPhysicalDevice pd          = m_context.getPhysicalDevice();
2139     VkDevice device              = m_context.getDevice();
2140     uint32_t queueFamilyIndex    = m_context.getUniversalQueueFamilyIndex();
2141     VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, 0u, 0u};
2142 
2143     Move<VkShaderModule> vertShader0 = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert0"), 0);
2144     Move<VkShaderModule> vertShader1 = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert1"), 0);
2145     Move<VkShaderModule> fragShader  = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
2146 
2147     Move<VkCommandPool> cmdPool =
2148         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
2149     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2150 
2151     // fetch information about supported rates
2152     uint32_t supportedFragmentShadingRateCount;
2153     std::vector<VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates;
2154     vki.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount, DE_NULL);
2155     supportedFragmentShadingRates.resize(
2156         supportedFragmentShadingRateCount,
2157         {
2158             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, // VkStructureType sType;
2159             DE_NULL,                                                     // void* pNext;
2160             VK_SAMPLE_COUNT_1_BIT,                                       // VkSampleCountFlags sampleCounts;
2161             {0, 0}                                                       // VkExtent2D fragmentSize;
2162         });
2163     vki.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount,
2164                                                  &supportedFragmentShadingRates[0]);
2165 
2166     // grab min and max tile sieze and biggest and smallest rate
2167     uint32_t sr0Width      = (m_cbWidth + m_minTileSize.width - 1) / m_minTileSize.width;
2168     uint32_t sr0Height     = (m_cbHeight + m_minTileSize.height - 1) / m_minTileSize.height;
2169     uint32_t sr1Width      = (m_cbWidth + m_maxTileSize.width - 1) / m_maxTileSize.width;
2170     uint32_t sr1Height     = (m_cbHeight + m_maxTileSize.height - 1) / m_maxTileSize.height;
2171     uint32_t sr0RateWidth  = supportedFragmentShadingRates[0].fragmentSize.width; // bigets supported rate
2172     uint32_t sr0RateHeight = supportedFragmentShadingRates[0].fragmentSize.height;
2173     uint32_t sr1RateWidth  = supportedFragmentShadingRates[supportedFragmentShadingRateCount - 2]
2174                                 .fragmentSize.width; // smallest supported rate excluding {1, 1}
2175     uint32_t sr1RateHeight = supportedFragmentShadingRates[supportedFragmentShadingRateCount - 2].fragmentSize.height;
2176 
2177     buildColorBufferObjects(device, vk, m_context.getDefaultAllocator(), 0, m_cbUsage);
2178     buildColorBufferObjects(device, vk, m_context.getDefaultAllocator(), 1, m_cbUsage);
2179     buildShadingRateObjects(device, vk, m_context.getDefaultAllocator(), 0, sr0Width, sr0Height, m_srUsage);
2180     buildShadingRateObjects(device, vk, m_context.getDefaultAllocator(), 1, sr1Width, sr1Height, m_srUsage);
2181     buildCounterBufferObjects(device, vk, m_context.getDefaultAllocator());
2182 
2183     const auto dsFormat                   = m_params->getDSFormat();
2184     Move<VkRenderPass> renderPass         = buildRenderPass(device, vk, m_cbFormat, dsFormat, m_minTileSize.width,
2185                                                             m_minTileSize.height, m_maxTileSize.width, m_maxTileSize.height);
2186     Move<VkPipelineLayout> pipelineLayout = buildPipelineLayout(device, vk, &(*m_counterBufferDescriptorSetLayout));
2187     Move<VkPipeline> graphicsPipeline0    = buildGraphicsPipeline(device, vk, 0, *renderPass, m_cbFormat, dsFormat,
2188                                                                   *pipelineLayout, *vertShader0, *fragShader);
2189     Move<VkPipeline> graphicsPipeline1    = buildGraphicsPipeline(device, vk, 1, *renderPass, m_cbFormat, dsFormat,
2190                                                                   *pipelineLayout, *vertShader1, *fragShader);
2191 
2192     std::vector<FBAttachmentInfo> attachmentInfo{
2193         {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[0]},
2194         {m_params->srFormat, m_srUsage, sr0Width, sr0Height, *m_srImageView[0]},
2195         {m_cbFormat, m_cbUsage, m_cbWidth, m_cbHeight, *m_cbImageView[1]},
2196         {m_params->srFormat, m_srUsage, sr1Width, sr1Height, *m_srImageView[1]},
2197     };
2198     // This would need an additional attachment with m_dsImageView and a barrier to transition the DS layout.
2199     // See runFragmentShaderMode for more details.
2200     DE_ASSERT(!m_params->useDepthStencil());
2201 
2202     Move<VkFramebuffer> framebuffer = buildFramebuffer(device, vk, *renderPass, attachmentInfo);
2203 
2204     beginCommandBuffer(vk, *cmdBuffer, 0u);
2205 
2206     // change sr image layouts to general
2207     VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2208     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
2209     std::vector<VkImageMemoryBarrier> srImageBarrierGeneral(
2210         2, makeImageMemoryBarrier(VK_ACCESS_NONE_KHR, (VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT),
2211                                   VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, **m_srImage[0],
2212                                   m_defaultImageSubresourceRange));
2213     srImageBarrierGeneral[1].image = **m_srImage[1];
2214     vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 2,
2215                           srImageBarrierGeneral.data());
2216 
2217     VkClearColorValue clearValues[2] = {{{0, 0, 0, 0}}, {{0, 0, 0, 0}}};
2218     clearValues[0].uint32[0]         = calculateRate(sr0RateWidth, sr0RateHeight);
2219     clearValues[1].uint32[0]         = calculateRate(sr1RateWidth, sr1RateHeight);
2220     vk.cmdClearColorImage(*cmdBuffer, **m_srImage[0], VK_IMAGE_LAYOUT_GENERAL, &clearValues[0], 1,
2221                           &m_defaultImageSubresourceRange);
2222     vk.cmdClearColorImage(*cmdBuffer, **m_srImage[1], VK_IMAGE_LAYOUT_GENERAL, &clearValues[1], 1,
2223                           &m_defaultImageSubresourceRange);
2224 
2225     // wait till sr data is ready and change sr images layout
2226     srcStageMask                = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
2227     dstStageMask                = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
2228     memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2229     memoryBarrier.dstAccessMask = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
2230     std::vector<VkImageMemoryBarrier> srImageBarrierShadingRate(
2231         2, makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
2232                                   VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
2233                                   **m_srImage[0], m_defaultImageSubresourceRange));
2234     srImageBarrierShadingRate[1].image = **m_srImage[1];
2235     vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 2,
2236                           srImageBarrierShadingRate.data());
2237 
2238     // wait till cb image layouts are changed
2239     srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
2240     dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2241     std::vector<VkImageMemoryBarrier> cbImageBarrier(
2242         2, makeImageMemoryBarrier(VK_ACCESS_NONE_KHR, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
2243                                   VK_IMAGE_LAYOUT_GENERAL, **m_cbImage[0], m_defaultImageSubresourceRange));
2244     cbImageBarrier[1].image = **m_cbImage[1];
2245     vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 2, cbImageBarrier.data());
2246 
2247     startRendering(*cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_cbWidth, m_cbHeight), attachmentInfo);
2248 
2249     // draw single triangle to first cb
2250     vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0, 1,
2251                              &(*m_counterBufferDescriptorSet), 0, DE_NULL);
2252     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline0);
2253     vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
2254 
2255     vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
2256 
2257     // draw single triangle to second cb
2258     vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline1);
2259     vk.cmdDraw(*cmdBuffer, 3u, 1, 0u, 0u);
2260 
2261     finishRendering(*cmdBuffer);
2262 
2263     // wait till color attachments are fully written
2264     srcStageMask                = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2265     dstStageMask                = VK_PIPELINE_STAGE_TRANSFER_BIT;
2266     memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2267     memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2268     vk.cmdPipelineBarrier(*cmdBuffer, srcStageMask, dstStageMask, 0, 1, &memoryBarrier, 0, DE_NULL, 0, DE_NULL);
2269 
2270     // read back color buffer images
2271     vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[0], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[0], 1u,
2272                             &m_defaultBufferImageCopy);
2273     vk.cmdCopyImageToBuffer(*cmdBuffer, **m_cbImage[1], VK_IMAGE_LAYOUT_GENERAL, **m_cbReadBuffer[1], 1u,
2274                             &m_defaultBufferImageCopy);
2275 
2276     endCommandBuffer(vk, *cmdBuffer);
2277 
2278     // submit commands and wait
2279     const VkQueue queue = m_context.getUniversalQueue();
2280     submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
2281 
2282     // read back buffer with color attachment 1 data
2283     Allocation &cb0BuffAlloc = m_cbReadBuffer[0]->getAllocation();
2284     invalidateAlloc(vk, device, cb0BuffAlloc);
2285 
2286     // read back buffer with color attachment 2 data
2287     Allocation &cb1BuffAlloc = m_cbReadBuffer[1]->getAllocation();
2288     invalidateAlloc(vk, device, cb1BuffAlloc);
2289 
2290     // validate both attachemtns triangle
2291     return (verifyUsingAtomicChecks(m_minTileSize.width, m_minTileSize.height, sr0RateWidth, sr0RateHeight,
2292                                     (uint32_t *)m_cbReadBuffer[0]->getAllocation().getHostPtr()) &&
2293             verifyUsingAtomicChecks(m_maxTileSize.width, m_maxTileSize.height, sr1RateWidth, sr1RateHeight,
2294                                     (uint32_t *)m_cbReadBuffer[1]->getAllocation().getHostPtr()));
2295 }
2296 
2297 class AttachmentRateTestCase : public TestCase
2298 {
2299 public:
2300     AttachmentRateTestCase(tcu::TestContext &context, const char *name, de::SharedPtr<TestParams> params);
2301     ~AttachmentRateTestCase(void) = default;
2302 
2303     void initPrograms(SourceCollections &programCollection) const override;
2304     TestInstance *createInstance(Context &context) const override;
2305     void checkSupport(Context &context) const override;
2306 
2307 private:
2308     const de::SharedPtr<TestParams> m_params;
2309 };
2310 
AttachmentRateTestCase(tcu::TestContext & context,const char * name,de::SharedPtr<TestParams> params)2311 AttachmentRateTestCase::AttachmentRateTestCase(tcu::TestContext &context, const char *name,
2312                                                de::SharedPtr<TestParams> params)
2313     : vkt::TestCase(context, name)
2314     , m_params(params)
2315 {
2316 }
2317 
checkSupport(Context & context) const2318 void AttachmentRateTestCase::checkSupport(Context &context) const
2319 {
2320     context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate");
2321 
2322     if (m_params->useDynamicRendering)
2323         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
2324     if (m_params->useImagelessFramebuffer)
2325         context.requireDeviceFunctionality("VK_KHR_imageless_framebuffer");
2326 
2327     if (!context.getFragmentShadingRateFeatures().attachmentFragmentShadingRate)
2328         TCU_THROW(NotSupportedError, "attachmentFragmentShadingRate not supported");
2329 
2330     const vk::InstanceInterface &vk = context.getInstanceInterface();
2331     const vk::VkPhysicalDevice pd   = context.getPhysicalDevice();
2332 
2333     VkImageFormatProperties imageProperties;
2334     VkImageUsageFlags srUsage =
2335         VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2336 
2337     VkResult result = vk.getPhysicalDeviceImageFormatProperties(pd, m_params->srFormat, VK_IMAGE_TYPE_2D,
2338                                                                 VK_IMAGE_TILING_OPTIMAL, srUsage, 0, &imageProperties);
2339     if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
2340         TCU_THROW(NotSupportedError, "Format not supported");
2341 
2342     if (m_params->mode != TM_TWO_SUBPASS)
2343     {
2344         uint32_t supportedFragmentShadingRateCount;
2345         VkExtent2D testedRate = m_params->srRate;
2346         std::vector<VkPhysicalDeviceFragmentShadingRateKHR> supportedFragmentShadingRates;
2347 
2348         // fetch information about supported rates
2349         vk.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount, DE_NULL);
2350         supportedFragmentShadingRates.resize(
2351             supportedFragmentShadingRateCount,
2352             {
2353                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, // VkStructureType sType;
2354                 DE_NULL,                                                     // void* pNext;
2355                 VK_SAMPLE_COUNT_1_BIT,                                       // VkSampleCountFlags sampleCounts;
2356                 {0, 0}                                                       // VkExtent2D fragmentSize;
2357             });
2358         vk.getPhysicalDeviceFragmentShadingRatesKHR(pd, &supportedFragmentShadingRateCount,
2359                                                     &supportedFragmentShadingRates[0]);
2360 
2361         // check if rate required by test is not supported
2362         if (std::none_of(supportedFragmentShadingRates.begin(), supportedFragmentShadingRates.end(),
2363                          [&testedRate](const VkPhysicalDeviceFragmentShadingRateKHR &r) {
2364                              return (r.fragmentSize.width == testedRate.width &&
2365                                      r.fragmentSize.height == testedRate.height);
2366                          }))
2367         {
2368             TCU_THROW(NotSupportedError, "Rate not supported");
2369         }
2370     }
2371 
2372     if (m_params->mode == TM_MAINTENANCE_5)
2373         context.requireDeviceFunctionality("VK_KHR_maintenance5");
2374 
2375     VkFormatFeatureFlags requiredFeatures = 0;
2376     if (m_params->mode == TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER)
2377         requiredFeatures =
2378             VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
2379     else if ((m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE) ||
2380              (m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE) ||
2381              (m_params->mode == TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE) ||
2382              (m_params->mode == TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE))
2383         requiredFeatures = VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
2384     else if (m_params->mode == TM_SETUP_RATE_WITH_FRAGMENT_SHADER)
2385         requiredFeatures =
2386             VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
2387 
2388 #if DEBUG_USE_STORE_INSTEAD_OF_ATOMICS == 1
2389     if (m_params->mode == TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER)
2390         requiredFeatures =
2391             VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR | VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
2392 #endif
2393 
2394     if (requiredFeatures)
2395     {
2396         const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vk, pd, m_params->srFormat);
2397 
2398         if (m_params->mode == TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE)
2399         {
2400             if ((formatProperties.linearTilingFeatures & requiredFeatures) != requiredFeatures)
2401                 TCU_THROW(NotSupportedError, "Required format feature bits not supported");
2402         }
2403         else if ((formatProperties.optimalTilingFeatures & requiredFeatures) != requiredFeatures)
2404             TCU_THROW(NotSupportedError, "Required format feature bits not supported");
2405     }
2406 
2407     if (m_params->useDepthStencil())
2408     {
2409         const auto dsFormat                         = m_params->getDSFormat();
2410         const VkFormatProperties dsFormatProperties = getPhysicalDeviceFormatProperties(vk, pd, dsFormat);
2411 
2412         if ((dsFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)
2413         {
2414             std::ostringstream msg;
2415             msg << dsFormat << " not supported";
2416             TCU_THROW(NotSupportedError, msg.str());
2417         }
2418     }
2419 }
2420 
initPrograms(SourceCollections & programCollection) const2421 void AttachmentRateTestCase::initPrograms(SourceCollections &programCollection) const
2422 {
2423     uint32_t rateValue = calculateRate(m_params->srRate.width, m_params->srRate.height);
2424 
2425     if (m_params->mode == TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER)
2426     {
2427         std::stringstream compStream;
2428         compStream << "#version 450\n"
2429                       "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
2430                       "layout(r32ui, binding = 0) coherent uniform highp uimage2D srImage;\n"
2431                       "void main (void)\n"
2432                       "{\n"
2433 #if DEBUG_USE_STORE_INSTEAD_OF_ATOMICS == 1
2434                       "  imageStore(srImage, ivec2(gl_GlobalInvocationID.xy), uvec4("
2435                    << rateValue
2436                    << "));\n"
2437 #else
2438                       "  imageAtomicAdd(srImage, ivec2(gl_GlobalInvocationID.xy), "
2439                    << rateValue
2440                    << ");\n"
2441 #endif
2442                       "}\n";
2443 
2444         programCollection.glslSources.add("comp") << glu::ComputeSource(compStream.str());
2445     }
2446 
2447     tcu::StringTemplate vertTemplate(
2448         "#version 450 core\n"
2449         "out gl_PerVertex\n"
2450         "{\n"
2451         "  vec4 gl_Position;\n"
2452         "};\n"
2453         "void main()\n"
2454         "{\n"
2455         "  gl_Position = vec4(float(1.0 - 2.0 * int(gl_VertexIndex != 1)) * ${SCALE} + ${TRANSLATE},\n"
2456         "                     float(1.0 - 2.0 * int(gl_VertexIndex > 0))  * ${SCALE} + ${TRANSLATE}, 0.0, 1.0);\n"
2457         "}\n");
2458 
2459     std::map<std::string, std::string> specializationMap{
2460         {"SCALE", "0.8"},
2461         {"TRANSLATE", "0.0"},
2462     };
2463 
2464     if (m_params->mode == TM_TWO_SUBPASS)
2465     {
2466         specializationMap["SCALE"]     = "0.4";
2467         specializationMap["TRANSLATE"] = "-0.5";
2468         programCollection.glslSources.add("vert0") << glu::VertexSource(vertTemplate.specialize(specializationMap));
2469 
2470         specializationMap["SCALE"]     = "0.4";
2471         specializationMap["TRANSLATE"] = "0.5";
2472         programCollection.glslSources.add("vert1") << glu::VertexSource(vertTemplate.specialize(specializationMap));
2473     }
2474     else
2475     {
2476         programCollection.glslSources.add("vert") << glu::VertexSource(vertTemplate.specialize(specializationMap));
2477     }
2478 
2479     if ((m_params->mode == TM_SETUP_RATE_WITH_FRAGMENT_SHADER) || (m_params->mode == TM_MEMORY_ACCESS) ||
2480         (m_params->mode == TM_MAINTENANCE_5))
2481     {
2482         // use large triangle that will cover whole color buffer
2483         specializationMap["SCALE"]     = "9.0";
2484         specializationMap["TRANSLATE"] = "0.0";
2485         programCollection.glslSources.add("vert_setup")
2486             << glu::VertexSource(vertTemplate.specialize(specializationMap));
2487 
2488         std::stringstream fragStream;
2489         fragStream << "#version 450 core\n"
2490                       "layout(location = 0) out uint outColor;\n"
2491                       "void main()\n"
2492                       "{\n"
2493                       "  outColor.x = "
2494                    << rateValue
2495                    << ";\n"
2496                       "}\n";
2497         programCollection.glslSources.add("frag_setup") << glu::FragmentSource(fragStream.str());
2498     }
2499 
2500     std::string frag = "#version 450 core\n"
2501                        "#extension GL_EXT_fragment_shading_rate : enable\n"
2502                        "layout(set = 0, binding = 0) buffer Block { uint counter; } buf;\n"
2503                        "layout(location = 0) out uvec4 outColor;\n"
2504                        "void main()\n"
2505                        "{\n"
2506                        "  outColor.x = gl_ShadingRateEXT;\n"
2507                        "  outColor.y = 0;\n"
2508                        "  outColor.z = atomicAdd(buf.counter, 1);\n"
2509                        "  outColor.w = 0;\n"
2510                        "}\n";
2511     programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
2512 }
2513 
createInstance(Context & context) const2514 TestInstance *AttachmentRateTestCase::createInstance(Context &context) const
2515 {
2516     return new AttachmentRateInstance(context, m_params);
2517 }
2518 
2519 } // namespace
2520 
createAttachmentRateTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentGroup,SharedGroupParams groupParams)2521 void createAttachmentRateTests(tcu::TestContext &testCtx, tcu::TestCaseGroup *parentGroup,
2522                                SharedGroupParams groupParams)
2523 {
2524     struct SRFormat
2525     {
2526         VkFormat format;
2527         const char *name;
2528     };
2529 
2530     const std::vector<SRFormat> srFormats{
2531         {VK_FORMAT_R8_UINT, "r8_uint"},
2532         {VK_FORMAT_R8G8_UINT, "r8g8_uint"},
2533         {VK_FORMAT_R8G8B8_UINT, "r8g8b8_uint"},
2534         {VK_FORMAT_R8G8B8A8_UINT, "r8g8b8a8_uint"},
2535         {VK_FORMAT_R16_UINT, "r16_uint"},
2536         {VK_FORMAT_R16G16_UINT, "r16g16_uint"},
2537         {VK_FORMAT_R16G16B16_UINT, "r16g16b16_uint"},
2538         {VK_FORMAT_R16G16B16A16_UINT, "r16g16b16a16_uint"},
2539         {VK_FORMAT_R32_UINT, "r32_uint"},
2540         {VK_FORMAT_R32G32_UINT, "r32g32_uint"},
2541         {VK_FORMAT_R32G32B32_UINT, "r32g32b32_uint"},
2542         {VK_FORMAT_R32G32B32A32_UINT, "r32g32b32a32_uint"},
2543         {VK_FORMAT_R64_UINT, "r64_uint"},
2544         {VK_FORMAT_R64G64_UINT, "r64g64_uint"},
2545         {VK_FORMAT_R64G64B64_UINT, "r64g64b64_uint"},
2546         {VK_FORMAT_R64G64B64A64_UINT, "r64g64b64a64_uint"},
2547     };
2548 
2549     struct SRRate
2550     {
2551         VkExtent2D count;
2552         const char *name;
2553     };
2554 
2555     const std::vector<SRRate> srRates{
2556         {{1, 1}, "rate_1x1"}, {{1, 2}, "rate_1x2"}, {{1, 4}, "rate_1x4"}, {{2, 1}, "rate_2x1"}, {{2, 2}, "rate_2x2"},
2557         {{2, 4}, "rate_2x4"}, {{4, 1}, "rate_4x1"}, {{4, 2}, "rate_4x2"}, {{4, 4}, "rate_4x4"},
2558     };
2559 
2560     struct TestModeParam
2561     {
2562         TestMode mode;
2563         const char *name;
2564     };
2565 
2566     const std::vector<TestModeParam> testModeParams{
2567         {TM_SETUP_RATE_WITH_ATOMICS_IN_COMPUTE_SHADER, "setup_with_atomics"},
2568         {TM_SETUP_RATE_WITH_FRAGMENT_SHADER, "setup_with_fragment"},
2569         {TM_SETUP_RATE_WITH_COPYING_FROM_OTHER_IMAGE, "setup_with_copying"},
2570         {TM_SETUP_RATE_WITH_COPYING_FROM_CONCURENT_IMAGE_USING_TRANSFER_QUEUE,
2571          "setup_with_copying_using_transfer_queue_concurent"},
2572         {TM_SETUP_RATE_WITH_COPYING_FROM_EXCLUSIVE_IMAGE_USING_TRANSFER_QUEUE,
2573          "setup_with_copying_using_transfer_queue_exclusive"},
2574         {TM_SETUP_RATE_WITH_LINEAR_TILED_IMAGE, "setup_with_linear_tiled_image"},
2575     };
2576 
2577     de::MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, "attachment_rate"));
2578 
2579     for (const auto &testModeParam : testModeParams)
2580     {
2581         de::MovePtr<tcu::TestCaseGroup> testModeGroup(new tcu::TestCaseGroup(testCtx, testModeParam.name));
2582 
2583         for (const auto &srFormat : srFormats)
2584         {
2585             de::MovePtr<tcu::TestCaseGroup> formatGroup(new tcu::TestCaseGroup(testCtx, srFormat.name));
2586             for (const auto &srRate : srRates)
2587             {
2588                 formatGroup->addChild(
2589                     new AttachmentRateTestCase(testCtx, srRate.name,
2590                                                de::SharedPtr<TestParams>(new TestParams{
2591                                                    testModeParam.mode,               // TestMode mode;
2592                                                    srFormat.format,                  // VkFormat srFormat;
2593                                                    srRate.count,                     // VkExtent2D srRate;
2594                                                    groupParams->useDynamicRendering, // bool useDynamicRendering;
2595                                                    false,                            // bool useImagelessFramebuffer;
2596                                                    false,                            // bool useNullShadingRateImage;
2597                                                    tcu::Nothing,                     // OptDSParams dsParams;
2598                                                })));
2599 
2600                 if (groupParams->useDynamicRendering)
2601                 {
2602                     // Duplicate all tests using dynamic rendering for NULL shading image.
2603                     std::string nullShadingName = std::string(srRate.name) + "_null_shading";
2604                     formatGroup->addChild(new AttachmentRateTestCase(testCtx, nullShadingName.c_str(),
2605                                                                      de::SharedPtr<TestParams>(new TestParams{
2606                                                                          testModeParam.mode, // TestMode mode;
2607                                                                          srFormat.format,    // VkFormat srFormat;
2608                                                                          srRate.count,       // VkExtent2D srRate;
2609                                                                          false,        // bool useDynamicRendering;
2610                                                                          false,        // bool useImagelessFramebuffer;
2611                                                                          true,         // bool useNullShadingRateImage;
2612                                                                          tcu::Nothing, // OptDSParams dsParams;
2613                                                                      })));
2614                 }
2615 
2616                 if (!groupParams->useDynamicRendering)
2617                 {
2618                     // duplicate all tests for imageless framebuffer
2619                     std::string imagelessName = std::string(srRate.name) + "_imageless";
2620                     formatGroup->addChild(new AttachmentRateTestCase(testCtx, imagelessName.c_str(),
2621                                                                      de::SharedPtr<TestParams>(new TestParams{
2622                                                                          testModeParam.mode, // TestMode mode;
2623                                                                          srFormat.format,    // VkFormat srFormat;
2624                                                                          srRate.count,       // VkExtent2D srRate;
2625                                                                          false,        // bool useDynamicRendering;
2626                                                                          true,         // bool useImagelessFramebuffer;
2627                                                                          false,        // bool useNullShadingRateImage;
2628                                                                          tcu::Nothing, // OptDSParams dsParams;
2629                                                                      })));
2630                 }
2631             }
2632 
2633             testModeGroup->addChild(formatGroup.release());
2634         }
2635 
2636         mainGroup->addChild(testModeGroup.release());
2637     }
2638 
2639     de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testCtx, "misc"));
2640     if (!groupParams->useDynamicRendering)
2641     {
2642         miscGroup->addChild(new AttachmentRateTestCase(
2643             testCtx, "two_subpass",
2644             de::SharedPtr<TestParams>(new TestParams{
2645                 TM_TWO_SUBPASS,    // TestMode mode;
2646                 VK_FORMAT_R8_UINT, // VkFormat srFormat;
2647                 {0, 0},            // VkExtent2D        srRate;                    // not used in TM_TWO_SUBPASS
2648                 false,             // bool useDynamicRendering;
2649                 false,             // bool useImagelessFramebuffer;
2650                 false,             // bool useNullShadingRateImage;
2651                 tcu::Nothing,      // OptDSParams dsParams;
2652             })));
2653         miscGroup->addChild(new AttachmentRateTestCase(testCtx, "memory_access",
2654                                                        de::SharedPtr<TestParams>(new TestParams{
2655                                                            TM_MEMORY_ACCESS,  // TestMode mode;
2656                                                            VK_FORMAT_R8_UINT, // VkFormat srFormat;
2657                                                            {1, 1},            // VkExtent2D srRate;
2658                                                            false,             // bool useDynamicRendering;
2659                                                            false,             // bool useImagelessFramebuffer;
2660                                                            false,             // bool useNullShadingRateImage;
2661                                                            tcu::Nothing,      // OptDSParams dsParams;
2662                                                        })));
2663         {
2664             const VkImageLayout testedLayouts[] = {
2665                 VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR,
2666                 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL,
2667                 VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL,
2668                 VK_IMAGE_LAYOUT_GENERAL,
2669             };
2670 
2671             const auto skip = strlen("VK_IMAGE_LAYOUT_");
2672 
2673             for (const auto &layout : testedLayouts)
2674             {
2675                 const auto dsFormat =
2676                     ((layout == VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL) ? VK_FORMAT_S8_UINT : VK_FORMAT_D16_UNORM);
2677                 const std::string layoutName = de::toLower(de::toString(layout).substr(skip));
2678                 const std::string testName   = "ro_ds_" + layoutName;
2679 
2680                 miscGroup->addChild(
2681                     new AttachmentRateTestCase(testCtx, testName.c_str(),
2682                                                de::SharedPtr<TestParams>(new TestParams{
2683                                                    TM_MEMORY_ACCESS,  // TestMode mode;
2684                                                    VK_FORMAT_R8_UINT, // VkFormat srFormat;
2685                                                    {2, 2},            // VkExtent2D srRate;
2686                                                    false,             // bool useDynamicRendering;
2687                                                    false,             // bool useImagelessFramebuffer;
2688                                                    false,             // bool useNullShadingRateImage;
2689                                                    DepthStencilParams{dsFormat, layout}, // OptDSParams dsParams;
2690                                                })));
2691             }
2692         }
2693     }
2694     else
2695     {
2696 #ifndef CTS_USES_VULKANSC
2697         miscGroup->addChild(new AttachmentRateTestCase(testCtx, "maintenance5",
2698                                                        de::SharedPtr<TestParams>(new TestParams{
2699                                                            TM_MAINTENANCE_5,  // TestMode mode;
2700                                                            VK_FORMAT_R8_UINT, // VkFormat srFormat;
2701                                                            {1, 1},            // VkExtent2D srRate;
2702                                                            true,              // bool useDynamicRendering;
2703                                                            false,             // bool useImagelessFramebuffer;
2704                                                            false,             // bool useNullShadingRateImage;
2705                                                            tcu::Nothing       // OptDSParams dsParams;
2706                                                        })));
2707 #endif
2708     }
2709     if (!miscGroup->empty())
2710         mainGroup->addChild(miscGroup.release());
2711 
2712     parentGroup->addChild(mainGroup.release());
2713 }
2714 
2715 } // namespace FragmentShadingRate
2716 } // namespace vkt
2717