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