1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file vktGlobalPriorityQueueTests.cpp
21 * \brief Global Priority Queue Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktGlobalPriorityQueueTests.hpp"
25 #include "vktGlobalPriorityQueueUtils.hpp"
26
27 #include "vkBarrierUtil.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "../image/vktImageTestsUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkObjUtil.hpp"
35 #include "vkStrUtil.hpp"
36 #include "vkRefUtil.hpp"
37
38 #include "vktTestGroupUtil.hpp"
39 #include "vktTestCase.hpp"
40
41 #include "deDefs.h"
42 #include "deMath.h"
43 #include "deRandom.h"
44 #include "deRandom.hpp"
45 #include "deSharedPtr.hpp"
46 #include "deString.h"
47 #include "deMemory.h"
48
49 #include "tcuStringTemplate.hpp"
50
51 #include <string>
52 #include <sstream>
53 #include <map>
54
55 using namespace vk;
56
57 namespace vkt
58 {
59 namespace synchronization
60 {
61 namespace
62 {
63
64 enum class SyncType
65 {
66 None,
67 Semaphore
68 };
69
70 struct TestConfig
71 {
72 VkQueueFlagBits transitionFrom;
73 VkQueueFlagBits transitionTo;
74 VkQueueGlobalPriorityKHR priorityFrom;
75 VkQueueGlobalPriorityKHR priorityTo;
76 bool enableProtected;
77 bool enableSparseBinding;
78 SyncType syncType;
79 deUint32 width;
80 deUint32 height;
81 VkFormat format;
82 bool selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats);
83 };
84
selectFormat(const InstanceInterface & vk,VkPhysicalDevice dev,std::initializer_list<VkFormat> formats)85 bool TestConfig::selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats)
86 {
87 auto doesFormatMatch = [](const VkFormat fmt) -> bool
88 {
89 const auto tcuFmt = mapVkFormat(fmt);
90 return tcuFmt.order == tcu::TextureFormat::ChannelOrder::R;
91 };
92 VkFormatProperties2 props{};
93 const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
94 | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
95 for (auto i = formats.begin(); i != formats.end(); ++i)
96 {
97 props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
98 props.pNext = nullptr;
99 props.formatProperties = {};
100 const VkFormat fmt = *i;
101 vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
102 if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
103 {
104 this->format = fmt;
105 return true;
106 }
107 }
108 return false;
109 }
110
111 struct CheckerboardBuilder
112 {
CheckerboardBuildervkt::synchronization::__anon66461ea50111::CheckerboardBuilder113 CheckerboardBuilder (uint32_t width, uint32_t height)
114 : m_width(width), m_height(height) {}
115
blackFieldCountvkt::synchronization::__anon66461ea50111::CheckerboardBuilder116 static uint32_t blackFieldCount (uint32_t w, uint32_t h)
117 {
118 return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2);
119 }
120
blackFieldCountvkt::synchronization::__anon66461ea50111::CheckerboardBuilder121 uint32_t blackFieldCount () const
122 {
123 return blackFieldCount(m_width, m_height);
124 }
125
fieldIndexvkt::synchronization::__anon66461ea50111::CheckerboardBuilder126 uint32_t fieldIndex (uint32_t x, uint32_t y) const
127 {
128 return blackFieldCount(m_width, y) + (x / 2);
129 }
130
buildVerticesAndIndicesvkt::synchronization::__anon66461ea50111::CheckerboardBuilder131 void buildVerticesAndIndices (std::vector<float>& vertices, std::vector<uint32_t>& indices) const
132 {
133 const uint32_t vertPerQuad = 4;
134 const uint32_t indexPerQuad = 6;
135 const uint32_t quadCount = blackFieldCount();
136 const uint32_t compPerQuad = vertPerQuad * 2;
137 const uint32_t vertCount = quadCount * vertPerQuad;
138 const uint32_t indexCount = quadCount * indexPerQuad;
139
140 vertices.resize(vertCount * 2);
141 indices.resize(indexCount);
142
143 for (uint32_t z = 0; z < 2; ++z)
144 for (uint32_t y = 0; y < m_height; ++y)
145 for (uint32_t x = 0; x < m_width; ++x)
146 {
147 if (((x + y) % 2) == 1)
148 continue;
149
150 const float x1 = float(x) / float(m_width);
151 const float y1 = float(y) / float(m_height);
152 const float x2 = (float(x) + 1.0f) / float(m_width);
153 const float y2 = (float(y) + 1.0f) / float(m_height);
154
155 const float xx1 = x1 * 2.0f - 1.0f;
156 const float yy1 = y1 * 2.0f - 1.0f;
157 const float xx2 = x2 * 2.0f - 1.0f;
158 const float yy2 = y2 * 2.0f - 1.0f;
159
160 const uint32_t quad = fieldIndex(x, y);
161
162 if (z == 0)
163 {
164 vertices[ quad * compPerQuad + 0 ] = xx1;
165 vertices[ quad * compPerQuad + 1 ] = yy1;
166 vertices[ quad * compPerQuad + 2 ] = xx2;
167 vertices[ quad * compPerQuad + 3 ] = yy1;
168
169 indices[ quad * indexPerQuad + 0 ] = quad * vertPerQuad + 0;
170 indices[ quad * indexPerQuad + 1 ] = quad * vertPerQuad + 1;
171 indices[ quad * indexPerQuad + 2 ] = quad * vertPerQuad + 2;
172 }
173 else
174 {
175 vertices[ quad * compPerQuad + 4 ] = xx2;
176 vertices[ quad * compPerQuad + 5 ] = yy2;
177 vertices[ quad * compPerQuad + 6 ] = xx1;
178 vertices[ quad * compPerQuad + 7 ] = yy2;
179
180 indices[ quad * indexPerQuad + 3 ] = quad * vertPerQuad + 2;
181 indices[ quad * indexPerQuad + 4 ] = quad * vertPerQuad + 3;
182 indices[ quad * indexPerQuad + 5 ] = quad * vertPerQuad + 0;
183 }
184 }
185 }
186
187 private:
188 uint32_t m_width;
189 uint32_t m_height;
190 };
191
192 template<class T, class P = T(*)[1]>
begin(void * p)193 auto begin (void* p) -> decltype(std::begin(*std::declval<P>()))
194 {
195 return std::begin(*static_cast<P>(p));
196 }
197
198 class GPQInstanceBase : public TestInstance
199 {
200 public:
201 typedef std::initializer_list<VkDescriptorSetLayout> DSLayouts;
202 typedef tcu::ConstPixelBufferAccess BufferAccess;
203
204 GPQInstanceBase (Context& ctx,
205 const TestConfig& cfg);
206 template<class PushConstant = void>
207 auto createPipelineLayout (DSLayouts setLayouts) const -> Move<VkPipelineLayout>;
208 auto createGraphicsPipeline (VkPipelineLayout pipelineLayout,
209 VkRenderPass renderPass) -> Move<VkPipeline>;
210 auto createComputePipeline (VkPipelineLayout pipelineLayout) -> Move<VkPipeline>;
211 auto createImage (VkImageUsageFlags usage,
212 deUint32 queueFamilyIdx,
213 VkQueue queue) const -> de::MovePtr<ImageWithMemory>;
214 auto createView (VkImage image,
215 VkImageSubresourceRange& range) const -> Move<VkImageView>;
216 void submitCommands (VkCommandBuffer producerCmd,
217 VkCommandBuffer consumerCmd) const;
218 bool verify (const BufferAccess& result,
219 deUint32 blackColor,
220 deUint32 whiteColor) const;
221 protected:
222 auto createPipelineLayout (const VkPushConstantRange* pRange,
223 DSLayouts setLayouts) const -> Move<VkPipelineLayout>;
224 const TestConfig m_config;
225 const SpecialDevice m_device;
226 Move<VkShaderModule> m_vertex;
227 Move<VkShaderModule> m_fragment;
228 Move<VkShaderModule> m_compute;
229 };
GPQInstanceBase(Context & ctx,const TestConfig & cfg)230 GPQInstanceBase::GPQInstanceBase (Context& ctx, const TestConfig& cfg)
231 : TestInstance (ctx)
232 , m_config (cfg)
233 , m_device (ctx,
234 cfg.transitionFrom, cfg.transitionTo,
235 cfg.priorityFrom, cfg.priorityTo,
236 cfg.enableProtected, cfg.enableSparseBinding)
237 , m_vertex ()
238 , m_fragment ()
239 , m_compute ()
240 {
241 }
242
createImage(VkImageUsageFlags usage,deUint32 queueFamilyIdx,VkQueue queue) const243 de::MovePtr<ImageWithMemory> GPQInstanceBase::createImage (VkImageUsageFlags usage, deUint32 queueFamilyIdx, VkQueue queue) const
244 {
245 const InstanceInterface& vki = m_context.getInstanceInterface();
246 const DeviceInterface& vkd = m_context.getDeviceInterface();
247 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
248 const VkDevice dev = m_device.device;
249 Allocator& alloc = m_device.getAllocator();
250 VkImageCreateFlags flags = 0;
251
252 if (m_config.enableProtected) flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
253 if (m_config.enableSparseBinding) flags |= (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT);
254
255 VkImageCreateInfo imageInfo{};
256 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
257 imageInfo.pNext = nullptr;
258 imageInfo.flags = flags;
259 imageInfo.imageType = VK_IMAGE_TYPE_2D;
260 imageInfo.format = m_config.format;
261 imageInfo.extent.width = m_config.width;
262 imageInfo.extent.height = m_config.height;
263 imageInfo.extent.depth = 1;
264 imageInfo.mipLevels = 1;
265 imageInfo.arrayLayers = 1;
266 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
267 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
268 imageInfo.usage = usage;
269 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
270 imageInfo.queueFamilyIndexCount = 1;
271 imageInfo.pQueueFamilyIndices = &queueFamilyIdx;
272 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
273
274 return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vki, vkd, phys, dev, alloc, imageInfo, queue));
275 }
276
createView(VkImage image,VkImageSubresourceRange & range) const277 Move<VkImageView> GPQInstanceBase::createView (VkImage image, VkImageSubresourceRange& range) const
278 {
279 const DeviceInterface& vkd = m_context.getDeviceInterface();
280 const VkDevice dev = m_device.device;
281
282 range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
283 return makeImageView(vkd, dev, image, VK_IMAGE_VIEW_TYPE_2D, m_config.format, range);
284 }
285
createPipelineLayout(const VkPushConstantRange * pRange,DSLayouts setLayouts) const286 Move<VkPipelineLayout> GPQInstanceBase::createPipelineLayout (const VkPushConstantRange* pRange, DSLayouts setLayouts) const
287 {
288 std::vector<VkDescriptorSetLayout> layouts(setLayouts.size());
289 auto ii = setLayouts.begin();
290 for (auto i = ii; i != setLayouts.end(); ++i)
291 layouts[std::distance(ii, i)] = *i;
292
293 VkPipelineLayoutCreateInfo info{};
294 info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
295 info.pNext = nullptr;
296 info.flags = VkPipelineLayoutCreateFlags(0);
297 info.setLayoutCount = static_cast<uint32_t>(layouts.size());
298 info.pSetLayouts = layouts.size() ? layouts.data() : nullptr;
299 info.pushConstantRangeCount = pRange ? 1 : 0;
300 info.pPushConstantRanges = pRange;
301
302 return ::vk::createPipelineLayout(m_context.getDeviceInterface(), m_device.device, &info);
303 }
304
createPipelineLayout(DSLayouts setLayouts) const305 template<> Move<VkPipelineLayout> DE_UNUSED_FUNCTION GPQInstanceBase::createPipelineLayout<void> (DSLayouts setLayouts) const
306 {
307 return createPipelineLayout(nullptr, setLayouts);
308 }
309
createPipelineLayout(DSLayouts setLayouts) const310 template<class PushConstant> Move<VkPipelineLayout> GPQInstanceBase::createPipelineLayout (DSLayouts setLayouts) const
311 {
312 VkPushConstantRange range{};
313 range.stageFlags = VK_SHADER_STAGE_ALL;
314 range.offset = 0;
315 range.size = static_cast<uint32_t>(sizeof(PushConstant));
316 return createPipelineLayout(&range, setLayouts);
317 }
318
createGraphicsPipeline(VkPipelineLayout pipelineLayout,VkRenderPass renderPass)319 Move<VkPipeline> GPQInstanceBase::createGraphicsPipeline (VkPipelineLayout pipelineLayout, VkRenderPass renderPass)
320 {
321 const DeviceInterface& vkd = m_context.getDeviceInterface();
322 const VkDevice dev = m_device.device;
323
324 m_vertex = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("vert"));
325 m_fragment = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("frag"));
326
327 const std::vector<VkViewport> viewports { makeViewport(m_config.width, m_config.height) };
328 const std::vector<VkRect2D> scissors { makeRect2D(m_config.width, m_config.height) };
329 const auto vertexBinding = makeVertexInputBindingDescription(0u, static_cast<deUint32>(2 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
330 const auto vertexAttrib = makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u);
331 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
332 {
333 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
334 nullptr, // const void* pNext;
335 0u, // VkPipelineVertexInputStateCreateFlags flags;
336 1u, // deUint32 vertexBindingDescriptionCount;
337 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
338 1u, // deUint32 vertexAttributeDescriptionCount;
339 &vertexAttrib // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
340 };
341
342 return makeGraphicsPipeline(vkd, dev, pipelineLayout,*m_vertex,VkShaderModule(0),
343 VkShaderModule(0),VkShaderModule(0),*m_fragment,renderPass,viewports, scissors,
344 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,0,0,&vertexInputStateCreateInfo);
345
346
347 }
348
createComputePipeline(VkPipelineLayout pipelineLayout)349 Move<VkPipeline> GPQInstanceBase::createComputePipeline (VkPipelineLayout pipelineLayout)
350 {
351 const DeviceInterface& vk = m_context.getDeviceInterface();
352 const VkDevice dev = m_device.device;
353
354 m_compute = createShaderModule(vk, dev, m_context.getBinaryCollection().get("comp"));
355
356 VkPipelineShaderStageCreateInfo sci{};
357 sci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
358 sci.pNext = nullptr;
359 sci.flags = VkPipelineShaderStageCreateFlags(0);
360 sci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
361 sci.module = *m_compute;
362 sci.pName = "main";
363 sci.pSpecializationInfo = nullptr;
364
365 VkComputePipelineCreateInfo ci{};
366 ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
367 ci.pNext = nullptr;
368 ci.flags = VkPipelineCreateFlags(0);
369 ci.stage = sci;
370 ci.layout = pipelineLayout;
371 ci.basePipelineHandle = VkPipeline(0);
372 ci.basePipelineIndex = 0;
373
374 return vk::createComputePipeline(vk, dev, VkPipelineCache(0), &ci, nullptr);
375 }
376
377 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit);
submitCommands(VkCommandBuffer producerCmd,VkCommandBuffer consumerCmd) const378 void GPQInstanceBase::submitCommands (VkCommandBuffer producerCmd, VkCommandBuffer consumerCmd) const
379 {
380 const DeviceInterface& vkd = m_context.getDeviceInterface();
381 const VkDevice dev = m_device.device;
382
383 Move<VkSemaphore> sem = createSemaphore(vkd, dev);
384 Move<VkFence> fence = createFence(vkd, dev);
385
386 const VkSubmitInfo semSubmitProducer
387 {
388 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
389 nullptr, // const void* pNext;
390 0, // deUint32 waitSemaphoreCount;
391 nullptr, // const VkSemaphore* pWaitSemaphores;
392 nullptr, // const VkPipelineStageFlags* pWaitDstStageMask;
393 1u, // deUint32 commandBufferCount;
394 &producerCmd, // const VkCommandBuffer* pCommandBuffers;
395 1u, // deUint32 signalSemaphoreCount;
396 &sem.get(), // const VkSemaphore* pSignalSemaphores;
397 };
398
399 const VkPipelineStageFlags dstWaitStages = VK_PIPELINE_STAGE_TRANSFER_BIT |
400 queueFlagBitToPipelineStage(m_config.transitionTo);
401 const VkSubmitInfo semSubmitConsumer
402 {
403 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
404 nullptr, // const void* pNext;
405 1u, // deUint32 waitSemaphoreCount;
406 &(*sem), // const VkSemaphore* pWaitSemaphores;
407 &dstWaitStages, // const VkPipelineStageFlags* pWaitDstStageMask;
408 1u, // deUint32 commandBufferCount;
409 &consumerCmd, // const VkCommandBuffer* pCommandBuffers;
410 0, // deUint32 signalSemaphoreCount;
411 nullptr, // const VkSemaphore* pSignalSemaphores;
412 };
413
414 switch (m_config.syncType)
415 {
416 case SyncType::None:
417 submitCommandsAndWait(vkd, dev, m_device.queueFrom, producerCmd);
418 submitCommandsAndWait(vkd, dev, m_device.queueTo, consumerCmd);
419 break;
420 case SyncType::Semaphore:
421 VK_CHECK(vkd.queueSubmit(m_device.queueFrom, 1u, &semSubmitProducer, VkFence(0)));
422 VK_CHECK(vkd.queueSubmit(m_device.queueTo, 1u, &semSubmitConsumer, *fence));
423 VK_CHECK(vkd.waitForFences(dev, 1u, &fence.get(), DE_TRUE, ~0ull));
424 break;
425 }
426 }
427
428 template<VkQueueFlagBits, VkQueueFlagBits> class GPQInstance;
429 #define DECLARE_INSTANCE(flagsFrom_, flagsTo_) \
430 template<> class GPQInstance<flagsFrom_, flagsTo_> : public GPQInstanceBase \
431 { public: GPQInstance (Context& ctx, const TestConfig& cfg) \
432 : GPQInstanceBase(ctx, cfg) { } \
433 virtual tcu::TestStatus iterate (void) override; }
434
435 DECLARE_INSTANCE(VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT);
436 DECLARE_INSTANCE(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT);
437
438 class GPQCase;
439 typedef TestInstance* (GPQCase::* CreateInstanceProc)(Context&) const;
440 typedef std::pair<VkQueueFlagBits,VkQueueFlagBits> CreateInstanceKey;
441 typedef std::map<CreateInstanceKey, CreateInstanceProc> CreateInstanceMap;
442 #define MAPENTRY(from_,to_) m_createInstanceMap[{from_,to_}] = &GPQCase::createInstance<from_,to_>
443
444 class GPQCase : public TestCase
445 {
446 public:
447 GPQCase (tcu::TestContext& ctx,
448 const std::string& name,
449 const TestConfig& cfg,
450 const std::string& desc = {});
451 void initPrograms (SourceCollections& programs) const override;
452 TestInstance* createInstance (Context& context) const override;
453 void checkSupport (Context& context) const override;
454 static deUint32 testValue;
455
456 private:
457 template<VkQueueFlagBits, VkQueueFlagBits>
458 TestInstance* createInstance (Context& context) const;
459 mutable TestConfig m_config;
460 CreateInstanceMap m_createInstanceMap;
461 };
462 deUint32 GPQCase::testValue = 113;
463
GPQCase(tcu::TestContext & ctx,const std::string & name,const TestConfig & cfg,const std::string & desc)464 GPQCase::GPQCase (tcu::TestContext& ctx,
465 const std::string& name,
466 const TestConfig& cfg,
467 const std::string& desc)
468 : TestCase (ctx, name, desc)
469 , m_config (cfg)
470 , m_createInstanceMap ()
471 {
472 MAPENTRY(VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT);
473 MAPENTRY(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT);
474 }
475
queueFlagBitToPipelineStage(VkQueueFlagBits bit)476 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit)
477 {
478 switch (bit) {
479 case VK_QUEUE_COMPUTE_BIT:
480 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
481 case VK_QUEUE_GRAPHICS_BIT:
482 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
483 default:
484 DE_ASSERT(VK_FALSE);
485 }
486 return VK_QUEUE_FLAG_BITS_MAX_ENUM;
487 }
488
489 template<VkQueueFlagBits flagsFrom, VkQueueFlagBits flagsTo>
createInstance(Context & context) const490 TestInstance* GPQCase::createInstance (Context& context) const
491 {
492 return new GPQInstance<flagsFrom, flagsTo>(context, m_config);
493 }
494
createInstance(Context & context) const495 TestInstance* GPQCase::createInstance (Context& context) const
496 {
497 const CreateInstanceKey key(m_config.transitionFrom, m_config.transitionTo);
498 return (this->*(m_createInstanceMap.at(key)))(context);
499 }
500
operator <<(std::ostream & str,const VkQueueFlagBits & bit)501 std::ostream& operator<<(std::ostream& str, const VkQueueFlagBits& bit)
502 {
503 const char* s = nullptr;
504 const auto d = std::to_string(bit);
505 switch (bit)
506 {
507 case VK_QUEUE_GRAPHICS_BIT: s = "VK_QUEUE_GRAPHICS_BIT"; break;
508 case VK_QUEUE_COMPUTE_BIT: s = "VK_QUEUE_COMPUTE_BIT"; break;
509 case VK_QUEUE_TRANSFER_BIT: s = "VK_QUEUE_TRANSFER_BIT"; break;
510 case VK_QUEUE_SPARSE_BINDING_BIT: s = "VK_QUEUE_SPARSE_BINDING_BIT"; break;
511 case VK_QUEUE_PROTECTED_BIT: s = "VK_QUEUE_PROTECTED_BIT"; break;
512 default: s = d.c_str(); break;
513 }
514 return (str << s);
515 }
516
checkSupport(Context & context) const517 void GPQCase::checkSupport (Context& context) const
518 {
519 const InstanceInterface& vki = context.getInstanceInterface();
520 const VkPhysicalDevice dev = context.getPhysicalDevice();
521
522 context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
523 context.requireDeviceFunctionality("VK_EXT_global_priority");
524
525 if (!m_config.selectFormat(vki, dev, { VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT }))
526 {
527 TCU_THROW(NotSupportedError, "Unable to find a proper format");
528 }
529
530 VkPhysicalDeviceProtectedMemoryFeatures memFeatures
531 {
532 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
533 nullptr,
534 VK_FALSE
535 };
536 VkPhysicalDeviceFeatures2 devFeatures
537 {
538 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
539 &memFeatures,
540 {}
541 };
542 vki.getPhysicalDeviceFeatures2(dev, &devFeatures);
543
544 if (m_config.enableProtected && (VK_FALSE == memFeatures.protectedMemory))
545 {
546 TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_PROTECTED_BIT not supported");
547 }
548
549 const VkBool32 sparseEnabled = devFeatures.features.sparseBinding & devFeatures.features.sparseResidencyBuffer & devFeatures.features.sparseResidencyImage2D;
550 if (m_config.enableSparseBinding && (VK_FALSE == sparseEnabled))
551 {
552 TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_SPARSE_BINDING_BIT not supported");
553 }
554
555 auto assertUnavailableQueue = [](const deUint32 qIdx, VkQueueFlagBits qfb, VkQueueGlobalPriorityKHR qgp)
556 {
557 if (qIdx == INVALID_UINT32) {
558 std::ostringstream buf;
559 buf << "Unable to create a queue " << qfb << " with a priority " << qgp;
560 buf.flush();
561 TCU_THROW(NotSupportedError, buf.str());
562 }
563 };
564
565 const bool priorityQueryEnabled = context.isDeviceFunctionalitySupported("VK_EXT_global_priority_query");
566
567 VkQueueFlags flagFrom = m_config.transitionFrom;
568 VkQueueFlags flagTo = m_config.transitionTo;
569 if (m_config.enableProtected)
570 {
571 flagFrom |= VK_QUEUE_PROTECTED_BIT;
572 flagTo |= VK_QUEUE_PROTECTED_BIT;
573 }
574 if (m_config.enableSparseBinding)
575 {
576 flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
577 flagTo |= VK_QUEUE_SPARSE_BINDING_BIT;
578 }
579
580 const deUint32 queueFromIndex = findQueueFamilyIndex(vki, dev, flagFrom,
581 SpecialDevice::getColissionFlags(m_config.transitionFrom),
582 priorityQueryEnabled,
583 QueueGlobalPriorities({m_config.priorityFrom}));
584 assertUnavailableQueue(queueFromIndex, m_config.transitionFrom, m_config.priorityFrom);
585
586 const deUint32 queueToIndex = findQueueFamilyIndex(vki, dev, flagTo,
587 SpecialDevice::getColissionFlags(m_config.transitionTo),
588 priorityQueryEnabled,
589 QueueGlobalPriorities({m_config.priorityTo}));
590 assertUnavailableQueue(queueToIndex, m_config.transitionTo, m_config.priorityTo);
591
592 if (queueFromIndex == queueToIndex)
593 {
594 std::ostringstream buf;
595 buf << "Unable to find separate queues " << m_config.transitionFrom << " and " << m_config.transitionTo;
596 buf.flush();
597 TCU_THROW(NotSupportedError, buf.str());
598 }
599 }
600
getShaderImageBufferType(const tcu::TextureFormat & format)601 std::string getShaderImageBufferType (const tcu::TextureFormat& format)
602 {
603 return image::getFormatPrefix(format) + "imageBuffer";
604 }
605
initPrograms(SourceCollections & programs) const606 void GPQCase::initPrograms (SourceCollections& programs) const
607 {
608 const std::string producerComp(R"glsl(
609 #version 450
610 layout(std430, push_constant) uniform PC
611 { uint width, height; } pc;
612 struct Index { uint k; };
613 struct Quad { vec2 c[4]; };
614 layout(set=0, binding=0) buffer Quads
615 { Quad data[]; } quads;
616 layout(set=0, binding=1) buffer Indices
617 { Index data[]; } indices;
618 uint fieldCount (uint w, uint h) {
619 return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2);
620 }
621 uint fieldIndex () {
622 return fieldCount(pc.width, gl_GlobalInvocationID.y) + (gl_GlobalInvocationID.x / 2);
623 }
624 void main() {
625 float x1 = float(gl_GlobalInvocationID.x) / float(pc.width);
626 float y1 = float(gl_GlobalInvocationID.y) / float(pc.height);
627 float x2 = (float(gl_GlobalInvocationID.x) + 1.0) / float(pc.width);
628 float y2 = (float(gl_GlobalInvocationID.y) + 1.0) / float(pc.height);
629
630 float xx1 = x1 * 2.0 - 1.0;
631 float yy1 = y1 * 2.0 - 1.0;
632 float xx2 = x2 * 2.0 - 1.0;
633 float yy2 = y2 * 2.0 - 1.0;
634
635 if (((gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) % 2) == 0)
636 {
637 uint at = fieldIndex();
638
639 if (gl_GlobalInvocationID.z == 0)
640 {
641 quads.data[at].c[0] = vec2(xx1, yy1);
642 quads.data[at].c[1] = vec2(xx2, yy1);
643 indices.data[at*6+0].k = at * 4 + 0;
644 indices.data[at*6+1].k = at * 4 + 1;
645 indices.data[at*6+2].k = at * 4 + 2;
646 }
647 else
648 {
649 quads.data[at].c[2] = vec2(xx2, yy2);
650 quads.data[at].c[3] = vec2(xx1, yy2);
651 indices.data[at*6+3].k = at * 4 + 2;
652 indices.data[at*6+4].k = at * 4 + 3;
653 indices.data[at*6+5].k = at * 4 + 0;
654 }
655 }
656 }
657 )glsl");
658
659 const tcu::StringTemplate consumerComp(R"glsl(
660 #version 450
661 layout(std430, push_constant) uniform PC
662 { uint width, height; } pc;
663 struct Pixel { uint k; };
664 layout(${IMAGE_FORMAT}, set=0, binding=0) readonly uniform ${IMAGE_TYPE} srcImage;
665 layout(binding=1) writeonly coherent buffer Pixels { Pixel data[]; } pixels;
666 void main()
667 {
668 ivec2 pos2 = ivec2(gl_GlobalInvocationID.xy);
669 int pos1 = int(gl_GlobalInvocationID.y * pc.width + gl_GlobalInvocationID.x);
670 pixels.data[pos1].k = uint(imageLoad(srcImage, pos2).r) + 1;
671 }
672 )glsl");
673
674 const std::string vert(R"glsl(
675 #version 450
676 layout(location = 0) in vec2 pos;
677 void main()
678 {
679 gl_Position = vec4(pos, 0, 1);
680 }
681 )glsl");
682
683 const tcu::StringTemplate frag(R"glsl(
684 #version 450
685 layout(location = 0) out ${COLOR_TYPE} color;
686 void main()
687 {
688 color = ${COLOR_TYPE}(${TEST_VALUE},0,0,1);
689 }
690 )glsl");
691
692 const auto format = mapVkFormat(m_config.format);
693 const auto imageFormat = image::getShaderImageFormatQualifier(format);
694 const auto imageType = image::getShaderImageType(format, image::ImageType::IMAGE_TYPE_2D, false);
695 const auto imageBuffer = getShaderImageBufferType(format);
696 const auto colorType = image::getGlslAttachmentType(m_config.format); // ivec4
697
698 const std::map<std::string, std::string> abbreviations
699 {
700 { std::string("TEST_VALUE"), std::to_string(testValue) },
701 { std::string("IMAGE_FORMAT"), std::string(imageFormat) },
702 { std::string("IMAGE_TYPE"), std::string(imageType) },
703 { std::string("IMAGE_BUFFER"), std::string(imageBuffer) },
704 { std::string("COLOR_TYPE"), std::string(colorType) },
705 };
706
707 programs.glslSources.add("comp") << glu::ComputeSource(
708 m_config.transitionFrom == VK_QUEUE_COMPUTE_BIT
709 ? producerComp
710 : consumerComp.specialize(abbreviations));
711 programs.glslSources.add("vert") << glu::VertexSource(vert);
712 programs.glslSources.add("frag") << glu::FragmentSource(frag.specialize(abbreviations));
713 }
714
715
iterate(void)716 tcu::TestStatus GPQInstance<VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT>::iterate (void)
717 {
718 VkResult deviceStatus = VK_SUCCESS;
719 if (!m_device.isValid(deviceStatus))
720 {
721 if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus)
722 return tcu::TestStatus::pass(getResultName(deviceStatus));
723 TCU_CHECK(deviceStatus);
724 }
725
726 const InstanceInterface& vki = m_context.getInstanceInterface();
727 const DeviceInterface& vkd = m_context.getDeviceInterface();
728 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
729 const VkDevice device = m_device.device;
730 Allocator& allocator = m_device.getAllocator();
731 const deUint32 producerIndex = m_device.queueFamilyIndexFrom;
732 const deUint32 consumerIndex = m_device.queueFamilyIndexTo;
733 const VkQueue producerQueue = m_device.queueFrom; DE_UNREF(producerQueue);
734 const VkQueue consumerQueue = m_device.queueTo; DE_UNREF(consumerQueue);
735
736 const uint32_t width = m_config.width;
737 const uint32_t height = m_config.height;
738 const uint32_t clearComp = 97;
739 const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
740 const uint32_t quadCount = CheckerboardBuilder::blackFieldCount(width, height);
741 const uint32_t vertexCount = 4 * quadCount;
742 const uint32_t indexCount = 6 * quadCount;
743 const MemoryRequirement memReqs = (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
744
745 VkBufferCreateFlags buffsCreateFlags = 0;
746 if (m_config.enableProtected) buffsCreateFlags |= VK_BUFFER_CREATE_PROTECTED_BIT;
747 if (m_config.enableSparseBinding) buffsCreateFlags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
748 const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
749 const VkBufferUsageFlags indexBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
750 const VkDeviceSize vertBuffSize = vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize();
751 const VkDeviceSize indexBuffSize = indexCount * sizeof(uint32_t);
752 const VkDeviceSize resultBuffSize = (width * height * mapVkFormat(m_config.format).getPixelSize());
753 const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, buffsCreateFlags);
754 const VkBufferCreateInfo indexBuffInfo = makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, buffsCreateFlags);
755 const VkBufferCreateInfo resultBuffInfo = makeBufferCreateInfo(resultBuffSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
756 BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, memReqs, producerQueue);
757 BufferWithMemory indexBuffer (vki, vkd, phys, device, allocator, indexBuffInfo, memReqs, producerQueue);
758 BufferWithMemory resultBuffer (vki, vkd, phys, device, allocator, resultBuffInfo, MemoryRequirement::HostVisible);
759
760 const VkDescriptorBufferInfo dsVertInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertBuffSize);
761 const VkDescriptorBufferInfo dsIndexInfo = makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBuffSize);
762 Move<VkDescriptorPool> dsPool = DescriptorPoolBuilder()
763 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
764 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
765 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
766 Move<VkDescriptorSetLayout> dsLayout = DescriptorSetLayoutBuilder()
767 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
768 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
769 .build(vkd, device);
770 Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *dsPool, *dsLayout);
771 DescriptorSetUpdateBuilder()
772 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsVertInfo)
773 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsIndexInfo)
774 .update(vkd, device);
775
776 VkImageSubresourceRange colorResourceRange {};
777 const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
778 de::MovePtr<ImageWithMemory> image = this->createImage(imageUsage, consumerIndex, consumerQueue);
779 Move<VkImageView> view = createView(**image, colorResourceRange);
780 Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format);
781 Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *view, width, height);
782 const VkImageMemoryBarrier colorReadyBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
783 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
784 **image, colorResourceRange);
785 const VkBufferImageCopy colorCopyRegion = makeBufferImageCopy(makeExtent3D(width, height, 1),
786 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
787 const VkMemoryBarrier resultReadyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
788 struct PushConstant
789 { uint32_t width, height; } pc { width, height };
790 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout<PushConstant>({ *dsLayout });
791 Move<VkPipeline> producerPipeline = createComputePipeline(*pipelineLayout);
792 Move<VkPipeline> consumerPipeline = createGraphicsPipeline(*pipelineLayout, *renderPass);
793
794 Move<VkCommandPool> producerPool = makeCommandPool(vkd, device, producerIndex);
795 Move<VkCommandPool> consumerPool = makeCommandPool(vkd, device, consumerIndex);
796 Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
797 Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
798
799 beginCommandBuffer(vkd, *producerCmd);
800 vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &(*descriptorSet), 0, nullptr);
801 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerPipeline);
802 vkd.cmdPushConstants(*producerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc);
803 vkd.cmdDispatch(*producerCmd, width, height, 2);
804 endCommandBuffer(vkd, *producerCmd);
805
806 beginCommandBuffer(vkd, *consumerCmd);
807 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerPipeline);
808 vkd.cmdBindIndexBuffer(*consumerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
809 vkd.cmdBindVertexBuffers(*consumerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0));
810 beginRenderPass(vkd, *consumerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor);
811 vkd.cmdDrawIndexed(*consumerCmd, indexCount, 1, 0, 0, 0);
812 endRenderPass(vkd, *consumerCmd);
813 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorReadyBarrier);
814 vkd.cmdCopyImageToBuffer(*consumerCmd, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resultBuffer, 1u, &colorCopyRegion);
815 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &resultReadyBarrier, 0u, nullptr, 0u, nullptr);
816 endCommandBuffer(vkd, *consumerCmd);
817
818 submitCommands(*producerCmd, *consumerCmd);
819
820 resultBuffer.invalidateAlloc(vkd, device);
821 const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, resultBuffer.getHostPtr());
822
823 return verify(resultBufferAccess, GPQCase::testValue, clearComp) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
824 }
825
iterate(void)826 tcu::TestStatus GPQInstance<VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT>::iterate (void)
827 {
828 VkResult deviceStatus = VK_SUCCESS;
829 if (!m_device.isValid(deviceStatus))
830 {
831 if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus)
832 return tcu::TestStatus::pass(getResultName(deviceStatus));
833 TCU_CHECK(deviceStatus);
834 }
835
836 const InstanceInterface& vki = m_context.getInstanceInterface();
837 const DeviceInterface& vkd = m_context.getDeviceInterface();
838 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
839 const VkDevice device = m_device.device;
840 Allocator& allocator = m_device.getAllocator();
841 const deUint32 producerIndex = m_device.queueFamilyIndexFrom;
842 const deUint32 consumerIndex = m_device.queueFamilyIndexTo;
843 const VkQueue producerQueue = m_device.queueFrom; DE_UNREF(producerQueue);
844 const VkQueue consumerQueue = m_device.queueTo; DE_UNREF(consumerQueue);
845
846 const uint32_t width = m_config.width;
847 const uint32_t height = m_config.height;
848 const uint32_t clearComp = GPQCase::testValue - 11;
849 const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
850 const uint32_t quadCount = CheckerboardBuilder::blackFieldCount(width, height);
851 const uint32_t vertexCount = 4 * quadCount;
852 const uint32_t indexCount = 6 * quadCount;
853
854 const VkBufferCreateFlags graphCreateFlags = 0;
855 const MemoryRequirement graphBuffsMemReqs = (MemoryRequirement::HostVisible);
856
857 const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
858 const VkDeviceSize vertBuffSize = vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize();
859 const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, graphCreateFlags);
860 BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, graphBuffsMemReqs, producerQueue);
861
862 const VkBufferUsageFlags indexBuffUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
863 const VkDeviceSize indexBuffSize = indexCount * sizeof(uint32_t);
864 const VkBufferCreateInfo indexBuffInfo = makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, graphCreateFlags);
865 BufferWithMemory indexBuffer (vki, vkd, phys, device, allocator, indexBuffInfo, graphBuffsMemReqs, producerQueue);
866
867 VkImageSubresourceRange producerResRange {};
868 const VkImageUsageFlags producerUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
869 de::MovePtr<ImageWithMemory> producerImage = this->createImage(producerUsage, producerIndex, producerQueue);
870 Move<VkImageView> producerView = createView(**producerImage, producerResRange);
871 const VkDescriptorImageInfo producerImageInfo = makeDescriptorImageInfo(VkSampler(0), *producerView, VK_IMAGE_LAYOUT_GENERAL);
872
873 const VkBufferCreateFlags consumerCreateFlags = graphCreateFlags;
874 const MemoryRequirement consumerMemReqs = MemoryRequirement::HostVisible | MemoryRequirement::Coherent;
875 const VkBufferUsageFlags consumerUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
876 const VkDeviceSize consumerBuffSize = (width * height * sizeof(uint32_t));
877 const VkBufferCreateInfo consumerBuffInfo = makeBufferCreateInfo(consumerBuffSize, consumerUsage, {consumerIndex}, consumerCreateFlags);
878 BufferWithMemory consumerBuffer (vki, vkd, phys, device, allocator, consumerBuffInfo, consumerMemReqs, consumerQueue);
879 const VkDescriptorBufferInfo consumerInfo = makeDescriptorBufferInfo(*consumerBuffer, 0, consumerBuffSize);
880
881 const VkBufferCreateFlags tmpCreateFlags = graphCreateFlags;
882 const MemoryRequirement tmpMemReqs = MemoryRequirement::HostVisible | MemoryRequirement::Coherent;
883 const VkBufferUsageFlags tmpUsage = (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
884 const VkDeviceSize tmpBuffSize = (width * height * sizeof(uint32_t));
885 const VkBufferCreateInfo tmpBuffInfo = makeBufferCreateInfo(tmpBuffSize, tmpUsage, {consumerIndex}, tmpCreateFlags);
886 BufferWithMemory tmpBuffer (vki, vkd, phys, device, allocator, tmpBuffInfo, tmpMemReqs, consumerQueue);
887 const VkBufferImageCopy tmpCopyRegion = makeBufferImageCopy(makeExtent3D(width, height, 1),
888 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
889
890 Move<VkDescriptorPool> dsPool = DescriptorPoolBuilder()
891 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
892 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
893 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
894 Move<VkDescriptorSetLayout> dsLayout = DescriptorSetLayoutBuilder()
895 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
896 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
897 .build(vkd, device);
898 Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *dsPool, *dsLayout);
899
900 DescriptorSetUpdateBuilder()
901 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &producerImageInfo)
902 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &consumerInfo)
903 .update(vkd, device);
904
905 Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format);
906 Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *producerView, width, height);
907
908 const VkImageMemoryBarrier producerReadyBarrier= makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
909 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
910 **producerImage, producerResRange);
911 // const VkBufferMemoryBarrier consumerReadyBarrier= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
912 // *consumerBuffer, 0, consumerBuffSize,
913 // consumerIndex, consumerIndex);
914 //const VkMemoryBarrier tmpReadyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
915 // const VkBufferMemoryBarrier tmpReadyBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
916 // *tmpBuffer, 0, tmpBuffSize,
917 // consumerIndex, consumerIndex);
918 const VkBufferMemoryBarrier consumerBarriers[] { makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
919 *consumerBuffer, 0, consumerBuffSize,
920 consumerIndex, consumerIndex),
921 makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
922 *tmpBuffer, 0, tmpBuffSize,
923 consumerIndex, consumerIndex) };
924 struct PushConstant
925 { uint32_t width, height; } pc { width, height };
926 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout<PushConstant>({ *dsLayout });
927 Move<VkPipeline> producerPipeline = createGraphicsPipeline(*pipelineLayout, *renderPass);
928 Move<VkPipeline> consumerPipeline = createComputePipeline(*pipelineLayout);
929
930 Move<VkCommandPool> producerPool = makeCommandPool(vkd, device, producerIndex);
931 Move<VkCommandPool> consumerPool = makeCommandPool(vkd, device, consumerIndex);
932 Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
933 Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
934
935 {
936 std::vector<float> vertices;
937 std::vector<uint32_t> indices;
938 CheckerboardBuilder builder(width, height);
939 builder.buildVerticesAndIndices(vertices, indices);
940 DE_ASSERT(vertices.size() == (vertexCount * 2));
941 DE_ASSERT(indices.size() == indexCount);
942 std::copy(vertices.begin(), vertices.end(), begin<float>(vertexBuffer.getHostPtr()));
943 std::copy(indices.begin(), indices.end(), begin<uint32_t>(indexBuffer.getHostPtr()));
944 vertexBuffer.flushAlloc(vkd, device);
945 indexBuffer.flushAlloc(vkd, device);
946 }
947
948 beginCommandBuffer(vkd, *producerCmd);
949 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *producerPipeline);
950 vkd.cmdBindVertexBuffers(*producerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0));
951 vkd.cmdBindIndexBuffer(*producerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
952 beginRenderPass(vkd, *producerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor);
953 vkd.cmdDrawIndexed(*producerCmd, indexCount, 1, 0, 0, 0);
954 endRenderPass(vkd, *producerCmd);
955 vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VkDependencyFlags(0),
956 0u, nullptr, 0u, nullptr, 1u, &producerReadyBarrier);
957 endCommandBuffer(vkd, *producerCmd);
958
959 beginCommandBuffer(vkd, *consumerCmd);
960 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerPipeline);
961 vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, nullptr);
962 vkd.cmdCopyImageToBuffer(*consumerCmd, **producerImage, VK_IMAGE_LAYOUT_GENERAL, *tmpBuffer, 1u, &tmpCopyRegion);
963 vkd.cmdPushConstants(*consumerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc);
964 vkd.cmdDispatch(*consumerCmd, width, height, 1);
965 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkDependencyFlags(0),
966 0, nullptr, DE_LENGTH_OF_ARRAY(consumerBarriers), consumerBarriers, 0, nullptr);
967 endCommandBuffer(vkd, *consumerCmd);
968
969 submitCommands(*producerCmd, *consumerCmd);
970
971 tmpBuffer.invalidateAlloc(vkd, device);
972 const tcu::ConstPixelBufferAccess tmpBufferAccess(mapVkFormat(m_config.format), width, height, 1, tmpBuffer.getHostPtr());
973 const bool tmpRes = verify(tmpBufferAccess, GPQCase::testValue, clearComp);
974
975 consumerBuffer.invalidateAlloc(vkd, device);
976 const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, consumerBuffer.getHostPtr());
977
978 return (tmpRes && verify(resultBufferAccess, (GPQCase::testValue + 1), (clearComp + 1))) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
979 }
980
verify(const BufferAccess & result,deUint32 blackColor,deUint32 whiteColor) const981 bool GPQInstanceBase::verify (const BufferAccess& result, deUint32 blackColor, deUint32 whiteColor) const
982 {
983 bool ok = true;
984
985 for (deUint32 y = 0; ok && y < m_config.height; ++y)
986 {
987 for (deUint32 x = 0; ok && x < m_config.width; ++x)
988 {
989 const deUint32 color = result.getPixelT<deUint32>(x, y).x();
990 if (((x + y) % 2) == 0)
991 {
992 ok = color == blackColor;
993 }
994 else
995 {
996 ok = color == whiteColor;
997 }
998 }
999 }
1000 return ok;
1001 }
1002
1003 } // anonymous
1004
createGlobalPriorityQueueTests(tcu::TestContext & testCtx)1005 tcu::TestCaseGroup* createGlobalPriorityQueueTests (tcu::TestContext& testCtx)
1006 {
1007 typedef std::pair<VkQueueFlagBits, const char*> TransitionItem;
1008 TransitionItem const transitions[]
1009 {
1010 { VK_QUEUE_GRAPHICS_BIT, "graphics" },
1011 { VK_QUEUE_COMPUTE_BIT, "compute" },
1012 };
1013
1014 auto mkGroupName = [](const TransitionItem& from, const TransitionItem& to) -> std::string
1015 {
1016 return std::string("from_") + from.second + std::string("_to_") + to.second;
1017 };
1018
1019 std::pair<VkQueueFlags, const char*>
1020 const modifiers[]
1021 {
1022 { 0, "no_modifiers" },
1023 { VK_QUEUE_SPARSE_BINDING_BIT, "sparse" },
1024 { VK_QUEUE_PROTECTED_BIT, "protected" },
1025 { VK_QUEUE_SPARSE_BINDING_BIT|VK_QUEUE_PROTECTED_BIT, "sparse_protected" },
1026 };
1027
1028 std::pair<VkQueueGlobalPriorityKHR, const char*>
1029 const prios[]
1030 {
1031 { VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, "low" },
1032 { VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, "medium" },
1033 { VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, "high" },
1034 { VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, "realtime" },
1035 };
1036
1037 std::pair<SyncType, const char*>
1038 const syncs[]
1039 {
1040 { SyncType::None, "no_sync" },
1041 { SyncType::Semaphore, "semaphore" },
1042 };
1043
1044 const uint32_t dim0 = 34;
1045 const uint32_t dim1 = 25;
1046 bool swap = true;
1047
1048 auto rootGroup = new tcu::TestCaseGroup(testCtx, "global_priority_transition", "Global Priority Queue Tests");
1049
1050 for (const auto& prio : prios)
1051 {
1052 auto prioGroup = new tcu::TestCaseGroup(testCtx, prio.second, "");
1053
1054 for (const auto& sync : syncs)
1055 {
1056 auto syncGroup = new tcu::TestCaseGroup(testCtx, sync.second, "");
1057
1058 for (const auto& mod : modifiers)
1059 {
1060 auto modGroup = new tcu::TestCaseGroup(testCtx, mod.second, "");
1061
1062 for (const auto& transitionFrom : transitions)
1063 {
1064 for (const auto& transitionTo : transitions)
1065 {
1066 if (transitionFrom != transitionTo)
1067 {
1068 TestConfig cfg{};
1069 cfg.transitionFrom = transitionFrom.first;
1070 cfg.transitionTo = transitionTo.first;
1071 cfg.priorityFrom = prio.first;
1072 cfg.priorityTo = prio.first;
1073 cfg.syncType = sync.first;
1074 cfg.enableProtected = (mod.first & VK_QUEUE_PROTECTED_BIT) != 0;
1075 cfg.enableSparseBinding = (mod.first & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
1076 // Note that format is changing in GPQCase::checkSupport(...)
1077 cfg.format = VK_FORMAT_R32G32B32A32_SFLOAT;
1078 cfg.width = swap ? dim0 : dim1;
1079 cfg.height = swap ? dim1 : dim0;
1080
1081 swap ^= true;
1082
1083 modGroup->addChild(new GPQCase(testCtx, mkGroupName(transitionFrom, transitionTo), cfg));
1084 }
1085 }
1086 }
1087 syncGroup->addChild(modGroup);
1088 }
1089 prioGroup->addChild(syncGroup);
1090 }
1091 rootGroup->addChild(prioGroup);
1092 }
1093
1094 return rootGroup;
1095 }
1096
1097 } // synchronization
1098 } // vkt
1099