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 Ray Tracing barrier tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktRayTracingBarrierTests.hpp"
26 #include "vktTestCase.hpp"
27
28 #include "vkDefs.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vkRayTracingUtil.hpp"
31 #include "vkObjUtil.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkCmdUtil.hpp"
38
39 #include "deUniquePtr.hpp"
40
41 #include <string>
42 #include <sstream>
43 #include <memory>
44 #include <numeric>
45 #include <vector>
46 #include <algorithm>
47
48 namespace vkt
49 {
50 namespace RayTracing
51 {
52
53 namespace
54 {
55
56 using namespace vk;
57
58 constexpr deUint32 kBufferElements = 1024u;
59 constexpr deUint32 kBufferSize = kBufferElements * static_cast<deUint32>(sizeof(tcu::UVec4)); // std140
60 constexpr deUint32 kBufferSize430 = kBufferElements * static_cast<deUint32>(sizeof(deUint32)); // std430
61 constexpr deUint32 kValuesOffset = 2048u;
62 constexpr deUint32 kImageDim = 32u; // So that kImageDim*kImageDim == kBufferElements.
63 constexpr VkFormat kImageFormat = VK_FORMAT_R32_UINT; // So that each pixel has the same size as a deUint32.
64 const auto kImageExtent = makeExtent3D(kImageDim, kImageDim, 1u);
65 const std::vector<tcu::Vec4> kFullScreenQuad =
66 {
67 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
68 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
69 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
70 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
71 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
72 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
73 };
74
75
76 enum class Stage
77 {
78 HOST = 0,
79 TRANSFER,
80 RAYGEN,
81 INTERSECT,
82 ANY_HIT,
83 CLOSEST_HIT,
84 MISS,
85 CALLABLE,
86 COMPUTE,
87 FRAGMENT,
88 };
89
getOptimalReadLayout(Stage stage)90 VkImageLayout getOptimalReadLayout (Stage stage)
91 {
92 VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
93
94 switch (stage)
95 {
96 case Stage::HOST:
97 break; // Images will not be read directly from the host.
98 case Stage::TRANSFER:
99 layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
100 break;
101 case Stage::RAYGEN:
102 case Stage::INTERSECT:
103 case Stage::ANY_HIT:
104 case Stage::CLOSEST_HIT:
105 case Stage::MISS:
106 case Stage::CALLABLE:
107 case Stage::COMPUTE:
108 case Stage::FRAGMENT:
109 layout = VK_IMAGE_LAYOUT_GENERAL;
110 break;
111 default:
112 DE_ASSERT(false);
113 break;
114 }
115
116 return layout;
117 }
118
getPipelineStage(Stage stage)119 VkPipelineStageFlagBits getPipelineStage (Stage stage)
120 {
121 VkPipelineStageFlagBits bits = VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM;
122
123 switch (stage)
124 {
125 case Stage::HOST:
126 bits = VK_PIPELINE_STAGE_HOST_BIT;
127 break;
128 case Stage::TRANSFER:
129 bits = VK_PIPELINE_STAGE_TRANSFER_BIT;
130 break;
131 case Stage::RAYGEN:
132 case Stage::INTERSECT:
133 case Stage::ANY_HIT:
134 case Stage::CLOSEST_HIT:
135 case Stage::MISS:
136 case Stage::CALLABLE:
137 bits = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
138 break;
139 case Stage::COMPUTE:
140 bits = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
141 break;
142 case Stage::FRAGMENT:
143 bits = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
144 break;
145 default:
146 DE_ASSERT(false);
147 break;
148 }
149
150 return bits;
151 }
152
getWriterAccessFlag(Stage stage)153 VkAccessFlagBits getWriterAccessFlag (Stage stage)
154 {
155 VkAccessFlagBits bits = VK_ACCESS_FLAG_BITS_MAX_ENUM;
156
157 switch (stage)
158 {
159 case Stage::HOST:
160 bits = VK_ACCESS_HOST_WRITE_BIT;
161 break;
162 case Stage::TRANSFER:
163 bits = VK_ACCESS_TRANSFER_WRITE_BIT;
164 break;
165 case Stage::RAYGEN:
166 case Stage::INTERSECT:
167 case Stage::ANY_HIT:
168 case Stage::CLOSEST_HIT:
169 case Stage::MISS:
170 case Stage::CALLABLE:
171 case Stage::COMPUTE:
172 case Stage::FRAGMENT:
173 bits = VK_ACCESS_SHADER_WRITE_BIT;
174 break;
175 default:
176 DE_ASSERT(false);
177 break;
178 }
179
180 return bits;
181 }
182
getReaderAccessFlag(Stage stage,VkDescriptorType resourceType)183 VkAccessFlagBits getReaderAccessFlag (Stage stage, VkDescriptorType resourceType)
184 {
185 VkAccessFlagBits bits = VK_ACCESS_FLAG_BITS_MAX_ENUM;
186
187 switch (stage)
188 {
189 case Stage::HOST:
190 bits = VK_ACCESS_HOST_READ_BIT;
191 break;
192 case Stage::TRANSFER:
193 bits = VK_ACCESS_TRANSFER_READ_BIT;
194 break;
195 case Stage::RAYGEN:
196 case Stage::INTERSECT:
197 case Stage::ANY_HIT:
198 case Stage::CLOSEST_HIT:
199 case Stage::MISS:
200 case Stage::CALLABLE:
201 case Stage::COMPUTE:
202 case Stage::FRAGMENT:
203 bits = ((resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ? VK_ACCESS_UNIFORM_READ_BIT : VK_ACCESS_SHADER_READ_BIT);
204 break;
205 default:
206 DE_ASSERT(false);
207 break;
208 }
209
210 return bits;
211 }
212
213 // Translate a stage to the corresponding single stage flag.
getShaderStageFlagBits(Stage stage)214 VkShaderStageFlagBits getShaderStageFlagBits (Stage stage)
215 {
216 VkShaderStageFlagBits bits = VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM;
217
218 switch (stage)
219 {
220 case Stage::RAYGEN: bits = VK_SHADER_STAGE_RAYGEN_BIT_KHR; break;
221 case Stage::INTERSECT: bits = VK_SHADER_STAGE_INTERSECTION_BIT_KHR; break;
222 case Stage::ANY_HIT: bits = VK_SHADER_STAGE_ANY_HIT_BIT_KHR; break;
223 case Stage::CLOSEST_HIT: bits = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; break;
224 case Stage::MISS: bits = VK_SHADER_STAGE_MISS_BIT_KHR; break;
225 case Stage::CALLABLE: bits = VK_SHADER_STAGE_CALLABLE_BIT_KHR; break;
226 case Stage::COMPUTE: bits = VK_SHADER_STAGE_COMPUTE_BIT; break;
227 case Stage::FRAGMENT: bits = VK_SHADER_STAGE_FRAGMENT_BIT; break;
228 default: DE_ASSERT(false); break;
229 }
230
231 return bits;
232 }
233
234 // Gets shader stage flags that will be used when choosing a given stage.
getStageFlags(Stage stage)235 VkShaderStageFlags getStageFlags (Stage stage)
236 {
237 VkShaderStageFlags flags = 0u;
238
239 switch (stage)
240 {
241 case Stage::HOST: break;
242 case Stage::TRANSFER: break;
243 case Stage::RAYGEN: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR); break;
244 case Stage::INTERSECT: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR); break;
245 case Stage::ANY_HIT: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR); break;
246 case Stage::CLOSEST_HIT: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); break;
247 case Stage::MISS: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR); break;
248 case Stage::CALLABLE: flags |= (VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CALLABLE_BIT_KHR); break;
249 case Stage::COMPUTE: flags |= (VK_SHADER_STAGE_COMPUTE_BIT); break;
250 case Stage::FRAGMENT: flags |= (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); break;
251 default: DE_ASSERT(false); break;
252 }
253
254 return flags;
255 }
256
isRayTracingStage(Stage stage)257 bool isRayTracingStage (Stage stage)
258 {
259 bool isRT = false;
260
261 switch (stage)
262 {
263 case Stage::HOST:
264 case Stage::TRANSFER:
265 case Stage::COMPUTE:
266 case Stage::FRAGMENT:
267 break;
268
269 case Stage::RAYGEN:
270 case Stage::INTERSECT:
271 case Stage::ANY_HIT:
272 case Stage::CLOSEST_HIT:
273 case Stage::MISS:
274 case Stage::CALLABLE:
275 isRT = true;
276 break;
277
278 default:
279 DE_ASSERT(false);
280 break;
281 }
282
283 return isRT;
284 }
285
286 enum class BarrierType
287 {
288 GENERAL = 0,
289 SPECIFIC = 1,
290 };
291
292 struct TestParams
293 {
294 VkDescriptorType resourceType;
295 Stage writerStage;
296 Stage readerStage;
297 BarrierType barrierType;
298
TestParamsvkt::RayTracing::__anon2c1cb5820111::TestParams299 TestParams (VkDescriptorType resourceType_, Stage writerStage_, Stage readerStage_, BarrierType barrierType_)
300 : resourceType (resourceType_)
301 , writerStage (writerStage_)
302 , readerStage (readerStage_)
303 , barrierType (barrierType_)
304 {
305 DE_ASSERT(resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
306 resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
307 resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
308 }
309 };
310
resourceNeedsHostVisibleMemory(const TestParams & params)311 bool resourceNeedsHostVisibleMemory (const TestParams& params)
312 {
313 return (params.writerStage == Stage::HOST || params.readerStage == Stage::HOST);
314 }
315
needsAccelerationStructure(Stage stage)316 bool needsAccelerationStructure (Stage stage)
317 {
318 bool needed;
319
320 switch (stage)
321 {
322 case Stage::INTERSECT:
323 case Stage::ANY_HIT:
324 case Stage::CLOSEST_HIT:
325 case Stage::MISS:
326 case Stage::CALLABLE:
327 needed = true;
328 break;
329 default:
330 needed = false;
331 break;
332 }
333
334 return needed;
335 }
336
337 // The general idea is having a resource like a buffer or image that is generated from a given pipeline stage (including host,
338 // transfer and all ray shader stages) and read from another stage, using a barrier to synchronize access to the resource. Read
339 // values are copied to an output host-visible buffer for verification.
340
341 class BarrierTestCase : public vkt::TestCase
342 {
343 public:
344 BarrierTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& testParams);
~BarrierTestCase(void)345 virtual ~BarrierTestCase (void) {}
346
347 virtual void initPrograms (SourceCollections& programCollection) const;
348 virtual TestInstance* createInstance (Context& context) const;
349 virtual void checkSupport (Context& context) const;
350
351 private:
352 TestParams m_params;
353 };
354
355 class BarrierTestInstance : public vkt::TestInstance
356 {
357 public:
358 BarrierTestInstance (Context& context, const TestParams& testParams);
~BarrierTestInstance(void)359 virtual ~BarrierTestInstance (void) {}
360
361 virtual tcu::TestStatus iterate (void);
362
363 private:
364 TestParams m_params;
365 };
366
BarrierTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & testParams)367 BarrierTestCase::BarrierTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& testParams)
368 : vkt::TestCase (testCtx, name, description)
369 , m_params (testParams)
370 {
371 }
372
initPrograms(SourceCollections & programCollection) const373 void BarrierTestCase::initPrograms (SourceCollections& programCollection) const
374 {
375 const auto& wstage = m_params.writerStage;
376 const auto& rstage = m_params.readerStage;
377 const bool readNeedAS = needsAccelerationStructure(rstage);
378 const deUint32 readerVerifierBinding = (readNeedAS ? 2u : 1u); // 0 is the barrier resource, 1 may be the AS.
379 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_4, 0u, true);
380 const std::string valStatement = " const uint val = id1d + " + de::toString(kValuesOffset) + ";\n";
381 const std::string readerSaveStatement = " verificationBuffer.data[id1d] = val;\n";
382
383 // Common for all ray tracing shaders.
384 std::stringstream rayTracingIdsStream;
385 rayTracingIdsStream
386 << " const uint id1d = gl_LaunchIDEXT.y * " << kImageDim << " + gl_LaunchIDEXT.x;\n"
387 << " const ivec2 id2d = ivec2(gl_LaunchIDEXT.xy);\n"
388 ;
389 const std::string rayTracingIds = rayTracingIdsStream.str();
390
391 // Common for all compute shaders.
392 std::stringstream computeIdsStream;
393 computeIdsStream
394 << " const uint id1d = gl_GlobalInvocationID.y * " << kImageDim << " + gl_GlobalInvocationID.x;\n"
395 << " const ivec2 id2d = ivec2(gl_GlobalInvocationID.xy);\n"
396 ;
397 const std::string computeIds = computeIdsStream.str();
398
399 // Common for all fragment shaders.
400 std::stringstream fragIdsStream;
401 fragIdsStream
402 << " const uint id1d = uint(gl_FragCoord.y) * " << kImageDim << " + uint(gl_FragCoord.x);\n"
403 << " const ivec2 id2d = ivec2(gl_FragCoord.xy);\n"
404 ;
405 const std::string fragIds = fragIdsStream.str();
406
407 // Statements to declare the resource in the writer and reader sides, as well as writing to and reading from it.
408 std::stringstream writerResourceDecl;
409 std::stringstream readerResourceDecl;
410 std::stringstream writeStatement;
411 std::stringstream readStatement;
412
413 switch (m_params.resourceType)
414 {
415 case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
416 writerResourceDecl << "layout(set = 0, binding = 0, std140) uniform ubodef { uint data[" << kBufferElements << "]; } ubo;\n";
417 readerResourceDecl << "layout(set = 0, binding = 0, std140) uniform ubodef { uint data[" << kBufferElements << "]; } ubo;\n";
418 // No writes can happen from shaders in this case.
419 readStatement << " const uint val = ubo.data[id1d];\n";
420 break;
421 case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
422 writerResourceDecl << "layout(set = 0, binding = 0, std140) buffer ssbodef { uint data[" << kBufferElements << "]; } ssbo;\n";
423 readerResourceDecl << "layout(set = 0, binding = 0, std140) buffer ssbodef { uint data[" << kBufferElements << "]; } ssbo;\n";
424 writeStatement << " ssbo.data[id1d] = val;\n";
425 readStatement << " const uint val = ssbo.data[id1d];\n";
426 break;
427 case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
428 writerResourceDecl << "layout(r32ui, set = 0, binding = 0) uniform uimage2D simage;\n";
429 readerResourceDecl << "layout(r32ui, set = 0, binding = 0) uniform uimage2D simage;\n";
430 writeStatement << " imageStore(simage, id2d, uvec4(val, 0, 0, 0));\n";
431 readStatement << " const uint val = imageLoad(simage, id2d).x;\n";
432 break;
433 default:
434 DE_ASSERT(false);
435 break;
436 }
437
438 // This extra buffer will be used to copy values from the resource as obtained by the reader and will later be verified on the host.
439 std::stringstream readerVerifierDeclStream;
440 readerVerifierDeclStream << "layout(set = 0, binding = " << readerVerifierBinding << ") buffer vssbodef { uint data[" << kBufferElements << "]; } verificationBuffer;\n";
441 const std::string readerVerifierDecl = readerVerifierDeclStream.str();
442
443 // These are always used together in writer shaders.
444 const std::string writerCalcAndWrite = valStatement + writeStatement.str();
445
446 // Add shaders that will be used to write to the resource.
447 if (wstage == Stage::HOST || wstage == Stage::TRANSFER)
448 ; // Nothing to do here.
449 else if (wstage == Stage::RAYGEN)
450 {
451 std::stringstream rgen;
452 rgen
453 << "#version 460 core\n"
454 << "#extension GL_EXT_ray_tracing : require\n"
455 << writerResourceDecl.str()
456 << "void main()\n"
457 << "{\n"
458 << rayTracingIds
459 << writerCalcAndWrite
460 << "}\n"
461 ;
462 programCollection.glslSources.add("writer_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
463 }
464 else if (wstage == Stage::INTERSECT)
465 {
466 programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
467
468 std::stringstream isect;
469 isect
470 << "#version 460 core\n"
471 << "#extension GL_EXT_ray_tracing : require\n"
472 << "hitAttributeEXT vec3 hitAttribute;\n"
473 << writerResourceDecl.str()
474 << "void main()\n"
475 << "{\n"
476 << rayTracingIds
477 << writerCalcAndWrite
478 << " hitAttribute = vec3(0.0f, 0.0f, 0.0f);\n"
479 << " reportIntersectionEXT(1.0f, 0);\n"
480 << "}\n"
481 ;
482 programCollection.glslSources.add("writer_isect") << glu::IntersectionSource(updateRayTracingGLSL(isect.str())) << buildOptions;
483 }
484 else if (wstage == Stage::ANY_HIT)
485 {
486 programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
487
488 std::stringstream ahit;
489 ahit
490 << "#version 460 core\n"
491 << "#extension GL_EXT_ray_tracing : require\n"
492 << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
493 << "hitAttributeEXT vec3 attribs;\n"
494 << writerResourceDecl.str()
495 << "void main()\n"
496 << "{\n"
497 << rayTracingIds
498 << writerCalcAndWrite
499 << "}\n"
500 ;
501 programCollection.glslSources.add("writer_ahit") << glu::AnyHitSource(updateRayTracingGLSL(ahit.str())) << buildOptions;
502 }
503 else if (wstage == Stage::CLOSEST_HIT)
504 {
505 programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
506
507 std::stringstream chit;
508 chit
509 << "#version 460 core\n"
510 << "#extension GL_EXT_ray_tracing : require\n"
511 << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
512 << "hitAttributeEXT vec3 attribs;\n"
513 << writerResourceDecl.str()
514 << "void main()\n"
515 << "{\n"
516 << rayTracingIds
517 << writerCalcAndWrite
518 << "}\n"
519 ;
520 programCollection.glslSources.add("writer_chit") << glu::ClosestHitSource(updateRayTracingGLSL(chit.str())) << buildOptions;
521 }
522 else if (wstage == Stage::MISS)
523 {
524 programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
525
526 std::stringstream miss;
527 miss
528 << "#version 460 core\n"
529 << "#extension GL_EXT_ray_tracing : require\n"
530 << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
531 << writerResourceDecl.str()
532 << "void main()\n"
533 << "{\n"
534 << rayTracingIds
535 << writerCalcAndWrite
536 << "}\n"
537 ;
538 programCollection.glslSources.add("writer_miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << buildOptions;
539 }
540 else if (wstage == Stage::CALLABLE)
541 {
542 {
543 std::stringstream rgen;
544 rgen
545 << "#version 460 core\n"
546 << "#extension GL_EXT_ray_tracing : require\n"
547 << "layout(location = 0) callableDataEXT float unusedCallableData;"
548 << "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
549 << "\n"
550 << "void main()\n"
551 << "{\n"
552 << " executeCallableEXT(0, 0);\n"
553 << "}\n"
554 ;
555 programCollection.glslSources.add("writer_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
556 }
557
558 std::stringstream callable;
559 callable
560 << "#version 460 core\n"
561 << "#extension GL_EXT_ray_tracing : require\n"
562 << "layout(location = 0) callableDataInEXT float unusedCallableData;\n"
563 << writerResourceDecl.str()
564 << "void main()\n"
565 << "{\n"
566 << rayTracingIds
567 << writerCalcAndWrite
568 << "}\n"
569 ;
570 programCollection.glslSources.add("writer_callable") << glu::CallableSource(updateRayTracingGLSL(callable.str())) << buildOptions;
571 }
572 else if (wstage == Stage::COMPUTE)
573 {
574 std::stringstream compute;
575 compute
576 << "#version 460 core\n"
577 << writerResourceDecl.str()
578 << "void main()\n"
579 << "{\n"
580 << computeIds
581 << writerCalcAndWrite
582 << "}\n"
583 ;
584 programCollection.glslSources.add("writer_comp") << glu::ComputeSource(compute.str());
585 }
586 else if (wstage == Stage::FRAGMENT)
587 {
588 {
589 std::stringstream vert;
590 vert
591 << "#version 460 core\n"
592 << "layout(location = 0) in highp vec4 position;\n"
593 << "void main()\n"
594 << "{\n"
595 << " gl_Position = position;\n"
596 << "}\n"
597 ;
598 programCollection.glslSources.add("writer_aux_vert") << glu::VertexSource(vert.str());
599 }
600
601 std::stringstream frag;
602 frag
603 << "#version 460 core\n"
604 << writerResourceDecl.str()
605 << "void main()\n"
606 << "{\n"
607 << fragIds
608 << writerCalcAndWrite
609 << "}\n"
610 ;
611 programCollection.glslSources.add("writer_frag") << glu::FragmentSource(frag.str());
612 }
613 else
614 {
615 DE_ASSERT(false);
616 }
617
618 // These are always used together by reader shaders.
619 const std::string readerAllDecls = readerResourceDecl.str() + readerVerifierDecl;
620 const std::string readerReadAndSave = readStatement.str() + readerSaveStatement;
621
622 // Add shaders that will be used to read from the resource.
623 if (rstage == Stage::HOST || rstage == Stage::TRANSFER)
624 ; // Nothing to do here.
625 else if (rstage == Stage::RAYGEN)
626 {
627 std::stringstream rgen;
628 rgen
629 << "#version 460 core\n"
630 << "#extension GL_EXT_ray_tracing : require\n"
631 << readerAllDecls
632 << "void main()\n"
633 << "{\n"
634 << rayTracingIds
635 << readerReadAndSave
636 << "}\n"
637 ;
638 programCollection.glslSources.add("reader_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
639 }
640 else if (rstage == Stage::INTERSECT)
641 {
642 programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
643
644 std::stringstream isect;
645 isect
646 << "#version 460 core\n"
647 << "#extension GL_EXT_ray_tracing : require\n"
648 << "hitAttributeEXT vec3 hitAttribute;\n"
649 << readerAllDecls
650 << "void main()\n"
651 << "{\n"
652 << rayTracingIds
653 << readerReadAndSave
654 << " hitAttribute = vec3(0.0f, 0.0f, 0.0f);\n"
655 << " reportIntersectionEXT(1.0f, 0);\n"
656 << "}\n"
657 ;
658 programCollection.glslSources.add("reader_isect") << glu::IntersectionSource(updateRayTracingGLSL(isect.str())) << buildOptions;
659 }
660 else if (rstage == Stage::ANY_HIT)
661 {
662 programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
663
664 std::stringstream ahit;
665 ahit
666 << "#version 460 core\n"
667 << "#extension GL_EXT_ray_tracing : require\n"
668 << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
669 << "hitAttributeEXT vec3 attribs;\n"
670 << readerAllDecls
671 << "void main()\n"
672 << "{\n"
673 << rayTracingIds
674 << readerReadAndSave
675 << "}\n"
676 ;
677 programCollection.glslSources.add("reader_ahit") << glu::AnyHitSource(updateRayTracingGLSL(ahit.str())) << buildOptions;
678 }
679 else if (rstage == Stage::CLOSEST_HIT)
680 {
681 programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
682
683 std::stringstream chit;
684 chit
685 << "#version 460 core\n"
686 << "#extension GL_EXT_ray_tracing : require\n"
687 << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
688 << "hitAttributeEXT vec3 attribs;\n"
689 << readerAllDecls
690 << "void main()\n"
691 << "{\n"
692 << rayTracingIds
693 << readerReadAndSave
694 << "}\n"
695 ;
696 programCollection.glslSources.add("reader_chit") << glu::ClosestHitSource(updateRayTracingGLSL(chit.str())) << buildOptions;
697 }
698 else if (rstage == Stage::MISS)
699 {
700 programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(getCommonRayGenerationShader())) << buildOptions;
701
702 std::stringstream miss;
703 miss
704 << "#version 460 core\n"
705 << "#extension GL_EXT_ray_tracing : require\n"
706 << "layout(location = 0) rayPayloadInEXT vec3 unusedPayload;\n"
707 << readerAllDecls
708 << "void main()\n"
709 << "{\n"
710 << rayTracingIds
711 << readerReadAndSave
712 << "}\n"
713 ;
714 programCollection.glslSources.add("reader_miss") << glu::MissSource(updateRayTracingGLSL(miss.str())) << buildOptions;
715 }
716 else if (rstage == Stage::CALLABLE)
717 {
718 {
719 std::stringstream rgen;
720 rgen
721 << "#version 460 core\n"
722 << "#extension GL_EXT_ray_tracing : require\n"
723 << "layout(location = 0) callableDataEXT float unusedCallableData;"
724 << "layout(set = 0, binding = 1) uniform accelerationStructureEXT topLevelAS;\n"
725 << "\n"
726 << "void main()\n"
727 << "{\n"
728 << " executeCallableEXT(0, 0);\n"
729 << "}\n"
730 ;
731 programCollection.glslSources.add("reader_aux_rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions;
732 }
733
734 std::stringstream callable;
735 callable
736 << "#version 460 core\n"
737 << "#extension GL_EXT_ray_tracing : require\n"
738 << "layout(location = 0) callableDataInEXT float unusedCallableData;\n"
739 << readerAllDecls
740 << "void main()\n"
741 << "{\n"
742 << rayTracingIds
743 << readerReadAndSave
744 << "}\n"
745 ;
746 programCollection.glslSources.add("reader_callable") << glu::CallableSource(updateRayTracingGLSL(callable.str())) << buildOptions;
747 }
748 else if (rstage == Stage::COMPUTE)
749 {
750 std::stringstream compute;
751 compute
752 << "#version 460 core\n"
753 << readerAllDecls
754 << "void main()\n"
755 << "{\n"
756 << computeIds
757 << readerReadAndSave
758 << "}\n"
759 ;
760 programCollection.glslSources.add("reader_comp") << glu::ComputeSource(compute.str());
761 }
762 else if (rstage == Stage::FRAGMENT)
763 {
764 {
765 std::stringstream vert;
766 vert
767 << "#version 460 core\n"
768 << "layout(location = 0) in highp vec4 position;\n"
769 << "void main()\n"
770 << "{\n"
771 << " gl_Position = position;\n"
772 << "}\n"
773 ;
774 programCollection.glslSources.add("reader_aux_vert") << glu::VertexSource(vert.str());
775 }
776
777 std::stringstream frag;
778 frag
779 << "#version 460 core\n"
780 << readerAllDecls
781 << "void main()\n"
782 << "{\n"
783 << fragIds
784 << readerReadAndSave
785 << "}\n"
786 ;
787 programCollection.glslSources.add("reader_frag") << glu::FragmentSource(frag.str());
788 }
789 else
790 {
791 DE_ASSERT(false);
792 }
793 }
794
createInstance(Context & context) const795 TestInstance* BarrierTestCase::createInstance (Context& context) const
796 {
797 return new BarrierTestInstance(context, m_params);
798 }
799
checkSupport(Context & context) const800 void BarrierTestCase::checkSupport (Context& context) const
801 {
802 if (m_params.writerStage == Stage::FRAGMENT)
803 {
804 const auto& features = context.getDeviceFeatures();
805
806 if (!features.fragmentStoresAndAtomics)
807 TCU_THROW(NotSupportedError, "Fragment shader does not support stores");
808 }
809
810 if (isRayTracingStage(m_params.readerStage) || isRayTracingStage(m_params.writerStage))
811 {
812 context.requireDeviceFunctionality("VK_KHR_acceleration_structure");
813 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
814
815 const auto& rtFeatures = context.getRayTracingPipelineFeatures();
816 if (!rtFeatures.rayTracingPipeline)
817 TCU_THROW(NotSupportedError, "Ray Tracing pipelines not supported");
818
819 const auto& asFeatures = context.getAccelerationStructureFeatures();
820 if (!asFeatures.accelerationStructure)
821 TCU_FAIL("VK_KHR_acceleration_structure supported without accelerationStructure support");
822 }
823 }
824
BarrierTestInstance(Context & context,const TestParams & testParams)825 BarrierTestInstance::BarrierTestInstance (Context& context, const TestParams& testParams)
826 : vkt::TestInstance (context)
827 , m_params (testParams)
828 {
829 }
830
831 // Creates a buffer with kBufferElements elements of type deUint32 and std140 padding.
makeStd140Buffer(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,VkBufferUsageFlags flags,MemoryRequirement memReq)832 std::unique_ptr<BufferWithMemory> makeStd140Buffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags, MemoryRequirement memReq)
833 {
834 std::unique_ptr<BufferWithMemory> buffer;
835
836 const auto bufferCreateInfo = makeBufferCreateInfo(static_cast<VkDeviceSize>(kBufferSize), flags);
837 buffer.reset(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, memReq));
838
839 return buffer;
840 }
841
842 // Fill buffer with data using std140 padding rules.
fillStd140Buffer(const DeviceInterface & vkd,VkDevice device,const BufferWithMemory & buffer)843 void fillStd140Buffer (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer)
844 {
845 // Buffer host ptr.
846 auto& bufferAlloc = buffer.getAllocation();
847 auto* bufferPtr = bufferAlloc.getHostPtr();
848
849 // Fill buffer with data. This uses the same strategy as the writer shaders.
850 std::vector<tcu::UVec4> bufferData(kBufferElements, tcu::UVec4(kValuesOffset, 0u, 0u, 0u));
851 for (size_t i = 0; i < bufferData.size(); ++i)
852 bufferData[i].x() += static_cast<deUint32>(i);
853 deMemcpy(bufferPtr, bufferData.data(), static_cast<size_t>(kBufferSize));
854 flushAlloc(vkd, device, bufferAlloc);
855 }
856
857 // Fill buffer with data using std430 padding rules (compact integers).
fillStd430Buffer(const DeviceInterface & vkd,VkDevice device,const BufferWithMemory & buffer)858 void fillStd430Buffer (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer)
859 {
860 // Buffer host ptr.
861 auto& bufferAlloc = buffer.getAllocation();
862 auto* bufferPtr = bufferAlloc.getHostPtr();
863
864 // Fill buffer with data. This uses the same strategy as the writer shaders.
865 std::vector<deUint32> bufferData(kBufferElements);
866 std::iota(begin(bufferData), end(bufferData), kValuesOffset);
867 deMemcpy(bufferPtr, bufferData.data(), static_cast<size_t>(kBufferSize430));
868 flushAlloc(vkd, device, bufferAlloc);
869 }
870
871 // Creates a host-visible std430 buffer with kBufferElements elements of type deUint32. If requested, fill buffer with values
872 // starting at kValuesOffset.
makeStd430BufferImpl(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,VkBufferUsageFlags flags,bool fill)873 std::unique_ptr<BufferWithMemory> makeStd430BufferImpl (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags, bool fill)
874 {
875 std::unique_ptr<BufferWithMemory> buffer;
876
877 const auto bufferCreateInfo = makeBufferCreateInfo(static_cast<VkDeviceSize>(kBufferSize430), flags);
878 buffer.reset(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible));
879
880 if (fill)
881 fillStd430Buffer(vkd, device, *buffer);
882
883 return buffer;
884 }
885
makeStd430Buffer(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,VkBufferUsageFlags flags)886 std::unique_ptr<BufferWithMemory> makeStd430Buffer (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags)
887 {
888 return makeStd430BufferImpl(vkd, device, alloc, flags, false);
889 }
890
makeStd430BufferFilled(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,VkBufferUsageFlags flags)891 std::unique_ptr<BufferWithMemory> makeStd430BufferFilled (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, VkBufferUsageFlags flags)
892 {
893 return makeStd430BufferImpl(vkd, device, alloc, flags, true);
894 }
895
896 // Helper struct to group data related to the writer or reader stages.
897 // Not every member will be used at the same time.
898 struct StageData
899 {
900 Move<VkDescriptorSetLayout> descriptorSetLayout;
901 Move<VkPipelineLayout> pipelineLayout;
902
903 Move<VkDescriptorPool> descriptorPool;
904 Move<VkDescriptorSet> descriptorSet;
905
906 Move<VkPipeline> pipeline;
907 Move<VkRenderPass> renderPass;
908 Move<VkFramebuffer> framebuffer;
909 std::unique_ptr<BufferWithMemory> vertexBuffer;
910
911 de::MovePtr<BottomLevelAccelerationStructure> bottomLevelAccelerationStructure;
912 de::MovePtr<TopLevelAccelerationStructure> topLevelAccelerationStructure;
913
914 de::MovePtr<BufferWithMemory> raygenShaderBindingTable;
915 de::MovePtr<BufferWithMemory> missShaderBindingTable;
916 de::MovePtr<BufferWithMemory> hitShaderBindingTable;
917 de::MovePtr<BufferWithMemory> callableShaderBindingTable;
918
919 VkStridedDeviceAddressRegionKHR raygenShaderBindingTableRegion;
920 VkStridedDeviceAddressRegionKHR missShaderBindingTableRegion;
921 VkStridedDeviceAddressRegionKHR hitShaderBindingTableRegion;
922 VkStridedDeviceAddressRegionKHR callableShaderBindingTableRegion;
923
StageDatavkt::RayTracing::__anon2c1cb5820111::StageData924 StageData ()
925 : descriptorSetLayout ()
926 , pipelineLayout ()
927 , descriptorPool ()
928 , descriptorSet ()
929 , pipeline ()
930 , renderPass ()
931 , framebuffer ()
932 , vertexBuffer ()
933 , bottomLevelAccelerationStructure ()
934 , topLevelAccelerationStructure ()
935 , raygenShaderBindingTable ()
936 , missShaderBindingTable ()
937 , hitShaderBindingTable ()
938 , callableShaderBindingTable ()
939 , raygenShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0))
940 , missShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0))
941 , hitShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0))
942 , callableShaderBindingTableRegion (makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0))
943 {
944 }
945
946 // Make sure we don't mistakenly pass one of these by value.
947 StageData (const StageData&) = delete;
948 StageData (StageData&&) = delete;
949 };
950
951 // Auxiliar function to update the descriptor set for the writer or reader stages.
updateDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkCommandBuffer cmdBuffer,Allocator & alloc,VkDescriptorType resourceType,Stage stage,StageData & stageData,BufferWithMemory * resourceBuffer,VkImageView resourceImgView,VkImageLayout layout,bool asNeeded,BufferWithMemory * verificationBuffer)952 void updateDescriptorSet (const DeviceInterface& vkd, VkDevice device, VkCommandBuffer cmdBuffer, Allocator& alloc, VkDescriptorType resourceType, Stage stage, StageData& stageData, BufferWithMemory* resourceBuffer, VkImageView resourceImgView, VkImageLayout layout, bool asNeeded, BufferWithMemory* verificationBuffer)
953 {
954 DescriptorSetUpdateBuilder updateBuilder;
955 VkWriteDescriptorSetAccelerationStructureKHR writeASInfo;
956
957 if (resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
958 {
959 const auto descriptorBufferInfo = makeDescriptorBufferInfo(resourceBuffer->get(), 0ull, VK_WHOLE_SIZE);
960 updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), resourceType, &descriptorBufferInfo);
961 }
962 else if (resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
963 {
964 const auto descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, resourceImgView, layout);
965 updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), resourceType, &descriptorImageInfo);
966 }
967 else
968 {
969 DE_ASSERT(false);
970 }
971
972 // Create top and bottom level acceleration structures if needed.
973 if (asNeeded)
974 {
975 stageData.bottomLevelAccelerationStructure = makeBottomLevelAccelerationStructure();
976 stageData.bottomLevelAccelerationStructure->setDefaultGeometryData(getShaderStageFlagBits(stage));
977 stageData.bottomLevelAccelerationStructure->createAndBuild(vkd, device, cmdBuffer, alloc);
978
979 stageData.topLevelAccelerationStructure = makeTopLevelAccelerationStructure();
980 stageData.topLevelAccelerationStructure->setInstanceCount(1);
981 stageData.topLevelAccelerationStructure->addInstance(de::SharedPtr<BottomLevelAccelerationStructure>(stageData.bottomLevelAccelerationStructure.release()));
982 stageData.topLevelAccelerationStructure->createAndBuild(vkd, device, cmdBuffer, alloc);
983
984 writeASInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
985 writeASInfo.pNext = nullptr;
986 writeASInfo.accelerationStructureCount = 1u;
987 writeASInfo.pAccelerationStructures = stageData.topLevelAccelerationStructure.get()->getPtr();
988
989 updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, &writeASInfo);
990 }
991
992 if (verificationBuffer)
993 {
994 const deUint32 bindingNumber = (asNeeded ? 2u : 1u);
995 const auto descriptorBufferInfo = makeDescriptorBufferInfo(verificationBuffer->get(), 0ull, VK_WHOLE_SIZE);
996
997 updateBuilder.writeSingle(stageData.descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(bindingNumber), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo);
998 }
999
1000 updateBuilder.update(vkd, device);
1001 }
1002
1003 // Auxiliar function to create the writer or reader compute pipeline
createComputePipeline(const DeviceInterface & vkd,VkDevice device,Context & context,const char * shaderName,StageData & stageData)1004 void createComputePipeline (const DeviceInterface& vkd, VkDevice device, Context& context, const char* shaderName, StageData& stageData)
1005 {
1006 const auto shaderModule = createShaderModule(vkd, device, context.getBinaryCollection().get(shaderName), 0u);
1007
1008 const VkPipelineShaderStageCreateInfo stageInfo =
1009 {
1010 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1011 nullptr, // const void* pNext;
1012 0u, // VkPipelineShaderStageCreateFlags flags;
1013 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1014 shaderModule.get(), // VkShaderModule module;
1015 "main", // const char* pName;
1016 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1017 };
1018
1019 const VkComputePipelineCreateInfo createInfo =
1020 {
1021 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1022 nullptr, // const void* pNext;
1023 0u, // VkPipelineCreateFlags flags;
1024 stageInfo, // VkPipelineShaderStageCreateInfo stage;
1025 stageData.pipelineLayout.get(), // VkPipelineLayout layout;
1026 DE_NULL, // VkPipeline basePipelineHandle;
1027 0, // deInt32 basePipelineIndex;
1028 };
1029
1030 // Compute pipeline.
1031 stageData.pipeline = createComputePipeline(vkd, device, DE_NULL, &createInfo);
1032 }
1033
1034 // Auxiliar function to record commands using the compute pipeline.
useComputePipeline(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,StageData & stageData)1035 void useComputePipeline (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, StageData& stageData)
1036 {
1037 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, stageData.pipeline.get());
1038 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, stageData.pipelineLayout.get(), 0u, 1u, &stageData.descriptorSet.get(), 0u, nullptr);
1039 vkd.cmdDispatch(cmdBuffer, kImageDim, kImageDim, 1u);
1040 }
1041
1042 // Auxiliar function to create graphics pipeline objects for writer or reader stages.
createGraphicsPipelineObjects(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,Context & context,const char * vertShaderName,const char * fragShaderName,StageData & stageData)1043 void createGraphicsPipelineObjects (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, Context& context, const char* vertShaderName, const char* fragShaderName, StageData& stageData)
1044 {
1045 const auto vertShader = createShaderModule(vkd, device, context.getBinaryCollection().get(vertShaderName), 0u);
1046 const auto fragShader = createShaderModule(vkd, device, context.getBinaryCollection().get(fragShaderName), 0u);
1047
1048 // Render pass.
1049 const auto subpassDescription = makeSubpassDescription(0u, VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, nullptr, 0u, nullptr, nullptr, nullptr, 0u, nullptr);
1050 const VkRenderPassCreateInfo renderPassInfo =
1051 {
1052 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1053 nullptr, // const void* pNext;
1054 0u, // VkRenderPassCreateFlags flags;
1055 0u, // deUint32 attachmentCount;
1056 nullptr, // const VkAttachmentDescription* pAttachments;
1057 1u, // deUint32 subpassCount;
1058 &subpassDescription, // const VkSubpassDescription* pSubpasses;
1059 0u, // deUint32 dependencyCount;
1060 nullptr, // const VkSubpassDependency* pDependencies;
1061 };
1062 stageData.renderPass = createRenderPass(vkd, device, &renderPassInfo);
1063
1064 // Viewport.
1065 const auto viewport = makeViewport(kImageExtent);
1066 const std::vector<VkViewport> viewports(1u, viewport);
1067
1068 // Scissor.
1069 const auto scissor = makeRect2D(kImageExtent);
1070 const std::vector<VkRect2D> scissors(1u, scissor);
1071
1072 // Pipeline.
1073 stageData.pipeline = makeGraphicsPipeline(vkd, device, stageData.pipelineLayout.get(), vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(), stageData.renderPass.get(), viewports, scissors);
1074
1075 // Framebuffer.
1076 stageData.framebuffer = makeFramebuffer(vkd, device, stageData.renderPass.get(), 0u, nullptr, kImageDim, kImageDim);
1077
1078 // Vertex buffer with full-screen quad.
1079 const auto vertexBufferSize = static_cast<VkDeviceSize>(kFullScreenQuad.size() * sizeof(decltype(kFullScreenQuad)::value_type));
1080 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1081
1082 stageData.vertexBuffer.reset(new BufferWithMemory(vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible));
1083 const auto& vertexBufferAlloc = stageData.vertexBuffer->getAllocation();
1084
1085 deMemcpy(vertexBufferAlloc.getHostPtr(), kFullScreenQuad.data(), static_cast<size_t>(vertexBufferSize));
1086 flushAlloc(vkd, device, vertexBufferAlloc);
1087 }
1088
1089 // Auxiliar function to record commands using the graphics pipeline.
useGraphicsPipeline(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,StageData & stageData)1090 void useGraphicsPipeline (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, StageData& stageData)
1091 {
1092 const VkDeviceSize vertexBufferOffset = 0ull;
1093 const auto scissor = makeRect2D(kImageExtent);
1094
1095 beginRenderPass(vkd, cmdBuffer, stageData.renderPass.get(), stageData.framebuffer.get(), scissor);
1096 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, stageData.pipeline.get());
1097 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, stageData.pipelineLayout.get(), 0u, 1u, &stageData.descriptorSet.get(), 0u, nullptr);
1098 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &stageData.vertexBuffer->get(), &vertexBufferOffset);
1099 vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(kFullScreenQuad.size()), 1u, 0u, 0u);
1100 endRenderPass(vkd, cmdBuffer);
1101 }
1102
1103 // Auxiliar function to create ray tracing pipelines for the writer or reader stages.
createRayTracingPipelineData(const DeviceInterface & vkd,VkDevice device,Allocator & alloc,Context & context,Stage stage,StageData & stageData,deUint32 shaderGroupHandleSize,deUint32 shaderGroupBaseAlignment,const char * rgenAuxName,const char * rgenName,const char * isectName,const char * ahitName,const char * chitName,const char * missName,const char * callableName)1104 void createRayTracingPipelineData (const DeviceInterface& vkd, VkDevice device, Allocator& alloc, Context& context,
1105 Stage stage, StageData& stageData, deUint32 shaderGroupHandleSize, deUint32 shaderGroupBaseAlignment,
1106 const char* rgenAuxName, const char* rgenName, const char* isectName, const char* ahitName, const char* chitName, const char* missName, const char* callableName)
1107 {
1108 // Ray tracing stage
1109 DE_ASSERT(isRayTracingStage(stage));
1110
1111 if (stage == Stage::RAYGEN)
1112 {
1113 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1114
1115 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenName), 0), 0);
1116
1117 stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get());
1118
1119 stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
1120 stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1121 }
1122 else if (stage == Stage::INTERSECT)
1123 {
1124 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1125
1126 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0);
1127 rayTracingPipeline->addShader(VK_SHADER_STAGE_INTERSECTION_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(isectName), 0), 1);
1128
1129 stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get());
1130
1131 stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
1132 stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1133
1134 stageData.hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
1135 stageData.hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1136 }
1137 else if (stage == Stage::ANY_HIT)
1138 {
1139 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1140
1141 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0);
1142 rayTracingPipeline->addShader(VK_SHADER_STAGE_ANY_HIT_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(ahitName), 0), 1);
1143
1144 stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get());
1145
1146 stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
1147 stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1148
1149 stageData.hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
1150 stageData.hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1151 }
1152 else if (stage == Stage::CLOSEST_HIT)
1153 {
1154 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1155
1156 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0);
1157 rayTracingPipeline->addShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(chitName), 0), 1);
1158
1159 stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get());
1160
1161 stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
1162 stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1163
1164 stageData.hitShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
1165 stageData.hitShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.hitShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1166 }
1167 else if (stage == Stage::MISS)
1168 {
1169 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1170
1171 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0);
1172 rayTracingPipeline->addShader(VK_SHADER_STAGE_MISS_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(missName), 0), 1);
1173
1174 stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get());
1175
1176 stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
1177 stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1178
1179 stageData.missShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
1180 stageData.missShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.missShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1181 }
1182 else if (stage == Stage::CALLABLE)
1183 {
1184 const auto rayTracingPipeline = de::newMovePtr<RayTracingPipeline>();
1185
1186 rayTracingPipeline->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(rgenAuxName), 0), 0);
1187 rayTracingPipeline->addShader(VK_SHADER_STAGE_CALLABLE_BIT_KHR, createShaderModule(vkd, device, context.getBinaryCollection().get(callableName), 0), 1);
1188
1189 stageData.pipeline = rayTracingPipeline->createPipeline(vkd, device, stageData.pipelineLayout.get());
1190
1191 stageData.raygenShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1);
1192 stageData.raygenShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.raygenShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1193
1194 stageData.callableShaderBindingTable = rayTracingPipeline->createShaderBindingTable(vkd, device, stageData.pipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 1, 1);
1195 stageData.callableShaderBindingTableRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, stageData.callableShaderBindingTable->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize);
1196 }
1197 else
1198 {
1199 DE_ASSERT(false);
1200 }
1201 }
1202
1203 // Auxiliar function to record commands using the ray tracing pipeline for the writer or reader stages.
useRayTracingPipeline(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,StageData & stageData)1204 void useRayTracingPipeline (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, StageData& stageData)
1205 {
1206 vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, stageData.pipeline.get());
1207 vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, stageData.pipelineLayout.get(), 0u, 1u, &stageData.descriptorSet.get(), 0u, nullptr);
1208 vkd.cmdTraceRaysKHR(cmdBuffer, &stageData.raygenShaderBindingTableRegion, &stageData.missShaderBindingTableRegion, &stageData.hitShaderBindingTableRegion, &stageData.callableShaderBindingTableRegion, kImageDim, kImageDim, 1u);
1209 }
1210
iterate(void)1211 tcu::TestStatus BarrierTestInstance::iterate (void)
1212 {
1213 const auto& vki = m_context.getInstanceInterface();
1214 const auto physicalDevice = m_context.getPhysicalDevice();
1215 const auto& vkd = m_context.getDeviceInterface();
1216 const auto device = m_context.getDevice();
1217 const auto queue = m_context.getUniversalQueue();
1218 const auto familyIndex = m_context.getUniversalQueueFamilyIndex();
1219 auto& alloc = m_context.getDefaultAllocator();
1220 const auto imageSubresourceLayers = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
1221 const bool rtInUse = (isRayTracingStage(m_params.readerStage) || isRayTracingStage(m_params.writerStage));
1222
1223 // Stage data for the writer and reader stages.
1224 StageData writerStageData;
1225 StageData readerStageData;
1226
1227 // Get some ray tracing properties.
1228 deUint32 shaderGroupHandleSize = 0u;
1229 deUint32 shaderGroupBaseAlignment = 1u;
1230 if (rtInUse)
1231 {
1232 const auto rayTracingPropertiesKHR = makeRayTracingProperties(vki, physicalDevice);
1233 shaderGroupHandleSize = rayTracingPropertiesKHR->getShaderGroupHandleSize();
1234 shaderGroupBaseAlignment = rayTracingPropertiesKHR->getShaderGroupBaseAlignment();
1235 }
1236
1237 // Shader stages involved.
1238 const auto writerStages = getStageFlags(m_params.writerStage);
1239 const auto readerStages = getStageFlags(m_params.readerStage);
1240 const auto allStages = (writerStages | readerStages);
1241 const bool writerNeedsAS = needsAccelerationStructure(m_params.writerStage);
1242 const bool readerNeedsAS = needsAccelerationStructure(m_params.readerStage);
1243
1244 // Command buffer.
1245 const auto cmdPool = makeCommandPool(vkd, device, familyIndex);
1246 const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1247 const auto cmdBuffer = cmdBufferPtr.get();
1248
1249 beginCommandBuffer(vkd, cmdBuffer);
1250
1251 std::unique_ptr<ImageWithMemory> resourceImg;
1252 Move<VkImageView> resourceImgView;
1253 VkImageLayout resourceImgLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1254 const auto resourceImgSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1255 std::unique_ptr<BufferWithMemory> stagingBuffer;
1256 std::unique_ptr<BufferWithMemory> resourceBuffer;
1257 std::unique_ptr<BufferWithMemory> verificationBuffer;
1258 const VkBufferUsageFlags stagingBufferFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1259
1260 // Create verification buffer for later use.
1261 {
1262 VkBufferUsageFlags verificationBufferFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
1263 if (m_params.readerStage == Stage::TRANSFER)
1264 verificationBufferFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1265
1266 verificationBuffer = makeStd430Buffer(vkd, device, alloc, verificationBufferFlags);
1267 }
1268
1269 // Create resource buffer or resource image.
1270 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1271 {
1272 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
1273 DE_ASSERT(m_params.writerStage == Stage::HOST || m_params.writerStage == Stage::TRANSFER);
1274
1275 VkBufferUsageFlags bufferFlags = ((m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
1276 ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
1277 : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
1278
1279 if (m_params.writerStage == Stage::TRANSFER)
1280 bufferFlags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1281
1282 if (m_params.readerStage == Stage::TRANSFER)
1283 bufferFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1284
1285 MemoryRequirement bufferMemReq = (resourceNeedsHostVisibleMemory(m_params) ? MemoryRequirement::HostVisible : MemoryRequirement::Any);
1286 resourceBuffer = makeStd140Buffer(vkd, device, alloc, bufferFlags, bufferMemReq);
1287 }
1288 else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1289 {
1290 DE_ASSERT(m_params.writerStage != Stage::HOST);
1291
1292 VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_STORAGE_BIT;
1293
1294 if (m_params.writerStage == Stage::TRANSFER)
1295 imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1296
1297 if (m_params.readerStage == Stage::TRANSFER)
1298 imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1299
1300 const VkImageCreateInfo resourceImageInfo =
1301 {
1302 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1303 nullptr, // const void* pNext;
1304 0u, // VkImageCreateFlags flags;
1305 VK_IMAGE_TYPE_2D, // VkImageType imageType;
1306 kImageFormat, // VkFormat format;
1307 kImageExtent, // VkExtent3D extent;
1308 1u, // deUint32 mipLevels;
1309 1u, // deUint32 arrayLayers;
1310 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1311 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1312 imageUsage, // VkImageUsageFlags usage;
1313 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1314 0u, // deUint32 queueFamilyIndexCount;
1315 nullptr, // const deUint32* pQueueFamilyIndices;
1316 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1317 };
1318 resourceImg.reset(new ImageWithMemory(vkd, device, alloc, resourceImageInfo, MemoryRequirement::Any));
1319 resourceImgLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1320
1321 // Image view.
1322 resourceImgView = makeImageView(vkd, device, resourceImg->get(), VK_IMAGE_VIEW_TYPE_2D, kImageFormat, resourceImgSubresourceRange);
1323 }
1324 else
1325 {
1326 DE_ASSERT(false);
1327 }
1328
1329 // Populate resource from the writer stage.
1330 if (m_params.writerStage == Stage::HOST)
1331 {
1332 DE_ASSERT(m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
1333
1334 // Fill buffer data from the host.
1335 fillStd140Buffer(vkd, device, *resourceBuffer);
1336 }
1337 else if (m_params.writerStage == Stage::TRANSFER)
1338 {
1339 // Similar to the previous one, but using a staging buffer.
1340 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1341 {
1342 // Create and fill staging buffer.
1343 stagingBuffer = makeStd140Buffer(vkd, device, alloc, stagingBufferFlags, MemoryRequirement::HostVisible);
1344 fillStd140Buffer(vkd, device, *stagingBuffer);
1345
1346 // Fill resource buffer using a transfer operation.
1347 const auto region = makeBufferCopy(0u, 0u, static_cast<VkDeviceSize>(kBufferSize));
1348 const auto barrier = makeMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
1349 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 1u, &barrier, 0u, nullptr, 0u, nullptr);
1350 vkd.cmdCopyBuffer(cmdBuffer, stagingBuffer->get(), resourceBuffer->get(), 1u, ®ion);
1351 }
1352 else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1353 {
1354 // Prepare staging buffer with packed pixels.
1355 stagingBuffer = makeStd430BufferFilled(vkd, device, alloc, stagingBufferFlags);
1356
1357 // Barrier for the staging buffer.
1358 const auto stagingBufferBarrier = makeMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
1359 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 1u, &stagingBufferBarrier, 0u, nullptr, 0u, nullptr);
1360
1361 // Transition image to the proper layout.
1362 const auto expectedLayout = ((m_params.barrierType == BarrierType::SPECIFIC) ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL);
1363 if (expectedLayout != resourceImgLayout)
1364 {
1365 const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange);
1366 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier);
1367 resourceImgLayout = expectedLayout;
1368 }
1369
1370 // Copy buffer to image.
1371 const auto bufferImageCopy = makeBufferImageCopy(kImageExtent, imageSubresourceLayers);
1372 vkd.cmdCopyBufferToImage(cmdBuffer, stagingBuffer->get(), resourceImg->get(), resourceImgLayout, 1u, &bufferImageCopy);
1373 }
1374 else
1375 {
1376 DE_ASSERT(false);
1377 }
1378 }
1379 else
1380 {
1381 // Other cases use pipelines and a shader to fill the resource.
1382
1383 // Descriptor set layout.
1384 DescriptorSetLayoutBuilder dslBuilder;
1385 dslBuilder.addBinding(m_params.resourceType, 1u, allStages, nullptr); // The resource is used in the writer and reader stages.
1386 if (writerNeedsAS)
1387 dslBuilder.addBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, writerStages, nullptr);
1388 writerStageData.descriptorSetLayout = dslBuilder.build(vkd, device);
1389
1390 // Pipeline layout.
1391 writerStageData.pipelineLayout = makePipelineLayout(vkd, device, writerStageData.descriptorSetLayout.get());
1392
1393 // Descriptor pool and set.
1394 DescriptorPoolBuilder poolBuilder;
1395 poolBuilder.addType(m_params.resourceType);
1396 if (writerNeedsAS)
1397 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
1398 writerStageData.descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1399 writerStageData.descriptorSet = makeDescriptorSet(vkd, device, writerStageData.descriptorPool.get(), writerStageData.descriptorSetLayout.get());
1400
1401 // Update descriptor set.
1402 updateDescriptorSet(vkd, device, cmdBuffer, alloc, m_params.resourceType, m_params.writerStage, writerStageData, resourceBuffer.get(), resourceImgView.get(), VK_IMAGE_LAYOUT_GENERAL, writerNeedsAS, nullptr);
1403
1404 if (m_params.writerStage == Stage::COMPUTE)
1405 {
1406 createComputePipeline(vkd, device, m_context, "writer_comp", writerStageData);
1407
1408 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1409 {
1410 // Make sure the image is in the proper layout for shader writes.
1411 const auto expectedLayout = VK_IMAGE_LAYOUT_GENERAL;
1412 if (expectedLayout != resourceImgLayout)
1413 {
1414 const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange);
1415 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier);
1416 resourceImgLayout = expectedLayout;
1417 }
1418 }
1419
1420 // Generate the resource using the pipeline.
1421 useComputePipeline(vkd, cmdBuffer, writerStageData);
1422 }
1423 else if (m_params.writerStage == Stage::FRAGMENT)
1424 {
1425 createGraphicsPipelineObjects(vkd, device, alloc, m_context, "writer_aux_vert", "writer_frag", writerStageData);
1426
1427 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1428 {
1429 // Make sure the image is in the proper layout for shader writes.
1430 const auto expectedLayout = VK_IMAGE_LAYOUT_GENERAL;
1431 if (expectedLayout != resourceImgLayout)
1432 {
1433 const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange);
1434 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier);
1435 resourceImgLayout = expectedLayout;
1436 }
1437 }
1438
1439 useGraphicsPipeline(vkd, cmdBuffer, writerStageData);
1440 }
1441 else
1442 {
1443 createRayTracingPipelineData(vkd, device, alloc, m_context, m_params.writerStage, writerStageData, shaderGroupHandleSize, shaderGroupBaseAlignment,
1444 "writer_aux_rgen", "writer_rgen", "writer_isect", "writer_ahit", "writer_chit", "writer_miss", "writer_callable");
1445
1446 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1447 {
1448 // Make sure the image is in the proper layout for shader writes.
1449 const auto expectedLayout = VK_IMAGE_LAYOUT_GENERAL;
1450 if (expectedLayout != resourceImgLayout)
1451 {
1452 const auto imgBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, resourceImgLayout, expectedLayout, resourceImg->get(), resourceImgSubresourceRange);
1453 vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, 0u, 0u, nullptr, 0u, nullptr, 1u, &imgBarrier);
1454 resourceImgLayout = expectedLayout;
1455 }
1456 }
1457
1458 useRayTracingPipeline(vkd, cmdBuffer, writerStageData);
1459 }
1460 }
1461
1462 // Main barrier to synchronize the writer stage to the reader stage.
1463 const auto writerPipelineStage = getPipelineStage(m_params.writerStage);
1464 const auto readerPipelineStage = getPipelineStage(m_params.readerStage);
1465 const auto writerAccessFlag = getWriterAccessFlag(m_params.writerStage);
1466 const auto readerAccessFlag = getReaderAccessFlag(m_params.readerStage, m_params.resourceType);
1467
1468 if (m_params.barrierType == BarrierType::GENERAL)
1469 {
1470 const auto memoryBarrier = makeMemoryBarrier(writerAccessFlag, readerAccessFlag);
1471 vkd.cmdPipelineBarrier(cmdBuffer, writerPipelineStage, readerPipelineStage, 0u, 1u, &memoryBarrier, 0u, nullptr, 0u, nullptr);
1472 // Note the image will remain in the general layout in this case.
1473 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1474 DE_ASSERT(resourceImgLayout == VK_IMAGE_LAYOUT_GENERAL);
1475 }
1476 else if (m_params.barrierType == BarrierType::SPECIFIC)
1477 {
1478 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1479 {
1480 const auto bufferBarrier = makeBufferMemoryBarrier(writerAccessFlag, readerAccessFlag, resourceBuffer->get(), 0ull, VK_WHOLE_SIZE);
1481 vkd.cmdPipelineBarrier(cmdBuffer, writerPipelineStage, readerPipelineStage, 0u, 0u, nullptr, 1u, &bufferBarrier, 0u, nullptr);
1482 }
1483 else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1484 {
1485 // We'll switch the image layout from the current layout to the one the reader expects.
1486 const auto newLayout = getOptimalReadLayout(m_params.readerStage);
1487 const auto imageBarrier = makeImageMemoryBarrier(writerAccessFlag, readerAccessFlag, resourceImgLayout, newLayout, resourceImg->get(), resourceImgSubresourceRange);
1488
1489 vkd.cmdPipelineBarrier(cmdBuffer, writerPipelineStage, readerPipelineStage, 0u, 0u, nullptr, 0u, nullptr, 1u, &imageBarrier);
1490 resourceImgLayout = newLayout;
1491 }
1492 else
1493 {
1494 DE_ASSERT(false);
1495 }
1496 }
1497 else
1498 {
1499 DE_ASSERT(false);
1500 }
1501
1502 // Read resource from the reader stage copying it to the verification buffer.
1503 if (m_params.readerStage == Stage::HOST)
1504 {
1505 // This needs to wait until we have submitted the command buffer. See below.
1506 }
1507 else if (m_params.readerStage == Stage::TRANSFER)
1508 {
1509 if (m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1510 {
1511 // This is a bit tricky because the resource buffer is in std140 format and the verification buffer is in std430 format.
1512 std::vector<VkBufferCopy> regions;
1513 regions.reserve(kBufferElements);
1514 for (deUint32 i = 0; i < kBufferElements; ++i)
1515 {
1516 const VkBufferCopy region =
1517 {
1518 static_cast<VkDeviceSize>(i * sizeof(tcu::UVec4)), // VkDeviceSize srcOffset;
1519 static_cast<VkDeviceSize>(i * sizeof(deUint32)), // VkDeviceSize dstOffset;
1520 static_cast<VkDeviceSize>(sizeof(deUint32)), // VkDeviceSize size;
1521 };
1522 regions.push_back(region);
1523 }
1524 vkd.cmdCopyBuffer(cmdBuffer, resourceBuffer->get(), verificationBuffer->get(), static_cast<deUint32>(regions.size()), regions.data());
1525 }
1526 else if (m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
1527 {
1528 const auto bufferImageCopyRegion = makeBufferImageCopy(kImageExtent, imageSubresourceLayers);
1529 vkd.cmdCopyImageToBuffer(cmdBuffer, resourceImg->get(), resourceImgLayout, verificationBuffer->get(), 1u, &bufferImageCopyRegion);
1530 }
1531 else
1532 {
1533 DE_ASSERT(false);
1534 }
1535 }
1536 else
1537 {
1538 // All other stages use shaders to read the resource into the verification buffer.
1539
1540 // Descriptor set layout.
1541 DescriptorSetLayoutBuilder dslBuilder;
1542 dslBuilder.addBinding(m_params.resourceType, 1u, allStages, nullptr); // Resource accessed in writers and readers.
1543 if (readerNeedsAS)
1544 dslBuilder.addBinding(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1u, readerStages, nullptr);
1545 dslBuilder.addBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u, readerStages, nullptr); // Verification buffer.
1546 readerStageData.descriptorSetLayout = dslBuilder.build(vkd, device);
1547
1548 // Pipeline layout.
1549 readerStageData.pipelineLayout = makePipelineLayout(vkd, device, readerStageData.descriptorSetLayout.get());
1550
1551 // Descriptor pool and set.
1552 DescriptorPoolBuilder poolBuilder;
1553 poolBuilder.addType(m_params.resourceType);
1554 if (readerNeedsAS)
1555 poolBuilder.addType(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
1556 poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1557 readerStageData.descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1558 readerStageData.descriptorSet = makeDescriptorSet(vkd, device, readerStageData.descriptorPool.get(), readerStageData.descriptorSetLayout.get());
1559
1560 // Update descriptor set.
1561 updateDescriptorSet(vkd, device, cmdBuffer, alloc, m_params.resourceType, m_params.readerStage, readerStageData, resourceBuffer.get(), resourceImgView.get(), resourceImgLayout, readerNeedsAS, verificationBuffer.get());
1562
1563 if (m_params.readerStage == Stage::COMPUTE)
1564 {
1565 createComputePipeline(vkd, device, m_context, "reader_comp", readerStageData);
1566 useComputePipeline(vkd, cmdBuffer, readerStageData);
1567 }
1568 else if (m_params.readerStage == Stage::FRAGMENT)
1569 {
1570 createGraphicsPipelineObjects(vkd, device, alloc, m_context, "reader_aux_vert", "reader_frag", readerStageData);
1571 useGraphicsPipeline(vkd, cmdBuffer, readerStageData);
1572 }
1573 else
1574 {
1575 createRayTracingPipelineData(vkd, device, alloc, m_context, m_params.readerStage, readerStageData, shaderGroupHandleSize, shaderGroupBaseAlignment,
1576 "reader_aux_rgen", "reader_rgen", "reader_isect", "reader_ahit", "reader_chit", "reader_miss", "reader_callable");
1577 useRayTracingPipeline(vkd, cmdBuffer, readerStageData);
1578 }
1579 }
1580
1581 // Sync verification buffer.
1582 {
1583 const auto readerVerificationFlags = getWriterAccessFlag(m_params.readerStage);
1584 const auto barrier = makeBufferMemoryBarrier(readerVerificationFlags, VK_ACCESS_HOST_READ_BIT, verificationBuffer->get(), 0ull, VK_WHOLE_SIZE);
1585 vkd.cmdPipelineBarrier(cmdBuffer, readerPipelineStage, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &barrier, 0u, nullptr);
1586 }
1587
1588 // Submit all recorded commands.
1589 endCommandBuffer(vkd, cmdBuffer);
1590 submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1591
1592 invalidateAlloc(vkd, device, verificationBuffer->getAllocation());
1593
1594 // If the reader stage is the host, we have to wait until the commands have been submitted and the work has been done.
1595 if (m_params.readerStage == Stage::HOST)
1596 {
1597 DE_ASSERT(m_params.resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER || m_params.resourceType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1598
1599 auto& resourceBufferAlloc = resourceBuffer->getAllocation();
1600 auto* resourceBufferPtr = resourceBufferAlloc.getHostPtr();
1601
1602 std::vector<tcu::UVec4> resourceData(kBufferElements);
1603 invalidateAlloc(vkd, device, resourceBufferAlloc);
1604 deMemcpy(resourceData.data(), resourceBufferPtr, static_cast<size_t>(kBufferElements) * sizeof(tcu::UVec4));
1605
1606 // Convert from std140 to std430 on the host.
1607 std::vector<deUint32> verificationData(kBufferElements);
1608 std::transform(begin(resourceData), end(resourceData), begin(verificationData),
1609 [](const tcu::UVec4 &v) -> deUint32 { return v.x(); });
1610
1611 auto& verificationBufferAlloc = verificationBuffer->getAllocation();
1612 auto* verificationBufferPtr = verificationBufferAlloc.getHostPtr();
1613 deMemcpy(verificationBufferPtr, verificationData.data(), static_cast<size_t>(kBufferElements) * sizeof(deUint32));
1614 flushAlloc(vkd, device, verificationBufferAlloc);
1615 }
1616
1617 // Check verification buffer on the host.
1618 {
1619 auto& verificationAlloc = verificationBuffer->getAllocation();
1620 auto* verificationPtr = verificationAlloc.getHostPtr();
1621 std::vector<deUint32> verificationData(kBufferElements);
1622 deMemcpy(verificationData.data(), verificationPtr, static_cast<size_t>(kBufferElements) * sizeof(deUint32));
1623
1624 for (size_t i = 0; i < verificationData.size(); ++i)
1625 {
1626 const auto& value = verificationData[i];
1627 const auto expected = kValuesOffset + i;
1628
1629 if (value != expected)
1630 {
1631 std::ostringstream msg;
1632 msg << "Unexpected value found at position " << i << ": found " << value << " and expected " << expected;
1633 return tcu::TestStatus::fail(msg.str());
1634 }
1635 }
1636 }
1637
1638 return tcu::TestStatus::pass("Pass");
1639 }
1640
1641 } // anonymous.
1642
createBarrierTests(tcu::TestContext & testCtx)1643 tcu::TestCaseGroup* createBarrierTests(tcu::TestContext& testCtx)
1644 {
1645 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "barrier", "Tests involving pipeline barriers and ray tracing"));
1646
1647 const struct
1648 {
1649 VkDescriptorType type;
1650 const char* name;
1651 } resourceTypes[] =
1652 {
1653 { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "ubo" },
1654 { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, "ssbo" },
1655 { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, "simg" },
1656 };
1657
1658 const struct
1659 {
1660 Stage stage;
1661 const char* name;
1662 } stageList[] =
1663 {
1664 { Stage::HOST, "host" },
1665 { Stage::TRANSFER, "xfer" },
1666 { Stage::RAYGEN, "rgen" },
1667 { Stage::INTERSECT, "isec" },
1668 { Stage::ANY_HIT, "ahit" },
1669 { Stage::CLOSEST_HIT, "chit" },
1670 { Stage::MISS, "miss" },
1671 { Stage::CALLABLE, "call" },
1672 { Stage::COMPUTE, "comp" },
1673 { Stage::FRAGMENT, "frag" },
1674 };
1675
1676 const struct
1677 {
1678 BarrierType barrierType;
1679 const char* name;
1680 } barrierTypes[] =
1681 {
1682 { BarrierType::GENERAL, "memory_barrier" },
1683 { BarrierType::SPECIFIC, "specific_barrier" },
1684 };
1685
1686 for (int resourceTypeIdx = 0; resourceTypeIdx < DE_LENGTH_OF_ARRAY(resourceTypes); ++resourceTypeIdx)
1687 {
1688 de::MovePtr<tcu::TestCaseGroup> resourceTypeGroup(new tcu::TestCaseGroup(testCtx, resourceTypes[resourceTypeIdx].name, ""));
1689
1690 for (int barrierTypeIdx = 0; barrierTypeIdx < DE_LENGTH_OF_ARRAY(barrierTypes); ++barrierTypeIdx)
1691 {
1692 de::MovePtr<tcu::TestCaseGroup> barrierTypeGroup(new tcu::TestCaseGroup(testCtx, barrierTypes[barrierTypeIdx].name, ""));
1693
1694 for (int writerStageIdx = 0; writerStageIdx < DE_LENGTH_OF_ARRAY(stageList); ++writerStageIdx)
1695 for (int readerStageIdx = 0; readerStageIdx < DE_LENGTH_OF_ARRAY(stageList); ++readerStageIdx)
1696 {
1697 const auto resourceType = resourceTypes[resourceTypeIdx].type;
1698 const auto barrierType = barrierTypes[barrierTypeIdx].barrierType;
1699 const auto readerStage = stageList[readerStageIdx].stage;
1700 const auto writerStage = stageList[writerStageIdx].stage;
1701
1702 // Skip tests that do not involve ray tracing.
1703 if (!isRayTracingStage(readerStage) && !isRayTracingStage(writerStage))
1704 continue;
1705
1706 // Skip tests which require host acess to images.
1707 if (resourceType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && (writerStage == Stage::HOST || readerStage == Stage::HOST))
1708 continue;
1709
1710 // Skip tests that would require writes from shaders to an UBO.
1711 if (resourceType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER && writerStage != Stage::HOST && writerStage != Stage::TRANSFER)
1712 continue;
1713
1714 const std::string testName = std::string("from_") + stageList[writerStageIdx].name + "_to_" + stageList[readerStageIdx].name;
1715 barrierTypeGroup->addChild(new BarrierTestCase(testCtx, testName, "", TestParams(resourceType, writerStage, readerStage, barrierType)));
1716 }
1717 resourceTypeGroup->addChild(barrierTypeGroup.release());
1718 }
1719 group->addChild(resourceTypeGroup.release());
1720 }
1721 return group.release();
1722 }
1723
1724 } // RayTracing
1725 } // vkt
1726