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