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::__anoneb0b3f2c0111::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 std::string& description, 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 std::string & description,const TestParams & params)357 MultiDrawTest::MultiDrawTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
358 : vkt::TestCase (testCtx, name, description)
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 if (m_params.useTessellation)
372 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
373
374 if (m_params.useGeometry)
375 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
376
377 if (m_params.multiview)
378 {
379 const auto& multiviewFeatures = context.getMultiviewFeatures();
380
381 if (!multiviewFeatures.multiview)
382 TCU_THROW(NotSupportedError, "Multiview not supported");
383
384 if (m_params.useTessellation && !multiviewFeatures.multiviewTessellationShader)
385 TCU_THROW(NotSupportedError, "Multiview not supported with tesellation shaders");
386
387 if (m_params.useGeometry && !multiviewFeatures.multiviewGeometryShader)
388 TCU_THROW(NotSupportedError, "Multiview not supported with geometry shaders");
389 }
390
391 if (m_params.groupParams->useDynamicRendering)
392 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
393 }
394
initPrograms(vk::SourceCollections & programCollection) const395 void MultiDrawTest::initPrograms (vk::SourceCollections& programCollection) const
396 {
397 // The general idea behind these tests is to have a 32x32 framebuffer with 1024 pixels and 1024 triangles to draw.
398 //
399 // When using a mosaic mesh, the tests will generally draw a single triangle around the center of each of these pixels. When
400 // using an overlapping mesh, each single triangle will cover the whole framebuffer using a different depth value, and the depth
401 // test will be enabled.
402 //
403 // The color of each triangle will depend on the instance index, the draw index and, when using multiview, the view index. This
404 // way, it's possible to draw those 1024 triangles with a single draw call or to draw each triangle with a separate draw call,
405 // with up to 1024 draw calls. Combinations in between are possible.
406 //
407 // With overlapping meshes, the resulting color buffer will be uniform in color. With mosaic meshes, it depends on the submitted
408 // draw count. In some cases, all pixels will be slightly different in color.
409 //
410 // The color buffer will be cleared to transparent black when beginning the render pass, and in some special cases some or all
411 // pixels will preserve that clear color because they will not be drawn into. This happens, for example, if the instance count
412 // or draw count is zero and in some cases of meshed geometry with stride zero.
413 //
414 // The output color for each pixel will:
415 // - Have the draw index split into the R and G components.
416 // - Have the instance index I stored into the B component as 255-I.
417 //
418 // In addition, the tests will use a depth/stencil buffer. The stencil buffer will be cleared to zero and the depth buffer to an
419 // appropriate initial value (0.0 or 1.0, depending on triangle order). The stencil component will be increased with each draw
420 // 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
421 // that all draw operations have taken place.
422
423 // Make sure the blue channel can be calculated without issues.
424 DE_ASSERT(m_params.maxInstanceIndex() <= 255u);
425
426 std::ostringstream vert;
427 vert
428 << "#version 460\n"
429 << (m_params.multiview ? "#extension GL_EXT_multiview : enable\n" : "")
430 << "\n"
431 << "out gl_PerVertex\n"
432 << "{\n"
433 << " vec4 gl_Position;\n"
434 << "};\n"
435 << "\n"
436 << "layout (location=0) in vec4 inPos;\n"
437 << "layout (location=0) out uvec4 outColor;\n"
438 << "\n"
439 << "void main()\n"
440 << "{\n"
441 << " gl_Position = inPos;\n"
442 << " const uint uDrawIndex = uint(gl_DrawID);\n"
443 << " outColor.r = ((uDrawIndex >> 8u) & 0xFFu);\n"
444 << " outColor.g = ((uDrawIndex ) & 0xFFu);\n"
445 << " outColor.b = 255u - uint(gl_InstanceIndex);\n"
446 << " outColor.a = 255u" << (m_params.multiview ? " - uint(gl_ViewIndex)" : "") << ";\n"
447 << "}\n"
448 ;
449 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
450
451 std::ostringstream frag;
452 frag
453 << "#version 460\n"
454 << "\n"
455 << "layout (location=0) flat in uvec4 inColor;\n"
456 << "layout (location=0) out uvec4 outColor;\n"
457 << "\n"
458 << "void main ()\n"
459 << "{\n"
460 << " outColor = inColor;\n"
461 << "}\n"
462 ;
463 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
464
465 if (m_params.useTessellation)
466 {
467 std::ostringstream tesc;
468 tesc
469 << "#version 460\n"
470 << "\n"
471 << "layout (vertices=3) out;\n"
472 << "in gl_PerVertex\n"
473 << "{\n"
474 << " vec4 gl_Position;\n"
475 << "} gl_in[gl_MaxPatchVertices];\n"
476 << "out gl_PerVertex\n"
477 << "{\n"
478 << " vec4 gl_Position;\n"
479 << "} gl_out[];\n"
480 << "\n"
481 << "layout (location=0) in uvec4 inColor[gl_MaxPatchVertices];\n"
482 << "layout (location=0) out uvec4 outColor[];\n"
483 << "\n"
484 << "void main (void)\n"
485 << "{\n"
486 << " gl_TessLevelInner[0] = 1.0;\n"
487 << " gl_TessLevelInner[1] = 1.0;\n"
488 << " gl_TessLevelOuter[0] = 1.0;\n"
489 << " gl_TessLevelOuter[1] = 1.0;\n"
490 << " gl_TessLevelOuter[2] = 1.0;\n"
491 << " gl_TessLevelOuter[3] = 1.0;\n"
492 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
493 << " outColor[gl_InvocationID] = inColor[gl_InvocationID];\n"
494 << "}\n"
495 ;
496 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
497
498 std::ostringstream tese;
499 tese
500 << "#version 460\n"
501 << "\n"
502 << "layout (triangles, fractional_odd_spacing, cw) in;\n"
503 << "in gl_PerVertex\n"
504 << "{\n"
505 << " vec4 gl_Position;\n"
506 << "} gl_in[gl_MaxPatchVertices];\n"
507 << "out gl_PerVertex\n"
508 << "{\n"
509 << " vec4 gl_Position;\n"
510 << "};\n"
511 << "\n"
512 << "layout (location=0) in uvec4 inColor[gl_MaxPatchVertices];\n"
513 << "layout (location=0) out uvec4 outColor;\n"
514 << "\n"
515 << "void main (void)\n"
516 << "{\n"
517 << " gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
518 << " (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
519 << " (gl_TessCoord.z * gl_in[2].gl_Position);\n"
520 << " outColor = inColor[0];\n"
521 << "}\n"
522 ;
523 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
524 }
525
526 if (m_params.useGeometry)
527 {
528 std::ostringstream geom;
529 geom
530 << "#version 460\n"
531 << "\n"
532 << "layout (triangles) in;\n"
533 << "layout (triangle_strip, max_vertices=3) out;\n"
534 << "in gl_PerVertex\n"
535 << "{\n"
536 << " vec4 gl_Position;\n"
537 << "} gl_in[3];\n"
538 << "out gl_PerVertex\n"
539 << "{\n"
540 << " vec4 gl_Position;\n"
541 << "};\n"
542 << "\n"
543 << "layout (location=0) in uvec4 inColor[3];\n"
544 << "layout (location=0) out uvec4 outColor;\n"
545 << "\n"
546 << "void main ()\n"
547 << "{\n"
548 << " gl_Position = gl_in[0].gl_Position; outColor = inColor[0]; EmitVertex();\n"
549 << " gl_Position = gl_in[1].gl_Position; outColor = inColor[1]; EmitVertex();\n"
550 << " gl_Position = gl_in[2].gl_Position; outColor = inColor[2]; EmitVertex();\n"
551 << "}\n"
552 ;
553 programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
554 }
555 }
556
MultiDrawInstance(Context & context,const TestParams & params)557 MultiDrawInstance::MultiDrawInstance (Context& context, const TestParams& params)
558 : vkt::TestInstance (context)
559 , m_params (params)
560 {}
561
appendPaddingVertices(std::vector<tcu::Vec4> & vertices,deUint32 count)562 void appendPaddingVertices (std::vector<tcu::Vec4>& vertices, deUint32 count)
563 {
564 for (deUint32 i = 0u; i < count; ++i)
565 vertices.emplace_back(0.0f, 0.0f, 0.0f, 1.0f);
566 }
567
568 // Creates a render pass with multiple subpasses, one per layer.
makeMultidrawRenderPass(const DeviceInterface & vk,VkDevice device,VkFormat colorFormat,VkFormat depthStencilFormat,deUint32 layerCount)569 Move<VkRenderPass> makeMultidrawRenderPass (const DeviceInterface& vk,
570 VkDevice device,
571 VkFormat colorFormat,
572 VkFormat depthStencilFormat,
573 deUint32 layerCount)
574 {
575 const VkAttachmentDescription colorAttachmentDescription =
576 {
577 0u, // VkAttachmentDescriptionFlags flags
578 colorFormat, // VkFormat format
579 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
580 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
581 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
582 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
583 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
584 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
585 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout
586 };
587
588 const VkAttachmentDescription depthStencilAttachmentDescription =
589 {
590 0u, // VkAttachmentDescriptionFlags flags
591 depthStencilFormat, // VkFormat format
592 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
593 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp
594 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
595 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp
596 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp
597 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
598 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout
599 };
600
601 const std::vector<VkAttachmentDescription> attachmentDescriptions = { colorAttachmentDescription, depthStencilAttachmentDescription };
602 const VkAttachmentReference colorAttachmentRef = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
603 const VkAttachmentReference depthStencilAttachmentRef = makeAttachmentReference(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
604
605 const VkSubpassDescription subpassDescription =
606 {
607 0u, // VkSubpassDescriptionFlags flags
608 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
609 0u, // deUint32 inputAttachmentCount
610 nullptr, // const VkAttachmentReference* pInputAttachments
611 1u, // deUint32 colorAttachmentCount
612 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments
613 nullptr, // const VkAttachmentReference* pResolveAttachments
614 &depthStencilAttachmentRef, // const VkAttachmentReference* pDepthStencilAttachment
615 0u, // deUint32 preserveAttachmentCount
616 nullptr // const deUint32* pPreserveAttachments
617 };
618
619 std::vector<VkSubpassDescription> subpassDescriptions;
620
621 subpassDescriptions.reserve(layerCount);
622 for (deUint32 subpassIdx = 0u; subpassIdx < layerCount; ++subpassIdx)
623 subpassDescriptions.push_back(subpassDescription);
624
625 using MultiviewInfoPtr = de::MovePtr<VkRenderPassMultiviewCreateInfo>;
626
627 MultiviewInfoPtr multiviewCreateInfo;
628 std::vector<deUint32> viewMasks;
629
630 if (layerCount > 1u)
631 {
632 multiviewCreateInfo = MultiviewInfoPtr(new VkRenderPassMultiviewCreateInfo);
633 *multiviewCreateInfo = initVulkanStructure();
634
635 viewMasks.resize(subpassDescriptions.size());
636 for (deUint32 subpassIdx = 0u; subpassIdx < static_cast<deUint32>(viewMasks.size()); ++subpassIdx)
637 viewMasks[subpassIdx] = (1u << subpassIdx);
638
639 multiviewCreateInfo->subpassCount = static_cast<deUint32>(viewMasks.size());
640 multiviewCreateInfo->pViewMasks = de::dataOrNull(viewMasks);
641 }
642
643 // Dependencies between subpasses for color and depth/stencil read/writes.
644 std::vector<VkSubpassDependency> dependencies;
645 if (layerCount > 1u)
646 dependencies.reserve((layerCount - 1u) * 2u);
647
648 const auto fragmentTestStages = (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
649 const auto dsWrites = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
650 const auto dsReadWrites = (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
651 const auto colorStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
652 const auto colorWrites = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
653 const auto colorReadWrites = (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
654
655 for (deUint32 subpassIdx = 1u; subpassIdx < layerCount; ++subpassIdx)
656 {
657 const auto prev = subpassIdx - 1u;
658
659 const VkSubpassDependency dsDep =
660 {
661 prev, // deUint32 srcSubpass;
662 subpassIdx, // deUint32 dstSubpass;
663 fragmentTestStages, // VkPipelineStageFlags srcStageMask;
664 fragmentTestStages, // VkPipelineStageFlags dstStageMask;
665 dsWrites, // VkAccessFlags srcAccessMask;
666 dsReadWrites, // VkAccessFlags dstAccessMask;
667 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags;
668 };
669 dependencies.push_back(dsDep);
670
671 const VkSubpassDependency colorDep =
672 {
673 prev, // deUint32 srcSubpass;
674 subpassIdx, // deUint32 dstSubpass;
675 colorStage, // VkPipelineStageFlags srcStageMask;
676 colorStage, // VkPipelineStageFlags dstStageMask;
677 colorWrites, // VkAccessFlags srcAccessMask;
678 colorReadWrites, // VkAccessFlags dstAccessMask;
679 VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags;
680 };
681 dependencies.push_back(colorDep);
682 }
683
684 const VkRenderPassCreateInfo renderPassInfo =
685 {
686 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType
687 multiviewCreateInfo.get(), // const void* pNext
688 0u, // VkRenderPassCreateFlags flags
689 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount
690 de::dataOrNull(attachmentDescriptions), // const VkAttachmentDescription* pAttachments
691 static_cast<deUint32>(subpassDescriptions.size()), // deUint32 subpassCount
692 de::dataOrNull(subpassDescriptions), // const VkSubpassDescription* pSubpasses
693 static_cast<deUint32>(dependencies.size()), // deUint32 dependencyCount
694 de::dataOrNull(dependencies), // const VkSubpassDependency* pDependencies
695 };
696
697 return createRenderPass(vk, device, &renderPassInfo, nullptr);
698 }
699
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkFormat colorFormat,VkFormat depthStencilFormat,VkRenderingFlagsKHR renderingFlags,deUint32 viewMask) const700 void MultiDrawInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorFormat,
701 VkFormat depthStencilFormat, VkRenderingFlagsKHR renderingFlags, deUint32 viewMask) const
702 {
703 VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
704 {
705 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
706 DE_NULL, // const void* pNext;
707 renderingFlags, // VkRenderingFlagsKHR flags;
708 viewMask, // uint32_t viewMask;
709 1u, // uint32_t colorAttachmentCount;
710 &colorFormat, // const VkFormat* pColorAttachmentFormats;
711 depthStencilFormat, // VkFormat depthAttachmentFormat;
712 depthStencilFormat, // VkFormat stencilAttachmentFormat;
713 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
714 };
715
716 const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
717
718 VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
719 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
720 usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
721
722 const VkCommandBufferBeginInfo commandBufBeginParams
723 {
724 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
725 DE_NULL, // const void* pNext;
726 usageFlags, // VkCommandBufferUsageFlags flags;
727 &bufferInheritanceInfo
728 };
729
730 const DeviceInterface& vk = m_context.getDeviceInterface();
731 VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
732 }
733
preRenderingCommands(VkCommandBuffer cmdBuffer,VkImage colorImage,const VkImageSubresourceRange colorSubresourceRange,VkImage dsImage,const VkImageSubresourceRange dsSubresourceRange) const734 void MultiDrawInstance::preRenderingCommands(VkCommandBuffer cmdBuffer,
735 VkImage colorImage, const VkImageSubresourceRange colorSubresourceRange,
736 VkImage dsImage, const VkImageSubresourceRange dsSubresourceRange) const
737 {
738 const auto& vk = m_context.getDeviceInterface();
739
740 // Transition color and depth stencil attachment to the proper initial layout for dynamic rendering
741 const auto colorPreBarrier = makeImageMemoryBarrier(
742 0u,
743 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
744 VK_IMAGE_LAYOUT_UNDEFINED,
745 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
746 colorImage, colorSubresourceRange);
747
748 vk.cmdPipelineBarrier(
749 cmdBuffer,
750 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
751 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
752 0u, 0u, nullptr, 0u, nullptr, 1u, &colorPreBarrier);
753
754 const auto dsPreBarrier = makeImageMemoryBarrier(
755 0u,
756 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
757 VK_IMAGE_LAYOUT_UNDEFINED,
758 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
759 dsImage, dsSubresourceRange);
760
761 vk.cmdPipelineBarrier(
762 cmdBuffer,
763 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
764 (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT),
765 0u, 0u, nullptr, 0u, nullptr, 1u, &dsPreBarrier);
766 }
767
drawCommands(VkCommandBuffer cmdBuffer,VkPipeline pipeline,VkBuffer vertexBuffer,VkDeviceSize vertexBufferOffset,deInt32 vertexOffset,VkBuffer indexBuffer,VkDeviceSize indexBufferOffset,bool isMixedMode,const DrawInfoPacker & drawInfos) const768 void MultiDrawInstance::drawCommands(VkCommandBuffer cmdBuffer, VkPipeline pipeline,
769 VkBuffer vertexBuffer, VkDeviceSize vertexBufferOffset, deInt32 vertexOffset,
770 VkBuffer indexBuffer, VkDeviceSize indexBufferOffset,
771 bool isMixedMode, const DrawInfoPacker& drawInfos) const
772 {
773 const auto& vk = m_context.getDeviceInterface();
774
775 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
776 vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
777
778 if (indexBuffer == DE_NULL)
779 {
780 const auto drawInfoPtr = reinterpret_cast<const VkMultiDrawInfoEXT*>(drawInfos.drawInfoData());
781 vk.cmdDrawMultiEXT(cmdBuffer, drawInfos.drawInfoCount(), drawInfoPtr, m_params.instanceCount, m_params.firstInstance, drawInfos.stride());
782 }
783 else
784 {
785 vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, indexBufferOffset, VK_INDEX_TYPE_UINT32);
786
787 const auto drawInfoPtr = reinterpret_cast<const VkMultiDrawIndexedInfoEXT*>(drawInfos.drawInfoData());
788 const auto offsetPtr = (isMixedMode ? nullptr : &vertexOffset);
789 vk.cmdDrawMultiIndexedEXT(cmdBuffer, drawInfos.drawInfoCount(), drawInfoPtr, m_params.instanceCount, m_params.firstInstance, drawInfos.stride(), offsetPtr);
790 }
791 }
792
iterate(void)793 tcu::TestStatus MultiDrawInstance::iterate (void)
794 {
795 const auto& vki = m_context.getInstanceInterface();
796 const auto physDev = m_context.getPhysicalDevice();
797 const auto& vkd = m_context.getDeviceInterface();
798 const auto device = m_context.getDevice();
799 auto& alloc = m_context.getDefaultAllocator();
800 const auto queue = m_context.getUniversalQueue();
801 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
802
803 const auto colorFormat = getColorFormat();
804 const auto dsFormat = chooseDepthStencilFormat(vki, physDev);
805 const auto tcuColorFormat = mapVkFormat(colorFormat);
806 const auto triangleCount = getTriangleCount();
807 const auto imageDim = static_cast<deUint32>(deSqrt(static_cast<double>(triangleCount)));
808 const auto imageExtent = makeExtent3D(imageDim, imageDim, 1u);
809 const auto imageLayers = (m_params.multiview ? 2u : 1u);
810 const auto imageViewType = ((imageLayers > 1u) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
811 const auto colorUsage = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
812 const auto dsUsage = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
813 const auto pixelCount = imageExtent.width * imageExtent.height;
814 const auto vertexCount = pixelCount * 3u; // Triangle list.
815 const auto isIndexed = (m_params.drawType == DrawType::INDEXED);
816 const auto isMixedMode = (isIndexed && m_params.vertexOffset && m_params.vertexOffset->offsetType == VertexOffsetType::MIXED);
817 const auto extraVertices = (m_params.vertexOffset ? m_params.vertexOffset->offset : 0u);
818 const auto isMosaic = (m_params.meshType == MeshType::MOSAIC);
819
820 // Make sure we're providing a vertex offset for indexed cases.
821 DE_ASSERT(!isIndexed || static_cast<bool>(m_params.vertexOffset));
822
823 // Make sure overlapping draws use a single instance.
824 DE_ASSERT(isMosaic || m_params.instanceCount <= 1u);
825
826 // Color buffer.
827 const VkImageCreateInfo imageCreateInfo =
828 {
829 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
830 nullptr, // const void* pNext;
831 0u, // VkImageCreateFlags flags;
832 VK_IMAGE_TYPE_2D, // VkImageType imageType;
833 colorFormat, // VkFormat format;
834 imageExtent, // VkExtent3D extent;
835 1u, // deUint32 mipLevels;
836 imageLayers, // deUint32 arrayLayers;
837 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
838 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
839 colorUsage, // VkImageUsageFlags usage;
840 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
841 0u, // deUint32 queueFamilyIndexCount;
842 nullptr, // const deUint32* pQueueFamilyIndices;
843 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
844 };
845
846 ImageWithMemory colorBuffer (vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any);
847 const auto colorSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, imageLayers);
848 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), imageViewType, colorFormat, colorSubresourceRange);
849
850 // Depth/stencil buffer.
851 const VkImageCreateInfo dsCreateInfo =
852 {
853 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
854 nullptr, // const void* pNext;
855 0u, // VkImageCreateFlags flags;
856 VK_IMAGE_TYPE_2D, // VkImageType imageType;
857 dsFormat, // VkFormat format;
858 imageExtent, // VkExtent3D extent;
859 1u, // deUint32 mipLevels;
860 imageLayers, // deUint32 arrayLayers;
861 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
862 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
863 dsUsage, // VkImageUsageFlags usage;
864 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
865 0u, // deUint32 queueFamilyIndexCount;
866 nullptr, // const deUint32* pQueueFamilyIndices;
867 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
868 };
869
870 ImageWithMemory dsBuffer (vkd, device, alloc, dsCreateInfo, MemoryRequirement::Any);
871 const auto dsSubresourceRange = makeImageSubresourceRange((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, imageLayers);
872 const auto dsBufferView = makeImageView(vkd, device, dsBuffer.get(), imageViewType, dsFormat, dsSubresourceRange);
873
874 // Output buffers to verify attachments.
875 using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
876
877 // Buffers to read color attachment.
878 const auto outputBufferSize = pixelCount * static_cast<VkDeviceSize>(tcu::getPixelSize(tcuColorFormat));
879 const auto bufferCreateInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
880
881 std::vector<BufferWithMemoryPtr> outputBuffers;
882 for (deUint32 i = 0u; i < imageLayers; ++i)
883 outputBuffers.push_back(BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)));
884
885 // Buffer to read depth/stencil attachment. Note: this supposes we'll only copy the stencil aspect. See below.
886 const auto tcuStencilFmt = mapVkFormat(getStencilVerificationFormat());
887 const auto stencilOutBufferSize = pixelCount * static_cast<VkDeviceSize>(tcu::getPixelSize(tcuStencilFmt));
888 const auto stencilOutCreateInfo = makeBufferCreateInfo(stencilOutBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
889
890 std::vector<BufferWithMemoryPtr> stencilOutBuffers;
891 for (deUint32 i = 0u; i < imageLayers; ++i)
892 stencilOutBuffers.push_back(BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, stencilOutCreateInfo, MemoryRequirement::HostVisible)));
893
894 // Shaders.
895 const auto vertModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
896 const auto fragModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
897 Move<VkShaderModule> tescModule;
898 Move<VkShaderModule> teseModule;
899 Move<VkShaderModule> geomModule;
900
901 if (m_params.useGeometry)
902 geomModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
903
904 if (m_params.useTessellation)
905 {
906 tescModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
907 teseModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
908 }
909
910 DescriptorSetLayoutBuilder layoutBuilder;
911 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
912 const auto pipelineLayout = makePipelineLayout(vkd, device, descriptorSetLayout.get());
913
914 Move<VkRenderPass> renderPass;
915 Move<VkFramebuffer> framebuffer;
916
917 // Render pass and Framebuffer (note layers is always 1 as required by the spec).
918 if (!m_params.groupParams->useDynamicRendering)
919 {
920 renderPass = makeMultidrawRenderPass(vkd, device, colorFormat, dsFormat, imageLayers);
921 const std::vector<VkImageView> attachments { colorBufferView.get(), dsBufferView.get() };
922 framebuffer = makeFramebuffer(vkd, device, renderPass.get(), static_cast<deUint32>(attachments.size()), de::dataOrNull(attachments), imageExtent.width, imageExtent.height, 1u);
923 }
924
925 // Viewports and scissors.
926 const auto viewport = makeViewport(imageExtent);
927 const std::vector<VkViewport> viewports (1u, viewport);
928 const auto scissor = makeRect2D(imageExtent);
929 const std::vector<VkRect2D> scissors (1u, scissor);
930
931 // Indexed draws will have triangle vertices in reverse order. See index buffer creation below.
932 const auto frontFace = (isIndexed ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE);
933 const VkPipelineRasterizationStateCreateInfo rasterizationInfo =
934 {
935 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
936 nullptr, // const void* pNext;
937 0u, // VkPipelineRasterizationStateCreateFlags flags;
938 VK_FALSE, // VkBool32 depthClampEnable;
939 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
940 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
941 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
942 frontFace, // VkFrontFace frontFace;
943 VK_FALSE, // VkBool32 depthBiasEnable;
944 0.0f, // float depthBiasConstantFactor;
945 0.0f, // float depthBiasClamp;
946 0.0f, // float depthBiasSlopeFactor;
947 1.0f, // float lineWidth;
948 };
949
950 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);
951 const auto backStencilState = makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER, 0xFFu, 0xFFu, 0u);
952 const auto depthTestEnable = (isMosaic ? VK_FALSE : VK_TRUE);
953 const auto depthWriteEnable = depthTestEnable;
954 const auto depthCompareOp = (isMosaic ? VK_COMPARE_OP_ALWAYS : (isIndexed ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS));
955
956 const VkPipelineDepthStencilStateCreateInfo depthStencilInfo =
957 {
958 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
959 nullptr, // const void* pNext;
960 0u, // VkPipelineDepthStencilStateCreateFlags flags;
961 depthTestEnable, // VkBool32 depthTestEnable;
962 depthWriteEnable, // VkBool32 depthWriteEnable;
963 depthCompareOp, // VkCompareOp depthCompareOp;
964 VK_FALSE, // VkBool32 depthBoundsTestEnable;
965 VK_TRUE, // VkBool32 stencilTestEnable;
966 frontStencilState, // VkStencilOpState front;
967 backStencilState, // VkStencilOpState back;
968 0.0f, // float minDepthBounds;
969 1.0f, // float maxDepthBounds;
970 };
971
972 vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
973 {
974 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
975 DE_NULL,
976 0u,
977 1u,
978 &colorFormat,
979 dsFormat,
980 dsFormat
981 };
982
983 vk::VkPipelineRenderingCreateInfoKHR* nextPtr = nullptr;
984 if (m_params.groupParams->useDynamicRendering)
985 nextPtr = &renderingCreateInfo;
986
987 const auto primitiveTopology = (m_params.useTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
988 const auto patchControlPoints = (m_params.useTessellation ? 3u : 0u);
989
990 // Pipelines.
991 std::vector<Move<VkPipeline>> pipelines;
992 pipelines.reserve(imageLayers);
993 for (deUint32 subpassIdx = 0u; subpassIdx < imageLayers; ++subpassIdx)
994 {
995 renderingCreateInfo.viewMask = m_params.multiview ? (1u << subpassIdx) : 0u;
996 pipelines.emplace_back(makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
997 vertModule.get(), tescModule.get(), teseModule.get(), geomModule.get(), fragModule.get(),
998 renderPass.get(), viewports, scissors, primitiveTopology, m_params.groupParams->useDynamicRendering ? 0u : subpassIdx, patchControlPoints,
999 nullptr/*vertexInputStateCreateInfo*/, &rasterizationInfo, nullptr/*multisampleStateCreateInfo*/, &depthStencilInfo,
1000 nullptr/*colorBlendStateCreateInfo*/, nullptr/*dynamicStateCreateInfo*/, nextPtr));
1001 }
1002
1003 // Command pool and buffer.
1004 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
1005 Move<VkCommandBuffer> cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1006 VkCommandBuffer cmdBuffer = cmdBufferPtr.get();
1007 std::vector<Move<VkCommandBuffer> > secCmdBuffers;
1008
1009 // Create vertex buffer.
1010 std::vector<tcu::Vec4> triangleVertices;
1011 triangleVertices.reserve(vertexCount + extraVertices);
1012
1013 // Vertex count per draw call.
1014 const bool atLeastOneDraw = (m_params.drawCount > 0u);
1015 const bool moreThanOneDraw = (m_params.drawCount > 1u);
1016 const auto trianglesPerDraw = (atLeastOneDraw ? pixelCount / m_params.drawCount : 0u);
1017 const auto verticesPerDraw = trianglesPerDraw * 3u;
1018
1019 if (atLeastOneDraw)
1020 DE_ASSERT(pixelCount % m_params.drawCount == 0u);
1021
1022 {
1023 using TriangleGeneratorPtr = de::MovePtr<TriangleGenerator>;
1024 TriangleGeneratorPtr triangleGen;
1025
1026 if (m_params.meshType == MeshType::MOSAIC)
1027 triangleGen = TriangleGeneratorPtr(new TriangleMosaicGenerator(imageExtent.width, imageExtent.height));
1028 else if (m_params.meshType == MeshType::OVERLAPPING)
1029 triangleGen = TriangleGeneratorPtr(new TriangleOverlapGenerator(imageExtent.width, imageExtent.height));
1030 else
1031 DE_ASSERT(false);
1032
1033 // When applying a vertex offset in nonmixed modes, there will be a few extra vertices at the start of the vertex buffer.
1034 if (isIndexed && !isMixedMode)
1035 appendPaddingVertices(triangleVertices, extraVertices);
1036
1037 for (deUint32 y = 0u; y < imageExtent.height; ++y)
1038 for (deUint32 x = 0u; x < imageExtent.width; ++x)
1039 {
1040 // When applying a vertex offset in mixed mode, there will be some extra padding between the triangles for the first
1041 // block and the rest, so that the vertex offset will not be constant in all draw info structures. This way, the first
1042 // triangles will always have offset zero, and the number of them depends on the given draw count.
1043 const auto pixelIndex = y * imageExtent.width + x;
1044 if (isIndexed && isMixedMode && moreThanOneDraw && pixelIndex == trianglesPerDraw)
1045 appendPaddingVertices(triangleVertices, extraVertices);
1046
1047 triangleGen->appendTriangle(x, y, triangleVertices);
1048 }
1049 }
1050
1051 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(triangleVertices));
1052 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1053 BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
1054 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
1055 const auto vertexBufferOffset = vertexBufferAlloc.getOffset();
1056 void* vertexBufferData = vertexBufferAlloc.getHostPtr();
1057
1058 deMemcpy(vertexBufferData, triangleVertices.data(), de::dataSize(triangleVertices));
1059 flushAlloc(vkd, device, vertexBufferAlloc);
1060
1061 // Index buffer if needed.
1062 de::MovePtr<BufferWithMemory> indexBuffer;
1063 VkDeviceSize indexBufferOffset = 0ull;
1064 VkBuffer indexBufferHandle = DE_NULL;
1065
1066 if (isIndexed)
1067 {
1068 // Indices will be given in reverse order, so they effectively also make the triangles have reverse winding order.
1069 std::vector<deUint32> indices;
1070 indices.reserve(vertexCount);
1071 for (deUint32 i = 0u; i < vertexCount; ++i)
1072 indices.push_back(vertexCount - i - 1u);
1073
1074 const auto indexBufferSize = static_cast<VkDeviceSize>(de::dataSize(indices));
1075 const auto indexBufferInfo = makeBufferCreateInfo(indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1076 indexBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible));
1077 auto& indexBufferAlloc = indexBuffer->getAllocation();
1078 indexBufferOffset = indexBufferAlloc.getOffset();
1079 void* indexBufferData = indexBufferAlloc.getHostPtr();
1080
1081 deMemcpy(indexBufferData, indices.data(), de::dataSize(indices));
1082 flushAlloc(vkd, device, indexBufferAlloc);
1083 indexBufferHandle = indexBuffer->get();
1084 }
1085
1086 // Prepare draw information.
1087 const auto offsetType = (m_params.vertexOffset ? tcu::just(m_params.vertexOffset->offsetType) : tcu::Nothing);
1088 const auto vertexOffset = static_cast<deInt32>(extraVertices);
1089
1090 DrawInfoPacker drawInfos(m_params.drawType, offsetType, m_params.stride, m_params.drawCount, m_params.seed);
1091
1092 if (m_params.drawCount > 0u)
1093 {
1094 deUint32 vertexIndex = 0u;
1095 for (deUint32 drawIdx = 0u; drawIdx < m_params.drawCount; ++drawIdx)
1096 {
1097 // For indexed draws in mixed offset mode, taking into account vertex indices have been stored in reversed order and
1098 // there may be a padding in the vertex buffer after the first verticesPerDraw vertices, we need to use offset 0 in the
1099 // last draw call. That draw will contain the indices for the first verticesPerDraw vertices, which are stored without
1100 // any offset, while other draw calls will use indices which are off by extraVertices vertices. This will make sure not
1101 // every draw call will use the same offset and the implementation handles that.
1102 const auto drawOffset = ((isIndexed && (!isMixedMode || (moreThanOneDraw && drawIdx < m_params.drawCount - 1u))) ? vertexOffset : 0);
1103 drawInfos.addDrawInfo(vertexIndex, verticesPerDraw, drawOffset);
1104 vertexIndex += verticesPerDraw;
1105 }
1106 }
1107
1108 std::vector<VkClearValue> clearValues;
1109 clearValues.reserve(2u);
1110 clearValues.push_back(makeClearValueColorU32(0u, 0u, 0u, 0u));
1111 clearValues.push_back(makeClearValueDepthStencil(((isMosaic || isIndexed) ? 0.0f : 1.0f), 0u));
1112
1113 if (m_params.groupParams->useSecondaryCmdBuffer)
1114 {
1115 secCmdBuffers.resize(imageLayers);
1116 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1117 {
1118 secCmdBuffers[layerIdx] = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
1119 VkCommandBuffer secCmdBuffer = *secCmdBuffers[layerIdx];
1120 const deUint32 viewMask = m_params.multiview ? (1u << layerIdx) : 0u;
1121
1122 // record secondary command buffer
1123 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1124 {
1125 beginSecondaryCmdBuffer(secCmdBuffer, colorFormat, dsFormat, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, viewMask);
1126 beginRendering(vkd, secCmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1127 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1128 VK_ATTACHMENT_LOAD_OP_CLEAR, 0, imageLayers, viewMask);
1129 }
1130 else
1131 beginSecondaryCmdBuffer(secCmdBuffer, colorFormat, dsFormat, 0u, viewMask);
1132
1133 drawCommands(secCmdBuffer, pipelines[layerIdx].get(), vertexBuffer.get(), vertexBufferOffset, vertexOffset,
1134 indexBufferHandle, indexBufferOffset, isMixedMode, drawInfos);
1135
1136 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1137 endRendering(vkd, secCmdBuffer);
1138
1139 endCommandBuffer(vkd, secCmdBuffer);
1140 }
1141
1142 // record primary command buffer
1143 beginCommandBuffer(vkd, cmdBuffer, 0u);
1144 preRenderingCommands(cmdBuffer, *colorBuffer, colorSubresourceRange, *dsBuffer, dsSubresourceRange);
1145
1146 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1147 {
1148 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1149 {
1150 beginRendering(vkd, cmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1151 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1152 VK_ATTACHMENT_LOAD_OP_CLEAR, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, imageLayers,
1153 m_params.multiview ? (1u << layerIdx) : 0u);
1154 }
1155
1156 vkd.cmdExecuteCommands(cmdBuffer, 1u, &*secCmdBuffers[layerIdx]);
1157
1158 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1159 endRendering(vkd, cmdBuffer);
1160 }
1161 }
1162 else
1163 {
1164 beginCommandBuffer(vkd, cmdBuffer);
1165
1166 if (m_params.groupParams->useDynamicRendering)
1167 preRenderingCommands(cmdBuffer, *colorBuffer, colorSubresourceRange, *dsBuffer, dsSubresourceRange);
1168 else
1169 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, static_cast<deUint32>(clearValues.size()), de::dataOrNull(clearValues));
1170
1171 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1172 {
1173 if (m_params.groupParams->useDynamicRendering)
1174 beginRendering(vkd, cmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1175 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1176 VK_ATTACHMENT_LOAD_OP_CLEAR, 0, imageLayers, m_params.multiview ? (1u << layerIdx) : 0u);
1177 else if (layerIdx > 0u)
1178 vkd.cmdNextSubpass(cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1179
1180 drawCommands(cmdBuffer, pipelines[layerIdx].get(), vertexBuffer.get(), vertexBufferOffset, vertexOffset,
1181 indexBufferHandle, indexBufferOffset, isMixedMode, drawInfos);
1182
1183 if (m_params.groupParams->useDynamicRendering)
1184 endRendering(vkd, cmdBuffer);
1185 }
1186
1187 if (!m_params.groupParams->useDynamicRendering)
1188 endRenderPass(vkd, cmdBuffer);
1189 }
1190
1191 // Prepare images for copying.
1192 const auto colorBufferBarrier = makeImageMemoryBarrier(
1193 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1194 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1195 colorBuffer.get(), colorSubresourceRange);
1196 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorBufferBarrier);
1197
1198 const auto dsBufferBarrier = makeImageMemoryBarrier(
1199 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1200 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1201 dsBuffer.get(), dsSubresourceRange);
1202 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);
1203
1204 // Copy images to output buffers.
1205 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1206 {
1207 const auto colorSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layerIdx, 1u);
1208 const auto colorCopyRegion = makeBufferImageCopy(imageExtent, colorSubresourceLayers);
1209 vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffers[layerIdx]->get(), 1u, &colorCopyRegion);
1210 }
1211
1212 // Note: this only copies the stencil aspect. See stencilOutBuffer creation.
1213 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1214 {
1215 const auto stencilSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, layerIdx, 1u);
1216 const auto stencilCopyRegion = makeBufferImageCopy(imageExtent, stencilSubresourceLayers);
1217 vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stencilOutBuffers[layerIdx]->get(), 1u, &stencilCopyRegion);
1218 }
1219
1220 // Prepare buffers for host reading.
1221 const auto outputBufferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1222 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &outputBufferBarrier, 0u, nullptr, 0u, nullptr);
1223
1224 endCommandBuffer(vkd, cmdBuffer);
1225 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1226
1227 // Read output buffers and verify their contents.
1228
1229 // With stride zero, mosaic meshes increment the stencil buffer as many times as draw operations for affected pixels and
1230 // overlapping meshes increment the stencil buffer only in the first draw operation (the rest fail the depth test) as many times
1231 // as triangles per draw.
1232 //
1233 // With nonzero stride, mosaic meshes increment the stencil buffer once per pixel. Overlapping meshes increment it once per
1234 // triangle.
1235 const auto stencilIncrements = ((m_params.stride == 0u)
1236 ? (isMosaic ? drawInfos.drawInfoCount() : trianglesPerDraw)
1237 : (isMosaic ? 1u : triangleCount));
1238 const auto maxInstanceIndex = m_params.maxInstanceIndex();
1239 const auto colorVerificationFormat = mapVkFormat(getVerificationFormat());
1240 const auto iWidth = static_cast<int>(imageExtent.width);
1241 const auto iHeight = static_cast<int>(imageExtent.height);
1242 auto& log = m_context.getTestContext().getLog();
1243 const auto logMode = tcu::CompareLogMode::COMPARE_LOG_ON_ERROR;
1244
1245 for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1246 {
1247 auto& outputBufferAlloc = outputBuffers[layerIdx]->getAllocation();
1248 invalidateAlloc(vkd, device, outputBufferAlloc);
1249 const void* outputBufferData = outputBufferAlloc.getHostPtr();
1250
1251 auto& stencilOutBufferAlloc = stencilOutBuffers[layerIdx]->getAllocation();
1252 invalidateAlloc(vkd, device, stencilOutBufferAlloc);
1253 const void* stencilOutBufferData = stencilOutBufferAlloc.getHostPtr();
1254
1255 tcu::ConstPixelBufferAccess colorAccess (colorVerificationFormat, iWidth, iHeight, 1, outputBufferData);
1256 tcu::ConstPixelBufferAccess stencilAccess (tcuStencilFmt, iWidth, iHeight, 1, stencilOutBufferData);
1257
1258 // Generate reference images.
1259 tcu::TextureLevel refColorLevel (colorVerificationFormat, iWidth, iHeight);
1260 tcu::PixelBufferAccess refColorAccess = refColorLevel.getAccess();
1261 tcu::TextureLevel refStencilLevel (tcuStencilFmt, iWidth, iHeight);
1262 tcu::PixelBufferAccess refStencilAccess = refStencilLevel.getAccess();
1263 tcu::IVec4 referenceColor;
1264 int referenceStencil;
1265
1266 for (int y = 0; y < iHeight; ++y)
1267 for (int x = 0; x < iWidth; ++x)
1268 {
1269 const auto pixelNumber = static_cast<deUint32>(y * iWidth + x);
1270 const auto triangleIndex = (isIndexed ? (pixelCount - 1u - pixelNumber) : pixelNumber); // Reverse order for indexed draws.
1271
1272 if (m_params.instanceCount == 0u || drawInfos.drawInfoCount() == 0u ||
1273 (m_params.stride == 0u && triangleIndex >= trianglesPerDraw && isMosaic))
1274 {
1275 // Some pixels may not be drawn into when there are no instances or draws, or when the stride is zero in mosaic mode.
1276 referenceColor = tcu::IVec4(0, 0, 0, 0);
1277 referenceStencil = 0;
1278 }
1279 else
1280 {
1281 // This must match the vertex shader.
1282 //
1283 // With stride zero, the same block is drawn over and over again in each draw call. This affects both the draw index and
1284 // the values in the depth/stencil buffer and, with overlapping meshes, only the first draw passes the depth test.
1285 //
1286 // With nonzero stride, the draw index depends on the triangle index and the number of triangles per draw and, for
1287 // overlapping meshes, the draw index is always the last one.
1288 const auto drawIndex = (m_params.stride == 0u
1289 ? (isMosaic ? (drawInfos.drawInfoCount() - 1u) : 0u)
1290 : (isMosaic ? (triangleIndex / trianglesPerDraw) : (drawInfos.drawInfoCount() - 1u)));
1291 referenceColor = tcu::IVec4(
1292 static_cast<int>((drawIndex >> 8) & 0xFFu),
1293 static_cast<int>((drawIndex ) & 0xFFu),
1294 static_cast<int>(255u - maxInstanceIndex),
1295 static_cast<int>(255u - layerIdx));
1296
1297 referenceStencil = static_cast<int>((m_params.instanceCount * stencilIncrements) % 256u); // VK_STENCIL_OP_INCREMENT_AND_WRAP.
1298 }
1299
1300 refColorAccess.setPixel(referenceColor, x, y);
1301 refStencilAccess.setPixStencil(referenceStencil, x, y);
1302 }
1303
1304 const auto layerIdxStr = de::toString(layerIdx);
1305 const auto colorSetName = "ColorTestResultLayer" + layerIdxStr;
1306 const auto stencilSetName = "StencilTestResultLayer" + layerIdxStr;
1307
1308 if (!tcu::intThresholdCompare(log, colorSetName.c_str(), "", refColorAccess, colorAccess, tcu::UVec4(0u, 0u, 0u, 0u), logMode))
1309 return tcu::TestStatus::fail("Color image comparison failed; check log for more details");
1310
1311 if (!tcu::dsThresholdCompare(log, stencilSetName.c_str(), "", refStencilAccess, stencilAccess, 0.0f, logMode))
1312 return tcu::TestStatus::fail("Stencil image comparison failed; check log for more details");
1313 }
1314
1315 return tcu::TestStatus::pass("Pass");
1316 }
1317
1318 } // anonymous
1319
createDrawMultiExtTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1320 tcu::TestCaseGroup* createDrawMultiExtTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1321 {
1322 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1323
1324 GroupPtr drawMultiGroup (new tcu::TestCaseGroup(testCtx, "multi_draw", "VK_EXT_multi_draw tests"));
1325
1326 const struct
1327 {
1328 MeshType meshType;
1329 const char* name;
1330 } meshTypeCases[] =
1331 {
1332 { MeshType::MOSAIC, "mosaic" },
1333 { MeshType::OVERLAPPING, "overlapping" },
1334 };
1335
1336 const struct
1337 {
1338 DrawType drawType;
1339 const char* name;
1340 } drawTypeCases[] =
1341 {
1342 { DrawType::NORMAL, "normal" },
1343 { DrawType::INDEXED, "indexed" },
1344 };
1345
1346 const struct
1347 {
1348 tcu::Maybe<VertexOffsetType> vertexOffsetType;
1349 const char* name;
1350 } offsetTypeCases[] =
1351 {
1352 { tcu::Nothing, "" },
1353 { VertexOffsetType::MIXED, "mixed" },
1354 { VertexOffsetType::CONSTANT_RANDOM, "random" },
1355 { VertexOffsetType::CONSTANT_PACK, "packed" },
1356 };
1357
1358 const struct
1359 {
1360 deUint32 drawCount;
1361 const char* name;
1362 } drawCountCases[] =
1363 {
1364 { 0u, "no_draws" },
1365 { 1u, "one_draw" },
1366 { 16u, "16_draws" },
1367 { getTriangleCount(), "max_draws" },
1368 };
1369
1370 const struct
1371 {
1372 int extraBytes;
1373 const char* name;
1374 } strideCases[] =
1375 {
1376 { -1, "stride_zero" },
1377 { 0, "standard_stride" },
1378 { 4, "stride_extra_4" },
1379 { 12, "stride_extra_12" },
1380 };
1381
1382 const struct
1383 {
1384 deUint32 firstInstance;
1385 deUint32 instanceCount;
1386 const char* name;
1387 } instanceCases[] =
1388 {
1389 { 0u, 0u, "no_instances" },
1390 { 0u, 1u, "1_instance" },
1391 { 0u, 10u, "10_instances" },
1392 { 3u, 2u, "2_instances_base_3" },
1393 };
1394
1395 const struct
1396 {
1397 bool useTessellation;
1398 bool useGeometry;
1399 const char* name;
1400 } shaderCases[] =
1401 {
1402 { false, false, "vert_only" },
1403 { false, true, "with_geom" },
1404 { true, false, "with_tess" },
1405 { true, true, "tess_geom" },
1406 };
1407
1408 const struct
1409 {
1410 bool multiview;
1411 const char* name;
1412 } multiviewCases[] =
1413 {
1414 { false, "single_view" },
1415 { true, "multiview" },
1416 };
1417
1418 constexpr deUint32 kSeed = 1621260419u;
1419
1420 for (const auto& meshTypeCase : meshTypeCases)
1421 {
1422 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1423 if (groupParams->useSecondaryCmdBuffer && (meshTypeCase.meshType != MeshType::MOSAIC))
1424 continue;
1425
1426 GroupPtr meshTypeGroup(new tcu::TestCaseGroup(testCtx, meshTypeCase.name, ""));
1427
1428 for (const auto& drawTypeCase : drawTypeCases)
1429 {
1430 for (const auto& offsetTypeCase : offsetTypeCases)
1431 {
1432 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1433 if (groupParams->useSecondaryCmdBuffer && offsetTypeCase.vertexOffsetType && (*offsetTypeCase.vertexOffsetType != VertexOffsetType::CONSTANT_RANDOM))
1434 continue;
1435
1436 const auto hasOffsetType = static_cast<bool>(offsetTypeCase.vertexOffsetType);
1437 if ((drawTypeCase.drawType == DrawType::NORMAL && hasOffsetType) ||
1438 (drawTypeCase.drawType == DrawType::INDEXED && !hasOffsetType))
1439 {
1440 continue;
1441 }
1442
1443 std::string drawGroupName = drawTypeCase.name;
1444 if (hasOffsetType)
1445 drawGroupName += std::string("_") + offsetTypeCase.name;
1446
1447 GroupPtr drawTypeGroup(new tcu::TestCaseGroup(testCtx, drawGroupName.c_str(), ""));
1448
1449 for (const auto& drawCountCase : drawCountCases)
1450 {
1451 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1452 if (groupParams->useSecondaryCmdBuffer && (drawCountCase.drawCount != 1u))
1453 continue;
1454
1455 GroupPtr drawCountGroup(new tcu::TestCaseGroup(testCtx, drawCountCase.name, ""));
1456
1457 for (const auto& strideCase : strideCases)
1458 {
1459 GroupPtr strideGroup(new tcu::TestCaseGroup(testCtx, strideCase.name, ""));
1460
1461 for (const auto& instanceCase : instanceCases)
1462 {
1463 GroupPtr instanceGroup(new tcu::TestCaseGroup(testCtx, instanceCase.name, ""));
1464
1465 for (const auto& shaderCase : shaderCases)
1466 {
1467 GroupPtr shaderGroup(new tcu::TestCaseGroup(testCtx, shaderCase.name, ""));
1468
1469 for (const auto& multiviewCase : multiviewCases)
1470 {
1471 GroupPtr multiviewGroup(new tcu::TestCaseGroup(testCtx, multiviewCase.name, ""));
1472
1473 const auto isIndexed = (drawTypeCase.drawType == DrawType::INDEXED);
1474 const auto isPacked = (offsetTypeCase.vertexOffsetType && *offsetTypeCase.vertexOffsetType == VertexOffsetType::CONSTANT_PACK);
1475 const auto baseStride = ((isIndexed && !isPacked) ? sizeof(VkMultiDrawIndexedInfoEXT) : sizeof(VkMultiDrawInfoEXT));
1476 const auto& extraBytes = strideCase.extraBytes;
1477 const auto testOffset = (isIndexed ? tcu::just(VertexOffsetParams{*offsetTypeCase.vertexOffsetType, 0u }) : tcu::Nothing);
1478 deUint32 testStride = 0u;
1479
1480 if (extraBytes >= 0)
1481 testStride = static_cast<deUint32>(baseStride) + static_cast<deUint32>(extraBytes);
1482
1483 // For overlapping triangles we will skip instanced drawing.
1484 if (instanceCase.instanceCount > 1u && meshTypeCase.meshType == MeshType::OVERLAPPING)
1485 continue;
1486
1487 TestParams params
1488 {
1489 meshTypeCase.meshType, // MeshType meshType;
1490 drawTypeCase.drawType, // DrawType drawType;
1491 drawCountCase.drawCount, // deUint32 drawCount;
1492 instanceCase.instanceCount, // deUint32 instanceCount;
1493 instanceCase.firstInstance, // deUint32 firstInstance;
1494 testStride, // deUint32 stride;
1495 testOffset, // tcu::Maybe<VertexOffsetParams>> vertexOffset; // Only used for indexed draws.
1496 kSeed, // deUint32 seed;
1497 shaderCase.useTessellation, // bool useTessellation;
1498 shaderCase.useGeometry, // bool useGeometry;
1499 multiviewCase.multiview, // bool multiview;
1500 groupParams, // SharedGroupParams groupParams;
1501 };
1502
1503 multiviewGroup->addChild(new MultiDrawTest(testCtx, "no_offset", "", params));
1504
1505 if (isIndexed)
1506 {
1507 params.vertexOffset->offset = 6u;
1508 multiviewGroup->addChild(new MultiDrawTest(testCtx, "offset_6", "", params));
1509 }
1510
1511 shaderGroup->addChild(multiviewGroup.release());
1512 }
1513
1514 instanceGroup->addChild(shaderGroup.release());
1515 }
1516
1517 strideGroup->addChild(instanceGroup.release());
1518 }
1519
1520 drawCountGroup->addChild(strideGroup.release());
1521 }
1522
1523 drawTypeGroup->addChild(drawCountGroup.release());
1524 }
1525
1526 meshTypeGroup->addChild(drawTypeGroup.release());
1527 }
1528 }
1529
1530 drawMultiGroup->addChild(meshTypeGroup.release());
1531 }
1532
1533 return drawMultiGroup.release();
1534 }
1535
1536 } // Draw
1537 } // vkt
1538