xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Functional rasterization tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktTestGroupUtil.hpp"
27 #include "vktAmberTestCase.hpp"
28 #include "vktRasterizationTests.hpp"
29 #include "vktRasterizationFragShaderSideEffectsTests.hpp"
30 #ifndef CTS_USES_VULKANSC
31 #include "vktRasterizationProvokingVertexTests.hpp"
32 #endif // CTS_USES_VULKANSC
33 #include "tcuRasterizationVerifier.hpp"
34 #include "tcuSurface.hpp"
35 #include "tcuRenderTarget.hpp"
36 #include "tcuVectorUtil.hpp"
37 #include "tcuStringTemplate.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuResultCollector.hpp"
40 #include "tcuFloatFormat.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "vkImageUtil.hpp"
43 #include "deStringUtil.hpp"
44 #include "deRandom.hpp"
45 #include "vktTestCase.hpp"
46 #include "vktTestCaseUtil.hpp"
47 #include "vkPrograms.hpp"
48 #include "vkMemUtil.hpp"
49 #include "vkRefUtil.hpp"
50 #include "vkQueryUtil.hpp"
51 #include "vkBuilderUtil.hpp"
52 #include "vkTypeUtil.hpp"
53 #include "vkCmdUtil.hpp"
54 #include "vkObjUtil.hpp"
55 #include "vkBufferWithMemory.hpp"
56 #include "vkImageWithMemory.hpp"
57 #include "vkBarrierUtil.hpp"
58 #include "vkBufferWithMemory.hpp"
59 #ifndef CTS_USES_VULKANSC
60 #include "vktRasterizationOrderAttachmentAccessTests.hpp"
61 #include "vktRasterizationDepthBiasControlTests.hpp"
62 #include "vktShaderTileImageTests.hpp"
63 #endif // CTS_USES_VULKANSC
64 
65 #include <vector>
66 #include <sstream>
67 #include <memory>
68 
69 using namespace vk;
70 
71 namespace vkt
72 {
73 namespace rasterization
74 {
75 namespace
76 {
77 
78 using tcu::LineSceneSpec;
79 using tcu::PointSceneSpec;
80 using tcu::RasterizationArguments;
81 using tcu::TriangleSceneSpec;
82 
83 static const char *const s_shaderVertexTemplate = "#version 310 es\n"
84                                                   "layout(location = 0) in highp vec4 a_position;\n"
85                                                   "layout(location = 1) in highp vec4 a_color;\n"
86                                                   "layout(location = 0) ${INTERPOLATION}out highp vec4 v_color;\n"
87                                                   "layout (set=0, binding=0) uniform PointSize {\n"
88                                                   "    highp float u_pointSize;\n"
89                                                   "};\n"
90                                                   "void main ()\n"
91                                                   "{\n"
92                                                   "    gl_Position = a_position;\n"
93                                                   "    gl_PointSize = u_pointSize;\n"
94                                                   "    v_color = a_color;\n"
95                                                   "}\n";
96 
97 static const char *const s_shaderFragmentTemplate = "#version 310 es\n"
98                                                     "layout(location = 0) out highp vec4 fragColor;\n"
99                                                     "layout(location = 0) ${INTERPOLATION}in highp vec4 v_color;\n"
100                                                     "void main ()\n"
101                                                     "{\n"
102                                                     "    fragColor = v_color;\n"
103                                                     "}\n";
104 
105 enum InterpolationCaseFlags
106 {
107     INTERPOLATIONFLAGS_NONE      = 0,
108     INTERPOLATIONFLAGS_PROJECTED = (1 << 1),
109     INTERPOLATIONFLAGS_FLATSHADE = (1 << 2),
110 };
111 
112 enum ResolutionValues
113 {
114     RESOLUTION_POT  = 256,
115     RESOLUTION_NPOT = 258
116 };
117 
118 enum PrimitiveWideness
119 {
120     PRIMITIVEWIDENESS_NARROW = 0,
121     PRIMITIVEWIDENESS_WIDE,
122 
123     PRIMITIVEWIDENESS_LAST
124 };
125 
126 enum LineStipple
127 {
128     LINESTIPPLE_DISABLED = 0,
129     LINESTIPPLE_STATIC,
130     LINESTIPPLE_DYNAMIC,
131     LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY,
132 
133     LINESTIPPLE_LAST
134 };
135 
136 static const uint32_t lineStippleFactor  = 2;
137 static const uint32_t lineStipplePattern = 0x0F0F;
138 
139 enum class LineStippleFactorCase
140 {
141     DEFAULT = 0,
142     ZERO,
143     LARGE,
144 };
145 
146 enum PrimitiveStrictness
147 {
148     PRIMITIVESTRICTNESS_STRICT = 0,
149     PRIMITIVESTRICTNESS_NONSTRICT,
150     PRIMITIVESTRICTNESS_IGNORE,
151 
152     PRIMITIVESTRICTNESS_LAST
153 };
154 
155 class BaseRenderingTestCase : public TestCase
156 {
157 public:
158     BaseRenderingTestCase(tcu::TestContext &context, const std::string &name,
159                           VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, bool flatshade = false);
160     virtual ~BaseRenderingTestCase(void);
161 
162     virtual void initPrograms(vk::SourceCollections &programCollection) const;
163 
164 protected:
165     const VkSampleCountFlagBits m_sampleCount;
166     const bool m_flatshade;
167 };
168 
BaseRenderingTestCase(tcu::TestContext & context,const std::string & name,VkSampleCountFlagBits sampleCount,bool flatshade)169 BaseRenderingTestCase::BaseRenderingTestCase(tcu::TestContext &context, const std::string &name,
170                                              VkSampleCountFlagBits sampleCount, bool flatshade)
171     : TestCase(context, name)
172     , m_sampleCount(sampleCount)
173     , m_flatshade(flatshade)
174 {
175 }
176 
initPrograms(vk::SourceCollections & programCollection) const177 void BaseRenderingTestCase::initPrograms(vk::SourceCollections &programCollection) const
178 {
179     tcu::StringTemplate vertexSource(s_shaderVertexTemplate);
180     tcu::StringTemplate fragmentSource(s_shaderFragmentTemplate);
181     std::map<std::string, std::string> params;
182 
183     params["INTERPOLATION"] = (m_flatshade) ? ("flat ") : ("");
184 
185     programCollection.glslSources.add("vertext_shader") << glu::VertexSource(vertexSource.specialize(params));
186     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fragmentSource.specialize(params));
187 }
188 
~BaseRenderingTestCase(void)189 BaseRenderingTestCase::~BaseRenderingTestCase(void)
190 {
191 }
192 
193 class BaseRenderingTestInstance : public TestInstance
194 {
195 public:
196     BaseRenderingTestInstance(Context &context, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT,
197                               uint32_t renderSize = RESOLUTION_POT, VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM,
198                               uint32_t additionalRenderSize = 0);
199     ~BaseRenderingTestInstance(void);
200 
201     const tcu::TextureFormat &getTextureFormat(void) const;
202 
203 protected:
204     void addImageTransitionBarrier(VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask,
205                                    VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
206                                    VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const;
207     virtual void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
208                                 VkPrimitiveTopology primitiveTopology);
209     void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
210                         const std::vector<tcu::Vec4> &coloDrata, VkPrimitiveTopology primitiveTopology);
211     void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &positionData,
212                         const std::vector<tcu::Vec4> &colorData, VkPrimitiveTopology primitiveTopology, VkImage image,
213                         VkImage resolvedImage, VkFramebuffer frameBuffer, const uint32_t renderSize,
214                         VkBuffer resultBuffer, const Allocation &resultBufferMemory);
215     virtual float getLineWidth(void) const;
216     virtual float getPointSize(void) const;
getLineStippleDynamic(void) const217     virtual bool getLineStippleDynamic(void) const
218     {
219         return false;
220     }
isDynamicTopology(void) const221     virtual bool isDynamicTopology(void) const
222     {
223         return false;
224     }
getWrongTopology(void) const225     virtual VkPrimitiveTopology getWrongTopology(void) const
226     {
227         return VK_PRIMITIVE_TOPOLOGY_LAST;
228     }
getRightTopology(void) const229     virtual VkPrimitiveTopology getRightTopology(void) const
230     {
231         return VK_PRIMITIVE_TOPOLOGY_LAST;
232     }
getOffScreenPoints(void) const233     virtual std::vector<tcu::Vec4> getOffScreenPoints(void) const
234     {
235         return std::vector<tcu::Vec4>();
236     }
237 
238     virtual const VkPipelineRasterizationStateCreateInfo *getRasterizationStateCreateInfo(void) const;
239 
240     virtual VkPipelineRasterizationLineStateCreateInfoEXT initLineRasterizationStateCreateInfo(void) const;
241 
242     virtual const VkPipelineRasterizationLineStateCreateInfoEXT *getLineRasterizationStateCreateInfo(void);
243 
244     virtual const VkPipelineColorBlendStateCreateInfo *getColorBlendStateCreateInfo(void) const;
245 
246     const uint32_t m_renderSize;
247     const VkSampleCountFlagBits m_sampleCount;
248     uint32_t m_subpixelBits;
249     const bool m_multisampling;
250 
251     const VkFormat m_imageFormat;
252     const tcu::TextureFormat m_textureFormat;
253     Move<VkCommandPool> m_commandPool;
254 
255     Move<VkImage> m_image;
256     de::MovePtr<Allocation> m_imageMemory;
257     Move<VkImageView> m_imageView;
258 
259     Move<VkImage> m_resolvedImage;
260     de::MovePtr<Allocation> m_resolvedImageMemory;
261     Move<VkImageView> m_resolvedImageView;
262 
263     Move<VkRenderPass> m_renderPass;
264     Move<VkFramebuffer> m_frameBuffer;
265 
266     Move<VkDescriptorPool> m_descriptorPool;
267     Move<VkDescriptorSet> m_descriptorSet;
268     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
269 
270     Move<VkBuffer> m_uniformBuffer;
271     de::MovePtr<Allocation> m_uniformBufferMemory;
272     const VkDeviceSize m_uniformBufferSize;
273 
274     Move<VkPipelineLayout> m_pipelineLayout;
275 
276     Move<VkShaderModule> m_vertexShaderModule;
277     Move<VkShaderModule> m_fragmentShaderModule;
278 
279     Move<VkBuffer> m_resultBuffer;
280     de::MovePtr<Allocation> m_resultBufferMemory;
281     const VkDeviceSize m_resultBufferSize;
282 
283     const uint32_t m_additionalRenderSize;
284     const VkDeviceSize m_additionalResultBufferSize;
285 
286     VkPipelineRasterizationLineStateCreateInfoEXT m_lineRasterizationStateInfo;
287 
288 private:
getIteration(void) const289     virtual int getIteration(void) const
290     {
291         TCU_THROW(InternalError, "Iteration undefined in the base class");
292     }
293 };
294 
BaseRenderingTestInstance(Context & context,VkSampleCountFlagBits sampleCount,uint32_t renderSize,VkFormat imageFormat,uint32_t additionalRenderSize)295 BaseRenderingTestInstance::BaseRenderingTestInstance(Context &context, VkSampleCountFlagBits sampleCount,
296                                                      uint32_t renderSize, VkFormat imageFormat,
297                                                      uint32_t additionalRenderSize)
298     : TestInstance(context)
299     , m_renderSize(renderSize)
300     , m_sampleCount(sampleCount)
301     , m_subpixelBits(context.getDeviceProperties().limits.subPixelPrecisionBits)
302     , m_multisampling(m_sampleCount != VK_SAMPLE_COUNT_1_BIT)
303     , m_imageFormat(imageFormat)
304     , m_textureFormat(vk::mapVkFormat(m_imageFormat))
305     , m_uniformBufferSize(sizeof(float))
306     , m_resultBufferSize(renderSize * renderSize * m_textureFormat.getPixelSize())
307     , m_additionalRenderSize(additionalRenderSize)
308     , m_additionalResultBufferSize(additionalRenderSize * additionalRenderSize * m_textureFormat.getPixelSize())
309     , m_lineRasterizationStateInfo()
310 {
311     const DeviceInterface &vkd      = m_context.getDeviceInterface();
312     const VkDevice vkDevice         = m_context.getDevice();
313     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
314     Allocator &allocator            = m_context.getDefaultAllocator();
315     DescriptorPoolBuilder descriptorPoolBuilder;
316     DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
317 
318     // Command Pool
319     m_commandPool = createCommandPool(vkd, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
320 
321     // Image
322     {
323         const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
324         VkImageFormatProperties properties;
325 
326         if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(
327                  m_context.getPhysicalDevice(), m_imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, imageUsage, 0,
328                  &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
329         {
330             TCU_THROW(NotSupportedError, "Format not supported");
331         }
332 
333         if ((properties.sampleCounts & m_sampleCount) != m_sampleCount)
334         {
335             TCU_THROW(NotSupportedError, "Format not supported");
336         }
337 
338         const VkImageCreateInfo imageCreateInfo = {
339             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
340             DE_NULL,                             // const void* pNext;
341             0u,                                  // VkImageCreateFlags flags;
342             VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
343             m_imageFormat,                       // VkFormat format;
344             {m_renderSize, m_renderSize, 1u},    // VkExtent3D extent;
345             1u,                                  // uint32_t mipLevels;
346             1u,                                  // uint32_t arrayLayers;
347             m_sampleCount,                       // VkSampleCountFlagBits samples;
348             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
349             imageUsage,                          // VkImageUsageFlags usage;
350             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
351             1u,                                  // uint32_t queueFamilyIndexCount;
352             &queueFamilyIndex,                   // const uint32_t* pQueueFamilyIndices;
353             VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
354         };
355 
356         m_image = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
357 
358         m_imageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_image), MemoryRequirement::Any);
359         VK_CHECK(vkd.bindImageMemory(vkDevice, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset()));
360     }
361 
362     // Image View
363     {
364         const VkImageViewCreateInfo imageViewCreateInfo = {
365             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
366             DE_NULL,                                  // const void* pNext;
367             0u,                                       // VkImageViewCreateFlags flags;
368             *m_image,                                 // VkImage image;
369             VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
370             m_imageFormat,                            // VkFormat format;
371             makeComponentMappingRGBA(),               // VkComponentMapping components;
372             {
373                 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
374                 0u,                        // uint32_t baseMipLevel;
375                 1u,                        // uint32_t mipLevels;
376                 0u,                        // uint32_t baseArrayLayer;
377                 1u,                        // uint32_t arraySize;
378             },                             // VkImageSubresourceRange subresourceRange;
379         };
380 
381         m_imageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
382     }
383 
384     if (m_multisampling)
385     {
386         {
387             // Resolved Image
388             const VkImageUsageFlags imageUsage =
389                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
390             VkImageFormatProperties properties;
391 
392             if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(
393                      m_context.getPhysicalDevice(), m_imageFormat, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
394                      imageUsage, 0, &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
395             {
396                 TCU_THROW(NotSupportedError, "Format not supported");
397             }
398 
399             const VkImageCreateInfo imageCreateInfo = {
400                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
401                 DE_NULL,                             // const void* pNext;
402                 0u,                                  // VkImageCreateFlags flags;
403                 VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
404                 m_imageFormat,                       // VkFormat format;
405                 {m_renderSize, m_renderSize, 1u},    // VkExtent3D extent;
406                 1u,                                  // uint32_t mipLevels;
407                 1u,                                  // uint32_t arrayLayers;
408                 VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
409                 VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
410                 imageUsage,                          // VkImageUsageFlags usage;
411                 VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
412                 1u,                                  // uint32_t queueFamilyIndexCount;
413                 &queueFamilyIndex,                   // const uint32_t* pQueueFamilyIndices;
414                 VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout initialLayout;
415             };
416 
417             m_resolvedImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
418             m_resolvedImageMemory =
419                 allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_resolvedImage), MemoryRequirement::Any);
420             VK_CHECK(vkd.bindImageMemory(vkDevice, *m_resolvedImage, m_resolvedImageMemory->getMemory(),
421                                          m_resolvedImageMemory->getOffset()));
422         }
423 
424         // Resolved Image View
425         {
426             const VkImageViewCreateInfo imageViewCreateInfo = {
427                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
428                 DE_NULL,                                  // const void* pNext;
429                 0u,                                       // VkImageViewCreateFlags flags;
430                 *m_resolvedImage,                         // VkImage image;
431                 VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
432                 m_imageFormat,                            // VkFormat format;
433                 makeComponentMappingRGBA(),               // VkComponentMapping components;
434                 {
435                     VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
436                     0u,                        // uint32_t baseMipLevel;
437                     1u,                        // uint32_t mipLevels;
438                     0u,                        // uint32_t baseArrayLayer;
439                     1u,                        // uint32_t arraySize;
440                 },                             // VkImageSubresourceRange subresourceRange;
441             };
442 
443             m_resolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
444         }
445     }
446 
447     // Render Pass
448     {
449         const VkImageLayout imageLayout                = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
450         const VkAttachmentDescription attachmentDesc[] = {
451             {
452                 0u,                               // VkAttachmentDescriptionFlags flags;
453                 m_imageFormat,                    // VkFormat format;
454                 m_sampleCount,                    // VkSampleCountFlagBits samples;
455                 VK_ATTACHMENT_LOAD_OP_CLEAR,      // VkAttachmentLoadOp loadOp;
456                 VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp storeOp;
457                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp stencilLoadOp;
458                 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
459                 imageLayout,                      // VkImageLayout initialLayout;
460                 imageLayout,                      // VkImageLayout finalLayout;
461             },
462             {
463                 0u,                               // VkAttachmentDescriptionFlags flags;
464                 m_imageFormat,                    // VkFormat format;
465                 VK_SAMPLE_COUNT_1_BIT,            // VkSampleCountFlagBits samples;
466                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp loadOp;
467                 VK_ATTACHMENT_STORE_OP_STORE,     // VkAttachmentStoreOp storeOp;
468                 VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // VkAttachmentLoadOp stencilLoadOp;
469                 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
470                 imageLayout,                      // VkImageLayout initialLayout;
471                 imageLayout,                      // VkImageLayout finalLayout;
472             }};
473 
474         const VkAttachmentReference attachmentRef = {
475             0u,          // uint32_t attachment;
476             imageLayout, // VkImageLayout layout;
477         };
478 
479         const VkAttachmentReference resolveAttachmentRef = {
480             1u,          // uint32_t attachment;
481             imageLayout, // VkImageLayout layout;
482         };
483 
484         const VkSubpassDescription subpassDesc = {
485             0u,                                                // VkSubpassDescriptionFlags flags;
486             VK_PIPELINE_BIND_POINT_GRAPHICS,                   // VkPipelineBindPoint pipelineBindPoint;
487             0u,                                                // uint32_t inputAttachmentCount;
488             DE_NULL,                                           // const VkAttachmentReference* pInputAttachments;
489             1u,                                                // uint32_t colorAttachmentCount;
490             &attachmentRef,                                    // const VkAttachmentReference* pColorAttachments;
491             m_multisampling ? &resolveAttachmentRef : DE_NULL, // const VkAttachmentReference* pResolveAttachments;
492             DE_NULL,                                           // const VkAttachmentReference* pDepthStencilAttachment;
493             0u,                                                // uint32_t preserveAttachmentCount;
494             DE_NULL,                                           // const VkAttachmentReference* pPreserveAttachments;
495         };
496 
497         const VkRenderPassCreateInfo renderPassCreateInfo = {
498             VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
499             DE_NULL,                                   // const void* pNext;
500             0u,                                        // VkRenderPassCreateFlags flags;
501             m_multisampling ? 2u : 1u,                 // uint32_t attachmentCount;
502             attachmentDesc,                            // const VkAttachmentDescription* pAttachments;
503             1u,                                        // uint32_t subpassCount;
504             &subpassDesc,                              // const VkSubpassDescription* pSubpasses;
505             0u,                                        // uint32_t dependencyCount;
506             DE_NULL,                                   // const VkSubpassDependency* pDependencies;
507         };
508 
509         m_renderPass = createRenderPass(vkd, vkDevice, &renderPassCreateInfo, DE_NULL);
510     }
511 
512     // FrameBuffer
513     {
514         const VkImageView attachments[] = {*m_imageView, *m_resolvedImageView};
515 
516         const VkFramebufferCreateInfo framebufferCreateInfo = {
517             VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
518             DE_NULL,                                   // const void* pNext;
519             0u,                                        // VkFramebufferCreateFlags flags;
520             *m_renderPass,                             // VkRenderPass renderPass;
521             m_multisampling ? 2u : 1u,                 // uint32_t attachmentCount;
522             attachments,                               // const VkImageView* pAttachments;
523             m_renderSize,                              // uint32_t width;
524             m_renderSize,                              // uint32_t height;
525             1u,                                        // uint32_t layers;
526         };
527 
528         m_frameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL);
529     }
530 
531     // Uniform Buffer
532     {
533         const VkBufferCreateInfo bufferCreateInfo = {
534             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
535             DE_NULL,                              // const void* pNext;
536             0u,                                   // VkBufferCreateFlags flags;
537             m_uniformBufferSize,                  // VkDeviceSize size;
538             VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,   // VkBufferUsageFlags usage;
539             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
540             1u,                                   // uint32_t queueFamilyIndexCount;
541             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
542         };
543 
544         m_uniformBuffer       = createBuffer(vkd, vkDevice, &bufferCreateInfo);
545         m_uniformBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_uniformBuffer),
546                                                    MemoryRequirement::HostVisible);
547 
548         VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_uniformBuffer, m_uniformBufferMemory->getMemory(),
549                                       m_uniformBufferMemory->getOffset()));
550     }
551 
552     // Descriptors
553     {
554         descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
555         m_descriptorPool =
556             descriptorPoolBuilder.build(vkd, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
557 
558         descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
559         m_descriptorSetLayout = descriptorSetLayoutBuilder.build(vkd, vkDevice);
560 
561         const VkDescriptorSetAllocateInfo descriptorSetParams = {
562             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
563             DE_NULL,
564             *m_descriptorPool,
565             1u,
566             &m_descriptorSetLayout.get(),
567         };
568 
569         m_descriptorSet = allocateDescriptorSet(vkd, vkDevice, &descriptorSetParams);
570 
571         const VkDescriptorBufferInfo descriptorBufferInfo = {
572             *m_uniformBuffer, // VkBuffer buffer;
573             0u,               // VkDeviceSize offset;
574             VK_WHOLE_SIZE     // VkDeviceSize range;
575         };
576 
577         const VkWriteDescriptorSet writeDescritporSet = {
578             VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
579             DE_NULL,                                // const void* pNext;
580             *m_descriptorSet,                       // VkDescriptorSet destSet;
581             0,                                      // uint32_t destBinding;
582             0,                                      // uint32_t destArrayElement;
583             1u,                                     // uint32_t count;
584             VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,      // VkDescriptorType descriptorType;
585             DE_NULL,                                // const VkDescriptorImageInfo* pImageInfo;
586             &descriptorBufferInfo,                  // const VkDescriptorBufferInfo* pBufferInfo;
587             DE_NULL                                 // const VkBufferView* pTexelBufferView;
588         };
589 
590         vkd.updateDescriptorSets(vkDevice, 1u, &writeDescritporSet, 0u, DE_NULL);
591     }
592 
593     // Pipeline Layout
594     {
595         const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
596             VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
597             DE_NULL,                                       // const void* pNext;
598             0u,                                            // VkPipelineLayoutCreateFlags flags;
599             1u,                                            // uint32_t descriptorSetCount;
600             &m_descriptorSetLayout.get(),                  // const VkDescriptorSetLayout* pSetLayouts;
601             0u,                                            // uint32_t pushConstantRangeCount;
602             DE_NULL                                        // const VkPushConstantRange* pPushConstantRanges;
603         };
604 
605         m_pipelineLayout = createPipelineLayout(vkd, vkDevice, &pipelineLayoutCreateInfo);
606     }
607 
608     // Shaders
609     {
610         m_vertexShaderModule =
611             createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("vertext_shader"), 0);
612         m_fragmentShaderModule =
613             createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("fragment_shader"), 0);
614     }
615 
616     // Result Buffer
617     {
618         const VkBufferCreateInfo bufferCreateInfo = {
619             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
620             DE_NULL,                              // const void* pNext;
621             0u,                                   // VkBufferCreateFlags flags;
622             m_resultBufferSize,                   // VkDeviceSize size;
623             VK_BUFFER_USAGE_TRANSFER_DST_BIT,     // VkBufferUsageFlags usage;
624             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
625             1u,                                   // uint32_t queueFamilyIndexCount;
626             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
627         };
628 
629         m_resultBuffer       = createBuffer(vkd, vkDevice, &bufferCreateInfo);
630         m_resultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_resultBuffer),
631                                                   MemoryRequirement::HostVisible);
632 
633         VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_resultBuffer, m_resultBufferMemory->getMemory(),
634                                       m_resultBufferMemory->getOffset()));
635     }
636 
637     m_context.getTestContext().getLog() << tcu::TestLog::Message
638                                         << "Sample count = " << getSampleCountFlagsStr(m_sampleCount)
639                                         << tcu::TestLog::EndMessage;
640     m_context.getTestContext().getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits
641                                         << tcu::TestLog::EndMessage;
642 }
643 
~BaseRenderingTestInstance(void)644 BaseRenderingTestInstance::~BaseRenderingTestInstance(void)
645 {
646 }
647 
addImageTransitionBarrier(VkCommandBuffer commandBuffer,VkImage image,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,VkAccessFlags srcAccessMask,VkAccessFlags dstAccessMask,VkImageLayout oldLayout,VkImageLayout newLayout) const648 void BaseRenderingTestInstance::addImageTransitionBarrier(VkCommandBuffer commandBuffer, VkImage image,
649                                                           VkPipelineStageFlags srcStageMask,
650                                                           VkPipelineStageFlags dstStageMask,
651                                                           VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
652                                                           VkImageLayout oldLayout, VkImageLayout newLayout) const
653 {
654 
655     const DeviceInterface &vkd = m_context.getDeviceInterface();
656 
657     const VkImageSubresourceRange subResourcerange = {
658         VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
659         0,                         // uint32_t baseMipLevel;
660         1,                         // uint32_t levelCount;
661         0,                         // uint32_t baseArrayLayer;
662         1                          // uint32_t layerCount;
663     };
664 
665     const VkImageMemoryBarrier imageBarrier = {
666         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
667         DE_NULL,                                // const void* pNext;
668         srcAccessMask,                          // VkAccessFlags srcAccessMask;
669         dstAccessMask,                          // VkAccessFlags dstAccessMask;
670         oldLayout,                              // VkImageLayout oldLayout;
671         newLayout,                              // VkImageLayout newLayout;
672         VK_QUEUE_FAMILY_IGNORED,                // uint32_t srcQueueFamilyIndex;
673         VK_QUEUE_FAMILY_IGNORED,                // uint32_t destQueueFamilyIndex;
674         image,                                  // VkImage image;
675         subResourcerange                        // VkImageSubresourceRange subresourceRange;
676     };
677 
678     vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &imageBarrier);
679 }
680 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,VkPrimitiveTopology primitiveTopology)681 void BaseRenderingTestInstance::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
682                                                VkPrimitiveTopology primitiveTopology)
683 {
684     // default to color white
685     const std::vector<tcu::Vec4> colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
686 
687     drawPrimitives(result, vertexData, colorData, primitiveTopology);
688 }
689 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & positionData,const std::vector<tcu::Vec4> & colorData,VkPrimitiveTopology primitiveTopology)690 void BaseRenderingTestInstance::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &positionData,
691                                                const std::vector<tcu::Vec4> &colorData,
692                                                VkPrimitiveTopology primitiveTopology)
693 {
694     drawPrimitives(result, positionData, colorData, primitiveTopology, *m_image, *m_resolvedImage, *m_frameBuffer,
695                    m_renderSize, *m_resultBuffer, *m_resultBufferMemory);
696 }
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & positionData,const std::vector<tcu::Vec4> & colorData,VkPrimitiveTopology primitiveTopology,VkImage image,VkImage resolvedImage,VkFramebuffer frameBuffer,const uint32_t renderSize,VkBuffer resultBuffer,const Allocation & resultBufferMemory)697 void BaseRenderingTestInstance::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &positionData,
698                                                const std::vector<tcu::Vec4> &colorData,
699                                                VkPrimitiveTopology primitiveTopology, VkImage image,
700                                                VkImage resolvedImage, VkFramebuffer frameBuffer,
701                                                const uint32_t renderSize, VkBuffer resultBuffer,
702                                                const Allocation &resultBufferMemory)
703 {
704     const DeviceInterface &vkd      = m_context.getDeviceInterface();
705     const VkDevice vkDevice         = m_context.getDevice();
706     const VkQueue queue             = m_context.getUniversalQueue();
707     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
708     Allocator &allocator            = m_context.getDefaultAllocator();
709     const size_t attributeBatchSize = de::dataSize(positionData);
710     const auto offscreenData        = getOffScreenPoints();
711 
712     Move<VkCommandBuffer> commandBuffer;
713     Move<VkPipeline> graphicsPipeline;
714     Move<VkBuffer> vertexBuffer;
715     de::MovePtr<Allocation> vertexBufferMemory;
716     std::unique_ptr<BufferWithMemory> offscreenDataBuffer;
717     const VkPhysicalDeviceProperties properties = m_context.getDeviceProperties();
718 
719     if (attributeBatchSize > properties.limits.maxVertexInputAttributeOffset)
720     {
721         std::stringstream message;
722         message << "Larger vertex input attribute offset is needed (" << attributeBatchSize
723                 << ") than the available maximum (" << properties.limits.maxVertexInputAttributeOffset << ").";
724         TCU_THROW(NotSupportedError, message.str().c_str());
725     }
726 
727     // Create Graphics Pipeline
728     {
729         const VkVertexInputBindingDescription vertexInputBindingDescription = {
730             0u,                         // uint32_t binding;
731             sizeof(tcu::Vec4),          // uint32_t strideInBytes;
732             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate;
733         };
734 
735         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
736             {
737                 0u,                            // uint32_t location;
738                 0u,                            // uint32_t binding;
739                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
740                 0u                             // uint32_t offsetInBytes;
741             },
742             {
743                 1u,                            // uint32_t location;
744                 0u,                            // uint32_t binding;
745                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
746                 (uint32_t)attributeBatchSize   // uint32_t offsetInBytes;
747             }};
748 
749         const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
750             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
751             DE_NULL,                                                   // const void* pNext;
752             0,                                                         // VkPipelineVertexInputStateCreateFlags flags;
753             1u,                                                        // uint32_t bindingCount;
754             &vertexInputBindingDescription,  // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
755             2u,                              // uint32_t attributeCount;
756             vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
757         };
758 
759         const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(renderSize)));
760         const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(renderSize)));
761 
762         const VkPipelineMultisampleStateCreateInfo multisampleStateParams = {
763             VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
764             DE_NULL,                                                  // const void* pNext;
765             0u,                                                       // VkPipelineMultisampleStateCreateFlags flags;
766             m_sampleCount,                                            // VkSampleCountFlagBits rasterizationSamples;
767             VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
768             0.0f,                                                     // float minSampleShading;
769             DE_NULL,                                                  // const VkSampleMask* pSampleMask;
770             VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
771             VK_FALSE                                                  // VkBool32 alphaToOneEnable;
772         };
773 
774         VkPipelineRasterizationStateCreateInfo rasterizationStateInfo = *getRasterizationStateCreateInfo();
775 
776         const VkPipelineRasterizationLineStateCreateInfoEXT *lineRasterizationStateInfo =
777             getLineRasterizationStateCreateInfo();
778 
779         if (lineRasterizationStateInfo != DE_NULL && lineRasterizationStateInfo->sType != 0)
780             appendStructurePtrToVulkanChain(&rasterizationStateInfo.pNext, lineRasterizationStateInfo);
781 
782         VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
783             VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType                      sType
784             DE_NULL,                                              // const void*                          pNext
785             0u,                                                   // VkPipelineDynamicStateCreateFlags    flags
786             0u,     // uint32_t                             dynamicStateCount
787             DE_NULL // const VkDynamicState*                pDynamicStates
788         };
789 
790         std::vector<VkDynamicState> dynamicStates;
791 
792         if (getLineStippleDynamic())
793             dynamicStates.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_EXT);
794 
795 #ifndef CTS_USES_VULKANSC
796         if (isDynamicTopology())
797             dynamicStates.push_back(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY);
798 #endif // CTS_USES_VULKANSC
799 
800         if (getLineStippleDynamic())
801         {
802             dynamicStateCreateInfo.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
803             dynamicStateCreateInfo.pDynamicStates    = de::dataOrNull(dynamicStates);
804         }
805 
806         graphicsPipeline = makeGraphicsPipeline(
807             vkd,                   // const DeviceInterface&                        vk
808             vkDevice,              // const VkDevice                                device
809             *m_pipelineLayout,     // const VkPipelineLayout                        pipelineLayout
810             *m_vertexShaderModule, // const VkShaderModule                          vertexShaderModule
811             DE_NULL,               // const VkShaderModule                          tessellationControlShaderModule
812             DE_NULL,               // const VkShaderModule                          tessellationEvalShaderModule
813             DE_NULL,               // const VkShaderModule                          geometryShaderModule
814             rasterizationStateInfo.rasterizerDiscardEnable ? DE_NULL : *m_fragmentShaderModule,
815             // const VkShaderModule                          fragmentShaderModule
816             *m_renderPass,           // const VkRenderPass                            renderPass
817             viewports,               // const std::vector<VkViewport>&                viewports
818             scissors,                // const std::vector<VkRect2D>&                  scissors
819             primitiveTopology,       // const VkPrimitiveTopology                     topology
820             0u,                      // const uint32_t                                subpass
821             0u,                      // const uint32_t                                patchControlPoints
822             &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
823             &rasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
824             &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo*   multisampleStateCreateInfo
825             DE_NULL,                 // const VkPipelineDepthStencilStateCreateInfo*  depthStencilStateCreateInfo,
826             getColorBlendStateCreateInfo(), // const VkPipelineColorBlendStateCreateInfo*    colorBlendStateCreateInfo,
827             &dynamicStateCreateInfo);       // const VkPipelineDynamicStateCreateInfo*       dynamicStateCreateInfo
828     }
829 
830     // Create Vertex Buffer
831     {
832         const VkBufferCreateInfo vertexBufferParams = {
833             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
834             DE_NULL,                              // const void* pNext;
835             0u,                                   // VkBufferCreateFlags flags;
836             attributeBatchSize * 2,               // VkDeviceSize size;
837             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
838             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
839             1u,                                   // uint32_t queueFamilyCount;
840             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
841         };
842 
843         vertexBuffer       = createBuffer(vkd, vkDevice, &vertexBufferParams);
844         vertexBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer),
845                                                 MemoryRequirement::HostVisible);
846 
847         VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(),
848                                       vertexBufferMemory->getOffset()));
849 
850         // Load vertices into vertex buffer
851         deMemcpy(vertexBufferMemory->getHostPtr(), positionData.data(), attributeBatchSize);
852         deMemcpy(reinterpret_cast<uint8_t *>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, colorData.data(),
853                  attributeBatchSize);
854         flushAlloc(vkd, vkDevice, *vertexBufferMemory);
855     }
856 
857     if (!offscreenData.empty())
858     {
859         // Concatenate positions with vertex colors.
860         const std::vector<tcu::Vec4> colors(offscreenData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
861         std::vector<tcu::Vec4> fullOffscreenData(offscreenData);
862         fullOffscreenData.insert(fullOffscreenData.end(), colors.begin(), colors.end());
863 
864         // Copy full data to offscreen data buffer.
865         const auto offscreenBufferSizeSz = de::dataSize(fullOffscreenData);
866         const auto offscreenBufferSize   = static_cast<VkDeviceSize>(offscreenBufferSizeSz);
867         const auto offscreenDataCreateInfo =
868             makeBufferCreateInfo(offscreenBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
869 
870         offscreenDataBuffer.reset(
871             new BufferWithMemory(vkd, vkDevice, allocator, offscreenDataCreateInfo, MemoryRequirement::HostVisible));
872         auto &bufferAlloc = offscreenDataBuffer->getAllocation();
873         void *dataPtr     = bufferAlloc.getHostPtr();
874 
875         deMemcpy(dataPtr, fullOffscreenData.data(), offscreenBufferSizeSz);
876         flushAlloc(vkd, vkDevice, bufferAlloc);
877     }
878 
879     // Create Command Buffer
880     commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
881 
882     // Begin Command Buffer
883     beginCommandBuffer(vkd, *commandBuffer);
884 
885     addImageTransitionBarrier(*commandBuffer, image,
886                               VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,         // VkPipelineStageFlags        srcStageMask
887                               VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,        // VkPipelineStageFlags        dstStageMask
888                               0,                                         // VkAccessFlags            srcAccessMask
889                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,      // VkAccessFlags            dstAccessMask
890                               VK_IMAGE_LAYOUT_UNDEFINED,                 // VkImageLayout oldLayout;
891                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
892 
893     if (m_multisampling)
894     {
895         addImageTransitionBarrier(*commandBuffer, resolvedImage,
896                                   VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,         // VkPipelineStageFlags        srcStageMask
897                                   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,        // VkPipelineStageFlags        dstStageMask
898                                   0,                                         // VkAccessFlags            srcAccessMask
899                                   VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,      // VkAccessFlags            dstAccessMask
900                                   VK_IMAGE_LAYOUT_UNDEFINED,                 // VkImageLayout oldLayout;
901                                   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
902     }
903 
904     // Begin Render Pass
905     beginRenderPass(vkd, *commandBuffer, *m_renderPass, frameBuffer, vk::makeRect2D(0, 0, renderSize, renderSize),
906                     tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
907 
908     const VkDeviceSize vertexBufferOffset = 0;
909 
910     vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
911     vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1,
912                               &m_descriptorSet.get(), 0u, DE_NULL);
913     if (getLineStippleDynamic())
914     {
915         vkd.cmdSetLineStippleKHR(*commandBuffer, lineStippleFactor, lineStipplePattern);
916 #ifndef CTS_USES_VULKANSC
917         if (isDynamicTopology())
918         {
919             // Using a dynamic topology can interact with the dynamic line stipple set above on some implementations, so we try to
920             // check nothing breaks here. We set a wrong topology, draw some offscreen data and go back to the right topology
921             // _without_ re-setting the line stipple again. Side effects should not be visible.
922             DE_ASSERT(!!offscreenDataBuffer);
923 
924             vkd.cmdSetPrimitiveTopology(*commandBuffer, getWrongTopology());
925             vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &offscreenDataBuffer->get(), &vertexBufferOffset);
926             vkd.cmdDraw(*commandBuffer, static_cast<uint32_t>(offscreenData.size()), 1u, 0u, 0u);
927             vkd.cmdSetPrimitiveTopology(*commandBuffer, getRightTopology());
928         }
929 #endif // CTS_USES_VULKANSC
930     }
931     vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset);
932     vkd.cmdDraw(*commandBuffer, (uint32_t)positionData.size(), 1, 0, 0);
933     endRenderPass(vkd, *commandBuffer);
934 
935     // Copy Image
936     copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? resolvedImage : image, resultBuffer,
937                       tcu::IVec2(renderSize, renderSize));
938 
939     endCommandBuffer(vkd, *commandBuffer);
940 
941     // Set Point Size
942     {
943         float pointSize = getPointSize();
944         deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
945         flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
946     }
947 
948     // Submit
949     submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
950 
951     invalidateAlloc(vkd, vkDevice, resultBufferMemory);
952     tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(renderSize, renderSize, 1),
953                                                               resultBufferMemory.getHostPtr()));
954 }
955 
getLineWidth(void) const956 float BaseRenderingTestInstance::getLineWidth(void) const
957 {
958     return 1.0f;
959 }
960 
getPointSize(void) const961 float BaseRenderingTestInstance::getPointSize(void) const
962 {
963     return 1.0f;
964 }
965 
getRasterizationStateCreateInfo(void) const966 const VkPipelineRasterizationStateCreateInfo *BaseRenderingTestInstance::getRasterizationStateCreateInfo(void) const
967 {
968     static VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
969         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
970         DE_NULL,                                                    // const void* pNext;
971         0,                                                          // VkPipelineRasterizationStateCreateFlags flags;
972         false,                                                      // VkBool32 depthClipEnable;
973         false,                                                      // VkBool32 rasterizerDiscardEnable;
974         VK_POLYGON_MODE_FILL,                                       // VkFillMode fillMode;
975         VK_CULL_MODE_NONE,                                          // VkCullMode cullMode;
976         VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // VkFrontFace frontFace;
977         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
978         0.0f,                                                       // float depthBias;
979         0.0f,                                                       // float depthBiasClamp;
980         0.0f,                                                       // float slopeScaledDepthBias;
981         getLineWidth(),                                             // float lineWidth;
982     };
983 
984     rasterizationStateCreateInfo.lineWidth = getLineWidth();
985     return &rasterizationStateCreateInfo;
986 }
987 
initLineRasterizationStateCreateInfo(void) const988 VkPipelineRasterizationLineStateCreateInfoEXT BaseRenderingTestInstance::initLineRasterizationStateCreateInfo(
989     void) const
990 {
991     VkPipelineRasterizationLineStateCreateInfoEXT lineRasterizationStateInfo = {
992         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
993         DE_NULL,                                                             // const void* pNext;
994         VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, // VkLineRasterizationModeEXT lineRasterizationMode;
995         VK_FALSE,                               // VkBool32 stippledLineEnable;
996         1,                                      // uint32_t lineStippleFactor;
997         0xFFFF,                                 // uint16_t lineStipplePattern;
998     };
999 
1000     return lineRasterizationStateInfo;
1001 }
1002 
getLineRasterizationStateCreateInfo(void)1003 const VkPipelineRasterizationLineStateCreateInfoEXT *BaseRenderingTestInstance::getLineRasterizationStateCreateInfo(
1004     void)
1005 {
1006     if (m_lineRasterizationStateInfo.sType != VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT)
1007         m_lineRasterizationStateInfo = initLineRasterizationStateCreateInfo();
1008 
1009     return &m_lineRasterizationStateInfo;
1010 }
1011 
getColorBlendStateCreateInfo(void) const1012 const VkPipelineColorBlendStateCreateInfo *BaseRenderingTestInstance::getColorBlendStateCreateInfo(void) const
1013 {
1014     static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1015         false,                // VkBool32 blendEnable;
1016         VK_BLEND_FACTOR_ONE,  // VkBlend srcBlendColor;
1017         VK_BLEND_FACTOR_ZERO, // VkBlend destBlendColor;
1018         VK_BLEND_OP_ADD,      // VkBlendOp blendOpColor;
1019         VK_BLEND_FACTOR_ONE,  // VkBlend srcBlendAlpha;
1020         VK_BLEND_FACTOR_ZERO, // VkBlend destBlendAlpha;
1021         VK_BLEND_OP_ADD,      // VkBlendOp blendOpAlpha;
1022         (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
1023          VK_COLOR_COMPONENT_A_BIT) // VkChannelFlags channelWriteMask;
1024     };
1025 
1026     static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
1027         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1028         DE_NULL,                                                  // const void* pNext;
1029         0,                                                        // VkPipelineColorBlendStateCreateFlags flags;
1030         false,                                                    // VkBool32 logicOpEnable;
1031         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
1032         1u,                                                       // uint32_t attachmentCount;
1033         &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1034         {0.0f, 0.0f, 0.0f, 0.0f},   // float blendConst[4];
1035     };
1036 
1037     return &colorBlendStateParams;
1038 }
1039 
getTextureFormat(void) const1040 const tcu::TextureFormat &BaseRenderingTestInstance::getTextureFormat(void) const
1041 {
1042     return m_textureFormat;
1043 }
1044 
1045 class BaseTriangleTestInstance : public BaseRenderingTestInstance
1046 {
1047 public:
1048     BaseTriangleTestInstance(Context &context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount,
1049                              uint32_t renderSize = RESOLUTION_POT);
1050     virtual tcu::TestStatus iterate(void);
1051 
1052 protected:
getIteration(void) const1053     int getIteration(void) const
1054     {
1055         return m_iteration;
1056     }
getIterationCount(void) const1057     int getIterationCount(void) const
1058     {
1059         return m_iterationCount;
1060     }
1061 
1062 private:
1063     virtual void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
1064                                    std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles) = DE_NULL;
1065     virtual bool compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> &triangles, tcu::Surface &resultImage,
1066                                   std::vector<tcu::Vec4> &drawBuffer);
1067 
1068     int m_iteration;
1069     const int m_iterationCount;
1070     VkPrimitiveTopology m_primitiveTopology;
1071     bool m_allIterationsPassed;
1072 };
1073 
BaseTriangleTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,VkSampleCountFlagBits sampleCount,uint32_t renderSize)1074 BaseTriangleTestInstance::BaseTriangleTestInstance(Context &context, VkPrimitiveTopology primitiveTopology,
1075                                                    VkSampleCountFlagBits sampleCount, uint32_t renderSize)
1076     : BaseRenderingTestInstance(context, sampleCount, renderSize)
1077     , m_iteration(0)
1078     , m_iterationCount(3)
1079     , m_primitiveTopology(primitiveTopology)
1080     , m_allIterationsPassed(true)
1081 {
1082 }
1083 
iterate(void)1084 tcu::TestStatus BaseTriangleTestInstance::iterate(void)
1085 {
1086     const std::string iterationDescription =
1087         "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
1088     const tcu::ScopedLogSection section(m_context.getTestContext().getLog(), iterationDescription,
1089                                         iterationDescription);
1090     tcu::Surface resultImage(m_renderSize, m_renderSize);
1091     std::vector<tcu::Vec4> drawBuffer;
1092     std::vector<TriangleSceneSpec::SceneTriangle> triangles;
1093 
1094     generateTriangles(m_iteration, drawBuffer, triangles);
1095 
1096     // draw image
1097     drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
1098 
1099     // compare
1100     {
1101         const bool compareOk = compareAndVerify(triangles, resultImage, drawBuffer);
1102 
1103         if (!compareOk)
1104             m_allIterationsPassed = false;
1105     }
1106 
1107     // result
1108     if (++m_iteration == m_iterationCount)
1109     {
1110         if (m_allIterationsPassed)
1111             return tcu::TestStatus::pass("Pass");
1112         else
1113             return tcu::TestStatus::fail("Incorrect rasterization");
1114     }
1115     else
1116         return tcu::TestStatus::incomplete();
1117 }
1118 
compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage,std::vector<tcu::Vec4> &)1119 bool BaseTriangleTestInstance::compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> &triangles,
1120                                                 tcu::Surface &resultImage, std::vector<tcu::Vec4> &)
1121 {
1122     RasterizationArguments args;
1123     TriangleSceneSpec scene;
1124 
1125     tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
1126 
1127     args.numSamples   = m_multisampling ? 1 : 0;
1128     args.subpixelBits = m_subpixelBits;
1129     args.redBits      = colorBits[0];
1130     args.greenBits    = colorBits[1];
1131     args.blueBits     = colorBits[2];
1132 
1133     scene.triangles.swap(triangles);
1134 
1135     return verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
1136 }
1137 
1138 class BaseLineTestInstance : public BaseRenderingTestInstance
1139 {
1140 public:
1141     BaseLineTestInstance(Context &context, VkPrimitiveTopology primitiveTopology, PrimitiveWideness wideness,
1142                          PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount, LineStipple stipple,
1143                          VkLineRasterizationModeEXT lineRasterizationMode, LineStippleFactorCase stippleFactor,
1144                          const uint32_t additionalRenderSize = 0, const uint32_t renderSize = RESOLUTION_POT,
1145                          const float narrowLineWidth = 1.0f);
1146     virtual tcu::TestStatus iterate(void);
1147     virtual float getLineWidth(void) const;
getLineStippleEnable(void) const1148     bool getLineStippleEnable(void) const
1149     {
1150         return m_stipple != LINESTIPPLE_DISABLED;
1151     }
getLineStippleDynamic(void) const1152     virtual bool getLineStippleDynamic(void) const
1153     {
1154         return (m_stipple == LINESTIPPLE_DYNAMIC || m_stipple == LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY);
1155     }
isDynamicTopology(void) const1156     virtual bool isDynamicTopology(void) const
1157     {
1158         return m_stipple == LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY;
1159     }
1160 
1161     virtual std::vector<tcu::Vec4> getOffScreenPoints(void) const;
1162 
1163     virtual VkPipelineRasterizationLineStateCreateInfoEXT initLineRasterizationStateCreateInfo(void) const;
1164 
1165     virtual const VkPipelineRasterizationLineStateCreateInfoEXT *getLineRasterizationStateCreateInfo(void);
1166 
1167 protected:
getIteration(void) const1168     int getIteration(void) const
1169     {
1170         return m_iteration;
1171     }
getIterationCount(void) const1172     int getIterationCount(void) const
1173     {
1174         return m_iterationCount;
1175     }
1176 
1177 private:
1178     virtual void generateLines(int iteration, std::vector<tcu::Vec4> &outData,
1179                                std::vector<LineSceneSpec::SceneLine> &outLines) = DE_NULL;
1180     virtual bool compareAndVerify(std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage,
1181                                   std::vector<tcu::Vec4> &drawBuffer);
1182 
1183     bool resultHasAlpha(tcu::Surface &result);
1184 
1185     int m_iteration;
1186     const int m_iterationCount;
1187     VkPrimitiveTopology m_primitiveTopology;
1188     const PrimitiveWideness m_primitiveWideness;
1189     const PrimitiveStrictness m_primitiveStrictness;
1190     bool m_allIterationsPassed;
1191     bool m_qualityWarning;
1192     float m_maxLineWidth;
1193     std::vector<float> m_lineWidths;
1194     LineStipple m_stipple;
1195     VkLineRasterizationModeEXT m_lineRasterizationMode;
1196     LineStippleFactorCase m_stippleFactor;
1197     Move<VkImage> m_additionalImage;
1198     de::MovePtr<Allocation> m_additionalImageMemory;
1199     Move<VkImageView> m_additionalImageView;
1200     Move<VkImage> m_additionalResolvedImage;
1201     de::MovePtr<Allocation> m_additionalResolvedImageMemory;
1202     Move<VkImageView> m_additionalResolvedImageView;
1203     Move<VkFramebuffer> m_additionalFrameBuffer;
1204     Move<VkBuffer> m_additionalResultBuffer;
1205     de::MovePtr<Allocation> m_additionalResultBufferMemory;
1206 };
1207 
BaseLineTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,LineStippleFactorCase stippleFactor,const uint32_t additionalRenderSize,const uint32_t renderSize,const float narrowLineWidth)1208 BaseLineTestInstance::BaseLineTestInstance(Context &context, VkPrimitiveTopology primitiveTopology,
1209                                            PrimitiveWideness wideness, PrimitiveStrictness strictness,
1210                                            VkSampleCountFlagBits sampleCount, LineStipple stipple,
1211                                            VkLineRasterizationModeEXT lineRasterizationMode,
1212                                            LineStippleFactorCase stippleFactor, const uint32_t additionalRenderSize,
1213                                            const uint32_t renderSize, const float narrowLineWidth)
1214     : BaseRenderingTestInstance(context, sampleCount, renderSize, VK_FORMAT_R8G8B8A8_UNORM, additionalRenderSize)
1215     , m_iteration(0)
1216     , m_iterationCount(3)
1217     , m_primitiveTopology(primitiveTopology)
1218     , m_primitiveWideness(wideness)
1219     , m_primitiveStrictness(strictness)
1220     , m_allIterationsPassed(true)
1221     , m_qualityWarning(false)
1222     , m_maxLineWidth(1.0f)
1223     , m_stipple(stipple)
1224     , m_lineRasterizationMode(lineRasterizationMode)
1225     , m_stippleFactor(stippleFactor)
1226 {
1227     DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
1228 
1229     if (m_lineRasterizationMode != VK_LINE_RASTERIZATION_MODE_KHR_LAST)
1230     {
1231         if (context.isDeviceFunctionalitySupported("VK_KHR_line_rasterization") ||
1232             context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"))
1233         {
1234             VkPhysicalDeviceLineRasterizationPropertiesKHR lineRasterizationProperties = {
1235                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_KHR, // VkStructureType sType;
1236                 DE_NULL,                                                             // void* pNext;
1237                 0u, // uint32_t lineSubPixelPrecisionBits;
1238             };
1239 
1240             VkPhysicalDeviceProperties2 deviceProperties2;
1241             deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1242             deviceProperties2.pNext = &lineRasterizationProperties;
1243 
1244             context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(),
1245                                                                         &deviceProperties2);
1246 
1247             m_subpixelBits = lineRasterizationProperties.lineSubPixelPrecisionBits;
1248         }
1249     }
1250 
1251     // create line widths
1252     if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
1253     {
1254         m_lineWidths.resize(m_iterationCount, narrowLineWidth);
1255 
1256         // Bump up m_maxLineWidth for conservative rasterization
1257         if (narrowLineWidth > m_maxLineWidth)
1258             m_maxLineWidth = narrowLineWidth;
1259     }
1260     else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
1261     {
1262         const float *range = context.getDeviceProperties().limits.lineWidthRange;
1263 
1264         m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0]
1265                                             << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
1266 
1267         DE_ASSERT(range[1] > 1.0f);
1268 
1269         // set hand picked sizes
1270         m_lineWidths.push_back(5.0f);
1271         m_lineWidths.push_back(10.0f);
1272 
1273         // Do not pick line width with 0.5 fractional value as rounding direction is not defined.
1274         if (deFloatFrac(range[1]) == 0.5f)
1275         {
1276             m_lineWidths.push_back(range[1] - context.getDeviceProperties().limits.lineWidthGranularity);
1277         }
1278         else
1279         {
1280             m_lineWidths.push_back(range[1]);
1281         }
1282 
1283         DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
1284 
1285         m_maxLineWidth = range[1];
1286     }
1287     else
1288         DE_ASSERT(false);
1289 
1290     // Create image, image view and frame buffer for testing at an additional resolution if required.
1291     if (m_additionalRenderSize != 0)
1292     {
1293         const DeviceInterface &vkd      = m_context.getDeviceInterface();
1294         const VkDevice vkDevice         = m_context.getDevice();
1295         const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1296         Allocator &allocator            = m_context.getDefaultAllocator();
1297         DescriptorPoolBuilder descriptorPoolBuilder;
1298         DescriptorSetLayoutBuilder descriptorSetLayoutBuilder;
1299         {
1300             const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1301             const VkImageCreateInfo imageCreateInfo = {
1302                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                  // VkStructureType sType;
1303                 DE_NULL,                                              // const void* pNext;
1304                 0u,                                                   // VkImageCreateFlags flags;
1305                 VK_IMAGE_TYPE_2D,                                     // VkImageType imageType;
1306                 m_imageFormat,                                        // VkFormat format;
1307                 {m_additionalRenderSize, m_additionalRenderSize, 1u}, // VkExtent3D extent;
1308                 1u,                                                   // uint32_t mipLevels;
1309                 1u,                                                   // uint32_t arrayLayers;
1310                 m_sampleCount,                                        // VkSampleCountFlagBits samples;
1311                 VK_IMAGE_TILING_OPTIMAL,                              // VkImageTiling tiling;
1312                 imageUsage,                                           // VkImageUsageFlags usage;
1313                 VK_SHARING_MODE_EXCLUSIVE,                            // VkSharingMode sharingMode;
1314                 1u,                                                   // uint32_t queueFamilyIndexCount;
1315                 &queueFamilyIndex,                                    // const uint32_t* pQueueFamilyIndices;
1316                 VK_IMAGE_LAYOUT_UNDEFINED                             // VkImageLayout initialLayout;
1317             };
1318 
1319             m_additionalImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
1320 
1321             m_additionalImageMemory = allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_additionalImage),
1322                                                          MemoryRequirement::Any);
1323             VK_CHECK(vkd.bindImageMemory(vkDevice, *m_additionalImage, m_additionalImageMemory->getMemory(),
1324                                          m_additionalImageMemory->getOffset()));
1325         }
1326 
1327         // Image View
1328         {
1329             const VkImageViewCreateInfo imageViewCreateInfo = {
1330                 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
1331                 DE_NULL,                                  // const void* pNext;
1332                 0u,                                       // VkImageViewCreateFlags flags;
1333                 *m_additionalImage,                       // VkImage image;
1334                 VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
1335                 m_imageFormat,                            // VkFormat format;
1336                 makeComponentMappingRGBA(),               // VkComponentMapping components;
1337                 {
1338                     VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1339                     0u,                        // uint32_t baseMipLevel;
1340                     1u,                        // uint32_t mipLevels;
1341                     0u,                        // uint32_t baseArrayLayer;
1342                     1u,                        // uint32_t arraySize;
1343                 },                             // VkImageSubresourceRange subresourceRange;
1344             };
1345 
1346             m_additionalImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
1347         }
1348 
1349         if (m_multisampling)
1350         {
1351             {
1352                 const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
1353                                                      VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1354                 const VkImageCreateInfo imageCreateInfo = {
1355                     VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                  // VkStructureType sType;
1356                     DE_NULL,                                              // const void* pNext;
1357                     0u,                                                   // VkImageCreateFlags flags;
1358                     VK_IMAGE_TYPE_2D,                                     // VkImageType imageType;
1359                     m_imageFormat,                                        // VkFormat format;
1360                     {m_additionalRenderSize, m_additionalRenderSize, 1u}, // VkExtent3D extent;
1361                     1u,                                                   // uint32_t mipLevels;
1362                     1u,                                                   // uint32_t arrayLayers;
1363                     VK_SAMPLE_COUNT_1_BIT,                                // VkSampleCountFlagBits samples;
1364                     VK_IMAGE_TILING_OPTIMAL,                              // VkImageTiling tiling;
1365                     imageUsage,                                           // VkImageUsageFlags usage;
1366                     VK_SHARING_MODE_EXCLUSIVE,                            // VkSharingMode sharingMode;
1367                     1u,                                                   // uint32_t queueFamilyIndexCount;
1368                     &queueFamilyIndex,                                    // const uint32_t* pQueueFamilyIndices;
1369                     VK_IMAGE_LAYOUT_UNDEFINED                             // VkImageLayout initialLayout;
1370                 };
1371 
1372                 m_additionalResolvedImage       = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
1373                 m_additionalResolvedImageMemory = allocator.allocate(
1374                     getImageMemoryRequirements(vkd, vkDevice, *m_additionalResolvedImage), MemoryRequirement::Any);
1375                 VK_CHECK(vkd.bindImageMemory(vkDevice, *m_additionalResolvedImage,
1376                                              m_additionalResolvedImageMemory->getMemory(),
1377                                              m_additionalResolvedImageMemory->getOffset()));
1378             }
1379 
1380             // Image view
1381             {
1382                 const VkImageViewCreateInfo imageViewCreateInfo = {
1383                     VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
1384                     DE_NULL,                                  // const void* pNext;
1385                     0u,                                       // VkImageViewCreateFlags flags;
1386                     *m_additionalResolvedImage,               // VkImage image;
1387                     VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
1388                     m_imageFormat,                            // VkFormat format;
1389                     makeComponentMappingRGBA(),               // VkComponentMapping components;
1390                     {
1391                         VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
1392                         0u,                        // uint32_t baseMipLevel;
1393                         1u,                        // uint32_t mipLevels;
1394                         0u,                        // uint32_t baseArrayLayer;
1395                         1u,                        // uint32_t arraySize;
1396                     },                             // VkImageSubresourceRange subresourceRange;
1397                 };
1398                 m_additionalResolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
1399             }
1400         }
1401 
1402         {
1403             const VkImageView attachments[] = {*m_additionalImageView, *m_additionalResolvedImageView};
1404 
1405             const VkFramebufferCreateInfo framebufferCreateInfo = {
1406                 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1407                 DE_NULL,                                   // const void* pNext;
1408                 0u,                                        // VkFramebufferCreateFlags flags;
1409                 *m_renderPass,                             // VkRenderPass renderPass;
1410                 m_multisampling ? 2u : 1u,                 // uint32_t attachmentCount;
1411                 attachments,                               // const VkImageView* pAttachments;
1412                 m_additionalRenderSize,                    // uint32_t width;
1413                 m_additionalRenderSize,                    // uint32_t height;
1414                 1u,                                        // uint32_t layers;
1415             };
1416             m_additionalFrameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL);
1417         }
1418 
1419         // Framebuffer
1420         {
1421             const VkBufferCreateInfo bufferCreateInfo = {
1422                 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1423                 DE_NULL,                              // const void* pNext;
1424                 0u,                                   // VkBufferCreateFlags flags;
1425                 m_additionalResultBufferSize,         // VkDeviceSize size;
1426                 VK_BUFFER_USAGE_TRANSFER_DST_BIT,     // VkBufferUsageFlags usage;
1427                 VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1428                 1u,                                   // uint32_t queueFamilyIndexCount;
1429                 &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
1430             };
1431 
1432             m_additionalResultBuffer       = createBuffer(vkd, vkDevice, &bufferCreateInfo);
1433             m_additionalResultBufferMemory = allocator.allocate(
1434                 getBufferMemoryRequirements(vkd, vkDevice, *m_additionalResultBuffer), MemoryRequirement::HostVisible);
1435 
1436             VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_additionalResultBuffer,
1437                                           m_additionalResultBufferMemory->getMemory(),
1438                                           m_additionalResultBufferMemory->getOffset()));
1439         }
1440     }
1441 }
1442 
resultHasAlpha(tcu::Surface & resultImage)1443 bool BaseLineTestInstance::resultHasAlpha(tcu::Surface &resultImage)
1444 {
1445     bool hasAlpha = false;
1446     for (int y = 0; y < resultImage.getHeight() && !hasAlpha; ++y)
1447         for (int x = 0; x < resultImage.getWidth(); ++x)
1448         {
1449             const tcu::RGBA color = resultImage.getPixel(x, y);
1450             if (color.getAlpha() > 0 && color.getAlpha() < 0xFF)
1451             {
1452                 hasAlpha = true;
1453                 break;
1454             }
1455         }
1456     return hasAlpha;
1457 }
1458 
iterate(void)1459 tcu::TestStatus BaseLineTestInstance::iterate(void)
1460 {
1461     const std::string iterationDescription =
1462         "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
1463     const tcu::ScopedLogSection section(m_context.getTestContext().getLog(), iterationDescription,
1464                                         iterationDescription);
1465     const float lineWidth = getLineWidth();
1466     tcu::Surface resultImage(m_renderSize, m_renderSize);
1467     std::vector<tcu::Vec4> drawBuffer;
1468     std::vector<LineSceneSpec::SceneLine> lines;
1469 
1470     // supported?
1471     if (lineWidth <= m_maxLineWidth)
1472     {
1473         // gen data
1474         generateLines(m_iteration, drawBuffer, lines);
1475 
1476         // draw image
1477         drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
1478 
1479         // compare
1480         {
1481             const bool compareOk = compareAndVerify(lines, resultImage, drawBuffer);
1482 
1483             if (!compareOk)
1484                 m_allIterationsPassed = false;
1485         }
1486     }
1487     else
1488         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth
1489                                             << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
1490 
1491     // result
1492     if (++m_iteration == m_iterationCount)
1493     {
1494         if (!m_allIterationsPassed)
1495             return tcu::TestStatus::fail("Incorrect rasterization");
1496         else if (m_qualityWarning)
1497             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality line rasterization");
1498         else
1499             return tcu::TestStatus::pass("Pass");
1500     }
1501     else
1502         return tcu::TestStatus::incomplete();
1503 }
1504 
compareAndVerify(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)1505 bool BaseLineTestInstance::compareAndVerify(std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage,
1506                                             std::vector<tcu::Vec4> &drawBuffer)
1507 {
1508     const float lineWidth = getLineWidth();
1509     bool result           = true;
1510     tcu::Surface additionalResultImage(m_additionalRenderSize, m_additionalRenderSize);
1511     RasterizationArguments args;
1512     LineSceneSpec scene;
1513     tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
1514     bool strict          = m_primitiveStrictness == PRIMITIVESTRICTNESS_STRICT;
1515 
1516     args.numSamples   = m_multisampling ? 1 : 0;
1517     args.subpixelBits = m_subpixelBits;
1518     args.redBits      = colorBits[0];
1519     args.greenBits    = colorBits[1];
1520     args.blueBits     = colorBits[2];
1521 
1522     scene.lines.swap(lines);
1523     scene.lineWidth      = lineWidth;
1524     scene.stippleEnable  = getLineStippleEnable();
1525     scene.stippleFactor  = getLineStippleEnable() ? lineStippleFactor : 1;
1526     scene.stipplePattern = getLineStippleEnable() ? lineStipplePattern : 0xFFFF;
1527     scene.isStrip        = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
1528     scene.isSmooth       = m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
1529     scene.isRectangular  = m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT ||
1530                           m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
1531 
1532     // Choose verification mode. Smooth lines assume mostly over-rasterization (bloated lines with a falloff).
1533     // Stippled lines lose some precision across segments in a strip, so need a weaker threshold than normal
1534     // lines. For simple cases, check for an exact match (STRICT).
1535     if (scene.isSmooth)
1536         scene.verificationMode = tcu::VERIFICATIONMODE_SMOOTH;
1537     else if (scene.stippleEnable)
1538         scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1539     else
1540         scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
1541 
1542     if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT)
1543     {
1544         // bresenham is "no AA" in GL, so set numSamples to zero.
1545         args.numSamples = 0;
1546         if (!verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog()))
1547             result = false;
1548     }
1549     else
1550     {
1551         if (scene.isSmooth)
1552         {
1553             // Smooth lines get the fractional coverage multiplied into the alpha component,
1554             // so do a quick check to validate that there is at least one pixel in the image
1555             // with a fractional opacity.
1556             bool hasAlpha = resultHasAlpha(resultImage);
1557             if (!hasAlpha)
1558             {
1559                 m_context.getTestContext().getLog()
1560                     << tcu::TestLog::Message << "Missing alpha transparency (failed)." << tcu::TestLog::EndMessage;
1561                 result = false;
1562             }
1563         }
1564 
1565         if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(),
1566                                                  (0 == m_multisampling), strict))
1567         {
1568             // Retry with weaker verification. If it passes, consider it a quality warning.
1569             scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1570             if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(),
1571                                                      false, strict))
1572                 result = false;
1573             else
1574                 m_qualityWarning = true;
1575         }
1576 
1577         if (m_additionalRenderSize != 0)
1578         {
1579             const std::vector<tcu::Vec4> colorData(drawBuffer.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
1580 
1581             if (scene.isSmooth)
1582                 scene.verificationMode = tcu::VERIFICATIONMODE_SMOOTH;
1583             else if (scene.stippleEnable)
1584                 scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1585             else
1586                 scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
1587 
1588             drawPrimitives(additionalResultImage, drawBuffer, colorData, m_primitiveTopology, *m_additionalImage,
1589                            *m_additionalResolvedImage, *m_additionalFrameBuffer, m_additionalRenderSize,
1590                            *m_additionalResultBuffer, *m_additionalResultBufferMemory);
1591 
1592             // Compare
1593             if (!verifyRelaxedLineGroupRasterization(additionalResultImage, scene, args,
1594                                                      m_context.getTestContext().getLog(), (0 == m_multisampling),
1595                                                      strict))
1596             {
1597                 if (strict)
1598                 {
1599                     result = false;
1600                 }
1601                 else
1602                 {
1603                     // Retry with weaker verification. If it passes, consider it a quality warning.
1604                     scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1605                     if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args,
1606                                                              m_context.getTestContext().getLog(),
1607                                                              (0 == m_multisampling), strict))
1608                         result = false;
1609                     else
1610                         m_qualityWarning = true;
1611                 }
1612             }
1613         }
1614     }
1615 
1616     return result;
1617 }
1618 
getLineWidth(void) const1619 float BaseLineTestInstance::getLineWidth(void) const
1620 {
1621     return m_lineWidths[m_iteration];
1622 }
1623 
getOffScreenPoints(void) const1624 std::vector<tcu::Vec4> BaseLineTestInstance::getOffScreenPoints(void) const
1625 {
1626     // These points will be used to draw something with the wrong topology.
1627     // They are offscreen so as not to affect the render result.
1628     return std::vector<tcu::Vec4>{
1629         tcu::Vec4(2.0f, 2.0f, 0.0f, 1.0f),
1630         tcu::Vec4(2.0f, 3.0f, 0.0f, 1.0f),
1631         tcu::Vec4(2.0f, 4.0f, 0.0f, 1.0f),
1632         tcu::Vec4(2.0f, 5.0f, 0.0f, 1.0f),
1633     };
1634 }
1635 
initLineRasterizationStateCreateInfo(void) const1636 VkPipelineRasterizationLineStateCreateInfoEXT BaseLineTestInstance::initLineRasterizationStateCreateInfo(void) const
1637 {
1638     VkPipelineRasterizationLineStateCreateInfoEXT lineRasterizationStateInfo = {
1639         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT, // VkStructureType sType;
1640         DE_NULL,                                                             // const void* pNext;
1641         m_lineRasterizationMode,                     // VkLineRasterizationModeEXT lineRasterizationMode;
1642         getLineStippleEnable() ? VK_TRUE : VK_FALSE, // VkBool32 stippledLineEnable;
1643         1,                                           // uint32_t lineStippleFactor;
1644         0xFFFF,                                      // uint16_t lineStipplePattern;
1645     };
1646 
1647     if (m_stipple == LINESTIPPLE_STATIC)
1648     {
1649         lineRasterizationStateInfo.lineStippleFactor  = lineStippleFactor;
1650         lineRasterizationStateInfo.lineStipplePattern = lineStipplePattern;
1651     }
1652     else if (m_stipple == LINESTIPPLE_DISABLED)
1653     {
1654         if (m_stippleFactor == LineStippleFactorCase::ZERO)
1655             lineRasterizationStateInfo.lineStippleFactor = 0u;
1656         else if (m_stippleFactor == LineStippleFactorCase::LARGE)
1657             lineRasterizationStateInfo.lineStippleFactor = 0xFEDCBA98u;
1658     }
1659 
1660     return lineRasterizationStateInfo;
1661 }
1662 
getLineRasterizationStateCreateInfo(void)1663 const VkPipelineRasterizationLineStateCreateInfoEXT *BaseLineTestInstance::getLineRasterizationStateCreateInfo(void)
1664 {
1665     if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_KHR_LAST)
1666         return DE_NULL;
1667 
1668     if (m_lineRasterizationStateInfo.sType != VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT)
1669         m_lineRasterizationStateInfo = initLineRasterizationStateCreateInfo();
1670 
1671     return &m_lineRasterizationStateInfo;
1672 }
1673 
1674 class PointTestInstance : public BaseRenderingTestInstance
1675 {
1676 public:
1677     PointTestInstance(Context &context, PrimitiveWideness wideness,
1678                       PrimitiveStrictness strictness, // ignored
1679                       VkSampleCountFlagBits sampleCount,
1680                       LineStipple stipple,                              // ignored
1681                       VkLineRasterizationModeEXT lineRasterizationMode, // ignored
1682                       LineStippleFactorCase stippleFactor,              // ignored
1683                       uint32_t additionalRenderSize,                    // ignored
1684                       uint32_t renderSize = RESOLUTION_POT, float pointSizeNarrow = 1.0f);
1685     virtual tcu::TestStatus iterate(void);
1686     virtual float getPointSize(void) const;
1687 
1688 protected:
getIteration(void) const1689     int getIteration(void) const
1690     {
1691         return m_iteration;
1692     }
getIterationCount(void) const1693     int getIterationCount(void) const
1694     {
1695         return m_iterationCount;
1696     }
1697 
1698 private:
1699     virtual void generatePoints(int iteration, std::vector<tcu::Vec4> &outData,
1700                                 std::vector<PointSceneSpec::ScenePoint> &outPoints);
1701     virtual bool compareAndVerify(std::vector<PointSceneSpec::ScenePoint> &points, tcu::Surface &resultImage,
1702                                   std::vector<tcu::Vec4> &drawBuffer);
1703 
1704     int m_iteration;
1705     const int m_iterationCount;
1706     const PrimitiveWideness m_primitiveWideness;
1707     bool m_allIterationsPassed;
1708     float m_maxPointSize;
1709     std::vector<float> m_pointSizes;
1710 };
1711 
PointTestInstance(Context & context,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,LineStippleFactorCase stippleFactor,uint32_t additionalRenderSize,uint32_t renderSize,float pointSizeNarrow)1712 PointTestInstance::PointTestInstance(Context &context, PrimitiveWideness wideness, PrimitiveStrictness strictness,
1713                                      VkSampleCountFlagBits sampleCount, LineStipple stipple,
1714                                      VkLineRasterizationModeEXT lineRasterizationMode,
1715                                      LineStippleFactorCase stippleFactor, uint32_t additionalRenderSize,
1716                                      uint32_t renderSize, float pointSizeNarrow)
1717     : BaseRenderingTestInstance(context, sampleCount, renderSize)
1718     , m_iteration(0)
1719     , m_iterationCount(3)
1720     , m_primitiveWideness(wideness)
1721     , m_allIterationsPassed(true)
1722     , m_maxPointSize(pointSizeNarrow)
1723 {
1724     DE_UNREF(strictness);
1725     DE_UNREF(stipple);
1726     DE_UNREF(lineRasterizationMode);
1727     DE_UNREF(stippleFactor);
1728     DE_UNREF(additionalRenderSize);
1729 
1730     // create point sizes
1731     if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
1732     {
1733         m_pointSizes.resize(m_iterationCount, pointSizeNarrow);
1734     }
1735     else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
1736     {
1737         const float *range = context.getDeviceProperties().limits.pointSizeRange;
1738 
1739         m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ALIASED_POINT_SIZE_RANGE = [" << range[0]
1740                                             << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
1741 
1742         DE_ASSERT(range[1] > 1.0f);
1743 
1744         // set hand picked sizes
1745         m_pointSizes.push_back(10.0f);
1746         m_pointSizes.push_back(25.0f);
1747         m_pointSizes.push_back(range[1]);
1748         DE_ASSERT((int)m_pointSizes.size() == m_iterationCount);
1749 
1750         m_maxPointSize = range[1];
1751     }
1752     else
1753         DE_ASSERT(false);
1754 }
1755 
iterate(void)1756 tcu::TestStatus PointTestInstance::iterate(void)
1757 {
1758     const std::string iterationDescription =
1759         "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
1760     const tcu::ScopedLogSection section(m_context.getTestContext().getLog(), iterationDescription,
1761                                         iterationDescription);
1762     const float pointSize = getPointSize();
1763     tcu::Surface resultImage(m_renderSize, m_renderSize);
1764     std::vector<tcu::Vec4> drawBuffer;
1765     std::vector<PointSceneSpec::ScenePoint> points;
1766 
1767     // supported?
1768     if (pointSize <= m_maxPointSize)
1769     {
1770         // gen data
1771         generatePoints(m_iteration, drawBuffer, points);
1772 
1773         // draw image
1774         drawPrimitives(resultImage, drawBuffer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
1775 
1776         // compare
1777         {
1778             const bool compareOk = compareAndVerify(points, resultImage, drawBuffer);
1779 
1780             if (!compareOk)
1781                 m_allIterationsPassed = false;
1782         }
1783     }
1784     else
1785         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point size " << pointSize
1786                                             << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
1787 
1788     // result
1789     if (++m_iteration == m_iterationCount)
1790     {
1791         if (m_allIterationsPassed)
1792             return tcu::TestStatus::pass("Pass");
1793         else
1794             return tcu::TestStatus::fail("Incorrect rasterization");
1795     }
1796     else
1797         return tcu::TestStatus::incomplete();
1798 }
1799 
compareAndVerify(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)1800 bool PointTestInstance::compareAndVerify(std::vector<PointSceneSpec::ScenePoint> &points, tcu::Surface &resultImage,
1801                                          std::vector<tcu::Vec4> &drawBuffer)
1802 {
1803     RasterizationArguments args;
1804     PointSceneSpec scene;
1805 
1806     tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
1807 
1808     args.numSamples   = m_multisampling ? 1 : 0;
1809     args.subpixelBits = m_subpixelBits;
1810     args.redBits      = colorBits[0];
1811     args.greenBits    = colorBits[1];
1812     args.blueBits     = colorBits[2];
1813 
1814     scene.points.swap(points);
1815 
1816     DE_UNREF(drawBuffer);
1817 
1818     return verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
1819 }
1820 
getPointSize(void) const1821 float PointTestInstance::getPointSize(void) const
1822 {
1823     return m_pointSizes[m_iteration];
1824 }
1825 
generatePoints(int iteration,std::vector<tcu::Vec4> & outData,std::vector<PointSceneSpec::ScenePoint> & outPoints)1826 void PointTestInstance::generatePoints(int iteration, std::vector<tcu::Vec4> &outData,
1827                                        std::vector<PointSceneSpec::ScenePoint> &outPoints)
1828 {
1829     outData.resize(6);
1830 
1831     switch (iteration)
1832     {
1833     case 0:
1834         // \note: these values are chosen arbitrarily
1835         outData[0] = tcu::Vec4(0.2f, 0.8f, 0.0f, 1.0f);
1836         outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
1837         outData[2] = tcu::Vec4(0.5f, 0.3f, 0.0f, 1.0f);
1838         outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
1839         outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f);
1840         outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f);
1841         break;
1842 
1843     case 1:
1844         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1845         outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
1846         outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
1847         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
1848         outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
1849         outData[5] = tcu::Vec4(0.4f, 1.2f, 0.0f, 1.0f);
1850         break;
1851 
1852     case 2:
1853         outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
1854         outData[1] = tcu::Vec4(0.3f, -0.9f, 0.0f, 1.0f);
1855         outData[2] = tcu::Vec4(-0.4f, -0.1f, 0.0f, 1.0f);
1856         outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f);
1857         outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
1858         outData[5] = tcu::Vec4(-0.4f, 0.4f, 0.0f, 1.0f);
1859         break;
1860     }
1861 
1862     outPoints.resize(outData.size());
1863     for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
1864     {
1865         outPoints[pointNdx].position  = outData[pointNdx];
1866         outPoints[pointNdx].pointSize = getPointSize();
1867     }
1868 
1869     // log
1870     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size()
1871                                         << " point(s): (point size = " << getPointSize() << ")"
1872                                         << tcu::TestLog::EndMessage;
1873     for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
1874         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point " << (pointNdx + 1) << ":\t"
1875                                             << outPoints[pointNdx].position << tcu::TestLog::EndMessage;
1876 }
1877 
1878 template <typename ConcreteTestInstance>
1879 class PointSizeTestCase : public BaseRenderingTestCase
1880 {
1881 public:
PointSizeTestCase(tcu::TestContext & context,std::string & name,uint32_t renderSize,float pointSize,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)1882     PointSizeTestCase(tcu::TestContext &context, std::string &name, uint32_t renderSize, float pointSize,
1883                       VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
1884         : BaseRenderingTestCase(context, name, sampleCount)
1885         , m_pointSize(pointSize)
1886         , m_renderSize(renderSize)
1887     {
1888     }
1889 
createInstance(Context & context) const1890     virtual TestInstance *createInstance(Context &context) const
1891     {
1892         VkPhysicalDeviceProperties properties(context.getDeviceProperties());
1893 
1894         if (m_renderSize > properties.limits.maxViewportDimensions[0] ||
1895             m_renderSize > properties.limits.maxViewportDimensions[1])
1896             TCU_THROW(NotSupportedError, "Viewport dimensions not supported");
1897 
1898         if (m_renderSize > properties.limits.maxFramebufferWidth ||
1899             m_renderSize > properties.limits.maxFramebufferHeight)
1900             TCU_THROW(NotSupportedError, "Framebuffer width/height not supported");
1901 
1902         return new ConcreteTestInstance(context, m_renderSize, m_pointSize);
1903     }
1904 
checkSupport(Context & context) const1905     virtual void checkSupport(Context &context) const
1906     {
1907         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
1908     }
1909 
1910 protected:
1911     const float m_pointSize;
1912     const uint32_t m_renderSize;
1913 };
1914 
1915 class PointSizeTestInstance : public BaseRenderingTestInstance
1916 {
1917 public:
1918     PointSizeTestInstance(Context &context, uint32_t renderSize, float pointSize);
1919     virtual tcu::TestStatus iterate(void);
1920     virtual float getPointSize(void) const;
1921 
1922 protected:
1923     void generatePointData(PointSceneSpec::ScenePoint &outPoint);
1924     virtual Move<VkPipeline> createPipeline(void);
1925     virtual void bindDrawData(VkCommandBuffer commandBuffer, VkPipeline graphicsPipeline, VkBuffer vertexBuffer);
1926     void drawPoint(tcu::PixelBufferAccess &result, tcu::PointSceneSpec::ScenePoint &point);
1927     bool verifyPoint(tcu::TestLog &log, tcu::PixelBufferAccess &access, float pointSize);
1928     bool isPointSizeClamped(float pointSize, float maxPointSizeLimit);
1929 
1930     const float m_pointSize;
1931     const float m_maxPointSize;
1932     const uint32_t m_renderSize;
1933     const VkFormat m_format;
1934 };
1935 
PointSizeTestInstance(Context & context,uint32_t renderSize,float pointSize)1936 PointSizeTestInstance::PointSizeTestInstance(Context &context, uint32_t renderSize, float pointSize)
1937     : BaseRenderingTestInstance(context, vk::VK_SAMPLE_COUNT_1_BIT, renderSize, VK_FORMAT_R8_UNORM)
1938     , m_pointSize(pointSize)
1939     , m_maxPointSize(context.getDeviceProperties().limits.pointSizeRange[1])
1940     , m_renderSize(renderSize)
1941     , m_format(
1942           VK_FORMAT_R8_UNORM) // Use single-channel format to minimize memory allocation when using large render targets
1943 {
1944 }
1945 
iterate(void)1946 tcu::TestStatus PointSizeTestInstance::iterate(void)
1947 {
1948     tcu::TextureLevel resultBuffer(mapVkFormat(m_format), m_renderSize, m_renderSize);
1949     tcu::PixelBufferAccess access(resultBuffer.getAccess());
1950     PointSceneSpec::ScenePoint point;
1951 
1952     // Generate data
1953     generatePointData(point);
1954 
1955     // Draw
1956     drawPoint(access, point);
1957 
1958     // Compare
1959 #ifdef CTS_USES_VULKANSC
1960     if (m_context.getTestContext().getCommandLine().isSubProcess())
1961 #endif // CTS_USES_VULKANSC
1962     {
1963         // pointSize must either be specified pointSize or clamped to device limit pointSizeRange[1]
1964         const float pointSize(deFloatMin(m_pointSize, m_maxPointSize));
1965         const bool compareOk(verifyPoint(m_context.getTestContext().getLog(), access, pointSize));
1966 
1967         // Result
1968         if (compareOk)
1969             return isPointSizeClamped(pointSize, m_maxPointSize) ?
1970                        tcu::TestStatus::pass("Pass, pointSize clamped to pointSizeRange[1]") :
1971                        tcu::TestStatus::pass("Pass");
1972         else
1973             return tcu::TestStatus::fail("Incorrect rasterization");
1974     }
1975     return tcu::TestStatus::pass("Pass");
1976 }
1977 
getPointSize(void) const1978 float PointSizeTestInstance::getPointSize(void) const
1979 {
1980     return m_pointSize;
1981 }
1982 
generatePointData(PointSceneSpec::ScenePoint & outPoint)1983 void PointSizeTestInstance::generatePointData(PointSceneSpec::ScenePoint &outPoint)
1984 {
1985     const tcu::PointSceneSpec::ScenePoint point = {
1986         tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f), // position
1987         tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f), // color
1988         m_pointSize                        // pointSize
1989     };
1990 
1991     outPoint = point;
1992 
1993     // log
1994     {
1995         tcu::TestLog &log = m_context.getTestContext().getLog();
1996 
1997         log << tcu::TestLog::Message << "Point position: " << de::toString(point.position) << tcu::TestLog::EndMessage;
1998         log << tcu::TestLog::Message << "Point color: " << de::toString(point.color) << tcu::TestLog::EndMessage;
1999         log << tcu::TestLog::Message << "Point size: " << de::toString(point.pointSize) << tcu::TestLog::EndMessage;
2000         log << tcu::TestLog::Message << "Render size: " << de::toString(m_renderSize) << tcu::TestLog::EndMessage;
2001         log << tcu::TestLog::Message << "Format: " << de::toString(m_format) << tcu::TestLog::EndMessage;
2002     }
2003 }
2004 
createPipeline(void)2005 Move<VkPipeline> PointSizeTestInstance::createPipeline(void)
2006 {
2007     const DeviceInterface &vkd(m_context.getDeviceInterface());
2008     const VkDevice vkDevice(m_context.getDevice());
2009     const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(m_renderSize)));
2010     const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(m_renderSize)));
2011 
2012     const VkVertexInputBindingDescription vertexInputBindingDescription = {
2013         0u,                                // uint32_t binding;
2014         (uint32_t)(2 * sizeof(tcu::Vec4)), // uint32_t strideInBytes;
2015         VK_VERTEX_INPUT_RATE_VERTEX        // VkVertexInputStepRate stepRate;
2016     };
2017 
2018     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
2019         {
2020             0u,                            // uint32_t location;
2021             0u,                            // uint32_t binding;
2022             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
2023             0u                             // uint32_t offsetInBytes;
2024         },
2025         {
2026             1u,                            // uint32_t location;
2027             0u,                            // uint32_t binding;
2028             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
2029             (uint32_t)sizeof(tcu::Vec4)    // uint32_t offsetInBytes;
2030         }};
2031 
2032     const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
2033         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
2034         DE_NULL,                                                   // const void* pNext;
2035         0,                                                         // VkPipelineVertexInputStateCreateFlags flags;
2036         1u,                                                        // uint32_t bindingCount;
2037         &vertexInputBindingDescription,  // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2038         2u,                              // uint32_t attributeCount;
2039         vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
2040     };
2041 
2042     return makeGraphicsPipeline(
2043         vkd,                     // const DeviceInterface&                             vk
2044         vkDevice,                // const VkDevice                                     device
2045         *m_pipelineLayout,       // const VkPipelineLayout                             pipelineLayout
2046         *m_vertexShaderModule,   // const VkShaderModule                                 vertexShaderModule
2047         DE_NULL,                 // const VkShaderModule                                 tessellationControlShaderModule
2048         DE_NULL,                 // const VkShaderModule                                 tessellationEvalShaderModule
2049         DE_NULL,                 // const VkShaderModule                                 geometryShaderModule
2050         *m_fragmentShaderModule, // const VkShaderModule                                 fragmentShaderModule
2051         *m_renderPass,           // const VkRenderPass                                 renderPass
2052         viewports,               // const std::vector<VkViewport>&                     viewports
2053         scissors,                // const std::vector<VkRect2D>&                         scissors
2054         VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // const VkPrimitiveTopology                         topology
2055         0u,                               // const uint32_t                                     subpass
2056         0u,                               // const uint32_t                                     patchControlPoints
2057         &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo*         vertexInputStateCreateInfo
2058         getRasterizationStateCreateInfo(), // const VkPipelineRasterizationStateCreateInfo*     rasterizationStateCreateInfo
2059         DE_NULL, // const VkPipelineMultisampleStateCreateInfo*         multisampleStateCreateInfo
2060         DE_NULL, // const VkPipelineDepthStencilStateCreateInfo*         depthStencilStateCreateInfo,
2061         getColorBlendStateCreateInfo()); // const VkPipelineColorBlendStateCreateInfo*         colorBlendStateCreateInfo
2062 }
2063 
bindDrawData(VkCommandBuffer commandBuffer,VkPipeline graphicsPipeline,VkBuffer vertexBuffer)2064 void PointSizeTestInstance::bindDrawData(VkCommandBuffer commandBuffer, VkPipeline graphicsPipeline,
2065                                          VkBuffer vertexBuffer)
2066 {
2067     const DeviceInterface &vkd(m_context.getDeviceInterface());
2068     const VkDevice vkDevice(m_context.getDevice());
2069     const VkDeviceSize vertexBufferOffset = 0;
2070 
2071     vkd.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
2072     vkd.cmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1,
2073                               &m_descriptorSet.get(), 0u, DE_NULL);
2074     vkd.cmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
2075 
2076     // Set Point Size
2077     {
2078         float pointSize = getPointSize();
2079 
2080         deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
2081         flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
2082     }
2083 }
2084 
drawPoint(tcu::PixelBufferAccess & result,PointSceneSpec::ScenePoint & point)2085 void PointSizeTestInstance::drawPoint(tcu::PixelBufferAccess &result, PointSceneSpec::ScenePoint &point)
2086 {
2087     const tcu::Vec4 positionData(point.position);
2088     const tcu::Vec4 colorData(point.color);
2089 
2090     const DeviceInterface &vkd(m_context.getDeviceInterface());
2091     const VkDevice vkDevice(m_context.getDevice());
2092     const VkQueue queue(m_context.getUniversalQueue());
2093     const uint32_t queueFamilyIndex(m_context.getUniversalQueueFamilyIndex());
2094     const size_t attributeBatchSize(sizeof(tcu::Vec4));
2095     Allocator &allocator(m_context.getDefaultAllocator());
2096 
2097     Move<VkCommandBuffer> commandBuffer;
2098     Move<VkPipeline> graphicsPipeline;
2099     Move<VkBuffer> vertexBuffer;
2100     de::MovePtr<Allocation> vertexBufferMemory;
2101 
2102     // Create Graphics Pipeline
2103     graphicsPipeline = createPipeline();
2104 
2105     // Create Vertex Buffer
2106     {
2107         const VkBufferCreateInfo vertexBufferParams = {
2108             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
2109             DE_NULL,                              // const void* pNext;
2110             0u,                                   // VkBufferCreateFlags flags;
2111             attributeBatchSize * 2,               // VkDeviceSize size;
2112             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
2113             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
2114             1u,                                   // uint32_t queueFamilyCount;
2115             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
2116         };
2117 
2118         vertexBuffer       = createBuffer(vkd, vkDevice, &vertexBufferParams);
2119         vertexBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer),
2120                                                 MemoryRequirement::HostVisible);
2121 
2122         VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(),
2123                                       vertexBufferMemory->getOffset()));
2124 
2125         // Load vertices into vertex buffer
2126         deMemcpy(vertexBufferMemory->getHostPtr(), &positionData, attributeBatchSize);
2127         deMemcpy(reinterpret_cast<uint8_t *>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, &colorData,
2128                  attributeBatchSize);
2129         flushAlloc(vkd, vkDevice, *vertexBufferMemory);
2130     }
2131 
2132     // Create Command Buffer
2133     commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2134 
2135     // Begin Command Buffer
2136     beginCommandBuffer(vkd, *commandBuffer);
2137 
2138     addImageTransitionBarrier(*commandBuffer, *m_image,
2139                               VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,         // VkPipelineStageFlags        srcStageMask
2140                               VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,        // VkPipelineStageFlags        dstStageMask
2141                               0,                                         // VkAccessFlags            srcAccessMask
2142                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,      // VkAccessFlags            dstAccessMask
2143                               VK_IMAGE_LAYOUT_UNDEFINED,                 // VkImageLayout oldLayout;
2144                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
2145 
2146     // Begin Render Pass
2147     beginRenderPass(vkd, *commandBuffer, *m_renderPass, *m_frameBuffer,
2148                     vk::makeRect2D(0, 0, m_renderSize, m_renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
2149 
2150     bindDrawData(commandBuffer.get(), graphicsPipeline.get(), vertexBuffer.get());
2151     vkd.cmdDraw(*commandBuffer, 1, 1, 0, 0);
2152     endRenderPass(vkd, *commandBuffer);
2153 
2154     // Copy Image
2155     copyImageToBuffer(vkd, *commandBuffer, *m_image, *m_resultBuffer, tcu::IVec2(m_renderSize, m_renderSize));
2156 
2157     endCommandBuffer(vkd, *commandBuffer);
2158 
2159     // Submit
2160     submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
2161 
2162     invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
2163 #ifdef CTS_USES_VULKANSC
2164     if (m_context.getTestContext().getCommandLine().isSubProcess())
2165 #endif // CTS_USES_VULKANSC
2166     {
2167         tcu::copy(result, tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1),
2168                                                       m_resultBufferMemory->getHostPtr()));
2169     }
2170 }
2171 
verifyPoint(tcu::TestLog & log,tcu::PixelBufferAccess & image,float pointSize)2172 bool PointSizeTestInstance::verifyPoint(tcu::TestLog &log, tcu::PixelBufferAccess &image, float pointSize)
2173 {
2174     const float expectedPointColor(1.0f);
2175     const float expectedBackgroundColor(0.0f);
2176     uint32_t pointWidth(0u);
2177     uint32_t pointHeight(0u);
2178     bool incorrectlyColoredPixelsFound(false);
2179     bool isOk(true);
2180 
2181     // Verify rasterized point width and color
2182     for (size_t x = 0; x < (uint32_t)image.getWidth(); x++)
2183     {
2184         float pixelColor = image.getPixel((uint32_t)x, image.getHeight() / 2).x();
2185 
2186         if (pixelColor == expectedPointColor)
2187             pointWidth++;
2188 
2189         if ((pixelColor != expectedPointColor) && (pixelColor != expectedBackgroundColor))
2190             incorrectlyColoredPixelsFound = true;
2191     }
2192 
2193     // Verify rasterized point height and color
2194     for (size_t y = 0; y < (uint32_t)image.getHeight(); y++)
2195     {
2196         float pixelColor = image.getPixel((uint32_t)y, image.getWidth() / 2).x();
2197 
2198         if (pixelColor == expectedPointColor)
2199             pointHeight++;
2200 
2201         if ((pixelColor != expectedPointColor) && (pixelColor != expectedBackgroundColor))
2202             incorrectlyColoredPixelsFound = true;
2203     }
2204 
2205     // Compare amount of rasterized point pixels to expected pointSize.
2206     if ((pointWidth != (uint32_t)deRoundFloatToInt32(pointSize)) ||
2207         (pointHeight != (uint32_t)deRoundFloatToInt32(pointSize)))
2208     {
2209         log << tcu::TestLog::Message << "Incorrect point size. Expected pointSize: " << de::toString(pointSize)
2210             << ". Rasterized point width: " << pointWidth << " pixels, height: " << pointHeight << " pixels."
2211             << tcu::TestLog::EndMessage;
2212 
2213         isOk = false;
2214     }
2215 
2216     // Check incorrectly colored pixels
2217     if (incorrectlyColoredPixelsFound)
2218     {
2219         log << tcu::TestLog::Message << "Incorrectly colored pixels found." << tcu::TestLog::EndMessage;
2220         isOk = false;
2221     }
2222 
2223     return isOk;
2224 }
2225 
isPointSizeClamped(float pointSize,float maxPointSizeLimit)2226 bool PointSizeTestInstance::isPointSizeClamped(float pointSize, float maxPointSizeLimit)
2227 {
2228     return (pointSize == maxPointSizeLimit);
2229 }
2230 
2231 class PointDefaultSizeTestInstance : public PointSizeTestInstance
2232 {
2233 public:
2234     PointDefaultSizeTestInstance(Context &context, uint32_t renderSize, VkShaderStageFlags stage);
2235 
2236 protected:
2237     Move<VkPipeline> createPipeline(void) override;
2238     void bindDrawData(VkCommandBuffer commandBuffer, VkPipeline graphicsPipeline, VkBuffer vertexBuffer) override;
2239 
2240     const VkShaderStageFlags m_tessellationBits =
2241         VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2242     const VkShaderStageFlags m_geometryBits = VK_SHADER_STAGE_GEOMETRY_BIT;
2243 
2244     Move<VkShaderModule> m_tessellationControlShaderModule;
2245     Move<VkShaderModule> m_tessellationEvaluationShaderModule;
2246     Move<VkShaderModule> m_geometryShaderModule;
2247 
2248     bool m_hasTessellationStage;
2249     bool m_hasGeometryStage;
2250 };
2251 
PointDefaultSizeTestInstance(Context & context,uint32_t renderSize,VkShaderStageFlags stage)2252 PointDefaultSizeTestInstance::PointDefaultSizeTestInstance(Context &context, uint32_t renderSize,
2253                                                            VkShaderStageFlags stage)
2254     : PointSizeTestInstance(context, renderSize, 1.0f)
2255     , m_hasTessellationStage(stage & m_tessellationBits)
2256     , m_hasGeometryStage(stage & m_geometryBits)
2257 {
2258     const DeviceInterface &vkd = m_context.getDeviceInterface();
2259     const VkDevice vkDevice    = m_context.getDevice();
2260 
2261     if (m_hasTessellationStage)
2262     {
2263         m_tessellationControlShaderModule =
2264             createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("tessellation_control_shader"), 0);
2265         m_tessellationEvaluationShaderModule =
2266             createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("tessellation_evaluation_shader"), 0);
2267     }
2268 
2269     if (m_hasGeometryStage)
2270     {
2271         m_geometryShaderModule =
2272             createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("geometry_shader"), 0);
2273     }
2274 }
2275 
createPipeline(void)2276 Move<VkPipeline> PointDefaultSizeTestInstance::createPipeline(void)
2277 {
2278     const DeviceInterface &vkd(m_context.getDeviceInterface());
2279     const VkDevice vkDevice(m_context.getDevice());
2280     const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(m_renderSize)));
2281     const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(m_renderSize)));
2282     const VkPrimitiveTopology topology =
2283         m_hasTessellationStage ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
2284     const uint32_t patchCount = m_hasTessellationStage ? 1u : 0u;
2285 
2286     const VkVertexInputBindingDescription vertexInputBindingDescription = {
2287         0u,                                // uint32_t binding;
2288         (uint32_t)(2 * sizeof(tcu::Vec4)), // uint32_t strideInBytes;
2289         VK_VERTEX_INPUT_RATE_VERTEX        // VkVertexInputStepRate stepRate;
2290     };
2291 
2292     const VkVertexInputAttributeDescription vertexInputAttributeDescriptions = {
2293         0u,                            // uint32_t location;
2294         0u,                            // uint32_t binding;
2295         VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
2296         0u                             // uint32_t offsetInBytes;
2297     };
2298 
2299     const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
2300         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
2301         DE_NULL,                                                   // const void* pNext;
2302         0,                                                         // VkPipelineVertexInputStateCreateFlags flags;
2303         1u,                                                        // uint32_t bindingCount;
2304         &vertexInputBindingDescription,   // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2305         1u,                               // uint32_t attributeCount;
2306         &vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
2307     };
2308 
2309     return makeGraphicsPipeline(
2310         vkd,                                // const DeviceInterface&                             vk
2311         vkDevice,                           // const VkDevice                                     device
2312         *m_pipelineLayout,                  // const VkPipelineLayout                             pipelineLayout
2313         *m_vertexShaderModule,              // const VkShaderModule                                 vertexShaderModule
2314         *m_tessellationControlShaderModule, // const VkShaderModule                                 tessellationControlShaderModule
2315         *m_tessellationEvaluationShaderModule, // const VkShaderModule                                 tessellationEvalShaderModule
2316         *m_geometryShaderModule, // const VkShaderModule                                 geometryShaderModule
2317         *m_fragmentShaderModule, // const VkShaderModule                                 fragmentShaderModule
2318         *m_renderPass,           // const VkRenderPass                                 renderPass
2319         viewports,               // const std::vector<VkViewport>&                     viewports
2320         scissors,                // const std::vector<VkRect2D>&                         scissors
2321         topology,                // const VkPrimitiveTopology                         topology
2322         0u,                      // const uint32_t                                     subpass
2323         patchCount,              // const uint32_t                                     patchControlPoints
2324         &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo*         vertexInputStateCreateInfo
2325         getRasterizationStateCreateInfo(), // const VkPipelineRasterizationStateCreateInfo*     rasterizationStateCreateInfo
2326         DE_NULL, // const VkPipelineMultisampleStateCreateInfo*         multisampleStateCreateInfo
2327         DE_NULL, // const VkPipelineDepthStencilStateCreateInfo*         depthStencilStateCreateInfo,
2328         getColorBlendStateCreateInfo()); // const VkPipelineColorBlendStateCreateInfo*         colorBlendStateCreateInfo
2329 }
2330 
bindDrawData(VkCommandBuffer commandBuffer,VkPipeline graphicsPipeline,VkBuffer vertexBuffer)2331 void PointDefaultSizeTestInstance::bindDrawData(VkCommandBuffer commandBuffer, VkPipeline graphicsPipeline,
2332                                                 VkBuffer vertexBuffer)
2333 {
2334     const DeviceInterface &vkd(m_context.getDeviceInterface());
2335     const VkDeviceSize vertexBufferOffset = 0;
2336 
2337     vkd.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
2338     vkd.cmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
2339 }
2340 
2341 class PointDefaultSizeTestCase : public BaseRenderingTestCase
2342 {
2343 public:
2344     PointDefaultSizeTestCase(tcu::TestContext &context, std::string name, uint32_t renderSize, VkShaderStageFlags stage,
2345                              VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT);
2346 
2347     void initPrograms(vk::SourceCollections &programCollection) const override;
2348     TestInstance *createInstance(Context &context) const override;
2349     void checkSupport(Context &context) const override;
2350 
2351 protected:
2352     const uint32_t m_renderSize;
2353     const VkShaderStageFlags m_stage;
2354 };
2355 
PointDefaultSizeTestCase(tcu::TestContext & context,std::string name,uint32_t renderSize,VkShaderStageFlags stage,VkSampleCountFlagBits sampleCount)2356 PointDefaultSizeTestCase::PointDefaultSizeTestCase(tcu::TestContext &context, std::string name, uint32_t renderSize,
2357                                                    VkShaderStageFlags stage, VkSampleCountFlagBits sampleCount)
2358     : BaseRenderingTestCase(context, name, sampleCount)
2359     , m_renderSize(renderSize)
2360     , m_stage(stage)
2361 {
2362 }
2363 
initPrograms(vk::SourceCollections & programCollection) const2364 void PointDefaultSizeTestCase::initPrograms(vk::SourceCollections &programCollection) const
2365 {
2366     std::ostringstream vert;
2367     std::ostringstream tesc;
2368     std::ostringstream tese;
2369     std::ostringstream geom;
2370     std::ostringstream frag;
2371 
2372     vert << "#version 450\n"
2373          << "layout(location = 0) in highp vec4 a_position;\n"
2374          << "void main()"
2375          << "{\n"
2376          << "    gl_Position = a_position;\n"
2377          << "}\n";
2378 
2379     tesc << "#version 450\n"
2380          << "layout(vertices = 1) out;\n"
2381          << "void main()\n"
2382          << "{\n"
2383          << "    gl_TessLevelOuter[0] = 1.0;\n"
2384          << "    gl_TessLevelOuter[1] = 1.0;\n"
2385          << "    gl_TessLevelOuter[2] = 1.0;\n"
2386          << "    gl_TessLevelOuter[3] = 1.0;\n"
2387          << "    gl_TessLevelInner[0] = 1.0;\n"
2388          << "    gl_TessLevelInner[1] = 1.0;\n"
2389          << "\n"
2390          << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2391          << "}\n";
2392 
2393     tese << "#version 450\n"
2394          << "layout(isolines, point_mode) in;\n"
2395          << "void main()\n"
2396          << "{\n"
2397          << "    gl_Position = gl_in[0].gl_Position;\n"
2398          << "}\n";
2399 
2400     geom << "#version 450\n"
2401          << "layout(points) in;\n"
2402          << "layout(points, max_vertices=1) out;\n"
2403          << "void main()\n"
2404          << "{\n"
2405          << "    gl_Position = gl_in[0].gl_Position;\n"
2406          << "    EmitVertex();\n"
2407          << "    EndPrimitive();\n"
2408          << "}\n";
2409 
2410     frag << "#version 450\n"
2411          << "layout(location = 0) out highp vec4 fragColor;\n"
2412          << "void main()"
2413          << "{\n"
2414          << "    fragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n"
2415          << "}\n";
2416 
2417     programCollection.glslSources.add("vertext_shader") << glu::VertexSource(vert.str());
2418     programCollection.glslSources.add("tessellation_control_shader") << glu::TessellationControlSource(tesc.str());
2419     programCollection.glslSources.add("tessellation_evaluation_shader")
2420         << glu::TessellationEvaluationSource(tese.str());
2421     programCollection.glslSources.add("geometry_shader") << glu::GeometrySource(geom.str());
2422     programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(frag.str());
2423 }
2424 
createInstance(Context & context) const2425 TestInstance *PointDefaultSizeTestCase::createInstance(Context &context) const
2426 {
2427     VkPhysicalDeviceProperties properties(context.getDeviceProperties());
2428 
2429     if (m_renderSize > properties.limits.maxViewportDimensions[0] ||
2430         m_renderSize > properties.limits.maxViewportDimensions[1])
2431         TCU_THROW(NotSupportedError, "Viewport dimensions not supported");
2432 
2433     if (m_renderSize > properties.limits.maxFramebufferWidth || m_renderSize > properties.limits.maxFramebufferHeight)
2434         TCU_THROW(NotSupportedError, "Framebuffer width/height not supported");
2435 
2436     return new PointDefaultSizeTestInstance(context, m_renderSize, m_stage);
2437 }
2438 
checkSupport(Context & context) const2439 void PointDefaultSizeTestCase::checkSupport(Context &context) const
2440 {
2441     const VkShaderStageFlags tessellationBits =
2442         VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2443     const VkShaderStageFlags geometryBits = VK_SHADER_STAGE_GEOMETRY_BIT;
2444 
2445     if (m_stage & tessellationBits)
2446     {
2447         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE);
2448         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
2449     }
2450 
2451     if (m_stage & geometryBits)
2452     {
2453         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE);
2454         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
2455     }
2456 
2457     context.requireDeviceFunctionality("VK_KHR_maintenance5");
2458 }
2459 
2460 template <typename ConcreteTestInstance>
2461 class BaseTestCase : public BaseRenderingTestCase
2462 {
2463 public:
BaseTestCase(tcu::TestContext & context,const std::string & name,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)2464     BaseTestCase(tcu::TestContext &context, const std::string &name,
2465                  VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
2466         : BaseRenderingTestCase(context, name, sampleCount)
2467     {
2468     }
2469 
createInstance(Context & context) const2470     virtual TestInstance *createInstance(Context &context) const
2471     {
2472         return new ConcreteTestInstance(context, m_sampleCount);
2473     }
2474 };
2475 
2476 class TrianglesTestInstance : public BaseTriangleTestInstance
2477 {
2478 public:
TrianglesTestInstance(Context & context,VkSampleCountFlagBits sampleCount)2479     TrianglesTestInstance(Context &context, VkSampleCountFlagBits sampleCount)
2480         : BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, sampleCount)
2481     {
2482     }
2483 
2484     void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2485                            std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
2486 };
2487 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2488 void TrianglesTestInstance::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2489                                               std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
2490 {
2491     outData.resize(6);
2492 
2493     switch (iteration)
2494     {
2495     case 0:
2496         // \note: these values are chosen arbitrarily
2497         outData[0] = tcu::Vec4(0.2f, 0.8f, 0.0f, 1.0f);
2498         outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
2499         outData[2] = tcu::Vec4(0.5f, 0.3f, 0.0f, 1.0f);
2500         outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
2501         outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
2502         outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f);
2503         break;
2504 
2505     case 1:
2506         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
2507         outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
2508         outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
2509         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
2510         outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
2511         outData[5] = tcu::Vec4(0.4f, 1.2f, 0.0f, 1.0f);
2512         break;
2513 
2514     case 2:
2515         outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
2516         outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
2517         outData[2] = tcu::Vec4(-1.1f, -0.1f, 0.0f, 1.0f);
2518         outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f);
2519         outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
2520         outData[5] = tcu::Vec4(-0.4f, 0.4f, 0.0f, 1.0f);
2521         break;
2522     }
2523 
2524     outTriangles.resize(2);
2525     outTriangles[0].positions[0]  = outData[0];
2526     outTriangles[0].sharedEdge[0] = false;
2527     outTriangles[0].positions[1]  = outData[1];
2528     outTriangles[0].sharedEdge[1] = false;
2529     outTriangles[0].positions[2]  = outData[2];
2530     outTriangles[0].sharedEdge[2] = false;
2531 
2532     outTriangles[1].positions[0]  = outData[3];
2533     outTriangles[1].sharedEdge[0] = false;
2534     outTriangles[1].positions[1]  = outData[4];
2535     outTriangles[1].sharedEdge[1] = false;
2536     outTriangles[1].positions[2]  = outData[5];
2537     outTriangles[1].sharedEdge[2] = false;
2538 
2539     // log
2540     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size()
2541                                         << " triangle(s):" << tcu::TestLog::EndMessage;
2542     for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx)
2543     {
2544         m_context.getTestContext().getLog()
2545             << tcu::TestLog::Message << "Triangle " << (triangleNdx + 1) << ":"
2546             << "\n\t" << outTriangles[triangleNdx].positions[0] << "\n\t" << outTriangles[triangleNdx].positions[1]
2547             << "\n\t" << outTriangles[triangleNdx].positions[2] << tcu::TestLog::EndMessage;
2548     }
2549 }
2550 
2551 class TriangleStripTestInstance : public BaseTriangleTestInstance
2552 {
2553 public:
TriangleStripTestInstance(Context & context,VkSampleCountFlagBits sampleCount)2554     TriangleStripTestInstance(Context &context, VkSampleCountFlagBits sampleCount)
2555         : BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, sampleCount)
2556     {
2557     }
2558 
2559     void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2560                            std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
2561 };
2562 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2563 void TriangleStripTestInstance::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2564                                                   std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
2565 {
2566     outData.resize(5);
2567 
2568     switch (iteration)
2569     {
2570     case 0:
2571         // \note: these values are chosen arbitrarily
2572         outData[0] = tcu::Vec4(-0.504f, 0.8f, 0.0f, 1.0f);
2573         outData[1] = tcu::Vec4(-0.2f, -0.2f, 0.0f, 1.0f);
2574         outData[2] = tcu::Vec4(-0.2f, 0.199f, 0.0f, 1.0f);
2575         outData[3] = tcu::Vec4(0.5f, 0.201f, 0.0f, 1.0f);
2576         outData[4] = tcu::Vec4(1.5f, 0.4f, 0.0f, 1.0f);
2577         break;
2578 
2579     case 1:
2580         outData[0] = tcu::Vec4(-0.499f, 0.129f, 0.0f, 1.0f);
2581         outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
2582         outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
2583         outData[3] = tcu::Vec4(0.11f, -0.31f, 0.0f, 1.0f);
2584         outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
2585         break;
2586 
2587     case 2:
2588         outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
2589         outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
2590         outData[2] = tcu::Vec4(-0.87f, -0.1f, 0.0f, 1.0f);
2591         outData[3] = tcu::Vec4(-0.11f, 0.19f, 0.0f, 1.0f);
2592         outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
2593         break;
2594     }
2595 
2596     outTriangles.resize(3);
2597     outTriangles[0].positions[0]  = outData[0];
2598     outTriangles[0].sharedEdge[0] = false;
2599     outTriangles[0].positions[1]  = outData[1];
2600     outTriangles[0].sharedEdge[1] = true;
2601     outTriangles[0].positions[2]  = outData[2];
2602     outTriangles[0].sharedEdge[2] = false;
2603 
2604     outTriangles[1].positions[0]  = outData[2];
2605     outTriangles[1].sharedEdge[0] = true;
2606     outTriangles[1].positions[1]  = outData[1];
2607     outTriangles[1].sharedEdge[1] = false;
2608     outTriangles[1].positions[2]  = outData[3];
2609     outTriangles[1].sharedEdge[2] = true;
2610 
2611     outTriangles[2].positions[0]  = outData[2];
2612     outTriangles[2].sharedEdge[0] = true;
2613     outTriangles[2].positions[1]  = outData[3];
2614     outTriangles[2].sharedEdge[1] = false;
2615     outTriangles[2].positions[2]  = outData[4];
2616     outTriangles[2].sharedEdge[2] = false;
2617 
2618     // log
2619     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size()
2620                                         << " vertices." << tcu::TestLog::EndMessage;
2621     for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
2622     {
2623         m_context.getTestContext().getLog()
2624             << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
2625     }
2626 }
2627 
2628 class TriangleFanTestInstance : public BaseTriangleTestInstance
2629 {
2630 public:
2631     TriangleFanTestInstance(Context &context, VkSampleCountFlagBits sampleCount);
2632 
2633     void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2634                            std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
2635 };
2636 
TriangleFanTestInstance(Context & context,VkSampleCountFlagBits sampleCount)2637 TriangleFanTestInstance::TriangleFanTestInstance(Context &context, VkSampleCountFlagBits sampleCount)
2638     : BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, sampleCount)
2639 {
2640 #ifndef CTS_USES_VULKANSC
2641     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
2642         !context.getPortabilitySubsetFeatures().triangleFans)
2643     {
2644         TCU_THROW(NotSupportedError,
2645                   "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
2646     }
2647 #endif // CTS_USES_VULKANSC
2648 }
2649 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2650 void TriangleFanTestInstance::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2651                                                 std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
2652 {
2653     outData.resize(5);
2654 
2655     switch (iteration)
2656     {
2657     case 0:
2658         // \note: these values are chosen arbitrarily
2659         outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
2660         outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
2661         outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
2662         outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
2663         outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
2664         break;
2665 
2666     case 1:
2667         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
2668         outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
2669         outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
2670         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
2671         outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
2672         break;
2673 
2674     case 2:
2675         outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
2676         outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
2677         outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
2678         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
2679         outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
2680         break;
2681     }
2682 
2683     outTriangles.resize(3);
2684     outTriangles[0].positions[0]  = outData[0];
2685     outTriangles[0].sharedEdge[0] = false;
2686     outTriangles[0].positions[1]  = outData[1];
2687     outTriangles[0].sharedEdge[1] = false;
2688     outTriangles[0].positions[2]  = outData[2];
2689     outTriangles[0].sharedEdge[2] = true;
2690 
2691     outTriangles[1].positions[0]  = outData[0];
2692     outTriangles[1].sharedEdge[0] = true;
2693     outTriangles[1].positions[1]  = outData[2];
2694     outTriangles[1].sharedEdge[1] = false;
2695     outTriangles[1].positions[2]  = outData[3];
2696     outTriangles[1].sharedEdge[2] = true;
2697 
2698     outTriangles[2].positions[0]  = outData[0];
2699     outTriangles[2].sharedEdge[0] = true;
2700     outTriangles[2].positions[1]  = outData[3];
2701     outTriangles[2].sharedEdge[1] = false;
2702     outTriangles[2].positions[2]  = outData[4];
2703     outTriangles[2].sharedEdge[2] = false;
2704 
2705     // log
2706     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size()
2707                                         << " vertices." << tcu::TestLog::EndMessage;
2708     for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
2709     {
2710         m_context.getTestContext().getLog()
2711             << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
2712     }
2713 }
2714 
2715 struct ConservativeTestConfig
2716 {
2717     VkConservativeRasterizationModeEXT conservativeRasterizationMode;
2718     float extraOverestimationSize;
2719     VkPrimitiveTopology primitiveTopology;
2720     bool degeneratePrimitives;
2721     float lineWidth;
2722     uint32_t resolution;
2723 };
2724 
getExtraOverestimationSize(const float overestimationSizeDesired,const VkPhysicalDeviceConservativeRasterizationPropertiesEXT & conservativeRasterizationProperties)2725 float getExtraOverestimationSize(
2726     const float overestimationSizeDesired,
2727     const VkPhysicalDeviceConservativeRasterizationPropertiesEXT &conservativeRasterizationProperties)
2728 {
2729     const float extraOverestimationSize =
2730         overestimationSizeDesired == TCU_INFINITY ?
2731             conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize :
2732         overestimationSizeDesired == -TCU_INFINITY ?
2733             conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity :
2734             overestimationSizeDesired;
2735 
2736     return extraOverestimationSize;
2737 }
2738 
2739 template <typename ConcreteTestInstance>
2740 class ConservativeTestCase : public BaseRenderingTestCase
2741 {
2742 public:
ConservativeTestCase(tcu::TestContext & context,const std::string & name,const ConservativeTestConfig & conservativeTestConfig,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)2743     ConservativeTestCase(tcu::TestContext &context, const std::string &name,
2744                          const ConservativeTestConfig &conservativeTestConfig,
2745                          VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
2746         : BaseRenderingTestCase(context, name, sampleCount)
2747         , m_conservativeTestConfig(conservativeTestConfig)
2748     {
2749     }
2750 
2751     virtual void checkSupport(Context &context) const;
2752 
createInstance(Context & context) const2753     virtual TestInstance *createInstance(Context &context) const
2754     {
2755         return new ConcreteTestInstance(context, m_conservativeTestConfig, m_sampleCount);
2756     }
2757 
2758 protected:
2759     bool isUseLineSubPixel(Context &context) const;
2760     uint32_t getSubPixelResolution(Context &context) const;
2761 
2762     const ConservativeTestConfig m_conservativeTestConfig;
2763 };
2764 
2765 template <typename ConcreteTestInstance>
isUseLineSubPixel(Context & context) const2766 bool ConservativeTestCase<ConcreteTestInstance>::isUseLineSubPixel(Context &context) const
2767 {
2768     return (isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology) &&
2769             (context.isDeviceFunctionalitySupported("VK_KHR_line_rasterization") ||
2770              context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization")));
2771 }
2772 
2773 template <typename ConcreteTestInstance>
getSubPixelResolution(Context & context) const2774 uint32_t ConservativeTestCase<ConcreteTestInstance>::getSubPixelResolution(Context &context) const
2775 {
2776     if (isUseLineSubPixel(context))
2777     {
2778         const VkPhysicalDeviceLineRasterizationPropertiesKHR lineRasterizationProperties =
2779             context.getLineRasterizationProperties();
2780 
2781         return lineRasterizationProperties.lineSubPixelPrecisionBits;
2782     }
2783     else
2784     {
2785         return context.getDeviceProperties().limits.subPixelPrecisionBits;
2786     }
2787 }
2788 
2789 template <typename ConcreteTestInstance>
checkSupport(Context & context) const2790 void ConservativeTestCase<ConcreteTestInstance>::checkSupport(Context &context) const
2791 {
2792     context.requireDeviceFunctionality("VK_EXT_conservative_rasterization");
2793 
2794     const VkPhysicalDeviceConservativeRasterizationPropertiesEXT conservativeRasterizationProperties =
2795         context.getConservativeRasterizationPropertiesEXT();
2796     const uint32_t subPixelPrecisionBits = getSubPixelResolution(context);
2797     const uint32_t subPixelPrecision     = 1 << subPixelPrecisionBits;
2798     const bool linesPrecision            = isUseLineSubPixel(context);
2799     const float primitiveOverestimationSizeMult =
2800         float(subPixelPrecision) * conservativeRasterizationProperties.primitiveOverestimationSize;
2801     const bool topologyLineOrPoint = isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology) ||
2802                                      isPrimitiveTopologyPoint(m_conservativeTestConfig.primitiveTopology);
2803 
2804     DE_ASSERT(subPixelPrecisionBits < sizeof(uint32_t) * 8);
2805 
2806     context.getTestContext().getLog() << tcu::TestLog::Message << "maxExtraPrimitiveOverestimationSize="
2807                                       << conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize << '\n'
2808                                       << "extraPrimitiveOverestimationSizeGranularity="
2809                                       << conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity
2810                                       << '\n'
2811                                       << "degenerateLinesRasterized="
2812                                       << conservativeRasterizationProperties.degenerateLinesRasterized << '\n'
2813                                       << "degenerateTrianglesRasterized="
2814                                       << conservativeRasterizationProperties.degenerateTrianglesRasterized << '\n'
2815                                       << "primitiveOverestimationSize="
2816                                       << conservativeRasterizationProperties.primitiveOverestimationSize
2817                                       << " (==" << primitiveOverestimationSizeMult << '/' << subPixelPrecision << ")\n"
2818                                       << "subPixelPrecisionBits=" << subPixelPrecisionBits
2819                                       << (linesPrecision ? " (using VK_EXT_line_rasterization)" : " (using limits)")
2820                                       << '\n'
2821                                       << tcu::TestLog::EndMessage;
2822 
2823     if (conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity >
2824         conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize)
2825         TCU_FAIL("Granularity cannot be greater than maximum extra size");
2826 
2827     if (topologyLineOrPoint)
2828     {
2829         if (!conservativeRasterizationProperties.conservativePointAndLineRasterization)
2830             TCU_THROW(NotSupportedError, "Conservative line and point rasterization is not supported");
2831     }
2832 
2833     if (m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT)
2834     {
2835         if (conservativeRasterizationProperties.primitiveUnderestimation == false)
2836             TCU_THROW(NotSupportedError, "Underestimation is not supported");
2837 
2838         if (isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology))
2839         {
2840             const float testLineWidth = m_conservativeTestConfig.lineWidth;
2841 
2842             if (testLineWidth != 1.0f)
2843             {
2844                 const VkPhysicalDeviceLimits &limits = context.getDeviceProperties().limits;
2845                 const float lineWidthRange[2]        = {limits.lineWidthRange[0], limits.lineWidthRange[1]};
2846                 const float lineWidthGranularity     = limits.lineWidthGranularity;
2847 
2848                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
2849 
2850                 if (lineWidthGranularity == 0.0f)
2851                     TCU_THROW(NotSupportedError, "Wide lines required for test, but are not supported");
2852 
2853                 DE_ASSERT(lineWidthGranularity > 0.0f && lineWidthRange[0] > 0.0f &&
2854                           lineWidthRange[1] >= lineWidthRange[0]);
2855 
2856                 if (!de::inBounds(testLineWidth, lineWidthRange[0], lineWidthRange[1]))
2857                     TCU_THROW(NotSupportedError, "Tested line width is not supported");
2858 
2859                 const float n = (testLineWidth - lineWidthRange[0]) / lineWidthGranularity;
2860 
2861                 if (deFloatFrac(n) != 0.0f || n * lineWidthGranularity + lineWidthRange[0] != testLineWidth)
2862                     TCU_THROW(NotSupportedError, "Exact match of line width is required for the test");
2863             }
2864         }
2865         else if (isPrimitiveTopologyPoint(m_conservativeTestConfig.primitiveTopology))
2866         {
2867             const float testPointSize = m_conservativeTestConfig.lineWidth;
2868 
2869             if (testPointSize != 1.0f)
2870             {
2871                 const VkPhysicalDeviceLimits &limits = context.getDeviceProperties().limits;
2872                 const float pointSizeRange[2]        = {limits.pointSizeRange[0], limits.pointSizeRange[1]};
2873                 const float pointSizeGranularity     = limits.pointSizeGranularity;
2874 
2875                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
2876 
2877                 if (pointSizeGranularity == 0.0f)
2878                     TCU_THROW(NotSupportedError, "Large points required for test, but are not supported");
2879 
2880                 DE_ASSERT(pointSizeGranularity > 0.0f && pointSizeRange[0] > 0.0f &&
2881                           pointSizeRange[1] >= pointSizeRange[0]);
2882 
2883                 if (!de::inBounds(testPointSize, pointSizeRange[0], pointSizeRange[1]))
2884                     TCU_THROW(NotSupportedError, "Tested point size is not supported");
2885 
2886                 const float n = (testPointSize - pointSizeRange[0]) / pointSizeGranularity;
2887 
2888                 if (deFloatFrac(n) != 0.0f || n * pointSizeGranularity + pointSizeRange[0] != testPointSize)
2889                     TCU_THROW(NotSupportedError, "Exact match of point size is required for the test");
2890             }
2891         }
2892     }
2893     else if (m_conservativeTestConfig.conservativeRasterizationMode ==
2894              VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT)
2895     {
2896         const float extraOverestimationSize = getExtraOverestimationSize(
2897             m_conservativeTestConfig.extraOverestimationSize, conservativeRasterizationProperties);
2898 
2899         if (extraOverestimationSize > conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize)
2900             TCU_THROW(NotSupportedError, "Specified overestimation size is not supported");
2901 
2902         if (topologyLineOrPoint)
2903         {
2904             if (!conservativeRasterizationProperties.conservativePointAndLineRasterization)
2905                 TCU_THROW(NotSupportedError, "Conservative line and point rasterization is not supported");
2906         }
2907 
2908         if (isPrimitiveTopologyTriangle(m_conservativeTestConfig.primitiveTopology))
2909         {
2910             if (m_conservativeTestConfig.degeneratePrimitives)
2911             {
2912                 // Enforce specification minimum required limit to avoid division by zero
2913                 DE_ASSERT(subPixelPrecisionBits >= 4);
2914 
2915                 // Make sure float precision of 22 bits is enough, i.e. resoultion in subpixel quarters less than float precision
2916                 if (m_conservativeTestConfig.resolution * (1 << (subPixelPrecisionBits + 2)) > (1 << 21))
2917                     TCU_THROW(NotSupportedError, "Subpixel resolution is too high to generate degenerate primitives");
2918             }
2919         }
2920     }
2921     else
2922         TCU_THROW(InternalError, "Non-conservative mode tests are not supported by this class");
2923 }
2924 
2925 class ConservativeTraingleTestInstance : public BaseTriangleTestInstance
2926 {
2927 public:
ConservativeTraingleTestInstance(Context & context,ConservativeTestConfig conservativeTestConfig,VkSampleCountFlagBits sampleCount)2928     ConservativeTraingleTestInstance(Context &context, ConservativeTestConfig conservativeTestConfig,
2929                                      VkSampleCountFlagBits sampleCount)
2930         : BaseTriangleTestInstance(context, conservativeTestConfig.primitiveTopology, sampleCount,
2931                                    conservativeTestConfig.resolution)
2932         , m_conservativeTestConfig(conservativeTestConfig)
2933         , m_conservativeRasterizationProperties(context.getConservativeRasterizationPropertiesEXT())
2934         , m_rasterizationConservativeStateCreateInfo(initRasterizationConservativeStateCreateInfo())
2935         , m_rasterizationStateCreateInfo(initRasterizationStateCreateInfo())
2936     {
2937     }
2938 
2939     void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2940                            std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
2941     const VkPipelineRasterizationStateCreateInfo *getRasterizationStateCreateInfo(void) const;
2942 
2943 protected:
2944     virtual const VkPipelineRasterizationLineStateCreateInfoEXT *getLineRasterizationStateCreateInfo(void);
2945 
2946     virtual bool compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> &triangles, tcu::Surface &resultImage,
2947                                   std::vector<tcu::Vec4> &drawBuffer);
2948     virtual bool compareAndVerifyOverestimatedNormal(std::vector<TriangleSceneSpec::SceneTriangle> &triangles,
2949                                                      tcu::Surface &resultImage);
2950     virtual bool compareAndVerifyOverestimatedDegenerate(std::vector<TriangleSceneSpec::SceneTriangle> &triangles,
2951                                                          tcu::Surface &resultImage);
2952     virtual bool compareAndVerifyUnderestimatedNormal(std::vector<TriangleSceneSpec::SceneTriangle> &triangles,
2953                                                       tcu::Surface &resultImage);
2954     virtual bool compareAndVerifyUnderestimatedDegenerate(std::vector<TriangleSceneSpec::SceneTriangle> &triangles,
2955                                                           tcu::Surface &resultImage);
2956     void generateNormalTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2957                                  std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
2958     void generateDegenerateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2959                                      std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles);
2960     void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
2961                         VkPrimitiveTopology primitiveTopology);
2962 
2963 private:
2964     const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> initRasterizationConservativeStateCreateInfo(
2965         void);
2966     const std::vector<VkPipelineRasterizationStateCreateInfo> initRasterizationStateCreateInfo(void);
2967 
2968     const ConservativeTestConfig m_conservativeTestConfig;
2969     const VkPhysicalDeviceConservativeRasterizationPropertiesEXT m_conservativeRasterizationProperties;
2970     const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> m_rasterizationConservativeStateCreateInfo;
2971     const std::vector<VkPipelineRasterizationStateCreateInfo> m_rasterizationStateCreateInfo;
2972 };
2973 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2974 void ConservativeTraingleTestInstance::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData,
2975                                                          std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
2976 {
2977     if (m_conservativeTestConfig.degeneratePrimitives)
2978         generateDegenerateTriangles(iteration, outData, outTriangles);
2979     else
2980         generateNormalTriangles(iteration, outData, outTriangles);
2981 }
2982 
generateNormalTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2983 void ConservativeTraingleTestInstance::generateNormalTriangles(
2984     int iteration, std::vector<tcu::Vec4> &outData, std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
2985 {
2986     const float halfPixel               = 1.0f / float(m_renderSize);
2987     const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
2988                                                                      m_conservativeRasterizationProperties);
2989     const float overestimate =
2990         2.0f * halfPixel *
2991         (m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize);
2992     const float overestimateMargin  = overestimate;
2993     const float underestimateMargin = 0.0f;
2994     const bool isOverestimate =
2995         m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
2996     const float margin                          = isOverestimate ? overestimateMargin : underestimateMargin;
2997     const char *overestimateIterationComments[] = {"Corner touch", "Any portion pixel coverage", "Edge touch"};
2998 
2999     outData.resize(6);
3000 
3001     switch (iteration)
3002     {
3003     case 0:
3004     {
3005         // Corner touch
3006         const float edge  = 2 * halfPixel + margin;
3007         const float left  = -1.0f + edge;
3008         const float right = +1.0f - edge;
3009         const float up    = -1.0f + edge;
3010         const float down  = +1.0f - edge;
3011 
3012         outData[0] = tcu::Vec4(left, down, 0.0f, 1.0f);
3013         outData[1] = tcu::Vec4(left, up, 0.0f, 1.0f);
3014         outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
3015 
3016         outData[3] = tcu::Vec4(left, up, 0.0f, 1.0f);
3017         outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
3018         outData[5] = tcu::Vec4(right, up, 0.0f, 1.0f);
3019 
3020         break;
3021     }
3022 
3023     case 1:
3024     {
3025         // Partial coverage
3026         const float eps   = halfPixel / 32.0f;
3027         const float edge  = 4.0f * halfPixel + margin - eps;
3028         const float left  = -1.0f + edge;
3029         const float right = +1.0f - edge;
3030         const float up    = -1.0f + edge;
3031         const float down  = +1.0f - edge;
3032 
3033         outData[0] = tcu::Vec4(left, down, 0.0f, 1.0f);
3034         outData[1] = tcu::Vec4(left, up, 0.0f, 1.0f);
3035         outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
3036 
3037         outData[3] = tcu::Vec4(left, up, 0.0f, 1.0f);
3038         outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
3039         outData[5] = tcu::Vec4(right, up, 0.0f, 1.0f);
3040 
3041         break;
3042     }
3043 
3044     case 2:
3045     {
3046         // Edge touch
3047         const float edge  = 6.0f * halfPixel + margin;
3048         const float left  = -1.0f + edge;
3049         const float right = +1.0f - edge;
3050         const float up    = -1.0f + edge;
3051         const float down  = +1.0f - edge;
3052 
3053         outData[0] = tcu::Vec4(left, down, 0.0f, 1.0f);
3054         outData[1] = tcu::Vec4(left, up, 0.0f, 1.0f);
3055         outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
3056 
3057         outData[3] = tcu::Vec4(left, up, 0.0f, 1.0f);
3058         outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
3059         outData[5] = tcu::Vec4(right, up, 0.0f, 1.0f);
3060 
3061         break;
3062     }
3063 
3064     default:
3065         TCU_THROW(InternalError, "Unexpected iteration");
3066     }
3067 
3068     outTriangles.resize(outData.size() / 3);
3069 
3070     for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
3071     {
3072         outTriangles[ndx].positions[0]  = outData[3 * ndx + 0];
3073         outTriangles[ndx].sharedEdge[0] = false;
3074         outTriangles[ndx].positions[1]  = outData[3 * ndx + 1];
3075         outTriangles[ndx].sharedEdge[1] = false;
3076         outTriangles[ndx].positions[2]  = outData[3 * ndx + 2];
3077         outTriangles[ndx].sharedEdge[2] = false;
3078     }
3079 
3080     // log
3081     if (isOverestimate)
3082     {
3083         m_context.getTestContext().getLog()
3084             << tcu::TestLog::Message << "Testing " << overestimateIterationComments[iteration] << " "
3085             << "with rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage;
3086     }
3087     else
3088     {
3089         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size()
3090                                             << " triangle(s):" << tcu::TestLog::EndMessage;
3091     }
3092 
3093     for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
3094     {
3095         const uint32_t multiplier = m_renderSize / 2;
3096 
3097         m_context.getTestContext().getLog()
3098             << tcu::TestLog::Message << "Triangle " << (ndx + 1) << ":"
3099             << "\n\t" << outTriangles[ndx].positions[0]
3100             << " == " << (float(multiplier) * outTriangles[ndx].positions[0]) << "/" << multiplier << "\n\t"
3101             << outTriangles[ndx].positions[1] << " == " << (float(multiplier) * outTriangles[ndx].positions[1]) << "/"
3102             << multiplier << "\n\t" << outTriangles[ndx].positions[2]
3103             << " == " << (float(multiplier) * outTriangles[ndx].positions[2]) << "/" << multiplier
3104             << tcu::TestLog::EndMessage;
3105     }
3106 }
3107 
generateDegenerateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)3108 void ConservativeTraingleTestInstance::generateDegenerateTriangles(
3109     int iteration, std::vector<tcu::Vec4> &outData, std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles)
3110 {
3111     tcu::TestLog &log                   = m_context.getTestContext().getLog();
3112     const float pixelSize               = 2.0f / float(m_renderSize);
3113     const uint32_t subPixels            = 1u << m_context.getDeviceProperties().limits.subPixelPrecisionBits;
3114     const float subPixelSize            = pixelSize / float(subPixels);
3115     const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
3116                                                                      m_conservativeRasterizationProperties);
3117     const float totalOverestimate =
3118         m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
3119     const float totalOverestimateInSubPixels = deFloatCeil(totalOverestimate * float(subPixels));
3120     const float overestimate                 = subPixelSize * totalOverestimateInSubPixels;
3121     const float overestimateSafetyMargin     = subPixelSize * 0.125f;
3122     const float overestimateMargin           = overestimate + overestimateSafetyMargin;
3123     const float underestimateMargin          = 0.0f;
3124     const bool isOverestimate =
3125         m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
3126     const float margin                          = isOverestimate ? overestimateMargin : underestimateMargin;
3127     const char *overestimateIterationComments[] = {"Backfacing", "Generate pixels", "Use provoking vertex"};
3128 
3129     if (pixelSize < 2 * overestimateMargin)
3130         TCU_THROW(NotSupportedError, "Could not generate degenerate triangle for such overestimate parameters");
3131 
3132     outData.clear();
3133 
3134     switch (iteration)
3135     {
3136     case 0:
3137     case 1:
3138     case 2:
3139     {
3140         for (int rowNdx = 0; rowNdx < 3; ++rowNdx)
3141             for (int colNdx = 0; colNdx < 4; ++colNdx)
3142             {
3143                 const float offsetX  = -1.0f + float(4 * (colNdx + 1)) * pixelSize;
3144                 const float offsetY  = -1.0f + float(4 * (rowNdx + 1)) * pixelSize;
3145                 const float left     = offsetX + margin;
3146                 const float right    = offsetX + margin + 0.25f * subPixelSize;
3147                 const float up       = offsetY + margin;
3148                 const float down     = offsetY + margin + 0.25f * subPixelSize;
3149                 const bool luPresent = (rowNdx & 1) == 0;
3150                 const bool rdPresent = (rowNdx & 2) == 0;
3151                 const bool luCW      = (colNdx & 1) == 0;
3152                 const bool rdCW      = (colNdx & 2) == 0;
3153 
3154                 DE_ASSERT(left < right);
3155                 DE_ASSERT(up < down);
3156 
3157                 if (luPresent)
3158                 {
3159                     if (luCW)
3160                     {
3161                         // CW triangle left up
3162                         outData.push_back(tcu::Vec4(left, down, 0.0f, 1.0f));
3163                         outData.push_back(tcu::Vec4(left, up, 0.0f, 1.0f));
3164                         outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
3165                     }
3166                     else
3167                     {
3168                         // CCW triangle left up
3169                         outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
3170                         outData.push_back(tcu::Vec4(left, up, 0.0f, 1.0f));
3171                         outData.push_back(tcu::Vec4(left, down, 0.0f, 1.0f));
3172                     }
3173                 }
3174 
3175                 if (rdPresent)
3176                 {
3177                     if (rdCW)
3178                     {
3179                         // CW triangle right down
3180                         outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
3181                         outData.push_back(tcu::Vec4(right, down, 0.0f, 1.0f));
3182                         outData.push_back(tcu::Vec4(left, down, 0.0f, 1.0f));
3183                     }
3184                     else
3185                     {
3186                         // CCW triangle right down
3187                         outData.push_back(tcu::Vec4(left, down, 0.0f, 1.0f));
3188                         outData.push_back(tcu::Vec4(right, down, 0.0f, 1.0f));
3189                         outData.push_back(tcu::Vec4(right, up, 0.0f, 1.0f));
3190                     }
3191                 }
3192             }
3193 
3194         break;
3195     }
3196 
3197     default:
3198         TCU_THROW(InternalError, "Unexpected iteration");
3199     }
3200 
3201     outTriangles.resize(outData.size() / 3);
3202 
3203     for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
3204     {
3205         outTriangles[ndx].positions[0]  = outData[3 * ndx + 0];
3206         outTriangles[ndx].sharedEdge[0] = false;
3207         outTriangles[ndx].positions[1]  = outData[3 * ndx + 1];
3208         outTriangles[ndx].sharedEdge[1] = false;
3209         outTriangles[ndx].positions[2]  = outData[3 * ndx + 2];
3210         outTriangles[ndx].sharedEdge[2] = false;
3211     }
3212 
3213     // log
3214     if (isOverestimate)
3215     {
3216         m_context.getTestContext().getLog()
3217             << tcu::TestLog::Message << "Testing " << overestimateIterationComments[iteration] << " "
3218             << "with rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage;
3219     }
3220     else
3221     {
3222         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size()
3223                                             << " triangle(s):" << tcu::TestLog::EndMessage;
3224     }
3225 
3226     for (int ndx = 0; ndx < (int)outTriangles.size(); ++ndx)
3227     {
3228         const uint32_t multiplierInt  = m_renderSize / 2;
3229         const uint32_t multiplierFrac = subPixels;
3230         std::string coordsString;
3231 
3232         for (size_t vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
3233         {
3234             const tcu::Vec4 &pos = outTriangles[ndx].positions[vertexNdx];
3235             std::ostringstream coordsFloat;
3236             std::ostringstream coordsNatural;
3237 
3238             for (int coordNdx = 0; coordNdx < 2; ++coordNdx)
3239             {
3240                 const char *sep   = (coordNdx < 1) ? "," : "";
3241                 const float coord = pos[coordNdx];
3242                 const char sign   = deSign(coord) < 0 ? '-' : '+';
3243                 const float m     = deFloatFloor(float(multiplierInt) * deFloatAbs(coord));
3244                 const float r     = deFloatFrac(float(multiplierInt) * deFloatAbs(coord)) * float(multiplierFrac);
3245 
3246                 coordsFloat << std::fixed << std::setw(13) << std::setprecision(10) << coord << sep;
3247                 coordsNatural << sign << '(' << m << '+' << r << '/' << multiplierFrac << ')' << sep;
3248             }
3249 
3250             coordsString +=
3251                 "\n\t[" + coordsFloat.str() + "] == [" + coordsNatural.str() + "] / " + de::toString(multiplierInt);
3252         }
3253 
3254         log << tcu::TestLog::Message << "Triangle " << (ndx + 1) << ':' << coordsString << tcu::TestLog::EndMessage;
3255     }
3256 }
3257 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,VkPrimitiveTopology primitiveTopology)3258 void ConservativeTraingleTestInstance::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
3259                                                       VkPrimitiveTopology primitiveTopology)
3260 {
3261     if (m_conservativeTestConfig.degeneratePrimitives && getIteration() == 2)
3262     {
3263         // Set provoking vertex color to white
3264         tcu::Vec4 colorProvoking(1.0f, 1.0f, 1.0f, 1.0f);
3265         tcu::Vec4 colorOther(0.0f, 1.0f, 1.0f, 1.0f);
3266         std::vector<tcu::Vec4> colorData;
3267 
3268         colorData.reserve(vertexData.size());
3269 
3270         for (size_t vertexNdx = 0; vertexNdx < vertexData.size(); ++vertexNdx)
3271             if (vertexNdx % 3 == 0)
3272                 colorData.push_back(colorProvoking);
3273             else
3274                 colorData.push_back(colorOther);
3275 
3276         BaseRenderingTestInstance::drawPrimitives(result, vertexData, colorData, primitiveTopology);
3277     }
3278     else
3279         BaseRenderingTestInstance::drawPrimitives(result, vertexData, primitiveTopology);
3280 }
3281 
compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)3282 bool ConservativeTraingleTestInstance::compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> &triangles,
3283                                                         tcu::Surface &resultImage, std::vector<tcu::Vec4> &drawBuffer)
3284 {
3285     DE_UNREF(drawBuffer);
3286 
3287     switch (m_conservativeTestConfig.conservativeRasterizationMode)
3288     {
3289     case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
3290     {
3291         if (m_conservativeTestConfig.degeneratePrimitives)
3292             return compareAndVerifyOverestimatedDegenerate(triangles, resultImage);
3293         else
3294             return compareAndVerifyOverestimatedNormal(triangles, resultImage);
3295     }
3296 
3297     case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
3298     {
3299         if (m_conservativeTestConfig.degeneratePrimitives)
3300             return compareAndVerifyUnderestimatedDegenerate(triangles, resultImage);
3301         else
3302             return compareAndVerifyUnderestimatedNormal(triangles, resultImage);
3303     }
3304 
3305     default:
3306         TCU_THROW(InternalError, "Unknown conservative rasterization mode");
3307     }
3308 }
3309 
compareAndVerifyOverestimatedNormal(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)3310 bool ConservativeTraingleTestInstance::compareAndVerifyOverestimatedNormal(
3311     std::vector<TriangleSceneSpec::SceneTriangle> &triangles, tcu::Surface &resultImage)
3312 {
3313     DE_UNREF(triangles);
3314 
3315     const int start                      = getIteration() + 1;
3316     const int end                        = resultImage.getHeight() - start;
3317     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
3318     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
3319     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
3320     tcu::TestLog &log                    = m_context.getTestContext().getLog();
3321     int errX                             = 0;
3322     int errY                             = 0;
3323     uint32_t errValue                    = 0;
3324     bool result                          = true;
3325 
3326     DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
3327 
3328     for (int y = start; result && y < end; ++y)
3329         for (int x = start; result && x < end; ++x)
3330         {
3331             if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
3332             {
3333                 result   = false;
3334                 errX     = x;
3335                 errY     = y;
3336                 errValue = resultImage.getPixel(x, y).getPacked();
3337 
3338                 break;
3339             }
3340         }
3341 
3342     if (!result)
3343     {
3344         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
3345         tcu::Surface expectedImage(resultImage.getWidth(), resultImage.getHeight());
3346 
3347         for (int y = 0; y < errorMask.getHeight(); ++y)
3348             for (int x = 0; x < errorMask.getWidth(); ++x)
3349             {
3350                 errorMask.setPixel(x, y, backgroundColor);
3351                 expectedImage.setPixel(x, y, backgroundColor);
3352             }
3353 
3354         for (int y = start; y < end; ++y)
3355             for (int x = start; x < end; ++x)
3356             {
3357                 expectedImage.setPixel(x, y, foregroundColor);
3358 
3359                 if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
3360                     errorMask.setPixel(x, y, unexpectedPixelColor);
3361             }
3362 
3363         log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x"
3364             << std::hex << errValue << tcu::TestLog::EndMessage;
3365         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3366             << tcu::TestLog::Image("Result", "Result", resultImage)
3367             << tcu::TestLog::Image("Expected", "Expected", expectedImage)
3368             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
3369     }
3370     else
3371     {
3372         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3373         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3374             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
3375     }
3376 
3377     return result;
3378 }
3379 
compareAndVerifyOverestimatedDegenerate(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)3380 bool ConservativeTraingleTestInstance::compareAndVerifyOverestimatedDegenerate(
3381     std::vector<TriangleSceneSpec::SceneTriangle> &triangles, tcu::Surface &resultImage)
3382 {
3383     DE_UNREF(triangles);
3384 
3385     const char *iterationComments[]      = {"Cull back face triangles", "Cull front face triangles", "Cull none"};
3386     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
3387     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
3388     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
3389     tcu::TestLog &log                    = m_context.getTestContext().getLog();
3390     bool result                          = true;
3391     tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
3392 
3393     for (int y = 0; y < resultImage.getHeight(); ++y)
3394         for (int x = 0; x < resultImage.getWidth(); ++x)
3395             referenceImage.setPixel(x, y, backgroundColor);
3396 
3397     if (m_conservativeRasterizationProperties.degenerateTrianglesRasterized)
3398     {
3399         if (getIteration() != 0)
3400         {
3401             log << tcu::TestLog::Message
3402                 << "Triangles expected to be rasterized with at least one pixel of white color each"
3403                 << tcu::TestLog::EndMessage;
3404 
3405             for (int rowNdx = 0; rowNdx < 3; ++rowNdx)
3406                 for (int colNdx = 0; colNdx < 4; ++colNdx)
3407                 {
3408                     referenceImage.setPixel(4 * (colNdx + 1), 4 * (rowNdx + 1), foregroundColor);
3409 
3410                     // Allow implementations that need to be extra conservative with degenerate triangles,
3411                     // which may cause extra coverage.
3412                     if (resultImage.getPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1) - 1) == foregroundColor)
3413                         referenceImage.setPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1) - 1, foregroundColor);
3414                     if (resultImage.getPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1)) == foregroundColor)
3415                         referenceImage.setPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1), foregroundColor);
3416                     if (resultImage.getPixel(4 * (colNdx + 1), 4 * (rowNdx + 1) - 1) == foregroundColor)
3417                         referenceImage.setPixel(4 * (colNdx + 1), 4 * (rowNdx + 1) - 1, foregroundColor);
3418                 }
3419         }
3420         else
3421             log << tcu::TestLog::Message
3422                 << "Triangles expected to be culled due to backfacing culling and all degenerate triangles assumed to "
3423                    "be backfacing"
3424                 << tcu::TestLog::EndMessage;
3425     }
3426     else
3427         log << tcu::TestLog::Message << "Triangles expected to be culled due to degenerateTrianglesRasterized=false"
3428             << tcu::TestLog::EndMessage;
3429 
3430     for (int y = 0; result && y < resultImage.getHeight(); ++y)
3431         for (int x = 0; result && x < resultImage.getWidth(); ++x)
3432         {
3433             if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3434             {
3435                 result = false;
3436 
3437                 break;
3438             }
3439         }
3440 
3441     if (!result)
3442     {
3443         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
3444 
3445         for (int y = 0; y < errorMask.getHeight(); ++y)
3446             for (int x = 0; x < errorMask.getWidth(); ++x)
3447             {
3448                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3449                     errorMask.setPixel(x, y, unexpectedPixelColor);
3450                 else
3451                     errorMask.setPixel(x, y, backgroundColor);
3452             }
3453 
3454         log << tcu::TestLog::Message << "Invalid pixels found for mode '" << iterationComments[getIteration()] << "'"
3455             << tcu::TestLog::EndMessage;
3456         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3457             << tcu::TestLog::Image("Result", "Result", resultImage)
3458             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
3459             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
3460     }
3461     else
3462     {
3463         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3464         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3465             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
3466     }
3467 
3468     return result;
3469 }
3470 
compareAndVerifyUnderestimatedNormal(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)3471 bool ConservativeTraingleTestInstance::compareAndVerifyUnderestimatedNormal(
3472     std::vector<TriangleSceneSpec::SceneTriangle> &triangles, tcu::Surface &resultImage)
3473 {
3474     DE_UNREF(triangles);
3475 
3476     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
3477     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
3478     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
3479     const tcu::IVec2 viewportSize        = tcu::IVec2(resultImage.getWidth(), resultImage.getHeight());
3480     tcu::TestLog &log                    = m_context.getTestContext().getLog();
3481     int errX                             = -1;
3482     int errY                             = -1;
3483     uint32_t errValue                    = 0;
3484     tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
3485     bool result = true;
3486 
3487     DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
3488 
3489     for (int y = 0; y < resultImage.getHeight(); ++y)
3490         for (int x = 0; x < resultImage.getWidth(); ++x)
3491             referenceImage.setPixel(x, y, backgroundColor);
3492 
3493     for (size_t triangleNdx = 0; triangleNdx < triangles.size(); ++triangleNdx)
3494     {
3495         const tcu::Vec4 &p0 = triangles[triangleNdx].positions[0];
3496         const tcu::Vec4 &p1 = triangles[triangleNdx].positions[1];
3497         const tcu::Vec4 &p2 = triangles[triangleNdx].positions[2];
3498 
3499         for (int y = 0; y < resultImage.getHeight(); ++y)
3500             for (int x = 0; x < resultImage.getWidth(); ++x)
3501             {
3502                 if (calculateUnderestimateTriangleCoverage(p0, p1, p2, tcu::IVec2(x, y), m_subpixelBits,
3503                                                            viewportSize) == tcu::COVERAGE_FULL)
3504                     referenceImage.setPixel(x, y, foregroundColor);
3505             }
3506     }
3507 
3508     for (int y = 0; result && y < resultImage.getHeight(); ++y)
3509         for (int x = 0; result && x < resultImage.getWidth(); ++x)
3510             if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3511             {
3512                 result   = false;
3513                 errX     = x;
3514                 errY     = y;
3515                 errValue = resultImage.getPixel(x, y).getPacked();
3516             }
3517 
3518     if (!result)
3519     {
3520         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
3521 
3522         for (int y = 0; y < errorMask.getHeight(); ++y)
3523             for (int x = 0; x < errorMask.getWidth(); ++x)
3524             {
3525                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3526                     errorMask.setPixel(x, y, unexpectedPixelColor);
3527                 else
3528                     errorMask.setPixel(x, y, backgroundColor);
3529             }
3530 
3531         log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x"
3532             << std::hex << errValue << tcu::TestLog::EndMessage;
3533         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3534             << tcu::TestLog::Image("Result", "Result", resultImage)
3535             << tcu::TestLog::Image("Refernce", "Refernce", referenceImage)
3536             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
3537     }
3538     else
3539     {
3540         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3541         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3542             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
3543     }
3544 
3545     return result;
3546 }
3547 
compareAndVerifyUnderestimatedDegenerate(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)3548 bool ConservativeTraingleTestInstance::compareAndVerifyUnderestimatedDegenerate(
3549     std::vector<TriangleSceneSpec::SceneTriangle> &triangles, tcu::Surface &resultImage)
3550 {
3551     DE_UNREF(triangles);
3552 
3553     const char *iterationComments[]      = {"Cull back face triangles", "Cull front face triangles", "Cull none"};
3554     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
3555     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
3556     tcu::TestLog &log                    = m_context.getTestContext().getLog();
3557     int errX                             = 0;
3558     int errY                             = 0;
3559     uint32_t errValue                    = 0;
3560     bool result                          = true;
3561 
3562     if (m_conservativeRasterizationProperties.degenerateTrianglesRasterized)
3563     {
3564         if (getIteration() != 0)
3565             log << tcu::TestLog::Message
3566                 << "Triangles expected to be not rendered due to no one triangle can fully cover fragment"
3567                 << tcu::TestLog::EndMessage;
3568         else
3569             log << tcu::TestLog::Message
3570                 << "Triangles expected to be culled due to backfacing culling and all degenerate triangles assumed to "
3571                    "be backfacing"
3572                 << tcu::TestLog::EndMessage;
3573     }
3574     else
3575         log << tcu::TestLog::Message << "Triangles expected to be culled due to degenerateTrianglesRasterized=false"
3576             << tcu::TestLog::EndMessage;
3577 
3578     for (int y = 0; result && y < resultImage.getHeight(); ++y)
3579         for (int x = 0; result && x < resultImage.getWidth(); ++x)
3580         {
3581             if (resultImage.getPixel(x, y).getPacked() != backgroundColor.getPacked())
3582             {
3583                 result   = false;
3584                 errX     = x;
3585                 errY     = y;
3586                 errValue = resultImage.getPixel(x, y).getPacked();
3587 
3588                 break;
3589             }
3590         }
3591 
3592     if (!result)
3593     {
3594         tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
3595         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
3596 
3597         for (int y = 0; y < resultImage.getHeight(); ++y)
3598             for (int x = 0; x < resultImage.getWidth(); ++x)
3599                 referenceImage.setPixel(x, y, backgroundColor);
3600 
3601         for (int y = 0; y < errorMask.getHeight(); ++y)
3602             for (int x = 0; x < errorMask.getWidth(); ++x)
3603             {
3604                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3605                     errorMask.setPixel(x, y, unexpectedPixelColor);
3606                 else
3607                     errorMask.setPixel(x, y, backgroundColor);
3608             }
3609 
3610         log << tcu::TestLog::Message << "Invalid pixels found for mode '" << iterationComments[getIteration()]
3611             << "' starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
3612             << tcu::TestLog::EndMessage;
3613 
3614         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3615             << tcu::TestLog::Image("Result", "Result", resultImage)
3616             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
3617             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
3618     }
3619     else
3620     {
3621         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3622         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3623             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
3624     }
3625 
3626     return result;
3627 }
3628 
3629 const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativeTraingleTestInstance::
initRasterizationConservativeStateCreateInfo(void)3630     initRasterizationConservativeStateCreateInfo(void)
3631 {
3632     const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
3633                                                                      m_conservativeRasterizationProperties);
3634     std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> result;
3635 
3636     result.reserve(getIterationCount());
3637 
3638     for (int iteration = 0; iteration < getIterationCount(); ++iteration)
3639     {
3640         const VkPipelineRasterizationConservativeStateCreateInfoEXT rasterizationConservativeStateCreateInfo = {
3641             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, //  VkStructureType sType;
3642             DE_NULL,                                                                     //  const void* pNext;
3643             (VkPipelineRasterizationConservativeStateCreateFlagsEXT)0, //  VkPipelineRasterizationConservativeStateCreateFlagsEXT flags;
3644             m_conservativeTestConfig
3645                 .conservativeRasterizationMode, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
3646             extraOverestimationSize             //  float extraPrimitiveOverestimationSize;
3647         };
3648 
3649         result.push_back(rasterizationConservativeStateCreateInfo);
3650     }
3651 
3652     return result;
3653 }
3654 
3655 const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativeTraingleTestInstance::
initRasterizationStateCreateInfo(void)3656     initRasterizationStateCreateInfo(void)
3657 {
3658     std::vector<VkPipelineRasterizationStateCreateInfo> result;
3659 
3660     result.reserve(getIterationCount());
3661 
3662     for (int iteration = 0; iteration < getIterationCount(); ++iteration)
3663     {
3664         const VkCullModeFlags cullModeFlags = (!m_conservativeTestConfig.degeneratePrimitives) ? VK_CULL_MODE_NONE :
3665                                               (iteration == 0)                                 ? VK_CULL_MODE_BACK_BIT :
3666                                               (iteration == 1) ? VK_CULL_MODE_FRONT_BIT :
3667                                                                  VK_CULL_MODE_NONE;
3668 
3669         const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
3670             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //  VkStructureType sType;
3671             &m_rasterizationConservativeStateCreateInfo[iteration],     //  const void* pNext;
3672             0,                               //  VkPipelineRasterizationStateCreateFlags flags;
3673             false,                           //  VkBool32 depthClampEnable;
3674             false,                           //  VkBool32 rasterizerDiscardEnable;
3675             VK_POLYGON_MODE_FILL,            //  VkPolygonMode polygonMode;
3676             cullModeFlags,                   //  VkCullModeFlags cullMode;
3677             VK_FRONT_FACE_COUNTER_CLOCKWISE, //  VkFrontFace frontFace;
3678             VK_FALSE,                        //  VkBool32 depthBiasEnable;
3679             0.0f,                            //  float depthBiasConstantFactor;
3680             0.0f,                            //  float depthBiasClamp;
3681             0.0f,                            //  float depthBiasSlopeFactor;
3682             getLineWidth(),                  //  float lineWidth;
3683         };
3684 
3685         result.push_back(rasterizationStateCreateInfo);
3686     }
3687 
3688     return result;
3689 }
3690 
getRasterizationStateCreateInfo(void) const3691 const VkPipelineRasterizationStateCreateInfo *ConservativeTraingleTestInstance::getRasterizationStateCreateInfo(
3692     void) const
3693 {
3694     return &m_rasterizationStateCreateInfo[getIteration()];
3695 }
3696 
3697 const VkPipelineRasterizationLineStateCreateInfoEXT *ConservativeTraingleTestInstance::
getLineRasterizationStateCreateInfo(void)3698     getLineRasterizationStateCreateInfo(void)
3699 {
3700     return DE_NULL;
3701 }
3702 
3703 class ConservativeLineTestInstance : public BaseLineTestInstance
3704 {
3705 public:
3706     ConservativeLineTestInstance(Context &context, ConservativeTestConfig conservativeTestConfig,
3707                                  VkSampleCountFlagBits sampleCount);
3708 
3709     void generateLines(int iteration, std::vector<tcu::Vec4> &outData, std::vector<LineSceneSpec::SceneLine> &outLines);
3710     const VkPipelineRasterizationStateCreateInfo *getRasterizationStateCreateInfo(void) const;
3711 
3712 protected:
3713     virtual const VkPipelineRasterizationLineStateCreateInfoEXT *getLineRasterizationStateCreateInfo(void);
3714 
3715     virtual bool compareAndVerify(std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage,
3716                                   std::vector<tcu::Vec4> &drawBuffer);
3717     virtual bool compareAndVerifyOverestimatedNormal(std::vector<LineSceneSpec::SceneLine> &lines,
3718                                                      tcu::Surface &resultImage);
3719     virtual bool compareAndVerifyOverestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> &lines,
3720                                                          tcu::Surface &resultImage);
3721     virtual bool compareAndVerifyUnderestimatedNormal(std::vector<LineSceneSpec::SceneLine> &lines,
3722                                                       tcu::Surface &resultImage);
3723     virtual bool compareAndVerifyUnderestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> &lines,
3724                                                           tcu::Surface &resultImage);
3725     void generateNormalLines(int iteration, std::vector<tcu::Vec4> &outData,
3726                              std::vector<LineSceneSpec::SceneLine> &outLines);
3727     void generateDegenerateLines(int iteration, std::vector<tcu::Vec4> &outData,
3728                                  std::vector<LineSceneSpec::SceneLine> &outLines);
3729     void drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
3730                         VkPrimitiveTopology primitiveTopology);
3731 
3732 private:
3733     const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> initRasterizationConservativeStateCreateInfo(
3734         void);
3735     const std::vector<VkPipelineRasterizationStateCreateInfo> initRasterizationStateCreateInfo(void);
3736 
3737     const ConservativeTestConfig m_conservativeTestConfig;
3738     const VkPhysicalDeviceConservativeRasterizationPropertiesEXT m_conservativeRasterizationProperties;
3739     const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> m_rasterizationConservativeStateCreateInfo;
3740     const std::vector<VkPipelineRasterizationStateCreateInfo> m_rasterizationStateCreateInfo;
3741 };
3742 
ConservativeLineTestInstance(Context & context,ConservativeTestConfig conservativeTestConfig,VkSampleCountFlagBits sampleCount)3743 ConservativeLineTestInstance::ConservativeLineTestInstance(Context &context,
3744                                                            ConservativeTestConfig conservativeTestConfig,
3745                                                            VkSampleCountFlagBits sampleCount)
3746     : BaseLineTestInstance(context, conservativeTestConfig.primitiveTopology, PRIMITIVEWIDENESS_NARROW,
3747                            PRIMITIVESTRICTNESS_IGNORE, sampleCount, LINESTIPPLE_DISABLED,
3748                            VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, LineStippleFactorCase::DEFAULT, 0,
3749                            conservativeTestConfig.resolution, conservativeTestConfig.lineWidth)
3750     , m_conservativeTestConfig(conservativeTestConfig)
3751     , m_conservativeRasterizationProperties(context.getConservativeRasterizationPropertiesEXT())
3752     , m_rasterizationConservativeStateCreateInfo(initRasterizationConservativeStateCreateInfo())
3753     , m_rasterizationStateCreateInfo(initRasterizationStateCreateInfo())
3754 {
3755 }
3756 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)3757 void ConservativeLineTestInstance::generateLines(int iteration, std::vector<tcu::Vec4> &outData,
3758                                                  std::vector<LineSceneSpec::SceneLine> &outLines)
3759 {
3760     if (m_conservativeTestConfig.degeneratePrimitives)
3761         generateDegenerateLines(iteration, outData, outLines);
3762     else
3763         generateNormalLines(iteration, outData, outLines);
3764 }
3765 
generateNormalLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)3766 void ConservativeLineTestInstance::generateNormalLines(int iteration, std::vector<tcu::Vec4> &outData,
3767                                                        std::vector<LineSceneSpec::SceneLine> &outLines)
3768 {
3769     const char *iterationComment        = "";
3770     const float halfPixel               = 1.0f / float(m_renderSize);
3771     const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
3772                                                                      m_conservativeRasterizationProperties);
3773     const float overestimate =
3774         2.0f * halfPixel *
3775         (m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize);
3776     const float overestimateMargin  = overestimate;
3777     const float underestimateMargin = 0.0f;
3778     const bool isOverestimate =
3779         m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
3780     const float margin = isOverestimate ? overestimateMargin : underestimateMargin;
3781     const float edge   = 4 * halfPixel + margin;
3782     const float left   = -1.0f + edge;
3783     const float right  = +1.0f - edge;
3784     const float up     = -1.0f + edge;
3785     const float down   = +1.0f - edge;
3786 
3787     outData.reserve(2);
3788 
3789     if (isOverestimate)
3790     {
3791         const char *iterationComments[] = {"Horizontal up line", "Vertical line", "Horizontal down line"};
3792 
3793         iterationComment = iterationComments[iteration];
3794 
3795         switch (iteration)
3796         {
3797         case 0:
3798         {
3799             outData.push_back(tcu::Vec4(left, up + halfPixel, 0.0f, 1.0f));
3800             outData.push_back(tcu::Vec4(right, up + halfPixel, 0.0f, 1.0f));
3801 
3802             break;
3803         }
3804 
3805         case 1:
3806         {
3807             outData.push_back(tcu::Vec4(left + halfPixel, up, 0.0f, 1.0f));
3808             outData.push_back(tcu::Vec4(left + halfPixel, down, 0.0f, 1.0f));
3809 
3810             break;
3811         }
3812 
3813         case 2:
3814         {
3815             outData.push_back(tcu::Vec4(left, down - halfPixel, 0.0f, 1.0f));
3816             outData.push_back(tcu::Vec4(right, down - halfPixel, 0.0f, 1.0f));
3817 
3818             break;
3819         }
3820 
3821         default:
3822             TCU_THROW(InternalError, "Unexpected iteration");
3823         }
3824     }
3825     else
3826     {
3827         const char *iterationComments[] = {"Horizontal lines", "Vertical lines", "Diagonal lines"};
3828         const uint32_t subPixels        = 1u << m_subpixelBits;
3829         const float subPixelSize        = 2.0f * halfPixel / float(subPixels);
3830         const float blockStep           = 16.0f * 2.0f * halfPixel;
3831         const float lineWidth           = 2.0f * halfPixel * getLineWidth();
3832         const float offsets[]           = {
3833             float(1) * blockStep,
3834             float(2) * blockStep + halfPixel,
3835             float(3) * blockStep + 0.5f * lineWidth + 2.0f * subPixelSize,
3836             float(4) * blockStep + 0.5f * lineWidth - 2.0f * subPixelSize,
3837         };
3838 
3839         iterationComment = iterationComments[iteration];
3840 
3841         outData.reserve(DE_LENGTH_OF_ARRAY(offsets));
3842 
3843         switch (iteration)
3844         {
3845         case 0:
3846         {
3847             for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
3848             {
3849                 outData.push_back(tcu::Vec4(left + halfPixel, up + offsets[lineNdx], 0.0f, 1.0f));
3850                 outData.push_back(tcu::Vec4(right - halfPixel, up + offsets[lineNdx], 0.0f, 1.0f));
3851             }
3852 
3853             break;
3854         }
3855 
3856         case 1:
3857         {
3858             for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
3859             {
3860                 outData.push_back(tcu::Vec4(left + offsets[lineNdx], up + halfPixel, 0.0f, 1.0f));
3861                 outData.push_back(tcu::Vec4(left + offsets[lineNdx], down - halfPixel, 0.0f, 1.0f));
3862             }
3863 
3864             break;
3865         }
3866 
3867         case 2:
3868         {
3869             for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
3870             {
3871                 outData.push_back(tcu::Vec4(left + offsets[lineNdx], up + halfPixel, 0.0f, 1.0f));
3872                 outData.push_back(tcu::Vec4(right - halfPixel, down - offsets[lineNdx], 0.0f, 1.0f));
3873             }
3874 
3875             break;
3876         }
3877 
3878         default:
3879             TCU_THROW(InternalError, "Unexpected iteration");
3880         }
3881     }
3882 
3883     DE_ASSERT(outData.size() % 2 == 0);
3884     outLines.resize(outData.size() / 2);
3885     for (size_t lineNdx = 0; lineNdx < outLines.size(); ++lineNdx)
3886     {
3887         outLines[lineNdx].positions[0] = outData[2 * lineNdx + 0];
3888         outLines[lineNdx].positions[1] = outData[2 * lineNdx + 1];
3889     }
3890 
3891     // log
3892     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Testing " << iterationComment << " "
3893                                         << "with rendering " << outLines.size()
3894                                         << " line(s):" << tcu::TestLog::EndMessage;
3895 
3896     for (int ndx = 0; ndx < (int)outLines.size(); ++ndx)
3897     {
3898         const uint32_t multiplier = m_renderSize / 2;
3899 
3900         m_context.getTestContext().getLog()
3901             << tcu::TestLog::Message << "Line " << (ndx + 1) << ":"
3902             << "\n\t" << outLines[ndx].positions[0] << " == " << (float(multiplier) * outLines[ndx].positions[0]) << "/"
3903             << multiplier << "\n\t" << outLines[ndx].positions[1]
3904             << " == " << (float(multiplier) * outLines[ndx].positions[1]) << "/" << multiplier
3905             << tcu::TestLog::EndMessage;
3906     }
3907 }
3908 
generateDegenerateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)3909 void ConservativeLineTestInstance::generateDegenerateLines(int iteration, std::vector<tcu::Vec4> &outData,
3910                                                            std::vector<LineSceneSpec::SceneLine> &outLines)
3911 {
3912     const bool isOverestimate =
3913         m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
3914     const float pixelSize           = 2.0f / float(m_renderSize);
3915     const uint32_t subPixels        = 1u << m_context.getDeviceProperties().limits.subPixelPrecisionBits;
3916     const float subPixelSize        = pixelSize / float(subPixels);
3917     const char *iterationComments[] = {"Horizontal line", "Vertical line", "Diagonal line"};
3918 
3919     outData.clear();
3920 
3921     if (isOverestimate)
3922     {
3923         const float extraOverestimationSize = getExtraOverestimationSize(
3924             m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
3925         const float totalOverestimate =
3926             m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
3927         const float totalOverestimateInSubPixels = deFloatCeil(totalOverestimate * float(subPixels));
3928         const float overestimate                 = subPixelSize * totalOverestimateInSubPixels;
3929         const float overestimateSafetyMargin     = subPixelSize * 0.125f;
3930         const float margin                       = overestimate + overestimateSafetyMargin;
3931         const float originOffset                 = -1.0f + 1 * pixelSize;
3932         const float originLeft                   = originOffset + margin;
3933         const float originRight                  = originOffset + margin + 0.25f * subPixelSize;
3934         const float originUp                     = originOffset + margin;
3935         const float originDown                   = originOffset + margin + 0.25f * subPixelSize;
3936 
3937         switch (iteration)
3938         {
3939         case 0:
3940         {
3941             outData.push_back(tcu::Vec4(originLeft, originUp, 0.0f, 1.0f));
3942             outData.push_back(tcu::Vec4(originRight, originUp, 0.0f, 1.0f));
3943 
3944             break;
3945         }
3946 
3947         case 1:
3948         {
3949             outData.push_back(tcu::Vec4(originLeft, originUp, 0.0f, 1.0f));
3950             outData.push_back(tcu::Vec4(originLeft, originDown, 0.0f, 1.0f));
3951 
3952             break;
3953         }
3954 
3955         case 2:
3956         {
3957             outData.push_back(tcu::Vec4(originLeft, originUp, 0.0f, 1.0f));
3958             outData.push_back(tcu::Vec4(originRight, originDown, 0.0f, 1.0f));
3959 
3960             break;
3961         }
3962 
3963         default:
3964             TCU_THROW(InternalError, "Unexpected iteration");
3965         }
3966     }
3967     else
3968     {
3969         size_t rowStart = 3 * getIteration();
3970         size_t rowEnd   = 3 * (getIteration() + 1);
3971 
3972         for (size_t rowNdx = rowStart; rowNdx < rowEnd; ++rowNdx)
3973             for (size_t colNdx = 0; colNdx < 3 * 3; ++colNdx)
3974             {
3975                 const float originOffsetY = -1.0f + float(4 * (1 + rowNdx)) * pixelSize;
3976                 const float originOffsetX = -1.0f + float(4 * (1 + colNdx)) * pixelSize;
3977                 const float x0            = float(rowNdx % 3);
3978                 const float y0            = float(rowNdx / 3);
3979                 const float x1            = float(colNdx % 3);
3980                 const float y1            = float(colNdx / 3);
3981                 const tcu::Vec4 p0 =
3982                     tcu::Vec4(originOffsetX + x0 * pixelSize / 2.0f, originOffsetY + y0 * pixelSize / 2.0f, 0.0f, 1.0f);
3983                 const tcu::Vec4 p1 =
3984                     tcu::Vec4(originOffsetX + x1 * pixelSize / 2.0f, originOffsetY + y1 * pixelSize / 2.0f, 0.0f, 1.0f);
3985 
3986                 if (x0 == x1 && y0 == y1)
3987                     continue;
3988 
3989                 outData.push_back(p0);
3990                 outData.push_back(p1);
3991             }
3992     }
3993 
3994     outLines.resize(outData.size() / 2);
3995 
3996     for (size_t ndx = 0; ndx < outLines.size(); ++ndx)
3997     {
3998         outLines[ndx].positions[0] = outData[2 * ndx + 0];
3999         outLines[ndx].positions[1] = outData[2 * ndx + 1];
4000     }
4001 
4002     // log
4003     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Testing " << iterationComments[iteration] << " "
4004                                         << "with rendering " << outLines.size()
4005                                         << " line(s):" << tcu::TestLog::EndMessage;
4006 
4007     for (int ndx = 0; ndx < (int)outLines.size(); ++ndx)
4008     {
4009         const uint32_t multiplierInt  = m_renderSize / 2;
4010         const uint32_t multiplierFrac = subPixels;
4011         std::string coordsString;
4012 
4013         for (size_t vertexNdx = 0; vertexNdx < 2; ++vertexNdx)
4014         {
4015             const tcu::Vec4 &pos = outLines[ndx].positions[vertexNdx];
4016             std::ostringstream coordsFloat;
4017             std::ostringstream coordsNatural;
4018 
4019             for (int coordNdx = 0; coordNdx < 2; ++coordNdx)
4020             {
4021                 const char *sep   = (coordNdx < 1) ? "," : "";
4022                 const float coord = pos[coordNdx];
4023                 const char sign   = deSign(coord) < 0 ? '-' : '+';
4024                 const float m     = deFloatFloor(float(multiplierInt) * deFloatAbs(coord));
4025                 const float r     = deFloatFrac(float(multiplierInt) * deFloatAbs(coord)) * float(multiplierFrac);
4026 
4027                 coordsFloat << std::fixed << std::setw(13) << std::setprecision(10) << coord << sep;
4028                 coordsNatural << sign << '(' << m << '+' << r << '/' << multiplierFrac << ')' << sep;
4029             }
4030 
4031             coordsString +=
4032                 "\n\t[" + coordsFloat.str() + "] == [" + coordsNatural.str() + "] / " + de::toString(multiplierInt);
4033         }
4034 
4035         m_context.getTestContext().getLog()
4036             << tcu::TestLog::Message << "Line " << (ndx + 1) << ':' << coordsString << tcu::TestLog::EndMessage;
4037     }
4038 }
4039 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,VkPrimitiveTopology primitiveTopology)4040 void ConservativeLineTestInstance::drawPrimitives(tcu::Surface &result, const std::vector<tcu::Vec4> &vertexData,
4041                                                   VkPrimitiveTopology primitiveTopology)
4042 {
4043     if (m_conservativeTestConfig.degeneratePrimitives)
4044     {
4045         // Set provoking vertex color to white
4046         tcu::Vec4 colorProvoking(1.0f, 1.0f, 1.0f, 1.0f);
4047         tcu::Vec4 colorOther(0.0f, 1.0f, 1.0f, 1.0f);
4048         std::vector<tcu::Vec4> colorData;
4049 
4050         colorData.reserve(vertexData.size());
4051 
4052         for (size_t vertexNdx = 0; vertexNdx < vertexData.size(); ++vertexNdx)
4053             if (vertexNdx % 2 == 0)
4054                 colorData.push_back(colorProvoking);
4055             else
4056                 colorData.push_back(colorOther);
4057 
4058         BaseRenderingTestInstance::drawPrimitives(result, vertexData, colorData, primitiveTopology);
4059     }
4060     else
4061         BaseRenderingTestInstance::drawPrimitives(result, vertexData, primitiveTopology);
4062 }
4063 
compareAndVerify(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)4064 bool ConservativeLineTestInstance::compareAndVerify(std::vector<LineSceneSpec::SceneLine> &lines,
4065                                                     tcu::Surface &resultImage, std::vector<tcu::Vec4> &drawBuffer)
4066 {
4067     DE_UNREF(drawBuffer);
4068 
4069     switch (m_conservativeTestConfig.conservativeRasterizationMode)
4070     {
4071     case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
4072     {
4073         if (m_conservativeTestConfig.degeneratePrimitives)
4074             return compareAndVerifyOverestimatedDegenerate(lines, resultImage);
4075         else
4076             return compareAndVerifyOverestimatedNormal(lines, resultImage);
4077     }
4078     case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
4079     {
4080         if (m_conservativeTestConfig.degeneratePrimitives)
4081             return compareAndVerifyUnderestimatedDegenerate(lines, resultImage);
4082         else
4083             return compareAndVerifyUnderestimatedNormal(lines, resultImage);
4084     }
4085 
4086     default:
4087         TCU_THROW(InternalError, "Unknown conservative rasterization mode");
4088     }
4089 }
4090 
compareAndVerifyOverestimatedNormal(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)4091 bool ConservativeLineTestInstance::compareAndVerifyOverestimatedNormal(std::vector<LineSceneSpec::SceneLine> &lines,
4092                                                                        tcu::Surface &resultImage)
4093 {
4094     DE_UNREF(lines);
4095 
4096     const int b                          = 3; // bar width
4097     const int w                          = resultImage.getWidth() - 1;
4098     const int h                          = resultImage.getHeight() - 1;
4099     const int xStarts[]                  = {1, 1, 1};
4100     const int xEnds[]                    = {w - 1, b, w - 1};
4101     const int yStarts[]                  = {1, 1, h - b};
4102     const int yEnds[]                    = {b, h - 1, h - 1};
4103     const int xStart                     = xStarts[getIteration()];
4104     const int xEnd                       = xEnds[getIteration()];
4105     const int yStart                     = yStarts[getIteration()];
4106     const int yEnd                       = yEnds[getIteration()];
4107     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
4108     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
4109     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
4110     tcu::TestLog &log                    = m_context.getTestContext().getLog();
4111     int errX                             = 0;
4112     int errY                             = 0;
4113     uint32_t errValue                    = 0;
4114     bool result                          = true;
4115 
4116     DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
4117 
4118     for (int y = yStart; result && y < yEnd; ++y)
4119         for (int x = xStart; result && x < xEnd; ++x)
4120         {
4121             if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
4122             {
4123                 result   = false;
4124                 errX     = x;
4125                 errY     = y;
4126                 errValue = resultImage.getPixel(x, y).getPacked();
4127 
4128                 break;
4129             }
4130         }
4131 
4132     if (!result)
4133     {
4134         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
4135 
4136         for (int y = 0; y < errorMask.getHeight(); ++y)
4137             for (int x = 0; x < errorMask.getWidth(); ++x)
4138                 errorMask.setPixel(x, y, backgroundColor);
4139 
4140         for (int y = yStart; y < yEnd; ++y)
4141             for (int x = xStart; x < xEnd; ++x)
4142             {
4143                 if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
4144                     errorMask.setPixel(x, y, unexpectedPixelColor);
4145             }
4146 
4147         log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x"
4148             << std::hex << errValue << tcu::TestLog::EndMessage;
4149         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4150             << tcu::TestLog::Image("Result", "Result", resultImage)
4151             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
4152     }
4153     else
4154     {
4155         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4156         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4157             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
4158     }
4159 
4160     return result;
4161 }
4162 
compareAndVerifyOverestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)4163 bool ConservativeLineTestInstance::compareAndVerifyOverestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> &lines,
4164                                                                            tcu::Surface &resultImage)
4165 {
4166     DE_UNREF(lines);
4167 
4168     const char *iterationComments[]      = {"Horizontal line", "Vertical line", "Diagonal line"};
4169     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
4170     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
4171     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
4172     tcu::TestLog &log                    = m_context.getTestContext().getLog();
4173     bool result                          = true;
4174     tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
4175 
4176     for (int y = 0; y < resultImage.getHeight(); ++y)
4177         for (int x = 0; x < resultImage.getWidth(); ++x)
4178             referenceImage.setPixel(x, y, backgroundColor);
4179 
4180     if (m_conservativeRasterizationProperties.degenerateLinesRasterized)
4181     {
4182         log << tcu::TestLog::Message << "Lines expected to be rasterized with white color" << tcu::TestLog::EndMessage;
4183 
4184         // This pixel will alway be covered due to the placement of the line.
4185         referenceImage.setPixel(1, 1, foregroundColor);
4186 
4187         // Additional pixels will be covered based on the extra bloat added to the primitive.
4188         const float extraOverestimation = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
4189                                                                      m_conservativeRasterizationProperties);
4190         const int xExtent               = 1 + int((extraOverestimation * 2.0f) + 0.5f);
4191         const int yExtent               = xExtent;
4192 
4193         for (int y = 0; y <= yExtent; ++y)
4194             for (int x = 0; x <= xExtent; ++x)
4195                 referenceImage.setPixel(x, y, foregroundColor);
4196     }
4197     else
4198         log << tcu::TestLog::Message << "Lines expected to be culled" << tcu::TestLog::EndMessage;
4199 
4200     for (int y = 0; result && y < resultImage.getHeight(); ++y)
4201         for (int x = 0; result && x < resultImage.getWidth(); ++x)
4202         {
4203             if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4204             {
4205                 result = false;
4206 
4207                 break;
4208             }
4209         }
4210 
4211     if (!result)
4212     {
4213         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
4214 
4215         for (int y = 0; y < errorMask.getHeight(); ++y)
4216             for (int x = 0; x < errorMask.getWidth(); ++x)
4217             {
4218                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4219                     errorMask.setPixel(x, y, unexpectedPixelColor);
4220                 else
4221                     errorMask.setPixel(x, y, backgroundColor);
4222             }
4223 
4224         log << tcu::TestLog::Message << "Invalid pixels found for mode " << iterationComments[getIteration()]
4225             << tcu::TestLog::EndMessage;
4226         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4227             << tcu::TestLog::Image("Result", "Result", resultImage)
4228             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
4229             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
4230     }
4231     else
4232     {
4233         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4234         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4235             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
4236     }
4237 
4238     return result;
4239 }
4240 
compareAndVerifyUnderestimatedNormal(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)4241 bool ConservativeLineTestInstance::compareAndVerifyUnderestimatedNormal(std::vector<LineSceneSpec::SceneLine> &lines,
4242                                                                         tcu::Surface &resultImage)
4243 {
4244     DE_UNREF(lines);
4245 
4246     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
4247     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
4248     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
4249     tcu::TestLog &log                    = m_context.getTestContext().getLog();
4250     int errX                             = -1;
4251     int errY                             = -1;
4252     tcu::RGBA errValue;
4253     bool result = true;
4254     tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
4255 
4256     DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
4257 
4258     for (int y = 0; y < referenceImage.getHeight(); ++y)
4259         for (int x = 0; x < referenceImage.getWidth(); ++x)
4260             referenceImage.setPixel(x, y, backgroundColor);
4261 
4262     if (getLineWidth() > 1.0f)
4263     {
4264         const tcu::IVec2 viewportSize(resultImage.getWidth(), resultImage.getHeight());
4265 
4266         for (size_t lineNdx = 0; lineNdx < lines.size(); ++lineNdx)
4267             for (int y = 0; y < resultImage.getHeight(); ++y)
4268                 for (int x = 0; x < resultImage.getWidth(); ++x)
4269                 {
4270                     if (calculateUnderestimateLineCoverage(lines[lineNdx].positions[0], lines[lineNdx].positions[1],
4271                                                            getLineWidth(), tcu::IVec2(x, y),
4272                                                            viewportSize) == tcu::COVERAGE_FULL)
4273                         referenceImage.setPixel(x, y, foregroundColor);
4274                 }
4275     }
4276 
4277     for (int y = 0; result && y < resultImage.getHeight(); ++y)
4278         for (int x = 0; result && x < resultImage.getWidth(); ++x)
4279         {
4280             if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4281             {
4282                 result   = false;
4283                 errX     = x;
4284                 errY     = y;
4285                 errValue = resultImage.getPixel(x, y);
4286 
4287                 break;
4288             }
4289         }
4290 
4291     if (!result)
4292     {
4293         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
4294 
4295         for (int y = 0; y < errorMask.getHeight(); ++y)
4296             for (int x = 0; x < errorMask.getWidth(); ++x)
4297                 errorMask.setPixel(x, y, backgroundColor);
4298 
4299         for (int y = 0; y < errorMask.getHeight(); ++y)
4300             for (int x = 0; x < errorMask.getWidth(); ++x)
4301             {
4302                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4303                     errorMask.setPixel(x, y, unexpectedPixelColor);
4304             }
4305 
4306         log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY
4307             << " errValue=" << errValue << tcu::TestLog::EndMessage;
4308         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4309             << tcu::TestLog::Image("Result", "Result", resultImage)
4310             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
4311             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
4312     }
4313     else
4314     {
4315         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4316         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4317             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
4318     }
4319 
4320     return result;
4321 }
4322 
compareAndVerifyUnderestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)4323 bool ConservativeLineTestInstance::compareAndVerifyUnderestimatedDegenerate(
4324     std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage)
4325 {
4326     DE_UNREF(lines);
4327 
4328     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
4329     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
4330     tcu::TestLog &log                    = m_context.getTestContext().getLog();
4331     bool result                          = true;
4332     tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
4333 
4334     for (int y = 0; y < resultImage.getHeight(); ++y)
4335         for (int x = 0; x < resultImage.getWidth(); ++x)
4336             referenceImage.setPixel(x, y, backgroundColor);
4337 
4338     log << tcu::TestLog::Message << "No lines expected to be rasterized" << tcu::TestLog::EndMessage;
4339 
4340     for (int y = 0; result && y < resultImage.getHeight(); ++y)
4341         for (int x = 0; result && x < resultImage.getWidth(); ++x)
4342         {
4343             if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4344             {
4345                 result = false;
4346 
4347                 break;
4348             }
4349         }
4350 
4351     if (!result)
4352     {
4353         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
4354 
4355         for (int y = 0; y < errorMask.getHeight(); ++y)
4356             for (int x = 0; x < errorMask.getWidth(); ++x)
4357             {
4358                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4359                     errorMask.setPixel(x, y, unexpectedPixelColor);
4360                 else
4361                     errorMask.setPixel(x, y, backgroundColor);
4362             }
4363 
4364         log << tcu::TestLog::Message << "Invalid pixels found" << tcu::TestLog::EndMessage;
4365         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4366             << tcu::TestLog::Image("Result", "Result", resultImage)
4367             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
4368             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
4369     }
4370     else
4371     {
4372         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4373         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4374             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
4375     }
4376 
4377     return result;
4378 }
4379 
4380 const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativeLineTestInstance::
initRasterizationConservativeStateCreateInfo(void)4381     initRasterizationConservativeStateCreateInfo(void)
4382 {
4383     const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
4384                                                                      m_conservativeRasterizationProperties);
4385     std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> result;
4386 
4387     result.reserve(getIterationCount());
4388 
4389     for (int iteration = 0; iteration < getIterationCount(); ++iteration)
4390     {
4391         const VkPipelineRasterizationConservativeStateCreateInfoEXT rasterizationConservativeStateCreateInfo = {
4392             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, //  VkStructureType sType;
4393             DE_NULL,                                                                     //  const void* pNext;
4394             (VkPipelineRasterizationConservativeStateCreateFlagsEXT)0, //  VkPipelineRasterizationConservativeStateCreateFlagsEXT flags;
4395             m_conservativeTestConfig
4396                 .conservativeRasterizationMode, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
4397             extraOverestimationSize             //  float extraPrimitiveOverestimationSize;
4398         };
4399 
4400         result.push_back(rasterizationConservativeStateCreateInfo);
4401     }
4402 
4403     return result;
4404 }
4405 
4406 const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativeLineTestInstance::
initRasterizationStateCreateInfo(void)4407     initRasterizationStateCreateInfo(void)
4408 {
4409     std::vector<VkPipelineRasterizationStateCreateInfo> result;
4410 
4411     result.reserve(getIterationCount());
4412 
4413     for (int iteration = 0; iteration < getIterationCount(); ++iteration)
4414     {
4415         const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
4416             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //  VkStructureType sType;
4417             &m_rasterizationConservativeStateCreateInfo[iteration],     //  const void* pNext;
4418             0,                               //  VkPipelineRasterizationStateCreateFlags flags;
4419             false,                           //  VkBool32 depthClampEnable;
4420             false,                           //  VkBool32 rasterizerDiscardEnable;
4421             VK_POLYGON_MODE_FILL,            //  VkPolygonMode polygonMode;
4422             VK_CULL_MODE_NONE,               //  VkCullModeFlags cullMode;
4423             VK_FRONT_FACE_COUNTER_CLOCKWISE, //  VkFrontFace frontFace;
4424             VK_FALSE,                        //  VkBool32 depthBiasEnable;
4425             0.0f,                            //  float depthBiasConstantFactor;
4426             0.0f,                            //  float depthBiasClamp;
4427             0.0f,                            //  float depthBiasSlopeFactor;
4428             getLineWidth(),                  //  float lineWidth;
4429         };
4430 
4431         result.push_back(rasterizationStateCreateInfo);
4432     }
4433 
4434     return result;
4435 }
4436 
getRasterizationStateCreateInfo(void) const4437 const VkPipelineRasterizationStateCreateInfo *ConservativeLineTestInstance::getRasterizationStateCreateInfo(void) const
4438 {
4439     return &m_rasterizationStateCreateInfo[getIteration()];
4440 }
4441 
getLineRasterizationStateCreateInfo(void)4442 const VkPipelineRasterizationLineStateCreateInfoEXT *ConservativeLineTestInstance::getLineRasterizationStateCreateInfo(
4443     void)
4444 {
4445     return DE_NULL;
4446 }
4447 
4448 class ConservativePointTestInstance : public PointTestInstance
4449 {
4450 public:
ConservativePointTestInstance(Context & context,ConservativeTestConfig conservativeTestConfig,VkSampleCountFlagBits sampleCount)4451     ConservativePointTestInstance(Context &context, ConservativeTestConfig conservativeTestConfig,
4452                                   VkSampleCountFlagBits sampleCount)
4453         : PointTestInstance(context, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, sampleCount,
4454                             LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,
4455                             LineStippleFactorCase::DEFAULT, 0, conservativeTestConfig.resolution,
4456                             conservativeTestConfig.lineWidth)
4457         , m_conservativeTestConfig(conservativeTestConfig)
4458         , m_conservativeRasterizationProperties(context.getConservativeRasterizationPropertiesEXT())
4459         , m_rasterizationConservativeStateCreateInfo(initRasterizationConservativeStateCreateInfo())
4460         , m_rasterizationStateCreateInfo(initRasterizationStateCreateInfo())
4461         , m_renderStart()
4462         , m_renderEnd()
4463     {
4464     }
4465 
4466     void generatePoints(int iteration, std::vector<tcu::Vec4> &outData,
4467                         std::vector<PointSceneSpec::ScenePoint> &outPoints);
4468     const VkPipelineRasterizationStateCreateInfo *getRasterizationStateCreateInfo(void) const;
4469 
4470 protected:
4471     virtual const VkPipelineRasterizationLineStateCreateInfoEXT *getLineRasterizationStateCreateInfo(void);
4472 
4473     virtual bool compareAndVerify(std::vector<PointSceneSpec::ScenePoint> &points, tcu::Surface &resultImage,
4474                                   std::vector<tcu::Vec4> &drawBuffer);
4475     virtual bool compareAndVerifyOverestimated(std::vector<PointSceneSpec::ScenePoint> &points,
4476                                                tcu::Surface &resultImage);
4477     virtual bool compareAndVerifyUnderestimated(std::vector<PointSceneSpec::ScenePoint> &points,
4478                                                 tcu::Surface &resultImage);
4479 
4480 private:
4481     const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> initRasterizationConservativeStateCreateInfo(
4482         void);
4483     const std::vector<VkPipelineRasterizationStateCreateInfo> initRasterizationStateCreateInfo(void);
4484 
4485     const ConservativeTestConfig m_conservativeTestConfig;
4486     const VkPhysicalDeviceConservativeRasterizationPropertiesEXT m_conservativeRasterizationProperties;
4487     const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> m_rasterizationConservativeStateCreateInfo;
4488     const std::vector<VkPipelineRasterizationStateCreateInfo> m_rasterizationStateCreateInfo;
4489     std::vector<int> m_renderStart;
4490     std::vector<int> m_renderEnd;
4491 };
4492 
generatePoints(int iteration,std::vector<tcu::Vec4> & outData,std::vector<PointSceneSpec::ScenePoint> & outPoints)4493 void ConservativePointTestInstance::generatePoints(int iteration, std::vector<tcu::Vec4> &outData,
4494                                                    std::vector<PointSceneSpec::ScenePoint> &outPoints)
4495 {
4496     const float pixelSize = 2.0f / float(m_renderSize);
4497     const bool isOverestimate =
4498         m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
4499 
4500     m_renderStart.clear();
4501     m_renderEnd.clear();
4502 
4503     if (isOverestimate)
4504     {
4505         const float extraOverestimationSize = getExtraOverestimationSize(
4506             m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
4507         const float overestimate =
4508             m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
4509         const float halfRenderAreaSize = overestimate + 0.5f;
4510         const float pointCenterOffset  = 2.0f + 0.5f * float(iteration) + halfRenderAreaSize;
4511         const float pointEdgeStart     = pointCenterOffset - halfRenderAreaSize;
4512         const float pointEdgeEnd       = pointEdgeStart + 2 * halfRenderAreaSize;
4513         const int renderStart = int(deFloatFloor(pointEdgeStart)) + int((deFloatFrac(pointEdgeStart) > 0.0f) ? 0 : -1);
4514         const int renderEnd   = int(deFloatCeil(pointEdgeEnd)) + int((deFloatFrac(pointEdgeEnd) > 0.0f) ? 0 : 1);
4515 
4516         outData.push_back(
4517             tcu::Vec4(-1.0f + pixelSize * pointCenterOffset, -1.0f + pixelSize * pointCenterOffset, 0.0f, 1.0f));
4518 
4519         m_renderStart.push_back(renderStart);
4520         m_renderEnd.push_back(renderEnd);
4521     }
4522     else
4523     {
4524         const float pointSize          = m_conservativeTestConfig.lineWidth;
4525         const float halfRenderAreaSize = pointSize / 2.0f;
4526 
4527         switch (iteration)
4528         {
4529         case 0:
4530         {
4531             const float pointCenterOffset = (pointSize + 1.0f + deFloatFrac(pointSize)) / 2.0f;
4532             const float pointEdgeStart    = pointCenterOffset - halfRenderAreaSize;
4533             const float pointEdgeEnd      = pointEdgeStart + 2.0f * halfRenderAreaSize;
4534             const int renderStart         = (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart));
4535             const int renderEnd           = (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd));
4536 
4537             outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
4538 
4539             m_renderStart.push_back(renderStart);
4540             m_renderEnd.push_back(renderEnd);
4541 
4542             break;
4543         }
4544 
4545         case 1:
4546         {
4547             const float subPixelSize      = 1.0f / float(1u << (m_subpixelBits - 1));
4548             const float pointBottomLeft   = 1.0f - subPixelSize;
4549             const float pointCenterOffset = pointBottomLeft + pointSize / 2.0f;
4550             const float pointEdgeStart    = pointCenterOffset - halfRenderAreaSize;
4551             const float pointEdgeEnd      = pointEdgeStart + 2.0f * halfRenderAreaSize;
4552             const int renderStart         = (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart));
4553             const int renderEnd           = (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd));
4554 
4555             outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
4556 
4557             m_renderStart.push_back(renderStart);
4558             m_renderEnd.push_back(renderEnd);
4559 
4560             break;
4561         }
4562 
4563         case 2:
4564         {
4565             // Edges of a point are considered not covered. Top-left coverage rule is not applicable for underestimate rasterization.
4566             const float pointCenterOffset = (pointSize + deFloatFrac(pointSize)) / 2.0f;
4567             const float pointEdgeStart    = pointCenterOffset - halfRenderAreaSize;
4568             const float pointEdgeEnd      = pointEdgeStart + 2.0f * halfRenderAreaSize;
4569             const int renderStart         = (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart)) + 1;
4570             const int renderEnd           = (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd)) - 1;
4571 
4572             outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
4573 
4574             m_renderStart.push_back(renderStart);
4575             m_renderEnd.push_back(renderEnd);
4576 
4577             break;
4578         }
4579 
4580         default:
4581             TCU_THROW(InternalError, "Unexpected iteration");
4582         }
4583     }
4584 
4585     outPoints.resize(outData.size());
4586     for (size_t ndx = 0; ndx < outPoints.size(); ++ndx)
4587     {
4588         outPoints[ndx].position  = outData[ndx];
4589         outPoints[ndx].pointSize = getPointSize();
4590     }
4591 
4592     // log
4593     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Testing conservative point rendering "
4594                                         << "with rendering " << outPoints.size()
4595                                         << " points(s):" << tcu::TestLog::EndMessage;
4596     for (int ndx = 0; ndx < (int)outPoints.size(); ++ndx)
4597     {
4598         const uint32_t multiplier = m_renderSize / 2;
4599 
4600         m_context.getTestContext().getLog()
4601             << tcu::TestLog::Message << "Point " << (ndx + 1) << ":"
4602             << "\n\t" << outPoints[ndx].position << " == " << (float(multiplier) * outPoints[ndx].position) << "/"
4603             << multiplier << tcu::TestLog::EndMessage;
4604     }
4605 }
4606 
compareAndVerify(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)4607 bool ConservativePointTestInstance::compareAndVerify(std::vector<PointSceneSpec::ScenePoint> &points,
4608                                                      tcu::Surface &resultImage, std::vector<tcu::Vec4> &drawBuffer)
4609 {
4610     DE_UNREF(drawBuffer);
4611 
4612     switch (m_conservativeTestConfig.conservativeRasterizationMode)
4613     {
4614     case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
4615     {
4616         return compareAndVerifyOverestimated(points, resultImage);
4617     }
4618     case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
4619     {
4620         return compareAndVerifyUnderestimated(points, resultImage);
4621     }
4622 
4623     default:
4624         TCU_THROW(InternalError, "Unknown conservative rasterization mode");
4625     }
4626 }
4627 
compareAndVerifyOverestimated(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage)4628 bool ConservativePointTestInstance::compareAndVerifyOverestimated(std::vector<PointSceneSpec::ScenePoint> &points,
4629                                                                   tcu::Surface &resultImage)
4630 {
4631     DE_UNREF(points);
4632 
4633     const char *iterationComments[]      = {"Edges and corners", "Partial coverage", "Edges and corners"};
4634     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
4635     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
4636     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
4637     tcu::TestLog &log                    = m_context.getTestContext().getLog();
4638     int errX                             = 0;
4639     int errY                             = 0;
4640     uint32_t errValue                    = 0;
4641     bool result                          = true;
4642 
4643     log << tcu::TestLog::Message << "Points expected to be rasterized with white color" << tcu::TestLog::EndMessage;
4644     log << tcu::TestLog::Message << "Testing " << iterationComments[getIteration()] << tcu::TestLog::EndMessage;
4645 
4646     for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4647     {
4648         const int renderStart = m_renderStart[renderAreaNdx];
4649         const int renderEnd   = m_renderEnd[renderAreaNdx];
4650 
4651         for (int y = renderStart; result && y < renderEnd; ++y)
4652             for (int x = renderStart; result && x < renderEnd; ++x)
4653             {
4654                 if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
4655                 {
4656                     result   = false;
4657                     errX     = x;
4658                     errY     = y;
4659                     errValue = resultImage.getPixel(x, y).getPacked();
4660 
4661                     break;
4662                 }
4663             }
4664     }
4665 
4666     if (!result)
4667     {
4668         tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
4669         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
4670         std::ostringstream css;
4671 
4672         for (int y = 0; y < resultImage.getHeight(); ++y)
4673             for (int x = 0; x < resultImage.getWidth(); ++x)
4674                 referenceImage.setPixel(x, y, backgroundColor);
4675 
4676         for (size_t renderAreaNdx = 0; renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4677         {
4678             const int renderStart = m_renderStart[renderAreaNdx];
4679             const int renderEnd   = m_renderEnd[renderAreaNdx];
4680 
4681             for (int y = renderStart; y < renderEnd; ++y)
4682                 for (int x = renderStart; x < renderEnd; ++x)
4683                     referenceImage.setPixel(x, y, foregroundColor);
4684         }
4685 
4686         for (int y = 0; y < errorMask.getHeight(); ++y)
4687             for (int x = 0; x < errorMask.getWidth(); ++x)
4688             {
4689                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4690                     errorMask.setPixel(x, y, unexpectedPixelColor);
4691                 else
4692                     errorMask.setPixel(x, y, backgroundColor);
4693             }
4694 
4695         css << std::endl;
4696         for (size_t renderAreaNdx = 0; renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4697         {
4698             const int renderStart = m_renderStart[renderAreaNdx];
4699             const int renderEnd   = m_renderEnd[renderAreaNdx];
4700 
4701             css << "[" << renderStart << "," << renderEnd << ") x [" << renderStart << "," << renderEnd << ")"
4702                 << std::endl;
4703         }
4704 
4705         log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x"
4706             << std::hex << errValue << tcu::TestLog::EndMessage;
4707         log << tcu::TestLog::Message << "Expected area(s) to be filled:" << css.str() << tcu::TestLog::EndMessage;
4708         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4709             << tcu::TestLog::Image("Result", "Result", resultImage)
4710             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
4711             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
4712     }
4713     else
4714     {
4715         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4716         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4717             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
4718     }
4719 
4720     return result;
4721 }
4722 
compareAndVerifyUnderestimated(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage)4723 bool ConservativePointTestInstance::compareAndVerifyUnderestimated(std::vector<PointSceneSpec::ScenePoint> &points,
4724                                                                    tcu::Surface &resultImage)
4725 {
4726     DE_UNREF(points);
4727 
4728     const char *iterationComments[]      = {"Full coverage", "Full coverage with subpixel", "Exact coverage"};
4729     const tcu::RGBA backgroundColor      = tcu::RGBA(0, 0, 0, 255);
4730     const tcu::RGBA foregroundColor      = tcu::RGBA(255, 255, 255, 255);
4731     const tcu::RGBA unexpectedPixelColor = tcu::RGBA(255, 0, 0, 255);
4732     tcu::TestLog &log                    = m_context.getTestContext().getLog();
4733     int errX                             = 0;
4734     int errY                             = 0;
4735     uint32_t errValue                    = 0;
4736     bool result                          = true;
4737     tcu::Surface referenceImage(resultImage.getWidth(), resultImage.getHeight());
4738 
4739     log << tcu::TestLog::Message << "Points expected to be rasterized with white color" << tcu::TestLog::EndMessage;
4740     log << tcu::TestLog::Message << "Testing " << iterationComments[getIteration()] << tcu::TestLog::EndMessage;
4741 
4742     for (int y = 0; y < resultImage.getHeight(); ++y)
4743         for (int x = 0; x < resultImage.getWidth(); ++x)
4744             referenceImage.setPixel(x, y, backgroundColor);
4745 
4746     for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4747     {
4748         const int renderStart = m_renderStart[renderAreaNdx];
4749         const int renderEnd   = m_renderEnd[renderAreaNdx];
4750 
4751         for (int y = renderStart; y < renderEnd; ++y)
4752             for (int x = renderStart; x < renderEnd; ++x)
4753                 referenceImage.setPixel(x, y, foregroundColor);
4754     }
4755 
4756     for (int y = 0; result && y < resultImage.getHeight(); ++y)
4757         for (int x = 0; result && x < resultImage.getWidth(); ++x)
4758         {
4759             if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4760             {
4761                 result   = false;
4762                 errX     = x;
4763                 errY     = y;
4764                 errValue = resultImage.getPixel(x, y).getPacked();
4765 
4766                 break;
4767             }
4768         }
4769 
4770     if (!result)
4771     {
4772         tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
4773         std::ostringstream css;
4774 
4775         for (int y = 0; y < errorMask.getHeight(); ++y)
4776             for (int x = 0; x < errorMask.getWidth(); ++x)
4777             {
4778                 if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4779                     errorMask.setPixel(x, y, unexpectedPixelColor);
4780                 else
4781                     errorMask.setPixel(x, y, backgroundColor);
4782             }
4783 
4784         css << std::endl;
4785         for (size_t renderAreaNdx = 0; renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4786         {
4787             const int renderStart = m_renderStart[renderAreaNdx];
4788             const int renderEnd   = m_renderEnd[renderAreaNdx];
4789 
4790             css << "[" << renderStart << "," << renderEnd << ") x [" << renderStart << "," << renderEnd << ")"
4791                 << std::endl;
4792         }
4793 
4794         log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x"
4795             << std::hex << errValue << tcu::TestLog::EndMessage;
4796         log << tcu::TestLog::Message << "Expected area(s) to be filled:" << css.str() << tcu::TestLog::EndMessage;
4797         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4798             << tcu::TestLog::Image("Result", "Result", resultImage)
4799             << tcu::TestLog::Image("Reference", "Reference", referenceImage)
4800             << tcu::TestLog::Image("ErrorMask", "ErrorMask", errorMask) << tcu::TestLog::EndImageSet;
4801     }
4802     else
4803     {
4804         log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4805         log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4806             << tcu::TestLog::Image("Result", "Result", resultImage) << tcu::TestLog::EndImageSet;
4807     }
4808 
4809     return result;
4810 }
4811 
4812 const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativePointTestInstance::
initRasterizationConservativeStateCreateInfo(void)4813     initRasterizationConservativeStateCreateInfo(void)
4814 {
4815     const float extraOverestimationSize = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize,
4816                                                                      m_conservativeRasterizationProperties);
4817     std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> result;
4818 
4819     result.reserve(getIterationCount());
4820 
4821     for (int iteration = 0; iteration < getIterationCount(); ++iteration)
4822     {
4823         const VkPipelineRasterizationConservativeStateCreateInfoEXT rasterizationConservativeStateCreateInfo = {
4824             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT, //  VkStructureType sType;
4825             DE_NULL,                                                                     //  const void* pNext;
4826             (VkPipelineRasterizationConservativeStateCreateFlagsEXT)0, //  VkPipelineRasterizationConservativeStateCreateFlagsEXT flags;
4827             m_conservativeTestConfig
4828                 .conservativeRasterizationMode, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
4829             extraOverestimationSize             //  float extraPrimitiveOverestimationSize;
4830         };
4831 
4832         result.push_back(rasterizationConservativeStateCreateInfo);
4833     }
4834 
4835     return result;
4836 }
4837 
4838 const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativePointTestInstance::
initRasterizationStateCreateInfo(void)4839     initRasterizationStateCreateInfo(void)
4840 {
4841     std::vector<VkPipelineRasterizationStateCreateInfo> result;
4842 
4843     result.reserve(getIterationCount());
4844 
4845     for (int iteration = 0; iteration < getIterationCount(); ++iteration)
4846     {
4847         const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
4848             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //  VkStructureType sType;
4849             &m_rasterizationConservativeStateCreateInfo[iteration],     //  const void* pNext;
4850             0,                               //  VkPipelineRasterizationStateCreateFlags flags;
4851             false,                           //  VkBool32 depthClampEnable;
4852             false,                           //  VkBool32 rasterizerDiscardEnable;
4853             VK_POLYGON_MODE_FILL,            //  VkPolygonMode polygonMode;
4854             VK_CULL_MODE_NONE,               //  VkCullModeFlags cullMode;
4855             VK_FRONT_FACE_COUNTER_CLOCKWISE, //  VkFrontFace frontFace;
4856             VK_FALSE,                        //  VkBool32 depthBiasEnable;
4857             0.0f,                            //  float depthBiasConstantFactor;
4858             0.0f,                            //  float depthBiasClamp;
4859             0.0f,                            //  float depthBiasSlopeFactor;
4860             0.0f,                            //  float lineWidth;
4861         };
4862 
4863         result.push_back(rasterizationStateCreateInfo);
4864     }
4865 
4866     return result;
4867 }
4868 
getRasterizationStateCreateInfo(void) const4869 const VkPipelineRasterizationStateCreateInfo *ConservativePointTestInstance::getRasterizationStateCreateInfo(void) const
4870 {
4871     return &m_rasterizationStateCreateInfo[getIteration()];
4872 }
4873 
getLineRasterizationStateCreateInfo(void)4874 const VkPipelineRasterizationLineStateCreateInfoEXT *ConservativePointTestInstance::getLineRasterizationStateCreateInfo(
4875     void)
4876 {
4877     return DE_NULL;
4878 }
4879 
4880 template <typename ConcreteTestInstance>
4881 class WidenessTestCase : public BaseRenderingTestCase
4882 {
4883 public:
WidenessTestCase(tcu::TestContext & context,const std::string & name,PrimitiveWideness wideness,PrimitiveStrictness strictness,bool isLineTest,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,LineStippleFactorCase stippleFactor=LineStippleFactorCase::DEFAULT,uint32_t additionalRenderSize=0)4884     WidenessTestCase(tcu::TestContext &context, const std::string &name, PrimitiveWideness wideness,
4885                      PrimitiveStrictness strictness, bool isLineTest, VkSampleCountFlagBits sampleCount,
4886                      LineStipple stipple, VkLineRasterizationModeEXT lineRasterizationMode,
4887                      LineStippleFactorCase stippleFactor = LineStippleFactorCase::DEFAULT,
4888                      uint32_t additionalRenderSize       = 0)
4889         : BaseRenderingTestCase(context, name, sampleCount)
4890         , m_wideness(wideness)
4891         , m_strictness(strictness)
4892         , m_isLineTest(isLineTest)
4893         , m_stipple(stipple)
4894         , m_lineRasterizationMode(lineRasterizationMode)
4895         , m_stippleFactor(stippleFactor)
4896         , m_additionalRenderSize(additionalRenderSize)
4897     {
4898     }
4899 
createInstance(Context & context) const4900     virtual TestInstance *createInstance(Context &context) const
4901     {
4902         return new ConcreteTestInstance(context, m_wideness, m_strictness, m_sampleCount, m_stipple,
4903                                         m_lineRasterizationMode, m_stippleFactor, m_additionalRenderSize);
4904     }
4905 
checkSupport(Context & context) const4906     virtual void checkSupport(Context &context) const
4907     {
4908         if (m_isLineTest)
4909         {
4910             if (m_stipple == LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY)
4911                 context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
4912 
4913             if (m_wideness == PRIMITIVEWIDENESS_WIDE)
4914                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
4915 
4916             switch (m_lineRasterizationMode)
4917             {
4918             default:
4919                 TCU_THROW(InternalError, "Unknown line rasterization mode");
4920 
4921             case VK_LINE_RASTERIZATION_MODE_KHR_LAST:
4922             {
4923                 if (m_strictness == PRIMITIVESTRICTNESS_STRICT)
4924                     if (!context.getDeviceProperties().limits.strictLines)
4925                         TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
4926 
4927                 if (m_strictness == PRIMITIVESTRICTNESS_NONSTRICT)
4928                     if (context.getDeviceProperties().limits.strictLines)
4929                         TCU_THROW(NotSupportedError, "Nonstrict rasterization is not supported");
4930 
4931                 break;
4932             }
4933 
4934             case VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT:
4935             {
4936                 if (!context.getDeviceProperties().limits.strictLines)
4937                     TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
4938 
4939                 if (getLineStippleEnable() && !context.getLineRasterizationFeatures().stippledRectangularLines)
4940                     TCU_THROW(NotSupportedError, "Stippled rectangular lines not supported");
4941                 break;
4942             }
4943 
4944             case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT:
4945             {
4946                 if (!context.getLineRasterizationFeatures().rectangularLines)
4947                     TCU_THROW(NotSupportedError, "Rectangular lines not supported");
4948 
4949                 if (getLineStippleEnable() && !context.getLineRasterizationFeatures().stippledRectangularLines)
4950                     TCU_THROW(NotSupportedError, "Stippled rectangular lines not supported");
4951                 break;
4952             }
4953 
4954             case VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT:
4955             {
4956                 if (!context.getLineRasterizationFeatures().bresenhamLines)
4957                     TCU_THROW(NotSupportedError, "Bresenham lines not supported");
4958 
4959                 if (getLineStippleEnable() && !context.getLineRasterizationFeatures().stippledBresenhamLines)
4960                     TCU_THROW(NotSupportedError, "Stippled Bresenham lines not supported");
4961                 break;
4962             }
4963 
4964             case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT:
4965             {
4966                 if (!context.getLineRasterizationFeatures().smoothLines)
4967                     TCU_THROW(NotSupportedError, "Smooth lines not supported");
4968 
4969                 if (getLineStippleEnable() && !context.getLineRasterizationFeatures().stippledSmoothLines)
4970                     TCU_THROW(NotSupportedError, "Stippled smooth lines not supported");
4971                 break;
4972             }
4973             }
4974         }
4975         else
4976         {
4977             if (m_wideness == PRIMITIVEWIDENESS_WIDE)
4978                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
4979         }
4980     }
4981 
getLineStippleEnable(void) const4982     bool getLineStippleEnable(void) const
4983     {
4984         return m_stipple != LINESTIPPLE_DISABLED;
4985     }
4986 
4987 protected:
4988     const PrimitiveWideness m_wideness;
4989     const PrimitiveStrictness m_strictness;
4990     const bool m_isLineTest;
4991     const LineStipple m_stipple;
4992     const VkLineRasterizationModeEXT m_lineRasterizationMode;
4993     const LineStippleFactorCase m_stippleFactor;
4994     const uint32_t m_additionalRenderSize;
4995 };
4996 
4997 class LinesTestInstance : public BaseLineTestInstance
4998 {
4999 public:
LinesTestInstance(Context & context,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,LineStippleFactorCase stippleFactor,uint32_t additionalRenderSize=0)5000     LinesTestInstance(Context &context, PrimitiveWideness wideness, PrimitiveStrictness strictness,
5001                       VkSampleCountFlagBits sampleCount, LineStipple stipple,
5002                       VkLineRasterizationModeEXT lineRasterizationMode, LineStippleFactorCase stippleFactor,
5003                       uint32_t additionalRenderSize = 0)
5004         : BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, wideness, strictness, sampleCount, stipple,
5005                                lineRasterizationMode, stippleFactor, additionalRenderSize)
5006     {
5007     }
5008 
getWrongTopology(void) const5009     VkPrimitiveTopology getWrongTopology(void) const override
5010     {
5011         return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
5012     }
getRightTopology(void) const5013     VkPrimitiveTopology getRightTopology(void) const override
5014     {
5015         return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
5016     }
5017     void generateLines(int iteration, std::vector<tcu::Vec4> &outData,
5018                        std::vector<LineSceneSpec::SceneLine> &outLines) override;
5019 };
5020 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)5021 void LinesTestInstance::generateLines(int iteration, std::vector<tcu::Vec4> &outData,
5022                                       std::vector<LineSceneSpec::SceneLine> &outLines)
5023 {
5024     outData.resize(8);
5025 
5026     switch (iteration)
5027     {
5028     case 0:
5029         // \note: these values are chosen arbitrarily
5030         outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
5031         outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
5032         outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
5033         outData[3] = tcu::Vec4(-0.3f, 0.2f, 0.0f, 1.0f);
5034         outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
5035         outData[5] = tcu::Vec4(0.1f, 0.5f, 0.0f, 1.0f);
5036         outData[6] = tcu::Vec4(0.75f, -0.4f, 0.0f, 1.0f);
5037         outData[7] = tcu::Vec4(0.3f, 0.8f, 0.0f, 1.0f);
5038         break;
5039 
5040     case 1:
5041         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
5042         outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
5043         outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
5044         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
5045         outData[4] = tcu::Vec4(0.88f, 0.9f, 0.0f, 1.0f);
5046         outData[5] = tcu::Vec4(0.18f, -0.2f, 0.0f, 1.0f);
5047         outData[6] = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
5048         outData[7] = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
5049         break;
5050 
5051     case 2:
5052         outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
5053         outData[1] = tcu::Vec4(1.1f, -0.9f, 0.0f, 1.0f);
5054         outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
5055         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
5056         outData[4] = tcu::Vec4(0.88f, 0.7f, 0.0f, 1.0f);
5057         outData[5] = tcu::Vec4(0.8f, -0.7f, 0.0f, 1.0f);
5058         outData[6] = tcu::Vec4(0.9f, 0.7f, 0.0f, 1.0f);
5059         outData[7] = tcu::Vec4(-0.9f, 0.7f, 0.0f, 1.0f);
5060         break;
5061     }
5062 
5063     outLines.resize(4);
5064     outLines[0].positions[0] = outData[0];
5065     outLines[0].positions[1] = outData[1];
5066     outLines[1].positions[0] = outData[2];
5067     outLines[1].positions[1] = outData[3];
5068     outLines[2].positions[0] = outData[4];
5069     outLines[2].positions[1] = outData[5];
5070     outLines[3].positions[0] = outData[6];
5071     outLines[3].positions[1] = outData[7];
5072 
5073     // log
5074     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outLines.size()
5075                                         << " lines(s): (width = " << getLineWidth() << ")" << tcu::TestLog::EndMessage;
5076     for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
5077     {
5078         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line " << (lineNdx + 1) << ":"
5079                                             << "\n\t" << outLines[lineNdx].positions[0] << "\n\t"
5080                                             << outLines[lineNdx].positions[1] << tcu::TestLog::EndMessage;
5081     }
5082 }
5083 
5084 class LineStripTestInstance : public BaseLineTestInstance
5085 {
5086 public:
LineStripTestInstance(Context & context,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,LineStippleFactorCase stippleFactor,uint32_t)5087     LineStripTestInstance(Context &context, PrimitiveWideness wideness, PrimitiveStrictness strictness,
5088                           VkSampleCountFlagBits sampleCount, LineStipple stipple,
5089                           VkLineRasterizationModeEXT lineRasterizationMode, LineStippleFactorCase stippleFactor,
5090                           uint32_t)
5091         : BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, wideness, strictness, sampleCount, stipple,
5092                                lineRasterizationMode, stippleFactor)
5093     {
5094     }
5095 
getWrongTopology(void) const5096     VkPrimitiveTopology getWrongTopology(void) const override
5097     {
5098         return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
5099     }
getRightTopology(void) const5100     VkPrimitiveTopology getRightTopology(void) const override
5101     {
5102         return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
5103     }
5104     void generateLines(int iteration, std::vector<tcu::Vec4> &outData,
5105                        std::vector<LineSceneSpec::SceneLine> &outLines) override;
5106 };
5107 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)5108 void LineStripTestInstance::generateLines(int iteration, std::vector<tcu::Vec4> &outData,
5109                                           std::vector<LineSceneSpec::SceneLine> &outLines)
5110 {
5111     outData.resize(4);
5112 
5113     switch (iteration)
5114     {
5115     case 0:
5116         // \note: these values are chosen arbitrarily
5117         outData[0] = tcu::Vec4(0.01f, 0.0f, 0.0f, 1.0f);
5118         outData[1] = tcu::Vec4(0.5f, 0.2f, 0.0f, 1.0f);
5119         outData[2] = tcu::Vec4(0.46f, 0.3f, 0.0f, 1.0f);
5120         outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f);
5121         break;
5122 
5123     case 1:
5124         outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
5125         outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f);
5126         outData[2] = tcu::Vec4(0.11f, -0.2f, 0.0f, 1.0f);
5127         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
5128         break;
5129 
5130     case 2:
5131         outData[0] = tcu::Vec4(-0.9f, -0.3f, 0.0f, 1.0f);
5132         outData[1] = tcu::Vec4(0.9f, -0.9f, 0.0f, 1.0f);
5133         outData[2] = tcu::Vec4(0.7f, -0.1f, 0.0f, 1.0f);
5134         outData[3] = tcu::Vec4(0.11f, 0.2f, 0.0f, 1.0f);
5135         break;
5136     }
5137 
5138     outLines.resize(3);
5139     outLines[0].positions[0] = outData[0];
5140     outLines[0].positions[1] = outData[1];
5141     outLines[1].positions[0] = outData[1];
5142     outLines[1].positions[1] = outData[2];
5143     outLines[2].positions[0] = outData[2];
5144     outLines[2].positions[1] = outData[3];
5145 
5146     // log
5147     m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << getLineWidth()
5148                                         << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
5149     for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
5150     {
5151         m_context.getTestContext().getLog()
5152             << tcu::TestLog::Message << "\t" << outData[vtxNdx] << tcu::TestLog::EndMessage;
5153     }
5154 }
5155 
5156 class FillRuleTestInstance : public BaseRenderingTestInstance
5157 {
5158 public:
5159     enum FillRuleCaseType
5160     {
5161         FILLRULECASE_BASIC = 0,
5162         FILLRULECASE_REVERSED,
5163         FILLRULECASE_CLIPPED_FULL,
5164         FILLRULECASE_CLIPPED_PARTIAL,
5165         FILLRULECASE_PROJECTED,
5166 
5167         FILLRULECASE_LAST
5168     };
5169     FillRuleTestInstance(Context &context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount);
5170     virtual tcu::TestStatus iterate(void);
5171 
5172 private:
5173     virtual const VkPipelineColorBlendStateCreateInfo *getColorBlendStateCreateInfo(void) const;
5174     int getRenderSize(FillRuleCaseType type) const;
5175     int getNumIterations(FillRuleCaseType type) const;
5176     void generateTriangles(int iteration, std::vector<tcu::Vec4> &outData) const;
5177 
5178     const FillRuleCaseType m_caseType;
5179     int m_iteration;
5180     const int m_iterationCount;
5181     bool m_allIterationsPassed;
5182 };
5183 
FillRuleTestInstance(Context & context,FillRuleCaseType type,VkSampleCountFlagBits sampleCount)5184 FillRuleTestInstance::FillRuleTestInstance(Context &context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount)
5185     : BaseRenderingTestInstance(context, sampleCount, getRenderSize(type))
5186     , m_caseType(type)
5187     , m_iteration(0)
5188     , m_iterationCount(getNumIterations(type))
5189     , m_allIterationsPassed(true)
5190 {
5191     DE_ASSERT(type < FILLRULECASE_LAST);
5192 }
5193 
iterate(void)5194 tcu::TestStatus FillRuleTestInstance::iterate(void)
5195 {
5196     const std::string iterationDescription =
5197         "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
5198     const tcu::ScopedLogSection section(m_context.getTestContext().getLog(), iterationDescription,
5199                                         iterationDescription);
5200     tcu::IVec4 colorBits     = tcu::getTextureFormatBitDepth(getTextureFormat());
5201     const int thresholdRed   = 1 << (8 - colorBits[0]);
5202     const int thresholdGreen = 1 << (8 - colorBits[1]);
5203     const int thresholdBlue  = 1 << (8 - colorBits[2]);
5204     tcu::Surface resultImage(m_renderSize, m_renderSize);
5205     std::vector<tcu::Vec4> drawBuffer;
5206 
5207     generateTriangles(m_iteration, drawBuffer);
5208 
5209     // draw image
5210     {
5211         const std::vector<tcu::Vec4> colorBuffer(drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
5212 
5213         m_context.getTestContext().getLog()
5214             << tcu::TestLog::Message
5215             << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments."
5216             << tcu::TestLog::EndMessage;
5217 
5218         drawPrimitives(resultImage, drawBuffer, colorBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
5219     }
5220 
5221     // verify no overdraw
5222     {
5223         const tcu::RGBA triangleColor = tcu::RGBA(127, 127, 127, 255);
5224         bool overdraw                 = false;
5225 
5226         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage;
5227 
5228         for (int y = 0; y < resultImage.getHeight(); ++y)
5229             for (int x = 0; x < resultImage.getWidth(); ++x)
5230             {
5231                 const tcu::RGBA color = resultImage.getPixel(x, y);
5232 
5233                 // color values are greater than triangle color? Allow lower values for multisampled edges and background.
5234                 if ((color.getRed() - triangleColor.getRed()) > thresholdRed ||
5235                     (color.getGreen() - triangleColor.getGreen()) > thresholdGreen ||
5236                     (color.getBlue() - triangleColor.getBlue()) > thresholdBlue)
5237                     overdraw = true;
5238             }
5239 
5240         // results
5241         if (!overdraw)
5242             m_context.getTestContext().getLog()
5243                 << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage;
5244         else
5245         {
5246             m_context.getTestContext().getLog()
5247                 << tcu::TestLog::Message << "Overlapping fragments detected, image is not valid."
5248                 << tcu::TestLog::EndMessage;
5249             m_allIterationsPassed = false;
5250         }
5251     }
5252 
5253     // verify no missing fragments in the full viewport case
5254     if (m_caseType == FILLRULECASE_CLIPPED_FULL)
5255     {
5256         bool missingFragments = false;
5257 
5258         m_context.getTestContext().getLog()
5259             << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage;
5260 
5261         for (int y = 0; y < resultImage.getHeight(); ++y)
5262             for (int x = 0; x < resultImage.getWidth(); ++x)
5263             {
5264                 const tcu::RGBA color = resultImage.getPixel(x, y);
5265 
5266                 // black? (background)
5267                 if (color.getRed() <= thresholdRed || color.getGreen() <= thresholdGreen ||
5268                     color.getBlue() <= thresholdBlue)
5269                     missingFragments = true;
5270             }
5271 
5272         // results
5273         if (!missingFragments)
5274             m_context.getTestContext().getLog()
5275                 << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage;
5276         else
5277         {
5278             m_context.getTestContext().getLog()
5279                 << tcu::TestLog::Message << "Missing fragments detected, image is not valid."
5280                 << tcu::TestLog::EndMessage;
5281 
5282             m_allIterationsPassed = false;
5283         }
5284     }
5285 
5286     m_context.getTestContext().getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
5287                                         << tcu::TestLog::Image("Result", "Result", resultImage)
5288                                         << tcu::TestLog::EndImageSet;
5289 
5290     // result
5291     if (++m_iteration == m_iterationCount)
5292     {
5293         if (m_allIterationsPassed)
5294             return tcu::TestStatus::pass("Pass");
5295         else
5296             return tcu::TestStatus::fail("Found invalid pixels");
5297     }
5298     else
5299         return tcu::TestStatus::incomplete();
5300 }
5301 
getRenderSize(FillRuleCaseType type) const5302 int FillRuleTestInstance::getRenderSize(FillRuleCaseType type) const
5303 {
5304     if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
5305         return RESOLUTION_POT / 4;
5306     else
5307         return RESOLUTION_POT;
5308 }
5309 
getNumIterations(FillRuleCaseType type) const5310 int FillRuleTestInstance::getNumIterations(FillRuleCaseType type) const
5311 {
5312     if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
5313         return 15;
5314     else
5315         return 2;
5316 }
5317 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData) const5318 void FillRuleTestInstance::generateTriangles(int iteration, std::vector<tcu::Vec4> &outData) const
5319 {
5320     switch (m_caseType)
5321     {
5322     case FILLRULECASE_BASIC:
5323     case FILLRULECASE_REVERSED:
5324     case FILLRULECASE_PROJECTED:
5325     {
5326         const int numRows    = 4;
5327         const int numColumns = 4;
5328         const float quadSide = 0.15f;
5329         de::Random rnd(0xabcd);
5330 
5331         outData.resize(6 * numRows * numColumns);
5332 
5333         for (int col = 0; col < numColumns; ++col)
5334             for (int row = 0; row < numRows; ++row)
5335             {
5336                 const tcu::Vec2 center = tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f,
5337                                                    ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f);
5338                 const float rotation   = (float)(iteration * numColumns * numRows + col * numRows + row) /
5339                                        (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
5340                 const tcu::Vec2 sideH   = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
5341                 const tcu::Vec2 sideV   = tcu::Vec2(sideH.y(), -sideH.x());
5342                 const tcu::Vec2 quad[4] = {
5343                     center + sideH + sideV,
5344                     center + sideH - sideV,
5345                     center - sideH - sideV,
5346                     center - sideH + sideV,
5347                 };
5348 
5349                 if (m_caseType == FILLRULECASE_BASIC)
5350                 {
5351                     outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
5352                     outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
5353                     outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
5354                     outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
5355                     outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
5356                     outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
5357                 }
5358                 else if (m_caseType == FILLRULECASE_REVERSED)
5359                 {
5360                     outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
5361                     outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
5362                     outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
5363                     outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
5364                     outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
5365                     outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
5366                 }
5367                 else if (m_caseType == FILLRULECASE_PROJECTED)
5368                 {
5369                     const float w0 = rnd.getFloat(0.1f, 4.0f);
5370                     const float w1 = rnd.getFloat(0.1f, 4.0f);
5371                     const float w2 = rnd.getFloat(0.1f, 4.0f);
5372                     const float w3 = rnd.getFloat(0.1f, 4.0f);
5373 
5374                     outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
5375                     outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
5376                     outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
5377                     outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
5378                     outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
5379                     outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
5380                 }
5381                 else
5382                     DE_ASSERT(false);
5383             }
5384 
5385         break;
5386     }
5387 
5388     case FILLRULECASE_CLIPPED_PARTIAL:
5389     case FILLRULECASE_CLIPPED_FULL:
5390     {
5391         const float quadSide = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
5392         const tcu::Vec2 center =
5393             (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
5394         const float rotation    = (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
5395         const tcu::Vec2 sideH   = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
5396         const tcu::Vec2 sideV   = tcu::Vec2(sideH.y(), -sideH.x());
5397         const tcu::Vec2 quad[4] = {
5398             center + sideH + sideV,
5399             center + sideH - sideV,
5400             center - sideH - sideV,
5401             center - sideH + sideV,
5402         };
5403 
5404         outData.resize(6);
5405         outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
5406         outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
5407         outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
5408         outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
5409         outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
5410         outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
5411         break;
5412     }
5413 
5414     default:
5415         DE_ASSERT(false);
5416     }
5417 }
5418 
getColorBlendStateCreateInfo(void) const5419 const VkPipelineColorBlendStateCreateInfo *FillRuleTestInstance::getColorBlendStateCreateInfo(void) const
5420 {
5421     static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
5422         true,                // VkBool32 blendEnable;
5423         VK_BLEND_FACTOR_ONE, // VkBlend srcBlendColor;
5424         VK_BLEND_FACTOR_ONE, // VkBlend destBlendColor;
5425         VK_BLEND_OP_ADD,     // VkBlendOp blendOpColor;
5426         VK_BLEND_FACTOR_ONE, // VkBlend srcBlendAlpha;
5427         VK_BLEND_FACTOR_ONE, // VkBlend destBlendAlpha;
5428         VK_BLEND_OP_ADD,     // VkBlendOp blendOpAlpha;
5429         (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
5430          VK_COLOR_COMPONENT_A_BIT) // VkChannelFlags channelWriteMask;
5431     };
5432 
5433     static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
5434         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
5435         DE_NULL,                                                  // const void* pNext;
5436         0,                                                        // VkPipelineColorBlendStateCreateFlags flags;
5437         false,                                                    // VkBool32 logicOpEnable;
5438         VK_LOGIC_OP_COPY,                                         // VkLogicOp logicOp;
5439         1u,                                                       // uint32_t attachmentCount;
5440         &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
5441         {0.0f, 0.0f, 0.0f, 0.0f},   // float blendConst[4];
5442     };
5443 
5444     return &colorBlendStateParams;
5445 }
5446 
5447 class FillRuleTestCase : public BaseRenderingTestCase
5448 {
5449 public:
FillRuleTestCase(tcu::TestContext & context,const std::string & name,FillRuleTestInstance::FillRuleCaseType type,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)5450     FillRuleTestCase(tcu::TestContext &context, const std::string &name, FillRuleTestInstance::FillRuleCaseType type,
5451                      VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
5452         : BaseRenderingTestCase(context, name, sampleCount)
5453         , m_type(type)
5454     {
5455     }
5456 
createInstance(Context & context) const5457     virtual TestInstance *createInstance(Context &context) const
5458     {
5459         return new FillRuleTestInstance(context, m_type, m_sampleCount);
5460     }
5461 
5462 protected:
5463     const FillRuleTestInstance::FillRuleCaseType m_type;
5464 };
5465 
5466 class CullingTestInstance : public BaseRenderingTestInstance
5467 {
5468 public:
CullingTestInstance(Context & context,VkCullModeFlags cullMode,VkPrimitiveTopology primitiveTopology,VkFrontFace frontFace,VkPolygonMode polygonMode)5469     CullingTestInstance(Context &context, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology,
5470                         VkFrontFace frontFace, VkPolygonMode polygonMode)
5471         : BaseRenderingTestInstance(context, VK_SAMPLE_COUNT_1_BIT, RESOLUTION_POT)
5472         , m_cullMode(cullMode)
5473         , m_primitiveTopology(primitiveTopology)
5474         , m_frontFace(frontFace)
5475         , m_polygonMode(polygonMode)
5476         , m_multisampling(true)
5477     {
5478     }
5479     virtual const VkPipelineRasterizationStateCreateInfo *getRasterizationStateCreateInfo(void) const;
5480 
5481     tcu::TestStatus iterate(void);
5482 
5483 private:
5484     void generateVertices(std::vector<tcu::Vec4> &outData) const;
5485     void extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5486                           const std::vector<tcu::Vec4> &vertices) const;
5487     void extractLines(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5488                       std::vector<LineSceneSpec::SceneLine> &outLines) const;
5489     void extractPoints(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5490                        std::vector<PointSceneSpec::ScenePoint> &outPoints) const;
5491     bool triangleOrder(const tcu::Vec4 &v0, const tcu::Vec4 &v1, const tcu::Vec4 &v2) const;
5492 
5493     const VkCullModeFlags m_cullMode;
5494     const VkPrimitiveTopology m_primitiveTopology;
5495     const VkFrontFace m_frontFace;
5496     const VkPolygonMode m_polygonMode;
5497     const bool m_multisampling;
5498 };
5499 
iterate(void)5500 tcu::TestStatus CullingTestInstance::iterate(void)
5501 {
5502     DE_ASSERT(m_polygonMode <= VK_POLYGON_MODE_POINT);
5503 
5504     tcu::Surface resultImage(m_renderSize, m_renderSize);
5505     std::vector<tcu::Vec4> drawBuffer;
5506     std::vector<TriangleSceneSpec::SceneTriangle> triangles;
5507     std::vector<PointSceneSpec::ScenePoint> points;
5508     std::vector<LineSceneSpec::SceneLine> lines;
5509 
5510     const InstanceInterface &vk                   = m_context.getInstanceInterface();
5511     const VkPhysicalDevice physicalDevice         = m_context.getPhysicalDevice();
5512     const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice);
5513 
5514     if (!(deviceFeatures.fillModeNonSolid) &&
5515         (m_polygonMode == VK_POLYGON_MODE_LINE || m_polygonMode == VK_POLYGON_MODE_POINT))
5516         TCU_THROW(NotSupportedError, "Wireframe fill modes are not supported");
5517 
5518     // generate scene
5519     generateVertices(drawBuffer);
5520     extractTriangles(triangles, drawBuffer);
5521 
5522     if (m_polygonMode == VK_POLYGON_MODE_LINE)
5523         extractLines(triangles, lines);
5524     else if (m_polygonMode == VK_POLYGON_MODE_POINT)
5525         extractPoints(triangles, points);
5526 
5527     // draw image
5528     {
5529         m_context.getTestContext().getLog()
5530             << tcu::TestLog::Message << "Setting front face to " << m_frontFace << tcu::TestLog::EndMessage;
5531         m_context.getTestContext().getLog()
5532             << tcu::TestLog::Message << "Setting cull face to " << m_cullMode << tcu::TestLog::EndMessage;
5533         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Drawing test pattern (" << m_primitiveTopology
5534                                             << ")" << tcu::TestLog::EndMessage;
5535 
5536         drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
5537     }
5538 
5539     // compare
5540     {
5541         RasterizationArguments args;
5542         tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
5543         bool isCompareOk     = false;
5544 
5545         args.numSamples   = m_multisampling ? 1 : 0;
5546         args.subpixelBits = m_subpixelBits;
5547         args.redBits      = colorBits[0];
5548         args.greenBits    = colorBits[1];
5549         args.blueBits     = colorBits[2];
5550 
5551         switch (m_polygonMode)
5552         {
5553         case VK_POLYGON_MODE_LINE:
5554         {
5555             LineSceneSpec scene;
5556             scene.lineWidth = 0;
5557             scene.lines.swap(lines);
5558             isCompareOk = verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
5559             break;
5560         }
5561         case VK_POLYGON_MODE_POINT:
5562         {
5563             PointSceneSpec scene;
5564             scene.points.swap(points);
5565             isCompareOk = verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
5566             break;
5567         }
5568         default:
5569         {
5570             TriangleSceneSpec scene;
5571             scene.triangles.swap(triangles);
5572             isCompareOk = verifyTriangleGroupRasterization(
5573                 resultImage, scene, args, m_context.getTestContext().getLog(), tcu::VERIFICATIONMODE_WEAK);
5574             break;
5575         }
5576         }
5577 
5578         if (isCompareOk)
5579             return tcu::TestStatus::pass("Pass");
5580         else
5581             return tcu::TestStatus::fail("Incorrect rendering");
5582     }
5583 }
5584 
generateVertices(std::vector<tcu::Vec4> & outData) const5585 void CullingTestInstance::generateVertices(std::vector<tcu::Vec4> &outData) const
5586 {
5587     de::Random rnd(543210);
5588 
5589     outData.resize(6);
5590     for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
5591     {
5592         outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
5593         outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
5594         outData[vtxNdx].z() = 0.0f;
5595         outData[vtxNdx].w() = 1.0f;
5596     }
5597 }
5598 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices) const5599 void CullingTestInstance::extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5600                                            const std::vector<tcu::Vec4> &vertices) const
5601 {
5602     const bool cullDirection =
5603         (m_cullMode == VK_CULL_MODE_FRONT_BIT) ^ (m_frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE);
5604 
5605     // No triangles
5606     if (m_cullMode == VK_CULL_MODE_FRONT_AND_BACK)
5607         return;
5608 
5609     switch (m_primitiveTopology)
5610     {
5611     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5612     {
5613         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
5614         {
5615             const tcu::Vec4 &v0 = vertices[vtxNdx + 0];
5616             const tcu::Vec4 &v1 = vertices[vtxNdx + 1];
5617             const tcu::Vec4 &v2 = vertices[vtxNdx + 2];
5618 
5619             if (triangleOrder(v0, v1, v2) != cullDirection)
5620             {
5621                 TriangleSceneSpec::SceneTriangle tri;
5622                 tri.positions[0]  = v0;
5623                 tri.sharedEdge[0] = false;
5624                 tri.positions[1]  = v1;
5625                 tri.sharedEdge[1] = false;
5626                 tri.positions[2]  = v2;
5627                 tri.sharedEdge[2] = false;
5628 
5629                 outTriangles.push_back(tri);
5630             }
5631         }
5632         break;
5633     }
5634 
5635     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5636     {
5637         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
5638         {
5639             const tcu::Vec4 &v0 = vertices[vtxNdx + 0];
5640             const tcu::Vec4 &v1 = vertices[vtxNdx + 1];
5641             const tcu::Vec4 &v2 = vertices[vtxNdx + 2];
5642 
5643             if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
5644             {
5645                 TriangleSceneSpec::SceneTriangle tri;
5646                 tri.positions[0]  = v0;
5647                 tri.sharedEdge[0] = false;
5648                 tri.positions[1]  = v1;
5649                 tri.sharedEdge[1] = false;
5650                 tri.positions[2]  = v2;
5651                 tri.sharedEdge[2] = false;
5652 
5653                 outTriangles.push_back(tri);
5654             }
5655         }
5656         break;
5657     }
5658 
5659     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5660     {
5661         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
5662         {
5663             const tcu::Vec4 &v0 = vertices[0];
5664             const tcu::Vec4 &v1 = vertices[vtxNdx + 0];
5665             const tcu::Vec4 &v2 = vertices[vtxNdx + 1];
5666 
5667             if (triangleOrder(v0, v1, v2) != cullDirection)
5668             {
5669                 TriangleSceneSpec::SceneTriangle tri;
5670                 tri.positions[0]  = v0;
5671                 tri.sharedEdge[0] = false;
5672                 tri.positions[1]  = v1;
5673                 tri.sharedEdge[1] = false;
5674                 tri.positions[2]  = v2;
5675                 tri.sharedEdge[2] = false;
5676 
5677                 outTriangles.push_back(tri);
5678             }
5679         }
5680         break;
5681     }
5682 
5683     default:
5684         DE_ASSERT(false);
5685     }
5686 }
5687 
extractLines(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,std::vector<LineSceneSpec::SceneLine> & outLines) const5688 void CullingTestInstance::extractLines(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5689                                        std::vector<LineSceneSpec::SceneLine> &outLines) const
5690 {
5691     for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
5692     {
5693         for (int vrtxNdx = 0; vrtxNdx < 2; ++vrtxNdx)
5694         {
5695             LineSceneSpec::SceneLine line;
5696             line.positions[0] = outTriangles.at(triNdx).positions[vrtxNdx];
5697             line.positions[1] = outTriangles.at(triNdx).positions[vrtxNdx + 1];
5698 
5699             outLines.push_back(line);
5700         }
5701         LineSceneSpec::SceneLine line;
5702         line.positions[0] = outTriangles.at(triNdx).positions[2];
5703         line.positions[1] = outTriangles.at(triNdx).positions[0];
5704         outLines.push_back(line);
5705     }
5706 }
5707 
extractPoints(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,std::vector<PointSceneSpec::ScenePoint> & outPoints) const5708 void CullingTestInstance::extractPoints(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5709                                         std::vector<PointSceneSpec::ScenePoint> &outPoints) const
5710 {
5711     for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
5712     {
5713         for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
5714         {
5715             PointSceneSpec::ScenePoint point;
5716             point.position  = outTriangles.at(triNdx).positions[vrtxNdx];
5717             point.pointSize = 1.0f;
5718 
5719             outPoints.push_back(point);
5720         }
5721     }
5722 }
5723 
triangleOrder(const tcu::Vec4 & v0,const tcu::Vec4 & v1,const tcu::Vec4 & v2) const5724 bool CullingTestInstance::triangleOrder(const tcu::Vec4 &v0, const tcu::Vec4 &v1, const tcu::Vec4 &v2) const
5725 {
5726     const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
5727     const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
5728     const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
5729 
5730     // cross
5731     return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) > 0;
5732 }
5733 
getRasterizationStateCreateInfo(void) const5734 const VkPipelineRasterizationStateCreateInfo *CullingTestInstance::getRasterizationStateCreateInfo(void) const
5735 {
5736     static VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
5737         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
5738         DE_NULL,                                                    // const void* pNext;
5739         0,                                                          // VkPipelineRasterizationStateCreateFlags flags;
5740         false,                                                      // VkBool32 depthClipEnable;
5741         false,                                                      // VkBool32 rasterizerDiscardEnable;
5742         VK_POLYGON_MODE_FILL,                                       // VkFillMode fillMode;
5743         VK_CULL_MODE_NONE,                                          // VkCullMode cullMode;
5744         VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // VkFrontFace frontFace;
5745         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
5746         0.0f,                                                       // float depthBias;
5747         0.0f,                                                       // float depthBiasClamp;
5748         0.0f,                                                       // float slopeScaledDepthBias;
5749         getLineWidth(),                                             // float lineWidth;
5750     };
5751 
5752     rasterizationStateCreateInfo.lineWidth   = getLineWidth();
5753     rasterizationStateCreateInfo.cullMode    = m_cullMode;
5754     rasterizationStateCreateInfo.frontFace   = m_frontFace;
5755     rasterizationStateCreateInfo.polygonMode = m_polygonMode;
5756 
5757     return &rasterizationStateCreateInfo;
5758 }
5759 
5760 class CullingTestCase : public BaseRenderingTestCase
5761 {
5762 public:
CullingTestCase(tcu::TestContext & context,const std::string & name,VkCullModeFlags cullMode,VkPrimitiveTopology primitiveTopology,VkFrontFace frontFace,VkPolygonMode polygonMode,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)5763     CullingTestCase(tcu::TestContext &context, const std::string &name, VkCullModeFlags cullMode,
5764                     VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace, VkPolygonMode polygonMode,
5765                     VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
5766         : BaseRenderingTestCase(context, name, sampleCount)
5767         , m_cullMode(cullMode)
5768         , m_primitiveTopology(primitiveTopology)
5769         , m_frontFace(frontFace)
5770         , m_polygonMode(polygonMode)
5771     {
5772     }
5773 
createInstance(Context & context) const5774     virtual TestInstance *createInstance(Context &context) const
5775     {
5776         return new CullingTestInstance(context, m_cullMode, m_primitiveTopology, m_frontFace, m_polygonMode);
5777     }
5778     void checkSupport(Context &context) const;
5779 
5780 protected:
5781     const VkCullModeFlags m_cullMode;
5782     const VkPrimitiveTopology m_primitiveTopology;
5783     const VkFrontFace m_frontFace;
5784     const VkPolygonMode m_polygonMode;
5785 };
5786 
checkSupport(Context & context) const5787 void CullingTestCase::checkSupport(Context &context) const
5788 {
5789 #ifndef CTS_USES_VULKANSC
5790     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
5791     {
5792         const VkPhysicalDevicePortabilitySubsetFeaturesKHR &subsetFeatures = context.getPortabilitySubsetFeatures();
5793         if (m_polygonMode == VK_POLYGON_MODE_POINT && !subsetFeatures.pointPolygons)
5794             TCU_THROW(NotSupportedError,
5795                       "VK_KHR_portability_subset: Point polygons are not supported by this implementation");
5796         if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN && !subsetFeatures.triangleFans)
5797             TCU_THROW(NotSupportedError,
5798                       "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
5799     }
5800 #else
5801     DE_UNREF(context);
5802 #endif // CTS_USES_VULKANSC
5803 }
5804 
5805 class DiscardTestInstance : public BaseRenderingTestInstance
5806 {
5807 public:
DiscardTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,bool queryFragmentShaderInvocations)5808     DiscardTestInstance(Context &context, VkPrimitiveTopology primitiveTopology, bool queryFragmentShaderInvocations)
5809         : BaseRenderingTestInstance(context, VK_SAMPLE_COUNT_1_BIT, RESOLUTION_POT)
5810         , m_primitiveTopology(primitiveTopology)
5811         , m_queryFragmentShaderInvocations(queryFragmentShaderInvocations)
5812     {
5813     }
5814 
5815     virtual const VkPipelineRasterizationStateCreateInfo *getRasterizationStateCreateInfo(void) const;
5816     tcu::TestStatus iterate(void);
5817 
5818 private:
5819     void generateVertices(std::vector<tcu::Vec4> &outData) const;
5820     void extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5821                           const std::vector<tcu::Vec4> &vertices) const;
5822     void extractLines(std::vector<LineSceneSpec::SceneLine> &outLines, const std::vector<tcu::Vec4> &vertices) const;
5823     void extractPoints(std::vector<PointSceneSpec::ScenePoint> &outPoints,
5824                        const std::vector<tcu::Vec4> &vertices) const;
5825     void drawPrimitivesDiscard(tcu::Surface &result, const std::vector<tcu::Vec4> &positionData,
5826                                VkPrimitiveTopology primitiveTopology, Move<VkQueryPool> &queryPool);
5827 
5828     const VkPrimitiveTopology m_primitiveTopology;
5829     const bool m_queryFragmentShaderInvocations;
5830 };
5831 
iterate(void)5832 tcu::TestStatus DiscardTestInstance::iterate(void)
5833 {
5834     const DeviceInterface &vkd = m_context.getDeviceInterface();
5835     const VkDevice vkDevice    = m_context.getDevice();
5836     uint64_t queryResult       = 0u;
5837     tcu::Surface resultImage(m_renderSize, m_renderSize);
5838     std::vector<tcu::Vec4> drawBuffer;
5839     std::vector<PointSceneSpec::ScenePoint> points;
5840     std::vector<LineSceneSpec::SceneLine> lines;
5841     std::vector<TriangleSceneSpec::SceneTriangle> triangles;
5842 
5843     generateVertices(drawBuffer);
5844 
5845     switch (m_primitiveTopology)
5846     {
5847     case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
5848         extractPoints(points, drawBuffer);
5849         break;
5850 
5851     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
5852     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
5853         extractLines(lines, drawBuffer);
5854         break;
5855 
5856     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5857     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5858     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5859         extractTriangles(triangles, drawBuffer);
5860         break;
5861 
5862     default:
5863         DE_ASSERT(false);
5864     }
5865 
5866     const VkQueryPoolCreateInfo queryPoolCreateInfo = {
5867         VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,                    // VkStructureType                    sType
5868         DE_NULL,                                                     // const void*                        pNext
5869         (VkQueryPoolCreateFlags)0,                                   // VkQueryPoolCreateFlags            flags
5870         VK_QUERY_TYPE_PIPELINE_STATISTICS,                           // VkQueryType                        queryType
5871         1u,                                                          // uint32_t                            entryCount
5872         VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT, // VkQueryPipelineStatisticFlags    pipelineStatistics
5873     };
5874 
5875     if (m_queryFragmentShaderInvocations)
5876     {
5877         Move<VkQueryPool> queryPool = createQueryPool(vkd, vkDevice, &queryPoolCreateInfo);
5878 
5879         drawPrimitivesDiscard(resultImage, drawBuffer, m_primitiveTopology, queryPool);
5880         vkd.getQueryPoolResults(vkDevice, *queryPool, 0u, 1u, sizeof(uint64_t), &queryResult, 0u,
5881                                 VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
5882     }
5883     else
5884         BaseRenderingTestInstance::drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
5885 
5886     // compare
5887     {
5888         tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
5889 
5890         const RasterizationArguments args = {
5891             0,                   // int numSamples;
5892             (int)m_subpixelBits, // int subpixelBits;
5893             colorBits[0],        // int redBits;
5894             colorBits[1],        // int greenBits;
5895             colorBits[2]         // int blueBits;
5896         };
5897 
5898         // Empty scene to compare to, primitives should be discarded before rasterization
5899         TriangleSceneSpec scene;
5900 
5901         const bool isCompareOk = verifyTriangleGroupRasterization(
5902             resultImage, scene, args, m_context.getTestContext().getLog(), tcu::VERIFICATIONMODE_STRICT);
5903 
5904         if (isCompareOk)
5905         {
5906             if (m_queryFragmentShaderInvocations && queryResult > 0u)
5907                 return tcu::TestStatus::fail("Fragment shader invocations occured");
5908             else
5909                 return tcu::TestStatus::pass("Pass");
5910         }
5911         else
5912             return tcu::TestStatus::fail("Incorrect rendering");
5913     }
5914 }
5915 
generateVertices(std::vector<tcu::Vec4> & outData) const5916 void DiscardTestInstance::generateVertices(std::vector<tcu::Vec4> &outData) const
5917 {
5918     de::Random rnd(12345);
5919 
5920     outData.resize(6);
5921 
5922     for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
5923     {
5924         outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
5925         outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
5926         outData[vtxNdx].z() = 0.0f;
5927         outData[vtxNdx].w() = 1.0f;
5928     }
5929 }
5930 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices) const5931 void DiscardTestInstance::extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
5932                                            const std::vector<tcu::Vec4> &vertices) const
5933 {
5934     switch (m_primitiveTopology)
5935     {
5936     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5937     {
5938         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
5939         {
5940             TriangleSceneSpec::SceneTriangle tri;
5941             const tcu::Vec4 &v0 = vertices[vtxNdx + 0];
5942             const tcu::Vec4 &v1 = vertices[vtxNdx + 1];
5943             const tcu::Vec4 &v2 = vertices[vtxNdx + 2];
5944 
5945             tri.positions[0] = v0;
5946             tri.positions[1] = v1;
5947             tri.positions[2] = v2;
5948 
5949             outTriangles.push_back(tri);
5950         }
5951 
5952         break;
5953     }
5954 
5955     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5956     {
5957         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
5958         {
5959             TriangleSceneSpec::SceneTriangle tri;
5960             const tcu::Vec4 &v0 = vertices[vtxNdx + 0];
5961             const tcu::Vec4 &v1 = vertices[vtxNdx + 1];
5962             const tcu::Vec4 &v2 = vertices[vtxNdx + 2];
5963 
5964             tri.positions[0] = v0;
5965             tri.positions[1] = v1;
5966             tri.positions[2] = v2;
5967 
5968             outTriangles.push_back(tri);
5969         }
5970 
5971         break;
5972     }
5973 
5974     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5975     {
5976         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
5977         {
5978             TriangleSceneSpec::SceneTriangle tri;
5979             const tcu::Vec4 &v0 = vertices[0];
5980             const tcu::Vec4 &v1 = vertices[vtxNdx + 0];
5981             const tcu::Vec4 &v2 = vertices[vtxNdx + 1];
5982 
5983             tri.positions[0] = v0;
5984             tri.positions[1] = v1;
5985             tri.positions[2] = v2;
5986 
5987             outTriangles.push_back(tri);
5988         }
5989 
5990         break;
5991     }
5992 
5993     default:
5994         DE_ASSERT(false);
5995     }
5996 }
5997 
extractLines(std::vector<LineSceneSpec::SceneLine> & outLines,const std::vector<tcu::Vec4> & vertices) const5998 void DiscardTestInstance::extractLines(std::vector<LineSceneSpec::SceneLine> &outLines,
5999                                        const std::vector<tcu::Vec4> &vertices) const
6000 {
6001     switch (m_primitiveTopology)
6002     {
6003     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
6004     {
6005         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
6006         {
6007             LineSceneSpec::SceneLine line;
6008 
6009             line.positions[0] = vertices[vtxNdx + 0];
6010             line.positions[1] = vertices[vtxNdx + 1];
6011 
6012             outLines.push_back(line);
6013         }
6014 
6015         break;
6016     }
6017 
6018     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
6019     {
6020         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
6021         {
6022             LineSceneSpec::SceneLine line;
6023 
6024             line.positions[0] = vertices[vtxNdx + 0];
6025             line.positions[1] = vertices[vtxNdx + 1];
6026 
6027             outLines.push_back(line);
6028         }
6029 
6030         break;
6031     }
6032 
6033     default:
6034         DE_ASSERT(false);
6035     }
6036 }
6037 
extractPoints(std::vector<PointSceneSpec::ScenePoint> & outPoints,const std::vector<tcu::Vec4> & vertices) const6038 void DiscardTestInstance::extractPoints(std::vector<PointSceneSpec::ScenePoint> &outPoints,
6039                                         const std::vector<tcu::Vec4> &vertices) const
6040 {
6041     for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
6042     {
6043         for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
6044         {
6045             PointSceneSpec::ScenePoint point;
6046 
6047             point.position  = vertices[vrtxNdx];
6048             point.pointSize = 1.0f;
6049 
6050             outPoints.push_back(point);
6051         }
6052     }
6053 }
6054 
getRasterizationStateCreateInfo(void) const6055 const VkPipelineRasterizationStateCreateInfo *DiscardTestInstance::getRasterizationStateCreateInfo(void) const
6056 {
6057     static const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
6058         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
6059         NULL,                                                       // const void* pNext;
6060         0,                                                          // VkPipelineRasterizationStateCreateFlags flags;
6061         VK_FALSE,                                                   // VkBool32 depthClipEnable;
6062         VK_TRUE,                                                    // VkBool32 rasterizerDiscardEnable;
6063         VK_POLYGON_MODE_FILL,                                       // VkFillMode fillMode;
6064         VK_CULL_MODE_NONE,                                          // VkCullMode cullMode;
6065         VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // VkFrontFace frontFace;
6066         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
6067         0.0f,                                                       // float depthBias;
6068         0.0f,                                                       // float depthBiasClamp;
6069         0.0f,                                                       // float slopeScaledDepthBias;
6070         getLineWidth(),                                             // float lineWidth;
6071     };
6072 
6073     return &rasterizationStateCreateInfo;
6074 }
6075 
drawPrimitivesDiscard(tcu::Surface & result,const std::vector<tcu::Vec4> & positionData,VkPrimitiveTopology primitiveTopology,Move<VkQueryPool> & queryPool)6076 void DiscardTestInstance::drawPrimitivesDiscard(tcu::Surface &result, const std::vector<tcu::Vec4> &positionData,
6077                                                 VkPrimitiveTopology primitiveTopology, Move<VkQueryPool> &queryPool)
6078 {
6079     const DeviceInterface &vkd                  = m_context.getDeviceInterface();
6080     const VkDevice vkDevice                     = m_context.getDevice();
6081     const VkPhysicalDeviceProperties properties = m_context.getDeviceProperties();
6082     const VkQueue queue                         = m_context.getUniversalQueue();
6083     const uint32_t queueFamilyIndex             = m_context.getUniversalQueueFamilyIndex();
6084     Allocator &allocator                        = m_context.getDefaultAllocator();
6085 
6086     const size_t attributeBatchSize       = positionData.size() * sizeof(tcu::Vec4);
6087     const VkDeviceSize vertexBufferOffset = 0;
6088     de::MovePtr<Allocation> vertexBufferMemory;
6089     Move<VkBuffer> vertexBuffer;
6090     Move<VkCommandBuffer> commandBuffer;
6091     Move<VkPipeline> graphicsPipeline;
6092 
6093     if (attributeBatchSize > properties.limits.maxVertexInputAttributeOffset)
6094     {
6095         std::stringstream message;
6096         message << "Larger vertex input attribute offset is needed (" << attributeBatchSize
6097                 << ") than the available maximum (" << properties.limits.maxVertexInputAttributeOffset << ").";
6098         TCU_THROW(NotSupportedError, message.str().c_str());
6099     }
6100 
6101     // Create Graphics Pipeline
6102     {
6103         const VkVertexInputBindingDescription vertexInputBindingDescription = {
6104             0u,                         // uint32_t binding;
6105             sizeof(tcu::Vec4),          // uint32_t strideInBytes;
6106             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate;
6107         };
6108 
6109         const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
6110             {
6111                 0u,                            // uint32_t location;
6112                 0u,                            // uint32_t binding;
6113                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
6114                 0u                             // uint32_t offsetInBytes;
6115             },
6116             {
6117                 1u,                            // uint32_t location;
6118                 0u,                            // uint32_t binding;
6119                 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
6120                 (uint32_t)attributeBatchSize   // uint32_t offsetInBytes;
6121             }};
6122 
6123         const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
6124             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
6125             DE_NULL,                                                   // const void* pNext;
6126             0,                                                         // VkPipelineVertexInputStateCreateFlags flags;
6127             1u,                                                        // uint32_t bindingCount;
6128             &vertexInputBindingDescription,  // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
6129             2u,                              // uint32_t attributeCount;
6130             vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
6131         };
6132 
6133         const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(m_renderSize)));
6134         const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(m_renderSize)));
6135 
6136         const VkPipelineMultisampleStateCreateInfo multisampleStateParams = {
6137             VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
6138             DE_NULL,                                                  // const void* pNext;
6139             0u,                                                       // VkPipelineMultisampleStateCreateFlags flags;
6140             m_sampleCount,                                            // VkSampleCountFlagBits rasterizationSamples;
6141             VK_FALSE,                                                 // VkBool32 sampleShadingEnable;
6142             0.0f,                                                     // float minSampleShading;
6143             DE_NULL,                                                  // const VkSampleMask* pSampleMask;
6144             VK_FALSE,                                                 // VkBool32 alphaToCoverageEnable;
6145             VK_FALSE                                                  // VkBool32 alphaToOneEnable;
6146         };
6147 
6148         const VkPipelineRasterizationStateCreateInfo *rasterizationStateInfo = getRasterizationStateCreateInfo();
6149 
6150         graphicsPipeline = makeGraphicsPipeline(
6151             vkd,                   // const DeviceInterface&                            vk
6152             vkDevice,              // const VkDevice                                    device
6153             *m_pipelineLayout,     // const VkPipelineLayout                            pipelineLayout
6154             *m_vertexShaderModule, // const VkShaderModule                                vertexShaderModule
6155             DE_NULL, // const VkShaderModule                                tessellationControlShaderModule
6156             DE_NULL, // const VkShaderModule                                tessellationEvalShaderModule
6157             DE_NULL, // const VkShaderModule                                geometryShaderModule
6158             rasterizationStateInfo->rasterizerDiscardEnable ? DE_NULL : *m_fragmentShaderModule,
6159             // const VkShaderModule                                fragmentShaderModule
6160             *m_renderPass,           // const VkRenderPass                                renderPass
6161             viewports,               // const std::vector<VkViewport>&                    viewports
6162             scissors,                // const std::vector<VkRect2D>&                        scissors
6163             primitiveTopology,       // const VkPrimitiveTopology                        topology
6164             0u,                      // const uint32_t                                    subpass
6165             0u,                      // const uint32_t                                    patchControlPoints
6166             &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo*        vertexInputStateCreateInfo
6167             rasterizationStateInfo,  // const VkPipelineRasterizationStateCreateInfo*    rasterizationStateCreateInfo
6168             &multisampleStateParams, // const VkPipelineMultisampleStateCreateInfo*        multisampleStateCreateInfo
6169             DE_NULL,                 // const VkPipelineDepthStencilStateCreateInfo*        depthStencilStateCreateInfo,
6170             getColorBlendStateCreateInfo()); // const VkPipelineColorBlendStateCreateInfo*        colorBlendStateCreateInfo
6171     }
6172 
6173     // Create Vertex Buffer
6174     {
6175         const VkBufferCreateInfo vertexBufferParams = {
6176             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
6177             DE_NULL,                              // const void* pNext;
6178             0u,                                   // VkBufferCreateFlags flags;
6179             attributeBatchSize * 2,               // VkDeviceSize size;
6180             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
6181             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
6182             1u,                                   // uint32_t queueFamilyCount;
6183             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
6184         };
6185 
6186         const std::vector<tcu::Vec4> colorData(positionData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
6187 
6188         vertexBuffer       = createBuffer(vkd, vkDevice, &vertexBufferParams);
6189         vertexBufferMemory = allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer),
6190                                                 MemoryRequirement::HostVisible);
6191 
6192         VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(),
6193                                       vertexBufferMemory->getOffset()));
6194 
6195         // Load vertices into vertex buffer
6196         deMemcpy(vertexBufferMemory->getHostPtr(), positionData.data(), attributeBatchSize);
6197         deMemcpy(reinterpret_cast<uint8_t *>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, colorData.data(),
6198                  attributeBatchSize);
6199         flushAlloc(vkd, vkDevice, *vertexBufferMemory);
6200     }
6201 
6202     // Create Command Buffer
6203     commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
6204 
6205     // Begin Command Buffer
6206     beginCommandBuffer(vkd, *commandBuffer);
6207 
6208     addImageTransitionBarrier(*commandBuffer,                            // VkCommandBuffer            commandBuffer
6209                               *m_image,                                  // VkImage                    image
6210                               VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,         // VkPipelineStageFlags        srcStageMask
6211                               VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,        // VkPipelineStageFlags        dstStageMask
6212                               0,                                         // VkAccessFlags            srcAccessMask
6213                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,      // VkAccessFlags            dstAccessMask
6214                               VK_IMAGE_LAYOUT_UNDEFINED,                 // VkImageLayout oldLayout;
6215                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
6216 
6217     if (m_multisampling)
6218     {
6219         addImageTransitionBarrier(*commandBuffer,                            // VkCommandBuffer            commandBuffer
6220                                   *m_resolvedImage,                          // VkImage                    image
6221                                   VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,         // VkPipelineStageFlags        srcStageMask
6222                                   VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,        // VkPipelineStageFlags        dstStageMask
6223                                   0,                                         // VkAccessFlags            srcAccessMask
6224                                   VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,      // VkAccessFlags            dstAccessMask
6225                                   VK_IMAGE_LAYOUT_UNDEFINED,                 // VkImageLayout oldLayout;
6226                                   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // VkImageLayout newLayout;
6227     }
6228 
6229     // Reset query pool
6230     vkd.cmdResetQueryPool(*commandBuffer, *queryPool, 0u, 1u);
6231 
6232     // Begin render pass and start query
6233     beginRenderPass(vkd, *commandBuffer, *m_renderPass, *m_frameBuffer,
6234                     vk::makeRect2D(0, 0, m_renderSize, m_renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
6235     vkd.cmdBeginQuery(*commandBuffer, *queryPool, 0u, (VkQueryControlFlags)0u);
6236     vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
6237     vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1,
6238                               &m_descriptorSet.get(), 0u, DE_NULL);
6239     vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset);
6240     vkd.cmdDraw(*commandBuffer, (uint32_t)positionData.size(), 1, 0, 0);
6241     vkd.cmdEndQuery(*commandBuffer, *queryPool, 0u);
6242     endRenderPass(vkd, *commandBuffer);
6243 
6244     // Copy Image
6245     copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? *m_resolvedImage : *m_image, *m_resultBuffer,
6246                       tcu::IVec2(m_renderSize, m_renderSize));
6247 
6248     endCommandBuffer(vkd, *commandBuffer);
6249 
6250     // Set Point Size
6251     {
6252         float pointSize = getPointSize();
6253 
6254         deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
6255         flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
6256     }
6257 
6258     // Submit
6259     submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
6260 
6261     invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
6262     tcu::copy(result.getAccess(),
6263               tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1),
6264                                           m_resultBufferMemory->getHostPtr()));
6265 }
6266 
6267 class DiscardTestCase : public BaseRenderingTestCase
6268 {
6269 public:
DiscardTestCase(tcu::TestContext & context,const std::string & name,VkPrimitiveTopology primitiveTopology,bool queryFragmentShaderInvocations,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)6270     DiscardTestCase(tcu::TestContext &context, const std::string &name, VkPrimitiveTopology primitiveTopology,
6271                     bool queryFragmentShaderInvocations, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
6272         : BaseRenderingTestCase(context, name, sampleCount)
6273         , m_primitiveTopology(primitiveTopology)
6274         , m_queryFragmentShaderInvocations(queryFragmentShaderInvocations)
6275     {
6276     }
6277 
createInstance(Context & context) const6278     virtual TestInstance *createInstance(Context &context) const
6279     {
6280         return new DiscardTestInstance(context, m_primitiveTopology, m_queryFragmentShaderInvocations);
6281     }
6282 
checkSupport(Context & context) const6283     virtual void checkSupport(Context &context) const
6284     {
6285         if (m_queryFragmentShaderInvocations)
6286             context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_PIPELINE_STATISTICS_QUERY);
6287 
6288 #ifndef CTS_USES_VULKANSC
6289         if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
6290             context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
6291             !context.getPortabilitySubsetFeatures().triangleFans)
6292             TCU_THROW(NotSupportedError,
6293                       "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
6294 #endif // CTS_USES_VULKANSC
6295     }
6296 
6297 protected:
6298     const VkPrimitiveTopology m_primitiveTopology;
6299     const bool m_queryFragmentShaderInvocations;
6300 };
6301 
6302 class TriangleInterpolationTestInstance : public BaseRenderingTestInstance
6303 {
6304 public:
TriangleInterpolationTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,int flags,VkSampleCountFlagBits sampleCount)6305     TriangleInterpolationTestInstance(Context &context, VkPrimitiveTopology primitiveTopology, int flags,
6306                                       VkSampleCountFlagBits sampleCount)
6307         : BaseRenderingTestInstance(context, sampleCount, RESOLUTION_POT)
6308         , m_primitiveTopology(primitiveTopology)
6309         , m_projective((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
6310         , m_iterationCount(3)
6311         , m_iteration(0)
6312         , m_allIterationsPassed(true)
6313         , m_flatshade((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
6314     {
6315     }
6316 
6317     tcu::TestStatus iterate(void);
6318 
6319 private:
6320     void generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices, std::vector<tcu::Vec4> &outColors) const;
6321     void extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
6322                           const std::vector<tcu::Vec4> &vertices, const std::vector<tcu::Vec4> &colors) const;
6323 
6324     VkPrimitiveTopology m_primitiveTopology;
6325     const bool m_projective;
6326     const int m_iterationCount;
6327     int m_iteration;
6328     bool m_allIterationsPassed;
6329     const bool m_flatshade;
6330 };
6331 
iterate(void)6332 tcu::TestStatus TriangleInterpolationTestInstance::iterate(void)
6333 {
6334     const std::string iterationDescription =
6335         "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
6336     const tcu::ScopedLogSection section(m_context.getTestContext().getLog(),
6337                                         "Iteration" + de::toString(m_iteration + 1), iterationDescription);
6338     tcu::Surface resultImage(m_renderSize, m_renderSize);
6339     std::vector<tcu::Vec4> drawBuffer;
6340     std::vector<tcu::Vec4> colorBuffer;
6341     std::vector<TriangleSceneSpec::SceneTriangle> triangles;
6342 
6343     // generate scene
6344     generateVertices(m_iteration, drawBuffer, colorBuffer);
6345     extractTriangles(triangles, drawBuffer, colorBuffer);
6346 
6347     // log
6348     {
6349         m_context.getTestContext().getLog()
6350             << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
6351         for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
6352             m_context.getTestContext().getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx]
6353                                                 << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
6354     }
6355 
6356     // draw image
6357     drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitiveTopology);
6358 
6359     // compare
6360     {
6361         RasterizationArguments args;
6362         TriangleSceneSpec scene;
6363         tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
6364 
6365         args.numSamples   = m_multisampling ? 1 : 0;
6366         args.subpixelBits = m_subpixelBits;
6367         args.redBits      = colorBits[0];
6368         args.greenBits    = colorBits[1];
6369         args.blueBits     = colorBits[2];
6370 
6371         scene.triangles.swap(triangles);
6372 
6373         if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog()))
6374             m_allIterationsPassed = false;
6375     }
6376 
6377     // result
6378     if (++m_iteration == m_iterationCount)
6379     {
6380         if (m_allIterationsPassed)
6381             return tcu::TestStatus::pass("Pass");
6382         else
6383             return tcu::TestStatus::fail("Found invalid pixel values");
6384     }
6385     else
6386         return tcu::TestStatus::incomplete();
6387 }
6388 
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const6389 void TriangleInterpolationTestInstance::generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices,
6390                                                          std::vector<tcu::Vec4> &outColors) const
6391 {
6392     // use only red, green and blue
6393     const tcu::Vec4 colors[] = {
6394         tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
6395         tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
6396         tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
6397     };
6398 
6399     de::Random rnd(123 + iteration * 1000 + (int)m_primitiveTopology);
6400 
6401     outVertices.resize(6);
6402     outColors.resize(6);
6403 
6404     for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
6405     {
6406         outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
6407         outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
6408         outVertices[vtxNdx].z() = 0.0f;
6409 
6410         if (!m_projective)
6411             outVertices[vtxNdx].w() = 1.0f;
6412         else
6413         {
6414             const float w = rnd.getFloat(0.2f, 4.0f);
6415 
6416             outVertices[vtxNdx].x() *= w;
6417             outVertices[vtxNdx].y() *= w;
6418             outVertices[vtxNdx].z() *= w;
6419             outVertices[vtxNdx].w() = w;
6420         }
6421 
6422         outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
6423     }
6424 }
6425 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const6426 void TriangleInterpolationTestInstance::extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> &outTriangles,
6427                                                          const std::vector<tcu::Vec4> &vertices,
6428                                                          const std::vector<tcu::Vec4> &colors) const
6429 {
6430     switch (m_primitiveTopology)
6431     {
6432     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
6433     {
6434         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
6435         {
6436             TriangleSceneSpec::SceneTriangle tri;
6437             tri.positions[0]  = vertices[vtxNdx + 0];
6438             tri.positions[1]  = vertices[vtxNdx + 1];
6439             tri.positions[2]  = vertices[vtxNdx + 2];
6440             tri.sharedEdge[0] = false;
6441             tri.sharedEdge[1] = false;
6442             tri.sharedEdge[2] = false;
6443 
6444             if (m_flatshade)
6445             {
6446                 tri.colors[0] = colors[vtxNdx];
6447                 tri.colors[1] = colors[vtxNdx];
6448                 tri.colors[2] = colors[vtxNdx];
6449             }
6450             else
6451             {
6452                 tri.colors[0] = colors[vtxNdx + 0];
6453                 tri.colors[1] = colors[vtxNdx + 1];
6454                 tri.colors[2] = colors[vtxNdx + 2];
6455             }
6456 
6457             outTriangles.push_back(tri);
6458         }
6459         break;
6460     }
6461 
6462     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
6463     {
6464         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
6465         {
6466             TriangleSceneSpec::SceneTriangle tri;
6467             tri.positions[0]  = vertices[vtxNdx + 0];
6468             tri.positions[1]  = vertices[vtxNdx + 1];
6469             tri.positions[2]  = vertices[vtxNdx + 2];
6470             tri.sharedEdge[0] = false;
6471             tri.sharedEdge[1] = false;
6472             tri.sharedEdge[2] = false;
6473 
6474             if (m_flatshade)
6475             {
6476                 tri.colors[0] = colors[vtxNdx];
6477                 tri.colors[1] = colors[vtxNdx];
6478                 tri.colors[2] = colors[vtxNdx];
6479             }
6480             else
6481             {
6482                 tri.colors[0] = colors[vtxNdx + 0];
6483                 tri.colors[1] = colors[vtxNdx + 1];
6484                 tri.colors[2] = colors[vtxNdx + 2];
6485             }
6486 
6487             outTriangles.push_back(tri);
6488         }
6489         break;
6490     }
6491 
6492     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
6493     {
6494         for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
6495         {
6496             TriangleSceneSpec::SceneTriangle tri;
6497             tri.positions[0]  = vertices[0];
6498             tri.positions[1]  = vertices[vtxNdx + 0];
6499             tri.positions[2]  = vertices[vtxNdx + 1];
6500             tri.sharedEdge[0] = false;
6501             tri.sharedEdge[1] = false;
6502             tri.sharedEdge[2] = false;
6503 
6504             if (m_flatshade)
6505             {
6506                 tri.colors[0] = colors[vtxNdx];
6507                 tri.colors[1] = colors[vtxNdx];
6508                 tri.colors[2] = colors[vtxNdx];
6509             }
6510             else
6511             {
6512                 tri.colors[0] = colors[0];
6513                 tri.colors[1] = colors[vtxNdx + 0];
6514                 tri.colors[2] = colors[vtxNdx + 1];
6515             }
6516 
6517             outTriangles.push_back(tri);
6518         }
6519         break;
6520     }
6521 
6522     default:
6523         DE_ASSERT(false);
6524     }
6525 }
6526 
6527 class TriangleInterpolationTestCase : public BaseRenderingTestCase
6528 {
6529 public:
TriangleInterpolationTestCase(tcu::TestContext & context,const std::string & name,VkPrimitiveTopology primitiveTopology,int flags,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)6530     TriangleInterpolationTestCase(tcu::TestContext &context, const std::string &name,
6531                                   VkPrimitiveTopology primitiveTopology, int flags,
6532                                   VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
6533         : BaseRenderingTestCase(context, name, sampleCount, (flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
6534         , m_primitiveTopology(primitiveTopology)
6535         , m_flags(flags)
6536     {
6537     }
6538 
createInstance(Context & context) const6539     virtual TestInstance *createInstance(Context &context) const
6540     {
6541         return new TriangleInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_sampleCount);
6542     }
6543 
checkSupport(Context & context) const6544     virtual void checkSupport(Context &context) const
6545     {
6546 #ifndef CTS_USES_VULKANSC
6547         if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
6548             context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
6549             !context.getPortabilitySubsetFeatures().triangleFans)
6550         {
6551             TCU_THROW(NotSupportedError,
6552                       "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
6553         }
6554 #else
6555         DE_UNREF(context);
6556 #endif // CTS_USES_VULKANSC
6557     }
6558 
6559 protected:
6560     const VkPrimitiveTopology m_primitiveTopology;
6561     const int m_flags;
6562 };
6563 
6564 class LineInterpolationTestInstance : public BaseRenderingTestInstance
6565 {
6566 public:
6567     LineInterpolationTestInstance(Context &context, VkPrimitiveTopology primitiveTopology, int flags,
6568                                   PrimitiveWideness wideness, PrimitiveStrictness strictness,
6569                                   VkSampleCountFlagBits sampleCount);
6570 
6571     virtual tcu::TestStatus iterate(void);
6572 
6573 private:
6574     void generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices, std::vector<tcu::Vec4> &outColors) const;
6575     void extractLines(std::vector<LineSceneSpec::SceneLine> &outLines, const std::vector<tcu::Vec4> &vertices,
6576                       const std::vector<tcu::Vec4> &colors) const;
6577     virtual float getLineWidth(void) const;
6578 
6579     VkPrimitiveTopology m_primitiveTopology;
6580     const bool m_projective;
6581     const int m_iterationCount;
6582     const PrimitiveWideness m_primitiveWideness;
6583 
6584     int m_iteration;
6585     bool m_allIterationsPassed;
6586     float m_maxLineWidth;
6587     std::vector<float> m_lineWidths;
6588     bool m_flatshade;
6589     PrimitiveStrictness m_strictness;
6590 };
6591 
LineInterpolationTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,int flags,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount)6592 LineInterpolationTestInstance::LineInterpolationTestInstance(Context &context, VkPrimitiveTopology primitiveTopology,
6593                                                              int flags, PrimitiveWideness wideness,
6594                                                              PrimitiveStrictness strictness,
6595                                                              VkSampleCountFlagBits sampleCount)
6596     : BaseRenderingTestInstance(context, sampleCount)
6597     , m_primitiveTopology(primitiveTopology)
6598     , m_projective((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
6599     , m_iterationCount(3)
6600     , m_primitiveWideness(wideness)
6601     , m_iteration(0)
6602     , m_allIterationsPassed(true)
6603     , m_maxLineWidth(1.0f)
6604     , m_flatshade((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
6605     , m_strictness(strictness)
6606 {
6607     DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
6608 
6609     // create line widths
6610     if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
6611     {
6612         m_lineWidths.resize(m_iterationCount, 1.0f);
6613     }
6614     else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
6615     {
6616         const float *range = context.getDeviceProperties().limits.lineWidthRange;
6617 
6618         m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0]
6619                                             << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
6620 
6621         DE_ASSERT(range[1] > 1.0f);
6622 
6623         // set hand picked sizes
6624         m_lineWidths.push_back(5.0f);
6625         m_lineWidths.push_back(10.0f);
6626         m_lineWidths.push_back(range[1]);
6627         DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
6628 
6629         m_maxLineWidth = range[1];
6630     }
6631     else
6632         DE_ASSERT(false);
6633 }
6634 
iterate(void)6635 tcu::TestStatus LineInterpolationTestInstance::iterate(void)
6636 {
6637     const std::string iterationDescription =
6638         "Test iteration " + de::toString(m_iteration + 1) + " / " + de::toString(m_iterationCount);
6639     const tcu::ScopedLogSection section(m_context.getTestContext().getLog(),
6640                                         "Iteration" + de::toString(m_iteration + 1), iterationDescription);
6641     const float lineWidth = getLineWidth();
6642     tcu::Surface resultImage(m_renderSize, m_renderSize);
6643     std::vector<tcu::Vec4> drawBuffer;
6644     std::vector<tcu::Vec4> colorBuffer;
6645     std::vector<LineSceneSpec::SceneLine> lines;
6646 
6647     // supported?
6648     if (lineWidth <= m_maxLineWidth)
6649     {
6650         // generate scene
6651         generateVertices(m_iteration, drawBuffer, colorBuffer);
6652         extractLines(lines, drawBuffer, colorBuffer);
6653 
6654         // log
6655         {
6656             m_context.getTestContext().getLog()
6657                 << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
6658             for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
6659                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx]
6660                                                     << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
6661         }
6662 
6663         // draw image
6664         drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitiveTopology);
6665 
6666         // compare
6667         {
6668             RasterizationArguments args;
6669             LineSceneSpec scene;
6670 
6671             tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
6672 
6673             args.numSamples   = m_multisampling ? 1 : 0;
6674             args.subpixelBits = m_subpixelBits;
6675             args.redBits      = colorBits[0];
6676             args.greenBits    = colorBits[1];
6677             args.blueBits     = colorBits[2];
6678 
6679             scene.lines.swap(lines);
6680             scene.lineWidth = getLineWidth();
6681 
6682             switch (m_strictness)
6683             {
6684             case PRIMITIVESTRICTNESS_STRICT:
6685             {
6686                 if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args,
6687                                                               m_context.getTestContext().getLog(), true))
6688                     m_allIterationsPassed = false;
6689 
6690                 break;
6691             }
6692 
6693             case PRIMITIVESTRICTNESS_NONSTRICT:
6694             case PRIMITIVESTRICTNESS_IGNORE:
6695             {
6696                 if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args,
6697                                                               m_context.getTestContext().getLog(), false, true))
6698                     m_allIterationsPassed = false;
6699 
6700                 break;
6701             }
6702 
6703             default:
6704                 TCU_THROW(InternalError, "Not implemented");
6705             }
6706         }
6707     }
6708     else
6709         m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth
6710                                             << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
6711 
6712     // result
6713     if (++m_iteration == m_iterationCount)
6714     {
6715         if (m_allIterationsPassed)
6716             return tcu::TestStatus::pass("Pass");
6717         else
6718             return tcu::TestStatus::fail("Incorrect rasterization");
6719     }
6720     else
6721         return tcu::TestStatus::incomplete();
6722 }
6723 
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const6724 void LineInterpolationTestInstance::generateVertices(int iteration, std::vector<tcu::Vec4> &outVertices,
6725                                                      std::vector<tcu::Vec4> &outColors) const
6726 {
6727     // use only red, green and blue
6728     const tcu::Vec4 colors[] = {
6729         tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
6730         tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
6731         tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
6732     };
6733 
6734     de::Random rnd(123 + iteration * 1000 + (int)m_primitiveTopology);
6735 
6736     outVertices.resize(6);
6737     outColors.resize(6);
6738 
6739     for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
6740     {
6741         outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
6742         outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
6743         outVertices[vtxNdx].z() = 0.0f;
6744 
6745         if (!m_projective)
6746             outVertices[vtxNdx].w() = 1.0f;
6747         else
6748         {
6749             const float w = rnd.getFloat(0.2f, 4.0f);
6750 
6751             outVertices[vtxNdx].x() *= w;
6752             outVertices[vtxNdx].y() *= w;
6753             outVertices[vtxNdx].z() *= w;
6754             outVertices[vtxNdx].w() = w;
6755         }
6756 
6757         outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
6758     }
6759 }
6760 
extractLines(std::vector<LineSceneSpec::SceneLine> & outLines,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const6761 void LineInterpolationTestInstance::extractLines(std::vector<LineSceneSpec::SceneLine> &outLines,
6762                                                  const std::vector<tcu::Vec4> &vertices,
6763                                                  const std::vector<tcu::Vec4> &colors) const
6764 {
6765     switch (m_primitiveTopology)
6766     {
6767     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
6768     {
6769         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
6770         {
6771             LineSceneSpec::SceneLine line;
6772             line.positions[0] = vertices[vtxNdx + 0];
6773             line.positions[1] = vertices[vtxNdx + 1];
6774 
6775             if (m_flatshade)
6776             {
6777                 line.colors[0] = colors[vtxNdx];
6778                 line.colors[1] = colors[vtxNdx];
6779             }
6780             else
6781             {
6782                 line.colors[0] = colors[vtxNdx + 0];
6783                 line.colors[1] = colors[vtxNdx + 1];
6784             }
6785 
6786             outLines.push_back(line);
6787         }
6788         break;
6789     }
6790 
6791     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
6792     {
6793         for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
6794         {
6795             LineSceneSpec::SceneLine line;
6796             line.positions[0] = vertices[vtxNdx + 0];
6797             line.positions[1] = vertices[vtxNdx + 1];
6798 
6799             if (m_flatshade)
6800             {
6801                 line.colors[0] = colors[vtxNdx];
6802                 line.colors[1] = colors[vtxNdx];
6803             }
6804             else
6805             {
6806                 line.colors[0] = colors[vtxNdx + 0];
6807                 line.colors[1] = colors[vtxNdx + 1];
6808             }
6809 
6810             outLines.push_back(line);
6811         }
6812         break;
6813     }
6814 
6815     default:
6816         DE_ASSERT(false);
6817     }
6818 }
6819 
getLineWidth(void) const6820 float LineInterpolationTestInstance::getLineWidth(void) const
6821 {
6822     return m_lineWidths[m_iteration];
6823 }
6824 
6825 class LineInterpolationTestCase : public BaseRenderingTestCase
6826 {
6827 public:
LineInterpolationTestCase(tcu::TestContext & context,const std::string & name,VkPrimitiveTopology primitiveTopology,int flags,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)6828     LineInterpolationTestCase(tcu::TestContext &context, const std::string &name, VkPrimitiveTopology primitiveTopology,
6829                               int flags, PrimitiveWideness wideness, PrimitiveStrictness strictness,
6830                               VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
6831         : BaseRenderingTestCase(context, name, sampleCount, (flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
6832         , m_primitiveTopology(primitiveTopology)
6833         , m_flags(flags)
6834         , m_wideness(wideness)
6835         , m_strictness(strictness)
6836     {
6837     }
6838 
createInstance(Context & context) const6839     virtual TestInstance *createInstance(Context &context) const
6840     {
6841         return new LineInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_wideness, m_strictness,
6842                                                  m_sampleCount);
6843     }
6844 
checkSupport(Context & context) const6845     virtual void checkSupport(Context &context) const
6846     {
6847         if (m_strictness == PRIMITIVESTRICTNESS_STRICT && !context.getDeviceProperties().limits.strictLines)
6848             TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
6849 
6850         if (m_wideness == PRIMITIVEWIDENESS_WIDE)
6851             context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
6852     }
6853 
6854 protected:
6855     const VkPrimitiveTopology m_primitiveTopology;
6856     const int m_flags;
6857     const PrimitiveWideness m_wideness;
6858     const PrimitiveStrictness m_strictness;
6859 };
6860 
6861 class StrideZeroCase : public vkt::TestCase
6862 {
6863 public:
6864     struct Params
6865     {
6866         std::vector<tcu::Vec2> bufferData;
6867         uint32_t drawVertexCount;
6868     };
6869 
StrideZeroCase(tcu::TestContext & testCtx,const std::string & name,const Params & params)6870     StrideZeroCase(tcu::TestContext &testCtx, const std::string &name, const Params &params)
6871         : vkt::TestCase(testCtx, name)
6872         , m_params(params)
6873     {
6874     }
6875 
~StrideZeroCase(void)6876     virtual ~StrideZeroCase(void)
6877     {
6878     }
6879 
6880     virtual void initPrograms(vk::SourceCollections &programCollection) const;
6881     virtual TestInstance *createInstance(Context &context) const;
6882     virtual void checkSupport(Context &context) const;
6883 
6884     static constexpr vk::VkFormat kColorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
6885     static constexpr vk::VkFormatFeatureFlags kColorFeatures =
6886         (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
6887     static constexpr vk::VkImageUsageFlags kColorUsage =
6888         (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
6889 
6890     //    (-1,-1)
6891     //        +-----+-----+
6892     //        |     |     |
6893     //        |  a  |  b  |    a = (-0.5, -0.5)
6894     //        |     |     |    b = ( 0.5, -0.5)
6895     //        +-----------+    c = (-0.5,  0.5)
6896     //        |     |     |    d = ( 0.5,  0.5)
6897     //        |  c  |  d  |
6898     //        |     |     |
6899     //        +-----+-----+
6900     //                    (1,1)
6901     static constexpr uint32_t kImageDim = 2u;
6902     static const float kCornerDelta; // 0.5f;
6903 
6904     static const tcu::Vec4 kClearColor;
6905     static const tcu::Vec4 kDrawColor;
6906 
6907 private:
6908     Params m_params;
6909 };
6910 
6911 const float StrideZeroCase::kCornerDelta = 0.5f;
6912 const tcu::Vec4 StrideZeroCase::kClearColor(0.0f, 0.0f, 0.0f, 1.0f);
6913 const tcu::Vec4 StrideZeroCase::kDrawColor(1.0f, 1.0f, 1.0f, 1.0f);
6914 
6915 class StrideZeroInstance : public vkt::TestInstance
6916 {
6917 public:
StrideZeroInstance(Context & context,const StrideZeroCase::Params & params)6918     StrideZeroInstance(Context &context, const StrideZeroCase::Params &params)
6919         : vkt::TestInstance(context)
6920         , m_params(params)
6921     {
6922     }
6923 
~StrideZeroInstance(void)6924     virtual ~StrideZeroInstance(void)
6925     {
6926     }
6927 
6928     virtual tcu::TestStatus iterate(void);
6929 
6930 private:
6931     StrideZeroCase::Params m_params;
6932 };
6933 
initPrograms(vk::SourceCollections & programCollection) const6934 void StrideZeroCase::initPrograms(vk::SourceCollections &programCollection) const
6935 {
6936     std::ostringstream vert;
6937     std::ostringstream frag;
6938 
6939     std::ostringstream drawColor;
6940     drawColor << std::setprecision(2) << std::fixed << "vec4(" << kDrawColor.x() << ", " << kDrawColor.y() << ", "
6941               << kDrawColor.z() << ", " << kDrawColor.w() << ")";
6942 
6943     vert << "#version 450\n"
6944          << "layout (location=0) in vec2 inPos;\n"
6945          << "void main() {\n"
6946          << "    gl_Position = vec4(inPos, 0.0, 1.0);\n"
6947          << "    gl_PointSize = 1.0;\n"
6948          << "}\n";
6949 
6950     frag << "#version 450\n"
6951          << "layout (location=0) out vec4 outColor;\n"
6952          << "void main() {\n"
6953          << "    outColor = " << drawColor.str() << ";\n"
6954          << "}\n";
6955 
6956     programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
6957     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
6958 }
6959 
createInstance(Context & context) const6960 TestInstance *StrideZeroCase::createInstance(Context &context) const
6961 {
6962     return new StrideZeroInstance(context, m_params);
6963 }
6964 
checkSupport(Context & context) const6965 void StrideZeroCase::checkSupport(Context &context) const
6966 {
6967     const auto properties = vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
6968                                                                   context.getPhysicalDevice(), kColorFormat);
6969     if ((properties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
6970         TCU_THROW(NotSupportedError, "Required image format not supported");
6971 }
6972 
6973 // Creates a vertex buffer with the given data but uses zero as the binding stride.
6974 // Then, tries to draw the requested number of points. Only the first point should ever be used.
iterate(void)6975 tcu::TestStatus StrideZeroInstance::iterate(void)
6976 {
6977     const auto &vkd          = m_context.getDeviceInterface();
6978     const auto device        = m_context.getDevice();
6979     auto &alloc              = m_context.getDefaultAllocator();
6980     const auto queue         = m_context.getUniversalQueue();
6981     const auto queueIndex    = m_context.getUniversalQueueFamilyIndex();
6982     constexpr auto kImageDim = StrideZeroCase::kImageDim;
6983     const auto colorExtent   = vk::makeExtent3D(kImageDim, kImageDim, 1u);
6984 
6985     // Prepare vertex buffer.
6986     const auto vertexBufferSize =
6987         static_cast<vk::VkDeviceSize>(m_params.bufferData.size() * sizeof(decltype(m_params.bufferData)::value_type));
6988     const auto vertexBufferInfo = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
6989     const vk::BufferWithMemory vertexBuffer(vkd, device, alloc, vertexBufferInfo, vk::MemoryRequirement::HostVisible);
6990     auto &vertexBufferAlloc                   = vertexBuffer.getAllocation();
6991     const vk::VkDeviceSize vertexBufferOffset = 0ull;
6992     deMemcpy(vertexBufferAlloc.getHostPtr(), m_params.bufferData.data(), static_cast<size_t>(vertexBufferSize));
6993     flushAlloc(vkd, device, vertexBufferAlloc);
6994 
6995     // Prepare render image.
6996     const vk::VkImageCreateInfo colorAttachmentInfo = {
6997         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
6998         nullptr,                                 // const void* pNext;
6999         0u,                                      // VkImageCreateFlags flags;
7000         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
7001         StrideZeroCase::kColorFormat,            // VkFormat format;
7002         colorExtent,                             // VkExtent3D extent;
7003         1u,                                      // uint32_t mipLevels;
7004         1u,                                      // uint32_t arrayLayers;
7005         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
7006         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
7007         StrideZeroCase::kColorUsage,             // VkImageUsageFlags usage;
7008         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
7009         1u,                                      // uint32_t queueFamilyIndexCount;
7010         &queueIndex,                             // const uint32_t* pQueueFamilyIndices;
7011         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
7012     };
7013     const vk::ImageWithMemory colorAttachment(vkd, device, alloc, colorAttachmentInfo, vk::MemoryRequirement::Any);
7014 
7015     const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
7016     const auto colorAttachmentView   = vk::makeImageView(vkd, device, colorAttachment.get(), vk::VK_IMAGE_VIEW_TYPE_2D,
7017                                                          StrideZeroCase::kColorFormat, colorSubresourceRange);
7018 
7019     const vk::VkVertexInputBindingDescription vertexBinding = {
7020         0u,                              // uint32_t binding;
7021         0u,                              //    uint32_t            stride;        [IMPORTANT]
7022         vk::VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
7023     };
7024 
7025     const vk::VkVertexInputAttributeDescription vertexAttribute = {
7026         0u,                          // uint32_t location;
7027         0u,                          // uint32_t binding;
7028         vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
7029         0u,                          // uint32_t offset;
7030     };
7031 
7032     const vk::VkPipelineVertexInputStateCreateInfo vertexInput = {
7033         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
7034         nullptr,                                                       // const void* pNext;
7035         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
7036         1u,                                                            // uint32_t vertexBindingDescriptionCount;
7037         &vertexBinding,   // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
7038         1u,               // uint32_t vertexAttributeDescriptionCount;
7039         &vertexAttribute, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
7040     };
7041 
7042     const auto renderArea     = vk::makeRect2D(kImageDim, kImageDim);
7043     const auto viewports      = std::vector<vk::VkViewport>(1, vk::makeViewport(kImageDim, kImageDim));
7044     const auto scissors       = std::vector<vk::VkRect2D>(1, renderArea);
7045     const auto pipelineLayout = vk::makePipelineLayout(vkd, device);
7046     const auto vertexShader   = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
7047     const auto fragmentShader = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
7048     const auto renderPass     = vk::makeRenderPass(vkd, device, StrideZeroCase::kColorFormat);
7049     const auto graphicsPipeline =
7050         vk::makeGraphicsPipeline(vkd, device, pipelineLayout.get(), vertexShader.get(), DE_NULL, DE_NULL, DE_NULL,
7051                                  fragmentShader.get(), // Shaders.
7052                                  renderPass.get(), viewports, scissors, vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0u,
7053                                  0u,            // Render pass, viewports, scissors, topology.
7054                                  &vertexInput); // Vertex input state.
7055     const auto framebuffer =
7056         vk::makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), kImageDim, kImageDim);
7057 
7058     const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
7059     const auto cmdBufferPtr =
7060         vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
7061     const auto cmdBuffer = cmdBufferPtr.get();
7062 
7063     // Buffer used to verify results.
7064     const auto tcuFormat       = vk::mapVkFormat(StrideZeroCase::kColorFormat);
7065     const auto colorBufferSize = static_cast<vk::VkDeviceSize>(tcu::getPixelSize(tcuFormat)) * kImageDim * kImageDim;
7066     const auto colorBufferInfo = vk::makeBufferCreateInfo(colorBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
7067     const vk::BufferWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, vk::MemoryRequirement::HostVisible);
7068     auto &colorBufferAlloc = colorBuffer.getAllocation();
7069     void *colorBufferPtr   = colorBufferAlloc.getHostPtr();
7070     const auto colorLayers = vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
7071     const auto copyRegion  = vk::makeBufferImageCopy(colorExtent, colorLayers);
7072 
7073     // Barriers from attachment to buffer and buffer to host.
7074     const auto colorAttachmentBarrier = vk::makeImageMemoryBarrier(
7075         vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
7076         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorAttachment.get(),
7077         colorSubresourceRange);
7078     const auto colorBufferBarrier = vk::makeBufferMemoryBarrier(
7079         vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, colorBuffer.get(), 0ull, colorBufferSize);
7080 
7081     vk::beginCommandBuffer(vkd, cmdBuffer);
7082     vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea, StrideZeroCase::kClearColor);
7083     vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
7084     vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
7085     vkd.cmdDraw(cmdBuffer, m_params.drawVertexCount, 1u, 0u, 0u);
7086     vk::endRenderPass(vkd, cmdBuffer);
7087     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
7088                            vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u,
7089                            &colorAttachmentBarrier);
7090     vkd.cmdCopyImageToBuffer(cmdBuffer, colorAttachment.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
7091                              colorBuffer.get(), 1u, &copyRegion);
7092     vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u,
7093                            nullptr, 1u, &colorBufferBarrier, 0u, nullptr);
7094     vk::endCommandBuffer(vkd, cmdBuffer);
7095 
7096     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
7097 
7098     // Invalidate color buffer alloc.
7099     vk::invalidateAlloc(vkd, device, colorBufferAlloc);
7100 
7101     // Check buffer.
7102     const int imageDimI = static_cast<int>(kImageDim);
7103     const tcu::ConstPixelBufferAccess colorPixels(tcuFormat, imageDimI, imageDimI, 1, colorBufferPtr);
7104     tcu::TestStatus testStatus = tcu::TestStatus::pass("Pass");
7105     auto &log                  = m_context.getTestContext().getLog();
7106 
7107     for (int x = 0; x < imageDimI; ++x)
7108         for (int y = 0; y < imageDimI; ++y)
7109         {
7110             // Only the top-left corner should have draw data.
7111             const auto expectedColor = ((x == 0 && y == 0) ? StrideZeroCase::kDrawColor : StrideZeroCase::kClearColor);
7112             const auto imageColor    = colorPixels.getPixel(x, y);
7113 
7114             if (expectedColor != imageColor)
7115             {
7116                 log << tcu::TestLog::Message << "Unexpected color found in pixel (" << x << ", " << y << "): "
7117                     << "expected (" << expectedColor.x() << ", " << expectedColor.y() << ", " << expectedColor.z()
7118                     << ", " << expectedColor.w() << ") "
7119                     << "and found (" << imageColor.x() << ", " << imageColor.y() << ", " << imageColor.z() << ", "
7120                     << imageColor.w() << ")" << tcu::TestLog::EndMessage;
7121 
7122                 testStatus = tcu::TestStatus::fail("Failed; Check log for details");
7123             }
7124         }
7125 
7126     return testStatus;
7127 }
7128 
7129 class CullAndPrimitiveIdCase : public vkt::TestCase
7130 {
7131 public:
CullAndPrimitiveIdCase(tcu::TestContext & testCtx,const std::string & name)7132     CullAndPrimitiveIdCase(tcu::TestContext &testCtx, const std::string &name) : vkt::TestCase(testCtx, name)
7133     {
7134     }
~CullAndPrimitiveIdCase(void)7135     ~CullAndPrimitiveIdCase(void)
7136     {
7137     }
7138     void initPrograms(vk::SourceCollections &programCollection) const override;
7139     void checkSupport(Context &context) const override;
7140     TestInstance *createInstance(Context &context) const override;
7141 
7142     static constexpr uint32_t kCullAndPrimitiveIDWidth  = 64u;
7143     static constexpr uint32_t kCullAndPrimitiveIDHeight = 64u;
7144 };
7145 
7146 class CullAndPrimitiveIdInstance : public vkt::TestInstance
7147 {
7148 public:
CullAndPrimitiveIdInstance(Context & context)7149     CullAndPrimitiveIdInstance(Context &context) : vkt::TestInstance(context)
7150     {
7151     }
~CullAndPrimitiveIdInstance(void)7152     ~CullAndPrimitiveIdInstance(void)
7153     {
7154     }
7155 
7156     tcu::TestStatus iterate(void) override;
7157 };
7158 
createInstance(Context & context) const7159 TestInstance *CullAndPrimitiveIdCase::createInstance(Context &context) const
7160 {
7161     return new CullAndPrimitiveIdInstance(context);
7162 }
7163 
checkSupport(Context & context) const7164 void CullAndPrimitiveIdCase::checkSupport(Context &context) const
7165 {
7166     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
7167 }
7168 
initPrograms(vk::SourceCollections & sources) const7169 void CullAndPrimitiveIdCase::initPrograms(vk::SourceCollections &sources) const
7170 {
7171     // One triangle per image pixel, alternating clockwise and counter-clockwise.
7172     std::ostringstream vert;
7173     vert << "#version 450\n"
7174          << "void main ()\n"
7175          << "{\n"
7176          << "    const uint width = " << kCullAndPrimitiveIDWidth << ";\n"
7177          << "    const uint height = " << kCullAndPrimitiveIDHeight << ";\n"
7178          << "    const uint uVertexIndex = uint(gl_VertexIndex);\n"
7179          << "    const uint triangleId = uVertexIndex / 3u;\n"
7180          << "    const uint vertId = uVertexIndex % 3u;\n"
7181          << "    const uint rowId = triangleId / width;\n"
7182          << "    const uint colId = triangleId % width;\n"
7183          << "    const float fWidth = float(width);\n"
7184          << "    const float fHeight = float(height);\n"
7185          << "    const float xPixelCoord = (float(colId) + 0.5) / fWidth * 2.0 - 1.0;\n"
7186          << "    const float yPixelCoord = (float(rowId) + 0.5) / fHeight * 2.0 - 1.0;\n"
7187          << "    const float quarterPixelWidth = (2.0 / fWidth) / 4.0;\n"
7188          << "    const float quarterPixelHeight = (2.0 / fHeight) / 4.0;\n"
7189          << "    const vec2 bottomLeft = vec2(xPixelCoord - quarterPixelWidth, yPixelCoord + quarterPixelHeight);\n"
7190          << "    const vec2 bottomRight = vec2(xPixelCoord + quarterPixelWidth, yPixelCoord + quarterPixelHeight);\n"
7191          << "    const vec2 topCenter = vec2(xPixelCoord, yPixelCoord - quarterPixelHeight);\n"
7192          << "    const vec2 cwCoords[3] = vec2[](bottomLeft, topCenter, bottomRight);\n"
7193          << "    const vec2 ccwCoords[3] = vec2[](bottomLeft, bottomRight, topCenter);\n"
7194          << "    // Half the triangles will be culled.\n"
7195          << "    const bool counterClockWise = ((triangleId % 2u) == 0u);\n"
7196          << "    vec2 pointCoords;\n"
7197          << "    if (counterClockWise) { pointCoords = ccwCoords[vertId]; }\n"
7198          << "    else                  { pointCoords = cwCoords[vertId]; }\n"
7199          << "    gl_Position = vec4(pointCoords, 0.0, 1.0);\n"
7200          << "}\n";
7201     sources.glslSources.add("vert") << glu::VertexSource(vert.str());
7202 
7203     std::ostringstream frag;
7204     frag << "#version 450\n"
7205          << "layout (location=0) out vec4 outColor;\n"
7206          << "\n"
7207          << "void main ()\n"
7208          << "{\n"
7209          << "    const uint primId = uint(gl_PrimitiveID);\n"
7210          << "    // Pixel color rotates every 3 pixels.\n"
7211          << "    const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
7212          << "    const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
7213          << "    const vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
7214          << "    const vec4 colorPalette[3] = vec4[](red, green, blue);\n"
7215          << "    const uint colorIdx = primId % 3u;\n"
7216          << "    outColor = colorPalette[colorIdx];\n"
7217          << "}\n";
7218     sources.glslSources.add("frag") << glu::FragmentSource(frag.str());
7219 }
7220 
iterate()7221 tcu::TestStatus CullAndPrimitiveIdInstance::iterate()
7222 {
7223     const auto &vkd             = m_context.getDeviceInterface();
7224     const auto device           = m_context.getDevice();
7225     auto &alloc                 = m_context.getDefaultAllocator();
7226     const auto qIndex           = m_context.getUniversalQueueFamilyIndex();
7227     const auto queue            = m_context.getUniversalQueue();
7228     const auto kWidth           = CullAndPrimitiveIdCase::kCullAndPrimitiveIDWidth;
7229     const auto kHeight          = CullAndPrimitiveIdCase::kCullAndPrimitiveIDHeight;
7230     const auto extent           = makeExtent3D(kWidth, kHeight, 1u);
7231     const auto triangleCount    = extent.width * extent.height * extent.depth;
7232     const auto vertexCount      = triangleCount * 3u;
7233     const auto format           = VK_FORMAT_R8G8B8A8_UNORM;
7234     const auto tcuFormat        = mapVkFormat(format);
7235     const auto colorUsage       = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
7236     const auto verifBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
7237     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
7238 
7239     // Color attachment.
7240     const VkImageCreateInfo colorBufferInfo = {
7241         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
7242         nullptr,                             // const void* pNext;
7243         0u,                                  // VkImageCreateFlags flags;
7244         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
7245         format,                              // VkFormat format;
7246         extent,                              // VkExtent3D extent;
7247         1u,                                  // uint32_t mipLevels;
7248         1u,                                  // uint32_t arrayLayers;
7249         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
7250         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
7251         colorUsage,                          // VkImageUsageFlags usage;
7252         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
7253         0u,                                  // uint32_t queueFamilyIndexCount;
7254         nullptr,                             // const uint32_t* pQueueFamilyIndices;
7255         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
7256     };
7257     ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
7258     const auto colorSRR        = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
7259     const auto colorSRL        = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
7260     const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, format, colorSRR);
7261 
7262     // Verification buffer.
7263     const auto verifBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat)) * extent.width * extent.height;
7264     const auto verifBufferInfo = makeBufferCreateInfo(verifBufferSize, verifBufferUsage);
7265     BufferWithMemory verifBuffer(vkd, device, alloc, verifBufferInfo, MemoryRequirement::HostVisible);
7266     auto &verifBufferAlloc = verifBuffer.getAllocation();
7267     void *verifBufferData  = verifBufferAlloc.getHostPtr();
7268 
7269     // Render pass and framebuffer.
7270     const auto renderPass = makeRenderPass(vkd, device, format);
7271     const auto framebuffer =
7272         makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), extent.width, extent.height);
7273 
7274     // Shader modules.
7275     const auto &binaries  = m_context.getBinaryCollection();
7276     const auto vertModule = createShaderModule(vkd, device, binaries.get("vert"));
7277     const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"));
7278 
7279     // Viewports and scissors.
7280     const std::vector<VkViewport> viewports(1u, makeViewport(extent));
7281     const std::vector<VkRect2D> scissors(1u, makeRect2D(extent));
7282 
7283     // Vertex input and culling.
7284     const VkPipelineVertexInputStateCreateInfo inputState           = initVulkanStructure();
7285     const VkPipelineRasterizationStateCreateInfo rasterizationState = {
7286         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
7287         nullptr,                                                    // const void* pNext;
7288         0u,                                                         // VkPipelineRasterizationStateCreateFlags flags;
7289         VK_FALSE,                                                   // VkBool32 depthClampEnable;
7290         VK_FALSE,                                                   // VkBool32 rasterizerDiscardEnable;
7291         VK_POLYGON_MODE_FILL,                                       // VkPolygonMode polygonMode;
7292         VK_CULL_MODE_BACK_BIT,                                      // VkCullModeFlags cullMode;
7293         VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // VkFrontFace frontFace;
7294         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
7295         0.0f,                                                       // float depthBiasConstantFactor;
7296         0.0f,                                                       // float depthBiasClamp;
7297         0.0f,                                                       // float depthBiasSlopeFactor;
7298         1.0f,                                                       // float lineWidth;
7299     };
7300 
7301     // Pipeline layout and graphics pipeline.
7302     const auto pipelineLayout = makePipelineLayout(vkd, device);
7303     const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), vertModule.get(), DE_NULL, DE_NULL,
7304                                                DE_NULL, fragModule.get(), renderPass.get(), viewports, scissors,
7305                                                VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u /*subpass*/,
7306                                                0u /*patchControlPoints*/, &inputState, &rasterizationState);
7307 
7308     // Command pool and buffer.
7309     const auto cmdPool      = makeCommandPool(vkd, device, qIndex);
7310     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
7311     const auto cmdBuffer    = cmdBufferPtr.get();
7312 
7313     beginCommandBuffer(vkd, cmdBuffer);
7314 
7315     // Draw.
7316     beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
7317     vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
7318     vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
7319     endRenderPass(vkd, cmdBuffer);
7320 
7321     // Copy to verification buffer.
7322     const auto copyRegion     = makeBufferImageCopy(extent, colorSRL);
7323     const auto transfer2Host  = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
7324     const auto color2Transfer = makeImageMemoryBarrier(
7325         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
7326         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.get(), colorSRR);
7327 
7328     cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
7329                                   VK_PIPELINE_STAGE_TRANSFER_BIT, &color2Transfer);
7330     vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u,
7331                              &copyRegion);
7332     cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
7333                              &transfer2Host);
7334 
7335     endCommandBuffer(vkd, cmdBuffer);
7336 
7337     // Submit and validate result.
7338     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
7339     invalidateAlloc(vkd, device, verifBufferAlloc);
7340 
7341     const tcu::IVec3 iExtent(static_cast<int>(extent.width), static_cast<int>(extent.height),
7342                              static_cast<int>(extent.depth));
7343     const tcu::PixelBufferAccess verifAccess(tcuFormat, iExtent, verifBufferData);
7344     tcu::TextureLevel referenceLevel(tcuFormat, iExtent.x(), iExtent.y(), iExtent.z());
7345     const auto referenceAccess = referenceLevel.getAccess();
7346 
7347     // Compose reference image.
7348     const tcu::Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
7349     const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
7350     const tcu::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
7351     const std::vector<tcu::Vec4> colorPalette{red, green, blue};
7352 
7353     for (int y = 0; y < iExtent.y(); ++y)
7354         for (int x = 0; x < iExtent.x(); ++x)
7355         {
7356             const auto pixelId = y * iExtent.x() + x;
7357             const bool culled  = (pixelId % 2 == 1);
7358             const auto color   = (culled ? clearColor : colorPalette[pixelId % 3]);
7359             referenceAccess.setPixel(color, x, y);
7360         }
7361 
7362     // Compare.
7363     {
7364         auto &log = m_context.getTestContext().getLog();
7365         if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, verifAccess,
7366                                         tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::COMPARE_LOG_ON_ERROR))
7367             TCU_FAIL("Failed; check log for details");
7368     }
7369 
7370     return tcu::TestStatus::pass("Pass");
7371 }
7372 
7373 struct PolygonModeLargePointsConfig
7374 {
7375     const float pointSize;
7376     const bool meshShader;
7377     const bool tessellationShaders;
7378     const bool geometryShader;
7379     const bool dynamicPolygonMode;
7380     const bool defaultSize;
7381 
PolygonModeLargePointsConfigvkt::rasterization::__anon5742e12a0111::PolygonModeLargePointsConfig7382     PolygonModeLargePointsConfig(float pointSize_, bool meshShader_, bool tessellationShaders_, bool geometryShader_,
7383                                  bool dynamicPolygonMode_, bool defaultSize_ = false)
7384         : pointSize(pointSize_)
7385         , meshShader(meshShader_)
7386         , tessellationShaders(tessellationShaders_)
7387         , geometryShader(geometryShader_)
7388         , dynamicPolygonMode(dynamicPolygonMode_)
7389         , defaultSize(defaultSize_)
7390     {
7391         if (meshShader)
7392         {
7393             DE_ASSERT(!tessellationShaders && !geometryShader);
7394         }
7395     }
7396 };
7397 
7398 class PolygonModeLargePointsCase : public vkt::TestCase
7399 {
7400 public:
PolygonModeLargePointsCase(tcu::TestContext & testCtx,const std::string & name,const PolygonModeLargePointsConfig & config)7401     PolygonModeLargePointsCase(tcu::TestContext &testCtx, const std::string &name,
7402                                const PolygonModeLargePointsConfig &config)
7403         : vkt::TestCase(testCtx, name)
7404         , m_config(config)
7405     {
7406     }
~PolygonModeLargePointsCase(void)7407     virtual ~PolygonModeLargePointsCase(void)
7408     {
7409     }
7410 
7411     void checkSupport(Context &context) const override;
7412     void initPrograms(vk::SourceCollections &programCollection) const override;
7413     TestInstance *createInstance(Context &context) const override;
7414 
7415     static const tcu::Vec4 geometryColor;
7416     static constexpr uint32_t kNumTriangles = 2u;
7417     static constexpr uint32_t kNumPoints    = kNumTriangles * 3u;
7418 
7419 protected:
7420     const PolygonModeLargePointsConfig m_config;
7421 };
7422 
7423 const tcu::Vec4 PolygonModeLargePointsCase::geometryColor(0.0f, 0.0f, 1.0f, 1.0f);
7424 
7425 class PolygonModeLargePointsInstance : public vkt::TestInstance
7426 {
7427 public:
PolygonModeLargePointsInstance(Context & context,const PolygonModeLargePointsConfig & config)7428     PolygonModeLargePointsInstance(Context &context, const PolygonModeLargePointsConfig &config)
7429         : vkt::TestInstance(context)
7430         , m_config(config)
7431     {
7432     }
~PolygonModeLargePointsInstance(void)7433     virtual ~PolygonModeLargePointsInstance(void)
7434     {
7435     }
7436 
7437     tcu::TestStatus iterate(void) override;
7438 
7439 protected:
7440     const PolygonModeLargePointsConfig m_config;
7441 };
7442 
checkSupport(Context & context) const7443 void PolygonModeLargePointsCase::checkSupport(Context &context) const
7444 {
7445 #ifndef CTS_USES_VULKANSC
7446     context.requireDeviceFunctionality("VK_KHR_maintenance5");
7447 #else
7448     DE_ASSERT(false);
7449 #endif // CTS_USES_VULKANSC
7450 
7451     context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FILL_MODE_NON_SOLID);
7452 
7453 #ifndef CTS_USES_VULKANSC
7454     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
7455         !context.getPortabilitySubsetFeatures().pointPolygons)
7456         TCU_THROW(NotSupportedError,
7457                   "VK_KHR_portability_subset: Point polygons are not supported by this implementation");
7458 
7459     if (!context.getMaintenance5Properties().polygonModePointSize && !m_config.defaultSize)
7460         TCU_THROW(NotSupportedError,
7461                   "VK_KHR_maintenance5: polygonModePointSize property is not supported by this implementation");
7462 #else
7463     DE_ASSERT(false);
7464 #endif // CTS_USES_VULKANSC
7465 
7466     const auto &limits = context.getDeviceProperties().limits;
7467     if (!limits.standardSampleLocations)
7468         TCU_THROW(NotSupportedError, "standardSampleLocations not supported");
7469 
7470     if (m_config.meshShader)
7471         context.requireDeviceFunctionality("VK_EXT_mesh_shader");
7472 
7473     if (m_config.tessellationShaders || m_config.geometryShader)
7474         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE);
7475 
7476     if (m_config.tessellationShaders)
7477         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
7478 
7479     if (m_config.geometryShader)
7480         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
7481 
7482     if (m_config.pointSize != 1.0f)
7483     {
7484         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
7485 
7486         const auto &validRange = limits.pointSizeRange;
7487         if (validRange[0] > m_config.pointSize || validRange[1] < m_config.pointSize)
7488         {
7489             std::ostringstream msg;
7490             msg << "Required point size " << m_config.pointSize << " outside valid range [" << validRange[0] << ", "
7491                 << validRange[1] << "]";
7492             TCU_THROW(NotSupportedError, msg.str());
7493         }
7494     }
7495 
7496 #ifndef CTS_USES_VULKANSC
7497     if (m_config.dynamicPolygonMode)
7498     {
7499         const auto eds3Features = context.getExtendedDynamicState3FeaturesEXT();
7500         if (!eds3Features.extendedDynamicState3PolygonMode)
7501             TCU_THROW(NotSupportedError, "extendedDynamicState3PolygonMode not supported");
7502     }
7503 #else
7504     DE_ASSERT(false);
7505 #endif // CTS_USES_VULKANSC
7506 }
7507 
initPrograms(vk::SourceCollections & programCollection) const7508 void PolygonModeLargePointsCase::initPrograms(vk::SourceCollections &programCollection) const
7509 {
7510     if (!m_config.meshShader)
7511     {
7512         std::ostringstream vert;
7513         vert << "#version 460\n"
7514              << "layout (location=0) in vec4 inPosition;\n"
7515              << "out gl_PerVertex {\n"
7516              << "    vec4  gl_Position;\n"
7517              << "    float gl_PointSize;\n"
7518              << "};\n"
7519              << "void main (void) {\n"
7520              << "    gl_Position  = inPosition;\n";
7521         if (!m_config.defaultSize)
7522         {
7523             vert << "    gl_PointSize = " << std::fixed << m_config.pointSize << ";\n";
7524         }
7525         vert << "}\n";
7526         programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
7527     }
7528     else
7529     {
7530         std::ostringstream mesh;
7531         mesh << "#version 450\n"
7532              << "#extension GL_EXT_mesh_shader : enable\n"
7533              << "\n"
7534              << "layout (local_size_x=" << kNumPoints << ", local_size_y=1, local_size_z=1) in;\n"
7535              << "layout (triangles) out;\n"
7536              << "layout (max_vertices=" << kNumPoints << ", max_primitives=" << kNumTriangles << ") out;\n"
7537              << "\n"
7538              << "out gl_MeshPerVertexEXT {\n"
7539              << "    vec4  gl_Position;\n"
7540              << "    float gl_PointSize;\n"
7541              << "} gl_MeshVerticesEXT[];\n"
7542              << "\n"
7543              << "layout (set=0, binding=0, std430) readonly buffer VertexData {\n"
7544              << "    vec4 vertices[];\n"
7545              << "} vertexBuffer;\n"
7546              << "\n"
7547              << "void main (void) {\n"
7548              << "    SetMeshOutputsEXT(" << kNumPoints << ", " << kNumTriangles << ");\n"
7549              << "    gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = "
7550                 "vertexBuffer.vertices[gl_LocalInvocationIndex];\n";
7551         if (!m_config.defaultSize)
7552         {
7553             mesh << "    gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_PointSize = " << std::fixed
7554                  << m_config.pointSize << ";\n";
7555         }
7556         mesh << "    if (gl_LocalInvocationIndex < " << kNumTriangles << ") {\n"
7557              << "        const uint baseIndex = gl_LocalInvocationIndex * 3u;\n"
7558              << "        gl_PrimitiveTriangleIndicesEXT[gl_LocalInvocationIndex] = uvec3(baseIndex, baseIndex + 1u, "
7559                 "baseIndex + 2u);\n"
7560              << "    }\n"
7561              << "}\n";
7562         const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
7563         programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
7564     }
7565 
7566     std::ostringstream frag;
7567     frag << "#version 460\n"
7568          << "layout (location=0) out vec4 outColor;\n"
7569          << "void main (void) {\n"
7570          << "    outColor = vec4" << geometryColor << ";\n"
7571          << "}\n";
7572     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
7573 
7574     if (m_config.tessellationShaders)
7575     {
7576         std::ostringstream tesc;
7577         tesc << "#version 460\n"
7578              << "layout (vertices=3) out;\n"
7579              << "in gl_PerVertex {\n"
7580              << "    vec4  gl_Position;\n"
7581              << "    float gl_PointSize;\n"
7582              << "} gl_in[gl_MaxPatchVertices];\n"
7583              << "out gl_PerVertex {\n"
7584              << "    vec4  gl_Position;\n"
7585              << "    float gl_PointSize;\n"
7586              << "} gl_out[];\n"
7587              << "void main (void) {\n"
7588              << "  gl_TessLevelInner[0] = 1.0;\n"
7589              << "  gl_TessLevelInner[1] = 1.0;\n"
7590              << "  gl_TessLevelOuter[0] = 1.0;\n"
7591              << "  gl_TessLevelOuter[1] = 1.0;\n"
7592              << "  gl_TessLevelOuter[2] = 1.0;\n"
7593              << "  gl_TessLevelOuter[3] = 1.0;\n"
7594              << "  gl_out[gl_InvocationID].gl_Position  = gl_in[gl_InvocationID].gl_Position;\n";
7595         if (!m_config.defaultSize)
7596         {
7597             tesc << "  gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
7598         }
7599         tesc << "}\n";
7600         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
7601 
7602         std::ostringstream tese;
7603         tese << "#version 460\n"
7604              << "layout (triangles, fractional_odd_spacing, cw) in;\n"
7605              << "in gl_PerVertex {\n"
7606              << "    vec4  gl_Position;\n"
7607              << "    float gl_PointSize;\n"
7608              << "} gl_in[gl_MaxPatchVertices];\n"
7609              << "out gl_PerVertex {\n"
7610              << "    vec4  gl_Position;\n"
7611              << "    float gl_PointSize;\n"
7612              << "};\n"
7613              << "void main (void) {\n"
7614              << "    gl_Position  = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
7615              << "                   (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
7616              << "                   (gl_TessCoord.z * gl_in[2].gl_Position);\n";
7617         if (!m_config.defaultSize)
7618         {
7619             tese << "    gl_PointSize = gl_in[0].gl_PointSize;\n";
7620         }
7621         tese << "}\n";
7622         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
7623     }
7624 
7625     if (m_config.geometryShader)
7626     {
7627         std::ostringstream geom;
7628         geom << "#version 460\n"
7629              << "layout (triangles) in;\n"
7630              << "layout (triangle_strip, max_vertices=3) out;\n"
7631              << "in gl_PerVertex {\n"
7632              << "    vec4  gl_Position;\n"
7633              << "    float gl_PointSize;\n"
7634              << "} gl_in[3];\n"
7635              << "out gl_PerVertex {\n"
7636              << "    vec4  gl_Position;\n"
7637              << "    float gl_PointSize;\n"
7638              << "};\n"
7639              << "void main (void) {\n"
7640              << "    for (uint i = 0u; i < 3u; ++i) {\n"
7641              << "        gl_Position  = gl_in[i].gl_Position;\n";
7642         if (!m_config.defaultSize)
7643         {
7644             geom << "        gl_PointSize = gl_in[i].gl_PointSize;\n";
7645         }
7646         geom << "        EmitVertex();\n"
7647              << "    }\n"
7648              << "}\n";
7649         programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
7650     }
7651 }
7652 
createInstance(Context & context) const7653 TestInstance *PolygonModeLargePointsCase::createInstance(Context &context) const
7654 {
7655     return new PolygonModeLargePointsInstance(context, m_config);
7656 }
7657 
7658 /*
7659  * The test will create a 4x4 framebuffer and will draw a quad in the middle of it, roughly covering the 4 center pixels. Instead of
7660  * making the quad have the exact size to cover the whole center area, the quad will be slightly inside the 4 center pixels, with a
7661  * margin of 0.125 units (1/4 of a pixel in unnormalized coordinates). This means a point size of 1.0 will not reach the sampling
7662  * points at the pixel center of the edge pixels, but a point size of 2.0 will.
7663  */
7664 /*
7665     +----------+----------+----------+----------+
7666     |          |          |          |          |
7667     |          |          |          |          |
7668     |     x    |     x    |     x    |     x    |
7669     |          |          |          |          |
7670     |          |          |          |          |
7671     +----------+----------+----------+----------+
7672     |          |          |          |          |
7673     |          | +--------+--------+ |          |
7674     |     x    | |        |        | |     x    |
7675     |          | |        |        | |          |
7676     |          | |        |        | |          |
7677     +----------+-+--------+--------+-+----------+
7678     |          | |        |        | |          |
7679     |          | |        |        | |          |
7680     |     x    | |        |        | |     x    |
7681     |          | +--------+--------+ |          |
7682     |          |          |          |          |
7683     +----------+----------+----------+----------+
7684     |          |          |          |          |
7685     |          |          |          |          |
7686     |     x    |     x    |     x    |     x    |
7687     |          |          |          |          |
7688     |          |          |          |          |
7689     +----------+----------+----------+----------+
7690 */
iterate(void)7691 tcu::TestStatus PolygonModeLargePointsInstance::iterate(void)
7692 {
7693     const auto &vkd    = m_context.getDeviceInterface();
7694     const auto device  = m_context.getDevice();
7695     auto &alloc        = m_context.getDefaultAllocator();
7696     const auto queue   = m_context.getUniversalQueue();
7697     const auto qfIndex = m_context.getUniversalQueueFamilyIndex();
7698 
7699     const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
7700     const auto tcuFormat   = mapVkFormat(colorFormat);
7701     const auto colorExtent = makeExtent3D(4u, 4u, 1u);
7702     const tcu::IVec3 colorIExtent(static_cast<int>(colorExtent.width), static_cast<int>(colorExtent.height),
7703                                   static_cast<int>(colorExtent.depth));
7704     const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
7705     const auto colorSRR   = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
7706     const auto colorSRL   = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
7707     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
7708 
7709     // Color buffer.
7710     const VkImageCreateInfo colorBufferCreateInfo = {
7711         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
7712         nullptr,                             // const void* pNext;
7713         0u,                                  // VkImageCreateFlags flags;
7714         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
7715         colorFormat,                         // VkFormat format;
7716         colorExtent,                         // VkExtent3D extent;
7717         1u,                                  // uint32_t mipLevels;
7718         1u,                                  // uint32_t arrayLayers;
7719         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
7720         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
7721         colorUsage,                          // VkImageUsageFlags usage;
7722         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
7723         0u,                                  // uint32_t queueFamilyIndexCount;
7724         nullptr,                             // const uint32_t* pQueueFamilyIndices;
7725         VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
7726     };
7727     ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferCreateInfo, MemoryRequirement::Any);
7728 
7729     const auto colorBufferView =
7730         makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
7731 
7732     // Verification buffer.
7733     const auto pixelSize              = static_cast<VkDeviceSize>(tcuFormat.getPixelSize());
7734     const auto verificationBufferSize = pixelSize * colorExtent.width * colorExtent.height * colorExtent.depth;
7735     const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
7736     BufferWithMemory verificationBuffer(vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
7737     auto &verificationBufferAlloc = verificationBuffer.getAllocation();
7738 
7739     // Vertex buffer.
7740     const float insideMargin = 0.125f;
7741     const tcu::Vec4 topLeft(-0.5f, -0.5f, 0.0f, 1.0f);
7742     const tcu::Vec4 topRight(0.5f, -0.5f, 0.0f, 1.0f);
7743     const tcu::Vec4 bottomLeft(-0.5f, 0.5f, 0.0f, 1.0f);
7744     const tcu::Vec4 bottomRight(0.5f, 0.5f, 0.0f, 1.0f);
7745 
7746     const tcu::Vec4 actualTL = topLeft + tcu::Vec4(insideMargin, insideMargin, 0.0f, 0.0f);
7747     const tcu::Vec4 actualTR = topRight + tcu::Vec4(-insideMargin, insideMargin, 0.0f, 0.0f);
7748     const tcu::Vec4 actualBL = bottomLeft + tcu::Vec4(insideMargin, -insideMargin, 0.0f, 0.0f);
7749     const tcu::Vec4 actualBR = bottomRight + tcu::Vec4(-insideMargin, -insideMargin, 0.0f, 0.0f);
7750 
7751     const std::vector<tcu::Vec4> vertices{
7752         actualTL, actualTR, actualBL, actualTR, actualBR, actualBL,
7753     };
7754 
7755     DE_ASSERT(de::sizeU32(vertices) == PolygonModeLargePointsCase::kNumPoints);
7756 
7757     const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
7758     const auto vertexBufferUsage =
7759         (m_config.meshShader ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
7760     const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
7761     BufferWithMemory vertexBuffer(vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
7762     auto &vertexBufferAlloc               = vertexBuffer.getAllocation();
7763     void *vertexBufferData                = vertexBufferAlloc.getHostPtr();
7764     const VkDeviceSize vertexBufferOffset = 0ull;
7765 
7766     deMemcpy(vertexBufferData, vertices.data(), static_cast<size_t>(vertexBufferSize));
7767     flushAlloc(vkd, device, vertexBufferAlloc);
7768 
7769     // Pipeline layout.
7770     DescriptorSetLayoutBuilder setLayoutBuilder;
7771     if (m_config.meshShader)
7772     {
7773 #ifndef CTS_USES_VULKANSC
7774         setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_MESH_BIT_EXT);
7775 #else
7776         DE_ASSERT(false);
7777 #endif // CTS_USES_VULKANSC
7778     }
7779     const auto setLayout      = setLayoutBuilder.build(vkd, device);
7780     const auto pipelineLayout = makePipelineLayout(vkd, device, setLayout.get());
7781 
7782     // Descriptor pool and set if needed.
7783     Move<VkDescriptorPool> descriptorPool;
7784     Move<VkDescriptorSet> descriptorSet;
7785     if (m_config.meshShader)
7786     {
7787         DescriptorPoolBuilder poolBuilder;
7788         poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
7789 
7790         descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
7791         descriptorSet  = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
7792 
7793         DescriptorSetUpdateBuilder updateBuilder;
7794         const auto vertexBufferDescInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBufferSize);
7795         updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u),
7796                                   VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &vertexBufferDescInfo);
7797         updateBuilder.update(vkd, device);
7798     }
7799 
7800     // Render pass and framebuffer.
7801     const auto renderPass = makeRenderPass(vkd, device, colorFormat);
7802     const auto framebuffer =
7803         makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorExtent.width, colorExtent.height);
7804 
7805     // Shader modules.
7806     const auto &binaries = m_context.getBinaryCollection();
7807     const auto vertModule =
7808         (!m_config.meshShader ? createShaderModule(vkd, device, binaries.get("vert")) : Move<VkShaderModule>());
7809     const auto meshModule =
7810         (m_config.meshShader ? createShaderModule(vkd, device, binaries.get("mesh")) : Move<VkShaderModule>());
7811     const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"));
7812     const auto tescModule =
7813         (m_config.tessellationShaders ? createShaderModule(vkd, device, binaries.get("tesc")) : Move<VkShaderModule>());
7814     const auto teseModule =
7815         (m_config.tessellationShaders ? createShaderModule(vkd, device, binaries.get("tese")) : Move<VkShaderModule>());
7816     const auto geomModule =
7817         (m_config.geometryShader ? createShaderModule(vkd, device, binaries.get("geom")) : Move<VkShaderModule>());
7818 
7819     // Viewports and scissors.
7820     const std::vector<VkViewport> viewports(1u, makeViewport(colorExtent));
7821     const std::vector<VkRect2D> scissors(1u, makeRect2D(colorExtent));
7822 
7823     // Rasterization state: key for the test. Rendering triangles as points.
7824     const auto polygonMode = (m_config.dynamicPolygonMode ? VK_POLYGON_MODE_FILL : VK_POLYGON_MODE_POINT);
7825     const VkPipelineRasterizationStateCreateInfo rasterizationStateInfo = {
7826         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
7827         nullptr,                                                    // const void* pNext;
7828         0u,                                                         // VkPipelineRasterizationStateCreateFlags flags;
7829         VK_FALSE,                                                   // VkBool32 depthClampEnable;
7830         VK_FALSE,                                                   // VkBool32 rasterizerDiscardEnable;
7831         polygonMode,                                                // VkPolygonMode polygonMode;
7832         VK_CULL_MODE_NONE,                                          // VkCullModeFlags cullMode;
7833         VK_FRONT_FACE_CLOCKWISE,                                    // VkFrontFace frontFace;
7834         VK_FALSE,                                                   // VkBool32 depthBiasEnable;
7835         0.0f,                                                       // float depthBiasConstantFactor;
7836         0.0f,                                                       // float depthBiasClamp;
7837         0.0f,                                                       // float depthBiasSlopeFactor;
7838         1.0f,                                                       // float lineWidth;
7839     };
7840 
7841     std::vector<VkDynamicState> dynamicStates;
7842 
7843 #ifndef CTS_USES_VULKANSC
7844     if (m_config.dynamicPolygonMode)
7845         dynamicStates.push_back(VK_DYNAMIC_STATE_POLYGON_MODE_EXT);
7846 #else
7847     DE_ASSERT(false);
7848 #endif // CTS_USES_VULKANSC
7849 
7850     const VkPipelineDynamicStateCreateInfo dynamicStateInfo = {
7851         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
7852         nullptr,                                              // const void* pNext;
7853         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
7854         de::sizeU32(dynamicStates),                           // uint32_t dynamicStateCount;
7855         de::dataOrNull(dynamicStates),                        // const VkDynamicState* pDynamicStates;
7856     };
7857 
7858     const auto primitiveTopology =
7859         (m_config.tessellationShaders ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
7860     const auto patchControlPoints = (m_config.tessellationShaders ? 3u : 0u);
7861 
7862     // Pipeline.
7863     Move<VkPipeline> pipeline;
7864 
7865     if (m_config.meshShader)
7866     {
7867 #ifndef CTS_USES_VULKANSC
7868         pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), VK_NULL_HANDLE, meshModule.get(),
7869                                         fragModule.get(), renderPass.get(), viewports, scissors, 0u,
7870                                         &rasterizationStateInfo, nullptr, nullptr, nullptr, &dynamicStateInfo);
7871 #else
7872         DE_ASSERT(false);
7873 #endif // CTS_USES_VULKANSC
7874     }
7875     else
7876     {
7877         pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(), vertModule.get(), tescModule.get(),
7878                                         teseModule.get(), geomModule.get(), fragModule.get(), renderPass.get(),
7879                                         viewports, scissors, primitiveTopology, 0u, patchControlPoints, nullptr,
7880                                         &rasterizationStateInfo, nullptr, nullptr, nullptr, &dynamicStateInfo);
7881     }
7882 
7883     // Command pool and buffer, render and verify results.
7884     const auto cmdPool      = makeCommandPool(vkd, device, qfIndex);
7885     const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
7886     const auto cmdBuffer    = cmdBufferPtr.get();
7887 
7888     beginCommandBuffer(vkd, cmdBuffer);
7889     beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
7890     vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
7891 
7892     if (m_config.meshShader)
7893         vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u,
7894                                   &descriptorSet.get(), 0u, nullptr);
7895     else
7896         vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
7897 
7898     if (m_config.dynamicPolygonMode)
7899     {
7900 #ifndef CTS_USES_VULKANSC
7901         vkd.cmdSetPolygonModeEXT(cmdBuffer, VK_POLYGON_MODE_POINT);
7902 #else
7903         DE_ASSERT(false);
7904 #endif // CTS_USES_VULKANSC
7905     }
7906 
7907     if (m_config.meshShader)
7908 #ifndef CTS_USES_VULKANSC
7909         vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
7910 #else
7911         DE_ASSERT(false);
7912 #endif // CTS_USES_VULKANSC
7913     else
7914         vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
7915 
7916     endRenderPass(vkd, cmdBuffer);
7917 
7918     // Copy image to verification buffer.
7919     const auto preTransferBarrier = makeImageMemoryBarrier(
7920         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
7921         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.get(), colorSRR);
7922 
7923     cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
7924                                   VK_PIPELINE_STAGE_TRANSFER_BIT, &preTransferBarrier);
7925 
7926     const auto copyRegion = makeBufferImageCopy(colorExtent, colorSRL);
7927     vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
7928                              verificationBuffer.get(), 1u, &copyRegion);
7929 
7930     const auto preHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
7931     cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
7932                              &preHostBarrier);
7933 
7934     endCommandBuffer(vkd, cmdBuffer);
7935     submitCommandsAndWait(vkd, device, queue, cmdBuffer);
7936 
7937     // Check results.
7938     invalidateAlloc(vkd, device, verificationBufferAlloc);
7939 
7940     const tcu::PixelBufferAccess resultAccess(tcuFormat, colorIExtent, verificationBufferAlloc.getHostPtr());
7941     tcu::TextureLevel referenceLevel(tcuFormat, colorIExtent.x(), colorIExtent.y(), colorIExtent.z());
7942     const tcu::PixelBufferAccess referenceAccess = referenceLevel.getAccess();
7943     const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f);
7944 #ifndef CTS_USES_VULKANSC
7945     const auto &m5Properties = m_context.getMaintenance5Properties();
7946     // If testing default size means we are not setting the point size in shaders, and therefore we don't care about m5Properties.polygonModePointSize
7947     // Default size is 1.0f, so we should only take the border into account
7948     const bool pointSizeUsed = m_config.defaultSize ? false : m5Properties.polygonModePointSize;
7949 #else
7950     const bool pointSizeUsed = false;
7951 #endif // CTS_USES_VULKANSC
7952 
7953     // Prepare reference color image, which depends on VkPhysicalDeviceMaintenance5PropertiesKHR::polygonModePointSize.
7954     DE_ASSERT(referenceAccess.getDepth() == 1);
7955     for (int y = 0; y < referenceAccess.getHeight(); ++y)
7956         for (int x = 0; x < referenceAccess.getWidth(); ++x)
7957         {
7958             const bool border =
7959                 (x == 0 || y == 0 || x == referenceAccess.getWidth() - 1 || y == referenceAccess.getHeight() - 1);
7960             const auto color = ((border && !pointSizeUsed) ? clearColor : PolygonModeLargePointsCase::geometryColor);
7961             referenceAccess.setPixel(color, x, y);
7962         }
7963 
7964     if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Result", "", referenceAccess, resultAccess,
7965                                     threshold, tcu::COMPARE_LOG_ON_ERROR))
7966         return tcu::TestStatus::fail("Color buffer contents do not match expected result -- check log for details");
7967 
7968     return tcu::TestStatus::pass("Pass");
7969 }
7970 
7971 template <typename ConcreteTestInstance>
7972 class NonStrictLinesMaintenance5TestCase : public BaseRenderingTestCase
7973 {
7974 public:
NonStrictLinesMaintenance5TestCase(tcu::TestContext & context,const std::string & name,PrimitiveWideness wideness)7975     NonStrictLinesMaintenance5TestCase(tcu::TestContext &context, const std::string &name, PrimitiveWideness wideness)
7976         : BaseRenderingTestCase(context, name, VK_SAMPLE_COUNT_1_BIT)
7977         , m_wideness(wideness)
7978     {
7979     }
createInstance(Context & context) const7980     virtual auto createInstance(Context &context) const -> TestInstance * override
7981     {
7982         return new ConcreteTestInstance(context, m_wideness, 0);
7983     }
checkSupport(Context & context) const7984     virtual auto checkSupport(Context &context) const -> void override
7985     {
7986         context.requireDeviceFunctionality("VK_KHR_maintenance5");
7987 
7988         if (context.getDeviceProperties().limits.strictLines)
7989             TCU_THROW(NotSupportedError, "Nonstrict rasterization is not supported");
7990 
7991         if (m_wideness == PRIMITIVEWIDENESS_WIDE)
7992             context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
7993     }
7994 
7995 protected:
7996     const PrimitiveWideness m_wideness;
7997 
7998     friend class NonStrictLinesMaintenance5TestInstance;
7999     friend class NonStrictLineStripMaintenance5TestInstance;
8000     static bool compareAndVerify(Context &context, BaseLineTestInstance *lineInstance, bool isStrip, bool isWide,
8001                                  std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage,
8002                                  std::vector<tcu::Vec4> & /* drawBuffer */);
8003 };
8004 
8005 template <class X>
compareAndVerify(Context & context,BaseLineTestInstance * lineInstance,bool isStrip,bool isWide,std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> &)8006 bool NonStrictLinesMaintenance5TestCase<X>::compareAndVerify(Context &context, BaseLineTestInstance *lineInstance,
8007                                                              bool isStrip, bool isWide,
8008                                                              std::vector<LineSceneSpec::SceneLine> &lines,
8009                                                              tcu::Surface &resultImage, std::vector<tcu::Vec4> &)
8010 {
8011     const tcu::IVec4 colorBits = tcu::getTextureFormatBitDepth(lineInstance->getTextureFormat());
8012 
8013     RasterizationArguments args;
8014     args.numSamples   = 0;
8015     args.subpixelBits = context.getDeviceProperties().limits.subPixelPrecisionBits;
8016     args.redBits      = colorBits[0];
8017     args.greenBits    = colorBits[1];
8018     args.blueBits     = colorBits[2];
8019 
8020     LineSceneSpec scene;
8021     scene.lines.swap(lines);
8022     scene.lineWidth        = lineInstance->getLineWidth();
8023     scene.stippleEnable    = false;
8024     scene.stippleFactor    = 1;
8025     scene.stipplePattern   = 0xFFFF;
8026     scene.isStrip          = isStrip;
8027     scene.isSmooth         = false;
8028     scene.isRectangular    = false;
8029     scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
8030 
8031     bool result                  = false;
8032     const bool strict            = false;
8033     tcu::TestLog &log            = context.getTestContext().getLog();
8034     const bool algoBresenhan     = verifyLineGroupRasterization(resultImage, scene, args, log);
8035     const bool algoParallelogram = verifyRelaxedLineGroupRasterization(resultImage, scene, args, log, true, strict);
8036 
8037 #ifndef CTS_USES_VULKANSC
8038     const VkPhysicalDeviceMaintenance5PropertiesKHR &p = context.getMaintenance5Properties();
8039     if (isWide)
8040     {
8041         // nonStrictWideLinesUseParallelogram is a boolean value indicating whether non-strict lines
8042         // with a width greater than 1.0 are rasterized as parallelograms or using Bresenham's algorithm.
8043         result = p.nonStrictWideLinesUseParallelogram ? algoParallelogram : algoBresenhan;
8044     }
8045     else
8046     {
8047         // nonStrictSinglePixelWideLinesUseParallelogram is a boolean value indicating whether
8048         // non-strict lines with a width of 1.0 are rasterized as parallelograms or using Bresenham's algorithm.
8049         result = p.nonStrictSinglePixelWideLinesUseParallelogram ? algoParallelogram : algoBresenhan;
8050     }
8051 #else
8052     DE_UNREF(isWide);
8053     DE_UNREF(algoBresenhan);
8054     DE_UNREF(algoParallelogram);
8055 #endif
8056 
8057     return result;
8058 }
8059 
8060 class NonStrictLinesMaintenance5TestInstance : public LinesTestInstance
8061 {
8062 public:
NonStrictLinesMaintenance5TestInstance(Context & context,PrimitiveWideness wideness,uint32_t additionalRenderSize)8063     NonStrictLinesMaintenance5TestInstance(Context &context, PrimitiveWideness wideness, uint32_t additionalRenderSize)
8064         : LinesTestInstance(context, wideness, PRIMITIVESTRICTNESS_NONSTRICT, VK_SAMPLE_COUNT_1_BIT,
8065                             LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST, LineStippleFactorCase::DEFAULT,
8066                             additionalRenderSize)
8067         , m_amIWide(PRIMITIVEWIDENESS_WIDE == wideness)
8068     {
8069     }
8070 
8071 protected:
compareAndVerify(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)8072     virtual bool compareAndVerify(std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage,
8073                                   std::vector<tcu::Vec4> &drawBuffer)
8074     {
8075         return NonStrictLinesMaintenance5TestCase<NonStrictLinesMaintenance5TestInstance>::compareAndVerify(
8076             m_context, this, false, m_amIWide, lines, resultImage, drawBuffer);
8077     }
8078 
8079 private:
8080     const bool m_amIWide;
8081 };
8082 
8083 class NonStrictLineStripMaintenance5TestInstance : public LineStripTestInstance
8084 {
8085 public:
NonStrictLineStripMaintenance5TestInstance(Context & context,PrimitiveWideness wideness,uint32_t additionalRenderSize)8086     NonStrictLineStripMaintenance5TestInstance(Context &context, PrimitiveWideness wideness,
8087                                                uint32_t additionalRenderSize)
8088         : LineStripTestInstance(context, wideness, PRIMITIVESTRICTNESS_NONSTRICT, VK_SAMPLE_COUNT_1_BIT,
8089                                 LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST,
8090                                 LineStippleFactorCase::DEFAULT, additionalRenderSize)
8091         , m_amIWide(PRIMITIVEWIDENESS_WIDE == wideness)
8092     {
8093     }
8094 
8095 protected:
compareAndVerify(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)8096     virtual bool compareAndVerify(std::vector<LineSceneSpec::SceneLine> &lines, tcu::Surface &resultImage,
8097                                   std::vector<tcu::Vec4> &drawBuffer)
8098     {
8099         return NonStrictLinesMaintenance5TestCase<NonStrictLineStripMaintenance5TestInstance>::compareAndVerify(
8100             m_context, this, true, m_amIWide, lines, resultImage, drawBuffer);
8101     }
8102 
8103 private:
8104     const bool m_amIWide;
8105 };
8106 
createRasterizationTests(tcu::TestCaseGroup * rasterizationTests)8107 void createRasterizationTests(tcu::TestCaseGroup *rasterizationTests)
8108 {
8109     tcu::TestContext &testCtx = rasterizationTests->getTestContext();
8110 
8111     const struct
8112     {
8113         LineStippleFactorCase stippleFactor;
8114         const std::string nameSuffix;
8115     } stippleFactorCases[] = {
8116         {LineStippleFactorCase::DEFAULT, ""},
8117         //  and use zero as the line stipple factor
8118         {LineStippleFactorCase::ZERO, "_factor_0"},
8119         //  and use a large number as the line stipple factor
8120         {LineStippleFactorCase::LARGE, "_factor_large"},
8121     };
8122 
8123     // .primitives
8124     {
8125         tcu::TestCaseGroup *const primitives = new tcu::TestCaseGroup(testCtx, "primitives");
8126 
8127         rasterizationTests->addChild(primitives);
8128 
8129         tcu::TestCaseGroup *const nostippleTests      = new tcu::TestCaseGroup(testCtx, "no_stipple");
8130         tcu::TestCaseGroup *const stippleStaticTests  = new tcu::TestCaseGroup(testCtx, "static_stipple");
8131         tcu::TestCaseGroup *const stippleDynamicTests = new tcu::TestCaseGroup(testCtx, "dynamic_stipple");
8132 #ifndef CTS_USES_VULKANSC
8133         tcu::TestCaseGroup *const stippleDynamicTopoTests =
8134             new tcu::TestCaseGroup(testCtx, "dynamic_stipple_and_topology");
8135 #endif // CTS_USES_VULKANSC
8136         tcu::TestCaseGroup *const strideZeroTests = new tcu::TestCaseGroup(testCtx, "stride_zero");
8137 
8138         primitives->addChild(nostippleTests);
8139         primitives->addChild(stippleStaticTests);
8140         primitives->addChild(stippleDynamicTests);
8141 #ifndef CTS_USES_VULKANSC
8142         primitives->addChild(stippleDynamicTopoTests);
8143 #endif // CTS_USES_VULKANSC
8144         primitives->addChild(strideZeroTests);
8145 
8146         // .stride_zero
8147         {
8148             {
8149                 StrideZeroCase::Params params;
8150                 params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
8151                 params.drawVertexCount = 1u;
8152                 // Attempt to draw 1 point with stride 0
8153                 strideZeroTests->addChild(new StrideZeroCase(testCtx, "single_point", params));
8154             }
8155             {
8156                 StrideZeroCase::Params params;
8157                 params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
8158                 params.bufferData.emplace_back(StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
8159                 params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, StrideZeroCase::kCornerDelta);
8160                 params.bufferData.emplace_back(StrideZeroCase::kCornerDelta, StrideZeroCase::kCornerDelta);
8161                 params.drawVertexCount = static_cast<uint32_t>(params.bufferData.size());
8162                 // Attempt to draw 4 points with stride 0 and 4 points in the buffer
8163                 strideZeroTests->addChild(new StrideZeroCase(testCtx, "four_points", params));
8164             }
8165             {
8166                 StrideZeroCase::Params params;
8167                 params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
8168                 params.drawVertexCount = 100000u;
8169                 // Attempt to draw many points with stride 0 with one point in the buffer
8170                 strideZeroTests->addChild(new StrideZeroCase(testCtx, "many_points", params));
8171             }
8172         }
8173 
8174         // Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result
8175         nostippleTests->addChild(new BaseTestCase<TrianglesTestInstance>(testCtx, "triangles"));
8176         // Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, verify rasterization result
8177         nostippleTests->addChild(new BaseTestCase<TriangleStripTestInstance>(testCtx, "triangle_strip"));
8178         // Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, verify rasterization result
8179         nostippleTests->addChild(new BaseTestCase<TriangleFanTestInstance>(testCtx, "triangle_fan"));
8180         // Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result
8181         nostippleTests->addChild(new WidenessTestCase<PointTestInstance>(
8182             testCtx, "points", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, false, VK_SAMPLE_COUNT_1_BIT,
8183             LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
8184 
8185         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode, verify rasterization result
8186         nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
8187             testCtx, "strict_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT,
8188             LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8189         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in strict mode, verify rasterization result
8190         nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>(
8191             testCtx, "strict_line_strip", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true,
8192             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8193         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode with wide lines, verify rasterization result
8194         nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
8195             testCtx, "strict_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true,
8196             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8197         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in strict mode with wide lines, verify rasterization result
8198         nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>(
8199             testCtx, "strict_line_strip_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true,
8200             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8201 
8202         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result
8203         nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
8204             testCtx, "non_strict_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, true,
8205             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8206         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode, verify rasterization result
8207         nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>(
8208             testCtx, "non_strict_line_strip", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, true,
8209             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8210         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode with wide lines, verify rasterization result
8211         nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
8212             testCtx, "non_strict_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, true,
8213             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8214         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode with wide lines, verify rasterization result
8215         nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>(
8216             testCtx, "non_strict_line_strip_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, true,
8217             VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
8218 
8219         for (int i = 0; i < static_cast<int>(LINESTIPPLE_LAST); ++i)
8220         {
8221 
8222             LineStipple stipple = (LineStipple)i;
8223 
8224 #ifdef CTS_USES_VULKANSC
8225             if (stipple == LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY)
8226                 continue;
8227 #endif // CTS_USES_VULKANSC
8228 
8229             tcu::TestCaseGroup *g = (stipple == LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY)
8230 #ifndef CTS_USES_VULKANSC
8231                                         ?
8232                                         stippleDynamicTopoTests
8233 #else
8234                                         ?
8235                                         nullptr // Note this is actually unused, due to the continue statement above.
8236 #endif // CTS_USES_VULKANSC
8237                                         :
8238                                         (stipple == LINESTIPPLE_DYNAMIC) ? stippleDynamicTests :
8239                                         (stipple == LINESTIPPLE_STATIC)  ? stippleStaticTests :
8240                                                                            nostippleTests;
8241 
8242             for (const auto &sfCase : stippleFactorCases)
8243             {
8244                 if (sfCase.stippleFactor != LineStippleFactorCase::DEFAULT && stipple != LINESTIPPLE_DISABLED)
8245                     continue;
8246 
8247                 const auto &factor = sfCase.stippleFactor;
8248                 const auto &suffix = sfCase.nameSuffix;
8249 
8250                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
8251                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8252                     testCtx, "lines" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
8253                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor,
8254                     i == 0 ? RESOLUTION_NPOT : 0));
8255                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
8256                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8257                     testCtx, "line_strip" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
8258                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor));
8259                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
8260                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8261                     testCtx, "lines_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
8262                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor));
8263                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
8264                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8265                     testCtx, "line_strip_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
8266                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, factor));
8267 
8268                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
8269                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8270                     testCtx, "rectangular_lines" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true,
8271                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
8272                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
8273                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8274                     testCtx, "rectangular_line_strip" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT,
8275                     true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
8276                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
8277                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8278                     testCtx, "rectangular_lines_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT,
8279                     true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
8280                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
8281                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8282                     testCtx, "rectangular_line_strip_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT,
8283                     true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT, factor));
8284 
8285                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
8286                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8287                     testCtx, "bresenham_lines" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
8288                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
8289                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
8290                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8291                     testCtx, "bresenham_line_strip" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE,
8292                     true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
8293                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
8294                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8295                     testCtx, "bresenham_lines_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
8296                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
8297                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
8298                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8299                     testCtx, "bresenham_line_strip_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE,
8300                     true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT, factor));
8301 
8302                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
8303                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8304                     testCtx, "smooth_lines" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
8305                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
8306                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
8307                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8308                     testCtx, "smooth_line_strip" + suffix, PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
8309                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
8310                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
8311                 g->addChild(new WidenessTestCase<LinesTestInstance>(
8312                     testCtx, "smooth_lines_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
8313                     VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
8314                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
8315                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
8316                     testCtx, "smooth_line_strip_wide" + suffix, PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE,
8317                     true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT, factor));
8318             }
8319         }
8320     }
8321 
8322     // .primitive_size
8323     {
8324         tcu::TestCaseGroup *const primitiveSize = new tcu::TestCaseGroup(testCtx, "primitive_size");
8325         rasterizationTests->addChild(primitiveSize);
8326 
8327         // .points
8328         {
8329             tcu::TestCaseGroup *const points = new tcu::TestCaseGroup(testCtx, "points");
8330 
8331             static const struct TestCombinations
8332             {
8333                 const uint32_t renderSize;
8334                 const float pointSize;
8335             } testCombinations[] = {{1024, 128.0f},  {1024, 256.0f},  {1024, 512.0f},  {2048, 1024.0f},
8336                                     {4096, 2048.0f}, {8192, 4096.0f}, {9216, 8192.0f}, {10240, 10000.0f}};
8337 
8338             for (size_t testCombNdx = 0; testCombNdx < DE_LENGTH_OF_ARRAY(testCombinations); testCombNdx++)
8339             {
8340                 std::string testCaseName = "point_size_" + de::toString(testCombinations[testCombNdx].pointSize);
8341                 uint32_t renderSize      = testCombinations[testCombNdx].renderSize;
8342                 float pointSize          = testCombinations[testCombNdx].pointSize;
8343 
8344                 points->addChild(
8345                     new PointSizeTestCase<PointSizeTestInstance>(testCtx, testCaseName, renderSize, pointSize));
8346             }
8347 
8348             primitiveSize->addChild(points);
8349         }
8350 
8351         // .default_size
8352         {
8353             // Default size
8354             tcu::TestCaseGroup *const defaultSize = new tcu::TestCaseGroup(testCtx, "default_size");
8355 
8356             // .points
8357             {
8358                 // Default point size
8359                 tcu::TestCaseGroup *const points                = new tcu::TestCaseGroup(testCtx, "points");
8360                 static const VkShaderStageFlags vertexStageBits = VK_SHADER_STAGE_VERTEX_BIT;
8361                 static const VkShaderStageFlags tessellationStageBits =
8362                     VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
8363                 static const VkShaderStageFlags geometryStageBits = VK_SHADER_STAGE_GEOMETRY_BIT;
8364                 static const struct PointDefaultSizeCombination
8365                 {
8366                     const VkShaderStageFlags stageFlags;
8367                     const std::string stageName;
8368                 } pointDefaultSizeCombinations[] = {
8369                     {vertexStageBits, "vertex"},
8370                     {vertexStageBits | tessellationStageBits, "tessellation"},
8371                     {vertexStageBits | geometryStageBits, "geometry"},
8372                     {vertexStageBits | tessellationStageBits | geometryStageBits, "all"},
8373                 };
8374 
8375                 for (size_t testCombNdx = 0u; testCombNdx < DE_LENGTH_OF_ARRAY(pointDefaultSizeCombinations);
8376                      testCombNdx++)
8377                 {
8378                     const std::string testCaseName          = pointDefaultSizeCombinations[testCombNdx].stageName;
8379                     const VkShaderStageFlags testStageFlags = pointDefaultSizeCombinations[testCombNdx].stageFlags;
8380                     const uint32_t renderSize               = 3u; // Odd number so only the center pixel is rendered
8381 
8382                     points->addChild(new PointDefaultSizeTestCase(testCtx, testCaseName, renderSize, testStageFlags));
8383                 }
8384 
8385                 defaultSize->addChild(points);
8386             }
8387 
8388 #ifndef CTS_USES_VULKANSC
8389             // .polygons_as_points
8390             {
8391                 tcu::TestCaseGroup *const polygonsAsPoints = new tcu::TestCaseGroup(testCtx, "polygon_as_points");
8392                 for (int k = 0; k < 2; ++k)
8393                 {
8394                     for (int j = 0; j < 2; ++j)
8395                     {
8396                         for (int i = 0; i < 2; ++i)
8397                         {
8398                             for (int m = 0; m < 2; ++m)
8399                             {
8400                                 const bool meshShader      = (m > 0);
8401                                 const bool tessellation    = (i > 0);
8402                                 const bool geometryShader  = (j > 0);
8403                                 const bool dynamicPolyMode = (k > 0);
8404 
8405                                 if (meshShader && (tessellation || geometryShader))
8406                                     continue;
8407 
8408                                 std::string testName(meshShader ? "mesh" : "vert");
8409 
8410                                 if (tessellation)
8411                                     testName += "_tess";
8412 
8413                                 if (geometryShader)
8414                                     testName += "_geom";
8415 
8416                                 testName += (dynamicPolyMode ? "_dynamic_polygon_mode" : "_static_polygon_mode");
8417 
8418                                 PolygonModeLargePointsConfig config(1.0f, meshShader, tessellation, geometryShader,
8419                                                                     dynamicPolyMode, true);
8420                                 polygonsAsPoints->addChild(new PolygonModeLargePointsCase(testCtx, testName, config));
8421                             }
8422                         }
8423                     }
8424                 }
8425 
8426                 defaultSize->addChild(polygonsAsPoints);
8427             }
8428 #endif
8429 
8430             primitiveSize->addChild(defaultSize);
8431         }
8432     }
8433 
8434 #ifndef CTS_USES_VULKANSC
8435     // .polygon_as_large_points
8436     {
8437         de::MovePtr<tcu::TestCaseGroup> polygonModeLargePointsGroup(
8438             new tcu::TestCaseGroup(testCtx, "polygon_as_large_points"));
8439 
8440         for (int k = 0; k < 2; ++k)
8441             for (int j = 0; j < 2; ++j)
8442                 for (int i = 0; i < 2; ++i)
8443                     for (int m = 0; m < 2; ++m)
8444                     {
8445                         const bool meshShader      = (m > 0);
8446                         const bool tessellation    = (i > 0);
8447                         const bool geometryShader  = (j > 0);
8448                         const bool dynamicPolyMode = (k > 0);
8449 
8450                         if (meshShader && (tessellation || geometryShader))
8451                             continue;
8452 
8453                         std::string testName(meshShader ? "mesh" : "vert");
8454 
8455                         if (tessellation)
8456                             testName += "_tess";
8457 
8458                         if (geometryShader)
8459                             testName += "_geom";
8460 
8461                         testName += (dynamicPolyMode ? "_dynamic_polygon_mode" : "_static_polygon_mode");
8462 
8463                         PolygonModeLargePointsConfig config(2.0f, meshShader, tessellation, geometryShader,
8464                                                             dynamicPolyMode);
8465                         polygonModeLargePointsGroup->addChild(
8466                             new PolygonModeLargePointsCase(testCtx, testName, config));
8467                     }
8468 
8469         rasterizationTests->addChild(polygonModeLargePointsGroup.release());
8470     }
8471 #endif // CTS_USES_VULKANSC
8472 
8473     // .fill_rules
8474     {
8475         tcu::TestCaseGroup *const fillRules = new tcu::TestCaseGroup(testCtx, "fill_rules");
8476 
8477         rasterizationTests->addChild(fillRules);
8478 
8479         fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad", FillRuleTestInstance::FILLRULECASE_BASIC));
8480         fillRules->addChild(
8481             new FillRuleTestCase(testCtx, "basic_quad_reverse", FillRuleTestInstance::FILLRULECASE_REVERSED));
8482         fillRules->addChild(
8483             new FillRuleTestCase(testCtx, "clipped_full", FillRuleTestInstance::FILLRULECASE_CLIPPED_FULL));
8484         fillRules->addChild(
8485             new FillRuleTestCase(testCtx, "clipped_partly", FillRuleTestInstance::FILLRULECASE_CLIPPED_PARTIAL));
8486         fillRules->addChild(new FillRuleTestCase(testCtx, "projected", FillRuleTestInstance::FILLRULECASE_PROJECTED));
8487     }
8488 
8489     // .culling
8490     {
8491         static const struct CullMode
8492         {
8493             VkCullModeFlags mode;
8494             const char *prefix;
8495         } cullModes[] = {
8496             {VK_CULL_MODE_FRONT_BIT, "front_"},
8497             {VK_CULL_MODE_BACK_BIT, "back_"},
8498             {VK_CULL_MODE_FRONT_AND_BACK, "both_"},
8499         };
8500         static const struct PrimitiveType
8501         {
8502             VkPrimitiveTopology type;
8503             const char *name;
8504         } primitiveTypes[] = {
8505             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles"},
8506             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip"},
8507             {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan"},
8508         };
8509         static const struct FrontFaceOrder
8510         {
8511             VkFrontFace mode;
8512             const char *postfix;
8513         } frontOrders[] = {
8514             {VK_FRONT_FACE_COUNTER_CLOCKWISE, ""},
8515             {VK_FRONT_FACE_CLOCKWISE, "_reverse"},
8516         };
8517 
8518         static const struct PolygonMode
8519         {
8520             VkPolygonMode mode;
8521             const char *name;
8522         } polygonModes[] = {
8523             {VK_POLYGON_MODE_FILL, ""}, {VK_POLYGON_MODE_LINE, "_line"}, {VK_POLYGON_MODE_POINT, "_point"}};
8524 
8525         tcu::TestCaseGroup *const culling = new tcu::TestCaseGroup(testCtx, "culling");
8526 
8527         rasterizationTests->addChild(culling);
8528 
8529         for (int cullModeNdx = 0; cullModeNdx < DE_LENGTH_OF_ARRAY(cullModes); ++cullModeNdx)
8530             for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
8531                 for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders); ++frontOrderNdx)
8532                     for (int polygonModeNdx = 0; polygonModeNdx < DE_LENGTH_OF_ARRAY(polygonModes); ++polygonModeNdx)
8533                     {
8534                         if (!(cullModes[cullModeNdx].mode == VK_CULL_MODE_FRONT_AND_BACK &&
8535                               polygonModes[polygonModeNdx].mode != VK_POLYGON_MODE_FILL))
8536                         {
8537                             const std::string name =
8538                                 std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name +
8539                                 frontOrders[frontOrderNdx].postfix + polygonModes[polygonModeNdx].name;
8540                             // Test primitive culling.
8541                             culling->addChild(new CullingTestCase(
8542                                 testCtx, name, cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type,
8543                                 frontOrders[frontOrderNdx].mode, polygonModes[polygonModeNdx].mode));
8544                         }
8545                     }
8546 
8547         // Cull some triangles and check primitive ID works
8548         culling->addChild(new CullAndPrimitiveIdCase(testCtx, "primitive_id"));
8549     }
8550 
8551     // .discard
8552     {
8553         static const struct PrimitiveType
8554         {
8555             VkPrimitiveTopology type;
8556             const char *name;
8557         } primitiveTypes[] = {{VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangle_list"},
8558                               {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, "triangle_strip"},
8559                               {VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, "triangle_fan"},
8560                               {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "line_list"},
8561                               {VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, "line_strip"},
8562                               {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "point_list"}};
8563 
8564         static const struct queryPipeline
8565         {
8566             bool useQuery;
8567             const char *name;
8568         } queryPipeline[] = {
8569             {false, "query_pipeline_false"},
8570             {true, "query_pipeline_true"},
8571         };
8572 
8573         tcu::TestCaseGroup *const discard = new tcu::TestCaseGroup(testCtx, "discard");
8574 
8575         for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
8576         {
8577             tcu::TestCaseGroup *const primitive = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveNdx].name);
8578 
8579             for (int useQueryNdx = 0; useQueryNdx < DE_LENGTH_OF_ARRAY(queryPipeline); useQueryNdx++)
8580             {
8581                 const std::string name = std::string(queryPipeline[useQueryNdx].name);
8582                 // Test primitive discarding.
8583                 primitive->addChild(new DiscardTestCase(testCtx, name, primitiveTypes[primitiveNdx].type,
8584                                                         queryPipeline[useQueryNdx].useQuery));
8585             }
8586 
8587             discard->addChild(primitive);
8588         }
8589 
8590         rasterizationTests->addChild(discard);
8591     }
8592 
8593     // .conservative
8594     {
8595         typedef struct
8596         {
8597             float size;
8598             const char *name;
8599         } overestimateSizes;
8600 
8601         const overestimateSizes overestimateNormalSizes[] = {
8602             {0.00f, "0_00"}, {0.25f, "0_25"}, {0.50f, "0_50"},        {0.75f, "0_75"},       {1.00f, "1_00"},
8603             {2.00f, "2_00"}, {4.00f, "4_00"}, {-TCU_INFINITY, "min"}, {TCU_INFINITY, "max"},
8604         };
8605         const overestimateSizes overestimateDegenerate[] = {
8606             {0.00f, "0_00"},
8607             {0.25f, "0_25"},
8608             {-TCU_INFINITY, "min"},
8609             {TCU_INFINITY, "max"},
8610         };
8611         const overestimateSizes underestimateLineWidths[] = {
8612             {0.50f, "0_50"},
8613             {1.00f, "1_00"},
8614             {1.50f, "1_50"},
8615         };
8616         const overestimateSizes underestimatePointSizes[] = {
8617             {1.00f, "1_00"}, {1.50f, "1_50"}, {2.00f, "2_00"}, {3.00f, "3_00"}, {4.00f, "4_00"}, {8.00f, "8_00"},
8618         };
8619         const struct PrimitiveType
8620         {
8621             VkPrimitiveTopology type;
8622             const char *name;
8623         } primitiveTypes[]                    = {{VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, "triangles"},
8624                                                  {VK_PRIMITIVE_TOPOLOGY_LINE_LIST, "lines"},
8625                                                  {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, "points"}};
8626         const VkSampleCountFlagBits samples[] = {VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT,  VK_SAMPLE_COUNT_4_BIT,
8627                                                  VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT,
8628                                                  VK_SAMPLE_COUNT_64_BIT};
8629 
8630         tcu::TestCaseGroup *const conservative = new tcu::TestCaseGroup(testCtx, "conservative");
8631 
8632         rasterizationTests->addChild(conservative);
8633 
8634         {
8635             tcu::TestCaseGroup *const overestimate = new tcu::TestCaseGroup(testCtx, "overestimate");
8636 
8637             conservative->addChild(overestimate);
8638 
8639             for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
8640             {
8641                 const std::string samplesGroupName = "samples_" + de::toString(samples[samplesNdx]);
8642 
8643                 tcu::TestCaseGroup *const samplesGroup = new tcu::TestCaseGroup(testCtx, samplesGroupName.c_str());
8644 
8645                 overestimate->addChild(samplesGroup);
8646 
8647                 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes);
8648                      ++primitiveTypeNdx)
8649                 {
8650                     tcu::TestCaseGroup *const primitiveGroup =
8651                         new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveTypeNdx].name);
8652 
8653                     samplesGroup->addChild(primitiveGroup);
8654 
8655                     {
8656                         tcu::TestCaseGroup *const normal = new tcu::TestCaseGroup(testCtx, "normal");
8657 
8658                         primitiveGroup->addChild(normal);
8659 
8660                         for (int overestimateSizesNdx = 0;
8661                              overestimateSizesNdx < DE_LENGTH_OF_ARRAY(overestimateNormalSizes); ++overestimateSizesNdx)
8662                         {
8663                             const ConservativeTestConfig config = {
8664                                 VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
8665                                 overestimateNormalSizes[overestimateSizesNdx].size, //  float extraOverestimationSize;
8666                                 primitiveTypes[primitiveTypeNdx].type, //  VkPrimitiveTopology primitiveTopology;
8667                                 false,                                 //  bool degeneratePrimitives;
8668                                 1.0f,                                  //  float lineWidth;
8669                                 RESOLUTION_POT,                        //  uint32_t resolution;
8670                             };
8671 
8672                             // Overestimate tests, verify rasterization result
8673 
8674                             if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
8675                                 normal->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>(
8676                                     testCtx, overestimateNormalSizes[overestimateSizesNdx].name, config,
8677                                     samples[samplesNdx]));
8678 
8679                             if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
8680                                 normal->addChild(new ConservativeTestCase<ConservativeLineTestInstance>(
8681                                     testCtx, overestimateNormalSizes[overestimateSizesNdx].name, config,
8682                                     samples[samplesNdx]));
8683 
8684                             if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
8685                                 normal->addChild(new ConservativeTestCase<ConservativePointTestInstance>(
8686                                     testCtx, overestimateNormalSizes[overestimateSizesNdx].name, config,
8687                                     samples[samplesNdx]));
8688                         }
8689                     }
8690 
8691                     {
8692                         tcu::TestCaseGroup *const degenerate = new tcu::TestCaseGroup(testCtx, "degenerate");
8693 
8694                         primitiveGroup->addChild(degenerate);
8695 
8696                         for (int overestimateSizesNdx = 0;
8697                              overestimateSizesNdx < DE_LENGTH_OF_ARRAY(overestimateDegenerate); ++overestimateSizesNdx)
8698                         {
8699                             const ConservativeTestConfig config = {
8700                                 VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
8701                                 overestimateDegenerate[overestimateSizesNdx].size, //  float extraOverestimationSize;
8702                                 primitiveTypes[primitiveTypeNdx].type, //  VkPrimitiveTopology primitiveTopology;
8703                                 true,                                  //  bool degeneratePrimitives;
8704                                 1.0f,                                  //  float lineWidth;
8705                                 64u,                                   //  uint32_t resolution;
8706                             };
8707 
8708                             // Overestimate triangle test, verify rasterization result
8709 
8710                             if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
8711                                 degenerate->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>(
8712                                     testCtx, overestimateDegenerate[overestimateSizesNdx].name, config,
8713                                     samples[samplesNdx]));
8714 
8715                             if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
8716                                 degenerate->addChild(new ConservativeTestCase<ConservativeLineTestInstance>(
8717                                     testCtx, overestimateDegenerate[overestimateSizesNdx].name, config,
8718                                     samples[samplesNdx]));
8719                         }
8720                     }
8721                 }
8722             }
8723         }
8724 
8725         {
8726             tcu::TestCaseGroup *const underestimate = new tcu::TestCaseGroup(testCtx, "underestimate");
8727 
8728             conservative->addChild(underestimate);
8729 
8730             for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
8731             {
8732                 const std::string samplesGroupName = "samples_" + de::toString(samples[samplesNdx]);
8733 
8734                 tcu::TestCaseGroup *const samplesGroup = new tcu::TestCaseGroup(testCtx, samplesGroupName.c_str());
8735 
8736                 underestimate->addChild(samplesGroup);
8737 
8738                 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes);
8739                      ++primitiveTypeNdx)
8740                 {
8741                     tcu::TestCaseGroup *const primitiveGroup =
8742                         new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveTypeNdx].name);
8743 
8744                     samplesGroup->addChild(primitiveGroup);
8745 
8746                     {
8747                         tcu::TestCaseGroup *const normal = new tcu::TestCaseGroup(testCtx, "normal");
8748 
8749                         primitiveGroup->addChild(normal);
8750 
8751                         ConservativeTestConfig config = {
8752                             VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
8753                             0.0f,                                                 //  float extraOverestimationSize;
8754                             primitiveTypes[primitiveTypeNdx].type, //  VkPrimitiveTopology primitiveTopology;
8755                             false,                                 //  bool degeneratePrimitives;
8756                             1.0f,                                  //  float lineWidth;
8757                             64u,                                   //  uint32_t resolution;
8758                         };
8759 
8760                         // Underestimate test, verify rasterization result
8761 
8762                         if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
8763                             normal->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>(
8764                                 testCtx, "test", config, samples[samplesNdx]));
8765 
8766                         if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
8767                         {
8768                             for (int underestimateWidthNdx = 0;
8769                                  underestimateWidthNdx < DE_LENGTH_OF_ARRAY(underestimateLineWidths);
8770                                  ++underestimateWidthNdx)
8771                             {
8772                                 config.lineWidth = underestimateLineWidths[underestimateWidthNdx].size;
8773                                 normal->addChild(new ConservativeTestCase<ConservativeLineTestInstance>(
8774                                     testCtx, underestimateLineWidths[underestimateWidthNdx].name, config,
8775                                     samples[samplesNdx]));
8776                             }
8777                         }
8778 
8779                         if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
8780                         {
8781                             for (int underestimatePointSizeNdx = 0;
8782                                  underestimatePointSizeNdx < DE_LENGTH_OF_ARRAY(underestimatePointSizes);
8783                                  ++underestimatePointSizeNdx)
8784                             {
8785                                 config.lineWidth = underestimatePointSizes[underestimatePointSizeNdx].size;
8786                                 normal->addChild(new ConservativeTestCase<ConservativePointTestInstance>(
8787                                     testCtx, underestimatePointSizes[underestimatePointSizeNdx].name, config,
8788                                     samples[samplesNdx]));
8789                             }
8790                         }
8791                     }
8792 
8793                     { // Degenerate primitives conservative rasterization tests
8794                         tcu::TestCaseGroup *const degenerate = new tcu::TestCaseGroup(testCtx, "degenerate");
8795 
8796                         primitiveGroup->addChild(degenerate);
8797 
8798                         ConservativeTestConfig config = {
8799                             VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT, //  VkConservativeRasterizationModeEXT conservativeRasterizationMode;
8800                             0.0f,                                                 //  float extraOverestimationSize;
8801                             primitiveTypes[primitiveTypeNdx].type, //  VkPrimitiveTopology primitiveTopology;
8802                             true,                                  //  bool degeneratePrimitives;
8803                             1.0f,                                  //  float lineWidth;
8804                             64u,                                   //  uint32_t resolution;
8805                         };
8806 
8807                         if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
8808                             // Underestimate triangle test, verify rasterization result
8809                             degenerate->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>(
8810                                 testCtx, "test", config, samples[samplesNdx]));
8811 
8812                         if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
8813                         {
8814                             for (int underestimateWidthNdx = 0;
8815                                  underestimateWidthNdx < DE_LENGTH_OF_ARRAY(underestimateLineWidths);
8816                                  ++underestimateWidthNdx)
8817                             {
8818                                 config.lineWidth = underestimateLineWidths[underestimateWidthNdx].size;
8819                                 // Underestimate line test, verify rasterization result
8820                                 degenerate->addChild(new ConservativeTestCase<ConservativeLineTestInstance>(
8821                                     testCtx, underestimateLineWidths[underestimateWidthNdx].name, config,
8822                                     samples[samplesNdx]));
8823                             }
8824                         }
8825                     }
8826                 }
8827             }
8828         }
8829     }
8830 
8831     // .interpolation
8832     {
8833         tcu::TestCaseGroup *const interpolation = new tcu::TestCaseGroup(testCtx, "interpolation");
8834 
8835         rasterizationTests->addChild(interpolation);
8836 
8837         // .basic
8838         {
8839             tcu::TestCaseGroup *const basic = new tcu::TestCaseGroup(testCtx, "basic");
8840 
8841             interpolation->addChild(basic);
8842 
8843             // Verify triangle interpolation
8844             basic->addChild(new TriangleInterpolationTestCase(testCtx, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
8845                                                               INTERPOLATIONFLAGS_NONE));
8846             // Verify triangle strip interpolation
8847             basic->addChild(new TriangleInterpolationTestCase(
8848                 testCtx, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, INTERPOLATIONFLAGS_NONE));
8849             // Verify triangle fan interpolation
8850             basic->addChild(new TriangleInterpolationTestCase(
8851                 testCtx, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, INTERPOLATIONFLAGS_NONE));
8852             // Verify line interpolation
8853             basic->addChild(new LineInterpolationTestCase(testCtx, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8854                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW,
8855                                                           PRIMITIVESTRICTNESS_IGNORE));
8856             // Verify line strip interpolation
8857             basic->addChild(new LineInterpolationTestCase(testCtx, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
8858                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW,
8859                                                           PRIMITIVESTRICTNESS_IGNORE));
8860             // Verify wide line interpolation
8861             basic->addChild(new LineInterpolationTestCase(testCtx, "lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8862                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE,
8863                                                           PRIMITIVESTRICTNESS_IGNORE));
8864             // Verify wide line strip interpolation
8865             basic->addChild(new LineInterpolationTestCase(testCtx, "line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
8866                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE,
8867                                                           PRIMITIVESTRICTNESS_IGNORE));
8868 
8869             // Verify strict line interpolation
8870             basic->addChild(new LineInterpolationTestCase(testCtx, "strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8871                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW,
8872                                                           PRIMITIVESTRICTNESS_STRICT));
8873             // Verify strict line strip interpolation
8874             basic->addChild(new LineInterpolationTestCase(testCtx, "strict_line_strip",
8875                                                           VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE,
8876                                                           PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
8877             // Verify strict wide line interpolation
8878             basic->addChild(new LineInterpolationTestCase(testCtx, "strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8879                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE,
8880                                                           PRIMITIVESTRICTNESS_STRICT));
8881             // Verify strict wide line strip interpolation
8882             basic->addChild(new LineInterpolationTestCase(testCtx, "strict_line_strip_wide",
8883                                                           VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE,
8884                                                           PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
8885 
8886             // Verify non-strict line interpolation
8887             basic->addChild(new LineInterpolationTestCase(testCtx, "non_strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8888                                                           INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW,
8889                                                           PRIMITIVESTRICTNESS_NONSTRICT));
8890             // Verify non-strict line strip interpolation
8891             basic->addChild(new LineInterpolationTestCase(testCtx, "non_strict_line_strip",
8892                                                           VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE,
8893                                                           PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
8894             // Verify non-strict wide line interpolation
8895             basic->addChild(new LineInterpolationTestCase(testCtx, "non_strict_lines_wide",
8896                                                           VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE,
8897                                                           PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
8898             // Verify non-strict wide line strip interpolation
8899             basic->addChild(new LineInterpolationTestCase(testCtx, "non_strict_line_strip_wide",
8900                                                           VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_NONE,
8901                                                           PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
8902         }
8903 
8904         // .projected
8905         {
8906             tcu::TestCaseGroup *const projected = new tcu::TestCaseGroup(testCtx, "projected");
8907 
8908             interpolation->addChild(projected);
8909 
8910             // Verify triangle interpolation
8911             projected->addChild(new TriangleInterpolationTestCase(
8912                 testCtx, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, INTERPOLATIONFLAGS_PROJECTED));
8913             // Verify triangle strip interpolation
8914             projected->addChild(new TriangleInterpolationTestCase(
8915                 testCtx, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, INTERPOLATIONFLAGS_PROJECTED));
8916             // Verify triangle fan interpolation
8917             projected->addChild(new TriangleInterpolationTestCase(
8918                 testCtx, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, INTERPOLATIONFLAGS_PROJECTED));
8919             // Verify line interpolation
8920             projected->addChild(new LineInterpolationTestCase(testCtx, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8921                                                               INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW,
8922                                                               PRIMITIVESTRICTNESS_IGNORE));
8923             // Verify line strip interpolation
8924             projected->addChild(new LineInterpolationTestCase(testCtx, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
8925                                                               INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW,
8926                                                               PRIMITIVESTRICTNESS_IGNORE));
8927             // Verify wide line interpolation
8928             projected->addChild(new LineInterpolationTestCase(testCtx, "lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8929                                                               INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_WIDE,
8930                                                               PRIMITIVESTRICTNESS_IGNORE));
8931             // Verify wide line strip interpolation
8932             projected->addChild(new LineInterpolationTestCase(
8933                 testCtx, "line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED,
8934                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
8935 
8936             // Verify strict line interpolation
8937             projected->addChild(new LineInterpolationTestCase(testCtx, "strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8938                                                               INTERPOLATIONFLAGS_PROJECTED, PRIMITIVEWIDENESS_NARROW,
8939                                                               PRIMITIVESTRICTNESS_STRICT));
8940             // Verify strict line strip interpolation
8941             projected->addChild(new LineInterpolationTestCase(
8942                 testCtx, "strict_line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED,
8943                 PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
8944             // Verify strict wide line interpolation
8945             projected->addChild(new LineInterpolationTestCase(
8946                 testCtx, "strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED,
8947                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
8948             // Verify strict wide line strip interpolation
8949             projected->addChild(new LineInterpolationTestCase(
8950                 testCtx, "strict_line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED,
8951                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
8952 
8953             // Verify non-strict line interpolation
8954             projected->addChild(new LineInterpolationTestCase(
8955                 testCtx, "non_strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED,
8956                 PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
8957             // Verify non-strict line strip interpolation
8958             projected->addChild(new LineInterpolationTestCase(
8959                 testCtx, "non_strict_line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED,
8960                 PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
8961             // Verify non-strict wide line interpolation
8962             projected->addChild(new LineInterpolationTestCase(
8963                 testCtx, "non_strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_PROJECTED,
8964                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
8965             // Verify non-strict wide line strip interpolation
8966             projected->addChild(new LineInterpolationTestCase(
8967                 testCtx, "non_strict_line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED,
8968                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
8969         }
8970     }
8971 
8972     // .flatshading
8973     {
8974         tcu::TestCaseGroup *const flatshading = new tcu::TestCaseGroup(testCtx, "flatshading");
8975 
8976         rasterizationTests->addChild(flatshading);
8977 
8978         // Verify triangle flatshading
8979         flatshading->addChild(new TriangleInterpolationTestCase(
8980             testCtx, "triangles", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, INTERPOLATIONFLAGS_FLATSHADE));
8981         // Verify triangle strip flatshading
8982         flatshading->addChild(new TriangleInterpolationTestCase(
8983             testCtx, "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, INTERPOLATIONFLAGS_FLATSHADE));
8984         // Verify triangle fan flatshading
8985         flatshading->addChild(new TriangleInterpolationTestCase(
8986             testCtx, "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, INTERPOLATIONFLAGS_FLATSHADE));
8987         // Verify line flatshading
8988         flatshading->addChild(new LineInterpolationTestCase(testCtx, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8989                                                             INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW,
8990                                                             PRIMITIVESTRICTNESS_IGNORE));
8991         // Verify line strip flatshading
8992         flatshading->addChild(new LineInterpolationTestCase(testCtx, "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
8993                                                             INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW,
8994                                                             PRIMITIVESTRICTNESS_IGNORE));
8995         // Verify wide line flatshading
8996         flatshading->addChild(new LineInterpolationTestCase(testCtx, "lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
8997                                                             INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_WIDE,
8998                                                             PRIMITIVESTRICTNESS_IGNORE));
8999         // Verify wide line strip flatshading
9000         flatshading->addChild(new LineInterpolationTestCase(
9001             testCtx, "line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE,
9002             PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE));
9003 
9004         // Verify strict line flatshading
9005         flatshading->addChild(new LineInterpolationTestCase(testCtx, "strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
9006                                                             INTERPOLATIONFLAGS_FLATSHADE, PRIMITIVEWIDENESS_NARROW,
9007                                                             PRIMITIVESTRICTNESS_STRICT));
9008         // Verify strict line strip flatshading
9009         flatshading->addChild(new LineInterpolationTestCase(
9010             testCtx, "strict_line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE,
9011             PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT));
9012         // Verify strict wide line flatshading
9013         flatshading->addChild(new LineInterpolationTestCase(
9014             testCtx, "strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE,
9015             PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
9016         // Verify strict wide line strip flatshading
9017         flatshading->addChild(new LineInterpolationTestCase(
9018             testCtx, "strict_line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE,
9019             PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT));
9020 
9021         // Verify non-strict line flatshading
9022         flatshading->addChild(new LineInterpolationTestCase(
9023             testCtx, "non_strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE,
9024             PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
9025         // Verify non-strict line strip flatshading
9026         flatshading->addChild(new LineInterpolationTestCase(
9027             testCtx, "non_strict_line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE,
9028             PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT));
9029         // Verify non-strict wide line flatshading
9030         flatshading->addChild(new LineInterpolationTestCase(
9031             testCtx, "non_strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_FLATSHADE,
9032             PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
9033         // Verify non-strict wide line strip flatshading
9034         flatshading->addChild(new LineInterpolationTestCase(
9035             testCtx, "non_strict_line_strip_wide", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, INTERPOLATIONFLAGS_FLATSHADE,
9036             PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT));
9037     }
9038 
9039     const VkSampleCountFlagBits samples[] = {VK_SAMPLE_COUNT_2_BIT,  VK_SAMPLE_COUNT_4_BIT,  VK_SAMPLE_COUNT_8_BIT,
9040                                              VK_SAMPLE_COUNT_16_BIT, VK_SAMPLE_COUNT_32_BIT, VK_SAMPLE_COUNT_64_BIT};
9041 
9042     for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
9043     {
9044         std::ostringstream caseName;
9045 
9046         caseName << "_multisample_" << (2 << samplesNdx) << "_bit";
9047 
9048         // .primitives
9049         {
9050             tcu::TestCaseGroup *const primitives =
9051                 new tcu::TestCaseGroup(testCtx, ("primitives" + caseName.str()).c_str());
9052 
9053             rasterizationTests->addChild(primitives);
9054 
9055             tcu::TestCaseGroup *const nostippleTests      = new tcu::TestCaseGroup(testCtx, "no_stipple");
9056             tcu::TestCaseGroup *const stippleStaticTests  = new tcu::TestCaseGroup(testCtx, "static_stipple");
9057             tcu::TestCaseGroup *const stippleDynamicTests = new tcu::TestCaseGroup(testCtx, "dynamic_stipple");
9058 
9059             primitives->addChild(nostippleTests);
9060             primitives->addChild(stippleStaticTests);
9061             primitives->addChild(stippleDynamicTests);
9062 
9063             // Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result
9064             nostippleTests->addChild(
9065                 new BaseTestCase<TrianglesTestInstance>(testCtx, "triangles", samples[samplesNdx]));
9066             // Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result
9067             nostippleTests->addChild(new WidenessTestCase<PointTestInstance>(
9068                 testCtx, "points", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, false, samples[samplesNdx],
9069                 LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
9070 
9071             // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode, verify rasterization result
9072             nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
9073                 testCtx, "strict_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true,
9074                 samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
9075             // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode with wide lines, verify rasterization result
9076             nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
9077                 testCtx, "strict_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true,
9078                 samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
9079 
9080             // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result
9081             nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
9082                 testCtx, "non_strict_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, true,
9083                 samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
9084             // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode with wide lines, verify rasterization result
9085             nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>(
9086                 testCtx, "non_strict_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, true,
9087                 samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_KHR_LAST));
9088 
9089             for (int i = 0; i < static_cast<int>(LINESTIPPLE_LAST); ++i)
9090             {
9091 
9092                 LineStipple stipple = (LineStipple)i;
9093 
9094                 // These variants are not needed for multisample cases.
9095                 if (stipple == LINESTIPPLE_DYNAMIC_WITH_TOPOLOGY)
9096                     continue;
9097 
9098                 tcu::TestCaseGroup *g = (stipple == LINESTIPPLE_DYNAMIC) ? stippleDynamicTests :
9099                                         (stipple == LINESTIPPLE_STATIC)  ? stippleStaticTests :
9100                                                                            nostippleTests;
9101 
9102                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
9103                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9104                     testCtx, "lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx],
9105                     stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, LineStippleFactorCase::DEFAULT,
9106                     i == 0 ? RESOLUTION_NPOT : 0));
9107                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
9108                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9109                     testCtx, "line_strip", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
9110                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
9111                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
9112                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9113                     testCtx, "lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
9114                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
9115                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
9116                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9117                     testCtx, "line_strip_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
9118                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
9119 
9120                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
9121                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9122                     testCtx, "rectangular_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true,
9123                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
9124                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
9125                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9126                     testCtx, "rectangular_line_strip", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, true,
9127                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
9128                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
9129                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9130                     testCtx, "rectangular_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true,
9131                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
9132                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
9133                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9134                     testCtx, "rectangular_line_strip_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, true,
9135                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
9136 
9137                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
9138                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9139                     testCtx, "bresenham_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
9140                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
9141                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
9142                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9143                     testCtx, "bresenham_line_strip", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
9144                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
9145                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
9146                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9147                     testCtx, "bresenham_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
9148                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
9149                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
9150                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9151                     testCtx, "bresenham_line_strip_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
9152                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
9153 
9154                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result
9155                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9156                     testCtx, "smooth_lines", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
9157                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
9158                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result
9159                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9160                     testCtx, "smooth_line_strip", PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_IGNORE, true,
9161                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
9162                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result
9163                 g->addChild(new WidenessTestCase<LinesTestInstance>(
9164                     testCtx, "smooth_lines_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
9165                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
9166                 // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result
9167                 g->addChild(new WidenessTestCase<LineStripTestInstance>(
9168                     testCtx, "smooth_line_strip_wide", PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_IGNORE, true,
9169                     samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
9170             }
9171         }
9172 
9173         // .fill_rules
9174         {
9175             tcu::TestCaseGroup *const fillRules =
9176                 new tcu::TestCaseGroup(testCtx, ("fill_rules" + caseName.str()).c_str());
9177 
9178             rasterizationTests->addChild(fillRules);
9179 
9180             // Verify fill rules
9181             fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad", FillRuleTestInstance::FILLRULECASE_BASIC,
9182                                                      samples[samplesNdx]));
9183             // Verify fill rules
9184             fillRules->addChild(new FillRuleTestCase(testCtx, "basic_quad_reverse",
9185                                                      FillRuleTestInstance::FILLRULECASE_REVERSED, samples[samplesNdx]));
9186             // Verify fill rules
9187             fillRules->addChild(new FillRuleTestCase(
9188                 testCtx, "clipped_full", FillRuleTestInstance::FILLRULECASE_CLIPPED_FULL, samples[samplesNdx]));
9189             // Verify fill rules
9190             fillRules->addChild(new FillRuleTestCase(
9191                 testCtx, "clipped_partly", FillRuleTestInstance::FILLRULECASE_CLIPPED_PARTIAL, samples[samplesNdx]));
9192             // Verify fill rules
9193             fillRules->addChild(new FillRuleTestCase(testCtx, "projected", FillRuleTestInstance::FILLRULECASE_PROJECTED,
9194                                                      samples[samplesNdx]));
9195         }
9196 
9197         // .interpolation
9198         {
9199             tcu::TestCaseGroup *const interpolation =
9200                 new tcu::TestCaseGroup(testCtx, ("interpolation" + caseName.str()).c_str());
9201 
9202             rasterizationTests->addChild(interpolation);
9203 
9204             // Verify triangle interpolation
9205             interpolation->addChild(new TriangleInterpolationTestCase(testCtx, "triangles",
9206                                                                       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
9207                                                                       INTERPOLATIONFLAGS_NONE, samples[samplesNdx]));
9208             // Verify line interpolation
9209             interpolation->addChild(new LineInterpolationTestCase(testCtx, "lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
9210                                                                   INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_NARROW,
9211                                                                   PRIMITIVESTRICTNESS_IGNORE, samples[samplesNdx]));
9212             // Verify wide line interpolation
9213             interpolation->addChild(new LineInterpolationTestCase(
9214                 testCtx, "lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE, PRIMITIVEWIDENESS_WIDE,
9215                 PRIMITIVESTRICTNESS_IGNORE, samples[samplesNdx]));
9216 
9217             // Verify strict line interpolation
9218             interpolation->addChild(new LineInterpolationTestCase(
9219                 testCtx, "strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE,
9220                 PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_STRICT, samples[samplesNdx]));
9221             // Verify strict wide line interpolation
9222             interpolation->addChild(new LineInterpolationTestCase(
9223                 testCtx, "strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE,
9224                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_STRICT, samples[samplesNdx]));
9225 
9226             // Verify non-strict line interpolation
9227             interpolation->addChild(new LineInterpolationTestCase(
9228                 testCtx, "non_strict_lines", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE,
9229                 PRIMITIVEWIDENESS_NARROW, PRIMITIVESTRICTNESS_NONSTRICT, samples[samplesNdx]));
9230             // Verify non-strict wide line interpolation
9231             interpolation->addChild(new LineInterpolationTestCase(
9232                 testCtx, "non_strict_lines_wide", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, INTERPOLATIONFLAGS_NONE,
9233                 PRIMITIVEWIDENESS_WIDE, PRIMITIVESTRICTNESS_NONSTRICT, samples[samplesNdx]));
9234         }
9235     }
9236 
9237     // .provoking_vertex
9238 #ifndef CTS_USES_VULKANSC
9239     {
9240         rasterizationTests->addChild(createProvokingVertexTests(testCtx));
9241     }
9242 #endif
9243 
9244     // .line_continuity
9245 #ifndef CTS_USES_VULKANSC
9246     {
9247         tcu::TestCaseGroup *const lineContinuity = new tcu::TestCaseGroup(testCtx, "line_continuity");
9248         static const char dataDir[]              = "rasterization/line_continuity";
9249 
9250         struct Case
9251         {
9252             std::string name;
9253             bool requireFillModeNonSolid;
9254         };
9255 
9256         static const Case cases[] = {// Test line strip drawing produces continuous lines
9257                                      {"line-strip", false},
9258                                      // Test triangles drawn with lines are continuous
9259                                      {"polygon-mode-lines", true}};
9260 
9261         rasterizationTests->addChild(lineContinuity);
9262 
9263         for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
9264         {
9265             const std::string fileName = cases[i].name + ".amber";
9266             cts_amber::AmberTestCase *testCase =
9267                 cts_amber::createAmberTestCase(testCtx, cases[i].name.c_str(), dataDir, fileName);
9268 
9269             if (cases[i].requireFillModeNonSolid)
9270             {
9271                 testCase->addRequirement("Features.fillModeNonSolid");
9272             }
9273 
9274             lineContinuity->addChild(testCase);
9275         }
9276     }
9277 #endif
9278 
9279     // .depth bias
9280 #ifndef CTS_USES_VULKANSC
9281     {
9282         tcu::TestCaseGroup *const depthBias = new tcu::TestCaseGroup(testCtx, "depth_bias");
9283         static const char dataDir[]         = "rasterization/depth_bias";
9284 
9285         static const struct
9286         {
9287             std::string name;
9288             vk::VkFormat format;
9289         } cases[] = {
9290             // Test depth bias with format D16_UNORM
9291             {"d16_unorm", vk::VK_FORMAT_D16_UNORM},
9292             // Test depth bias with format D32_SFLOAT
9293             {"d32_sfloat", vk::VK_FORMAT_D32_SFLOAT},
9294             // Test depth bias with format D24_UNORM_S8_UINT
9295             {"d24_unorm", vk::VK_FORMAT_D24_UNORM_S8_UINT},
9296             // Test depth bias constant 1 and -1 with format D16_UNORM
9297             {"d16_unorm_constant_one", vk::VK_FORMAT_D16_UNORM},
9298             // Test depth bias constant 1 and -1 with format D32_SFLOAT
9299             {"d32_sfloat_constant_one", vk::VK_FORMAT_D32_SFLOAT},
9300             // Test depth bias constant 1 and -1 with format D24_UNORM_S8_UINT
9301             {"d24_unorm_constant_one", vk::VK_FORMAT_D24_UNORM_S8_UINT},
9302             // Test depth bias slope with format D16_UNORM
9303             {"d16_unorm_slope", vk::VK_FORMAT_D16_UNORM},
9304             // Test depth bias constant 1 and -1 with format D16_UNORM
9305             {"d16_unorm_constant_one_less", vk::VK_FORMAT_D16_UNORM},
9306             // Test depth bias constant 1 and -1 with format D16_UNORM
9307             {"d16_unorm_constant_one_greater", vk::VK_FORMAT_D16_UNORM},
9308             // Test depth bias constant 1 and -1 with format D24_UNORM_S8_UINT
9309             {"d24_unorm_constant_one_less", vk::VK_FORMAT_D24_UNORM_S8_UINT},
9310             // Test depth bias constant 1 and -1 with format D24_UNORM_S8_UINT
9311             {"d24_unorm_constant_one_greater", vk::VK_FORMAT_D24_UNORM_S8_UINT},
9312             // Test depth bias constant 1 and -1 with format D32_SFLOAT
9313             {"d32_sfloat_constant_one_less", vk::VK_FORMAT_D32_SFLOAT},
9314             // Test depth bias constant 1 and -1 with format D32_SFLOAT
9315             {"d32_sfloat_constant_one_greater", vk::VK_FORMAT_D32_SFLOAT},
9316         };
9317 
9318         for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
9319         {
9320             const VkImageCreateInfo vkImageCreateInfo = {
9321                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
9322                 nullptr,                                     // pNext
9323                 0,                                           // flags
9324                 VK_IMAGE_TYPE_2D,                            // imageType
9325                 cases[i].format,                             // format
9326                 {250, 250, 1},                               // extent
9327                 1,                                           // mipLevels
9328                 1,                                           // arrayLayers
9329                 VK_SAMPLE_COUNT_1_BIT,                       // samples
9330                 VK_IMAGE_TILING_OPTIMAL,                     // tiling
9331                 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, // usage
9332                 VK_SHARING_MODE_EXCLUSIVE,                   // sharingMode
9333                 0,                                           // queueFamilyIndexCount
9334                 nullptr,                                     // pQueueFamilyIndices
9335                 VK_IMAGE_LAYOUT_UNDEFINED,                   // initialLayout
9336             };
9337 
9338             std::vector<std::string> requirements = std::vector<std::string>(0);
9339             std::vector<VkImageCreateInfo> imageRequirements;
9340             imageRequirements.push_back(vkImageCreateInfo);
9341             const std::string fileName         = cases[i].name + ".amber";
9342             cts_amber::AmberTestCase *testCase = cts_amber::createAmberTestCase(
9343                 testCtx, cases[i].name.c_str(), dataDir, fileName, requirements, imageRequirements);
9344 
9345             depthBias->addChild(testCase);
9346         }
9347 
9348         rasterizationTests->addChild(depthBias);
9349     }
9350 #endif // CTS_USES_VULKANSC
9351 
9352 #ifndef CTS_USES_VULKANSC
9353     // Depth bias control.
9354     rasterizationTests->addChild(createDepthBiasControlTests(testCtx));
9355 #endif // CTS_USES_VULKANSC
9356 
9357     // Fragment shader side effects.
9358     {
9359         rasterizationTests->addChild(createFragSideEffectsTests(testCtx));
9360     }
9361 
9362 #ifndef CTS_USES_VULKANSC
9363     // Rasterization order attachment access tests
9364     {
9365         rasterizationTests->addChild(createRasterizationOrderAttachmentAccessTests(testCtx));
9366     }
9367 
9368     // Tile Storage tests
9369     {
9370         rasterizationTests->addChild(createShaderTileImageTests(testCtx));
9371     }
9372 #endif // CTS_USES_VULKANSC
9373 
9374 #ifndef CTS_USES_VULKANSC
9375     // .maintenance5
9376     {
9377         //NonStrictLineStripMaintenance5TestInstance
9378         tcu::TestCaseGroup *const maintenance5tests = new tcu::TestCaseGroup(testCtx, "maintenance5");
9379         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result
9380         maintenance5tests->addChild(new NonStrictLinesMaintenance5TestCase<NonStrictLinesMaintenance5TestInstance>(
9381             testCtx, "non_strict_lines_narrow", PRIMITIVEWIDENESS_NARROW));
9382         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result
9383         maintenance5tests->addChild(new NonStrictLinesMaintenance5TestCase<NonStrictLinesMaintenance5TestInstance>(
9384             testCtx, "non_strict_lines_wide", PRIMITIVEWIDENESS_WIDE));
9385         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode, verify rasterization result
9386         maintenance5tests->addChild(new NonStrictLinesMaintenance5TestCase<NonStrictLineStripMaintenance5TestInstance>(
9387             testCtx, "non_strict_line_strip_narrow", PRIMITIVEWIDENESS_NARROW));
9388         // Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode, verify rasterization result
9389         maintenance5tests->addChild(new NonStrictLinesMaintenance5TestCase<NonStrictLineStripMaintenance5TestInstance>(
9390             testCtx, "non_strict_line_strip_wide", PRIMITIVEWIDENESS_WIDE));
9391         rasterizationTests->addChild(maintenance5tests);
9392     }
9393 #endif // CTS_USES_VULKANSC
9394 }
9395 
9396 } // namespace
9397 
createTests(tcu::TestContext & testCtx,const std::string & name)9398 tcu::TestCaseGroup *createTests(tcu::TestContext &testCtx, const std::string &name)
9399 {
9400     return createTestGroup(testCtx, name.c_str(), createRasterizationTests);
9401 }
9402 
9403 } // namespace rasterization
9404 } // namespace vkt
9405