1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve Corporation.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Tests with shaders that do not write to the Position built-in.
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineNoPositionTests.hpp"
28 #include "vktTestCase.hpp"
29
30 #include "vkQueryUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkBufferWithMemory.hpp"
37 #include "vktPipelineImageUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkBarrierUtil.hpp"
40 #include "vkBuilderUtil.hpp"
41
42 #include "tcuVector.hpp"
43 #include "tcuTestLog.hpp"
44
45 #include "deUniquePtr.hpp"
46
47 #include <vector>
48 #include <set>
49 #include <sstream>
50 #include <array>
51
52 namespace vkt
53 {
54 namespace pipeline
55 {
56
57 namespace
58 {
59
60 using namespace vk;
61
62 enum ShaderStageBits
63 {
64 STAGE_VERTEX = (1 << 0),
65 STAGE_TESS_CONTROL = (1 << 1),
66 STAGE_TESS_EVALUATION = (1 << 2),
67 STAGE_GEOMETRY = (1 << 3),
68 STAGE_MASK_COUNT = (1 << 4),
69 };
70
71 using ShaderStageFlags = deUint32;
72
73 constexpr deUint32 kStageCount = 4u;
74
75 static_assert((1u << kStageCount) == static_cast<deUint32>(STAGE_MASK_COUNT),
76 "Total stage count does not match stage mask bits");
77
78 struct TestParams
79 {
80 vk::PipelineConstructionType pipelineConstructionType; // The way pipeline is constructed
81 ShaderStageFlags selectedStages; // Stages that will be present in the pipeline.
82 ShaderStageFlags writeStages; // Subset of selectedStages that will write to the Position built-in.
83 deUint32 numViews; // Number of views for multiview.
84 bool explicitDeclarations; // Explicitly declare the input and output blocks or not.
85 bool useSSBO; // Write to an SSBO from the selected stages.
86 bool useDeviceIndexAsViewIndex; // Treat gl_DeviceIndex shader input variable like gl_ViewIndex.
87
88 // Commonly used checks.
tessellationvkt::pipeline::__anon530049140111::TestParams89 bool tessellation (void) const { return (selectedStages & (STAGE_TESS_CONTROL | STAGE_TESS_EVALUATION)); }
geometryvkt::pipeline::__anon530049140111::TestParams90 bool geometry (void) const { return (selectedStages & STAGE_GEOMETRY); }
91 };
92
93 // Generates the combinations list of stage flags for writeStages when a given subset of stages are selected.
getWriteSubCases(ShaderStageFlags selectedStages)94 std::vector<ShaderStageFlags> getWriteSubCases (ShaderStageFlags selectedStages)
95 {
96 std::set<ShaderStageFlags> uniqueCases;
97 for (ShaderStageFlags stages = 0; stages < STAGE_MASK_COUNT; ++stages)
98 uniqueCases.insert(stages & selectedStages);
99 return std::vector<ShaderStageFlags>(begin(uniqueCases), end(uniqueCases));
100 }
101
102 class NoPositionCase : public vkt::TestCase
103 {
104 public:
105 NoPositionCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params);
~NoPositionCase(void)106 virtual ~NoPositionCase (void) {}
107
108 virtual void initPrograms (vk::SourceCollections& programCollection) const;
109 virtual TestInstance* createInstance (Context& context) const;
110 virtual void checkSupport (Context& context) const;
111
getBackGroundColor(void)112 static tcu::Vec4 getBackGroundColor (void) { return tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); }
getImageFormat(void)113 static VkFormat getImageFormat (void) { return VK_FORMAT_R8G8B8A8_UNORM; }
getImageExtent(void)114 static VkExtent3D getImageExtent (void) { return makeExtent3D(64u, 64u, 1u); }
115
116 private:
117 TestParams m_params;
118 };
119
120 class NoPositionInstance : public vkt::TestInstance
121 {
122 public:
123 NoPositionInstance (Context& context, const TestParams& params);
~NoPositionInstance(void)124 virtual ~NoPositionInstance (void) {}
125
126 virtual tcu::TestStatus iterate (void);
127
128 private:
129 TestParams m_params;
130 };
131
NoPositionCase(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)132 NoPositionCase::NoPositionCase (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
133 : vkt::TestCase (testCtx, name)
134 , m_params (params)
135 {
136 DE_ASSERT(params.numViews >= 1u);
137 }
138
initPrograms(vk::SourceCollections & programCollection) const139 void NoPositionCase::initPrograms (vk::SourceCollections& programCollection) const
140 {
141 // Add shaders for the selected stages and write to gl_Position in the subset of stages marked for writing.
142
143 // Optional writes, extensions and declarations.
144 std::string ssboDecl;
145 std::string extensions;
146 std::string vertSSBOWrite;
147 std::string tescSSBOWrite;
148 std::string teseSSBOWrite;
149 std::string geomSSBOWrite;
150
151 const bool multiview = (m_params.numViews > 1u);
152
153 if (m_params.useDeviceIndexAsViewIndex)
154 extensions = "#extension GL_EXT_device_group : require\n";
155 else if (multiview)
156 extensions = "#extension GL_EXT_multiview : require\n";
157
158 if (m_params.useSSBO)
159 {
160 const auto ssboElementCount = kStageCount * m_params.numViews;
161 ssboDecl = "layout (set=0, binding=0, std430) buffer StorageBlock { uint counters[" + de::toString(ssboElementCount) + "]; } ssbo;\n";
162
163 const std::array<std::string*, kStageCount> writeStrings = {{ &vertSSBOWrite, &tescSSBOWrite, &teseSSBOWrite, &geomSSBOWrite }};
164 for (size_t stageNum = 0; stageNum < writeStrings.size(); ++stageNum)
165 {
166 std::ostringstream s;
167 s << " atomicAdd(ssbo.counters[" << stageNum;
168 if (multiview || m_params.useDeviceIndexAsViewIndex)
169 {
170 s << " * " << m_params.numViews << " + ";
171 if (m_params.useDeviceIndexAsViewIndex)
172 s << "gl_DeviceIndex";
173 else
174 s << "gl_ViewIndex";
175 }
176 s << "], 1);\n";
177 s.flush();
178 *writeStrings[stageNum] = s.str();
179 }
180 }
181
182 if (m_params.selectedStages & STAGE_VERTEX)
183 {
184 std::ostringstream vert;
185 vert
186 << "#version 450\n"
187 << extensions
188 << ssboDecl
189 << "layout (location=0) in vec4 in_pos;\n"
190 << (m_params.explicitDeclarations ?
191 "out gl_PerVertex\n"
192 "{\n"
193 " vec4 gl_Position;\n"
194 " float gl_PointSize;\n"
195 " float gl_ClipDistance[];\n"
196 " float gl_CullDistance[];\n"
197 "};\n"
198 : "")
199 << "void main (void)\n"
200 << "{\n"
201 << ((m_params.writeStages & STAGE_VERTEX) ? " gl_Position = in_pos;\n" : "")
202 << vertSSBOWrite
203 << "}\n"
204 ;
205
206 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
207 }
208
209 if (m_params.selectedStages & STAGE_TESS_CONTROL)
210 {
211 std::ostringstream tesc;
212 tesc
213 << "#version 450\n"
214 << extensions
215 << ssboDecl
216 << "layout (vertices = 3) out;\n"
217 << (m_params.explicitDeclarations ?
218 "in gl_PerVertex\n"
219 "{\n"
220 " vec4 gl_Position;\n"
221 " float gl_PointSize;\n"
222 " float gl_ClipDistance[];\n"
223 " float gl_CullDistance[];\n"
224 "} gl_in[gl_MaxPatchVertices];\n"
225 "out gl_PerVertex\n"
226 "{\n"
227 " vec4 gl_Position;\n"
228 " float gl_PointSize;\n"
229 " float gl_ClipDistance[];\n"
230 " float gl_CullDistance[];\n"
231 "} gl_out[];\n"
232 : "")
233 << "void main (void)\n"
234 << "{\n"
235 << " gl_TessLevelInner[0] = 1.0;\n"
236 << " gl_TessLevelInner[1] = 1.0;\n"
237 << " gl_TessLevelOuter[0] = 1.0;\n"
238 << " gl_TessLevelOuter[1] = 1.0;\n"
239 << " gl_TessLevelOuter[2] = 1.0;\n"
240 << " gl_TessLevelOuter[3] = 1.0;\n"
241 << "\n"
242 << ((m_params.writeStages & STAGE_TESS_CONTROL) ? " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" : "")
243 << tescSSBOWrite
244 << "}\n"
245 ;
246
247 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
248 }
249
250 if (m_params.selectedStages & STAGE_TESS_EVALUATION)
251 {
252 std::ostringstream tese;
253 tese
254 << "#version 450\n"
255 << extensions
256 << ssboDecl
257 << "layout (triangles, fractional_odd_spacing, cw) in;\n"
258 << (m_params.explicitDeclarations ?
259 "in gl_PerVertex\n"
260 "{\n"
261 " vec4 gl_Position;\n"
262 " float gl_PointSize;\n"
263 " float gl_ClipDistance[];\n"
264 " float gl_CullDistance[];\n"
265 "} gl_in[gl_MaxPatchVertices];\n"
266 "out gl_PerVertex\n"
267 "{\n"
268 " vec4 gl_Position;\n"
269 " float gl_PointSize;\n"
270 " float gl_ClipDistance[];\n"
271 " float gl_CullDistance[];\n"
272 "};\n"
273 : "")
274 << "void main (void)\n"
275 << "{\n"
276 << ((m_params.writeStages & STAGE_TESS_EVALUATION) ?
277 " gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
278 " (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
279 " (gl_TessCoord.z * gl_in[2].gl_Position);\n"
280 : "")
281 << teseSSBOWrite
282 << "}\n"
283 ;
284
285 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
286 }
287
288 if (m_params.selectedStages & STAGE_GEOMETRY)
289 {
290 std::ostringstream geom;
291 geom
292 << "#version 450\n"
293 << extensions
294 << ssboDecl
295 << "layout (triangles) in;\n"
296 << "layout (triangle_strip, max_vertices=3) out;\n"
297 << (m_params.explicitDeclarations ?
298 "in gl_PerVertex\n"
299 "{\n"
300 " vec4 gl_Position;\n"
301 " float gl_PointSize;\n"
302 " float gl_ClipDistance[];\n"
303 " float gl_CullDistance[];\n"
304 "} gl_in[3];\n"
305 "out gl_PerVertex\n"
306 "{\n"
307 " vec4 gl_Position;\n"
308 " float gl_PointSize;\n"
309 " float gl_ClipDistance[];\n"
310 " float gl_CullDistance[];\n"
311 "};\n"
312 : "")
313 << "void main (void)\n"
314 << "{\n"
315 << " for (int i = 0; i < 3; i++)\n"
316 << " {\n"
317 << ((m_params.writeStages & STAGE_GEOMETRY) ? " gl_Position = gl_in[i].gl_Position;\n" : "")
318 << " EmitVertex();\n"
319 << " }\n"
320 << geomSSBOWrite
321 << "}\n"
322 ;
323
324 programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
325 }
326
327 {
328 const auto backgroundColor = getBackGroundColor();
329
330 std::ostringstream colorStr;
331 colorStr << "vec4(" << backgroundColor.x() << ", " << backgroundColor.y() << ", " << backgroundColor.z() << ", " << backgroundColor.w() << ")";
332
333 std::ostringstream frag;
334 frag
335 << "#version 450\n"
336 << "layout (location=0) out vec4 out_color;\n"
337 << "void main (void)\n"
338 << "{\n"
339 << " out_color = " << colorStr.str() << ";\n"
340 << "}\n"
341 ;
342
343 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
344 }
345 }
346
createInstance(Context & context) const347 TestInstance* NoPositionCase::createInstance (Context& context) const
348 {
349 return new NoPositionInstance (context, m_params);
350 }
351
checkSupport(Context & context) const352 void NoPositionCase::checkSupport (Context& context) const
353 {
354 const auto features = getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
355 const bool hasTess = m_params.tessellation();
356 const bool hasGeom = m_params.geometry();
357
358 if (hasTess && !features.tessellationShader)
359 TCU_THROW(NotSupportedError, "Tessellation shaders not supported");
360
361 if (hasGeom && !features.geometryShader)
362 TCU_THROW(NotSupportedError, "Geometry shaders not supported");
363
364 if (m_params.numViews > 1u)
365 {
366 context.requireDeviceFunctionality("VK_KHR_multiview");
367 const auto& multiviewFeatures = context.getMultiviewFeatures();
368
369 if (!multiviewFeatures.multiview)
370 TCU_THROW(NotSupportedError, "Multiview not supported");
371
372 if (hasTess && !multiviewFeatures.multiviewTessellationShader)
373 TCU_THROW(NotSupportedError, "Multiview not supported with tessellation shaders");
374
375 if (hasGeom && !multiviewFeatures.multiviewGeometryShader)
376 TCU_THROW(NotSupportedError, "Multiview not supported with geometry shaders");
377
378 if (m_params.numViews > context.getMultiviewProperties().maxMultiviewViewCount)
379 TCU_THROW(NotSupportedError, "Not enough views supported");
380 }
381
382 if (m_params.useSSBO)
383 {
384 if (!features.vertexPipelineStoresAndAtomics)
385 TCU_THROW(NotSupportedError, "Vertex pipeline stores and atomics not supported");
386 }
387 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_params.pipelineConstructionType);
388 }
389
NoPositionInstance(Context & context,const TestParams & params)390 NoPositionInstance::NoPositionInstance (Context& context, const TestParams& params)
391 : vkt::TestInstance (context)
392 , m_params (params)
393 {}
394
iterate(void)395 tcu::TestStatus NoPositionInstance::iterate (void)
396 {
397 const auto& vki = m_context.getInstanceInterface();
398 const auto& vkd = m_context.getDeviceInterface();
399 const auto physicalDevice = m_context.getPhysicalDevice();
400 const auto device = m_context.getDevice();
401 const auto queue = m_context.getUniversalQueue();
402 const auto qIndex = m_context.getUniversalQueueFamilyIndex();
403 auto& alloc = m_context.getDefaultAllocator();
404 const auto format = NoPositionCase::getImageFormat();
405 const auto extent = NoPositionCase::getImageExtent();
406 const auto color = NoPositionCase::getBackGroundColor();
407 const VkImageUsageFlags usage = (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
408 const auto viewType = (m_params.numViews > 1u ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
409 const bool tess = m_params.tessellation();
410 VkShaderStageFlags stageFlags = 0u;
411
412 // Shader modules.
413 ShaderWrapper vert;
414 ShaderWrapper tesc;
415 ShaderWrapper tese;
416 ShaderWrapper geom;
417 ShaderWrapper frag;
418
419 if (m_params.selectedStages & STAGE_VERTEX)
420 {
421 vert = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
422 stageFlags |= VK_SHADER_STAGE_VERTEX_BIT;
423 }
424 if (m_params.selectedStages & STAGE_TESS_CONTROL)
425 {
426 tesc = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
427 stageFlags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
428 }
429 if (m_params.selectedStages & STAGE_TESS_EVALUATION)
430 {
431 tese = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
432 stageFlags |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
433 }
434 if (m_params.selectedStages & STAGE_GEOMETRY)
435 {
436 geom = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
437 stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;
438 }
439
440 frag = ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
441 stageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT;
442
443 // Color attachment.
444 const VkImageCreateInfo colorImageInfo =
445 {
446 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
447 nullptr, // const void* pNext;
448 0u, // VkImageCreateFlags flags;
449 VK_IMAGE_TYPE_2D, // VkImageType imageType;
450 format, // VkFormat format;
451 extent, // VkExtent3D extent;
452 1u, // deUint32 mipLevels;
453 m_params.numViews, // deUint32 arrayLayers;
454 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
455 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
456 usage, // VkImageUsageFlags usage;
457 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
458 0u, // deUint32 queueFamilyIndexCount;
459 nullptr, // const deUint32* pQueueFamilyIndices;
460 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
461 };
462 ImageWithMemory colorImage (vkd, device, alloc, colorImageInfo, MemoryRequirement::Any);
463
464 const auto subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_params.numViews);
465 const auto colorImageView = makeImageView(vkd, device, colorImage.get(), viewType, format, subresourceRange);
466
467 // Vertices and vertex buffer.
468 std::vector<tcu::Vec4> vertices =
469 {
470 tcu::Vec4( 0.0f, -0.5f, 0.0f, 1.0f),
471 tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f),
472 tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f),
473 };
474
475 const auto vertexBufferSize = static_cast<VkDeviceSize>(vertices.size() * sizeof(decltype(vertices)::value_type));
476 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
477 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
478 BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
479
480 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
481 void* vertexBufferPtr = vertexBufferAlloc.getHostPtr();
482 deMemcpy(vertexBufferPtr, vertices.data(), static_cast<size_t>(vertexBufferSize));
483 flushAlloc(vkd, device, vertexBufferAlloc);
484
485 // Render pass.
486 const VkAttachmentDescription colorAttachment =
487 {
488 0u, // VkAttachmentDescriptionFlags flags;
489 format, // VkFormat format;
490 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
491 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
492 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
493 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
494 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
495 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
496 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
497 };
498
499 const VkAttachmentReference colorAttachmentReference =
500 {
501 0u, // deUint32 attachment;
502 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
503 };
504
505 const VkSubpassDescription subpassDescription =
506 {
507 0u, // VkSubpassDescriptionFlags flags;
508 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
509 0u, // deUint32 inputAttachmentCount;
510 nullptr, // const VkAttachmentReference* pInputAttachments;
511 1u, // deUint32 colorAttachmentCount;
512 &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
513 0u, // const VkAttachmentReference* pResolveAttachments;
514 nullptr, // const VkAttachmentReference* pDepthStencilAttachment;
515 0u, // deUint32 preserveAttachmentCount;
516 nullptr, // const deUint32* pPreserveAttachments;
517 };
518
519 de::MovePtr<VkRenderPassMultiviewCreateInfo> multiviewInfo;
520 deUint32 viewMask = 0u;
521 deUint32 correlationMask = 0u;
522
523 if (m_params.numViews > 1u)
524 {
525 for (deUint32 viewIdx = 0u; viewIdx < m_params.numViews; ++viewIdx)
526 {
527 viewMask |= (1 << viewIdx);
528 correlationMask |= (1 << viewIdx);
529 }
530
531 multiviewInfo = de::MovePtr<VkRenderPassMultiviewCreateInfo>(new VkRenderPassMultiviewCreateInfo
532 {
533 VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, // VkStructureType sType;
534 nullptr, // const void* pNext;
535 1u, // deUint32 subpassCount;
536 &viewMask, // const deUint32* pViewMasks;
537 0u, // deUint32 dependencyCount;
538 nullptr, // const deInt32* pViewOffsets;
539 1u, // deUint32 correlationMaskCount;
540 &correlationMask, // const deUint32* pCorrelationMasks;
541 });
542 }
543
544 const VkRenderPassCreateInfo renderPassInfo =
545 {
546 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
547 (m_params.numViews > 1u)
548 ? multiviewInfo.get()
549 : nullptr, // const void* pNext;
550 0u, // VkRenderPassCreateFlags flags;
551 1u, // deUint32 attachmentCount;
552 &colorAttachment, // const VkAttachmentDescription* pAttachments;
553 1u, // deUint32 subpassCount;
554 &subpassDescription, // const VkSubpassDescription* pSubpasses;
555 0u, // deUint32 dependencyCount;
556 nullptr, // const VkSubpassDependency* pDependencies;
557 };
558
559 RenderPassWrapper renderPass (m_params.pipelineConstructionType, vkd, device, &renderPassInfo);
560
561 // Framebuffer.
562 renderPass.createFramebuffer(vkd, device, *colorImage, colorImageView.get(), extent.width, extent.height);
563
564 // Descriptor set layout and pipeline layout.
565 DescriptorSetLayoutBuilder layoutBuilder;
566 if (m_params.useSSBO)
567 {
568 layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageFlags);
569 }
570 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
571 const PipelineLayoutWrapper pipelineLayout (m_params.pipelineConstructionType, vkd, device, descriptorSetLayout.get());
572
573 // Pipeline.
574 const std::vector<VkViewport> viewports { makeViewport(extent) };
575 const std::vector<VkRect2D> scissors { makeRect2D(extent) };
576
577 const auto primitiveTopology (tess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
578 const VkPipelineCreateFlags createFlags = m_params.useDeviceIndexAsViewIndex ? VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT : VkPipelineCreateFlagBits(0u);
579 GraphicsPipelineWrapper pipeline (vki, vkd, physicalDevice, device, m_context.getDeviceExtensions(),
580 m_params.pipelineConstructionType, createFlags);
581 pipeline.setDefaultTopology(primitiveTopology)
582 .setDefaultRasterizationState()
583 .setDefaultMultisampleState()
584 .setDefaultDepthStencilState()
585 .setDefaultColorBlendState()
586 .setupVertexInputState()
587 .setupPreRasterizationShaderState(viewports,
588 scissors,
589 pipelineLayout,
590 *renderPass,
591 0u,
592 vert,
593 DE_NULL,
594 tesc,
595 tese,
596 geom)
597 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, frag)
598 .setupFragmentOutputState(*renderPass)
599 .setMonolithicPipelineLayout(pipelineLayout)
600 .buildPipeline();
601
602 // Descriptor set and output SSBO if needed.
603 Move<VkDescriptorPool> descriptorPool;
604 Move<VkDescriptorSet> descriptorSet;
605 de::MovePtr<BufferWithMemory> ssboBuffer;
606 const auto ssboElementCount = kStageCount * m_params.numViews;
607 const auto ssboBufferSize = static_cast<VkDeviceSize>(ssboElementCount * sizeof(deUint32));
608
609 if (m_params.useSSBO)
610 {
611 // Output SSBO.
612 const auto ssboBufferInfo = makeBufferCreateInfo(ssboBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
613 ssboBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, ssboBufferInfo, MemoryRequirement::HostVisible));
614 auto& ssboBufferAlloc = ssboBuffer->getAllocation();
615
616 deMemset(ssboBufferAlloc.getHostPtr(), 0, static_cast<size_t>(ssboBufferSize));
617 flushAlloc(vkd, device, ssboBufferAlloc);
618
619 // Descriptor pool.
620 DescriptorPoolBuilder poolBuilder;
621 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
622 descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
623
624 // Descriptor set.
625 descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
626 const auto ssboWriteInfo = makeDescriptorBufferInfo(ssboBuffer->get(), 0ull, ssboBufferSize);
627 DescriptorSetUpdateBuilder updateBuilder;
628 updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboWriteInfo);
629 updateBuilder.update(vkd, device);
630 }
631
632 // Output verification buffer.
633 const auto tcuFormat = mapVkFormat(format);
634 const auto pixelSize = static_cast<deUint32>(tcu::getPixelSize(tcuFormat));
635 const auto layerPixels = extent.width * extent.height;
636 const auto layerBytes = layerPixels * pixelSize;
637 const auto totalBytes = layerBytes * m_params.numViews;
638
639 const auto verificationBufferInfo = makeBufferCreateInfo(totalBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
640 BufferWithMemory verificationBuffer(vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
641
642 // Command pool and buffer.
643 const auto cmdPool = makeCommandPool(vkd, device, qIndex);
644 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
645 const auto cmdBuffer = cmdBufferPtr.get();
646
647 // Render triangle.
648 beginCommandBuffer(vkd, cmdBuffer);
649 renderPass.begin(vkd, cmdBuffer, scissors.front(), color);
650 pipeline.bind(cmdBuffer);
651 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
652 if (m_params.useSSBO)
653 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
654 vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
655 renderPass.end(vkd, cmdBuffer);
656
657 // Copy output image to verification buffer.
658 const auto preTransferBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), subresourceRange);
659 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preTransferBarrier);
660
661 const auto subresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, m_params.numViews);
662 const VkBufferImageCopy copyRegion =
663 {
664 0ull, // VkDeviceSize bufferOffset;
665 0u, // deUint32 bufferRowLength;
666 0u, // deUint32 bufferImageHeight;
667 subresourceLayers, // VkImageSubresourceLayers imageSubresource;
668 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
669 extent, // VkExtent3D imageExtent;
670 };
671 vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, ©Region);
672
673 const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
674 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postTransferBarrier, 0u, nullptr, 0u, nullptr);
675
676 // Output SSBO to host barrier.
677 if (m_params.useSSBO)
678 {
679 const auto ssboBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
680 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &ssboBarrier, 0u, nullptr, 0u, nullptr);
681 }
682
683 // Submit commands.
684 endCommandBuffer(vkd, cmdBuffer);
685 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
686
687 // Verify the image has the background color.
688 auto& verificationBufferAlloc = verificationBuffer.getAllocation();
689 auto verificationBufferPtr = reinterpret_cast<const char*>(verificationBufferAlloc.getHostPtr());
690 invalidateAlloc(vkd, device, verificationBufferAlloc);
691
692 const auto iWidth = static_cast<int>(extent.width);
693 const auto iHeight = static_cast<int>(extent.height);
694 const auto iDepth = static_cast<int>(extent.depth);
695
696 for (deUint32 layer = 0u; layer < m_params.numViews; ++layer)
697 {
698 const auto pixels = tcu::ConstPixelBufferAccess(tcuFormat, iWidth, iHeight, iDepth, reinterpret_cast<const void*>(verificationBufferPtr + layer * layerBytes));
699
700 for (int y = 0; y < iHeight; ++y)
701 for (int x = 0; x < iWidth; ++x)
702 {
703 const auto pixel = pixels.getPixel(x, y);
704 if (pixel != color)
705 {
706 std::ostringstream msg;
707 msg << "Unexpected color found at pixel (" << x << ", " << y << ") in layer " << layer;
708
709 auto& log = m_context.getTestContext().getLog();
710 log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
711 log << tcu::TestLog::Image("Result", "Result Image", pixels);
712 TCU_FAIL(msg.str());
713 }
714 }
715 }
716
717 // Verify SSBO if used.
718 if (m_params.useSSBO)
719 {
720 // Get stored counters.
721 const auto ssboBufferSizeSz = static_cast<size_t>(ssboBufferSize);
722 auto& ssboAlloc = ssboBuffer->getAllocation();
723 invalidateAlloc(vkd, device, ssboAlloc);
724
725 std::vector<deUint32> ssboCounters(ssboElementCount);
726 DE_ASSERT(ssboBufferSizeSz == ssboCounters.size() * sizeof(decltype(ssboCounters)::value_type));
727 deMemcpy(ssboCounters.data(), ssboAlloc.getHostPtr(), ssboBufferSizeSz);
728
729 // Minimum accepted counter values.
730 // Vertex, Tessellation Control, Tesellation Evaluation, Geometry.
731 deUint32 expectedCounters[kStageCount] = { 3u, 3u, 3u, 1u };
732
733 // Verify.
734 for (deUint32 stageIdx = 0u; stageIdx < kStageCount; ++stageIdx)
735 for (deUint32 viewIdx = 0u; viewIdx < m_params.numViews; ++viewIdx)
736 {
737 // If the stage is not selected, the expected value is exactly zero. Otherwise, it must be at least as expectedCounters.
738 const deUint32 minVal = ((m_params.selectedStages & (1u << stageIdx)) ? expectedCounters[stageIdx] : 0u);
739 const deUint32 storedVal = ssboCounters[stageIdx * m_params.numViews + viewIdx];
740 const bool ok = ((minVal == 0u)
741 ? true /* continue */
742 : (storedVal == minVal)
743 ? true
744 // All shaders must process at least gl_ViewIndex|gl_DeviceIndex times.
745 : ((storedVal % minVal) == 0u));
746 if (!ok)
747 {
748 const char* stageNames[kStageCount] =
749 {
750 "vertex",
751 "tessellation control",
752 "tessellation evaluation",
753 "geometry",
754 };
755
756 std::ostringstream msg;
757 msg << "Unexpected SSBO counter value in view " << viewIdx
758 << " for the " << stageNames[stageIdx] << " shader:"
759 << " got " << storedVal << " but expected " << minVal;
760 TCU_FAIL(msg.str());
761 }
762 }
763 }
764
765 return tcu::TestStatus::pass("Pass");
766 }
767
768 } // anonymous
769
createNoPositionTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)770 tcu::TestCaseGroup* createNoPositionTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
771 {
772 // Tests with shaders that do not write to the Position built-in
773 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "no_position"));
774
775 for (int aux = 0; aux < 2; ++aux)
776 {
777 const bool explicitDeclarations = (aux == 1);
778 const std::string declGroupName (explicitDeclarations ? "explicit_declarations" : "implicit_declarations");
779 de::MovePtr<tcu::TestCaseGroup> declGroup (new tcu::TestCaseGroup(testCtx, declGroupName.c_str()));
780
781 for (int aux2 = 0; aux2 < 2; ++aux2)
782 {
783 const bool useSSBO = (aux2 == 1);
784 const std::string ssboGroupName (useSSBO ? "ssbo_writes" : "basic");
785 de::MovePtr<tcu::TestCaseGroup> ssboGroup (new tcu::TestCaseGroup(testCtx, ssboGroupName.c_str()));
786
787 const uint32_t maxTestedViewCount = useSSBO ? 3u : 2u;
788 for (deUint32 viewCount = 1u; viewCount <= maxTestedViewCount; ++viewCount)
789 {
790 auto makeViewGroupName = [&]() -> std::string
791 {
792 switch (viewCount)
793 {
794 case 1u: return "single_view";
795 case 2u: return "multiview";
796 case 3u: return "device_index_as_view_index";
797 }
798 DE_ASSERT(false);
799 return std::string();
800 };
801
802 const std::string viewGroupName = makeViewGroupName();
803 const bool useDeviceIndexAsViewIndex = (3u == viewCount);
804
805 // Shader objects do not support multiview
806 if (viewCount != 1 && vk::isConstructionTypeShaderObject(pipelineConstructionType))
807 continue;
808 de::MovePtr<tcu::TestCaseGroup> viewGroup(new tcu::TestCaseGroup(testCtx, viewGroupName.c_str()));
809
810 for (ShaderStageFlags stages = 0u; stages < STAGE_MASK_COUNT; ++stages)
811 {
812 // Vertex must always be present.
813 if (! (stages & STAGE_VERTEX))
814 continue;
815
816 // Tessellation stages must both be present or none must be.
817 if (static_cast<bool>(stages & STAGE_TESS_CONTROL) != static_cast<bool>(stages & STAGE_TESS_EVALUATION))
818 continue;
819
820 const auto writeMaskCases = getWriteSubCases(stages);
821 for (const auto writeMask : writeMaskCases)
822 {
823 std::string testName;
824 if (stages & STAGE_VERTEX) testName += (testName.empty() ? "" : "_") + std::string("v") + ((writeMask & STAGE_VERTEX) ? "1" : "0");
825 if (stages & STAGE_TESS_CONTROL) testName += (testName.empty() ? "" : "_") + std::string("c") + ((writeMask & STAGE_TESS_CONTROL) ? "1" : "0");
826 if (stages & STAGE_TESS_EVALUATION) testName += (testName.empty() ? "" : "_") + std::string("e") + ((writeMask & STAGE_TESS_EVALUATION) ? "1" : "0");
827 if (stages & STAGE_GEOMETRY) testName += (testName.empty() ? "" : "_") + std::string("g") + ((writeMask & STAGE_GEOMETRY) ? "1" : "0");
828
829 TestParams params{};
830 params.pipelineConstructionType = pipelineConstructionType;
831 params.selectedStages = stages;
832 params.writeStages = writeMask;
833 params.numViews = viewCount;
834 params.explicitDeclarations = explicitDeclarations;
835 params.useSSBO = useSSBO;
836 params.useDeviceIndexAsViewIndex = useDeviceIndexAsViewIndex;
837
838 viewGroup->addChild(new NoPositionCase(testCtx, testName, params));
839 }
840 }
841
842 ssboGroup->addChild(viewGroup.release());
843 }
844
845 declGroup->addChild(ssboGroup.release());
846 }
847
848 group->addChild(declGroup.release());
849 }
850
851 return group.release();
852 }
853
854 } // pipeline
855 } // vkt
856