1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2021 The Khronos Group Inc.
6 * Copyright (c) 2021 Valve Corporation.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Mesh Shader Smoke Tests for VK_EXT_mesh_shader
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktMeshShaderSmokeTestsEXT.hpp"
28 #include "vktMeshShaderUtil.hpp"
29 #include "vktTestCase.hpp"
30 #include "vktTestCaseUtil.hpp"
31
32 #include "vkBuilderUtil.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkObjUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkBarrierUtil.hpp"
40 #include "vkPipelineConstructionUtil.hpp"
41
42 #include "tcuImageCompare.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuTextureUtil.hpp"
45
46 #include "deRandom.hpp"
47
48 #include <utility>
49 #include <vector>
50 #include <string>
51 #include <sstream>
52 #include <set>
53 #include <memory>
54
55 namespace vkt
56 {
57 namespace MeshShader
58 {
59
60 namespace
61 {
62
63 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
64
65 using namespace vk;
66
commonMeshFragShader()67 std::string commonMeshFragShader ()
68 {
69 std::string frag =
70 "#version 450\n"
71 "#extension GL_EXT_mesh_shader : enable\n"
72 "\n"
73 "layout (location=0) in perprimitiveEXT vec4 triangleColor;\n"
74 "layout (location=0) out vec4 outColor;\n"
75 "\n"
76 "void main ()\n"
77 "{\n"
78 " outColor = triangleColor;\n"
79 "}\n"
80 ;
81 return frag;
82 }
83
getClearColor()84 tcu::Vec4 getClearColor ()
85 {
86 return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
87 }
88
makeMeshGraphicsPipeline(GraphicsPipelineWrapper & maker,const PipelineLayoutWrapper & pipelineLayout,const ShaderWrapper taskShader,const ShaderWrapper meshShader,const ShaderWrapper fragShader,const VkRenderPass renderPass,const std::vector<VkViewport> & viewports,const std::vector<VkRect2D> & scissors,const uint32_t subpass=0u,const VkPipelineDepthStencilStateCreateInfo * depthStencilStateCreateInfo=nullptr,VkPipelineFragmentShadingRateStateCreateInfoKHR * fragmentShadingRateStateCreateInfo=nullptr)89 void makeMeshGraphicsPipeline ( GraphicsPipelineWrapper& maker,
90 const PipelineLayoutWrapper& pipelineLayout,
91 const ShaderWrapper taskShader,
92 const ShaderWrapper meshShader,
93 const ShaderWrapper fragShader,
94 const VkRenderPass renderPass,
95 const std::vector<VkViewport>& viewports,
96 const std::vector<VkRect2D>& scissors,
97 const uint32_t subpass = 0u,
98 const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo = nullptr,
99 VkPipelineFragmentShadingRateStateCreateInfoKHR* fragmentShadingRateStateCreateInfo = nullptr)
100 {
101 #ifndef CTS_USES_VULKANSC
102 maker.setDefaultMultisampleState()
103 .setDefaultColorBlendState()
104 .setDefaultRasterizationState()
105 .setDefaultDepthStencilState()
106 .setupPreRasterizationMeshShaderState(viewports,
107 scissors,
108 pipelineLayout,
109 renderPass,
110 subpass,
111 taskShader,
112 meshShader,
113 nullptr,
114 nullptr,
115 nullptr,
116 fragmentShadingRateStateCreateInfo)
117 .setupFragmentShaderState(pipelineLayout,
118 renderPass,
119 subpass,
120 fragShader,
121 depthStencilStateCreateInfo)
122 .setupFragmentOutputState(renderPass, subpass)
123 .setMonolithicPipelineLayout(pipelineLayout)
124 .buildPipeline();
125 #else
126 DE_ASSERT(false);
127 #endif // CTS_USES_VULKANSC
128 }
129
130 struct MeshTriangleRendererParams
131 {
132 PipelineConstructionType constructionType;
133 std::vector<tcu::Vec4> vertexCoords;
134 std::vector<uint32_t> vertexIndices;
135 uint32_t taskCount;
136 tcu::Vec4 expectedColor;
137 bool rasterizationDisabled;
138
MeshTriangleRendererParamsvkt::MeshShader::__anon4a1cb0ed0111::MeshTriangleRendererParams139 MeshTriangleRendererParams (PipelineConstructionType constructionType_,
140 std::vector<tcu::Vec4> vertexCoords_,
141 std::vector<uint32_t> vertexIndices_,
142 uint32_t taskCount_,
143 const tcu::Vec4& expectedColor_,
144 bool rasterizationDisabled_ = false)
145 : constructionType (constructionType_)
146 , vertexCoords (std::move(vertexCoords_))
147 , vertexIndices (std::move(vertexIndices_))
148 , taskCount (taskCount_)
149 , expectedColor (expectedColor_)
150 , rasterizationDisabled (rasterizationDisabled_)
151 {}
152
MeshTriangleRendererParamsvkt::MeshShader::__anon4a1cb0ed0111::MeshTriangleRendererParams153 MeshTriangleRendererParams (MeshTriangleRendererParams&& other)
154 : MeshTriangleRendererParams (other.constructionType,
155 std::move(other.vertexCoords),
156 std::move(other.vertexIndices),
157 other.taskCount,
158 other.expectedColor,
159 other.rasterizationDisabled)
160 {}
161 };
162
163 class MeshOnlyTriangleCase : public vkt::TestCase
164 {
165 public:
MeshOnlyTriangleCase(tcu::TestContext & testCtx,const std::string & name,PipelineConstructionType constructionType,bool rasterizationDisabled=false)166 MeshOnlyTriangleCase (tcu::TestContext& testCtx, const std::string& name,
167 PipelineConstructionType constructionType, bool rasterizationDisabled = false)
168 : vkt::TestCase (testCtx, name)
169 , m_constructionType (constructionType)
170 , m_rasterizationDisabled (rasterizationDisabled)
171 {}
~MeshOnlyTriangleCase(void)172 virtual ~MeshOnlyTriangleCase (void) {}
173
174 void initPrograms (vk::SourceCollections& programCollection) const override;
175 TestInstance* createInstance (Context& context) const override;
176 void checkSupport (Context& context) const override;
177
178 protected:
179 const PipelineConstructionType m_constructionType;
180 const bool m_rasterizationDisabled;
181 };
182
183 class MeshTaskTriangleCase : public vkt::TestCase
184 {
185 public:
MeshTaskTriangleCase(tcu::TestContext & testCtx,const std::string & name,PipelineConstructionType constructionType)186 MeshTaskTriangleCase (tcu::TestContext& testCtx, const std::string& name, PipelineConstructionType constructionType)
187 : vkt::TestCase (testCtx, name)
188 , m_constructionType (constructionType)
189 {}
~MeshTaskTriangleCase(void)190 virtual ~MeshTaskTriangleCase (void) {}
191
192 void initPrograms (vk::SourceCollections& programCollection) const override;
193 TestInstance* createInstance (Context& context) const override;
194 void checkSupport (Context& context) const override;
195
196 protected:
197 const PipelineConstructionType m_constructionType;
198 };
199
200 // Note: not actually task-only. The task shader will not emit mesh shader work groups.
201 class TaskOnlyTriangleCase : public vkt::TestCase
202 {
203 public:
TaskOnlyTriangleCase(tcu::TestContext & testCtx,const std::string & name,PipelineConstructionType constructionType)204 TaskOnlyTriangleCase (tcu::TestContext& testCtx, const std::string& name, PipelineConstructionType constructionType)
205 : vkt::TestCase (testCtx, name)
206 , m_constructionType (constructionType)
207 {}
~TaskOnlyTriangleCase(void)208 virtual ~TaskOnlyTriangleCase (void) {}
209
210 void initPrograms (vk::SourceCollections& programCollection) const override;
211 TestInstance* createInstance (Context& context) const override;
212 void checkSupport (Context& context) const override;
213
214 protected:
215 const PipelineConstructionType m_constructionType;
216 };
217
218 class MeshTriangleRenderer : public vkt::TestInstance
219 {
220 public:
MeshTriangleRenderer(Context & context,MeshTriangleRendererParams params)221 MeshTriangleRenderer (Context& context, MeshTriangleRendererParams params) : vkt::TestInstance(context), m_params(std::move(params)) {}
~MeshTriangleRenderer(void)222 virtual ~MeshTriangleRenderer (void) {}
223
224 tcu::TestStatus iterate (void) override;
225
226 protected:
227 MeshTriangleRendererParams m_params;
228 };
229
checkSupport(Context & context) const230 void MeshOnlyTriangleCase::checkSupport (Context& context) const
231 {
232 checkTaskMeshShaderSupportEXT(context, false, true);
233 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_constructionType);
234 }
235
checkSupport(Context & context) const236 void MeshTaskTriangleCase::checkSupport (Context& context) const
237 {
238 checkTaskMeshShaderSupportEXT(context, true, true);
239 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_constructionType);
240 }
241
checkSupport(Context & context) const242 void TaskOnlyTriangleCase::checkSupport (Context& context) const
243 {
244 checkTaskMeshShaderSupportEXT(context, true, true);
245 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_constructionType);
246 }
247
initPrograms(SourceCollections & dst) const248 void MeshOnlyTriangleCase::initPrograms (SourceCollections& dst) const
249 {
250 const auto buildOptions = getMinMeshEXTBuildOptions(dst.usedVulkanVersion);
251
252 std::ostringstream mesh;
253 mesh
254 << "#version 450\n"
255 << "#extension GL_EXT_mesh_shader : enable\n"
256 << "\n"
257 // We will actually output a single triangle and most invocations will do no work.
258 << "layout(local_size_x=8, local_size_y=4, local_size_z=4) in;\n"
259 << "layout(triangles) out;\n"
260 << "layout(max_vertices=256, max_primitives=256) out;\n"
261 << "\n"
262 // Unique vertex coordinates.
263 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
264 << " vec4 coords[3];\n"
265 << "} cb;\n"
266 // Unique vertex indices.
267 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
268 << " uint indices[3];\n"
269 << "} ib;\n"
270 << "\n"
271 // Triangle color.
272 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
273 << "\n"
274 << "void main ()\n"
275 << "{\n"
276 << " SetMeshOutputsEXT(3u, 1u);\n"
277 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
278 << "\n"
279 << " const uint vertexIndex = gl_LocalInvocationIndex;\n"
280 << " if (vertexIndex < 3u)\n"
281 << " {\n"
282 << " const uint coordsIndex = ib.indices[vertexIndex];\n"
283 << " gl_MeshVerticesEXT[vertexIndex].gl_Position = cb.coords[coordsIndex];\n"
284 << " }\n"
285 << " if (vertexIndex == 0u)\n"
286 << " {\n"
287 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
288 << " }\n"
289 << "}\n"
290 ;
291 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
292
293 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader()) << buildOptions;
294 }
295
initPrograms(SourceCollections & dst) const296 void MeshTaskTriangleCase::initPrograms (SourceCollections& dst) const
297 {
298 const auto buildOptions = getMinMeshEXTBuildOptions(dst.usedVulkanVersion);
299
300 std::string taskDataDecl =
301 "struct TaskData {\n"
302 " uint triangleIndex;\n"
303 "};\n"
304 "taskPayloadSharedEXT TaskData td;\n"
305 ;
306
307 std::ostringstream task;
308 task
309 // Each work group spawns 1 task each (2 in total) and each task will draw 1 triangle.
310 << "#version 460\n"
311 << "#extension GL_EXT_mesh_shader : enable\n"
312 << "\n"
313 << "layout(local_size_x=8, local_size_y=4, local_size_z=4) in;\n"
314 << "\n"
315 << taskDataDecl
316 << "\n"
317 << "void main ()\n"
318 << "{\n"
319 << " if (gl_LocalInvocationIndex == 0u)\n"
320 << " {\n"
321 << " td.triangleIndex = gl_WorkGroupID.x;\n"
322 << " }\n"
323 << " EmitMeshTasksEXT(1u, 1u, 1u);\n"
324 << "}\n"
325 ;
326 ;
327 dst.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
328
329 std::ostringstream mesh;
330 mesh
331 << "#version 460\n"
332 << "#extension GL_EXT_mesh_shader : enable\n"
333 << "\n"
334 // We will actually output a single triangle and most invocations will do no work.
335 << "layout(local_size_x=8, local_size_y=4, local_size_z=4) in;\n"
336 << "layout(triangles) out;\n"
337 << "layout(max_vertices=256, max_primitives=256) out;\n"
338 << "\n"
339 // Unique vertex coordinates.
340 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
341 << " vec4 coords[4];\n"
342 << "} cb;\n"
343 // Unique vertex indices.
344 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
345 << " uint indices[6];\n"
346 << "} ib;\n"
347 << "\n"
348 // Triangle color.
349 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
350 << "\n"
351 << taskDataDecl
352 << "\n"
353 << "void main ()\n"
354 << "{\n"
355 << " SetMeshOutputsEXT(3u, 1u);\n"
356 << "\n"
357 // Each "active" invocation will copy one vertex.
358 << " const uint triangleVertex = gl_LocalInvocationIndex;\n"
359 << " const uint indexArrayPos = td.triangleIndex * 3u + triangleVertex;\n"
360 << "\n"
361 << " if (triangleVertex < 3u)\n"
362 << " {\n"
363 << " const uint coordsIndex = ib.indices[indexArrayPos];\n"
364 // Copy vertex coordinates.
365 << " gl_MeshVerticesEXT[triangleVertex].gl_Position = cb.coords[coordsIndex];\n"
366 // Index renumbering: final indices will always be 0, 1, 2.
367 << " }\n"
368 << " if (triangleVertex == 0u)\n"
369 << " {\n"
370 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
371 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
372 << " }\n"
373 << "}\n"
374 ;
375 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
376
377 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader()) << buildOptions;
378 }
379
initPrograms(SourceCollections & dst) const380 void TaskOnlyTriangleCase::initPrograms (SourceCollections& dst) const
381 {
382 const auto buildOptions = getMinMeshEXTBuildOptions(dst.usedVulkanVersion);
383
384 // The task shader does not spawn any mesh shader invocations.
385 std::ostringstream task;
386 task
387 << "#version 450\n"
388 << "#extension GL_EXT_mesh_shader : enable\n"
389 << "\n"
390 << "layout(local_size_x=1) in;\n"
391 << "\n"
392 << "void main ()\n"
393 << "{\n"
394 << " EmitMeshTasksEXT(0u, 0u, 0u);\n"
395 << "}\n"
396 ;
397 dst.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
398
399 // Same shader as the mesh only case, but it should not be launched.
400 std::ostringstream mesh;
401 mesh
402 << "#version 450\n"
403 << "#extension GL_EXT_mesh_shader : enable\n"
404 << "\n"
405 // We will actually output a single triangle and most invocations will do no work.
406 << "layout(local_size_x=8, local_size_y=4, local_size_z=4) in;\n"
407 << "layout(triangles) out;\n"
408 << "layout(max_vertices=256, max_primitives=256) out;\n"
409 << "\n"
410 << "layout (set=0, binding=0) uniform CoordsBuffer {\n"
411 << " vec4 coords[3];\n"
412 << "} cb;\n"
413 << "layout (set=0, binding=1, std430) readonly buffer IndexBuffer {\n"
414 << " uint indices[3];\n"
415 << "} ib;\n"
416 << "\n"
417 << "layout (location=0) out perprimitiveEXT vec4 triangleColor[];\n"
418 << "\n"
419 << "void main ()\n"
420 << "{\n"
421 << " SetMeshOutputsEXT(3u, 1u);\n"
422 << " triangleColor[0] = vec4(0.0, 0.0, 1.0, 1.0);\n"
423 << "\n"
424 << " const uint vertexIndex = gl_LocalInvocationIndex;\n"
425 << " if (vertexIndex < 3u)\n"
426 << " {\n"
427 << " const uint coordsIndex = ib.indices[vertexIndex];\n"
428 << " gl_MeshVerticesEXT[vertexIndex].gl_Position = cb.coords[coordsIndex];\n"
429 << " }\n"
430 << " if (vertexIndex == 0u)\n"
431 << " {\n"
432 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
433 << " }\n"
434 << "}\n"
435 ;
436 dst.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
437
438 dst.glslSources.add("frag") << glu::FragmentSource(commonMeshFragShader()) << buildOptions;
439 }
440
createInstance(Context & context) const441 TestInstance* MeshOnlyTriangleCase::createInstance (Context& context) const
442 {
443 const std::vector<tcu::Vec4> vertexCoords =
444 {
445 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
446 tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
447 tcu::Vec4( 3.0f, -1.0f, 0.0f, 1.0f),
448 };
449 const std::vector<uint32_t> vertexIndices = { 0u, 1u, 2u };
450 const auto expectedColor = (m_rasterizationDisabled ? getClearColor() : tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
451 MeshTriangleRendererParams params (m_constructionType, std::move(vertexCoords), std::move(vertexIndices), 1u, expectedColor, m_rasterizationDisabled);
452
453 return new MeshTriangleRenderer(context, std::move(params));
454 }
455
createInstance(Context & context) const456 TestInstance* MeshTaskTriangleCase::createInstance (Context& context) const
457 {
458 const std::vector<tcu::Vec4> vertexCoords =
459 {
460 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
461 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
462 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
463 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
464 };
465 const std::vector<uint32_t> vertexIndices = { 2u, 0u, 1u, 1u, 3u, 2u };
466 MeshTriangleRendererParams params (m_constructionType, std::move(vertexCoords), std::move(vertexIndices), 2u, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
467
468 return new MeshTriangleRenderer(context, std::move(params));
469 }
470
createInstance(Context & context) const471 TestInstance* TaskOnlyTriangleCase::createInstance (Context& context) const
472 {
473 const std::vector<tcu::Vec4> vertexCoords =
474 {
475 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
476 tcu::Vec4(-1.0f, 3.0f, 0.0f, 1.0f),
477 tcu::Vec4( 3.0f, -1.0f, 0.0f, 1.0f),
478 };
479 const std::vector<uint32_t> vertexIndices = { 0u, 1u, 2u };
480 // Note we expect the clear color.
481 MeshTriangleRendererParams params (m_constructionType, std::move(vertexCoords), std::move(vertexIndices), 1u, getClearColor());
482
483 return new MeshTriangleRenderer(context, std::move(params));
484 }
485
iterate()486 tcu::TestStatus MeshTriangleRenderer::iterate ()
487 {
488 const auto& vki = m_context.getInstanceInterface();
489 const auto& vkd = m_context.getDeviceInterface();
490 const auto physicalDevice = m_context.getPhysicalDevice();
491 const auto device = m_context.getDevice();
492 auto& alloc = m_context.getDefaultAllocator();
493 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
494 const auto queue = m_context.getUniversalQueue();
495
496 const auto vertexBufferStages = VK_SHADER_STAGE_MESH_BIT_EXT;
497 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.vertexCoords));
498 const auto vertexBufferUsage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
499 const auto vertexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(0u);
500 const auto vertexBufferType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
501
502 const auto indexBufferStages = VK_SHADER_STAGE_MESH_BIT_EXT;
503 const auto indexBufferSize = static_cast<VkDeviceSize>(de::dataSize(m_params.vertexIndices));
504 const auto indexBufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
505 const auto indexBufferLoc = DescriptorSetUpdateBuilder::Location::binding(1u);
506 const auto indexBufferType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
507
508 // Vertex buffer.
509 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
510 BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
511 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
512 void* vertexBufferDataPtr = vertexBufferAlloc.getHostPtr();
513
514 deMemcpy(vertexBufferDataPtr, m_params.vertexCoords.data(), static_cast<size_t>(vertexBufferSize));
515 flushAlloc(vkd, device, vertexBufferAlloc);
516
517 // Index buffer.
518 const auto indexBufferInfo = makeBufferCreateInfo(indexBufferSize, indexBufferUsage);
519 BufferWithMemory indexBuffer (vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible);
520 auto& indexBufferAlloc = indexBuffer.getAllocation();
521 void* indexBufferDataPtr = indexBufferAlloc.getHostPtr();
522
523 deMemcpy(indexBufferDataPtr, m_params.vertexIndices.data(), static_cast<size_t>(indexBufferSize));
524 flushAlloc(vkd, device, indexBufferAlloc);
525
526 // Color buffer.
527 const auto colorBufferFormat = VK_FORMAT_R8G8B8A8_UNORM;
528 const auto colorBufferExtent = makeExtent3D(8u, 8u, 1u);
529 const auto colorBufferUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
530
531 const VkImageCreateInfo colorBufferInfo =
532 {
533 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
534 nullptr, // const void* pNext;
535 0u, // VkImageCreateFlags flags;
536 VK_IMAGE_TYPE_2D, // VkImageType imageType;
537 colorBufferFormat, // VkFormat format;
538 colorBufferExtent, // VkExtent3D extent;
539 1u, // uint32_t mipLevels;
540 1u, // uint32_t arrayLayers;
541 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
542 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
543 colorBufferUsage, // VkImageUsageFlags usage;
544 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
545 0u, // uint32_t queueFamilyIndexCount;
546 nullptr, // const uint32_t* pQueueFamilyIndices;
547 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
548 };
549 ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
550
551 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
552 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorBufferFormat, colorSRR);
553
554 // Render pass.
555 const auto renderPass = makeRenderPass(vkd, device, colorBufferFormat);
556
557 // Framebuffer.
558 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorBufferExtent.width, colorBufferExtent.height);
559
560 // Set layout.
561 DescriptorSetLayoutBuilder layoutBuilder;
562 layoutBuilder.addSingleBinding(vertexBufferType, vertexBufferStages);
563 layoutBuilder.addSingleBinding(indexBufferType, indexBufferStages);
564 const auto setLayout = layoutBuilder.build(vkd, device);
565
566 // Descriptor pool.
567 DescriptorPoolBuilder poolBuilder;
568 poolBuilder.addType(vertexBufferType);
569 poolBuilder.addType(indexBufferType);
570 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
571
572 // Descriptor set.
573 const auto descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
574
575 // Update descriptor set.
576 DescriptorSetUpdateBuilder updateBuilder;
577 const auto vertexBufferDescInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBufferSize);
578 const auto indexBufferDescInfo = makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBufferSize);
579 updateBuilder.writeSingle(descriptorSet.get(), vertexBufferLoc, vertexBufferType, &vertexBufferDescInfo);
580 updateBuilder.writeSingle(descriptorSet.get(), indexBufferLoc, indexBufferType, &indexBufferDescInfo);
581 updateBuilder.update(vkd, device);
582
583 // Pipeline layout.
584 const PipelineLayoutWrapper pipelineLayout (m_params.constructionType, vkd, device, setLayout.get());
585
586 // Shader modules.
587 ShaderWrapper taskModule;
588 ShaderWrapper fragModule;
589 const auto& binaries = m_context.getBinaryCollection();
590
591 if (binaries.contains("task"))
592 taskModule = ShaderWrapper(vkd, device, binaries.get("task"), 0u);
593 if (!m_params.rasterizationDisabled)
594 fragModule = ShaderWrapper(vkd, device, binaries.get("frag"), 0u);
595 const auto meshModule = ShaderWrapper(vkd, device, binaries.get("mesh"), 0u);
596
597 // Graphics pipeline.
598 std::vector<VkViewport> viewports (1u, makeViewport(colorBufferExtent));
599 std::vector<VkRect2D> scissors (1u, makeRect2D(colorBufferExtent));
600 GraphicsPipelineWrapper pipelineMaker (vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_params.constructionType);
601
602 makeMeshGraphicsPipeline(pipelineMaker, pipelineLayout, taskModule, meshModule, fragModule, renderPass.get(), viewports, scissors);
603 const auto pipeline = pipelineMaker.getPipeline();
604
605 // Command pool and buffer.
606 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
607 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
608 const auto cmdBuffer = cmdBufferPtr.get();
609
610 // Output buffer.
611 const auto tcuFormat = mapVkFormat(colorBufferFormat);
612 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * colorBufferExtent.width * colorBufferExtent.height);
613 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
614 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
615 BufferWithMemory outBuffer (vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible);
616 auto& outBufferAlloc = outBuffer.getAllocation();
617 void* outBufferData = outBufferAlloc.getHostPtr();
618
619 // Draw triangle.
620 beginCommandBuffer(vkd, cmdBuffer);
621 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), getClearColor());
622 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
623 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
624 vkd.cmdDrawMeshTasksEXT(cmdBuffer, m_params.taskCount, 1u, 1u);
625 endRenderPass(vkd, cmdBuffer);
626
627 // Copy color buffer to output buffer.
628 const tcu::IVec3 imageDim (static_cast<int>(colorBufferExtent.width), static_cast<int>(colorBufferExtent.height), static_cast<int>(colorBufferExtent.depth));
629 const tcu::IVec2 imageSize (imageDim.x(), imageDim.y());
630
631 copyImageToBuffer(vkd, cmdBuffer, colorBuffer.get(), outBuffer.get(), imageSize);
632 endCommandBuffer(vkd, cmdBuffer);
633 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
634
635 // Invalidate alloc.
636 invalidateAlloc(vkd, device, outBufferAlloc);
637 tcu::ConstPixelBufferAccess outPixels(tcuFormat, imageDim, outBufferData);
638
639 auto& log = m_context.getTestContext().getLog();
640 const tcu::Vec4 threshold (0.0f); // The color can be represented exactly.
641
642 if (!tcu::floatThresholdCompare(log, "Result", "", m_params.expectedColor, outPixels, threshold, tcu::COMPARE_LOG_EVERYTHING))
643 return tcu::TestStatus::fail("Failed; check log for details");
644
645 return tcu::TestStatus::pass("Pass");
646 }
647
gradientImageExtent()648 VkExtent3D gradientImageExtent ()
649 {
650 return makeExtent3D(256u, 256u, 1u);
651 }
652
653 struct GradientParams
654 {
655 tcu::Maybe<FragmentSize> fragmentSize;
656 PipelineConstructionType constructionType;
657
GradientParamsvkt::MeshShader::__anon4a1cb0ed0111::GradientParams658 GradientParams (const tcu::Maybe<FragmentSize>& fragmentSize_, PipelineConstructionType constructionType_)
659 : fragmentSize (fragmentSize_)
660 , constructionType (constructionType_)
661 {}
662 };
663
checkMeshSupport(Context & context,GradientParams params)664 void checkMeshSupport (Context& context, GradientParams params)
665 {
666 checkTaskMeshShaderSupportEXT(context, false, true);
667
668 if (static_cast<bool>(params.fragmentSize))
669 {
670 const auto& features = context.getMeshShaderFeaturesEXT();
671 if (!features.primitiveFragmentShadingRateMeshShader)
672 TCU_THROW(NotSupportedError, "Primitive fragment shading rate not supported in mesh shaders");
673 }
674
675 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), params.constructionType);
676 }
677
initGradientPrograms(vk::SourceCollections & programCollection,GradientParams params)678 void initGradientPrograms (vk::SourceCollections& programCollection, GradientParams params)
679 {
680 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
681 const auto extent = gradientImageExtent();
682
683 std::ostringstream frag;
684 frag
685 << "#version 450\n"
686 << "\n"
687 << "layout (location=0) in vec4 inColor;\n"
688 << "layout (location=0) out vec4 outColor;\n"
689 << "\n"
690 << "void main ()\n"
691 << "{\n"
692 << " outColor = inColor;\n"
693 << "}\n"
694 ;
695 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
696
697 std::string fragmentSizeStr;
698 const auto useFragmentSize = static_cast<bool>(params.fragmentSize);
699
700 if (useFragmentSize)
701 {
702 const auto& fragSize = params.fragmentSize.get();
703 fragmentSizeStr = getGLSLShadingRateMask(fragSize);
704
705 const auto val = getSPVShadingRateValue(fragSize);
706 DE_ASSERT(val != 0);
707 DE_UNREF(val); // For release builds.
708 }
709
710 std::ostringstream mesh;
711 mesh
712 << "#version 450\n"
713 << "#extension GL_EXT_mesh_shader : enable\n"
714 ;
715
716 if (useFragmentSize)
717 mesh << "#extension GL_EXT_fragment_shading_rate : enable\n";
718
719 mesh
720 << "\n"
721 << "layout(local_size_x=4) in;\n"
722 << "layout(triangles) out;\n"
723 << "layout(max_vertices=256, max_primitives=256) out;\n"
724 << "\n"
725 << "layout (location=0) out vec4 outColor[];\n"
726 << "\n"
727 ;
728
729 if (useFragmentSize)
730 {
731 mesh
732 << "perprimitiveEXT out gl_MeshPerPrimitiveEXT {\n"
733 << " int gl_PrimitiveShadingRateEXT;\n"
734 << "} gl_MeshPrimitivesEXT[];\n"
735 << "\n"
736 ;
737 }
738
739 mesh
740 << "void main ()\n"
741 << "{\n"
742 << " SetMeshOutputsEXT(4u, 2u);\n"
743 << "\n"
744 << " const uint vertex = gl_LocalInvocationIndex;\n"
745 << " const uint primitive = gl_LocalInvocationIndex;\n"
746 << "\n"
747 << " const vec4 topLeft = vec4(-1.0, -1.0, 0.0, 1.0);\n"
748 << " const vec4 botLeft = vec4(-1.0, 1.0, 0.0, 1.0);\n"
749 << " const vec4 topRight = vec4( 1.0, -1.0, 0.0, 1.0);\n"
750 << " const vec4 botRight = vec4( 1.0, 1.0, 0.0, 1.0);\n"
751 << " const vec4 positions[4] = vec4[](topLeft, botLeft, topRight, botRight);\n"
752 << "\n"
753 // Green changes according to the width.
754 // Blue changes according to the height.
755 // Value 0 at the center of the first pixel and value 1 at the center of the last pixel.
756 << " const float width = " << extent.width << ";\n"
757 << " const float height = " << extent.height << ";\n"
758 << " const float halfWidth = (1.0 / (width - 1.0)) / 2.0;\n"
759 << " const float halfHeight = (1.0 / (height - 1.0)) / 2.0;\n"
760 << " const float minGreen = -halfWidth;\n"
761 << " const float maxGreen = 1.0+halfWidth;\n"
762 << " const float minBlue = -halfHeight;\n"
763 << " const float maxBlue = 1.0+halfHeight;\n"
764 << " const vec4 colors[4] = vec4[](\n"
765 << " vec4(0, minGreen, minBlue, 1.0),\n"
766 << " vec4(0, minGreen, maxBlue, 1.0),\n"
767 << " vec4(0, maxGreen, minBlue, 1.0),\n"
768 << " vec4(0, maxGreen, maxBlue, 1.0)\n"
769 << " );\n"
770 << "\n"
771 << " const uvec3 indices[2] = uvec3[](\n"
772 << " uvec3(0, 1, 2),\n"
773 << " uvec3(1, 3, 2)\n"
774 << " );\n"
775 << " if (vertex < 4u)\n"
776 << " {\n"
777 << " gl_MeshVerticesEXT[vertex].gl_Position = positions[vertex];\n"
778 << " outColor[vertex] = colors[vertex];\n"
779 << " }\n"
780 << " if (primitive < 2u)\n"
781 << " {\n"
782 ;
783
784 if (useFragmentSize)
785 {
786 mesh
787 << " gl_MeshPrimitivesEXT[primitive].gl_PrimitiveShadingRateEXT = " << fragmentSizeStr << ";\n"
788 ;
789 }
790
791 mesh
792 << " gl_PrimitiveTriangleIndicesEXT[primitive] = indices[primitive];\n"
793 << " }\n"
794 << "}\n"
795 ;
796 ;
797 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
798 }
799
coordColorFormat(int x,int y,const tcu::Vec4 & color)800 std::string coordColorFormat (int x, int y, const tcu::Vec4& color)
801 {
802 std::ostringstream msg;
803 msg << "[" << x << ", " << y << "]=(" << color.x() << ", " << color.y() << ", " << color.z() << ", " << color.w() << ")";
804 return msg.str();
805 }
806
testFullscreenGradient(Context & context,GradientParams params)807 tcu::TestStatus testFullscreenGradient (Context& context, GradientParams params)
808 {
809 const auto& vki = context.getInstanceInterface();
810 const auto& vkd = context.getDeviceInterface();
811 const auto physicalDevice = context.getPhysicalDevice();
812 const auto device = context.getDevice();
813 auto& alloc = context.getDefaultAllocator();
814 const auto qIndex = context.getUniversalQueueFamilyIndex();
815 const auto queue = context.getUniversalQueue();
816 const auto useFragmentSize = static_cast<bool>(params.fragmentSize);
817 const auto defaultFragmentSize = FragmentSize::SIZE_1X1;
818 const auto rateSize = getShadingRateSize(useFragmentSize ? params.fragmentSize.get() : defaultFragmentSize);
819
820 // Color buffer.
821 const auto colorBufferFormat = VK_FORMAT_R8G8B8A8_UNORM;
822 const auto colorBufferExtent = makeExtent3D(256u, 256u, 1u); // Big enough for a detailed gradient, small enough to get unique colors.
823 const auto colorBufferUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
824
825 const VkImageCreateInfo colorBufferInfo =
826 {
827 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
828 nullptr, // const void* pNext;
829 0u, // VkImageCreateFlags flags;
830 VK_IMAGE_TYPE_2D, // VkImageType imageType;
831 colorBufferFormat, // VkFormat format;
832 colorBufferExtent, // VkExtent3D extent;
833 1u, // uint32_t mipLevels;
834 1u, // uint32_t arrayLayers;
835 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
836 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
837 colorBufferUsage, // VkImageUsageFlags usage;
838 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
839 0u, // uint32_t queueFamilyIndexCount;
840 nullptr, // const uint32_t* pQueueFamilyIndices;
841 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
842 };
843 ImageWithMemory colorBuffer(vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
844
845 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
846 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, colorBufferFormat, colorSRR);
847
848 // Render pass.
849 const auto renderPass = makeRenderPass(vkd, device, colorBufferFormat);
850
851 // Framebuffer.
852 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), colorBufferExtent.width, colorBufferExtent.height);
853
854 // Set layout.
855 DescriptorSetLayoutBuilder layoutBuilder;
856 const auto setLayout = layoutBuilder.build(vkd, device);
857
858 // Pipeline layout.
859 const PipelineLayoutWrapper pipelineLayout (params.constructionType, vkd, device, setLayout.get());
860
861 // Shader modules.
862 ShaderWrapper taskModule;
863 const auto& binaries = context.getBinaryCollection();
864
865 const auto meshModule = ShaderWrapper(vkd, device, binaries.get("mesh"), 0u);
866 const auto fragModule = ShaderWrapper(vkd, device, binaries.get("frag"), 0u);
867
868 using ShadingRateInfoPtr = de::MovePtr<VkPipelineFragmentShadingRateStateCreateInfoKHR>;
869 ShadingRateInfoPtr pNext;
870 if (useFragmentSize)
871 {
872 pNext = ShadingRateInfoPtr(new VkPipelineFragmentShadingRateStateCreateInfoKHR);
873 *pNext = initVulkanStructure();
874
875 pNext->fragmentSize = getShadingRateSize(FragmentSize::SIZE_1X1); // 1x1 will not be used as the primitive rate in tests with fragment size.
876 pNext->combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR;
877 pNext->combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR;
878 }
879
880 // Graphics pipeline.
881 std::vector<VkViewport> viewports (1u, makeViewport(colorBufferExtent));
882 std::vector<VkRect2D> scissors (1u, makeRect2D(colorBufferExtent));
883 GraphicsPipelineWrapper pipelineMaker (vki, vkd, physicalDevice, device, context.getDeviceExtensions(), params.constructionType);
884
885 makeMeshGraphicsPipeline(pipelineMaker, pipelineLayout,
886 taskModule, meshModule, fragModule,
887 renderPass.get(), viewports, scissors, 0u, nullptr, pNext.get());
888 const auto pipeline = pipelineMaker.getPipeline();
889
890 // Command pool and buffer.
891 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
892 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
893 const auto cmdBuffer = cmdBufferPtr.get();
894
895 // Output buffer.
896 const auto tcuFormat = mapVkFormat(colorBufferFormat);
897 const auto outBufferSize = static_cast<VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * colorBufferExtent.width * colorBufferExtent.height);
898 const auto outBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
899 const auto outBufferInfo = makeBufferCreateInfo(outBufferSize, outBufferUsage);
900 BufferWithMemory outBuffer (vkd, device, alloc, outBufferInfo, MemoryRequirement::HostVisible);
901 auto& outBufferAlloc = outBuffer.getAllocation();
902 void* outBufferData = outBufferAlloc.getHostPtr();
903
904 // Draw triangles.
905 beginCommandBuffer(vkd, cmdBuffer);
906 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), getClearColor());
907 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
908 vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
909 endRenderPass(vkd, cmdBuffer);
910
911 // Copy color buffer to output buffer.
912 const tcu::IVec3 imageDim (static_cast<int>(colorBufferExtent.width), static_cast<int>(colorBufferExtent.height), static_cast<int>(colorBufferExtent.depth));
913 const tcu::IVec2 imageSize (imageDim.x(), imageDim.y());
914
915 copyImageToBuffer(vkd, cmdBuffer, colorBuffer.get(), outBuffer.get(), imageSize);
916 endCommandBuffer(vkd, cmdBuffer);
917 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
918
919 // Invalidate alloc.
920 invalidateAlloc(vkd, device, outBufferAlloc);
921 tcu::ConstPixelBufferAccess outPixels(tcuFormat, imageDim, outBufferData);
922
923 // Create reference image.
924 tcu::TextureLevel refLevel (tcuFormat, imageDim.x(), imageDim.y(), imageDim.z());
925 tcu::PixelBufferAccess refAccess (refLevel);
926 for (int y = 0; y < imageDim.y(); ++y)
927 for (int x = 0; x < imageDim.x(); ++x)
928 {
929 const tcu::IVec4 color (0, x, y, 255);
930 refAccess.setPixel(color, x, y);
931 }
932
933 const tcu::TextureFormat maskFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
934 tcu::TextureLevel errorMask (maskFormat, imageDim.x(), imageDim.y(), imageDim.z());
935 tcu::PixelBufferAccess errorAccess (errorMask);
936 const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
937 const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f);
938 auto& log = context.getTestContext().getLog();
939
940 // Each block needs to have the same color and be equal to one of the pixel colors of that block in the reference image.
941 const auto blockWidth = static_cast<int>(rateSize.width);
942 const auto blockHeight = static_cast<int>(rateSize.height);
943
944 tcu::clear(errorAccess, green);
945 bool globalFail = false;
946
947 for (int y = 0; y < imageDim.y() / blockHeight; ++y)
948 for (int x = 0; x < imageDim.x() / blockWidth; ++x)
949 {
950 bool blockFail = false;
951 std::vector<tcu::Vec4> candidates;
952
953 candidates.reserve(rateSize.width * rateSize.height);
954
955 const auto cornerY = y * blockHeight;
956 const auto cornerX = x * blockWidth;
957 const auto cornerColor = outPixels.getPixel(cornerX, cornerY);
958
959 for (int blockY = 0; blockY < blockHeight; ++blockY)
960 for (int blockX = 0; blockX < blockWidth; ++blockX)
961 {
962 const auto absY = cornerY + blockY;
963 const auto absX = cornerX + blockX;
964 const auto resColor = outPixels.getPixel(absX, absY);
965
966 candidates.push_back(refAccess.getPixel(absX, absY));
967
968 if (cornerColor != resColor)
969 {
970 std::ostringstream msg;
971 msg << "Block not uniform: "
972 << coordColorFormat(cornerX, cornerY, cornerColor)
973 << " vs "
974 << coordColorFormat(absX, absY, resColor);
975 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
976
977 blockFail = true;
978 }
979 }
980
981 if (!de::contains(begin(candidates), end(candidates), cornerColor))
982 {
983 std::ostringstream msg;
984 msg << "Block color does not match any reference color at [" << cornerX << ", " << cornerY << "]";
985 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
986 blockFail = true;
987 }
988
989 if (blockFail)
990 {
991 const auto blockAccess = tcu::getSubregion(errorAccess, cornerX, cornerY, blockWidth, blockHeight);
992 tcu::clear(blockAccess, red);
993 globalFail = true;
994 }
995 }
996
997 if (globalFail)
998 {
999 log << tcu::TestLog::Image("Result", "", outPixels);
1000 log << tcu::TestLog::Image("Reference", "", refAccess);
1001 log << tcu::TestLog::Image("ErrorMask", "", errorAccess);
1002
1003 TCU_FAIL("Color mismatch; check log for more details");
1004 }
1005
1006 return tcu::TestStatus::pass("Pass");
1007 }
1008
1009 // Smoke test that emits one triangle per pixel plus one more global background triangle, but doesn't use every triangle. It only
1010 // draws half the front triangles. It gets information from a mix of vertex buffers, per primitive buffers and push constants.
1011 struct PartialUsageParams
1012 {
1013 PipelineConstructionType constructionType;
1014 bool compactVertices;
1015 };
1016
1017 class PartialUsageCase : public vkt::TestCase
1018 {
1019 public:
1020 static constexpr uint32_t kWidth = 16u;
1021 static constexpr uint32_t kHeight = 16u;
1022 static constexpr uint32_t kLocalInvocations = 64u;
1023 static constexpr uint32_t kMaxPrimitives = kLocalInvocations;
1024 static constexpr uint32_t kMaxVertices = kMaxPrimitives * 3u;
1025 static constexpr uint32_t kNumWorkGroups = 2u;
1026 static constexpr uint32_t kTotalPrimitives = kNumWorkGroups * kMaxPrimitives;
1027
PartialUsageCase(tcu::TestContext & testCtx,const std::string & name,const PartialUsageParams & params)1028 PartialUsageCase (tcu::TestContext& testCtx, const std::string& name, const PartialUsageParams& params)
1029 : vkt::TestCase(testCtx, name)
1030 , m_params(params)
1031 {}
~PartialUsageCase(void)1032 virtual ~PartialUsageCase (void) {}
1033
1034 void checkSupport (Context& context) const override;
1035 void initPrograms (vk::SourceCollections& programCollection) const override;
1036 TestInstance* createInstance (Context& context) const override;
1037
1038 struct IndexAndColor
1039 {
1040 uint32_t index;
1041 float color;
1042 };
1043
1044 struct PushConstants
1045 {
1046 uint32_t totalTriangles;
1047 float depth;
1048 float red;
1049 };
1050
1051 protected:
1052 PartialUsageParams m_params;
1053 };
1054
1055 class PartialUsageInstance : public vkt::TestInstance
1056 {
1057 public:
PartialUsageInstance(Context & context,PipelineConstructionType constructionType)1058 PartialUsageInstance (Context& context, PipelineConstructionType constructionType)
1059 : vkt::TestInstance (context)
1060 , m_constructionType (constructionType)
1061 {}
~PartialUsageInstance(void)1062 virtual ~PartialUsageInstance (void) {}
1063
1064 tcu::TestStatus iterate (void) override;
1065
1066 protected:
1067 const PipelineConstructionType m_constructionType;
1068 };
1069
checkSupport(Context & context) const1070 void PartialUsageCase::checkSupport (Context& context) const
1071 {
1072 checkTaskMeshShaderSupportEXT(context, true, true);
1073 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params.constructionType);
1074 }
1075
createInstance(Context & context) const1076 TestInstance* PartialUsageCase::createInstance (Context &context) const
1077 {
1078 return new PartialUsageInstance(context, m_params.constructionType);
1079 }
1080
initPrograms(vk::SourceCollections & programCollection) const1081 void PartialUsageCase::initPrograms (vk::SourceCollections &programCollection) const
1082 {
1083 const auto buildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1084
1085 // The task shader will always emit two mesh shader work groups, which may do some work.
1086 std::ostringstream task;
1087 task
1088 << "#version 450\n"
1089 << "#extension GL_EXT_mesh_shader : enable\n"
1090 << "\n"
1091 << "layout (local_size_x=1) in;\n"
1092 << "\n"
1093 << "void main ()\n"
1094 << "{\n"
1095 << " EmitMeshTasksEXT(" << kNumWorkGroups << ", 1u, 1u);\n"
1096 << "}\n"
1097 ;
1098 programCollection.glslSources.add("task") << glu::TaskSource(task.str()) << buildOptions;
1099
1100 // The frag shader will color the output with the indicated color;
1101 std::ostringstream frag;
1102 frag
1103 << "#version 450\n"
1104 << "#extension GL_EXT_mesh_shader : enable\n"
1105 << "\n"
1106 << "layout (location=0) perprimitiveEXT in vec4 primitiveColor;\n"
1107 << "layout (location=0) out vec4 outColor;\n"
1108 << "\n"
1109 << "void main ()\n"
1110 << "{\n"
1111 << " outColor = primitiveColor;\n"
1112 << "}\n"
1113 ;
1114 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()) << buildOptions;
1115
1116 // The mesh shader reads primitive indices and vertices data from buffers and push constants. The primitive data block contains
1117 // primitive indices and primitive colors that must be read by the current invocation using an index that depends on its global
1118 // invocation index. The primitive index allows access into the triangle vertices buffer. Depending on the current work group
1119 // index and total number of triangles (set by push constants), the current invocation may have to emit a primitive or not.
1120 //
1121 // In addition, the non-compacted variant emits some extra unused vertices at the start of the array.
1122 const auto kExtraVertices = (m_params.compactVertices ? 0u : kLocalInvocations);
1123 const auto kLocationMaxVertices = kMaxVertices + kExtraVertices;
1124
1125 if (!m_params.compactVertices)
1126 DE_ASSERT(kLocationMaxVertices <= 256u);
1127
1128 std::ostringstream mesh;
1129 mesh
1130 << "#version 450\n"
1131 << "#extension GL_EXT_mesh_shader : enable\n"
1132 << "\n"
1133 << "layout (local_size_x=" << kLocalInvocations << ", local_size_y=1, local_size_z=1) in;\n"
1134 << "layout (triangles) out;\n"
1135 << "layout (max_vertices=" << kLocationMaxVertices << ", max_primitives=" << kMaxPrimitives << ") out;\n"
1136 << "\n"
1137 << "layout (location=0) perprimitiveEXT out vec4 primitiveColor[];\n"
1138 << "\n"
1139 << "layout (set=0, binding=0, std430) readonly buffer VerticesBlock {\n"
1140 << " vec2 coords[];\n" // 3 vertices per triangle.
1141 << "} vertex;\n"
1142 << "\n"
1143 << "struct IndexAndColor {\n"
1144 << " uint index;\n" // Triangle index (for accessing the coordinates buffer above).
1145 << " float color;\n" // Triangle blue color component.
1146 << "};\n"
1147 << "\n"
1148 << "layout (set=0, binding=1, std430) readonly buffer PrimitiveDataBlock {\n"
1149 << " IndexAndColor data[];\n"
1150 << "} primitive;\n"
1151 << "\n"
1152 << "layout (push_constant, std430) uniform PushConstantBlock {\n"
1153 << " uint totalTriangles;\n" // How many triangles in total we have to emit.
1154 << " float depth;\n" // Triangle depth (allows painting the background with a different color).
1155 << " float red;\n" // Triangle red color component.
1156 << "} pc;\n"
1157 << "\n"
1158 << "void main ()\n"
1159 << "{\n"
1160 // First primitive for this work group, plus the work group primitive and vertex count.
1161 << " const uint firstPrimitive = gl_WorkGroupID.x * gl_WorkGroupSize.x;\n"
1162 << " const uint wgTriangleCount = ((pc.totalTriangles >= firstPrimitive) ? min(pc.totalTriangles - firstPrimitive, " << kLocalInvocations << ") : 0u);\n"
1163 << " const uint wgVertexCount = wgTriangleCount * 3u + " << kExtraVertices << "u;\n"
1164 << "\n"
1165 ;
1166
1167 if (!m_params.compactVertices)
1168 {
1169 // Produce extra unused vertices.
1170 mesh
1171 << " {\n"
1172 << " const float proportion = float(gl_LocalInvocationIndex) / float(gl_WorkGroupSize.x);\n"
1173 << " gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(proportion, 1.0 - proportion, pc.depth, 1.0);\n"
1174 << " }\n"
1175 << "\n"
1176 ;
1177 }
1178
1179 mesh
1180 << " SetMeshOutputsEXT(wgVertexCount, wgTriangleCount);\n"
1181 << "\n"
1182 // Calculate global invocation primitive id, and use it to access the per-primitive buffer. From there, get the primitive index in the
1183 // vertex buffer and the blue color component.
1184 << " if (gl_LocalInvocationIndex < wgTriangleCount) {\n"
1185 << " const uint primitiveID = firstPrimitive + gl_LocalInvocationIndex;\n"
1186 << " const uint primitiveIndex = primitive.data[primitiveID].index;\n"
1187 << " const float blue = primitive.data[primitiveID].color;\n"
1188 << " const uint firstVertexIndex = primitiveIndex * 3u;\n"
1189 << " const uvec3 globalVertexIndices = uvec3(firstVertexIndex, firstVertexIndex+1u, firstVertexIndex+2u);\n"
1190 << " const uint localPrimitiveID = gl_LocalInvocationIndex;\n"
1191 << " const uint firstLocalVertex = localPrimitiveID * 3u + " << kExtraVertices << "u;\n"
1192 << " const uvec3 localVertexIndices = uvec3(firstLocalVertex, firstLocalVertex+1u, firstLocalVertex+2u);\n"
1193 << "\n"
1194 << " gl_MeshVerticesEXT[localVertexIndices.x].gl_Position = vec4(vertex.coords[globalVertexIndices.x], pc.depth, 1.0);\n"
1195 << " gl_MeshVerticesEXT[localVertexIndices.y].gl_Position = vec4(vertex.coords[globalVertexIndices.y], pc.depth, 1.0);\n"
1196 << " gl_MeshVerticesEXT[localVertexIndices.z].gl_Position = vec4(vertex.coords[globalVertexIndices.z], pc.depth, 1.0);\n"
1197 << "\n"
1198 << " gl_PrimitiveTriangleIndicesEXT[localPrimitiveID] = localVertexIndices;\n"
1199 << " primitiveColor[localPrimitiveID] = vec4(pc.red, 0.0, blue, 1.0f);\n"
1200 << " }\n"
1201 << "}\n"
1202 ;
1203 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << buildOptions;
1204 }
1205
pixelToFBCoords(uint32_t pixelId,uint32_t totalPixels)1206 inline float pixelToFBCoords (uint32_t pixelId, uint32_t totalPixels)
1207 {
1208 return (static_cast<float>(pixelId) + 0.5f) / static_cast<float>(totalPixels) * 2.0f - 1.0f;
1209 }
1210
iterate()1211 tcu::TestStatus PartialUsageInstance::iterate ()
1212 {
1213 const auto& vki = m_context.getInstanceInterface();
1214 const auto& vkd = m_context.getDeviceInterface();
1215 const auto physicalDevice = m_context.getPhysicalDevice();
1216 const auto device = m_context.getDevice();
1217 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
1218 const auto queue = m_context.getUniversalQueue();
1219 auto& alloc = m_context.getDefaultAllocator();
1220 const auto bufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
1221 const auto bufferDescType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1222 const auto bufferDescStages = VK_SHADER_STAGE_MESH_BIT_EXT;
1223 const auto pcSize = static_cast<VkDeviceSize>(sizeof(PartialUsageCase::PushConstants));
1224 const auto pcStages = bufferDescStages;
1225 const auto pcRange = makePushConstantRange(pcStages, 0u, static_cast<uint32_t>(pcSize));
1226 const auto fbExtent = makeExtent3D(PartialUsageCase::kWidth, PartialUsageCase::kHeight, 1u);
1227 const tcu::IVec3 iExtent (static_cast<int>(fbExtent.width), static_cast<int>(fbExtent.height), static_cast<int>(fbExtent.depth));
1228 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
1229 const auto colorTcuFormat = mapVkFormat(colorFormat);
1230 const auto dsFormat = VK_FORMAT_D16_UNORM;
1231 const auto vertexSize = sizeof(tcu::Vec2);
1232 const auto verticesPerTriangle = 3u;
1233 const auto pixelCount = fbExtent.width * fbExtent.height * fbExtent.depth;
1234 const auto vertexCount = pixelCount * verticesPerTriangle;
1235 const auto triangleSize = vertexSize * verticesPerTriangle;
1236 const auto colorThreshold = 0.005f; // 1/255 < 0.005 < 2/255
1237 const float fgRed = 0.0f;
1238 const float bgRed = 1.0f;
1239 const float bgBlue = 1.0f;
1240
1241 // Quarter of the pixel width and height in framebuffer coordinates.
1242 const float pixelWidth4 = 2.0f / (static_cast<float>(fbExtent.width) * 4.0f);
1243 const float pixelHeight4 = 2.0f / (static_cast<float>(fbExtent.height) * 4.0f);
1244
1245 // Offsets for each triangle vertex from the pixel center.
1246 // +-------------------+
1247 // | 2 |
1248 // | x |
1249 // | x x |
1250 // | x x |
1251 // | x x x |
1252 // | x x |
1253 // | xxxxxxxxxxx |
1254 // | 0 1 |
1255 // +-------------------+
1256 const std::vector<tcu::Vec2> offsets
1257 {
1258 tcu::Vec2(-pixelWidth4, +pixelHeight4),
1259 tcu::Vec2(+pixelWidth4, +pixelHeight4),
1260 tcu::Vec2( 0.0f, -pixelHeight4),
1261 };
1262
1263 // We'll use two draw calls: triangles on the front and triangle that sets the background color, so we need two vertex buffers
1264 // and two primitive data buffers.
1265 const auto vertexBufferFrontSize = static_cast<VkDeviceSize>(triangleSize * pixelCount);
1266 const auto vertexBufferFrontInfo = makeBufferCreateInfo(vertexBufferFrontSize, bufferUsage);
1267 BufferWithMemory vertexBufferFront (vkd, device, alloc, vertexBufferFrontInfo, MemoryRequirement::HostVisible);
1268 auto& vertexBufferFrontAlloc = vertexBufferFront.getAllocation();
1269 void* vertexBufferFrontData = vertexBufferFrontAlloc.getHostPtr();
1270
1271 std::vector<tcu::Vec2> trianglePerPixel;
1272 trianglePerPixel.reserve(vertexCount);
1273
1274 // Fill front vertex buffer.
1275 for (uint32_t y = 0u; y < PartialUsageCase::kHeight; ++y)
1276 for (uint32_t x = 0u; x < PartialUsageCase::kWidth; ++x)
1277 for (uint32_t v = 0u; v < verticesPerTriangle; ++v)
1278 {
1279 const auto& offset = offsets.at(v);
1280 const auto xCoord = pixelToFBCoords(x, PartialUsageCase::kWidth) + offset.x();
1281 const auto yCoord = pixelToFBCoords(y, PartialUsageCase::kHeight) + offset.y();
1282 trianglePerPixel.emplace_back(xCoord, yCoord);
1283 }
1284 deMemcpy(vertexBufferFrontData, trianglePerPixel.data(), de::dataSize(trianglePerPixel));
1285
1286 // For the front triangles we will select some pixels randomly.
1287 using IndexAndColor = PartialUsageCase::IndexAndColor;
1288
1289 std::set<uint32_t> selectedPixels;
1290 std::vector<IndexAndColor> indicesAndColors;
1291 de::Random rnd (1646058327u);
1292 const auto maxId = static_cast<int>(pixelCount) - 1;
1293 const auto fTotalTriangles = static_cast<float>(PartialUsageCase::kTotalPrimitives);
1294
1295 while (selectedPixels.size() < PartialUsageCase::kTotalPrimitives)
1296 {
1297 const auto pixelId = static_cast<uint32_t>(rnd.getInt(0, maxId));
1298 if (!selectedPixels.count(pixelId))
1299 {
1300 selectedPixels.insert(pixelId);
1301
1302 const float colorVal = static_cast<float>(selectedPixels.size()) / fTotalTriangles;
1303 const IndexAndColor indexAndColor { pixelId, colorVal };
1304
1305 indicesAndColors.push_back(indexAndColor);
1306 }
1307 }
1308
1309 const auto primDataBufferFrontSize = static_cast<VkDeviceSize>(de::dataSize(indicesAndColors));
1310 const auto primDataBufferFrontInfo = makeBufferCreateInfo(primDataBufferFrontSize, bufferUsage);
1311 BufferWithMemory primDataBufferFront (vkd, device, alloc, primDataBufferFrontInfo, MemoryRequirement::HostVisible);
1312 auto& primDataBufferFrontAlloc = primDataBufferFront.getAllocation();
1313 void* primDataBufferFrontData = primDataBufferFrontAlloc.getHostPtr();
1314 deMemcpy(primDataBufferFrontData, indicesAndColors.data(), de::dataSize(indicesAndColors));
1315
1316 // Generate reference image based on the previous data.
1317 tcu::TextureLevel referenceLevel (colorTcuFormat, iExtent.x(), iExtent.y(), iExtent.z());
1318 tcu::PixelBufferAccess referenceAccess = referenceLevel.getAccess();
1319 const tcu::Vec4 bgColor (bgRed, 0.0f, bgBlue, 1.0f);
1320
1321 tcu::clear(referenceAccess, bgColor);
1322 for (const auto& indexAndColor : indicesAndColors)
1323 {
1324 const int xCoord = static_cast<int>(indexAndColor.index % fbExtent.width);
1325 const int yCoord = static_cast<int>(indexAndColor.index / fbExtent.width);
1326 const tcu::Vec4 color (fgRed, 0.0f, indexAndColor.color, 1.0f);
1327
1328 referenceAccess.setPixel(color, xCoord, yCoord);
1329 }
1330
1331 // Background buffers. These will only contain one triangle.
1332 const std::vector<tcu::Vec2> backgroundTriangle
1333 {
1334 tcu::Vec2(-1.0f, -1.0f),
1335 tcu::Vec2(-1.0f, 3.0f),
1336 tcu::Vec2( 3.0f, -1.0f),
1337 };
1338
1339 const PartialUsageCase::IndexAndColor backgroundTriangleData { 0u, bgBlue };
1340
1341 const auto vertexBufferBackSize = static_cast<VkDeviceSize>(de::dataSize(backgroundTriangle));
1342 const auto vertexBufferBackInfo = makeBufferCreateInfo(vertexBufferBackSize, bufferUsage);
1343 BufferWithMemory vertexBufferBack (vkd, device, alloc, vertexBufferBackInfo, MemoryRequirement::HostVisible);
1344 auto& vertexBufferBackAlloc = vertexBufferBack.getAllocation();
1345 void* vertexBufferBackData = vertexBufferBackAlloc.getHostPtr();
1346 deMemcpy(vertexBufferBackData, backgroundTriangle.data(), de::dataSize(backgroundTriangle));
1347
1348 const auto primDataBufferBackSize = static_cast<VkDeviceSize>(sizeof(backgroundTriangleData));
1349 const auto primDataBufferBackInfo = makeBufferCreateInfo(primDataBufferBackSize, bufferUsage);
1350 BufferWithMemory primDataBufferBack (vkd, device, alloc, primDataBufferBackInfo, MemoryRequirement::HostVisible);
1351 auto& primDataBufferBackAlloc = primDataBufferBack.getAllocation();
1352 void* primDataBufferBackData = primDataBufferBackAlloc.getHostPtr();
1353 deMemcpy(primDataBufferBackData, &backgroundTriangleData, sizeof(backgroundTriangleData));
1354
1355 // Descriptor pool and descriptor sets.
1356 DescriptorPoolBuilder poolBuilder;
1357 poolBuilder.addType(bufferDescType, 4u);
1358 const auto descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
1359
1360 DescriptorSetLayoutBuilder setLayoutBuilder;
1361 setLayoutBuilder.addSingleBinding(bufferDescType, bufferDescStages);
1362 setLayoutBuilder.addSingleBinding(bufferDescType, bufferDescStages);
1363 const auto setLayout = setLayoutBuilder.build(vkd, device);
1364
1365 const auto setFront = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
1366 const auto setBack = makeDescriptorSet(vkd, device, descriptorPool.get(), setLayout.get());
1367
1368 // Update descriptor sets.
1369 DescriptorSetUpdateBuilder updateBuilder;
1370 {
1371 const auto bufferInfo = makeDescriptorBufferInfo(vertexBufferFront.get(), 0ull, vertexBufferFrontSize);
1372 updateBuilder.writeSingle(setFront.get(), DescriptorSetUpdateBuilder::Location::binding(0u), bufferDescType, &bufferInfo);
1373 }
1374 {
1375 const auto bufferInfo = makeDescriptorBufferInfo(primDataBufferFront.get(), 0ull, primDataBufferFrontSize);
1376 updateBuilder.writeSingle(setFront.get(), DescriptorSetUpdateBuilder::Location::binding(1u), bufferDescType, &bufferInfo);
1377 }
1378 {
1379 const auto bufferInfo = makeDescriptorBufferInfo(vertexBufferBack.get(), 0ull, vertexBufferBackSize);
1380 updateBuilder.writeSingle(setBack.get(), DescriptorSetUpdateBuilder::Location::binding(0u), bufferDescType, &bufferInfo);
1381 }
1382 {
1383 const auto bufferInfo = makeDescriptorBufferInfo(primDataBufferBack.get(), 0ull, primDataBufferBackSize);
1384 updateBuilder.writeSingle(setBack.get(), DescriptorSetUpdateBuilder::Location::binding(1u), bufferDescType, &bufferInfo);
1385 }
1386 updateBuilder.update(vkd, device);
1387
1388 // Pipeline layout.
1389 const PipelineLayoutWrapper pipelineLayout (m_constructionType, vkd, device, setLayout.get(), &pcRange);
1390
1391 // Shader modules.
1392 const auto& binaries = m_context.getBinaryCollection();
1393 const auto taskShader = ShaderWrapper(vkd, device, binaries.get("task"));
1394 const auto meshShader = ShaderWrapper(vkd, device, binaries.get("mesh"));
1395 const auto fragShader = ShaderWrapper(vkd, device, binaries.get("frag"));
1396
1397 // Render pass.
1398 const auto renderPass = makeRenderPass(vkd, device, colorFormat, dsFormat);
1399
1400 // Color and depth/stencil buffers.
1401 const VkImageCreateInfo imageCreateInfo =
1402 {
1403 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1404 nullptr, // const void* pNext;
1405 0u, // VkImageCreateFlags flags;
1406 VK_IMAGE_TYPE_2D, // VkImageType imageType;
1407 VK_FORMAT_UNDEFINED, // VkFormat format;
1408 fbExtent, // VkExtent3D extent;
1409 1u, // uint32_t mipLevels;
1410 1u, // uint32_t arrayLayers;
1411 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1412 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1413 0u, // VkImageUsageFlags usage;
1414 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1415 0u, // uint32_t queueFamilyIndexCount;
1416 nullptr, // const uint32_t* pQueueFamilyIndices;
1417 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1418 };
1419
1420 std::unique_ptr<ImageWithMemory> colorAttachment;
1421 {
1422 auto colorAttCreateInfo = imageCreateInfo;
1423 colorAttCreateInfo.format = colorFormat;
1424 colorAttCreateInfo.usage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1425
1426 colorAttachment.reset(new ImageWithMemory(vkd, device, alloc, colorAttCreateInfo, MemoryRequirement::Any));
1427 }
1428
1429 std::unique_ptr<ImageWithMemory> dsAttachment;
1430 {
1431 auto dsAttCreateInfo = imageCreateInfo;
1432 dsAttCreateInfo.format = dsFormat;
1433 dsAttCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1434
1435 dsAttachment.reset(new ImageWithMemory(vkd, device, alloc, dsAttCreateInfo, MemoryRequirement::Any));
1436 }
1437
1438 const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1439 const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
1440 const auto dsSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u);
1441
1442 const auto colorView = makeImageView(vkd, device, colorAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
1443 const auto dsView = makeImageView(vkd, device, dsAttachment->get(), VK_IMAGE_VIEW_TYPE_2D, dsFormat, dsSRR);
1444
1445 // Create verification buffer.
1446 const auto verificationBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(colorTcuFormat) * iExtent.x() * iExtent.y() * iExtent.z());
1447 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1448 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
1449 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
1450 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
1451
1452 // Framebuffer.
1453 const std::vector<VkImageView> fbViews { colorView.get(), dsView.get() };
1454 const auto framebuffer = makeFramebuffer(
1455 vkd, device, renderPass.get(),
1456 static_cast<uint32_t>(fbViews.size()), de::dataOrNull(fbViews),
1457 fbExtent.width, fbExtent.height);
1458
1459 // Viewports and scissors.
1460 const std::vector<VkViewport> viewports (1u, makeViewport(fbExtent));
1461 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent));
1462
1463 // Pipeline.
1464 const VkStencilOpState stencilOpState = {};
1465 const VkPipelineDepthStencilStateCreateInfo dsInfo =
1466 {
1467 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
1468 nullptr, // const void* pNext;
1469 0u, // VkPipelineDepthStencilStateCreateFlags flags;
1470 VK_TRUE, // VkBool32 depthTestEnable;
1471 VK_TRUE, // VkBool32 depthWriteEnable;
1472 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
1473 VK_FALSE, // VkBool32 depthBoundsTestEnable;
1474 VK_FALSE, // VkBool32 stencilTestEnable;
1475 stencilOpState, // VkStencilOpState front;
1476 stencilOpState, // VkStencilOpState back;
1477 0.0f, // float minDepthBounds;
1478 1.0f, // float maxDepthBounds;
1479 };
1480
1481 GraphicsPipelineWrapper pipelineMaker(vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(), m_constructionType);
1482 makeMeshGraphicsPipeline(pipelineMaker, pipelineLayout,
1483 taskShader, meshShader, fragShader,
1484 renderPass.get(), viewports, scissors, 0u, &dsInfo);
1485 const auto pipeline = pipelineMaker.getPipeline();
1486
1487 // Command pool and buffer.
1488 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
1489 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1490 const auto cmdBuffer = cmdBufferPtr.get();
1491
1492 // Draw the triangles in the front, then the triangle in the back.
1493 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
1494 const float clearDepth = 1.0f;
1495 const uint32_t clearStencil = 0u;
1496
1497 const PartialUsageCase::PushConstants pcFront = { PartialUsageCase::kTotalPrimitives, 0.0f, fgRed };
1498 const PartialUsageCase::PushConstants pcBack = { 1u, 0.5f, bgRed };
1499
1500 beginCommandBuffer(vkd, cmdBuffer);
1501 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor, clearDepth, clearStencil);
1502 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
1503
1504 // Front triangles.
1505 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &setFront.get(), 0u, nullptr);
1506 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pcStages, 0u, static_cast<uint32_t>(pcSize), &pcFront);
1507 vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
1508
1509 // Back triangles.
1510 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &setBack.get(), 0u, nullptr);
1511 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pcStages, 0u, static_cast<uint32_t>(pcSize), &pcBack);
1512 vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
1513
1514 endRenderPass(vkd, cmdBuffer);
1515
1516 // Copy color attachment to verification buffer.
1517 const auto colorToTransferBarrier = makeImageMemoryBarrier(
1518 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1519 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1520 colorAttachment->get(), colorSRR);
1521 const auto transferToHostBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1522 const auto copyRegion = makeBufferImageCopy(fbExtent, colorSRL);
1523
1524 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &colorToTransferBarrier);
1525 vkd.cmdCopyImageToBuffer(cmdBuffer, colorAttachment->get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
1526 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &transferToHostBarrier);
1527
1528 endCommandBuffer(vkd, cmdBuffer);
1529 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1530
1531 // Verify color attachment.
1532 invalidateAlloc(vkd, device, verificationBufferAlloc);
1533
1534 tcu::ConstPixelBufferAccess resultAccess (colorTcuFormat, iExtent, verificationBufferData);
1535 auto& log = m_context.getTestContext().getLog();
1536 const tcu::Vec4 errorThreshold (colorThreshold, 0.0f, colorThreshold, 0.0f);
1537
1538 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, errorThreshold, tcu::COMPARE_LOG_ON_ERROR))
1539 TCU_FAIL("Result does not match reference -- check log for details");
1540
1541 return tcu::TestStatus::pass("Pass");
1542 }
1543
1544 // Create a classic and a mesh shading pipeline using graphics pipeline libraries. Both pipelines will use the same fragment shader
1545 // pipeline library, and the fragment shader will use the gl_Layer built-in, which is per-primitive in mesh shaders and per-vertex
1546 // in vertex shaders.
1547 class SharedFragLibraryCase : public vkt::TestCase
1548 {
1549 public:
SharedFragLibraryCase(tcu::TestContext & testCtx,const std::string & name,PipelineConstructionType constructionType)1550 SharedFragLibraryCase (tcu::TestContext& testCtx, const std::string& name, PipelineConstructionType constructionType)
1551 : vkt::TestCase (testCtx, name)
1552 , m_constructionType (constructionType)
1553 {}
~SharedFragLibraryCase(void)1554 virtual ~SharedFragLibraryCase (void) {}
1555
1556 void checkSupport (Context& context) const override;
1557 void initPrograms (vk::SourceCollections& programCollection) const override;
1558 TestInstance* createInstance (Context& context) const override;
1559
1560 static std::vector<tcu::Vec4> getLayerColors (void);
1561
1562 protected:
1563 PipelineConstructionType m_constructionType;
1564 };
1565
1566 class SharedFragLibraryInstance : public vkt::TestInstance
1567 {
1568 public:
SharedFragLibraryInstance(Context & context,PipelineConstructionType constructionType)1569 SharedFragLibraryInstance (Context& context, PipelineConstructionType constructionType)
1570 : vkt::TestInstance (context)
1571 , m_constructionType (constructionType)
1572 {}
~SharedFragLibraryInstance(void)1573 virtual ~SharedFragLibraryInstance (void) {}
1574
1575 tcu::TestStatus iterate (void) override;
1576
1577 protected:
1578 PipelineConstructionType m_constructionType;
1579 };
1580
getLayerColors(void)1581 std::vector<tcu::Vec4> SharedFragLibraryCase::getLayerColors (void)
1582 {
1583 std::vector<tcu::Vec4> layerColors
1584 {
1585 tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
1586 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
1587 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
1588 };
1589
1590 return layerColors;
1591 }
1592
checkSupport(Context & context) const1593 void SharedFragLibraryCase::checkSupport (Context& context) const
1594 {
1595 checkTaskMeshShaderSupportEXT(context, false/*requireTask*/, true/*requireMesh*/);
1596
1597 if (context.getUsedApiVersion() < VK_API_VERSION_1_2)
1598 context.requireDeviceFunctionality("VK_EXT_shader_viewport_index_layer");
1599 else
1600 {
1601 // More fine-grained: we do not need shaderViewportIndex.
1602 const auto& vk12Features = context.getDeviceVulkan12Features();
1603 if (!vk12Features.shaderOutputLayer)
1604 TCU_THROW(NotSupportedError, "shaderOutputLayer not supported");
1605 }
1606
1607 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_constructionType);
1608 }
1609
initPrograms(vk::SourceCollections & programCollection) const1610 void SharedFragLibraryCase::initPrograms (vk::SourceCollections &programCollection) const
1611 {
1612 const auto meshBuildOptions = getMinMeshEXTBuildOptions(programCollection.usedVulkanVersion);
1613
1614 const std::string vtxPositions =
1615 "vec2 positions[3] = vec2[](\n"
1616 " vec2(-1.0, -1.0),\n"
1617 " vec2(-1.0, 3.0),\n"
1618 " vec2(3.0, -1.0)\n"
1619 ");\n"
1620 ;
1621
1622 // The vertex shader emits geometry to layer 1.
1623 std::ostringstream vert;
1624 vert
1625 << "#version 450\n"
1626 << "#extension GL_ARB_shader_viewport_layer_array : enable\n"
1627 << "\n"
1628 << vtxPositions
1629 << "void main ()\n"
1630 << "{\n"
1631 << " gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);\n"
1632 << " gl_Layer = 1;\n"
1633 << "}\n"
1634 ;
1635 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
1636 programCollection.glslSources.add("vert_1_2") << glu::VertexSource(vert.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_5, 0u, true);
1637
1638 // The mesh shader emits geometry to layer 2.
1639 std::ostringstream mesh;
1640 mesh
1641 << "#version 450\n"
1642 << "#extension GL_EXT_mesh_shader : enable\n"
1643 << "\n"
1644 << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
1645 << "layout (triangles) out;\n"
1646 << "layout (max_vertices=3, max_primitives=1) out;\n"
1647 << "\n"
1648 << "perprimitiveEXT out gl_MeshPerPrimitiveEXT {\n"
1649 << " int gl_Layer;\n"
1650 << "} gl_MeshPrimitivesEXT[];\n"
1651 << "\n"
1652 << vtxPositions
1653 << "void main ()\n"
1654 << "{\n"
1655 << " SetMeshOutputsEXT(3u, 1u);\n"
1656 << " for (uint i = 0; i < 3; ++i)\n"
1657 << " gl_MeshVerticesEXT[i].gl_Position = vec4(positions[i], 0.0, 1.0);\n"
1658 << " gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
1659 << " gl_MeshPrimitivesEXT[0].gl_Layer = 2;\n"
1660 << "}\n"
1661 ;
1662 programCollection.glslSources.add("mesh") << glu::MeshSource(mesh.str()) << meshBuildOptions;
1663
1664 // The frag shader uses the gl_Layer built-in to choose an output color.
1665 const auto outColors = getLayerColors();
1666 DE_ASSERT(outColors.size() == 3);
1667
1668 std::ostringstream frag;
1669 frag
1670 << "#version 450\n"
1671 << "\n"
1672 << "layout (location=0) out vec4 outColor;\n"
1673 << "\n"
1674 << "vec4 outColors[3] = vec4[](\n"
1675 << " vec4" << outColors.at(0) << ",\n"
1676 << " vec4" << outColors.at(1) << ",\n"
1677 << " vec4" << outColors.at(2) << "\n"
1678 << ");\n"
1679 << "\n"
1680 << "void main ()\n"
1681 << "{\n"
1682 << " outColor = outColors[gl_Layer];\n"
1683 << "}\n"
1684 ;
1685 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1686 }
1687
createInstance(Context & context) const1688 TestInstance* SharedFragLibraryCase::createInstance (Context& context) const
1689 {
1690 return new SharedFragLibraryInstance(context, m_constructionType);
1691 }
1692
makeLibCreateInfo(VkGraphicsPipelineLibraryFlagsEXT flags,void * pNext=nullptr)1693 VkGraphicsPipelineLibraryCreateInfoEXT makeLibCreateInfo (VkGraphicsPipelineLibraryFlagsEXT flags, void* pNext = nullptr)
1694 {
1695 const VkGraphicsPipelineLibraryCreateInfoEXT createInfo =
1696 {
1697 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT, // VkStructureType sType;
1698 pNext, // void* pNext;
1699 flags, // VkGraphicsPipelineLibraryFlagsEXT flags;
1700 };
1701
1702 return createInfo;
1703 }
1704
iterate(void)1705 tcu::TestStatus SharedFragLibraryInstance::iterate (void)
1706 {
1707 const auto& vkd = m_context.getDeviceInterface();
1708 const auto& device = m_context.getDevice();
1709 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
1710 const auto queue = m_context.getUniversalQueue();
1711 auto& alloc = m_context.getDefaultAllocator();
1712 const auto layerColors = SharedFragLibraryCase::getLayerColors();
1713 const auto& clearColor = layerColors.front();
1714 const auto layerCount = static_cast<uint32_t>(layerColors.size());
1715 const auto fbExtent = makeExtent3D(1u, 1u, 1u);
1716 const tcu::IVec3 iExtent (static_cast<int>(fbExtent.width), static_cast<int>(fbExtent.height), static_cast<int>(layerCount));
1717 const auto fbFormat = VK_FORMAT_R8G8B8A8_UNORM;
1718 const auto tcuFormat = mapVkFormat(fbFormat);
1719 const auto pixelSize = tcu::getPixelSize(tcuFormat);
1720 const auto pixelCount = fbExtent.width * fbExtent.height * layerCount;
1721 const auto fbUsage = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
1722 const bool optimized = (m_constructionType == PIPELINE_CONSTRUCTION_TYPE_LINK_TIME_OPTIMIZED_LIBRARY);
1723 const auto libExtraFlags = (optimized ? VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT : 0);
1724 const auto libCompileFlags = (VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | libExtraFlags);
1725 const auto pipelineLinkFlags = (optimized ? VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT : 0);
1726
1727 // Color buffer.
1728 const VkImageCreateInfo colorBufferCreateInfo =
1729 {
1730 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1731 nullptr, // const void* pNext;
1732 0u, // VkImageCreateFlags flags;
1733 VK_IMAGE_TYPE_2D, // VkImageType imageType;
1734 fbFormat, // VkFormat format;
1735 fbExtent, // VkExtent3D extent;
1736 1u, // uint32_t mipLevels;
1737 layerCount, // uint32_t arrayLayers;
1738 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1739 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1740 fbUsage, // VkImageUsageFlags usage;
1741 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1742 0u, // uint32_t queueFamilyIndexCount;
1743 nullptr, // const uint32_t* pQueueFamilyIndices;
1744 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1745 };
1746
1747 ImageWithMemory colorBuffer (vkd, device, alloc, colorBufferCreateInfo, MemoryRequirement::Any);
1748 const auto colorBufferSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, layerCount);
1749 const auto colorBufferSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, layerCount);
1750 const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D_ARRAY, fbFormat, colorBufferSRR);
1751
1752 // Render pass.
1753 const auto renderPass = makeRenderPass(vkd, device, fbFormat);
1754
1755 // Framebuffer.
1756 const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), fbExtent.width, fbExtent.height, layerCount);
1757
1758 // Verification buffer.
1759 const auto verificationBufferSize = static_cast<VkDeviceSize>(static_cast<int>(pixelCount) * pixelSize);
1760 const auto verificationBufferInfo = makeBufferCreateInfo(verificationBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1761 BufferWithMemory verificationBuffer (vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
1762 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
1763 void* verificationBufferData = verificationBufferAlloc.getHostPtr();
1764
1765 // Pipeline layout (common).
1766 const auto pipelineLayout = makePipelineLayout(vkd, device);
1767
1768 // Shader modules.
1769 const auto& binaries = m_context.getBinaryCollection();
1770 const auto vertModule = createShaderModule(vkd, device, (m_context.contextSupports(VK_API_VERSION_1_2)) ? binaries.get("vert_1_2") : binaries.get("vert"));
1771 const auto meshModule = createShaderModule(vkd, device, binaries.get("mesh"));
1772 const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"));
1773
1774 // Fragment output state library (common).
1775 const VkColorComponentFlags colorComponentFlags = ( VK_COLOR_COMPONENT_R_BIT
1776 | VK_COLOR_COMPONENT_G_BIT
1777 | VK_COLOR_COMPONENT_B_BIT
1778 | VK_COLOR_COMPONENT_A_BIT);
1779 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
1780 {
1781 VK_FALSE, // VkBool32 blendEnable
1782 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
1783 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
1784 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
1785 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
1786 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
1787 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
1788 colorComponentFlags, // VkColorComponentFlags colorWriteMask
1789 };
1790
1791 const VkPipelineColorBlendStateCreateInfo colorBlendState =
1792 {
1793 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1794 nullptr, // const void* pNext;
1795 0u, // VkPipelineColorBlendStateCreateFlags flags;
1796 VK_FALSE, // VkBool32 logicOpEnable;
1797 VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp;
1798 1u, // uint32_t attachmentCount;
1799 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1800 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
1801 };
1802
1803 const VkPipelineMultisampleStateCreateInfo multisampleState =
1804 {
1805 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
1806 nullptr, // const void* pNext
1807 0u, // VkPipelineMultisampleStateCreateFlags flags
1808 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples
1809 VK_FALSE, // VkBool32 sampleShadingEnable
1810 1.0f, // float minSampleShading
1811 nullptr, // const VkSampleMask* pSampleMask
1812 VK_FALSE, // VkBool32 alphaToCoverageEnable
1813 VK_FALSE // VkBool32 alphaToOneEnable
1814 };
1815
1816 const auto fragOutputLibInfo = makeLibCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT);
1817
1818 VkGraphicsPipelineCreateInfo fragOutputInfo = initVulkanStructure();
1819 fragOutputInfo.layout = pipelineLayout.get();
1820 fragOutputInfo.renderPass = renderPass.get();
1821 fragOutputInfo.pColorBlendState = &colorBlendState;
1822 fragOutputInfo.pMultisampleState = &multisampleState;
1823 fragOutputInfo.flags = libCompileFlags;
1824 fragOutputInfo.pNext = &fragOutputLibInfo;
1825
1826 const auto fragOutputLib = createGraphicsPipeline(vkd, device, DE_NULL, &fragOutputInfo);
1827
1828 // Fragment shader lib (shared among the classic and mesh pipelines).
1829 const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = initVulkanStructure();
1830
1831 const VkPipelineShaderStageCreateInfo fragShaderStageCreateInfo =
1832 {
1833 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1834 nullptr, // const void* pNext;
1835 0u, // VkPipelineShaderStageCreateFlags flags;
1836 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
1837 fragModule.get(), // VkShaderModule module;
1838 "main", // const char* pName;
1839 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1840 };
1841
1842 const auto fragShaderLibInfo = makeLibCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT);
1843
1844 VkGraphicsPipelineCreateInfo fragShaderInfo = initVulkanStructure();
1845 fragShaderInfo.layout = pipelineLayout.get();
1846 fragShaderInfo.renderPass = renderPass.get();
1847 fragShaderInfo.pMultisampleState = &multisampleState;
1848 fragShaderInfo.pDepthStencilState = &depthStencilStateCreateInfo;
1849 fragShaderInfo.stageCount = 1u;
1850 fragShaderInfo.pStages = &fragShaderStageCreateInfo;
1851 fragShaderInfo.flags = libCompileFlags;
1852 fragShaderInfo.pNext = &fragShaderLibInfo;
1853
1854 const auto fragShaderLib = createGraphicsPipeline(vkd, device, DE_NULL, &fragShaderInfo);
1855
1856 // Vertex input state (common, but should be unused by the mesh shading pipeline).
1857 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
1858 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = initVulkanStructure();
1859 inputAssemblyStateCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1860 const auto vertexInputLibInfo = makeLibCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT);
1861
1862 VkGraphicsPipelineCreateInfo vertexInputInfo = initVulkanStructure();
1863 vertexInputInfo.layout = pipelineLayout.get();
1864 vertexInputInfo.pVertexInputState = &vertexInputStateCreateInfo;
1865 vertexInputInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo;
1866 vertexInputInfo.flags = libCompileFlags;
1867 vertexInputInfo.pNext = &vertexInputLibInfo;
1868
1869 const auto vertexInputLib = createGraphicsPipeline(vkd, device, DE_NULL, &vertexInputInfo);
1870
1871 // Pre-rasterization shader state: common pieces.
1872 const std::vector<VkViewport> viewports (1u, makeViewport(fbExtent));
1873 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent));
1874
1875 const VkPipelineViewportStateCreateInfo viewportStateCreateInfo =
1876 {
1877 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
1878 nullptr, // const void* pNext;
1879 0u, // VkPipelineViewportStateCreateFlags flags;
1880 static_cast<uint32_t>(viewports.size()), // uint32_t viewportCount;
1881 de::dataOrNull(viewports), // const VkViewport* pViewports;
1882 static_cast<uint32_t>(scissors.size()), // uint32_t scissorCount;
1883 de::dataOrNull(scissors), // const VkRect2D* pScissors;
1884 };
1885
1886 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
1887 {
1888 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
1889 nullptr, // const void* pNext;
1890 0u, // VkPipelineRasterizationStateCreateFlags flags;
1891 VK_FALSE, // VkBool32 depthClampEnable;
1892 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
1893 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
1894 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
1895 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
1896 VK_FALSE, // VkBool32 depthBiasEnable;
1897 0.0f, // float depthBiasConstantFactor;
1898 0.0f, // float depthBiasClamp;
1899 0.0f, // float depthBiasSlopeFactor;
1900 1.0f, // float lineWidth;
1901 };
1902
1903 const auto preRastLibInfo = makeLibCreateInfo(VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT);
1904
1905 VkGraphicsPipelineCreateInfo preRastShaderInfo = initVulkanStructure();
1906 preRastShaderInfo.layout = pipelineLayout.get();
1907 preRastShaderInfo.pViewportState = &viewportStateCreateInfo;
1908 preRastShaderInfo.pRasterizationState = &rasterizationStateCreateInfo;
1909 preRastShaderInfo.renderPass = renderPass.get();
1910 preRastShaderInfo.flags = libCompileFlags;
1911 preRastShaderInfo.pNext = &preRastLibInfo;
1912 preRastShaderInfo.stageCount = 1u;
1913
1914 // Vertex stage info.
1915 const VkPipelineShaderStageCreateInfo vertShaderStageCreateInfo =
1916 {
1917 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1918 nullptr, // const void* pNext;
1919 0u, // VkPipelineShaderStageCreateFlags flags;
1920 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
1921 vertModule.get(), // VkShaderModule module;
1922 "main", // const char* pName;
1923 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1924 };
1925
1926 // Mesh stage info.
1927 const VkPipelineShaderStageCreateInfo meshShaderStageCreateInfo =
1928 {
1929 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1930 nullptr, // const void* pNext;
1931 0u, // VkPipelineShaderStageCreateFlags flags;
1932 VK_SHADER_STAGE_MESH_BIT_EXT, // VkShaderStageFlagBits stage;
1933 meshModule.get(), // VkShaderModule module;
1934 "main", // const char* pName;
1935 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1936 };
1937
1938 // Pre-rasterization shader libs.
1939 preRastShaderInfo.pStages = &vertShaderStageCreateInfo;
1940 const auto preRastClassicLib = createGraphicsPipeline(vkd, device, DE_NULL, &preRastShaderInfo);
1941
1942 preRastShaderInfo.pStages = &meshShaderStageCreateInfo;
1943 const auto preRastMeshLib = createGraphicsPipeline(vkd, device, DE_NULL, &preRastShaderInfo);
1944
1945 // Pipelines.
1946 const std::vector<VkPipeline> classicLibs { vertexInputLib.get(), preRastClassicLib.get(), fragShaderLib.get(), fragOutputLib.get() };
1947 const std::vector<VkPipeline> meshLibs { vertexInputLib.get(), preRastMeshLib.get(), fragShaderLib.get(), fragOutputLib.get() };
1948
1949 const VkPipelineLibraryCreateInfoKHR classicLinkInfo =
1950 {
1951 VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR, // VkStructureType sType;
1952 nullptr, // const void* pNext;
1953 static_cast<uint32_t>(classicLibs.size()), // uint32_t libraryCount;
1954 de::dataOrNull(classicLibs), // const VkPipeline* pLibraries;
1955 };
1956
1957 const VkPipelineLibraryCreateInfoKHR meshLinkInfo =
1958 {
1959 VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR, // VkStructureType sType;
1960 nullptr, // const void* pNext;
1961 static_cast<uint32_t>(meshLibs.size()), // uint32_t libraryCount;
1962 de::dataOrNull(meshLibs), // const VkPipeline* pLibraries;
1963 };
1964
1965 VkGraphicsPipelineCreateInfo classicPipelineCreateInfo = initVulkanStructure();
1966 classicPipelineCreateInfo.flags = pipelineLinkFlags;
1967 classicPipelineCreateInfo.layout = pipelineLayout.get();
1968 classicPipelineCreateInfo.pNext = &classicLinkInfo;
1969
1970 VkGraphicsPipelineCreateInfo meshPipelineCreateInfo = initVulkanStructure();
1971 meshPipelineCreateInfo.flags = pipelineLinkFlags;
1972 meshPipelineCreateInfo.layout = pipelineLayout.get();
1973 meshPipelineCreateInfo.pNext = &meshLinkInfo;
1974
1975 const auto classicPipeline = createGraphicsPipeline(vkd, device, DE_NULL, &classicPipelineCreateInfo);
1976 const auto meshPipeline = createGraphicsPipeline(vkd, device, DE_NULL, &meshPipelineCreateInfo);
1977
1978 // Record commands with both pipelines.
1979 const auto cmdPool = makeCommandPool(vkd, device, queueIndex);
1980 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1981 const auto cmdBuffer = cmdBufferPtr.get();
1982
1983 beginCommandBuffer(vkd, cmdBuffer);
1984
1985 // Draw using both pipelines.
1986 beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0), clearColor);
1987 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, classicPipeline.get());
1988 vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
1989 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, meshPipeline.get());
1990 vkd.cmdDrawMeshTasksEXT(cmdBuffer, 1u, 1u, 1u);
1991 endRenderPass(vkd, cmdBuffer);
1992
1993 // Copy color buffer to verification buffer.
1994 const auto preTransferBarrier = makeImageMemoryBarrier(
1995 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1996 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1997 colorBuffer.get(), colorBufferSRR);
1998
1999 const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
2000
2001 const auto copyRegion = makeBufferImageCopy(fbExtent, colorBufferSRL);
2002
2003 cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preTransferBarrier);
2004 vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
2005 cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &postTransferBarrier);
2006
2007 endCommandBuffer(vkd, cmdBuffer);
2008 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2009
2010 // Validate color buffer.
2011 invalidateAlloc(vkd, device, verificationBufferAlloc);
2012
2013 tcu::ConstPixelBufferAccess resultAccess (tcuFormat, iExtent, verificationBufferData);
2014 auto& log = m_context.getTestContext().getLog();
2015 bool fail = false;
2016
2017 for (int z = 0; z < iExtent.z(); ++z)
2018 {
2019 const auto& expectedColor = layerColors.at(z);
2020 for (int y = 0; y < iExtent.y(); ++y)
2021 for (int x = 0; x < iExtent.x(); ++x)
2022 {
2023 const auto resultColor = resultAccess.getPixel(x, y, z);
2024 if (resultColor != expectedColor)
2025 {
2026 std::ostringstream msg;
2027 msg << "Unexpected color at coordinates (x=" << x << ", y=" << y << ", layer=" << z << "): expected " << expectedColor << " but found " << resultColor;
2028 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
2029 fail = true;
2030 }
2031 }
2032 }
2033
2034 if (fail)
2035 return tcu::TestStatus::fail("Failed; check log for details");
2036 return tcu::TestStatus::pass("Pass");
2037 }
2038
2039 } // anonymous namespace
2040
createMeshShaderSmokeTestsEXT(tcu::TestContext & testCtx)2041 tcu::TestCaseGroup* createMeshShaderSmokeTestsEXT (tcu::TestContext& testCtx)
2042 {
2043 struct
2044 {
2045 PipelineConstructionType constructionType;
2046 const char* name;
2047 } constructionTypes[] =
2048 {
2049 { PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC, "monolithic" },
2050 { PIPELINE_CONSTRUCTION_TYPE_LINK_TIME_OPTIMIZED_LIBRARY, "optimized_lib" },
2051 { PIPELINE_CONSTRUCTION_TYPE_FAST_LINKED_LIBRARY, "fast_lib" },
2052 };
2053
2054 GroupPtr smokeTests (new tcu::TestCaseGroup(testCtx, "smoke"));
2055
2056 for (const auto& constructionCase : constructionTypes)
2057 {
2058 GroupPtr constructionGroup(new tcu::TestCaseGroup(testCtx, constructionCase.name));
2059
2060 const auto& cType = constructionCase.constructionType;
2061
2062 constructionGroup->addChild(new MeshOnlyTriangleCase(testCtx, "mesh_shader_triangle", cType));
2063 constructionGroup->addChild(new MeshOnlyTriangleCase(testCtx, "mesh_shader_triangle_rasterization_disabled", cType, true/*rasterizationDisabled*/));
2064 constructionGroup->addChild(new MeshTaskTriangleCase(testCtx, "mesh_task_shader_triangle", cType));
2065 constructionGroup->addChild(new TaskOnlyTriangleCase(testCtx, "task_only_shader_triangle", cType));
2066
2067 for (int i = 0; i < 2; ++i)
2068 {
2069 const bool compaction = (i == 0);
2070 const std::string nameSuffix = (compaction ? "" : "_without_compaction");
2071 const PartialUsageParams params { cType, compaction };
2072
2073 constructionGroup->addChild(new PartialUsageCase(testCtx, "partial_usage" + nameSuffix, params));
2074 }
2075
2076 addFunctionCaseWithPrograms(constructionGroup.get(), "fullscreen_gradient", checkMeshSupport, initGradientPrograms, testFullscreenGradient, GradientParams(tcu::nothing<FragmentSize>(), cType));
2077 addFunctionCaseWithPrograms(constructionGroup.get(), "fullscreen_gradient_fs2x2", checkMeshSupport, initGradientPrograms, testFullscreenGradient, GradientParams(tcu::just(FragmentSize::SIZE_2X2), cType));
2078 addFunctionCaseWithPrograms(constructionGroup.get(), "fullscreen_gradient_fs2x1", checkMeshSupport, initGradientPrograms, testFullscreenGradient, GradientParams(tcu::just(FragmentSize::SIZE_2X1), cType));
2079
2080 if (cType != PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC)
2081 {
2082 constructionGroup->addChild(new SharedFragLibraryCase(testCtx, "shared_frag_library", cType));
2083 }
2084
2085 smokeTests->addChild(constructionGroup.release());
2086 }
2087
2088 return smokeTests.release();
2089 }
2090
2091 } // MeshShader
2092 } // vkt
2093