1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2022 The Khronos Group Inc.
6  * Copyright (c) 2022 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file vktDrawMultisampleLinearInterpolationTests.cpp
22  * \brief InterpolateAt tests with linear interpolation
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawMultisampleLinearInterpolationTests.hpp"
26 
27 #include "vktDrawBaseClass.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 
33 namespace vkt
34 {
35 namespace Draw
36 {
37 namespace
38 {
39 using namespace vk;
40 
41 class MultisampleLinearInterpolationTestInstance : public TestInstance
42 {
43 public:
MultisampleLinearInterpolationTestInstance(Context & context,const tcu::IVec2 renderSize,const float interpolationRange,const VkSampleCountFlagBits sampleCountFlagBits,const SharedGroupParams groupParams)44     MultisampleLinearInterpolationTestInstance(Context &context, const tcu::IVec2 renderSize,
45                                                const float interpolationRange,
46                                                const VkSampleCountFlagBits sampleCountFlagBits,
47                                                const SharedGroupParams groupParams)
48         : vkt::TestInstance(context)
49         , m_renderSize(renderSize)
50         , m_interpolationRange(interpolationRange)
51         , m_sampleCountFlagBits(sampleCountFlagBits)
52         , m_groupParams(groupParams)
53     {
54     }
55 
~MultisampleLinearInterpolationTestInstance(void)56     ~MultisampleLinearInterpolationTestInstance(void)
57     {
58     }
59 
60     tcu::TestStatus iterate(void);
61 
62 private:
63     const tcu::IVec2 m_renderSize;
64     const float m_interpolationRange;
65     const VkSampleCountFlagBits m_sampleCountFlagBits;
66     const SharedGroupParams m_groupParams;
67 };
68 
iterate(void)69 tcu::TestStatus MultisampleLinearInterpolationTestInstance::iterate(void)
70 {
71     const DeviceInterface &vk = m_context.getDeviceInterface();
72     const VkDevice device     = m_context.getDevice();
73 
74     tcu::ConstPixelBufferAccess resultPixelBufferAccesses[2];
75     de::SharedPtr<Image> colorTargetImages[2];
76     de::SharedPtr<Image> multisampleImages[2];
77 
78     const VkFormat imageColorFormat = VK_FORMAT_R8G8B8A8_UNORM;
79 
80     const std::string vertShadernames[2] = {"vertRef", "vertNoPer"};
81     const std::string fragShadernames[2] = {"fragRef", "fragNoPer"};
82 
83     tcu::TestLog &log = m_context.getTestContext().getLog();
84 
85     const bool useMultisampling = m_sampleCountFlagBits == VK_SAMPLE_COUNT_1_BIT ? false : true;
86 
87     for (int draw = 0; draw < 2; draw++)
88     {
89         const Unique<VkShaderModule> vs(
90             createShaderModule(vk, device, m_context.getBinaryCollection().get(vertShadernames[draw].c_str()), 0));
91         const Unique<VkShaderModule> fs(
92             createShaderModule(vk, device, m_context.getBinaryCollection().get(fragShadernames[draw].c_str()), 0));
93 
94         de::SharedPtr<Buffer> vertexBuffer;
95 
96         const CmdPoolCreateInfo cmdPoolCreateInfo(m_context.getUniversalQueueFamilyIndex());
97         Move<VkCommandPool> cmdPool     = createCommandPool(vk, device, &cmdPoolCreateInfo);
98         Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
99         Move<VkCommandBuffer> secCmdBuffer;
100 
101         Move<VkRenderPass> renderPass;
102 
103         std::vector<Move<VkImageView>> colorTargetViews;
104         std::vector<Move<VkImageView>> multisampleViews;
105 
106         Move<VkFramebuffer> framebuffer;
107 
108         Move<VkPipeline> pipeline;
109         const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
110         Move<VkPipelineLayout> pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
111 
112         const VkVertexInputAttributeDescription vertInAttrDescs[2] = {
113             {0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
114             {1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(sizeof(float) * 4)}};
115 
116         // Create color buffer images
117         {
118             const VkExtent3D targetImageExtent = {static_cast<uint32_t>(m_renderSize.x()),
119                                                   static_cast<uint32_t>(m_renderSize.y()), 1u};
120             const VkImageUsageFlags usage =
121                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
122             const ImageCreateInfo targetImageCreateInfo(VK_IMAGE_TYPE_2D, imageColorFormat, targetImageExtent, 1u, 1u,
123                                                         VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_TILING_OPTIMAL, usage);
124 
125             colorTargetImages[draw] =
126                 Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
127                                       m_context.getUniversalQueueFamilyIndex());
128 
129             if (useMultisampling)
130             {
131                 const ImageCreateInfo multisampleImageCreateInfo(VK_IMAGE_TYPE_2D, imageColorFormat, targetImageExtent,
132                                                                  1u, 1u, m_sampleCountFlagBits, VK_IMAGE_TILING_OPTIMAL,
133                                                                  usage);
134 
135                 multisampleImages[draw] =
136                     Image::createAndAlloc(vk, device, multisampleImageCreateInfo, m_context.getDefaultAllocator(),
137                                           m_context.getUniversalQueueFamilyIndex());
138             }
139         }
140 
141         {
142             const ImageViewCreateInfo colorTargetViewInfo(colorTargetImages[draw]->object(), VK_IMAGE_VIEW_TYPE_2D,
143                                                           imageColorFormat);
144 
145             colorTargetViews.push_back(createImageView(vk, device, &colorTargetViewInfo));
146 
147             if (useMultisampling)
148             {
149                 const ImageViewCreateInfo multisamplingTargetViewInfo(multisampleImages[draw]->object(),
150                                                                       VK_IMAGE_VIEW_TYPE_2D, imageColorFormat);
151 
152                 multisampleViews.push_back(createImageView(vk, device, &multisamplingTargetViewInfo));
153             }
154         }
155 
156         // Create render pass and frame buffer.
157         if (!m_groupParams->useDynamicRendering)
158         {
159             RenderPassCreateInfo renderPassCreateInfo;
160             std::vector<VkImageView> attachments;
161             std::vector<VkAttachmentReference> colorAttachmentRefs;
162             std::vector<VkAttachmentReference> multisampleAttachmentRefs;
163             uint32_t attachmentNdx = 0;
164 
165             {
166                 const VkAttachmentReference colorAttachmentReference = {
167                     attachmentNdx++,                         // uint32_t attachment;
168                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
169                 };
170 
171                 colorAttachmentRefs.push_back(colorAttachmentReference);
172 
173                 renderPassCreateInfo.addAttachment(AttachmentDescription(
174                     imageColorFormat, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE,
175                     VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
176                     VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL));
177 
178                 if (useMultisampling)
179                 {
180                     const VkAttachmentReference multiSampleAttachmentReference = {
181                         attachmentNdx++,                         // uint32_t attachment;
182                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
183                     };
184 
185                     multisampleAttachmentRefs.push_back(multiSampleAttachmentReference);
186 
187                     renderPassCreateInfo.addAttachment(
188                         AttachmentDescription(imageColorFormat, m_sampleCountFlagBits, VK_ATTACHMENT_LOAD_OP_CLEAR,
189                                               VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
190                                               VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED,
191                                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
192                 }
193             }
194 
195             renderPassCreateInfo.addSubpass(SubpassDescription(
196                 VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, (uint32_t)colorAttachmentRefs.size(),
197                 useMultisampling ? &multisampleAttachmentRefs[0] : &colorAttachmentRefs[0],
198                 useMultisampling ? &colorAttachmentRefs[0] : DE_NULL, AttachmentReference(), 0, DE_NULL));
199 
200             renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
201 
202             for (uint32_t frameNdx = 0; frameNdx < colorTargetViews.size(); frameNdx++)
203             {
204                 attachments.push_back(*colorTargetViews[frameNdx]);
205 
206                 if (useMultisampling)
207                     attachments.push_back(*multisampleViews[frameNdx]);
208             }
209 
210             const VkFramebufferCreateInfo framebufferCreateInfo = {
211                 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
212                 DE_NULL,                                   // const void* pNext;
213                 0u,                                        // VkFramebufferCreateFlags flags;
214                 *renderPass,                               // VkRenderPass renderPass;
215                 static_cast<uint32_t>(attachments.size()), // uint32_t attachmentCount;
216                 &attachments[0],                           // const VkImageView* pAttachments;
217                 static_cast<uint32_t>(m_renderSize.x()),   // uint32_t width;
218                 static_cast<uint32_t>(m_renderSize.y()),   // uint32_t height;
219                 1u                                         // uint32_t layers;
220             };
221 
222             framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
223         }
224 
225         // Create vertex buffer.
226         {
227             const PositionColorVertex vertices[] = {
228                 // The first draw is for reference image.
229                 /*     ____            ____   */
230                 /*    /    \          |    |  */
231                 /*   /      \         |____|  */
232                 /*  /        \                */
233                 /* /__________\               */
234                 /*                            */
235                 /*    result        reference */
236                 /*                            */
237                 // In result shape the bottom vertices are deeper. When the drawn result image is a perfect square,
238                 // and color comparison with reference image is easy to make.
239                 PositionColorVertex(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
240                                     tcu::Vec4(0.0f, m_interpolationRange, 0.0f, m_interpolationRange)), // Top Right
241                 PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
242                                     tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
243                                               m_interpolationRange)), // Top Left
244                 PositionColorVertex(
245                     tcu::Vec4(draw == 0 ? 1.0f : 2.0f, draw == 0 ? 1.0f : 2.0f, 0.0f, draw == 0 ? 1.0f : 2.0f),
246                     tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
247                               m_interpolationRange)), // Bottom Right
248                 PositionColorVertex(
249                     tcu::Vec4(draw == 0 ? -1.0f : -2.0f, draw == 0 ? 1.0f : 2.0f, 0.0f, draw == 0 ? 1.0f : 2.0f),
250                     tcu::Vec4(m_interpolationRange, 0.0f, 0.0f, m_interpolationRange)), // Bottom Left
251                 PositionColorVertex(
252                     tcu::Vec4(draw == 0 ? 1.0f : 2.0f, draw == 0 ? 1.0f : 2.0f, 0.0f, draw == 0 ? 1.0f : 2.0f),
253                     tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
254                               m_interpolationRange)), // Bottom Right
255                 PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
256                                     tcu::Vec4(m_interpolationRange * 0.5f, m_interpolationRange * 0.5f, 0.0f,
257                                               m_interpolationRange)) // Top Left
258             };
259 
260             const VkDeviceSize dataSize = sizeof(vertices);
261             vertexBuffer =
262                 Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
263                                        m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
264             uint8_t *ptr = static_cast<uint8_t *>(vertexBuffer->getBoundMemory().getHostPtr());
265 
266             deMemcpy(ptr, vertices, static_cast<size_t>(dataSize));
267             flushMappedMemoryRange(vk, device, vertexBuffer->getBoundMemory().getMemory(),
268                                    vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
269         }
270 
271         // Create pipeline.
272         {
273             const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
274 
275             VkViewport viewport = makeViewport(m_renderSize.x(), m_renderSize.y());
276             VkRect2D scissor    = makeRect2D(m_renderSize.x(), m_renderSize.y());
277 
278             const std::vector<uint32_t> sampleMask = {0xfffffff, 0xfffffff};
279 
280             const VkVertexInputBindingDescription vertexInputBindingDescription = {0, (uint32_t)sizeof(tcu::Vec4) * 2,
281                                                                                    VK_VERTEX_INPUT_RATE_VERTEX};
282             PipelineCreateInfo::VertexInputState vertexInputState =
283                 PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertInAttrDescs);
284 
285             PipelineCreateInfo pipelineCreateInfo(*pipelineLayout, *renderPass, 0, 0);
286 
287             pipelineCreateInfo.addShader(
288                 PipelineCreateInfo::PipelineShaderStage(*vs, "main", VK_SHADER_STAGE_VERTEX_BIT));
289             pipelineCreateInfo.addShader(
290                 PipelineCreateInfo::PipelineShaderStage(*fs, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
291             pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(vertexInputState));
292             pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
293             pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
294             pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<VkViewport>(1, viewport),
295                                                                           std::vector<VkRect2D>(1, scissor)));
296             pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
297             pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
298             pipelineCreateInfo.addState(
299                 PipelineCreateInfo::MultiSampleState(m_sampleCountFlagBits, false, 0.0f, sampleMask));
300 
301 #ifndef CTS_USES_VULKANSC
302             VkPipelineRenderingCreateInfo renderingCreateInfo{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
303                                                               DE_NULL,
304                                                               0u,
305                                                               1u,
306                                                               &imageColorFormat,
307                                                               VK_FORMAT_UNDEFINED,
308                                                               VK_FORMAT_UNDEFINED};
309 
310             if (m_groupParams->useDynamicRendering)
311                 pipelineCreateInfo.pNext = &renderingCreateInfo;
312 #endif // CTS_USES_VULKANSC
313 
314             pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
315         }
316 
317         // Draw quad and read results.
318         {
319             const VkQueue queue           = m_context.getUniversalQueue();
320             const VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
321             const ImageSubresourceRange subresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
322             const VkRect2D renderArea   = makeRect2D(m_renderSize.x(), m_renderSize.y());
323             const VkBuffer buffer       = vertexBuffer->object();
324             const VkOffset3D zeroOffset = {0, 0, 0};
325 
326             std::vector<VkClearValue> clearValues(2, clearColor);
327 
328             auto drawCommands = [&](VkCommandBuffer cmdBuff)
329             {
330                 const VkDeviceSize vertexBufferOffset = 0;
331                 vk.cmdBindVertexBuffers(cmdBuff, 0, 1, &buffer, &vertexBufferOffset);
332                 vk.cmdBindPipeline(cmdBuff, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
333                 vk.cmdDraw(cmdBuff, 6u, 1u, 0u, 0u);
334             };
335 
336             clearColorImage(vk, device, queue, m_context.getUniversalQueueFamilyIndex(),
337                             colorTargetImages[draw]->object(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
338                             VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
339                             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 1u);
340 
341 #ifndef CTS_USES_VULKANSC
342             auto preRenderBarriers = [&]()
343             {
344                 // Transition Images
345                 initialTransitionColor2DImage(
346                     vk, *cmdBuffer, colorTargetImages[draw]->object(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
347                     VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
348 
349                 if (useMultisampling)
350                 {
351                     initialTransitionColor2DImage(
352                         vk, *cmdBuffer, multisampleImages[draw]->object(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
353                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
354                 }
355             };
356 
357             if (m_groupParams->useDynamicRendering)
358             {
359                 const uint32_t imagesCount = static_cast<uint32_t>(colorTargetViews.size());
360 
361                 std::vector<VkRenderingAttachmentInfo> colorAttachments(
362                     imagesCount,
363                     {
364                         VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType;
365                         DE_NULL,                                         // const void* pNext;
366                         DE_NULL,                                         // VkImageView imageView;
367                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,        // VkImageLayout imageLayout;
368                         VK_RESOLVE_MODE_NONE,                            // VkResolveModeFlagBits resolveMode;
369                         DE_NULL,                                         // VkImageView resolveImageView;
370                         VK_IMAGE_LAYOUT_GENERAL,                         // VkImageLayout resolveImageLayout;
371                         VK_ATTACHMENT_LOAD_OP_CLEAR,                     // VkAttachmentLoadOp loadOp;
372                         VK_ATTACHMENT_STORE_OP_STORE,                    // VkAttachmentStoreOp storeOp;
373                         clearColor                                       // VkClearValue clearValue;
374                     });
375 
376                 for (uint32_t i = 0; i < imagesCount; ++i)
377                 {
378                     if (useMultisampling)
379                     {
380                         colorAttachments[i].imageView        = *multisampleViews[i];
381                         colorAttachments[i].resolveMode      = VK_RESOLVE_MODE_AVERAGE_BIT;
382                         colorAttachments[i].resolveImageView = *colorTargetViews[i];
383                     }
384                     else
385                     {
386                         colorAttachments[i].imageView = *colorTargetViews[i];
387                     }
388                 }
389 
390                 VkRenderingInfo renderingInfo{
391                     VK_STRUCTURE_TYPE_RENDERING_INFO, // VkStructureType sType;
392                     DE_NULL,                          // const void* pNext;
393                     0,                                // VkRenderingFlagsKHR flags;
394                     renderArea,                       // VkRect2D renderArea;
395                     1u,                               // uint32_t layerCount;
396                     0u,                               // uint32_t viewMask;
397                     imagesCount,                      // uint32_t colorAttachmentCount;
398                     colorAttachments.data(),          // const VkRenderingAttachmentInfoKHR* pColorAttachments;
399                     DE_NULL,                          // const VkRenderingAttachmentInfoKHR* pDepthAttachment;
400                     DE_NULL,                          // const VkRenderingAttachmentInfoKHR* pStencilAttachment;
401                 };
402 
403                 if (m_groupParams->useSecondaryCmdBuffer)
404                 {
405                     VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
406                         VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
407                         DE_NULL,                                                         // const void* pNext;
408                         0u,                                                              // VkRenderingFlagsKHR flags;
409                         0u,                                                              // uint32_t viewMask;
410                         1u,                   // uint32_t colorAttachmentCount;
411                         &imageColorFormat,    // const VkFormat* pColorAttachmentFormats;
412                         VK_FORMAT_UNDEFINED,  // VkFormat depthAttachmentFormat;
413                         VK_FORMAT_UNDEFINED,  // VkFormat stencilAttachmentFormat;
414                         m_sampleCountFlagBits // VkSampleCountFlagBits rasterizationSamples;
415                     };
416 
417                     const VkCommandBufferInheritanceInfo bufferInheritanceInfo =
418                         initVulkanStructure(&inheritanceRenderingInfo);
419                     VkCommandBufferBeginInfo commandBufBeginParams{
420                         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
421                         DE_NULL,                                     // const void* pNext;
422                         VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags;
423                         &bufferInheritanceInfo};
424 
425                     secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
426 
427                     // record secondary command buffer
428                     if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
429                     {
430                         inheritanceRenderingInfo.flags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
431                         VK_CHECK(vk.beginCommandBuffer(*secCmdBuffer, &commandBufBeginParams));
432                         vk.cmdBeginRendering(*secCmdBuffer, &renderingInfo);
433                     }
434                     else
435                     {
436                         commandBufBeginParams.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
437                         VK_CHECK(vk.beginCommandBuffer(*secCmdBuffer, &commandBufBeginParams));
438                     }
439 
440                     drawCommands(*secCmdBuffer);
441 
442                     if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
443                         endRendering(vk, *secCmdBuffer);
444 
445                     endCommandBuffer(vk, *secCmdBuffer);
446 
447                     // record primary command buffer
448                     beginCommandBuffer(vk, *cmdBuffer, 0u);
449 
450                     preRenderBarriers();
451 
452                     if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
453                     {
454                         renderingInfo.flags = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
455                         vk.cmdBeginRendering(*cmdBuffer, &renderingInfo);
456                     }
457                     vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
458 
459                     if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
460                         endRendering(vk, *cmdBuffer);
461                     endCommandBuffer(vk, *cmdBuffer);
462                 }
463                 else
464                 {
465                     beginCommandBuffer(vk, *cmdBuffer, 0u);
466                     preRenderBarriers();
467 
468                     vk.cmdBeginRendering(*cmdBuffer, &renderingInfo);
469                     drawCommands(*cmdBuffer);
470                     endRendering(vk, *cmdBuffer);
471 
472                     endCommandBuffer(vk, *cmdBuffer);
473                 }
474             }
475             else
476 #endif // CTS_USES_VULKANSC
477             {
478                 beginCommandBuffer(vk, *cmdBuffer, 0u);
479 
480                 const uint32_t imagesCount = static_cast<uint32_t>(colorTargetViews.size() + multisampleViews.size());
481 
482                 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, imagesCount, &clearValues[0]);
483                 drawCommands(*cmdBuffer);
484                 endRenderPass(vk, *cmdBuffer);
485 
486                 endCommandBuffer(vk, *cmdBuffer);
487             }
488 
489             submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
490 
491             resultPixelBufferAccesses[draw] = colorTargetImages[draw]->readSurface(
492                 queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, zeroOffset,
493                 m_renderSize.x(), m_renderSize.y(), VK_IMAGE_ASPECT_COLOR_BIT);
494         }
495     }
496 
497     if (!tcu::floatThresholdCompare(log, "Result", "Image comparison result", resultPixelBufferAccesses[0],
498                                     resultPixelBufferAccesses[1], tcu::Vec4(0.005f), tcu::COMPARE_LOG_RESULT))
499         return tcu::TestStatus::fail("Rendered color image is not correct");
500 
501     return tcu::TestStatus::pass("Success");
502 }
503 
504 class MultisampleLinearInterpolationTestCase : public TestCase
505 {
506 public:
MultisampleLinearInterpolationTestCase(tcu::TestContext & context,const char * name,const tcu::IVec2 renderSize,const float interpolationRange,const tcu::Vec2 offset,const VkSampleCountFlagBits sampleCountFlagBits,const SharedGroupParams groupParams)507     MultisampleLinearInterpolationTestCase(tcu::TestContext &context, const char *name, const tcu::IVec2 renderSize,
508                                            const float interpolationRange, const tcu::Vec2 offset,
509                                            const VkSampleCountFlagBits sampleCountFlagBits,
510                                            const SharedGroupParams groupParams)
511         : vkt::TestCase(context, name)
512         , m_renderSize(renderSize)
513         , m_interpolationRange(interpolationRange)
514         , m_offset(offset)
515         , m_sampleCountFlagBits(sampleCountFlagBits)
516         , m_groupParams(groupParams)
517     {
518     }
519 
~MultisampleLinearInterpolationTestCase(void)520     ~MultisampleLinearInterpolationTestCase(void)
521     {
522     }
523 
524     virtual void initPrograms(SourceCollections &programCollection) const;
525     virtual void checkSupport(Context &context) const;
526     virtual TestInstance *createInstance(Context &context) const;
527 
528 private:
529     const tcu::IVec2 m_renderSize;
530     const float m_interpolationRange;
531     const tcu::Vec2 m_offset;
532     const VkSampleCountFlagBits m_sampleCountFlagBits;
533     const SharedGroupParams m_groupParams;
534 };
535 
initPrograms(SourceCollections & programCollection) const536 void MultisampleLinearInterpolationTestCase::initPrograms(SourceCollections &programCollection) const
537 {
538     // Reference vertex shader.
539     {
540         std::ostringstream vrt;
541 
542         vrt << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
543             << "\n"
544             << "layout(location = 0) in vec4 in_position;\n"
545             << "layout(location = 1) in vec4 in_color;\n"
546             << "layout(location = 0) out vec4 out_color;\n"
547             << "\n"
548             << "void main()\n"
549             << "{\n"
550             << "    gl_PointSize = 1.0;\n"
551             << "    gl_Position  = in_position;\n"
552             << "    out_color    = in_color;\n"
553             << "}\n";
554 
555         programCollection.glslSources.add("vertRef") << glu::VertexSource(vrt.str());
556     }
557 
558     // Noperspective vertex shader.
559     {
560         std::ostringstream vrt;
561 
562         vrt << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
563             << "\n"
564             << "layout(location = 0) in vec4 in_position;\n"
565             << "layout(location = 1) in vec4 in_color;\n"
566             << "layout(location = 0) noperspective out vec4 out_color;\n"
567             << "\n"
568             << "void main()\n"
569             << "{\n"
570             << "    gl_PointSize = 1.0;\n"
571             << "    gl_Position  = in_position;\n"
572             << "    out_color    = in_color;\n"
573             << "}\n";
574 
575         programCollection.glslSources.add("vertNoPer") << glu::VertexSource(vrt.str());
576     }
577 
578     // Reference fragment shader.
579     {
580         std::ostringstream frg;
581 
582         frg << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
583             << "layout(location = 0) in vec4 in_color;\n"
584             << "layout(location = 0) out vec4 out_color;\n"
585             << "void main()\n"
586             << "{\n"
587             << "    vec4 out_color_y = mix(vec4(0.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), gl_FragCoord.y / "
588             << static_cast<float>(m_renderSize.y()) << " + " << m_offset.y() / static_cast<float>(m_renderSize.y())
589             << ");\n"
590             << "    vec4 out_color_x = mix(vec4(1.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), gl_FragCoord.x / "
591             << static_cast<float>(m_renderSize.x()) << " + " << m_offset.x() / static_cast<float>(m_renderSize.x())
592             << ");\n"
593             << "    out_color = 0.5 * (out_color_y + out_color_x);\n"
594             << "}\n";
595 
596         programCollection.glslSources.add("fragRef") << glu::FragmentSource(frg.str());
597     }
598 
599     // Noperspective fragment shader.
600     {
601         std::ostringstream frg;
602 
603         frg << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
604             << "layout(location = 0) noperspective in vec4 in_color;\n"
605             << "layout(location = 0) out vec4 out_color;\n"
606             << "void main()\n"
607             << "{\n"
608             << "    vec4 out_color_offset = interpolateAtOffset(in_color, vec2(" << m_offset.x() << ", " << m_offset.y()
609             << "));\n"
610             << "    vec4 out_color_sample = interpolateAtSample(in_color, gl_SampleID);\n"
611             << "    out_color = (0.5 * (out_color_offset + out_color_sample));\n"
612             << "    out_color /= " << m_interpolationRange << ";\n";
613 
614         // Run additional sample comparison test. If it fails, we write 1.0 to blue color channel.
615         frg << "    vec4 diff = out_color_sample - interpolateAtOffset(in_color, gl_SamplePosition - vec2(0.5));"
616             << "    float min_precision = 0.000001;\n"
617             << "    if (diff.x > min_precision && diff.y > min_precision && diff.z > min_precision && diff.w > "
618                "min_precision)\n"
619             << "    {\n"
620             << "        out_color.z = 1.0;\n"
621             << "    }\n";
622 
623         frg << "}\n";
624 
625         programCollection.glslSources.add("fragNoPer") << glu::FragmentSource(frg.str());
626     }
627 }
628 
checkSupport(Context & context) const629 void MultisampleLinearInterpolationTestCase::checkSupport(Context &context) const
630 {
631     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SAMPLE_RATE_SHADING);
632 
633     if (!(m_sampleCountFlagBits & context.getDeviceProperties().limits.framebufferColorSampleCounts))
634         TCU_THROW(NotSupportedError,
635                   "Multisampling with " + de::toString(m_sampleCountFlagBits) + " samples not supported");
636 
637 #ifndef CTS_USES_VULKANSC
638     if (m_groupParams->useDynamicRendering)
639         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
640 
641     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
642         !context.getPortabilitySubsetFeatures().shaderSampleRateInterpolationFunctions)
643     {
644         TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Shader sample rate interpolation functions are not "
645                                      "supported by this implementation");
646     }
647 #endif // CTS_USES_VULKANSC
648 }
649 
createInstance(Context & context) const650 TestInstance *MultisampleLinearInterpolationTestCase::createInstance(Context &context) const
651 {
652     return new MultisampleLinearInterpolationTestInstance(context, m_renderSize, m_interpolationRange,
653                                                           m_sampleCountFlagBits, m_groupParams);
654 }
655 
createTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)656 void createTests(tcu::TestCaseGroup *testGroup, const SharedGroupParams groupParams)
657 {
658     tcu::TestContext &testCtx = testGroup->getTestContext();
659 
660     struct
661     {
662         const std::string name;
663         const tcu::Vec2 value;
664     } offsets[] = {{"no_offset", tcu::Vec2(0.0f, 0.0f)},
665                    {"offset_min", tcu::Vec2(-0.5f, -0.5f)},
666                    {"offset_max", tcu::Vec2(0.4375f, 0.4375f)}};
667 
668     struct
669     {
670         const std::string name;
671         VkSampleCountFlagBits value;
672     } flagBits[] = {{"1_sample", VK_SAMPLE_COUNT_1_BIT},    {"2_samples", VK_SAMPLE_COUNT_2_BIT},
673                     {"4_samples", VK_SAMPLE_COUNT_4_BIT},   {"8_samples", VK_SAMPLE_COUNT_8_BIT},
674                     {"16_samples", VK_SAMPLE_COUNT_16_BIT}, {"32_samples", VK_SAMPLE_COUNT_32_BIT},
675                     {"64_samples", VK_SAMPLE_COUNT_64_BIT}};
676 
677     for (const auto &offset : offsets)
678     {
679         for (const auto &flagBit : flagBits)
680         {
681             // reduce number of tests for dynamic rendering cases where secondary command buffer is used
682             if (groupParams->useSecondaryCmdBuffer && (flagBit.value > VK_SAMPLE_COUNT_4_BIT))
683                 break;
684 
685             testGroup->addChild(new MultisampleLinearInterpolationTestCase(
686                 testCtx, (offset.name + "_" + flagBit.name).c_str(), tcu::IVec2(16, 16), 1.0f, offset.value,
687                 flagBit.value, groupParams));
688         }
689     }
690 }
691 
692 } // namespace
693 
createMultisampleLinearInterpolationTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)694 tcu::TestCaseGroup *createMultisampleLinearInterpolationTests(tcu::TestContext &testCtx,
695                                                               const SharedGroupParams groupParams)
696 {
697     // Tests for linear interpolation decorations.
698     return createTestGroup(testCtx, "linear_interpolation", createTests, groupParams);
699 }
700 
701 } // namespace Draw
702 } // namespace vkt
703