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