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 ¶ms)
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, ®ion);
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