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::__anon29962::CheckerboardBuilder113 CheckerboardBuilder (uint32_t width, uint32_t height)
114 : m_width(width), m_height(height) {}
115
blackFieldCountvkt::synchronization::__anon29962::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::__anon29962::CheckerboardBuilder121 uint32_t blackFieldCount () const
122 {
123 return blackFieldCount(m_width, m_height);
124 }
125
fieldIndexvkt::synchronization::__anon29962::CheckerboardBuilder126 uint32_t fieldIndex (uint32_t x, uint32_t y) const
127 {
128 return blackFieldCount(m_width, y) + (x / 2);
129 }
130
buildVerticesAndIndicesvkt::synchronization::__anon29962::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]>
decltype(std::begin(std::declval<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.requireDeviceFunctionality("VK_EXT_global_priority");
523
524 if (!m_config.selectFormat(vki, dev, { VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT }))
525 {
526 TCU_THROW(NotSupportedError, "Unable to find a proper format");
527 }
528
529 VkPhysicalDeviceProtectedMemoryFeatures memFeatures
530 {
531 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
532 nullptr,
533 VK_FALSE
534 };
535 VkPhysicalDeviceFeatures2 devFeatures
536 {
537 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
538 &memFeatures,
539 {}
540 };
541 vki.getPhysicalDeviceFeatures2(dev, &devFeatures);
542
543 if (m_config.enableProtected && (VK_FALSE == memFeatures.protectedMemory))
544 {
545 TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_PROTECTED_BIT not supported");
546 }
547
548 const VkBool32 sparseEnabled = devFeatures.features.sparseBinding & devFeatures.features.sparseResidencyBuffer & devFeatures.features.sparseResidencyImage2D;
549 if (m_config.enableSparseBinding && (VK_FALSE == sparseEnabled))
550 {
551 TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_SPARSE_BINDING_BIT not supported");
552 }
553
554 auto assertUnavailableQueue = [](const deUint32 qIdx, VkQueueFlagBits qfb, VkQueueGlobalPriorityKHR qgp)
555 {
556 if (qIdx == INVALID_UINT32) {
557 std::ostringstream buf;
558 buf << "Unable to create a queue " << qfb << " with a priority " << qgp;
559 buf.flush();
560 TCU_THROW(NotSupportedError, buf.str());
561 }
562 };
563
564 const bool priorityQueryEnabled = context.isDeviceFunctionalitySupported("VK_EXT_global_priority_query");
565
566 VkQueueFlags flagFrom = m_config.transitionFrom;
567 VkQueueFlags flagTo = m_config.transitionTo;
568 if (m_config.enableProtected)
569 {
570 flagFrom |= VK_QUEUE_PROTECTED_BIT;
571 flagTo |= VK_QUEUE_PROTECTED_BIT;
572 }
573 if (m_config.enableSparseBinding)
574 {
575 flagFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
576 flagTo |= VK_QUEUE_SPARSE_BINDING_BIT;
577 }
578
579 const deUint32 queueFromIndex = findQueueFamilyIndex(vki, dev, flagFrom,
580 SpecialDevice::getColissionFlags(m_config.transitionFrom),
581 priorityQueryEnabled,
582 QueueGlobalPriorities({m_config.priorityFrom}));
583 assertUnavailableQueue(queueFromIndex, m_config.transitionFrom, m_config.priorityFrom);
584
585 const deUint32 queueToIndex = findQueueFamilyIndex(vki, dev, flagTo,
586 SpecialDevice::getColissionFlags(m_config.transitionTo),
587 priorityQueryEnabled,
588 QueueGlobalPriorities({m_config.priorityTo}));
589 assertUnavailableQueue(queueToIndex, m_config.transitionTo, m_config.priorityTo);
590
591 if (queueFromIndex == queueToIndex)
592 {
593 std::ostringstream buf;
594 buf << "Unable to find separate queues " << m_config.transitionFrom << " and " << m_config.transitionTo;
595 buf.flush();
596 TCU_THROW(NotSupportedError, buf.str());
597 }
598 }
599
getShaderImageBufferType(const tcu::TextureFormat& format)600 std::string getShaderImageBufferType (const tcu::TextureFormat& format)
601 {
602 return image::getFormatPrefix(format) + "imageBuffer";
603 }
604
initPrograms(SourceCollections& programs) const605 void GPQCase::initPrograms (SourceCollections& programs) const
606 {
607 const std::string producerComp(R"glsl(
608 #version 450
609 layout(std430, push_constant) uniform PC
610 { uint width, height; } pc;
611 struct Index { uint k; };
612 struct Quad { vec2 c[4]; };
613 layout(set=0, binding=0) buffer Quads
614 { Quad data[]; } quads;
615 layout(set=0, binding=1) buffer Indices
616 { Index data[]; } indices;
617 uint fieldCount (uint w, uint h) {
618 return ((w+1)/2)*((h+1)/2)+(w/2)*(h/2);
619 }
620 uint fieldIndex () {
621 return fieldCount(pc.width, gl_GlobalInvocationID.y) + (gl_GlobalInvocationID.x / 2);
622 }
623 void main() {
624 float x1 = float(gl_GlobalInvocationID.x) / float(pc.width);
625 float y1 = float(gl_GlobalInvocationID.y) / float(pc.height);
626 float x2 = (float(gl_GlobalInvocationID.x) + 1.0) / float(pc.width);
627 float y2 = (float(gl_GlobalInvocationID.y) + 1.0) / float(pc.height);
628
629 float xx1 = x1 * 2.0 - 1.0;
630 float yy1 = y1 * 2.0 - 1.0;
631 float xx2 = x2 * 2.0 - 1.0;
632 float yy2 = y2 * 2.0 - 1.0;
633
634 if (((gl_GlobalInvocationID.x + gl_GlobalInvocationID.y) % 2) == 0)
635 {
636 uint at = fieldIndex();
637
638 if (gl_GlobalInvocationID.z == 0)
639 {
640 quads.data[at].c[0] = vec2(xx1, yy1);
641 quads.data[at].c[1] = vec2(xx2, yy1);
642 indices.data[at*6+0].k = at * 4 + 0;
643 indices.data[at*6+1].k = at * 4 + 1;
644 indices.data[at*6+2].k = at * 4 + 2;
645 }
646 else
647 {
648 quads.data[at].c[2] = vec2(xx2, yy2);
649 quads.data[at].c[3] = vec2(xx1, yy2);
650 indices.data[at*6+3].k = at * 4 + 2;
651 indices.data[at*6+4].k = at * 4 + 3;
652 indices.data[at*6+5].k = at * 4 + 0;
653 }
654 }
655 }
656 )glsl");
657
658 const tcu::StringTemplate consumerComp(R"glsl(
659 #version 450
660 layout(std430, push_constant) uniform PC
661 { uint width, height; } pc;
662 struct Pixel { uint k; };
663 layout(${IMAGE_FORMAT}, set=0, binding=0) readonly uniform ${IMAGE_TYPE} srcImage;
664 layout(binding=1) writeonly coherent buffer Pixels { Pixel data[]; } pixels;
665 void main()
666 {
667 ivec2 pos2 = ivec2(gl_GlobalInvocationID.xy);
668 int pos1 = int(gl_GlobalInvocationID.y * pc.width + gl_GlobalInvocationID.x);
669 pixels.data[pos1].k = uint(imageLoad(srcImage, pos2).r) + 1;
670 }
671 )glsl");
672
673 const std::string vert(R"glsl(
674 #version 450
675 layout(location = 0) in vec2 pos;
676 void main()
677 {
678 gl_Position = vec4(pos, 0, 1);
679 }
680 )glsl");
681
682 const tcu::StringTemplate frag(R"glsl(
683 #version 450
684 layout(location = 0) out ${COLOR_TYPE} color;
685 void main()
686 {
687 color = ${COLOR_TYPE}(${TEST_VALUE},0,0,1);
688 }
689 )glsl");
690
691 const auto format = mapVkFormat(m_config.format);
692 const auto imageFormat = image::getShaderImageFormatQualifier(format);
693 const auto imageType = image::getShaderImageType(format, image::ImageType::IMAGE_TYPE_2D, false);
694 const auto imageBuffer = getShaderImageBufferType(format);
695 const auto colorType = image::getGlslAttachmentType(m_config.format); // ivec4
696
697 const std::map<std::string, std::string> abbreviations
698 {
699 { std::string("TEST_VALUE"), std::to_string(testValue) },
700 { std::string("IMAGE_FORMAT"), std::string(imageFormat) },
701 { std::string("IMAGE_TYPE"), std::string(imageType) },
702 { std::string("IMAGE_BUFFER"), std::string(imageBuffer) },
703 { std::string("COLOR_TYPE"), std::string(colorType) },
704 };
705
706 programs.glslSources.add("comp") << glu::ComputeSource(
707 m_config.transitionFrom == VK_QUEUE_COMPUTE_BIT
708 ? producerComp
709 : consumerComp.specialize(abbreviations));
710 programs.glslSources.add("vert") << glu::VertexSource(vert);
711 programs.glslSources.add("frag") << glu::FragmentSource(frag.specialize(abbreviations));
712 }
713
714
iterate(void)715 tcu::TestStatus GPQInstance<VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT>::iterate (void)
716 {
717 VkResult deviceStatus = VK_SUCCESS;
718 if (!m_device.isValid(deviceStatus))
719 {
720 if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus)
721 return tcu::TestStatus::pass(getResultName(deviceStatus));
722 TCU_CHECK(deviceStatus);
723 }
724
725 const InstanceInterface& vki = m_context.getInstanceInterface();
726 const DeviceInterface& vkd = m_context.getDeviceInterface();
727 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
728 const VkDevice device = m_device.device;
729 Allocator& allocator = m_device.getAllocator();
730 const deUint32 producerIndex = m_device.queueFamilyIndexFrom;
731 const deUint32 consumerIndex = m_device.queueFamilyIndexTo;
732 const VkQueue producerQueue = m_device.queueFrom; DE_UNREF(producerQueue);
733 const VkQueue consumerQueue = m_device.queueTo; DE_UNREF(consumerQueue);
734
735 const uint32_t width = m_config.width;
736 const uint32_t height = m_config.height;
737 const uint32_t clearComp = 97;
738 const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
739 const uint32_t quadCount = CheckerboardBuilder::blackFieldCount(width, height);
740 const uint32_t vertexCount = 4 * quadCount;
741 const uint32_t indexCount = 6 * quadCount;
742 const MemoryRequirement memReqs = (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
743
744 VkBufferCreateFlags buffsCreateFlags = 0;
745 if (m_config.enableProtected) buffsCreateFlags |= VK_BUFFER_CREATE_PROTECTED_BIT;
746 if (m_config.enableSparseBinding) buffsCreateFlags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
747 const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
748 const VkBufferUsageFlags indexBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
749 const VkDeviceSize vertBuffSize = vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize();
750 const VkDeviceSize indexBuffSize = indexCount * sizeof(uint32_t);
751 const VkDeviceSize resultBuffSize = (width * height * mapVkFormat(m_config.format).getPixelSize());
752 const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, buffsCreateFlags);
753 const VkBufferCreateInfo indexBuffInfo = makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, buffsCreateFlags);
754 const VkBufferCreateInfo resultBuffInfo = makeBufferCreateInfo(resultBuffSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
755 BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, memReqs, producerQueue);
756 BufferWithMemory indexBuffer (vki, vkd, phys, device, allocator, indexBuffInfo, memReqs, producerQueue);
757 BufferWithMemory resultBuffer (vki, vkd, phys, device, allocator, resultBuffInfo, MemoryRequirement::HostVisible);
758
759 const VkDescriptorBufferInfo dsVertInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertBuffSize);
760 const VkDescriptorBufferInfo dsIndexInfo = makeDescriptorBufferInfo(indexBuffer.get(), 0ull, indexBuffSize);
761 Move<VkDescriptorPool> dsPool = DescriptorPoolBuilder()
762 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
763 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
764 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
765 Move<VkDescriptorSetLayout> dsLayout = DescriptorSetLayoutBuilder()
766 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
767 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
768 .build(vkd, device);
769 Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *dsPool, *dsLayout);
770 DescriptorSetUpdateBuilder()
771 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsVertInfo)
772 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &dsIndexInfo)
773 .update(vkd, device);
774
775 VkImageSubresourceRange colorResourceRange {};
776 const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
777 de::MovePtr<ImageWithMemory> image = this->createImage(imageUsage, consumerIndex, consumerQueue);
778 Move<VkImageView> view = createView(**image, colorResourceRange);
779 Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format);
780 Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *view, width, height);
781 const VkImageMemoryBarrier colorReadyBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
782 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
783 **image, colorResourceRange);
784 const VkBufferImageCopy colorCopyRegion = makeBufferImageCopy(makeExtent3D(width, height, 1),
785 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
786 const VkMemoryBarrier resultReadyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
787 struct PushConstant
788 { uint32_t width, height; } pc { width, height };
789 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout<PushConstant>({ *dsLayout });
790 Move<VkPipeline> producerPipeline = createComputePipeline(*pipelineLayout);
791 Move<VkPipeline> consumerPipeline = createGraphicsPipeline(*pipelineLayout, *renderPass);
792
793 Move<VkCommandPool> producerPool = makeCommandPool(vkd, device, producerIndex);
794 Move<VkCommandPool> consumerPool = makeCommandPool(vkd, device, consumerIndex);
795 Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
796 Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
797
798 beginCommandBuffer(vkd, *producerCmd);
799 vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &(*descriptorSet), 0, nullptr);
800 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerPipeline);
801 vkd.cmdPushConstants(*producerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc);
802 vkd.cmdDispatch(*producerCmd, width, height, 2);
803 endCommandBuffer(vkd, *producerCmd);
804
805 beginCommandBuffer(vkd, *consumerCmd);
806 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerPipeline);
807 vkd.cmdBindIndexBuffer(*consumerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
808 vkd.cmdBindVertexBuffers(*consumerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0));
809 beginRenderPass(vkd, *consumerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor);
810 vkd.cmdDrawIndexed(*consumerCmd, indexCount, 1, 0, 0, 0);
811 endRenderPass(vkd, *consumerCmd);
812 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorReadyBarrier);
813 vkd.cmdCopyImageToBuffer(*consumerCmd, **image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resultBuffer, 1u, &colorCopyRegion);
814 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &resultReadyBarrier, 0u, nullptr, 0u, nullptr);
815 endCommandBuffer(vkd, *consumerCmd);
816
817 submitCommands(*producerCmd, *consumerCmd);
818
819 resultBuffer.invalidateAlloc(vkd, device);
820 const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, resultBuffer.getHostPtr());
821
822 return verify(resultBufferAccess, GPQCase::testValue, clearComp) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
823 }
824
iterate(void)825 tcu::TestStatus GPQInstance<VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT>::iterate (void)
826 {
827 VkResult deviceStatus = VK_SUCCESS;
828 if (!m_device.isValid(deviceStatus))
829 {
830 if (VK_ERROR_NOT_PERMITTED_KHR == deviceStatus)
831 return tcu::TestStatus::pass(getResultName(deviceStatus));
832 TCU_CHECK(deviceStatus);
833 }
834
835 const InstanceInterface& vki = m_context.getInstanceInterface();
836 const DeviceInterface& vkd = m_context.getDeviceInterface();
837 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
838 const VkDevice device = m_device.device;
839 Allocator& allocator = m_device.getAllocator();
840 const deUint32 producerIndex = m_device.queueFamilyIndexFrom;
841 const deUint32 consumerIndex = m_device.queueFamilyIndexTo;
842 const VkQueue producerQueue = m_device.queueFrom; DE_UNREF(producerQueue);
843 const VkQueue consumerQueue = m_device.queueTo; DE_UNREF(consumerQueue);
844
845 const uint32_t width = m_config.width;
846 const uint32_t height = m_config.height;
847 const uint32_t clearComp = GPQCase::testValue - 11;
848 const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
849 const uint32_t quadCount = CheckerboardBuilder::blackFieldCount(width, height);
850 const uint32_t vertexCount = 4 * quadCount;
851 const uint32_t indexCount = 6 * quadCount;
852
853 const VkBufferCreateFlags graphCreateFlags = 0;
854 const MemoryRequirement graphBuffsMemReqs = (MemoryRequirement::HostVisible);
855
856 const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
857 const VkDeviceSize vertBuffSize = vertexCount * mapVkFormat(VK_FORMAT_R32G32_SFLOAT).getPixelSize();
858 const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(vertBuffSize, vertBuffUsage, {producerIndex}, graphCreateFlags);
859 BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, graphBuffsMemReqs, producerQueue);
860
861 const VkBufferUsageFlags indexBuffUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
862 const VkDeviceSize indexBuffSize = indexCount * sizeof(uint32_t);
863 const VkBufferCreateInfo indexBuffInfo = makeBufferCreateInfo(indexBuffSize, indexBuffUsage, {producerIndex}, graphCreateFlags);
864 BufferWithMemory indexBuffer (vki, vkd, phys, device, allocator, indexBuffInfo, graphBuffsMemReqs, producerQueue);
865
866 VkImageSubresourceRange producerResRange {};
867 const VkImageUsageFlags producerUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
868 de::MovePtr<ImageWithMemory> producerImage = this->createImage(producerUsage, producerIndex, producerQueue);
869 Move<VkImageView> producerView = createView(**producerImage, producerResRange);
870 const VkDescriptorImageInfo producerImageInfo = makeDescriptorImageInfo(VkSampler(0), *producerView, VK_IMAGE_LAYOUT_GENERAL);
871
872 const VkBufferCreateFlags consumerCreateFlags = graphCreateFlags;
873 const MemoryRequirement consumerMemReqs = MemoryRequirement::HostVisible | MemoryRequirement::Coherent;
874 const VkBufferUsageFlags consumerUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
875 const VkDeviceSize consumerBuffSize = (width * height * sizeof(uint32_t));
876 const VkBufferCreateInfo consumerBuffInfo = makeBufferCreateInfo(consumerBuffSize, consumerUsage, {consumerIndex}, consumerCreateFlags);
877 BufferWithMemory consumerBuffer (vki, vkd, phys, device, allocator, consumerBuffInfo, consumerMemReqs, consumerQueue);
878 const VkDescriptorBufferInfo consumerInfo = makeDescriptorBufferInfo(*consumerBuffer, 0, consumerBuffSize);
879
880 const VkBufferCreateFlags tmpCreateFlags = graphCreateFlags;
881 const MemoryRequirement tmpMemReqs = MemoryRequirement::HostVisible | MemoryRequirement::Coherent;
882 const VkBufferUsageFlags tmpUsage = (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
883 const VkDeviceSize tmpBuffSize = (width * height * sizeof(uint32_t));
884 const VkBufferCreateInfo tmpBuffInfo = makeBufferCreateInfo(tmpBuffSize, tmpUsage, {consumerIndex}, tmpCreateFlags);
885 BufferWithMemory tmpBuffer (vki, vkd, phys, device, allocator, tmpBuffInfo, tmpMemReqs, consumerQueue);
886 const VkBufferImageCopy tmpCopyRegion = makeBufferImageCopy(makeExtent3D(width, height, 1),
887 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
888
889 Move<VkDescriptorPool> dsPool = DescriptorPoolBuilder()
890 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
891 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
892 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
893 Move<VkDescriptorSetLayout> dsLayout = DescriptorSetLayoutBuilder()
894 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
895 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
896 .build(vkd, device);
897 Move<VkDescriptorSet> descriptorSet = makeDescriptorSet(vkd, device, *dsPool, *dsLayout);
898
899 DescriptorSetUpdateBuilder()
900 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &producerImageInfo)
901 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &consumerInfo)
902 .update(vkd, device);
903
904 Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format);
905 Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *producerView, width, height);
906
907 const VkImageMemoryBarrier producerReadyBarrier= makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
908 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
909 **producerImage, producerResRange);
910 // const VkBufferMemoryBarrier consumerReadyBarrier= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
911 // *consumerBuffer, 0, consumerBuffSize,
912 // consumerIndex, consumerIndex);
913 //const VkMemoryBarrier tmpReadyBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
914 // const VkBufferMemoryBarrier tmpReadyBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
915 // *tmpBuffer, 0, tmpBuffSize,
916 // consumerIndex, consumerIndex);
917 const VkBufferMemoryBarrier consumerBarriers[] { makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
918 *consumerBuffer, 0, consumerBuffSize,
919 consumerIndex, consumerIndex),
920 makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_NONE,
921 *tmpBuffer, 0, tmpBuffSize,
922 consumerIndex, consumerIndex) };
923 struct PushConstant
924 { uint32_t width, height; } pc { width, height };
925 Move<VkPipelineLayout> pipelineLayout = createPipelineLayout<PushConstant>({ *dsLayout });
926 Move<VkPipeline> producerPipeline = createGraphicsPipeline(*pipelineLayout, *renderPass);
927 Move<VkPipeline> consumerPipeline = createComputePipeline(*pipelineLayout);
928
929 Move<VkCommandPool> producerPool = makeCommandPool(vkd, device, producerIndex);
930 Move<VkCommandPool> consumerPool = makeCommandPool(vkd, device, consumerIndex);
931 Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
932 Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
933
934 {
935 std::vector<float> vertices;
936 std::vector<uint32_t> indices;
937 CheckerboardBuilder builder(width, height);
938 builder.buildVerticesAndIndices(vertices, indices);
939 DE_ASSERT(vertices.size() == (vertexCount * 2));
940 DE_ASSERT(indices.size() == indexCount);
941 std::copy(vertices.begin(), vertices.end(), begin<float>(vertexBuffer.getHostPtr()));
942 std::copy(indices.begin(), indices.end(), begin<uint32_t>(indexBuffer.getHostPtr()));
943 vertexBuffer.flushAlloc(vkd, device);
944 indexBuffer.flushAlloc(vkd, device);
945 }
946
947 beginCommandBuffer(vkd, *producerCmd);
948 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *producerPipeline);
949 vkd.cmdBindVertexBuffers(*producerCmd, 0, 1, &static_cast<const VkBuffer&>(*vertexBuffer), &static_cast<const VkDeviceSize&>(0));
950 vkd.cmdBindIndexBuffer(*producerCmd, *indexBuffer, 0, VK_INDEX_TYPE_UINT32);
951 beginRenderPass(vkd, *producerCmd, *renderPass, *framebuffer, makeRect2D(width, height), clearColor);
952 vkd.cmdDrawIndexed(*producerCmd, indexCount, 1, 0, 0, 0);
953 endRenderPass(vkd, *producerCmd);
954 vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VkDependencyFlags(0),
955 0u, nullptr, 0u, nullptr, 1u, &producerReadyBarrier);
956 endCommandBuffer(vkd, *producerCmd);
957
958 beginCommandBuffer(vkd, *consumerCmd);
959 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerPipeline);
960 vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1, &descriptorSet.get(), 0, nullptr);
961 vkd.cmdCopyImageToBuffer(*consumerCmd, **producerImage, VK_IMAGE_LAYOUT_GENERAL, *tmpBuffer, 1u, &tmpCopyRegion);
962 vkd.cmdPushConstants(*consumerCmd, *pipelineLayout, VK_SHADER_STAGE_ALL, 0, static_cast<uint32_t>(sizeof(PushConstant)), &pc);
963 vkd.cmdDispatch(*consumerCmd, width, height, 1);
964 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VkDependencyFlags(0),
965 0, nullptr, DE_LENGTH_OF_ARRAY(consumerBarriers), consumerBarriers, 0, nullptr);
966 endCommandBuffer(vkd, *consumerCmd);
967
968 submitCommands(*producerCmd, *consumerCmd);
969
970 tmpBuffer.invalidateAlloc(vkd, device);
971 const tcu::ConstPixelBufferAccess tmpBufferAccess(mapVkFormat(m_config.format), width, height, 1, tmpBuffer.getHostPtr());
972 const bool tmpRes = verify(tmpBufferAccess, GPQCase::testValue, clearComp);
973
974 consumerBuffer.invalidateAlloc(vkd, device);
975 const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), width, height, 1, consumerBuffer.getHostPtr());
976
977 return (tmpRes && verify(resultBufferAccess, (GPQCase::testValue + 1), (clearComp + 1))) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
978 }
979
verify(const BufferAccess& result, deUint32 blackColor, deUint32 whiteColor) const980 bool GPQInstanceBase::verify (const BufferAccess& result, deUint32 blackColor, deUint32 whiteColor) const
981 {
982 bool ok = true;
983
984 for (deUint32 y = 0; ok && y < m_config.height; ++y)
985 {
986 for (deUint32 x = 0; ok && x < m_config.width; ++x)
987 {
988 const deUint32 color = result.getPixelT<deUint32>(x, y).x();
989 if (((x + y) % 2) == 0)
990 {
991 ok = color == blackColor;
992 }
993 else
994 {
995 ok = color == whiteColor;
996 }
997 }
998 }
999 return ok;
1000 }
1001
1002 } // anonymous
1003
createGlobalPriorityQueueTests(tcu::TestContext& testCtx)1004 tcu::TestCaseGroup* createGlobalPriorityQueueTests (tcu::TestContext& testCtx)
1005 {
1006 typedef std::pair<VkQueueFlagBits, const char*> TransitionItem;
1007 TransitionItem const transitions[]
1008 {
1009 { VK_QUEUE_GRAPHICS_BIT, "graphics" },
1010 { VK_QUEUE_COMPUTE_BIT, "compute" },
1011 };
1012
1013 auto mkGroupName = [](const TransitionItem& from, const TransitionItem& to) -> std::string
1014 {
1015 return std::string("from_") + from.second + std::string("_to_") + to.second;
1016 };
1017
1018 std::pair<VkQueueFlags, const char*>
1019 const modifiers[]
1020 {
1021 { 0, "no_modifiers" },
1022 { VK_QUEUE_SPARSE_BINDING_BIT, "sparse" },
1023 { VK_QUEUE_PROTECTED_BIT, "protected" },
1024 { VK_QUEUE_SPARSE_BINDING_BIT|VK_QUEUE_PROTECTED_BIT, "sparse_protected" },
1025 };
1026
1027 std::pair<VkQueueGlobalPriorityKHR, const char*>
1028 const prios[]
1029 {
1030 { VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, "low" },
1031 { VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, "medium" },
1032 { VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, "high" },
1033 { VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, "realtime" },
1034 };
1035
1036 std::pair<SyncType, const char*>
1037 const syncs[]
1038 {
1039 { SyncType::None, "no_sync" },
1040 { SyncType::Semaphore, "semaphore" },
1041 };
1042
1043 const uint32_t dim0 = 34;
1044 const uint32_t dim1 = 25;
1045 bool swap = true;
1046
1047 auto rootGroup = new tcu::TestCaseGroup(testCtx, "global_priority_transition", "Global Priority Queue Tests");
1048
1049 for (const auto& prio : prios)
1050 {
1051 auto prioGroup = new tcu::TestCaseGroup(testCtx, prio.second, "");
1052
1053 for (const auto& sync : syncs)
1054 {
1055 auto syncGroup = new tcu::TestCaseGroup(testCtx, sync.second, "");
1056
1057 for (const auto& mod : modifiers)
1058 {
1059 auto modGroup = new tcu::TestCaseGroup(testCtx, mod.second, "");
1060
1061 for (const auto& transitionFrom : transitions)
1062 {
1063 for (const auto& transitionTo : transitions)
1064 {
1065 if (transitionFrom != transitionTo)
1066 {
1067 TestConfig cfg{};
1068 cfg.transitionFrom = transitionFrom.first;
1069 cfg.transitionTo = transitionTo.first;
1070 cfg.priorityFrom = prio.first;
1071 cfg.priorityTo = prio.first;
1072 cfg.syncType = sync.first;
1073 cfg.enableProtected = (mod.first & VK_QUEUE_PROTECTED_BIT) != 0;
1074 cfg.enableSparseBinding = (mod.first & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
1075 // Note that format is changing in GPQCase::checkSupport(...)
1076 cfg.format = VK_FORMAT_R32G32B32A32_SFLOAT;
1077 cfg.width = swap ? dim0 : dim1;
1078 cfg.height = swap ? dim1 : dim0;
1079
1080 swap ^= true;
1081
1082 modGroup->addChild(new GPQCase(testCtx, mkGroupName(transitionFrom, transitionTo), cfg));
1083 }
1084 }
1085 }
1086 syncGroup->addChild(modGroup);
1087 }
1088 prioGroup->addChild(syncGroup);
1089 }
1090 rootGroup->addChild(prioGroup);
1091 }
1092
1093 return rootGroup;
1094 }
1095
1096 } // synchronization
1097 } // vkt
1098