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