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