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