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