1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Test for VK_EXT_multi_draw
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktDrawMultiExtTests.hpp"
26
27 #include "vkTypeUtil.hpp"
28 #include "vkImageWithMemory.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35
36 #include "tcuTexture.hpp"
37 #include "tcuMaybe.hpp"
38 #include "tcuImageCompare.hpp"
39
40 #include "deUniquePtr.hpp"
41 #include "deMath.h"
42 #include "deRandom.hpp"
43
44 #include <vector>
45 #include <sstream>
46 #include <algorithm>
47 #include <iterator>
48 #include <limits>
49
50 using namespace vk;
51
52 namespace vkt
53 {
54 namespace Draw
55 {
56
57 namespace
58 {
59
60 // Normal or indexed draws.
61 enum class DrawType { NORMAL = 0, INDEXED };
62
63 // How to apply the vertex offset in indexed draws.
64 enum class VertexOffsetType
65 {
66 MIXED = 0, // Do not use pVertexOffset and mix values in struct-indicated offsets.
67 CONSTANT_RANDOM, // Use a constant value for pVertexOffset and fill offset struct members with random values.
68 CONSTANT_PACK, // Use a constant value for pVertexOffset and a stride that removes the vertex offset member in structs.
69 };
70
71 // Triangle mesh type.
72 enum class MeshType { MOSAIC = 0, OVERLAPPING };
73
74 // Vertex offset parameters.
75 struct VertexOffsetParams
76 {
77 VertexOffsetType offsetType;
78 deUint32 offset;
79 };
80
81 // Test parameters.
82 struct TestParams
83 {
84 MeshType meshType;
85 DrawType drawType;
86 deUint32 drawCount;
87 deUint32 instanceCount;
88 deUint32 firstInstance;
89 deUint32 stride;
90 tcu::Maybe<VertexOffsetParams> vertexOffset; // Only used for indexed draws.
91 deUint32 seed;
92 bool useTessellation;
93 bool useGeometry;
94 bool multiview;
95 const SharedGroupParams groupParams;
96
maxInstanceIndexvkt::Draw::__anoneea1706f0111::TestParams97 deUint32 maxInstanceIndex () const
98 {
99 if (instanceCount == 0u)
100 return 0u;
101 return (firstInstance + instanceCount - 1u);
102 }
103 };
104
105 // For the color attachment. Must match what the fragment shader expects.
getColorFormat()106 VkFormat getColorFormat ()
107 {
108 return VK_FORMAT_R8G8B8A8_UINT;
109 }
110
111 // Compatible with getColorFormat() but better when used with the image logging facilities.
getVerificationFormat()112 VkFormat getVerificationFormat ()
113 {
114 return VK_FORMAT_R8G8B8A8_UNORM;
115 }
116
117 // Find a suitable format for the depth/stencil buffer.
chooseDepthStencilFormat(const InstanceInterface & vki,VkPhysicalDevice physDev)118 VkFormat chooseDepthStencilFormat (const InstanceInterface& vki, VkPhysicalDevice physDev)
119 {
120 // The spec mandates support for one of these two formats.
121 const VkFormat candidates[] = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT };
122
123 for (const auto& format : candidates)
124 {
125 const auto properties = getPhysicalDeviceFormatProperties(vki, physDev, format);
126 if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u)
127 return format;
128 }
129
130 TCU_FAIL("No suitable depth/stencil format found");
131 return VK_FORMAT_UNDEFINED; // Unreachable.
132 }
133
134 // Format used when verifying the stencil aspect.
getStencilVerificationFormat()135 VkFormat getStencilVerificationFormat ()
136 {
137 return VK_FORMAT_S8_UINT;
138 }
139
getTriangleCount()140 deUint32 getTriangleCount ()
141 {
142 return 1024u; // This matches the minumum allowed limit for maxMultiDrawCount, so we can submit a single triangle per draw call.
143 }
144
145 // Base class for creating triangles.
146 class TriangleGenerator
147 {
148 public:
149 // Append a new triangle for ID (x, y).
150 virtual void appendTriangle(deUint32 x, deUint32 y, std::vector<tcu::Vec4>& vertices) = 0;
151 };
152
153 // Class that helps creating triangle vertices for each framebuffer pixel, forming a mosaic of triangles.
154 class TriangleMosaicGenerator : public TriangleGenerator
155 {
156 private:
157 // Normalized width and height taking into account the framebuffer's width and height are two units (from -1 to 1).
158 float m_pixelWidth;
159 float m_pixelHeight;
160
161 float m_deltaX;
162 float m_deltaY;
163
164 public:
TriangleMosaicGenerator(deUint32 width,deUint32 height)165 TriangleMosaicGenerator (deUint32 width, deUint32 height)
166 : m_pixelWidth (2.0f / static_cast<float>(width))
167 , m_pixelHeight (2.0f / static_cast<float>(height))
168 , m_deltaX (m_pixelWidth * 0.25f)
169 , m_deltaY (m_pixelHeight * 0.25f)
170 {}
171
172 // Creates a triangle for framebuffer pixel (x, y) around its center. Appends the triangle vertices to the given list.
appendTriangle(deUint32 x,deUint32 y,std::vector<tcu::Vec4> & vertices)173 void appendTriangle(deUint32 x, deUint32 y, std::vector<tcu::Vec4>& vertices) override
174 {
175 // Pixel center.
176 const float coordX = (static_cast<float>(x) + 0.5f) * m_pixelWidth - 1.0f;
177 const float coordY = (static_cast<float>(y) + 0.5f) * m_pixelHeight - 1.0f;
178
179 // Triangle around it.
180 const float topY = coordY - m_deltaY;
181 const float bottomY = coordY + m_deltaY;
182
183 const float leftX = coordX - m_deltaX;
184 const float rightX = coordX + m_deltaX;
185
186 // Note: clockwise.
187 vertices.emplace_back(leftX, bottomY, 0.0f, 1.0f);
188 vertices.emplace_back(coordX, topY, 0.0f, 1.0f);
189 vertices.emplace_back(rightX, bottomY, 0.0f, 1.0f);
190 }
191 };
192
193 // Class that helps create full-screen triangles that overlap each other.
194 // This generator will generate width*height full-screen triangles with decreasing depth from 0.75 to 0.25.
195 class TriangleOverlapGenerator : public TriangleGenerator
196 {
197 private:
198 // Normalized width and height taking into account the framebuffer's width and height are two units (from -1 to 1).
199 deUint32 m_width;
200 deUint32 m_totalPixels;
201 float m_depthStep;
202
203 static constexpr float kMinDepth = 0.25f;
204 static constexpr float kMaxDepth = 0.75f;
205 static constexpr float kDepthRange = kMaxDepth - kMinDepth;
206
207 public:
TriangleOverlapGenerator(deUint32 width,deUint32 height)208 TriangleOverlapGenerator (deUint32 width, deUint32 height)
209 : m_width (width)
210 , m_totalPixels (width * height)
211 , m_depthStep (kDepthRange / static_cast<float>(m_totalPixels))
212 {}
213
214 // Creates full-screen triangle with 2D id (x, y) and decreasing depth with increasing ids.
appendTriangle(deUint32 x,deUint32 y,std::vector<tcu::Vec4> & vertices)215 void appendTriangle(deUint32 x, deUint32 y, std::vector<tcu::Vec4>& vertices) override
216 {
217 const auto pixelId = static_cast<float>(y * m_width + x);
218 const auto depth = kMaxDepth - m_depthStep * pixelId;
219
220 // Note: clockwise.
221 vertices.emplace_back(-1.0f, -1.0f, depth, 1.0f);
222 vertices.emplace_back(4.0f, -1.0f, depth, 1.0f);
223 vertices.emplace_back(-1.0f, 4.0f, depth, 1.0f);
224 }
225 };
226
227 // Class that helps creating a suitable draw info vector.
228 class DrawInfoPacker
229 {
230 private:
231 DrawType m_drawType;
232 tcu::Maybe<VertexOffsetType> m_offsetType; // Offset type when m_drawType is DrawType::INDEXED.
233 deUint32 m_stride; // Desired stride. Must be zero or at least as big as the needed VkMultiDraw*InfoExt.
234 deUint32 m_extraBytes; // Used to match the desired stride.
235 de::Random m_random; // Used to generate random offsets.
236 deUint32 m_infoCount; // How many infos have we appended so far?
237 std::vector<deUint8> m_dataVec; // Data vector in generic form.
238
239 // Are draws indexed and using the offset member of VkMultiDrawIndexedInfoEXT?
indexedWithOffset(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType)240 static bool indexedWithOffset (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType)
241 {
242 return (drawType == DrawType::INDEXED && *offsetType != VertexOffsetType::CONSTANT_PACK);
243 }
244
245 // Size in bytes for the base structure used with the given draw type.
baseSize(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType)246 static deUint32 baseSize (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType)
247 {
248 return static_cast<deUint32>(indexedWithOffset(drawType, offsetType) ? sizeof(VkMultiDrawIndexedInfoEXT) : sizeof(VkMultiDrawInfoEXT));
249 }
250
251 // Number of extra bytes per entry according to the given stride.
calcExtraBytes(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType,deUint32 stride)252 static deUint32 calcExtraBytes (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType, deUint32 stride)
253 {
254 // Stride 0 is a special allowed case.
255 if (stride == 0u)
256 return 0u;
257
258 const auto minStride = baseSize(drawType, offsetType);
259 DE_ASSERT(stride >= minStride);
260 return (stride - minStride);
261 }
262
263 // Entry size in bytes taking into account the number of extra bytes due to stride.
entrySize() const264 deUint32 entrySize () const
265 {
266 return baseSize(m_drawType, m_offsetType) + m_extraBytes;
267 }
268
269 public:
DrawInfoPacker(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType,deUint32 stride,deUint32 estimatedInfoCount,deUint32 seed)270 DrawInfoPacker (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType, deUint32 stride, deUint32 estimatedInfoCount, deUint32 seed)
271 : m_drawType (drawType)
272 , m_offsetType (offsetType)
273 , m_stride (stride)
274 , m_extraBytes (calcExtraBytes(drawType, offsetType, stride))
275 , m_random (seed)
276 , m_infoCount (0u)
277 , m_dataVec ()
278 {
279 // estimatedInfoCount is used to avoid excessive reallocation.
280 if (estimatedInfoCount > 0u)
281 m_dataVec.reserve(estimatedInfoCount * entrySize());
282 }
283
addDrawInfo(deUint32 first,deUint32 count,deInt32 offset)284 void addDrawInfo (deUint32 first, deUint32 count, deInt32 offset)
285 {
286 std::vector<deUint8> entry(entrySize(), 0);
287
288 if (indexedWithOffset(m_drawType, m_offsetType))
289 {
290 const auto usedOffset = ((*m_offsetType == VertexOffsetType::CONSTANT_RANDOM) ? m_random.getInt32() : offset);
291 const VkMultiDrawIndexedInfoEXT info = { first, count, usedOffset };
292 deMemcpy(entry.data(), &info, sizeof(info));
293 }
294 else
295 {
296 const VkMultiDrawInfoEXT info = { first, count };
297 deMemcpy(entry.data(), &info, sizeof(info));
298 }
299
300 std::copy(begin(entry), end(entry), std::back_inserter(m_dataVec));
301 ++m_infoCount;
302 }
303
drawInfoCount() const304 deUint32 drawInfoCount () const
305 {
306 return m_infoCount;
307 }
308
drawInfoData() const309 const void* drawInfoData () const
310 {
311 return m_dataVec.data();
312 }
313
stride() const314 deUint32 stride () const
315 {
316 return m_stride;
317 }
318 };
319
320 class MultiDrawTest : public vkt::TestCase
321 {
322 public:
323 MultiDrawTest (tcu::TestContext& testCtx, const std::string& name, const TestParams& params);
~MultiDrawTest(void)324 virtual ~MultiDrawTest (void) {}
325
326 void initPrograms (vk::SourceCollections& programCollection) const override;
327 TestInstance* createInstance (Context& context) const override;
328 void checkSupport (Context& context) const override;
329
330 private:
331 TestParams m_params;
332 };
333
334 class MultiDrawInstance : public vkt::TestInstance
335 {
336 public:
337 MultiDrawInstance (Context& context, const TestParams& params);
~MultiDrawInstance(void)338 virtual ~MultiDrawInstance (void) {}
339
340 tcu::TestStatus iterate (void) override;
341
342 protected:
343 void beginSecondaryCmdBuffer (VkCommandBuffer cmdBuffer, VkFormat colorFormat,
344 VkFormat depthStencilFormat, VkRenderingFlagsKHR renderingFlags, deUint32 viewMask) const;
345 void preRenderingCommands (VkCommandBuffer cmdBuffer,
346 VkImage colorImage, const VkImageSubresourceRange colorSubresourceRange,
347 VkImage dsImage, const VkImageSubresourceRange dsSubresourceRange) const;
348 void drawCommands (VkCommandBuffer cmdBuffer, VkPipeline pipeline,
349 VkBuffer vertexBuffer, VkDeviceSize vertexBufferOffset, deInt32 vertexOffset,
350 VkBuffer indexBuffer, VkDeviceSize indexBufferOffset,
351 bool isMixedMode, const DrawInfoPacker& drawInfos) const;
352
353 private:
354 TestParams m_params;
355 };
356
MultiDrawTest(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)357 MultiDrawTest::MultiDrawTest (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
358 : vkt::TestCase (testCtx, name)
359 , m_params (params)
360 {}
361
createInstance(Context & context) const362 TestInstance* MultiDrawTest::createInstance (Context& context) const
363 {
364 return new MultiDrawInstance(context, m_params);
365 }
366
checkSupport(Context & context) const367 void MultiDrawTest::checkSupport (Context& context) const
368 {
369 context.requireDeviceFunctionality("VK_EXT_multi_draw");
370
371 context.requireDeviceFunctionality("VK_KHR_shader_draw_parameters");
372
373 if (m_params.useTessellation)
374 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
375
376 if (m_params.useGeometry)
377 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
378
379 if (m_params.multiview)
380 {
381 const auto& multiviewFeatures = context.getMultiviewFeatures();
382
383 if (!multiviewFeatures.multiview)
384 TCU_THROW(NotSupportedError, "Multiview not supported");
385
386 if (m_params.useTessellation && !multiviewFeatures.multiviewTessellationShader)
387 TCU_THROW(NotSupportedError, "Multiview not supported with tesellation shaders");
388
389 if (m_params.useGeometry && !multiviewFeatures.multiviewGeometryShader)
390 TCU_THROW(NotSupportedError, "Multiview not supported with geometry shaders");
391 }
392
393 if (m_params.groupParams->useDynamicRendering)
394 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
395 }
396
initPrograms(vk::SourceCollections & programCollection) const397 void MultiDrawTest::initPrograms (vk::SourceCollections& programCollection) const
398 {
399 // The general idea behind these tests is to have a 32x32 framebuffer with 1024 pixels and 1024 triangles to draw.
400 //
401 // When using a mosaic mesh, the tests will generally draw a single triangle around the center of each of these pixels. When
402 // using an overlapping mesh, each single triangle will cover the whole framebuffer using a different depth value, and the depth
403 // test will be enabled.
404 //
405 // The color of each triangle will depend on the instance index, the draw index and, when using multiview, the view index. This
406 // way, it's possible to draw those 1024 triangles with a single draw call or to draw each triangle with a separate draw call,
407 // with up to 1024 draw calls. Combinations in between are possible.
408 //
409 // With overlapping meshes, the resulting color buffer will be uniform in color. With mosaic meshes, it depends on the submitted
410 // draw count. In some cases, all pixels will be slightly different in color.
411 //
412 // The color buffer will be cleared to transparent black when beginning the render pass, and in some special cases some or all
413 // pixels will preserve that clear color because they will not be drawn into. This happens, for example, if the instance count
414 // or draw count is zero and in some cases of meshed geometry with stride zero.
415 //
416 // The output color for each pixel will:
417 // - Have the draw index split into the R and G components.
418 // - Have the instance index I stored into the B component as 255-I.
419 //
420 // In addition, the tests will use a depth/stencil buffer. The stencil buffer will be cleared to zero and the depth buffer to an
421 // appropriate initial value (0.0 or 1.0, depending on triangle order). The stencil component will be increased with each draw
422 // on each pixel. This will allow us to verify that not only the last draw for the last instance has set the proper color, but
423 // that all draw operations have taken place.
424
425 // Make sure the blue channel can be calculated without issues.
426 DE_ASSERT(m_params.maxInstanceIndex() <= 255u);
427
428 std::ostringstream vert;
429 vert
430 << "#version 460\n"
431 << (m_params.multiview ? "#extension GL_EXT_multiview : enable\n" : "")
432 << "\n"
433 << "out gl_PerVertex\n"
434 << "{\n"
435 << " vec4 gl_Position;\n"
436 << "};\n"
437 << "\n"
438 << "layout (location=0) in vec4 inPos;\n"
439 << "layout (location=0) out uvec4 outColor;\n"
440 << "\n"
441 << "void main()\n"
442 << "{\n"
443 << " gl_Position = inPos;\n"
444 << " const uint uDrawIndex = uint(gl_DrawID);\n"
445 << " outColor.r = ((uDrawIndex >> 8u) & 0xFFu);\n"
446 << " outColor.g = ((uDrawIndex ) & 0xFFu);\n"
447 << " outColor.b = 255u - uint(gl_InstanceIndex);\n"
448 << " outColor.a = 255u" << (m_params.multiview ? " - uint(gl_ViewIndex)" : "") << ";\n"
449 << "}\n"
450 ;
451 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
452
453 std::ostringstream frag;
454 frag
455 << "#version 460\n"
456 << "\n"
457 << "layout (location=0) flat in uvec4 inColor;\n"
458 << "layout (location=0) out uvec4 outColor;\n"
459 << "\n"
460 << "void main ()\n"
461 << "{\n"
462 << " outColor = inColor;\n"
463 << "}\n"
464 ;
465 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
466
467 if (m_params.useTessellation)
468 {
469 std::ostringstream tesc;
470 tesc
471 << "#version 460\n"
472 << "\n"
473 << "layout (vertices=3) out;\n"
474 << "in gl_PerVertex\n"
475 << "{\n"
476 << " vec4 gl_Position;\n"
477 << "} gl_in[gl_MaxPatchVertices];\n"
478 << "out gl_PerVertex\n"
479 << "{\n"
480 << " vec4 gl_Position;\n"
481 << "} gl_out[];\n"
482 << "\n"
483 << "layout (location=0) in uvec4 inColor[gl_MaxPatchVertices];\n"
484 << "layout (location=0) out uvec4 outColor[];\n"
485 << "\n"
486 << "void main (void)\n"
487 << "{\n"
488 << " gl_TessLevelInner[0] = 1.0;\n"
489 << " gl_TessLevelInner[1] = 1.0;\n"
490 << " gl_TessLevelOuter[0] = 1.0;\n"
491 << " gl_TessLevelOuter[1] = 1.0;\n"
492 << " gl_TessLevelOuter[2] = 1.0;\n"
493 << " gl_TessLevelOuter[3] = 1.0;\n"
494 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
495 << " outColor[gl_InvocationID] = inColor[gl_InvocationID];\n"
496 << "}\n"
497 ;
498 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
499
500 std::ostringstream tese;
501 tese
502 << "#version 460\n"
503 << "\n"
504 << "layout (triangles, fractional_odd_spacing, cw) in;\n"
505 << "in gl_PerVertex\n"
506 << "{\n"
507 << " vec4 gl_Position;\n"
508 << "} gl_in[gl_MaxPatchVertices];\n"
509 << "out gl_PerVertex\n"
510 << "{\n"
511 << " vec4 gl_Position;\n"
512 << "};\n"
513 << "\n"
514 << "layout (location=0) in uvec4 inColor[gl_MaxPatchVertices];\n"
515 << "layout (location=0) out uvec4 outColor;\n"
516 << "\n"
517 << "void main (void)\n"
518 << "{\n"
519 << " gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
520 << " (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
521 << " (gl_TessCoord.z * gl_in[2].gl_Position);\n"
522 << " outColor = inColor[0];\n"
523 << "}\n"
524 ;
525 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
526 }
527
528 if (m_params.useGeometry)
529 {
530 std::ostringstream geom;
531 geom
532 << "#version 460\n"
533 << "\n"
534 << "layout (triangles) in;\n"
535 << "layout (triangle_strip, max_vertices=3) out;\n"
536 << "in gl_PerVertex\n"
537 << "{\n"
538 << " vec4 gl_Position;\n"
539 << "} gl_in[3];\n"
540 << "out gl_PerVertex\n"
541 << "{\n"
542 << " vec4 gl_Position;\n"
543 << "};\n"
544 << "\n"
545 << "layout (location=0) in uvec4 inColor[3];\n"
546 << "layout (location=0) out uvec4 outColor;\n"
547 << "\n"
548 << "void main ()\n"
549 << "{\n"
550 << " gl_Position = gl_in[0].gl_Position; outColor = inColor[0]; EmitVertex();\n"
551 << " gl_Position = gl_in[1].gl_Position; outColor = inColor[1]; EmitVertex();\n"
552 << " gl_Position = gl_in[2].gl_Position; outColor = inColor[2]; EmitVertex();\n"
553 << "}\n"
554 ;
555 programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
556 }
557 }
558
MultiDrawInstance(Context & context,const TestParams & params)559 MultiDrawInstance::MultiDrawInstance (Context& context, const TestParams& params)
560 : vkt::TestInstance (context)
561 , m_params (params)
562 {}
563
appendPaddingVertices(std::vector<tcu::Vec4> & vertices,deUint32 count)564 void appendPaddingVertices (std::vector<tcu::Vec4>& vertices, deUint32 count)
565 {
566 for (deUint32 i = 0u; i < count; ++i)
567 vertices.emplace_back(0.0f, 0.0f, 0.0f, 1.0f);
568 }
569
570 // Creates a render pass with multiple subpasses, one per layer.
makeMultidrawRenderPass(const DeviceInterface & vk,VkDevice device,VkFormat colorFormat,VkFormat depthStencilFormat,deUint32 layerCount)571 Move<VkRenderPass> makeMultidrawRenderPass (const DeviceInterface& vk,
572 VkDevice device,
573 VkFormat colorFormat,
574 VkFormat depthStencilFormat,
575 deUint32 layerCount)
576 {
577 const VkAttachmentDescription colorAttachmentDescription =
578 {
579 0u, // VkAttachmentDescriptionFlags flags
580 colorFormat, // VkFormat format
581 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
582 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
583 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
584 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
585 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
586 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
587 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout
588 };
589
590 const VkAttachmentDescription depthStencilAttachmentDescription =
591 {
592 0u, // VkAttachmentDescriptionFlags flags
593 depthStencilFormat, // VkFormat format
594 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
595 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
596 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
597 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp
598 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp
599 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
600 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout
601 };
602
603 const std::vector<VkAttachmentDescription> attachmentDescriptions = { colorAttachmentDescription, depthStencilAttachmentDescription };
604 const VkAttachmentReference colorAttachmentRef = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
605 const VkAttachmentReference depthStencilAttachmentRef = makeAttachmentReference(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
606
607 const VkSubpassDescription subpassDescription =
608 {
609 0u, // VkSubpassDescriptionFlags flags
610 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
611 0u, // deUint32 inputAttachmentCount
612 nullptr, // const VkAttachmentReference* pInputAttachments
613 1u, // deUint32 colorAttachmentCount
614 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments
615 nullptr, // const VkAttachmentReference* pResolveAttachments
616 &depthStencilAttachmentRef, // const VkAttachmentReference* pDepthStencilAttachment
617 0u, // deUint32 preserveAttachmentCount
618 nullptr // const deUint32* pPreserveAttachments
619 };
620
621 std::vector<VkSubpassDescription> subpassDescriptions;
622
623 subpassDescriptions.reserve(layerCount);
624 for (deUint32 subpassIdx = 0u; subpassIdx < layerCount; ++subpassIdx)
625 subpassDescriptions.push_back(subpassDescription);
626
627 using MultiviewInfoPtr = de::MovePtr<VkRenderPassMultiviewCreateInfo>;
628
629 MultiviewInfoPtr multiviewCreateInfo;
630 std::vector<deUint32> viewMasks;
631
632 if (layerCount > 1u)
633 {
634 multiviewCreateInfo = MultiviewInfoPtr(new VkRenderPassMultiviewCreateInfo);
635 *multiviewCreateInfo = initVulkanStructure();
636
637 viewMasks.resize(subpassDescriptions.size());
638 for (deUint32 subpassIdx = 0u; subpassIdx < static_cast<deUint32>(viewMasks.size()); ++subpassIdx)
639 viewMasks[subpassIdx] = (1u << subpassIdx);
640
641 multiviewCreateInfo->subpassCount = static_cast<deUint32>(viewMasks.size());
642 multiviewCreateInfo->pViewMasks = de::dataOrNull(viewMasks);
643 }
644
645 // Dependencies between subpasses for color and depth/stencil read/writes.
646 std::vector<VkSubpassDependency> dependencies;
647 if (layerCount > 1u)
648 dependencies.reserve((layerCount - 1u) * 2u);
649
650 const auto fragmentTestStages = (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
651 const auto dsWrites = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
652 const auto dsReadWrites = (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
653 const auto colorStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
654 const auto colorWrites = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
655 const auto colorReadWrites = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
656
657 for (deUint32 subpassIdx = 1u; subpassIdx < layerCount; ++subpassIdx)
658 {
659 const auto prev = subpassIdx - 1u;
660
661 const VkSubpassDependency dsDep =
662 {
663 prev, // deUint32 srcSubpass;
664 subpassIdx, // deUint32 dstSubpass;
665 fragmentTestStages, // VkPipelineStageFlags srcStageMask;
666 fragmentTestStages, // VkPipelineStageFlags dstStageMask;
667 dsWrites, // VkAccessFlags srcAccessMask;
668 dsReadWrites, // VkAccessFlags dstAccessMask;
669 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags;
670 };
671 dependencies.push_back(dsDep);
672
673 const VkSubpassDependency colorDep =
674 {
675 prev, // deUint32 srcSubpass;
676 subpassIdx, // deUint32 dstSubpass;
677 colorStage, // VkPipelineStageFlags srcStageMask;
678 colorStage, // VkPipelineStageFlags dstStageMask;
679 colorWrites, // VkAccessFlags srcAccessMask;
680 colorReadWrites, // VkAccessFlags dstAccessMask;
681 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags;
682 };
683 dependencies.push_back(colorDep);
684 }
685
686 const VkRenderPassCreateInfo renderPassInfo =
687 {
688 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType
689 multiviewCreateInfo.get(), // const void* pNext
690 0u, // VkRenderPassCreateFlags flags
691 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
692 de::dataOrNull(attachmentDescriptions), // const VkAttachmentDescription* pAttachments
693 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
694 de::dataOrNull(subpassDescriptions), // const VkSubpassDescription* pSubpasses
695 static_cast<deUint32>(dependencies.size()), // deUint32 dependencyCount
696 de::dataOrNull(dependencies), // const VkSubpassDependency* pDependencies
697 };
698
699 return createRenderPass(vk, device, &renderPassInfo, nullptr);
700 }
701
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkFormat colorFormat,VkFormat depthStencilFormat,VkRenderingFlagsKHR renderingFlags,deUint32 viewMask) const702 void MultiDrawInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorFormat,
703 VkFormat depthStencilFormat, VkRenderingFlagsKHR renderingFlags, deUint32 viewMask) const
704 {
705 VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
706 {
707 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
708 DE_NULL, // const void* pNext;
709 renderingFlags, // VkRenderingFlagsKHR flags;
710 viewMask, // uint32_t viewMask;
711 1u, // uint32_t colorAttachmentCount;
712 &colorFormat, // const VkFormat* pColorAttachmentFormats;
713 depthStencilFormat, // VkFormat depthAttachmentFormat;
714 depthStencilFormat, // VkFormat stencilAttachmentFormat;
715 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
716 };
717
718 const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
719
720 VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
721 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
722 usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
723
724 const VkCommandBufferBeginInfo commandBufBeginParams
725 {
726 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
727 DE_NULL, // const void* pNext;
728 usageFlags, // VkCommandBufferUsageFlags flags;
729 &bufferInheritanceInfo
730 };
731
732 const DeviceInterface& vk = m_context.getDeviceInterface();
733 VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
734 }
735
preRenderingCommands(VkCommandBuffer cmdBuffer,VkImage colorImage,const VkImageSubresourceRange colorSubresourceRange,VkImage dsImage,const VkImageSubresourceRange dsSubresourceRange) const736 void MultiDrawInstance::preRenderingCommands(VkCommandBuffer cmdBuffer,
737 VkImage colorImage, const VkImageSubresourceRange colorSubresourceRange,
738 VkImage dsImage, const VkImageSubresourceRange dsSubresourceRange) const
739 {
740 const auto& vk = m_context.getDeviceInterface();
741
742 // Transition color and depth stencil attachment to the proper initial layout for dynamic rendering
743 const auto colorPreBarrier = makeImageMemoryBarrier(
744 0u,
745 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
746 VK_IMAGE_LAYOUT_UNDEFINED,
747 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
748 colorImage, colorSubresourceRange);
749
750 vk.cmdPipelineBarrier(
751 cmdBuffer,
752 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
753 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
754 0u, 0u, nullptr, 0u, nullptr, 1u, &colorPreBarrier);
755
756 const auto dsPreBarrier = makeImageMemoryBarrier(
757 0u,
758 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
759 VK_IMAGE_LAYOUT_UNDEFINED,
760 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
761 dsImage, dsSubresourceRange);
762
763 vk.cmdPipelineBarrier(
764 cmdBuffer,
765 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
766 (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT),
767 0u, 0u, nullptr, 0u, nullptr, 1u, &dsPreBarrier);
768 }
769
drawCommands(VkCommandBuffer cmdBuffer,VkPipeline pipeline,VkBuffer vertexBuffer,VkDeviceSize vertexBufferOffset,deInt32 vertexOffset,VkBuffer indexBuffer,VkDeviceSize indexBufferOffset,bool isMixedMode,const DrawInfoPacker & drawInfos) const770 void MultiDrawInstance::drawCommands(VkCommandBuffer cmdBuffer, VkPipeline pipeline,
771 VkBuffer vertexBuffer, VkDeviceSize vertexBufferOffset, deInt32 vertexOffset,
772 VkBuffer indexBuffer, VkDeviceSize indexBufferOffset,
773 bool isMixedMode, const DrawInfoPacker& drawInfos) const
774 {
775 const auto& vk = m_context.getDeviceInterface();
776
777 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
778 vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
779
780 if (indexBuffer == DE_NULL)
781 {
782 const auto drawInfoPtr = reinterpret_cast<const VkMultiDrawInfoEXT*>(drawInfos.drawInfoData());
783 vk.cmdDrawMultiEXT(cmdBuffer, drawInfos.drawInfoCount(), drawInfoPtr, m_params.instanceCount, m_params.firstInstance, drawInfos.stride());
784 }
785 else
786 {
787 vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, indexBufferOffset, VK_INDEX_TYPE_UINT32);
788
789 const auto drawInfoPtr = reinterpret_cast<const VkMultiDrawIndexedInfoEXT*>(drawInfos.drawInfoData());
790 const auto offsetPtr = (isMixedMode ? nullptr : &vertexOffset);
791 vk.cmdDrawMultiIndexedEXT(cmdBuffer, drawInfos.drawInfoCount(), drawInfoPtr, m_params.instanceCount, m_params.firstInstance, drawInfos.stride(), offsetPtr);
792 }
793 }
794
iterate(void)795 tcu::TestStatus MultiDrawInstance::iterate (void)
796 {
797 const auto& vki = m_context.getInstanceInterface();
798 const auto physDev = m_context.getPhysicalDevice();
799 const auto& vkd = m_context.getDeviceInterface();
800 const auto device = m_context.getDevice();
801 auto& alloc = m_context.getDefaultAllocator();
802 const auto queue = m_context.getUniversalQueue();
803 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
804
805 const auto colorFormat = getColorFormat();
806 const auto dsFormat = chooseDepthStencilFormat(vki, physDev);
807 const auto tcuColorFormat = mapVkFormat(colorFormat);
808 const auto triangleCount = getTriangleCount();
809 const auto imageDim = static_cast<deUint32>(deSqrt(static_cast<double>(triangleCount)));
810 const auto imageExtent = makeExtent3D(imageDim, imageDim, 1u);
811 const auto imageLayers = (m_params.multiview ? 2u : 1u);
812 const auto imageViewType = ((imageLayers > 1u) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
813 const auto colorUsage = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
814 const auto dsUsage = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
815 const auto pixelCount = imageExtent.width * imageExtent.height;
816 const auto vertexCount = pixelCount * 3u; // Triangle list.
817 const auto isIndexed = (m_params.drawType == DrawType::INDEXED);
818 const auto isMixedMode = (isIndexed && m_params.vertexOffset && m_params.vertexOffset->offsetType == VertexOffsetType::MIXED);
819 const auto extraVertices = (m_params.vertexOffset ? m_params.vertexOffset->offset : 0u);
820 const auto isMosaic = (m_params.meshType == MeshType::MOSAIC);
821
822 // Make sure we're providing a vertex offset for indexed cases.
823 DE_ASSERT(!isIndexed || static_cast<bool>(m_params.vertexOffset));
824
825 // Make sure overlapping draws use a single instance.
826 DE_ASSERT(isMosaic || m_params.instanceCount <= 1u);
827
828 // Color buffer.
829 const VkImageCreateInfo imageCreateInfo =
830 {
831 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
832 nullptr, // const void* pNext;
833 0u, // VkImageCreateFlags flags;
834 VK_IMAGE_TYPE_2D, // VkImageType imageType;
835 colorFormat, // VkFormat format;
836 imageExtent, // VkExtent3D extent;
837 1u, // deUint32 mipLevels;
838 imageLayers, // deUint32 arrayLayers;
839 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
840 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
841 colorUsage, // VkImageUsageFlags usage;
842 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
843 0u, // deUint32 queueFamilyIndexCount;
844 nullptr, // const deUint32* pQueueFamilyIndices;
845 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
846 };
847
848 ImageWithMemory colorBuffer (vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any);
849 const auto colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, imageLayers);
850 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), imageViewType, colorFormat, colorSubresourceRange);
851
852 // Depth/stencil buffer.
853 const VkImageCreateInfo dsCreateInfo =
854 {
855 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
856 nullptr, // const void* pNext;
857 0u, // VkImageCreateFlags flags;
858 VK_IMAGE_TYPE_2D, // VkImageType imageType;
859 dsFormat, // VkFormat format;
860 imageExtent, // VkExtent3D extent;
861 1u, // deUint32 mipLevels;
862 imageLayers, // deUint32 arrayLayers;
863 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
864 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
865 dsUsage, // VkImageUsageFlags usage;
866 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
867 0u, // deUint32 queueFamilyIndexCount;
868 nullptr, // const deUint32* pQueueFamilyIndices;
869 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
870 };
871
872 ImageWithMemory dsBuffer (vkd, device, alloc, dsCreateInfo, MemoryRequirement::Any);
873 const auto dsSubresourceRange = makeImageSubresourceRange((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, imageLayers);
874 const auto dsBufferView = makeImageView(vkd, device, dsBuffer.get(), imageViewType, dsFormat, dsSubresourceRange);
875
876 // Output buffers to verify attachments.
877 using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
878
879 // Buffers to read color attachment.
880 const auto outputBufferSize = pixelCount * static_cast<VkDeviceSize>(tcu::getPixelSize(tcuColorFormat));
881 const auto bufferCreateInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
882
883 std::vector<BufferWithMemoryPtr> outputBuffers;
884 for (deUint32 i = 0u; i < imageLayers; ++i)
885 outputBuffers.push_back(BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)));
886
887 // Buffer to read depth/stencil attachment. Note: this supposes we'll only copy the stencil aspect. See below.
888 const auto tcuStencilFmt = mapVkFormat(getStencilVerificationFormat());
889 const auto stencilOutBufferSize = pixelCount * static_cast<VkDeviceSize>(tcu::getPixelSize(tcuStencilFmt));
890 const auto stencilOutCreateInfo = makeBufferCreateInfo(stencilOutBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
891
892 std::vector<BufferWithMemoryPtr> stencilOutBuffers;
893 for (deUint32 i = 0u; i < imageLayers; ++i)
894 stencilOutBuffers.push_back(BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, stencilOutCreateInfo, MemoryRequirement::HostVisible)));
895
896 // Shaders.
897 const auto vertModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
898 const auto fragModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
899 Move<VkShaderModule> tescModule;
900 Move<VkShaderModule> teseModule;
901 Move<VkShaderModule> geomModule;
902
903 if (m_params.useGeometry)
904 geomModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
905
906 if (m_params.useTessellation)
907 {
908 tescModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
909 teseModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
910 }
911
912 DescriptorSetLayoutBuilder layoutBuilder;
913 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
914 const auto pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
915
916 Move<VkRenderPass> renderPass;
917 Move<VkFramebuffer> framebuffer;
918
919 // Render pass and Framebuffer (note layers is always 1 as required by the spec).
920 if (!m_params.groupParams->useDynamicRendering)
921 {
922 renderPass = makeMultidrawRenderPass(vkd, device, colorFormat, dsFormat, imageLayers);
923 const std::vector<VkImageView> attachments { colorBufferView.get(), dsBufferView.get() };
924 framebuffer = makeFramebuffer(vkd, device, renderPass.get(), static_cast<deUint32>(attachments.size()), de::dataOrNull(attachments), imageExtent.width, imageExtent.height, 1u);
925 }
926
927 // Viewports and scissors.
928 const auto viewport = makeViewport(imageExtent);
929 const std::vector<VkViewport> viewports (1u, viewport);
930 const auto scissor = makeRect2D(imageExtent);
931 const std::vector<VkRect2D> scissors (1u, scissor);
932
933 // Indexed draws will have triangle vertices in reverse order. See index buffer creation below.
934 const auto frontFace = (isIndexed ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE);
935 const VkPipelineRasterizationStateCreateInfo rasterizationInfo =
936 {
937 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
938 nullptr, // const void* pNext;
939 0u, // VkPipelineRasterizationStateCreateFlags flags;
940 VK_FALSE, // VkBool32 depthClampEnable;
941 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
942 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
943 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
944 frontFace, // VkFrontFace frontFace;
945 VK_FALSE, // VkBool32 depthBiasEnable;
946 0.0f, // float depthBiasConstantFactor;
947 0.0f, // float depthBiasClamp;
948 0.0f, // float depthBiasSlopeFactor;
949 1.0f, // float lineWidth;
950 };
951
952 const auto frontStencilState = makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_WRAP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0xFFu, 0xFFu, 0u);
953 const auto backStencilState = makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER, 0xFFu, 0xFFu, 0u);
954 const auto depthTestEnable = (isMosaic ? VK_FALSE : VK_TRUE);
955 const auto depthWriteEnable = depthTestEnable;
956 const auto depthCompareOp = (isMosaic ? VK_COMPARE_OP_ALWAYS : (isIndexed ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS));
957
958 const VkPipelineDepthStencilStateCreateInfo depthStencilInfo =
959 {
960 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
961 nullptr, // const void* pNext;
962 0u, // VkPipelineDepthStencilStateCreateFlags flags;
963 depthTestEnable, // VkBool32 depthTestEnable;
964 depthWriteEnable, // VkBool32 depthWriteEnable;
965 depthCompareOp, // VkCompareOp depthCompareOp;
966 VK_FALSE, // VkBool32 depthBoundsTestEnable;
967 VK_TRUE, // VkBool32 stencilTestEnable;
968 frontStencilState, // VkStencilOpState front;
969 backStencilState, // VkStencilOpState back;
970 0.0f, // float minDepthBounds;
971 1.0f, // float maxDepthBounds;
972 };
973
974 vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
975 {
976 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
977 DE_NULL,
978 0u,
979 1u,
980 &colorFormat,
981 dsFormat,
982 dsFormat
983 };
984
985 vk::VkPipelineRenderingCreateInfoKHR* nextPtr = nullptr;
986 if (m_params.groupParams->useDynamicRendering)
987 nextPtr = &renderingCreateInfo;
988
989 const auto primitiveTopology = (m_params.useTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
990 const auto patchControlPoints = (m_params.useTessellation ? 3u : 0u);
991
992 // Pipelines.
993 std::vector<Move<VkPipeline>> pipelines;
994 pipelines.reserve(imageLayers);
995 for (deUint32 subpassIdx = 0u; subpassIdx < imageLayers; ++subpassIdx)
996 {
997 renderingCreateInfo.viewMask = m_params.multiview ? (1u << subpassIdx) : 0u;
998 pipelines.emplace_back(makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
999 vertModule.get(), tescModule.get(), teseModule.get(), geomModule.get(), fragModule.get(),
1000 renderPass.get(), viewports, scissors, primitiveTopology, m_params.groupParams->useDynamicRendering ? 0u : subpassIdx, patchControlPoints,
1001 nullptr/*vertexInputStateCreateInfo*/, &rasterizationInfo, nullptr/*multisampleStateCreateInfo*/, &depthStencilInfo,
1002 nullptr/*colorBlendStateCreateInfo*/, nullptr/*dynamicStateCreateInfo*/, nextPtr));
1003 }
1004
1005 // Command pool and buffer.
1006 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
1007 Move<VkCommandBuffer> cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1008 VkCommandBuffer cmdBuffer = cmdBufferPtr.get();
1009 std::vector<Move<VkCommandBuffer> > secCmdBuffers;
1010
1011 // Create vertex buffer.
1012 std::vector<tcu::Vec4> triangleVertices;
1013 triangleVertices.reserve(vertexCount + extraVertices);
1014
1015 // Vertex count per draw call.
1016 const bool atLeastOneDraw = (m_params.drawCount > 0u);
1017 const bool moreThanOneDraw = (m_params.drawCount > 1u);
1018 const auto trianglesPerDraw = (atLeastOneDraw ? pixelCount / m_params.drawCount : 0u);
1019 const auto verticesPerDraw = trianglesPerDraw * 3u;
1020
1021 if (atLeastOneDraw)
1022 DE_ASSERT(pixelCount % m_params.drawCount == 0u);
1023
1024 {
1025 using TriangleGeneratorPtr = de::MovePtr<TriangleGenerator>;
1026 TriangleGeneratorPtr triangleGen;
1027
1028 if (m_params.meshType == MeshType::MOSAIC)
1029 triangleGen = TriangleGeneratorPtr(new TriangleMosaicGenerator(imageExtent.width, imageExtent.height));
1030 else if (m_params.meshType == MeshType::OVERLAPPING)
1031 triangleGen = TriangleGeneratorPtr(new TriangleOverlapGenerator(imageExtent.width, imageExtent.height));
1032 else
1033 DE_ASSERT(false);
1034
1035 // When applying a vertex offset in nonmixed modes, there will be a few extra vertices at the start of the vertex buffer.
1036 if (isIndexed && !isMixedMode)
1037 appendPaddingVertices(triangleVertices, extraVertices);
1038
1039 for (deUint32 y = 0u; y < imageExtent.height; ++y)
1040 for (deUint32 x = 0u; x < imageExtent.width; ++x)
1041 {
1042 // When applying a vertex offset in mixed mode, there will be some extra padding between the triangles for the first
1043 // block and the rest, so that the vertex offset will not be constant in all draw info structures. This way, the first
1044 // triangles will always have offset zero, and the number of them depends on the given draw count.
1045 const auto pixelIndex = y * imageExtent.width + x;
1046 if (isIndexed && isMixedMode && moreThanOneDraw && pixelIndex == trianglesPerDraw)
1047 appendPaddingVertices(triangleVertices, extraVertices);
1048
1049 triangleGen->appendTriangle(x, y, triangleVertices);
1050 }
1051 }
1052
1053 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(triangleVertices));
1054 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1055 BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
1056 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
1057 const auto vertexBufferOffset = vertexBufferAlloc.getOffset();
1058 void* vertexBufferData = vertexBufferAlloc.getHostPtr();
1059
1060 deMemcpy(vertexBufferData, triangleVertices.data(), de::dataSize(triangleVertices));
1061 flushAlloc(vkd, device, vertexBufferAlloc);
1062
1063 // Index buffer if needed.
1064 de::MovePtr<BufferWithMemory> indexBuffer;
1065 VkDeviceSize indexBufferOffset = 0ull;
1066 VkBuffer indexBufferHandle = DE_NULL;
1067
1068 if (isIndexed)
1069 {
1070 // Indices will be given in reverse order, so they effectively also make the triangles have reverse winding order.
1071 std::vector<deUint32> indices;
1072 indices.reserve(vertexCount);
1073 for (deUint32 i = 0u; i < vertexCount; ++i)
1074 indices.push_back(vertexCount - i - 1u);
1075
1076 const auto indexBufferSize = static_cast<VkDeviceSize>(de::dataSize(indices));
1077 const auto indexBufferInfo = makeBufferCreateInfo(indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1078 indexBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible));
1079 auto& indexBufferAlloc = indexBuffer->getAllocation();
1080 indexBufferOffset = indexBufferAlloc.getOffset();
1081 void* indexBufferData = indexBufferAlloc.getHostPtr();
1082
1083 deMemcpy(indexBufferData, indices.data(), de::dataSize(indices));
1084 flushAlloc(vkd, device, indexBufferAlloc);
1085 indexBufferHandle = indexBuffer->get();
1086 }
1087
1088 // Prepare draw information.
1089 const auto offsetType = (m_params.vertexOffset ? tcu::just(m_params.vertexOffset->offsetType) : tcu::Nothing);
1090 const auto vertexOffset = static_cast<deInt32>(extraVertices);
1091
1092 DrawInfoPacker drawInfos(m_params.drawType, offsetType, m_params.stride, m_params.drawCount, m_params.seed);
1093
1094 if (m_params.drawCount > 0u)
1095 {
1096 deUint32 vertexIndex = 0u;
1097 for (deUint32 drawIdx = 0u; drawIdx < m_params.drawCount; ++drawIdx)
1098 {
1099 // For indexed draws in mixed offset mode, taking into account vertex indices have been stored in reversed order and
1100 // there may be a padding in the vertex buffer after the first verticesPerDraw vertices, we need to use offset 0 in the
1101 // last draw call. That draw will contain the indices for the first verticesPerDraw vertices, which are stored without
1102 // any offset, while other draw calls will use indices which are off by extraVertices vertices. This will make sure not
1103 // every draw call will use the same offset and the implementation handles that.
1104 const auto drawOffset = ((isIndexed && (!isMixedMode || (moreThanOneDraw && drawIdx < m_params.drawCount - 1u))) ? vertexOffset : 0);
1105 drawInfos.addDrawInfo(vertexIndex, verticesPerDraw, drawOffset);
1106 vertexIndex += verticesPerDraw;
1107 }
1108 }
1109
1110 std::vector<VkClearValue> clearValues;
1111 clearValues.reserve(2u);
1112 clearValues.push_back(makeClearValueColorU32(0u, 0u, 0u, 0u));
1113 clearValues.push_back(makeClearValueDepthStencil(((isMosaic || isIndexed) ? 0.0f : 1.0f), 0u));
1114
1115 if (m_params.groupParams->useSecondaryCmdBuffer)
1116 {
1117 secCmdBuffers.resize(imageLayers);
1118 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1119 {
1120 secCmdBuffers[layerIdx] = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
1121 VkCommandBuffer secCmdBuffer = *secCmdBuffers[layerIdx];
1122 const deUint32 viewMask = m_params.multiview ? (1u << layerIdx) : 0u;
1123
1124 // record secondary command buffer
1125 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1126 {
1127 beginSecondaryCmdBuffer(secCmdBuffer, colorFormat, dsFormat, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, viewMask);
1128 beginRendering(vkd, secCmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1129 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1130 VK_ATTACHMENT_LOAD_OP_CLEAR, 0, imageLayers, viewMask);
1131 }
1132 else
1133 beginSecondaryCmdBuffer(secCmdBuffer, colorFormat, dsFormat, 0u, viewMask);
1134
1135 drawCommands(secCmdBuffer, pipelines[layerIdx].get(), vertexBuffer.get(), vertexBufferOffset, vertexOffset,
1136 indexBufferHandle, indexBufferOffset, isMixedMode, drawInfos);
1137
1138 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1139 endRendering(vkd, secCmdBuffer);
1140
1141 endCommandBuffer(vkd, secCmdBuffer);
1142 }
1143
1144 // record primary command buffer
1145 beginCommandBuffer(vkd, cmdBuffer, 0u);
1146 preRenderingCommands(cmdBuffer, *colorBuffer, colorSubresourceRange, *dsBuffer, dsSubresourceRange);
1147
1148 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1149 {
1150 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1151 {
1152 beginRendering(vkd, cmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1153 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1154 VK_ATTACHMENT_LOAD_OP_CLEAR, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, imageLayers,
1155 m_params.multiview ? (1u << layerIdx) : 0u);
1156 }
1157
1158 vkd.cmdExecuteCommands(cmdBuffer, 1u, &*secCmdBuffers[layerIdx]);
1159
1160 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1161 endRendering(vkd, cmdBuffer);
1162 }
1163 }
1164 else
1165 {
1166 beginCommandBuffer(vkd, cmdBuffer);
1167
1168 if (m_params.groupParams->useDynamicRendering)
1169 preRenderingCommands(cmdBuffer, *colorBuffer, colorSubresourceRange, *dsBuffer, dsSubresourceRange);
1170 else
1171 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, static_cast<deUint32>(clearValues.size()), de::dataOrNull(clearValues));
1172
1173 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1174 {
1175 if (m_params.groupParams->useDynamicRendering)
1176 beginRendering(vkd, cmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1177 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1178 VK_ATTACHMENT_LOAD_OP_CLEAR, 0, imageLayers, m_params.multiview ? (1u << layerIdx) : 0u);
1179 else if (layerIdx > 0u)
1180 vkd.cmdNextSubpass(cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1181
1182 drawCommands(cmdBuffer, pipelines[layerIdx].get(), vertexBuffer.get(), vertexBufferOffset, vertexOffset,
1183 indexBufferHandle, indexBufferOffset, isMixedMode, drawInfos);
1184
1185 if (m_params.groupParams->useDynamicRendering)
1186 endRendering(vkd, cmdBuffer);
1187 }
1188
1189 if (!m_params.groupParams->useDynamicRendering)
1190 endRenderPass(vkd, cmdBuffer);
1191 }
1192
1193 // Prepare images for copying.
1194 const auto colorBufferBarrier = makeImageMemoryBarrier(
1195 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1196 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1197 colorBuffer.get(), colorSubresourceRange);
1198 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorBufferBarrier);
1199
1200 const auto dsBufferBarrier = makeImageMemoryBarrier(
1201 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1202 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1203 dsBuffer.get(), dsSubresourceRange);
1204 vkd.cmdPipelineBarrier(cmdBuffer, (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &dsBufferBarrier);
1205
1206 // Copy images to output buffers.
1207 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1208 {
1209 const auto colorSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layerIdx, 1u);
1210 const auto colorCopyRegion = makeBufferImageCopy(imageExtent, colorSubresourceLayers);
1211 vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffers[layerIdx]->get(), 1u, &colorCopyRegion);
1212 }
1213
1214 // Note: this only copies the stencil aspect. See stencilOutBuffer creation.
1215 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1216 {
1217 const auto stencilSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, layerIdx, 1u);
1218 const auto stencilCopyRegion = makeBufferImageCopy(imageExtent, stencilSubresourceLayers);
1219 vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stencilOutBuffers[layerIdx]->get(), 1u, &stencilCopyRegion);
1220 }
1221
1222 // Prepare buffers for host reading.
1223 const auto outputBufferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1224 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &outputBufferBarrier, 0u, nullptr, 0u, nullptr);
1225
1226 endCommandBuffer(vkd, cmdBuffer);
1227 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1228
1229 // Read output buffers and verify their contents.
1230
1231 // With stride zero, mosaic meshes increment the stencil buffer as many times as draw operations for affected pixels and
1232 // overlapping meshes increment the stencil buffer only in the first draw operation (the rest fail the depth test) as many times
1233 // as triangles per draw.
1234 //
1235 // With nonzero stride, mosaic meshes increment the stencil buffer once per pixel. Overlapping meshes increment it once per
1236 // triangle.
1237 const auto stencilIncrements = ((m_params.stride == 0u)
1238 ? (isMosaic ? drawInfos.drawInfoCount() : trianglesPerDraw)
1239 : (isMosaic ? 1u : triangleCount));
1240 const auto maxInstanceIndex = m_params.maxInstanceIndex();
1241 const auto colorVerificationFormat = mapVkFormat(getVerificationFormat());
1242 const auto iWidth = static_cast<int>(imageExtent.width);
1243 const auto iHeight = static_cast<int>(imageExtent.height);
1244 auto& log = m_context.getTestContext().getLog();
1245 const auto logMode = tcu::CompareLogMode::COMPARE_LOG_ON_ERROR;
1246
1247 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1248 {
1249 auto& outputBufferAlloc = outputBuffers[layerIdx]->getAllocation();
1250 invalidateAlloc(vkd, device, outputBufferAlloc);
1251 const void* outputBufferData = outputBufferAlloc.getHostPtr();
1252
1253 auto& stencilOutBufferAlloc = stencilOutBuffers[layerIdx]->getAllocation();
1254 invalidateAlloc(vkd, device, stencilOutBufferAlloc);
1255 const void* stencilOutBufferData = stencilOutBufferAlloc.getHostPtr();
1256
1257 tcu::ConstPixelBufferAccess colorAccess (colorVerificationFormat, iWidth, iHeight, 1, outputBufferData);
1258 tcu::ConstPixelBufferAccess stencilAccess (tcuStencilFmt, iWidth, iHeight, 1, stencilOutBufferData);
1259
1260 // Generate reference images.
1261 tcu::TextureLevel refColorLevel (colorVerificationFormat, iWidth, iHeight);
1262 tcu::PixelBufferAccess refColorAccess = refColorLevel.getAccess();
1263 tcu::TextureLevel refStencilLevel (tcuStencilFmt, iWidth, iHeight);
1264 tcu::PixelBufferAccess refStencilAccess = refStencilLevel.getAccess();
1265 tcu::IVec4 referenceColor;
1266 int referenceStencil;
1267
1268 for (int y = 0; y < iHeight; ++y)
1269 for (int x = 0; x < iWidth; ++x)
1270 {
1271 const auto pixelNumber = static_cast<deUint32>(y * iWidth + x);
1272 const auto triangleIndex = (isIndexed ? (pixelCount - 1u - pixelNumber) : pixelNumber); // Reverse order for indexed draws.
1273
1274 if (m_params.instanceCount == 0u || drawInfos.drawInfoCount() == 0u ||
1275 (m_params.stride == 0u && triangleIndex >= trianglesPerDraw && isMosaic))
1276 {
1277 // Some pixels may not be drawn into when there are no instances or draws, or when the stride is zero in mosaic mode.
1278 referenceColor = tcu::IVec4(0, 0, 0, 0);
1279 referenceStencil = 0;
1280 }
1281 else
1282 {
1283 // This must match the vertex shader.
1284 //
1285 // With stride zero, the same block is drawn over and over again in each draw call. This affects both the draw index and
1286 // the values in the depth/stencil buffer and, with overlapping meshes, only the first draw passes the depth test.
1287 //
1288 // With nonzero stride, the draw index depends on the triangle index and the number of triangles per draw and, for
1289 // overlapping meshes, the draw index is always the last one.
1290 const auto drawIndex = (m_params.stride == 0u
1291 ? (isMosaic ? (drawInfos.drawInfoCount() - 1u) : 0u)
1292 : (isMosaic ? (triangleIndex / trianglesPerDraw) : (drawInfos.drawInfoCount() - 1u)));
1293 referenceColor = tcu::IVec4(
1294 static_cast<int>((drawIndex >> 8) & 0xFFu),
1295 static_cast<int>((drawIndex ) & 0xFFu),
1296 static_cast<int>(255u - maxInstanceIndex),
1297 static_cast<int>(255u - layerIdx));
1298
1299 referenceStencil = static_cast<int>((m_params.instanceCount * stencilIncrements) % 256u); // VK_STENCIL_OP_INCREMENT_AND_WRAP.
1300 }
1301
1302 refColorAccess.setPixel(referenceColor, x, y);
1303 refStencilAccess.setPixStencil(referenceStencil, x, y);
1304 }
1305
1306 const auto layerIdxStr = de::toString(layerIdx);
1307 const auto colorSetName = "ColorTestResultLayer" + layerIdxStr;
1308 const auto stencilSetName = "StencilTestResultLayer" + layerIdxStr;
1309
1310 if (!tcu::intThresholdCompare(log, colorSetName.c_str(), "", refColorAccess, colorAccess, tcu::UVec4(0u, 0u, 0u, 0u), logMode))
1311 return tcu::TestStatus::fail("Color image comparison failed; check log for more details");
1312
1313 if (!tcu::dsThresholdCompare(log, stencilSetName.c_str(), "", refStencilAccess, stencilAccess, 0.0f, logMode))
1314 return tcu::TestStatus::fail("Stencil image comparison failed; check log for more details");
1315 }
1316
1317 return tcu::TestStatus::pass("Pass");
1318 }
1319
1320 } // anonymous
1321
createDrawMultiExtTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1322 tcu::TestCaseGroup* createDrawMultiExtTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1323 {
1324 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1325
1326 GroupPtr drawMultiGroup (new tcu::TestCaseGroup(testCtx, "multi_draw"));
1327
1328 const struct
1329 {
1330 MeshType meshType;
1331 const char* name;
1332 } meshTypeCases[] =
1333 {
1334 { MeshType::MOSAIC, "mosaic" },
1335 { MeshType::OVERLAPPING, "overlapping" },
1336 };
1337
1338 const struct
1339 {
1340 DrawType drawType;
1341 const char* name;
1342 } drawTypeCases[] =
1343 {
1344 { DrawType::NORMAL, "normal" },
1345 { DrawType::INDEXED, "indexed" },
1346 };
1347
1348 const struct
1349 {
1350 tcu::Maybe<VertexOffsetType> vertexOffsetType;
1351 const char* name;
1352 } offsetTypeCases[] =
1353 {
1354 { tcu::Nothing, "" },
1355 { VertexOffsetType::MIXED, "mixed" },
1356 { VertexOffsetType::CONSTANT_RANDOM, "random" },
1357 { VertexOffsetType::CONSTANT_PACK, "packed" },
1358 };
1359
1360 const struct
1361 {
1362 deUint32 drawCount;
1363 const char* name;
1364 } drawCountCases[] =
1365 {
1366 { 0u, "no_draws" },
1367 { 1u, "one_draw" },
1368 { 16u, "16_draws" },
1369 { getTriangleCount(), "max_draws" },
1370 };
1371
1372 const struct
1373 {
1374 int extraBytes;
1375 const char* name;
1376 } strideCases[] =
1377 {
1378 { -1, "stride_zero" },
1379 { 0, "standard_stride" },
1380 { 4, "stride_extra_4" },
1381 { 12, "stride_extra_12" },
1382 };
1383
1384 const struct
1385 {
1386 deUint32 firstInstance;
1387 deUint32 instanceCount;
1388 const char* name;
1389 } instanceCases[] =
1390 {
1391 { 0u, 0u, "no_instances" },
1392 { 0u, 1u, "1_instance" },
1393 { 0u, 10u, "10_instances" },
1394 { 3u, 2u, "2_instances_base_3" },
1395 };
1396
1397 const struct
1398 {
1399 bool useTessellation;
1400 bool useGeometry;
1401 const char* name;
1402 } shaderCases[] =
1403 {
1404 { false, false, "vert_only" },
1405 { false, true, "with_geom" },
1406 { true, false, "with_tess" },
1407 { true, true, "tess_geom" },
1408 };
1409
1410 const struct
1411 {
1412 bool multiview;
1413 const char* name;
1414 } multiviewCases[] =
1415 {
1416 { false, "single_view" },
1417 { true, "multiview" },
1418 };
1419
1420 constexpr deUint32 kSeed = 1621260419u;
1421
1422 for (const auto& meshTypeCase : meshTypeCases)
1423 {
1424 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1425 if (groupParams->useSecondaryCmdBuffer && (meshTypeCase.meshType != MeshType::MOSAIC))
1426 continue;
1427
1428 GroupPtr meshTypeGroup(new tcu::TestCaseGroup(testCtx, meshTypeCase.name));
1429
1430 for (const auto& drawTypeCase : drawTypeCases)
1431 {
1432 for (const auto& offsetTypeCase : offsetTypeCases)
1433 {
1434 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1435 if (groupParams->useSecondaryCmdBuffer && offsetTypeCase.vertexOffsetType && (*offsetTypeCase.vertexOffsetType != VertexOffsetType::CONSTANT_RANDOM))
1436 continue;
1437
1438 const auto hasOffsetType = static_cast<bool>(offsetTypeCase.vertexOffsetType);
1439 if ((drawTypeCase.drawType == DrawType::NORMAL && hasOffsetType) ||
1440 (drawTypeCase.drawType == DrawType::INDEXED && !hasOffsetType))
1441 {
1442 continue;
1443 }
1444
1445 std::string drawGroupName = drawTypeCase.name;
1446 if (hasOffsetType)
1447 drawGroupName += std::string("_") + offsetTypeCase.name;
1448
1449 GroupPtr drawTypeGroup(new tcu::TestCaseGroup(testCtx, drawGroupName.c_str()));
1450
1451 for (const auto& drawCountCase : drawCountCases)
1452 {
1453 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1454 if (groupParams->useSecondaryCmdBuffer && (drawCountCase.drawCount != 1u))
1455 continue;
1456
1457 GroupPtr drawCountGroup(new tcu::TestCaseGroup(testCtx, drawCountCase.name));
1458
1459 for (const auto& strideCase : strideCases)
1460 {
1461 GroupPtr strideGroup(new tcu::TestCaseGroup(testCtx, strideCase.name));
1462
1463 for (const auto& instanceCase : instanceCases)
1464 {
1465 GroupPtr instanceGroup(new tcu::TestCaseGroup(testCtx, instanceCase.name));
1466
1467 for (const auto& shaderCase : shaderCases)
1468 {
1469 GroupPtr shaderGroup(new tcu::TestCaseGroup(testCtx, shaderCase.name));
1470
1471 for (const auto& multiviewCase : multiviewCases)
1472 {
1473 GroupPtr multiviewGroup(new tcu::TestCaseGroup(testCtx, multiviewCase.name));
1474
1475 const auto isIndexed = (drawTypeCase.drawType == DrawType::INDEXED);
1476 const auto isPacked = (offsetTypeCase.vertexOffsetType && *offsetTypeCase.vertexOffsetType == VertexOffsetType::CONSTANT_PACK);
1477 const auto baseStride = ((isIndexed && !isPacked) ? sizeof(VkMultiDrawIndexedInfoEXT) : sizeof(VkMultiDrawInfoEXT));
1478 const auto& extraBytes = strideCase.extraBytes;
1479 const auto testOffset = (isIndexed ? tcu::just(VertexOffsetParams{*offsetTypeCase.vertexOffsetType, 0u }) : tcu::Nothing);
1480 deUint32 testStride = 0u;
1481
1482 if (extraBytes >= 0)
1483 testStride = static_cast<deUint32>(baseStride) + static_cast<deUint32>(extraBytes);
1484
1485 // For overlapping triangles we will skip instanced drawing.
1486 if (instanceCase.instanceCount > 1u && meshTypeCase.meshType == MeshType::OVERLAPPING)
1487 continue;
1488
1489 TestParams params
1490 {
1491 meshTypeCase.meshType, // MeshType meshType;
1492 drawTypeCase.drawType, // DrawType drawType;
1493 drawCountCase.drawCount, // deUint32 drawCount;
1494 instanceCase.instanceCount, // deUint32 instanceCount;
1495 instanceCase.firstInstance, // deUint32 firstInstance;
1496 testStride, // deUint32 stride;
1497 testOffset, // tcu::Maybe<VertexOffsetParams>> vertexOffset; // Only used for indexed draws.
1498 kSeed, // deUint32 seed;
1499 shaderCase.useTessellation, // bool useTessellation;
1500 shaderCase.useGeometry, // bool useGeometry;
1501 multiviewCase.multiview, // bool multiview;
1502 groupParams, // SharedGroupParams groupParams;
1503 };
1504
1505 multiviewGroup->addChild(new MultiDrawTest(testCtx, "no_offset", params));
1506
1507 if (isIndexed)
1508 {
1509 params.vertexOffset->offset = 6u;
1510 multiviewGroup->addChild(new MultiDrawTest(testCtx, "offset_6", params));
1511 }
1512
1513 shaderGroup->addChild(multiviewGroup.release());
1514 }
1515
1516 instanceGroup->addChild(shaderGroup.release());
1517 }
1518
1519 strideGroup->addChild(instanceGroup.release());
1520 }
1521
1522 drawCountGroup->addChild(strideGroup.release());
1523 }
1524
1525 drawTypeGroup->addChild(drawCountGroup.release());
1526 }
1527
1528 meshTypeGroup->addChild(drawTypeGroup.release());
1529 }
1530 }
1531
1532 drawMultiGroup->addChild(meshTypeGroup.release());
1533 }
1534
1535 return drawMultiGroup.release();
1536 }
1537
1538 } // Draw
1539 } // vkt
1540