1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
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 SPIR-V Assembly Tests for PhysicalStorageBuffer.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktSpvAsmPhysicalStorageBufferPointerTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vkBarrierUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "deSharedPtr.hpp"
37 #include "deUniquePtr.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuVectorUtil.hpp"
40 
41 #include <iterator>
42 
43 using namespace vk;
44 using de::MovePtr;
45 using de::SharedPtr;
46 
47 namespace vkt
48 {
49 namespace SpirVAssembly
50 {
51 
52 namespace
53 {
54 
55 enum class PassMethod
56 {
57     PUSH_CONSTANTS,
58     PUSH_CONSTANTS_FUNCTION,
59     VERTEX_IN_OUT_IN,
60     ADDRESSES_IN_SSBO
61 };
62 
63 struct TestParams
64 {
65     PassMethod method;
66     uint32_t elements;
67 };
68 
69 typedef SharedPtr<const TestParams> TestParamsPtr;
70 
71 namespace ut
72 {
73 
74 class Buffer
75 {
76 public:
77     Buffer(Context &ctx, VkBufferUsageFlags usage, VkDeviceSize size, bool address = false);
78     Buffer(const Buffer &src);
79 
getBuffer(void) const80     VkBuffer getBuffer(void) const
81     {
82         return **m_buffer;
83     }
getSize(void) const84     VkDeviceSize getSize(void) const
85     {
86         return m_size;
87     }
getData(void) const88     void *getData(void) const
89     {
90         return (*m_bufferMemory)->getHostPtr();
91     }
92     uint64_t getDeviceAddress(void) const;
93     void zero(bool flushAfter = false);
94     void flush(void);
95     void invalidate(void);
96 
97 protected:
98     Context &m_context;
99     const VkDeviceSize m_size;
100     const bool m_address;
101     SharedPtr<Move<VkBuffer>> m_buffer;
102     SharedPtr<MovePtr<Allocation>> m_bufferMemory;
103 };
104 
105 template <class X>
106 class TypedBuffer : public Buffer
107 {
108 public:
109     TypedBuffer(Context &ctx, VkBufferUsageFlags usage, uint32_t nelements, bool address = false);
110     TypedBuffer(Context &ctx, VkBufferUsageFlags usage, std::initializer_list<X> items, bool address = false);
111     TypedBuffer(const TypedBuffer &src);
112     TypedBuffer(const Buffer &src);
113 
getElements(void) const114     uint32_t getElements(void) const
115     {
116         return m_elements;
117     }
getData(void) const118     X *getData(void) const
119     {
120         return reinterpret_cast<X *>(Buffer::getData());
121     }
122     void iota(X start, bool flushAfter = false);
123     X &operator[](uint32_t at);
124 
125     struct iterator;
begin()126     iterator begin()
127     {
128         return iterator(getData());
129     }
end()130     iterator end()
131     {
132         return iterator(&getData()[m_elements]);
133     }
134 
135 private:
136     const uint32_t m_elements;
137 };
138 
139 class Image
140 {
141 public:
142     Image(Context &ctx, uint32_t width, uint32_t height, VkFormat format);
143     Image(const Image &) = delete;
144     Image(Image &&)      = delete;
145 
146     Move<VkRenderPass> createRenderPass(void) const;
147     Move<VkFramebuffer> createFramebuffer(VkRenderPass rp) const;
148 
149     template <class X>
150     TypedBuffer<X> getBuffer(void);
151     void downloadAfterDraw(VkCommandBuffer cmdBuffer);
152 
153 private:
154     Context &m_context;
155     const uint32_t m_width;
156     const uint32_t m_height;
157     const VkFormat m_format;
158     VkImageLayout m_layout;
159     Buffer m_buffer;
160 
161     Move<VkImage> m_image;
162     Move<VkImageView> m_view;
163     de::MovePtr<Allocation> m_imageMemory;
164 };
165 
166 template <class X>
makeShared(Move<X> move)167 SharedPtr<Move<X>> makeShared(Move<X> move)
168 {
169     return SharedPtr<Move<X>>(new Move<X>(move));
170 }
171 
172 template <class X>
makeShared(MovePtr<X> move)173 SharedPtr<MovePtr<X>> makeShared(MovePtr<X> move)
174 {
175     return SharedPtr<MovePtr<X>>(new MovePtr<X>(move));
176 }
177 
Buffer(Context & ctx,VkBufferUsageFlags usage,VkDeviceSize size,bool address)178 Buffer::Buffer(Context &ctx, VkBufferUsageFlags usage, VkDeviceSize size, bool address)
179     : m_context(ctx)
180     , m_size(size)
181     , m_address(address)
182 {
183     const DeviceInterface &vki      = m_context.getDeviceInterface();
184     const VkDevice dev              = m_context.getDevice();
185     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
186     Allocator &allocator            = m_context.getDefaultAllocator();
187 
188     const VkBufferUsageFlags bufferUsageFlags = address ? (usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) : usage;
189     const MemoryRequirement requirements      = MemoryRequirement::Coherent | MemoryRequirement::HostVisible |
190                                            (address ? MemoryRequirement::DeviceAddress : MemoryRequirement::Any);
191 
192     const VkBufferCreateInfo bufferCreateInfo{
193         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
194         DE_NULL,                              // const void* pNext;
195         0u,                                   // VkBufferCreateFlags flags;
196         size,                                 // VkDeviceSize size;
197         bufferUsageFlags,                     // VkBufferUsageFlags usage;
198         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
199         1u,                                   // uint32_t queueFamilyIndexCount;
200         &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
201     };
202 
203     m_buffer       = makeShared(createBuffer(vki, dev, &bufferCreateInfo));
204     m_bufferMemory = makeShared(allocator.allocate(getBufferMemoryRequirements(vki, dev, **m_buffer), requirements));
205 
206     VK_CHECK(vki.bindBufferMemory(dev, **m_buffer, (*m_bufferMemory)->getMemory(), (*m_bufferMemory)->getOffset()));
207 }
208 
Buffer(const Buffer & src)209 Buffer::Buffer(const Buffer &src)
210     : m_context(src.m_context)
211     , m_size(src.m_size)
212     , m_address(src.m_address)
213     , m_buffer(src.m_buffer)
214     , m_bufferMemory(src.m_bufferMemory)
215 {
216 }
217 
getDeviceAddress(void) const218 uint64_t Buffer::getDeviceAddress(void) const
219 {
220     DE_ASSERT(m_address);
221 
222     const DeviceInterface &vki = m_context.getDeviceInterface();
223     const VkDevice dev         = m_context.getDevice();
224     const VkBufferDeviceAddressInfo info{
225         VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, // VkStructureType sType;
226         DE_NULL,                                      // const void* pNext;
227         **m_buffer                                    // VkBuffer buffer;
228     };
229 
230     return vki.getBufferDeviceAddress(dev, &info);
231 }
232 
zero(bool flushAfter)233 void Buffer::zero(bool flushAfter)
234 {
235     deMemset(getData(), 0, static_cast<size_t>(m_size));
236     if (flushAfter)
237         flush();
238 }
239 
flush(void)240 void Buffer::flush(void)
241 {
242     const DeviceInterface &vki = m_context.getDeviceInterface();
243     const VkDevice dev         = m_context.getDevice();
244     flushAlloc(vki, dev, **m_bufferMemory);
245 }
246 
invalidate(void)247 void Buffer::invalidate(void)
248 {
249     const DeviceInterface &vki = m_context.getDeviceInterface();
250     const VkDevice dev         = m_context.getDevice();
251     invalidateAlloc(vki, dev, **m_bufferMemory);
252 }
253 
254 template <class X>
255 struct TypedBuffer<X>::iterator
256 {
257     typedef std::forward_iterator_tag iterator_category;
258     typedef std::ptrdiff_t difference_type;
259     typedef X value_type;
260     typedef X &reference;
261     typedef X *pointer;
262 
iteratorvkt::SpirVAssembly::__anon88b1b5860111::ut::TypedBuffer::iterator263     iterator(pointer p) : m_p(p)
264     {
265         DE_ASSERT(p);
266     }
operator *vkt::SpirVAssembly::__anon88b1b5860111::ut::TypedBuffer::iterator267     reference operator*()
268     {
269         return *m_p;
270     }
operator ++vkt::SpirVAssembly::__anon88b1b5860111::ut::TypedBuffer::iterator271     iterator &operator++()
272     {
273         ++m_p;
274         return *this;
275     }
operator ++vkt::SpirVAssembly::__anon88b1b5860111::ut::TypedBuffer::iterator276     iterator operator++(int)
277     {
278         return iterator(m_p++);
279     }
operator ==vkt::SpirVAssembly::__anon88b1b5860111::ut::TypedBuffer::iterator280     bool operator==(const iterator &other) const
281     {
282         return (m_p == other.m_p);
283     }
operator !=vkt::SpirVAssembly::__anon88b1b5860111::ut::TypedBuffer::iterator284     bool operator!=(const iterator &other) const
285     {
286         return (m_p != other.m_p);
287     }
288 
289 private:
290     pointer m_p;
291 };
292 
293 template <class X>
TypedBuffer(Context & ctx,VkBufferUsageFlags usage,uint32_t nelements,bool address)294 TypedBuffer<X>::TypedBuffer(Context &ctx, VkBufferUsageFlags usage, uint32_t nelements, bool address)
295     : Buffer(ctx, usage, (nelements * sizeof(X)), address)
296     , m_elements(nelements)
297 {
298 }
299 
300 template <class X>
TypedBuffer(Context & ctx,VkBufferUsageFlags usage,std::initializer_list<X> items,bool address)301 TypedBuffer<X>::TypedBuffer(Context &ctx, VkBufferUsageFlags usage, std::initializer_list<X> items, bool address)
302     : Buffer(ctx, usage, (items.size() * sizeof(X)), address)
303     , m_elements(static_cast<uint32_t>(items.size()))
304 {
305     std::copy(items.begin(), items.end(), begin());
306 }
307 
308 template <class X>
TypedBuffer(const TypedBuffer & src)309 TypedBuffer<X>::TypedBuffer(const TypedBuffer &src) : Buffer(src)
310                                                     , m_elements(src.m_elements)
311 {
312 }
313 
314 template <class X>
TypedBuffer(const Buffer & src)315 TypedBuffer<X>::TypedBuffer(const Buffer &src) : Buffer(src)
316                                                , m_elements(static_cast<uint32_t>(m_size / sizeof(X)))
317 {
318 }
319 
320 template <class X>
iota(X start,bool flushAfter)321 void TypedBuffer<X>::iota(X start, bool flushAfter)
322 {
323     X *data = getData();
324     for (uint32_t i = 0; i < m_elements; ++i)
325         data[i] = start++;
326     if (flushAfter)
327         flush();
328 }
329 
330 template <class X>
operator [](uint32_t at)331 X &TypedBuffer<X>::operator[](uint32_t at)
332 {
333     DE_ASSERT(at < m_elements);
334     return getData()[at];
335 }
336 
Image(Context & ctx,uint32_t width,uint32_t height,VkFormat format)337 Image::Image(Context &ctx, uint32_t width, uint32_t height, VkFormat format)
338     : m_context(ctx)
339     , m_width(width)
340     , m_height(height)
341     , m_format(format)
342     , m_layout(VK_IMAGE_LAYOUT_UNDEFINED)
343     , m_buffer(ctx, (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT),
344                (m_width * m_height * vk::mapVkFormat(m_format).getPixelSize()), false)
345 {
346     const DeviceInterface &vki      = m_context.getDeviceInterface();
347     const VkDevice dev              = m_context.getDevice();
348     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
349     const VkImageUsageFlags imageUsageFlags =
350         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
351     const VkImageSubresourceRange viewResourceRange =
352         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
353     Allocator &allocator = m_context.getDefaultAllocator();
354 
355     const VkImageCreateInfo imageCreateInfo = {
356         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
357         DE_NULL,                             // const void* pNext;
358         0u,                                  // VkImageCreateFlags flags;
359         VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
360         m_format,                            // VkFormat format;
361         {m_width, m_height, 1u},             // VkExtent3D extent;
362         1u,                                  // uint32_t mipLevels;
363         1u,                                  // uint32_t arrayLayers;
364         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits samples;
365         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
366         imageUsageFlags,                     // VkImageUsageFlags usage;
367         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
368         1u,                                  // uint32_t queueFamilyIndexCount;
369         &queueFamilyIndex,                   // const uint32_t* pQueueFamilyIndices;
370         m_layout                             // VkImageLayout initialLayout;
371     };
372 
373     m_image = createImage(vki, dev, &imageCreateInfo);
374 
375     m_imageMemory = allocator.allocate(getImageMemoryRequirements(vki, dev, *m_image), MemoryRequirement::Any);
376     VK_CHECK(vki.bindImageMemory(dev, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset()));
377 
378     m_view = makeImageView(vki, dev, *m_image, VK_IMAGE_VIEW_TYPE_2D, m_format, viewResourceRange);
379 }
380 
381 template <class X>
getBuffer(void)382 TypedBuffer<X> Image::getBuffer(void)
383 {
384     m_buffer.invalidate();
385     return TypedBuffer<X>(m_buffer);
386 }
387 
createRenderPass(void) const388 Move<VkRenderPass> Image::createRenderPass(void) const
389 {
390     const DeviceInterface &vki = m_context.getDeviceInterface();
391     const VkDevice dev         = m_context.getDevice();
392 
393     const VkAttachmentDescription attachmentDescription = {
394         (VkAttachmentDescriptionFlags)0,         // VkAttachmentDescriptionFlags    flags
395         m_format,                                // VkFormat                        format
396         VK_SAMPLE_COUNT_1_BIT,                   // VkSampleCountFlagBits           samples
397         VK_ATTACHMENT_LOAD_OP_CLEAR,             // VkAttachmentLoadOp              loadOp
398         VK_ATTACHMENT_STORE_OP_STORE,            // VkAttachmentStoreOp             storeOp
399         VK_ATTACHMENT_LOAD_OP_DONT_CARE,         // VkAttachmentLoadOp              stencilLoadOp
400         VK_ATTACHMENT_STORE_OP_DONT_CARE,        // VkAttachmentStoreOp             stencilStoreOp
401         m_layout,                                // VkImageLayout                   initialLayout
402         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                   finalLayout
403     };
404 
405     const VkAttachmentReference attachmentReference = {
406         0u,                                      // uint32_t                            attachment
407         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout                    layout
408     };
409 
410     const VkSubpassDescription subpassDescription = {
411         (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags       flags
412         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint             pipelineBindPoint
413         0u,                              // uint32_t                        inputAttachmentCount
414         DE_NULL,                         // const VkAttachmentReference*    pInputAttachments
415         1u,                              // uint32_t                        colorAttachmentCount
416         &attachmentReference,            // const VkAttachmentReference*    pColorAttachments
417         DE_NULL,                         // const VkAttachmentReference*    pResolveAttachments
418         DE_NULL,                         // const VkAttachmentReference*    pDepthStencilAttachment
419         0u,                              // uint32_t                        preserveAttachmentCount
420         DE_NULL                          // const uint32_t*                 pPreserveAttachments
421     };
422 
423     const VkRenderPassCreateInfo renderPassInfo = {
424         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType                   sType
425         DE_NULL,                                   // const void*                       pNext
426         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags           flags
427         1u,                                        // uint32_t                          attachmentCount
428         &attachmentDescription,                    // const VkAttachmentDescription*    pAttachments
429         1u,                                        // uint32_t                          subpassCount
430         &subpassDescription,                       // const VkSubpassDescription*       pSubpasses
431         0u,                                        // uint32_t                          dependencyCount
432         DE_NULL                                    // const VkSubpassDependency*        pDependencies
433     };
434 
435     return vk::createRenderPass(vki, dev, &renderPassInfo);
436 }
437 
createFramebuffer(VkRenderPass rp) const438 Move<VkFramebuffer> Image::createFramebuffer(VkRenderPass rp) const
439 {
440     const DeviceInterface &vki = m_context.getDeviceInterface();
441     const VkDevice dev         = m_context.getDevice();
442 
443     return makeFramebuffer(vki, dev, rp, 1u, &m_view.get(), m_width, m_height, 1u);
444 }
445 
downloadAfterDraw(VkCommandBuffer cmdBuffer)446 void Image::downloadAfterDraw(VkCommandBuffer cmdBuffer)
447 {
448     const DeviceInterface &vki = m_context.getDeviceInterface();
449     vk::copyImageToBuffer(vki, cmdBuffer, *m_image, m_buffer.getBuffer(), {int32_t(m_width), int32_t(m_height)});
450     m_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
451 }
452 
453 } // namespace ut
454 
455 class SpvAsmPhysicalStorageBufferTestInstance : public TestInstance
456 {
457 public:
SpvAsmPhysicalStorageBufferTestInstance(Context & ctx)458     SpvAsmPhysicalStorageBufferTestInstance(Context &ctx) : TestInstance(ctx)
459     {
460     }
461 };
462 
463 class SpvAsmPhysicalStorageBufferVertexInOutInTestInstance : public SpvAsmPhysicalStorageBufferTestInstance
464 {
465 public:
SpvAsmPhysicalStorageBufferVertexInOutInTestInstance(Context & ctx,const TestParamsPtr params)466     SpvAsmPhysicalStorageBufferVertexInOutInTestInstance(Context &ctx, const TestParamsPtr params)
467         : SpvAsmPhysicalStorageBufferTestInstance(ctx)
468         , m_params(params)
469     {
470     }
471     tcu::TestStatus iterate(void);
472     static void initPrograms(vk::SourceCollections &programCollection, const TestParamsPtr params);
473     struct alignas(16) Attribute
474     {
475         tcu::Vec4 position;
476         uint64_t address;
477     };
478     ut::TypedBuffer<tcu::Vec4> prepareColorBuffer(bool flushAfter = true) const;
479     ut::TypedBuffer<Attribute> prepareVertexAttributes(uint64_t address) const;
480     Move<VkPipeline> createGraphicsPipeline(VkPipelineLayout pipelineLayout, VkRenderPass renderPass,
481                                             VkShaderModule vertexModule, VkShaderModule fragmentModule) const;
482 
483 private:
484     const TestParamsPtr m_params;
485 };
486 
487 class SpvAsmPhysicalStorageBufferPushConstantsTestInstance : public SpvAsmPhysicalStorageBufferTestInstance
488 {
489 public:
SpvAsmPhysicalStorageBufferPushConstantsTestInstance(Context & ctx,const TestParamsPtr params)490     SpvAsmPhysicalStorageBufferPushConstantsTestInstance(Context &ctx, const TestParamsPtr params)
491         : SpvAsmPhysicalStorageBufferTestInstance(ctx)
492         , m_params(params)
493     {
494     }
495     tcu::TestStatus iterate(void);
496     static void initPrograms(vk::SourceCollections &programCollection, const TestParamsPtr params);
497 
498 private:
499     const TestParamsPtr m_params;
500 };
501 
502 class SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance : public SpvAsmPhysicalStorageBufferTestInstance
503 {
504 public:
SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance(Context & ctx,const TestParamsPtr params)505     SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance(Context &ctx, const TestParamsPtr params)
506         : SpvAsmPhysicalStorageBufferTestInstance(ctx)
507         , m_params(params)
508     {
509     }
510     tcu::TestStatus iterate(void);
511     static void initPrograms(vk::SourceCollections &programCollection, const TestParamsPtr params);
512 
513 private:
514     const TestParamsPtr m_params;
515 };
516 
517 class SpvAsmPhysicalStorageBufferTestCase : public TestCase
518 {
519 public:
SpvAsmPhysicalStorageBufferTestCase(tcu::TestContext & testCtx,const std::string & name,const TestParamsPtr params)520     SpvAsmPhysicalStorageBufferTestCase(tcu::TestContext &testCtx, const std::string &name, const TestParamsPtr params)
521         : TestCase(testCtx, name)
522         , m_params(params)
523     {
524     }
525     void checkSupport(Context &context) const;
526     void initPrograms(vk::SourceCollections &programCollection) const;
527     TestInstance *createInstance(Context &ctx) const;
528 
529 private:
530     const TestParamsPtr m_params;
531 };
532 
checkSupport(Context & context) const533 void SpvAsmPhysicalStorageBufferTestCase::checkSupport(Context &context) const
534 {
535     context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
536 
537     if (!context.isBufferDeviceAddressSupported())
538         TCU_THROW(NotSupportedError, "Request physical storage buffer feature not supported");
539 
540     if (m_params->method == PassMethod::ADDRESSES_IN_SSBO)
541     {
542         if (!context.getDeviceFeatures().shaderInt64)
543             TCU_THROW(NotSupportedError, "Int64 not supported");
544     }
545 
546     if (m_params->method == PassMethod::VERTEX_IN_OUT_IN)
547     {
548         if (!context.getDeviceFeatures().shaderInt64)
549             TCU_THROW(NotSupportedError, "Int64 not supported");
550 
551         VkFormatProperties2 properties{VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, DE_NULL, {}};
552         context.getInstanceInterface().getPhysicalDeviceFormatProperties2(context.getPhysicalDevice(),
553                                                                           VK_FORMAT_R64_UINT, &properties);
554         if ((properties.formatProperties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) !=
555             VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
556             TCU_THROW(NotSupportedError, "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT not supported");
557     }
558 }
559 
createInstance(Context & ctx) const560 TestInstance *SpvAsmPhysicalStorageBufferTestCase::createInstance(Context &ctx) const
561 {
562     switch (m_params->method)
563     {
564     case PassMethod::PUSH_CONSTANTS:
565     case PassMethod::PUSH_CONSTANTS_FUNCTION:
566         return new SpvAsmPhysicalStorageBufferPushConstantsTestInstance(ctx, m_params);
567 
568     case PassMethod::VERTEX_IN_OUT_IN:
569         return new SpvAsmPhysicalStorageBufferVertexInOutInTestInstance(ctx, m_params);
570 
571     case PassMethod::ADDRESSES_IN_SSBO:
572         return new SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance(ctx, m_params);
573     }
574 
575     DE_ASSERT(false);
576     return DE_NULL;
577 }
578 
initPrograms(vk::SourceCollections & programCollection) const579 void SpvAsmPhysicalStorageBufferTestCase::initPrograms(vk::SourceCollections &programCollection) const
580 {
581     switch (m_params->method)
582     {
583     case PassMethod::PUSH_CONSTANTS:
584     case PassMethod::PUSH_CONSTANTS_FUNCTION:
585         SpvAsmPhysicalStorageBufferPushConstantsTestInstance::initPrograms(programCollection, m_params);
586         break;
587 
588     case PassMethod::VERTEX_IN_OUT_IN:
589         SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::initPrograms(programCollection, m_params);
590         break;
591 
592     case PassMethod::ADDRESSES_IN_SSBO:
593         SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance::initPrograms(programCollection, m_params);
594         break;
595     }
596 }
597 
initPrograms(SourceCollections & programCollection,const TestParamsPtr params)598 void SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::initPrograms(SourceCollections &programCollection,
599                                                                         const TestParamsPtr params)
600 {
601     DE_UNREF(params);
602 
603     const std::string vert(R"(
604         OpCapability Shader
605         OpCapability PhysicalStorageBufferAddresses
606 
607         OpExtension "SPV_KHR_physical_storage_buffer"
608         OpMemoryModel PhysicalStorageBuffer64 GLSL450
609 
610         OpEntryPoint Vertex %vert "main" %gl_PerVertex %in_pos %out_idx %gl_VertexIndex %in_addr %out_addr
611 
612         OpDecorate %PerVertex Block
613         OpDecorate %gl_VertexIndex BuiltIn VertexIndex
614         OpDecorate %in_pos Location 0
615         OpDecorate %in_addr Location 1
616         OpDecorate %in_addr RestrictPointerEXT
617         OpDecorate %out_addr RestrictPointerEXT
618         OpDecorate %out_idx Location 0
619         OpDecorate %out_addr Location 1
620 
621         OpMemberDecorate %PerVertex 0 BuiltIn Position
622         OpMemberDecorate %PerVertex 1 BuiltIn PointSize
623         OpMemberDecorate %PerVertex 2 BuiltIn ClipDistance
624         OpMemberDecorate %PerVertex 3 BuiltIn CullDistance
625 
626         OpDecorate %srta Block
627         OpMemberDecorate %srta 0 Offset 0
628 
629         OpDecorate %rta ArrayStride 16
630 
631         %void = OpTypeVoid
632         %voidf = OpTypeFunction %void
633 
634         %int = OpTypeInt 32 1
635         %flt = OpTypeFloat 32
636         %vec4 = OpTypeVector %flt 4
637         %rta = OpTypeRuntimeArray %vec4
638 
639         %zero = OpConstant %int 0
640         %one = OpConstant %int 1
641 
642         %srta = OpTypeStruct %rta
643         %srta_psb = OpTypePointer PhysicalStorageBuffer %srta
644     %srta_psb_in = OpTypePointer Input %srta_psb
645     %srta_psb_out = OpTypePointer Output %srta_psb
646         %in_addr = OpVariable %srta_psb_in Input
647         %out_addr = OpVariable %srta_psb_out Output
648 
649         %vec4_in = OpTypePointer Input %vec4
650         %vec4_out = OpTypePointer Output %vec4
651         %vec4_psb = OpTypePointer PhysicalStorageBuffer %vec4
652         %in_pos = OpVariable %vec4_in Input
653 
654         %int_in = OpTypePointer Input %int
655         %int_out = OpTypePointer Output %int
656     %gl_VertexIndex = OpVariable %int_in Input
657         %out_idx = OpVariable %int_out Output
658 
659         %flt_arr_1 = OpTypeArray %flt %one
660         %PerVertex = OpTypeStruct %vec4 %flt %flt_arr_1 %flt_arr_1
661         %pv_out = OpTypePointer Output %PerVertex
662     %gl_PerVertex = OpVariable %pv_out Output
663 
664 
665         %vert = OpFunction %void None %voidf
666         %vert_begin = OpLabel
667 
668         %vpos = OpLoad %vec4 %in_pos
669     %gl_Position = OpAccessChain %vec4_out %gl_PerVertex %zero
670                     OpStore %gl_Position %vpos
671 
672         %vidx = OpLoad %int %gl_VertexIndex
673                     OpStore %out_idx %vidx
674 
675         %vaddr = OpLoad %srta_psb %in_addr Aligned 8
676                     OpStore %out_addr %vaddr
677 
678                     OpReturn
679                     OpFunctionEnd
680     )");
681 
682     const std::string frag(R"(
683         OpCapability Shader
684         OpCapability PhysicalStorageBufferAddresses
685 
686         OpExtension "SPV_KHR_physical_storage_buffer"
687         OpMemoryModel PhysicalStorageBuffer64 GLSL450
688 
689         OpEntryPoint Fragment %frag "main" %in_idx %in_addr %dEQP_FragColor
690         OpExecutionMode %frag OriginUpperLeft
691 
692         OpDecorate %in_idx Location 0
693         OpDecorate %in_idx Flat
694         OpDecorate %in_addr Location 1
695         OpDecorate %in_addr AliasedPointerEXT
696         OpDecorate %in_addr Flat
697         OpDecorate %dEQP_FragColor Location 0
698 
699         OpDecorate %rta ArrayStride 16
700         OpDecorate %vec4_psb ArrayStride 16
701         OpDecorate %srta Block
702         OpMemberDecorate %srta 0 Offset 0
703 
704         %void = OpTypeVoid
705         %voidf = OpTypeFunction %void
706 
707         %int = OpTypeInt 32 1
708         %flt = OpTypeFloat 32
709         %vec4 = OpTypeVector %flt 4
710         %rta = OpTypeRuntimeArray %vec4
711 
712         %zero = OpConstant %int 0
713 
714         %int_in = OpTypePointer Input %int
715         %in_idx = OpVariable %int_in Input
716 
717         %vec4_out = OpTypePointer Output %vec4
718     %dEQP_FragColor = OpVariable %vec4_out Output
719 
720         %srta = OpTypeStruct %rta
721         %srta_psb = OpTypePointer PhysicalStorageBuffer %srta
722     %srta_psb_in = OpTypePointer Input %srta_psb
723         %in_addr = OpVariable %srta_psb_in Input
724         %rta_psb = OpTypePointer PhysicalStorageBuffer %rta
725         %rta_in = OpTypePointer Input %rta
726         %vec4_psb = OpTypePointer PhysicalStorageBuffer %vec4
727 
728         %frag = OpFunction %void None %voidf
729         %frag_begin = OpLabel
730 
731         %vidx = OpLoad %int %in_idx
732         %vaddr = OpLoad %srta_psb %in_addr
733         %pcolor = OpAccessChain %vec4_psb %vaddr %zero %vidx
734         %color = OpLoad %vec4 %pcolor Aligned 16
735                     OpStore %dEQP_FragColor %color
736         OpReturn
737         OpFunctionEnd
738     )");
739 
740     programCollection.spirvAsmSources.add("vert")
741         << vert << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
742     programCollection.spirvAsmSources.add("frag")
743         << frag << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
744 }
745 
prepareColorBuffer(bool flushAfter) const746 ut::TypedBuffer<tcu::Vec4> SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::prepareColorBuffer(
747     bool flushAfter) const
748 {
749     const uint32_t colorCount = 21;
750     tcu::Vec4 colors[colorCount];
751     tcu::Vec4 color(-1.0f, +1.0f, +1.0f, -1.0f);
752 
753     for (uint32_t c = 0; c < colorCount; ++c)
754     {
755         colors[c] = color;
756 
757         color[0] += 0.1f;
758         color[1] -= 0.1f;
759         color[2] -= 0.1f;
760         color[3] += 0.1f;
761     }
762 
763     ut::TypedBuffer<tcu::Vec4> buffer(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
764                                       (m_params->elements * m_params->elements), true);
765     for (auto j = buffer.begin(), begin = j; j != buffer.end(); ++j)
766     {
767         *j = colors[std::distance(begin, j) % colorCount];
768     }
769 
770     if (flushAfter)
771         buffer.flush();
772     return buffer;
773 }
774 
775 ut::TypedBuffer<SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::Attribute> SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::
prepareVertexAttributes(uint64_t address) const776     prepareVertexAttributes(uint64_t address) const
777 {
778     const float xStep  = 2.0f / static_cast<float>(m_params->elements);
779     const float yStep  = 2.0f / static_cast<float>(m_params->elements);
780     const float xStart = -1.0f + xStep / 2.0f;
781     const float yStart = -1.0f + yStep / 2.0f;
782 
783     float x = xStart;
784     float y = yStart;
785 
786     ut::TypedBuffer<Attribute> attrs(m_context, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
787                                      (m_params->elements * m_params->elements));
788 
789     for (uint32_t row = 0; row < m_params->elements; ++row)
790     {
791         for (uint32_t col = 0; col < m_params->elements; ++col)
792         {
793             Attribute &attr = attrs[(row * m_params->elements) + col];
794             attr.position   = tcu::Vec4(x, y, 0.0f, 1.0f);
795             attr.address    = address;
796 
797             x += xStep;
798         }
799         y += yStep;
800         x = xStart;
801     }
802 
803     attrs.flush();
804 
805     return attrs;
806 }
807 
createGraphicsPipeline(VkPipelineLayout pipelineLayout,VkRenderPass renderPass,VkShaderModule vertexModule,VkShaderModule fragmentModule) const808 Move<VkPipeline> SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::createGraphicsPipeline(
809     VkPipelineLayout pipelineLayout, VkRenderPass renderPass, VkShaderModule vertexModule,
810     VkShaderModule fragmentModule) const
811 {
812     const DeviceInterface &vk = m_context.getDeviceInterface();
813     const VkDevice device     = m_context.getDevice();
814     const std::vector<VkRect2D> scissors(1, makeRect2D(m_params->elements, m_params->elements));
815     const std::vector<VkViewport> viewports(1, makeViewport(m_params->elements, m_params->elements));
816 
817     const VkVertexInputBindingDescription bindingDescriptions[] = {
818         {
819             0u,                          // binding
820             sizeof(Attribute),           // stride
821             VK_VERTEX_INPUT_RATE_VERTEX, // inputRate
822         },
823     };
824 
825     const VkVertexInputAttributeDescription attributeDescriptions[] = {
826         {
827             0u,                            // location
828             0u,                            // binding
829             VK_FORMAT_R32G32B32A32_SFLOAT, // format
830             0u                             // offset
831         },
832         {
833             1u,                                                // location
834             0u,                                                // binding
835             VK_FORMAT_R64_UINT,                                // format
836             static_cast<uint32_t>(sizeof(Attribute::position)) // offset
837         },
838     };
839 
840     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
841         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
842         DE_NULL,
843         (VkPipelineVertexInputStateCreateFlags)0,  // flags
844         DE_LENGTH_OF_ARRAY(bindingDescriptions),   // vertexBindingDescriptionCount
845         bindingDescriptions,                       // pVertexBindingDescriptions
846         DE_LENGTH_OF_ARRAY(attributeDescriptions), // vertexAttributeDescriptionCount
847         attributeDescriptions                      // pVertexAttributeDescriptions
848     };
849 
850     return vk::makeGraphicsPipeline(vk,                               // vk
851                                     device,                           // device
852                                     pipelineLayout,                   // pipelineLayout
853                                     vertexModule,                     // vertexShaderModule
854                                     DE_NULL,                          // tessellationControlModule
855                                     DE_NULL,                          // tessellationEvalModule
856                                     DE_NULL,                          // geometryShaderModule
857                                     fragmentModule,                   // fragmentShaderModule
858                                     renderPass,                       // renderPass
859                                     viewports,                        // viewports
860                                     scissors,                         // scissors
861                                     VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // topology
862                                     0U,                               // subpass
863                                     0U,                               // patchControlPoints
864                                     &vertexInputStateCreateInfo,      // vertexInputStateCreateInfo
865                                     DE_NULL,                          // rasterizationStateCreateInfo
866                                     DE_NULL,                          // multisampleStateCreateInfo
867                                     DE_NULL,                          // depthStencilStateCreateInfo
868                                     DE_NULL,                          // colorBlendStateCreateInfo
869                                     DE_NULL);                         // dynamicStateCreateInfo
870 }
871 
iterate(void)872 tcu::TestStatus SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::iterate(void)
873 {
874     const DeviceInterface &vki      = m_context.getDeviceInterface();
875     const VkDevice dev              = m_context.getDevice();
876     const VkQueue queue             = m_context.getUniversalQueue();
877     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
878     const VkFormat format           = VK_FORMAT_R32G32B32A32_SFLOAT;
879     const VkRect2D renderArea       = makeRect2D(m_params->elements, m_params->elements);
880 
881     Move<VkCommandPool> cmdPool = createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
882     Move<VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
883 
884     ut::Image image(m_context, m_params->elements, m_params->elements, format);
885     Move<VkRenderPass> renderPass   = image.createRenderPass();
886     Move<VkFramebuffer> framebuffer = image.createFramebuffer(*renderPass);
887 
888     Move<VkShaderModule> vertexModule   = createShaderModule(vki, dev, m_context.getBinaryCollection().get("vert"), 0);
889     Move<VkShaderModule> fragmentModule = createShaderModule(vki, dev, m_context.getBinaryCollection().get("frag"), 0);
890     Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vki, dev, 0u, DE_NULL);
891     Move<VkPipeline> pipeline = createGraphicsPipeline(*pipelineLayout, *renderPass, *vertexModule, *fragmentModule);
892 
893     ut::TypedBuffer<tcu::Vec4> colorBuffer = prepareColorBuffer();
894     ut::TypedBuffer<Attribute> attributes  = prepareVertexAttributes(colorBuffer.getDeviceAddress());
895     const VkBuffer vertexBuffers[]         = {attributes.getBuffer()};
896     const VkDeviceSize vertexOffsets[]     = {0u};
897     const tcu::Vec4 clearColor(-1.0f);
898 
899     beginCommandBuffer(vki, *cmdBuffer);
900     vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
901     vki.cmdBindVertexBuffers(*cmdBuffer, 0, 1, vertexBuffers, vertexOffsets);
902     beginRenderPass(vki, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
903     vki.cmdDraw(*cmdBuffer, (m_params->elements * m_params->elements), 1u, 0u, 0u);
904     endRenderPass(vki, *cmdBuffer);
905     image.downloadAfterDraw(*cmdBuffer);
906     endCommandBuffer(vki, *cmdBuffer);
907 
908     submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
909 
910     ut::TypedBuffer<tcu::Vec4> resultBuffer = image.getBuffer<tcu::Vec4>();
911 
912     return std::equal(resultBuffer.begin(), resultBuffer.end(), colorBuffer.begin()) ? tcu::TestStatus::pass("") :
913                                                                                        tcu::TestStatus::fail("");
914 }
915 
initPrograms(vk::SourceCollections & programCollection,const TestParamsPtr params)916 void SpvAsmPhysicalStorageBufferPushConstantsTestInstance::initPrograms(vk::SourceCollections &programCollection,
917                                                                         const TestParamsPtr params)
918 {
919     DE_UNREF(params);
920 
921     const std::string program(R"(
922     OpCapability Shader
923     OpCapability PhysicalStorageBufferAddresses
924 
925     OpExtension "SPV_KHR_physical_storage_buffer"
926     OpMemoryModel PhysicalStorageBuffer64 GLSL450
927 
928     OpEntryPoint GLCompute %main "main" %id %str
929 
930     OpExecutionMode %main LocalSize 1 1 1
931     OpSource GLSL 450
932     OpName %main    "main"
933     OpName %id        "gl_GlobalInvocationID"
934     OpName %src        "source"
935     OpName %dst        "destination"
936     OpName %src_buf    "source"
937     OpName %dst_buf    "destination"
938     OpDecorate %id BuiltIn GlobalInvocationId
939 
940     OpDecorate %str_t Block
941     OpMemberDecorate %str_t 0 Offset 0
942     OpMemberDecorate %str_t 1 Offset 8
943     OpMemberDecorate %str_t 2 Offset 16
944     OpMemberDecorate %str_t 3 Offset 20
945 
946     OpDecorate %src_buf Restrict
947     OpDecorate %dst_buf Restrict
948 
949     OpDecorate %int_arr ArrayStride 4
950 
951             %int = OpTypeInt 32 1
952         %int_ptr = OpTypePointer PhysicalStorageBuffer %int
953        %int_fptr = OpTypePointer Function %int
954            %zero = OpConstant %int 0
955             %one = OpConstant %int 1
956             %two = OpConstant %int 2
957           %three = OpConstant %int 3
958 
959            %uint = OpTypeInt 32 0
960        %uint_ptr = OpTypePointer Input %uint
961       %uint_fptr = OpTypePointer Function %uint
962           %uvec3 = OpTypeVector %uint 3
963       %uvec3ptr  = OpTypePointer Input %uvec3
964           %uzero = OpConstant %uint 0
965              %id = OpVariable %uvec3ptr Input
966 
967         %int_arr = OpTypeRuntimeArray %int
968 
969         %buf_ptr = OpTypePointer PhysicalStorageBuffer %int_arr
970           %str_t = OpTypeStruct %buf_ptr %buf_ptr %int %int
971         %str_ptr = OpTypePointer PushConstant %str_t
972             %str = OpVariable %str_ptr PushConstant
973     %buf_ptr_fld = OpTypePointer PushConstant %buf_ptr
974         %int_fld = OpTypePointer PushConstant %int
975 
976            %bool = OpTypeBool
977            %void = OpTypeVoid
978           %voidf = OpTypeFunction %void
979        %cpbuffsf = OpTypeFunction %void %buf_ptr %buf_ptr %int
980 
981         %cpbuffs = OpFunction %void None %cpbuffsf
982         %src_buf = OpFunctionParameter %buf_ptr
983         %dst_buf = OpFunctionParameter %buf_ptr
984        %elements = OpFunctionParameter %int
985        %cp_begin = OpLabel
986               %j = OpVariable %int_fptr Function
987                    OpStore %j %zero
988                    OpBranch %for
989             %for = OpLabel
990              %vj = OpLoad %int %j
991              %cj = OpULessThan %bool %vj %elements
992                    OpLoopMerge %for_end %incj None
993                    OpBranchConditional %cj %for_body %for_end
994        %for_body = OpLabel
995      %src_el_lnk = OpAccessChain %int_ptr %src_buf %vj
996      %dst_el_lnk = OpAccessChain %int_ptr %dst_buf %vj
997          %src_el = OpLoad %int %src_el_lnk Aligned 4
998                    OpStore %dst_el_lnk %src_el Aligned 4
999                    OpBranch %incj
1000            %incj = OpLabel
1001              %nj = OpIAdd %int %vj %one
1002                    OpStore %j %nj
1003                    OpBranch %for
1004         %for_end = OpLabel
1005                    OpReturn
1006                    OpFunctionEnd
1007 
1008            %main = OpFunction %void None %voidf
1009           %begin = OpLabel
1010               %i = OpVariable %int_fptr Function
1011                    OpStore %i %zero
1012         %src_lnk = OpAccessChain %buf_ptr_fld %str %zero
1013         %dst_lnk = OpAccessChain %buf_ptr_fld %str %one
1014         %cnt_lnk = OpAccessChain %int_fld %str %two
1015     %use_fun_lnk = OpAccessChain %int_fld %str %three
1016             %src = OpLoad %buf_ptr %src_lnk
1017             %dst = OpLoad %buf_ptr %dst_lnk
1018             %cnt = OpLoad %int %cnt_lnk
1019         %use_fun = OpLoad %int %use_fun_lnk
1020 
1021             %cuf = OpINotEqual %bool %use_fun %zero
1022                    OpSelectionMerge %use_fun_end None
1023                    OpBranchConditional %cuf %copy %loop
1024            %copy = OpLabel
1025          %unused = OpFunctionCall %void %cpbuffs %src %dst %cnt
1026                    OpBranch %use_fun_end
1027            %loop = OpLabel
1028              %vi = OpLoad %int %i
1029              %ci = OpSLessThan %bool %vi %cnt
1030                    OpLoopMerge %loop_end %inci None
1031                    OpBranchConditional %ci %loop_body %loop_end
1032       %loop_body = OpLabel
1033      %src_px_lnk = OpAccessChain %int_ptr %src %vi
1034      %dst_px_lnk = OpAccessChain %int_ptr %dst %vi
1035          %src_px = OpLoad %int %src_px_lnk Aligned 4
1036                    OpStore %dst_px_lnk %src_px Aligned 4
1037                    OpBranch %inci
1038            %inci = OpLabel
1039              %ni = OpIAdd %int %vi %one
1040                    OpStore %i %ni
1041                    OpBranch %loop
1042        %loop_end = OpLabel
1043                    OpBranch %use_fun_end
1044     %use_fun_end = OpLabel
1045 
1046                    OpReturn
1047                    OpFunctionEnd
1048     )");
1049 
1050     programCollection.spirvAsmSources.add("comp")
1051         << program << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
1052 }
1053 
iterate(void)1054 tcu::TestStatus SpvAsmPhysicalStorageBufferPushConstantsTestInstance::iterate(void)
1055 {
1056     const DeviceInterface &vki      = m_context.getDeviceInterface();
1057     const VkDevice dev              = m_context.getDevice();
1058     const VkQueue queue             = m_context.getUniversalQueue();
1059     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1060 
1061     Move<VkCommandPool> cmdPool = createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1062     Move<VkCommandBuffer> cmdBuffer   = allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1063     Move<VkShaderModule> shaderModule = createShaderModule(vki, dev, m_context.getBinaryCollection().get("comp"), 0);
1064 
1065     struct PushConstant
1066     {
1067         uint64_t src;
1068         uint64_t dst;
1069         int32_t cnt;
1070         bool use_fun;
1071     };
1072 
1073     VkPushConstantRange pushConstantRange = {
1074         VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags stageFlags;
1075         0,                           // uint32_t offset;
1076         sizeof(PushConstant)         // uint32_t size;
1077     };
1078 
1079     Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vki, dev, 0, DE_NULL, 1, &pushConstantRange);
1080     Move<VkPipeline> pipeline             = makeComputePipeline(vki, dev, *pipelineLayout, *shaderModule);
1081 
1082     ut::TypedBuffer<int32_t> src(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1083     ut::TypedBuffer<int32_t> dst(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1084 
1085     src.iota(m_params->elements, true);
1086     dst.zero(true);
1087 
1088     const PushConstant pc = {src.getDeviceAddress(), dst.getDeviceAddress(), int32_t(m_params->elements),
1089                              m_params->method == PassMethod::PUSH_CONSTANTS_FUNCTION};
1090 
1091     beginCommandBuffer(vki, *cmdBuffer);
1092     vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1093     vki.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc);
1094     vki.cmdDispatch(*cmdBuffer, 1, 1, 1);
1095     endCommandBuffer(vki, *cmdBuffer);
1096 
1097     submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
1098 
1099     dst.invalidate();
1100 
1101     return std::equal(src.begin(), src.end(), dst.begin()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
1102 }
1103 
initPrograms(vk::SourceCollections & programCollection,const TestParamsPtr params)1104 void SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance::initPrograms(vk::SourceCollections &programCollection,
1105                                                                       const TestParamsPtr params)
1106 {
1107     DE_UNREF(params);
1108 
1109     const std::string comp(R"(
1110     OpCapability Shader
1111     OpCapability Int64
1112     OpCapability PhysicalStorageBufferAddresses
1113 
1114     OpExtension "SPV_KHR_physical_storage_buffer"
1115     OpMemoryModel PhysicalStorageBuffer64 GLSL450
1116 
1117     OpEntryPoint GLCompute %comp "main" %id %ssbo
1118 
1119     OpExecutionMode %comp LocalSize 1 1 1
1120     OpDecorate %id BuiltIn GlobalInvocationId
1121 
1122     OpDecorate %sssbo Block
1123     OpMemberDecorate %sssbo 0 Offset 0
1124     OpMemberDecorate %sssbo 1 Offset 8
1125     OpMemberDecorate %sssbo 2 Offset 16
1126     OpMemberDecorate %sssbo 3 Offset 24
1127 
1128     OpDecorate %ssbo DescriptorSet 0
1129     OpDecorate %ssbo Binding 0
1130 
1131     OpDecorate %rta ArrayStride 4
1132 
1133     %bool = OpTypeBool
1134     %int = OpTypeInt 32 1
1135     %uint = OpTypeInt 32 0
1136     %ulong = OpTypeInt 64 0
1137 
1138     %zero = OpConstant %int 0
1139     %one = OpConstant %int 1
1140     %two = OpConstant %int 2
1141     %three = OpConstant %int 3
1142 
1143     %uvec3 = OpTypeVector %uint 3
1144     %rta = OpTypeRuntimeArray %int
1145 
1146     %rta_psb = OpTypePointer PhysicalStorageBuffer %rta
1147     %sssbo = OpTypeStruct %rta_psb %ulong %rta_psb %ulong
1148     %sssbo_buf = OpTypePointer StorageBuffer %sssbo
1149     %ssbo = OpVariable %sssbo_buf StorageBuffer
1150     %rta_psb_sb = OpTypePointer StorageBuffer %rta_psb
1151     %int_psb = OpTypePointer PhysicalStorageBuffer %int
1152     %ulong_sb = OpTypePointer StorageBuffer %ulong
1153 
1154     %uvec3_in = OpTypePointer Input %uvec3
1155     %id = OpVariable %uvec3_in Input
1156     %uint_in = OpTypePointer Input %uint
1157 
1158     %void = OpTypeVoid
1159     %voidf = OpTypeFunction %void
1160 
1161     %comp = OpFunction %void None %voidf
1162     %comp_begin = OpLabel
1163 
1164         %pgid_x = OpAccessChain %uint_in %id %zero
1165         %gid_x = OpLoad %uint %pgid_x
1166         %mod2 = OpSMod %int %gid_x %two
1167         %even = OpIEqual %bool %mod2 %zero
1168 
1169         %psrc_buff_p = OpAccessChain %rta_psb_sb %ssbo %zero
1170         %pdst_buff_p = OpAccessChain %rta_psb_sb %ssbo %two
1171         %src_buff_p = OpLoad %rta_psb %psrc_buff_p
1172         %dst_buff_p = OpLoad %rta_psb %pdst_buff_p
1173 
1174         %psrc_buff_u = OpAccessChain %ulong_sb %ssbo %one
1175         %psrc_buff_v = OpLoad %ulong %psrc_buff_u
1176         %src_buff_v = OpConvertUToPtr %rta_psb %psrc_buff_v
1177         %pdst_buff_u = OpAccessChain %ulong_sb %ssbo %three
1178         %pdst_buff_v = OpLoad %ulong %pdst_buff_u
1179         %dst_buff_v = OpConvertUToPtr %rta_psb %pdst_buff_v
1180 
1181         %src = OpSelect %rta_psb %even %src_buff_p %src_buff_v
1182         %dst = OpSelect %rta_psb %even %dst_buff_v %dst_buff_p
1183 
1184         %psrc_color = OpAccessChain %int_psb %src %gid_x
1185         %src_color = OpLoad %int %psrc_color Aligned 4
1186         %pdst_color = OpAccessChain %int_psb %dst %gid_x
1187         OpStore %pdst_color %src_color Aligned 4
1188 
1189     OpReturn
1190     OpFunctionEnd
1191     )");
1192 
1193     programCollection.spirvAsmSources.add("comp")
1194         << comp << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
1195 }
1196 
1197 /*
1198  Below test does not add anything new. The main purpose of this test is to show that both PhysicalStorageBuffer
1199  and 64-bit integer value can coexist in one array one next to the other. In the both cases, when the one address
1200  has its own dedicated storage class and the other is regular integer, the shader is responsible for how to interpret
1201  and use input addresses. Regardless of the shader, the application always passes them as 64-bit integers.
1202 */
iterate(void)1203 tcu::TestStatus SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance::iterate(void)
1204 {
1205     const DeviceInterface &vki      = m_context.getDeviceInterface();
1206     const VkDevice dev              = m_context.getDevice();
1207     const VkQueue queue             = m_context.getUniversalQueue();
1208     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1209 
1210     Move<VkCommandPool> cmdPool = createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1211     Move<VkCommandBuffer> cmdBuffer   = allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1212     Move<VkShaderModule> shaderModule = createShaderModule(vki, dev, m_context.getBinaryCollection().get("comp"), 0);
1213 
1214     Move<VkDescriptorSetLayout> descriptorSetLayout =
1215         DescriptorSetLayoutBuilder()
1216             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1217             .build(vki, dev);
1218     Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
1219                                                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1220                                                 .build(vki, dev, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1221     Move<VkDescriptorSet> descriptorSet   = makeDescriptorSet(vki, dev, *descriptorPool, *descriptorSetLayout);
1222     Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vki, dev, 1u, &descriptorSetLayout.get());
1223     Move<VkPipeline> pipeline             = makeComputePipeline(vki, dev, *pipelineLayout, *shaderModule);
1224 
1225     ut::TypedBuffer<int32_t> src(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1226     ut::TypedBuffer<int32_t> dst(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1227 
1228     struct SSBO
1229     {
1230         uint64_t srcAsBuff;
1231         uint64_t srcAsUint;
1232         uint64_t dstAsBuff;
1233         uint64_t dstAsUint;
1234     };
1235     ut::TypedBuffer<SSBO> ssbo(
1236         m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
1237         {{src.getDeviceAddress(), src.getDeviceAddress(), dst.getDeviceAddress(), dst.getDeviceAddress()}});
1238     VkDescriptorBufferInfo ssboBufferInfo = makeDescriptorBufferInfo(ssbo.getBuffer(), 0, ssbo.getSize());
1239     DescriptorSetUpdateBuilder()
1240         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
1241                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboBufferInfo)
1242         .update(vki, dev);
1243 
1244     src.iota(m_params->elements, true);
1245     dst.zero(true);
1246 
1247     beginCommandBuffer(vki, *cmdBuffer);
1248     vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1249     vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(),
1250                               0u, DE_NULL);
1251     vki.cmdDispatch(*cmdBuffer, m_params->elements, 1, 1);
1252     endCommandBuffer(vki, *cmdBuffer);
1253 
1254     submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
1255 
1256     dst.invalidate();
1257 
1258     return std::equal(src.begin(), src.end(), dst.begin()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
1259 }
1260 
1261 } // namespace
1262 
createPhysicalStorageBufferTestGroup(tcu::TestContext & testCtx)1263 tcu::TestCaseGroup *createPhysicalStorageBufferTestGroup(tcu::TestContext &testCtx)
1264 {
1265     struct
1266     {
1267         PassMethod method;
1268         std::string testName;
1269     } const methods[] = {
1270         {PassMethod::PUSH_CONSTANTS, "push_constants"},
1271         {PassMethod::PUSH_CONSTANTS_FUNCTION, "push_constants_function"},
1272         {PassMethod::VERTEX_IN_OUT_IN, "vertex_in_out_in"},
1273         {PassMethod::ADDRESSES_IN_SSBO, "addrs_in_ssbo"},
1274     };
1275 
1276     tcu::TestCaseGroup *group = new tcu::TestCaseGroup(testCtx, "physical_storage_buffer");
1277 
1278     for (const auto &method : methods)
1279     {
1280         group->addChild(new SpvAsmPhysicalStorageBufferTestCase(testCtx, method.testName,
1281                                                                 TestParamsPtr(new TestParams({method.method, 64}))));
1282     }
1283 
1284     return group;
1285 }
1286 
1287 } // namespace SpirVAssembly
1288 } // namespace vkt
1289