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 #include <iostream>
55
56 using namespace vk;
57
58 namespace vkt
59 {
60 namespace synchronization
61 {
62 namespace
63 {
64
65 enum class SyncType
66 {
67 None,
68 Semaphore
69 };
70
71 struct TestConfig
72 {
73 VkQueueFlagBits transitionFrom;
74 VkQueueFlagBits transitionTo;
75 VkQueueGlobalPriorityKHR priorityFrom;
76 VkQueueGlobalPriorityKHR priorityTo;
77 bool enableProtected;
78 bool enableSparseBinding;
79 SyncType syncType;
80 deUint32 width;
81 deUint32 height;
82 VkFormat format;
83 bool selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats);
84 };
85
selectFormat(const InstanceInterface & vk,VkPhysicalDevice dev,std::initializer_list<VkFormat> formats)86 bool TestConfig::selectFormat (const InstanceInterface& vk, VkPhysicalDevice dev, std::initializer_list<VkFormat> formats)
87 {
88 auto doesFormatMatch = [](const VkFormat fmt) -> bool
89 {
90 const auto tcuFmt = mapVkFormat(fmt);
91 return tcuFmt.order == tcu::TextureFormat::ChannelOrder::R;
92 };
93 VkFormatProperties2 props{};
94 const VkFormatFeatureFlags flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
95 | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
96 for (auto i = formats.begin(); i != formats.end(); ++i)
97 {
98 props.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
99 props.pNext = nullptr;
100 props.formatProperties = {};
101 const VkFormat fmt = *i;
102 vk.getPhysicalDeviceFormatProperties2(dev, fmt, &props);
103 if (doesFormatMatch(fmt) && ((props.formatProperties.optimalTilingFeatures & flags) == flags))
104 {
105 this->format = fmt;
106 return true;
107 }
108 }
109 return false;
110 }
111
112 template<class T, class P = T(*)[1]>
begin(void * p)113 auto begin (void* p) -> decltype(std::begin(*std::declval<P>()))
114 {
115 return std::begin(*static_cast<P>(p));
116 }
117
118 class GPQInstanceBase : public TestInstance
119 {
120 public:
121 typedef std::initializer_list<VkDescriptorSetLayout> DSLayouts;
122 typedef tcu::ConstPixelBufferAccess BufferAccess;
123
124 GPQInstanceBase (Context& ctx,
125 const TestConfig& cfg);
126 template<class PushConstant = void>
127 auto createPipelineLayout (DSLayouts setLayouts) const -> Move<VkPipelineLayout>;
128 auto makeCommandPool (deUint32 qFamilyIndex) const -> Move<VkCommandPool>;
129 auto createGraphicsPipeline (VkPipelineLayout pipelineLayout,
130 VkRenderPass renderPass) -> Move<VkPipeline>;
131 auto createComputePipeline (VkPipelineLayout pipelineLayout,
132 bool producer) -> Move<VkPipeline>;
133 auto createImage (VkImageUsageFlags usage,
134 deUint32 queueFamilyIdx,
135 VkQueue queue) const -> de::MovePtr<ImageWithMemory>;
136 auto createView (VkImage image,
137 VkImageSubresourceRange& range) const -> Move<VkImageView>;
138 void submitCommands (VkCommandBuffer producerCmd,
139 VkCommandBuffer consumerCmd) const;
140 protected:
141 auto createPipelineLayout (const VkPushConstantRange* pRange,
142 DSLayouts setLayouts) const -> Move<VkPipelineLayout>;
143 const TestConfig m_config;
144 const SpecialDevice m_device;
145 struct NamedShader {
146 std::string name;
147 Move<VkShaderModule> handle;
148 } m_shaders[4];
149 };
GPQInstanceBase(Context & ctx,const TestConfig & cfg)150 GPQInstanceBase::GPQInstanceBase (Context& ctx, const TestConfig& cfg)
151 : TestInstance (ctx)
152 , m_config (cfg)
153 , m_device (ctx,
154 cfg.transitionFrom, cfg.transitionTo,
155 cfg.priorityFrom, cfg.priorityTo,
156 cfg.enableProtected, cfg.enableSparseBinding)
157 , m_shaders ()
158 {
159 m_shaders[0].name = "vert"; // vertex
160 m_shaders[1].name = "frag"; // fragment
161 m_shaders[2].name = "cpyb"; // compute
162 m_shaders[3].name = "cpyi"; // compute
163 }
164
createImage(VkImageUsageFlags usage,deUint32 queueFamilyIdx,VkQueue queue) const165 de::MovePtr<ImageWithMemory> GPQInstanceBase::createImage (VkImageUsageFlags usage, deUint32 queueFamilyIdx, VkQueue queue) const
166 {
167 const InstanceInterface& vki = m_context.getInstanceInterface();
168 const DeviceInterface& vkd = m_context.getDeviceInterface();
169 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
170 const VkDevice dev = m_device.handle;
171 Allocator& alloc = m_device.getAllocator();
172 VkImageCreateFlags flags = 0;
173
174 if (m_config.enableProtected) flags |= VK_IMAGE_CREATE_PROTECTED_BIT;
175 if (m_config.enableSparseBinding) flags |= (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT);
176 const MemoryRequirement memReqs = m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any;
177
178 VkImageCreateInfo imageInfo{};
179 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
180 imageInfo.pNext = nullptr;
181 imageInfo.flags = flags;
182 imageInfo.imageType = VK_IMAGE_TYPE_2D;
183 imageInfo.format = m_config.format;
184 imageInfo.extent.width = m_config.width;
185 imageInfo.extent.height = m_config.height;
186 imageInfo.extent.depth = 1;
187 imageInfo.mipLevels = 1;
188 imageInfo.arrayLayers = 1;
189 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
190 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
191 imageInfo.usage = usage;
192 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
193 imageInfo.queueFamilyIndexCount = 1;
194 imageInfo.pQueueFamilyIndices = &queueFamilyIdx;
195 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
196
197 return de::MovePtr<ImageWithMemory>(new ImageWithMemory(vki, vkd, phys, dev, alloc, imageInfo, queue, memReqs));
198 }
199
createView(VkImage image,VkImageSubresourceRange & range) const200 Move<VkImageView> GPQInstanceBase::createView (VkImage image, VkImageSubresourceRange& range) const
201 {
202 const DeviceInterface& vkd = m_context.getDeviceInterface();
203 const VkDevice dev = m_device.handle;
204
205 range = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1);
206 return makeImageView(vkd, dev, image, VK_IMAGE_VIEW_TYPE_2D, m_config.format, range);
207 }
208
createPipelineLayout(const VkPushConstantRange * pRange,DSLayouts setLayouts) const209 Move<VkPipelineLayout> GPQInstanceBase::createPipelineLayout (const VkPushConstantRange* pRange, DSLayouts setLayouts) const
210 {
211 std::vector<VkDescriptorSetLayout> layouts(setLayouts.size());
212 auto ii = setLayouts.begin();
213 for (auto i = ii; i != setLayouts.end(); ++i)
214 layouts[std::distance(ii, i)] = *i;
215
216 VkPipelineLayoutCreateInfo info{};
217 info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
218 info.pNext = nullptr;
219 info.flags = VkPipelineLayoutCreateFlags(0);
220 info.setLayoutCount = static_cast<uint32_t>(layouts.size());
221 info.pSetLayouts = layouts.size() ? layouts.data() : nullptr;
222 info.pushConstantRangeCount = (pRange != nullptr && pRange->size > 0) ? 1 : 0;
223 info.pPushConstantRanges = (pRange != nullptr && pRange->size > 0) ? pRange : nullptr;
224
225 return ::vk::createPipelineLayout(m_context.getDeviceInterface(), m_device.handle, &info);
226 }
227
createPipelineLayout(DSLayouts setLayouts) const228 template<> Move<VkPipelineLayout> DE_UNUSED_FUNCTION GPQInstanceBase::createPipelineLayout<void> (DSLayouts setLayouts) const
229 {
230 return createPipelineLayout(nullptr, setLayouts);
231 }
232
createPipelineLayout(DSLayouts setLayouts) const233 template<class PushConstant> Move<VkPipelineLayout> GPQInstanceBase::createPipelineLayout (DSLayouts setLayouts) const
234 {
235 VkPushConstantRange range{};
236 range.stageFlags = VK_SHADER_STAGE_ALL;
237 range.offset = 0;
238 range.size = static_cast<uint32_t>(sizeof(PushConstant));
239 return createPipelineLayout(&range, setLayouts);
240 }
241
makeCommandPool(deUint32 qFamilyIndex) const242 Move<VkCommandPool> GPQInstanceBase::makeCommandPool (deUint32 qFamilyIndex) const
243 {
244 const VkCommandPoolCreateFlags flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
245 | (m_config.enableProtected ? VK_COMMAND_POOL_CREATE_PROTECTED_BIT : 0);
246 const VkCommandPoolCreateInfo commandPoolParams =
247 {
248 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
249 DE_NULL, // const void* pNext;
250 flags, // VkCommandPoolCreateFlags flags;
251 qFamilyIndex, // deUint32 queueFamilyIndex;
252 };
253
254 return createCommandPool(m_context.getDeviceInterface(), m_device.handle, &commandPoolParams);
255 }
256
createGraphicsPipeline(VkPipelineLayout pipelineLayout,VkRenderPass renderPass)257 Move<VkPipeline> GPQInstanceBase::createGraphicsPipeline (VkPipelineLayout pipelineLayout, VkRenderPass renderPass)
258 {
259 const DeviceInterface& vkd = m_context.getDeviceInterface();
260 const VkDevice dev = m_device.handle;
261
262 auto sh = std::find_if(std::begin(m_shaders), std::end(m_shaders), [](const NamedShader& ns){ return ns.name == "vert"; });
263 if (*sh->handle == DE_NULL) sh->handle = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("vert"));
264 VkShaderModule vertex = *sh->handle;
265
266 sh = std::find_if(std::begin(m_shaders), std::end(m_shaders), [](const NamedShader& ns){ return ns.name == "frag"; });
267 if (*sh->handle == DE_NULL) sh->handle = createShaderModule(vkd, dev, m_context.getBinaryCollection().get("frag"));
268 VkShaderModule fragment = *sh->handle;
269
270 const std::vector<VkViewport> viewports { makeViewport(m_config.width, m_config.height) };
271 const std::vector<VkRect2D> scissors { makeRect2D(m_config.width, m_config.height) };
272 const auto vertexBinding = makeVertexInputBindingDescription(0u, static_cast<deUint32>(2 * sizeof(float)), VK_VERTEX_INPUT_RATE_VERTEX);
273 const auto vertexAttrib = makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u);
274 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo
275 {
276 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
277 nullptr, // const void* pNext;
278 0u, // VkPipelineVertexInputStateCreateFlags flags;
279 1u, // deUint32 vertexBindingDescriptionCount;
280 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
281 1u, // deUint32 vertexAttributeDescriptionCount;
282 &vertexAttrib // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
283 };
284
285 return makeGraphicsPipeline(vkd, dev, pipelineLayout,vertex,VkShaderModule(0),
286 VkShaderModule(0),VkShaderModule(0),fragment,renderPass,viewports, scissors,
287 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,0,0,&vertexInputStateCreateInfo);
288 }
289
createComputePipeline(VkPipelineLayout pipelineLayout,bool producer)290 Move<VkPipeline> GPQInstanceBase::createComputePipeline (VkPipelineLayout pipelineLayout, bool producer)
291 {
292 const DeviceInterface& vk = m_context.getDeviceInterface();
293 const VkDevice dev = m_device.handle;
294
295 const std::string compName = producer ? "cpyb" : "cpyi";
296 auto comp = std::find_if(std::begin(m_shaders), std::end(m_shaders), [&](const NamedShader& ns){ return ns.name == compName; });
297 if (*comp->handle == DE_NULL) comp->handle = createShaderModule(vk, dev, m_context.getBinaryCollection().get(compName));
298 VkShaderModule compute = *comp->handle;
299
300 VkPipelineShaderStageCreateInfo sci{};
301 sci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
302 sci.pNext = nullptr;
303 sci.flags = VkPipelineShaderStageCreateFlags(0);
304 sci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
305 sci.module = compute;
306 sci.pName = "main";
307 sci.pSpecializationInfo = nullptr;
308
309 VkComputePipelineCreateInfo ci{};
310 ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
311 ci.pNext = nullptr;
312 ci.flags = VkPipelineCreateFlags(0);
313 ci.stage = sci;
314 ci.layout = pipelineLayout;
315 ci.basePipelineHandle = VkPipeline(0);
316 ci.basePipelineIndex = 0;
317
318 return vk::createComputePipeline(vk, dev, VkPipelineCache(0), &ci, nullptr);
319 }
320
321 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit);
submitCommands(VkCommandBuffer producerCmd,VkCommandBuffer consumerCmd) const322 void GPQInstanceBase::submitCommands (VkCommandBuffer producerCmd, VkCommandBuffer consumerCmd) const
323 {
324 const DeviceInterface& vkd = m_context.getDeviceInterface();
325 const VkDevice dev = m_device.handle;
326
327 Move<VkSemaphore> sem = createSemaphore(vkd, dev);
328 Move<VkFence> fence = createFence(vkd, dev);
329
330 VkProtectedSubmitInfo protectedSubmitInfo
331 {
332 VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO, // VkStructureType sType;
333 nullptr, // void* pNext;
334 VK_TRUE // VkBool32 protectedSubmit;
335 };
336
337 const VkSubmitInfo producerSubmitInfo
338 {
339 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
340 m_config.enableProtected
341 ? &protectedSubmitInfo : nullptr, // const void* pNext;
342 0, // deUint32 waitSemaphoreCount;
343 nullptr, // const VkSemaphore* pWaitSemaphores;
344 nullptr, // const VkPipelineStageFlags* pWaitDstStageMask;
345 1u, // deUint32 commandBufferCount;
346 &producerCmd, // const VkCommandBuffer* pCommandBuffers;
347 1u, // deUint32 signalSemaphoreCount;
348 &sem.get(), // const VkSemaphore* pSignalSemaphores;
349 };
350
351 const VkPipelineStageFlags dstWaitStages = VK_PIPELINE_STAGE_TRANSFER_BIT |
352 queueFlagBitToPipelineStage(m_config.transitionTo);
353 const VkSubmitInfo consumerSubmitInfo
354 {
355 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
356 m_config.enableProtected
357 ? &protectedSubmitInfo : nullptr, // const void* pNext;
358 1u, // deUint32 waitSemaphoreCount;
359 &sem.get(), // const VkSemaphore* pWaitSemaphores;
360 &dstWaitStages, // const VkPipelineStageFlags* pWaitDstStageMask;
361 1u, // deUint32 commandBufferCount;
362 &consumerCmd, // const VkCommandBuffer* pCommandBuffers;
363 0, // deUint32 signalSemaphoreCount;
364 nullptr, // const VkSemaphore* pSignalSemaphores;
365 };
366
367 switch (m_config.syncType)
368 {
369 case SyncType::None:
370 submitCommandsAndWait(vkd, dev, m_device.queueFrom, producerCmd);
371 submitCommandsAndWait(vkd, dev, m_device.queueTo, consumerCmd);
372 break;
373 case SyncType::Semaphore:
374 VK_CHECK(vkd.queueSubmit(m_device.queueFrom, 1u, &producerSubmitInfo, VkFence(0)));
375 VK_CHECK(vkd.queueSubmit(m_device.queueTo, 1u, &consumerSubmitInfo, *fence));
376 VK_CHECK(vkd.waitForFences(dev, 1u, &fence.get(), DE_TRUE, ~0ull));
377 break;
378 }
379 }
380
381 template<VkQueueFlagBits, VkQueueFlagBits> class GPQInstance;
382 #define DECLARE_INSTANCE(flagsFrom_, flagsTo_) \
383 template<> class GPQInstance<flagsFrom_, flagsTo_> : public GPQInstanceBase \
384 { public: GPQInstance (Context& ctx, const TestConfig& cfg) \
385 : GPQInstanceBase(ctx, cfg) { } \
386 virtual tcu::TestStatus iterate (void) override; }
387
388 DECLARE_INSTANCE(VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT);
389 DECLARE_INSTANCE(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT);
390
391 class GPQCase;
392 typedef TestInstance* (GPQCase::* CreateInstanceProc)(Context&) const;
393 typedef std::pair<VkQueueFlagBits,VkQueueFlagBits> CreateInstanceKey;
394 typedef std::map<CreateInstanceKey, CreateInstanceProc> CreateInstanceMap;
395 #define MAPENTRY(from_,to_) m_createInstanceMap[{from_,to_}] = &GPQCase::createInstance<from_,to_>
396
397 class GPQCase : public TestCase
398 {
399 public:
400 GPQCase (tcu::TestContext& ctx,
401 const std::string& name,
402 const TestConfig& cfg);
403 void initPrograms (SourceCollections& programs) const override;
404 TestInstance* createInstance (Context& context) const override;
405 void checkSupport (Context& context) const override;
406 static deUint32 testValue;
407
408 private:
409 template<VkQueueFlagBits, VkQueueFlagBits>
410 TestInstance* createInstance (Context& context) const;
411 mutable TestConfig m_config;
412 CreateInstanceMap m_createInstanceMap;
413 };
414 deUint32 GPQCase::testValue = 113;
415
GPQCase(tcu::TestContext & ctx,const std::string & name,const TestConfig & cfg)416 GPQCase::GPQCase (tcu::TestContext& ctx,
417 const std::string& name,
418 const TestConfig& cfg)
419 : TestCase (ctx, name)
420 , m_config (cfg)
421 , m_createInstanceMap ()
422 {
423 MAPENTRY(VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT);
424 MAPENTRY(VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT);
425 }
426
queueFlagBitToPipelineStage(VkQueueFlagBits bit)427 VkPipelineStageFlags queueFlagBitToPipelineStage (VkQueueFlagBits bit)
428 {
429 switch (bit) {
430 case VK_QUEUE_COMPUTE_BIT:
431 return VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
432 case VK_QUEUE_GRAPHICS_BIT:
433 return VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
434 default:
435 DE_ASSERT(VK_FALSE);
436 }
437 return VK_QUEUE_FLAG_BITS_MAX_ENUM;
438 }
439
440 template<VkQueueFlagBits flagsFrom, VkQueueFlagBits flagsTo>
createInstance(Context & context) const441 TestInstance* GPQCase::createInstance (Context& context) const
442 {
443 return new GPQInstance<flagsFrom, flagsTo>(context, m_config);
444 }
445
createInstance(Context & context) const446 TestInstance* GPQCase::createInstance (Context& context) const
447 {
448 const CreateInstanceKey key(m_config.transitionFrom, m_config.transitionTo);
449 return (this->*(m_createInstanceMap.at(key)))(context);
450 }
451
operator <<(std::ostream & str,const VkQueueFlagBits & bit)452 std::ostream& operator<<(std::ostream& str, const VkQueueFlagBits& bit)
453 {
454 const char* s = nullptr;
455 const auto d = std::to_string(bit);
456 switch (bit)
457 {
458 case VK_QUEUE_GRAPHICS_BIT: s = "VK_QUEUE_GRAPHICS_BIT"; break;
459 case VK_QUEUE_COMPUTE_BIT: s = "VK_QUEUE_COMPUTE_BIT"; break;
460 case VK_QUEUE_TRANSFER_BIT: s = "VK_QUEUE_TRANSFER_BIT"; break;
461 case VK_QUEUE_SPARSE_BINDING_BIT: s = "VK_QUEUE_SPARSE_BINDING_BIT"; break;
462 case VK_QUEUE_PROTECTED_BIT: s = "VK_QUEUE_PROTECTED_BIT"; break;
463 default: s = d.c_str(); break;
464 }
465 return (str << s);
466 }
467
checkSupport(Context & context) const468 void GPQCase::checkSupport (Context& context) const
469 {
470 const InstanceInterface& vki = context.getInstanceInterface();
471 const VkPhysicalDevice dev = context.getPhysicalDevice();
472
473 context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
474 context.requireDeviceFunctionality("VK_EXT_global_priority_query");
475 context.requireDeviceFunctionality("VK_EXT_global_priority");
476
477 if (!m_config.selectFormat(vki, dev, { VK_FORMAT_R32_SINT, VK_FORMAT_R32_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8_UINT }))
478 {
479 TCU_THROW(NotSupportedError, "Unable to find a proper format");
480 }
481
482 VkPhysicalDeviceProtectedMemoryFeatures memFeatures
483 {
484 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
485 nullptr,
486 VK_FALSE
487 };
488 VkPhysicalDeviceFeatures2 devFeatures
489 {
490 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
491 &memFeatures,
492 {}
493 };
494 vki.getPhysicalDeviceFeatures2(dev, &devFeatures);
495
496 if (m_config.enableProtected && (VK_FALSE == memFeatures.protectedMemory))
497 {
498 TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_PROTECTED_BIT not supported");
499 }
500
501 const VkBool32 sparseEnabled = devFeatures.features.sparseBinding & devFeatures.features.sparseResidencyBuffer & devFeatures.features.sparseResidencyImage2D;
502 if (m_config.enableSparseBinding && (VK_FALSE == sparseEnabled))
503 {
504 TCU_THROW(NotSupportedError, "Queue families with VK_QUEUE_SPARSE_BINDING_BIT not supported");
505 }
506
507 auto assertUnavailableQueue = [](const deUint32 qIdx, VkQueueFlagBits qfb, VkQueueGlobalPriorityKHR qgp)
508 {
509 if (qIdx == INVALID_UINT32) {
510 std::ostringstream buf;
511 buf << "Unable to find queue " << qfb << " with priority " << qgp;
512 buf.flush();
513 TCU_THROW(NotSupportedError, buf.str());
514 }
515 };
516
517 VkQueueFlags flagsFrom = m_config.transitionFrom;
518 VkQueueFlags flagsTo = m_config.transitionTo;
519 if (m_config.enableProtected)
520 {
521 flagsFrom |= VK_QUEUE_PROTECTED_BIT;
522 flagsTo |= VK_QUEUE_PROTECTED_BIT;
523 }
524 if (m_config.enableSparseBinding)
525 {
526 flagsFrom |= VK_QUEUE_SPARSE_BINDING_BIT;
527 flagsTo |= VK_QUEUE_SPARSE_BINDING_BIT;
528 }
529
530 const deUint32 queueFromIndex = findQueueFamilyIndex(vki, dev, m_config.priorityFrom,
531 flagsFrom, SpecialDevice::getColissionFlags(flagsFrom),
532 INVALID_UINT32);
533 assertUnavailableQueue(queueFromIndex, m_config.transitionFrom, m_config.priorityFrom);
534
535 const deUint32 queueToIndex = findQueueFamilyIndex(vki, dev, m_config.priorityTo,
536 flagsTo, SpecialDevice::getColissionFlags(flagsTo),
537 queueFromIndex);
538 assertUnavailableQueue(queueToIndex, m_config.transitionTo, m_config.priorityTo);
539
540 if (queueFromIndex == queueToIndex)
541 {
542 std::ostringstream buf;
543 buf << "Unable to find separate queues " << m_config.transitionFrom << " and " << m_config.transitionTo;
544 buf.flush();
545 TCU_THROW(NotSupportedError, buf.str());
546 }
547 }
548
initPrograms(SourceCollections & programs) const549 void GPQCase::initPrograms (SourceCollections& programs) const
550 {
551 const std::string producerComp(R"glsl(
552 #version 450
553 layout(binding=0) buffer S { float src[]; };
554 layout(binding=1) buffer D { float dst[]; };
555 layout(local_size_x=1,local_size_y=1) in;
556 void main() {
557 dst[gl_GlobalInvocationID.x] = src[gl_GlobalInvocationID.x];
558 }
559 )glsl");
560
561 const tcu::StringTemplate consumerComp(R"glsl(
562 #version 450
563 layout(local_size_x=1,local_size_y=1) in;
564 layout(${IMAGE_FORMAT}, binding=0) readonly uniform ${IMAGE_TYPE} srcImage;
565 layout(binding=1) writeonly coherent buffer Pixels { uint data[]; } dstBuffer;
566 void main()
567 {
568 ivec2 srcIdx = ivec2(gl_GlobalInvocationID.xy);
569 int width = imageSize(srcImage).x;
570 int dstIdx = int(gl_GlobalInvocationID.y * width + gl_GlobalInvocationID.x);
571 dstBuffer.data[dstIdx] = uint(imageLoad(srcImage, srcIdx).r) == ${TEST_VALUE} ? 1 : 0;
572 }
573 )glsl");
574
575 const std::string vert(R"glsl(
576 #version 450
577 layout(location = 0) in vec2 pos;
578 void main()
579 {
580 gl_Position = vec4(pos, 0.0, 1.01);
581 }
582 )glsl");
583
584 const tcu::StringTemplate frag(R"glsl(
585 #version 450
586 layout(location = 0) out ${COLOR_TYPE} color;
587 void main()
588 {
589 color = ${COLOR_TYPE}(${TEST_VALUE},0,0,1);
590 }
591 )glsl");
592
593 const auto format = mapVkFormat(m_config.format);
594 const auto imageFormat = image::getShaderImageFormatQualifier(format);
595 const auto imageType = image::getShaderImageType(format, image::ImageType::IMAGE_TYPE_2D, false);
596 const auto colorType = image::getGlslAttachmentType(m_config.format); // ivec4
597
598 const std::map<std::string, std::string> abbreviations
599 {
600 { std::string("TEST_VALUE"), std::to_string(testValue) },
601 { std::string("IMAGE_FORMAT"), std::string(imageFormat) },
602 { std::string("IMAGE_TYPE"), std::string(imageType) },
603 { std::string("COLOR_TYPE"), std::string(colorType) },
604 };
605
606 programs.glslSources.add("cpyb") << glu::ComputeSource(producerComp);
607 programs.glslSources.add("cpyi") << glu::ComputeSource(consumerComp.specialize(abbreviations));
608 programs.glslSources.add("vert") << glu::VertexSource(vert);
609 programs.glslSources.add("frag") << glu::FragmentSource(frag.specialize(abbreviations));
610 }
611
iterate(void)612 tcu::TestStatus GPQInstance<VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT>::iterate (void)
613 {
614 if (VK_SUCCESS != m_device.createResult)
615 {
616 if (VK_ERROR_NOT_PERMITTED_KHR == m_device.createResult)
617 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Custom device creation returned " + std::string(getResultName(m_device.createResult)));
618 throw NotSupportedError(m_device.createResult, getResultName(m_device.createResult), m_device.createExpression, m_device.createFileName, m_device.createFileLine);
619 }
620
621 const InstanceInterface& vki = m_context.getInstanceInterface();
622 const DeviceInterface& vkd = m_context.getDeviceInterface();
623 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
624 const VkDevice device = m_device.handle;
625 Allocator& allocator = m_device.getAllocator();
626 const deUint32 producerIndex = m_device.queueFamilyIndexFrom;
627 const deUint32 consumerIndex = m_device.queueFamilyIndexTo;
628 const std::vector<deUint32> producerIndices { producerIndex };
629 const std::vector<deUint32> consumerIndices { consumerIndex };
630 const VkQueue producerQueue = m_device.queueFrom;
631 const VkQueue consumerQueue = m_device.queueTo;
632
633 // stagging buffer for vertices
634 const std::vector<float> positions { +1.f, -1.f, -1.f, -1.f, 0.f, +1.f };
635 const VkBufferCreateInfo posBuffInfo = makeBufferCreateInfo(positions.size() * sizeof(float), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, producerIndices);
636 BufferWithMemory positionsBuffer (vki, vkd, phys, device, allocator, posBuffInfo, MemoryRequirement::HostVisible);
637 std::copy_n(positions.data(), positions.size(), begin<float>(positionsBuffer.getHostPtr()));
638 const VkDescriptorBufferInfo posDsBuffInfo = makeDescriptorBufferInfo(positionsBuffer.get(), 0, positionsBuffer.getSize());
639
640 // vertex buffer
641 VkBufferCreateFlags vertCreateFlags = 0;
642 if (m_config.enableProtected) vertCreateFlags |= VK_BUFFER_CREATE_PROTECTED_BIT;
643 if (m_config.enableSparseBinding) vertCreateFlags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
644 const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
645 const MemoryRequirement vertMemReqs = (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
646 const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(positionsBuffer.getSize(), vertBuffUsage, producerIndices, vertCreateFlags);
647 const BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, vertMemReqs, producerQueue);
648 const VkDescriptorBufferInfo vertDsBuffInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBuffer.getSize());
649
650 // descriptor set for stagging and vertex buffers
651 Move<VkDescriptorPool> producerDsPool = DescriptorPoolBuilder()
652 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
653 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
654 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
655 Move<VkDescriptorSetLayout> producerDsLayout = DescriptorSetLayoutBuilder()
656 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
657 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
658 .build(vkd, device);
659 Move<VkDescriptorSet> producerDs = makeDescriptorSet(vkd, device, *producerDsPool, *producerDsLayout);
660 DescriptorSetUpdateBuilder()
661 .writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &posDsBuffInfo)
662 .writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &vertDsBuffInfo)
663 .update(vkd, device);
664
665 // consumer image
666 const uint32_t clearComp = 97;
667 const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
668 VkImageSubresourceRange imageResourceRange {};
669 const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
670 de::MovePtr<ImageWithMemory> image = createImage(imageUsage, consumerIndex, consumerQueue);
671 Move<VkImageView> view = createView(**image, imageResourceRange);
672 Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format);
673 Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *view, m_config.width, m_config.height);
674 const VkDescriptorImageInfo imageDsInfo = makeDescriptorImageInfo(VkSampler(0), *view, VK_IMAGE_LAYOUT_GENERAL);
675 const VkImageMemoryBarrier imageReadyBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
676 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
677 **image, imageResourceRange, consumerIndex, consumerIndex);
678 // stagging buffer for result
679 const VkDeviceSize resultBuffSize = (m_config.width * m_config.height * mapVkFormat(m_config.format).getPixelSize());
680 const VkBufferCreateInfo resultBuffInfo = makeBufferCreateInfo(resultBuffSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, consumerIndices);
681 BufferWithMemory resultBuffer (vki, vkd, phys, device, allocator, resultBuffInfo, MemoryRequirement::HostVisible);
682 const VkDescriptorBufferInfo resultDsBuffInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBuffSize);
683 const VkMemoryBarrier resultReadyBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
684
685 // descriptor set for consumer image and result buffer
686 Move<VkDescriptorPool> consumerDsPool = DescriptorPoolBuilder()
687 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
688 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
689 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
690 Move<VkDescriptorSetLayout> consumerDsLayout = DescriptorSetLayoutBuilder()
691 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
692 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
693 .build(vkd, device);
694 Move<VkDescriptorSet> consumerDs = makeDescriptorSet(vkd, device, *consumerDsPool, *consumerDsLayout);
695
696 DescriptorSetUpdateBuilder()
697 .writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageDsInfo)
698 .writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultDsBuffInfo)
699 .update(vkd, device);
700
701 Move<VkPipelineLayout> producerLayout = createPipelineLayout<>({ *producerDsLayout });
702 Move<VkPipeline> producerPipeline = createComputePipeline(*producerLayout, true);
703
704 Move<VkPipelineLayout> consumerLayout = createPipelineLayout<>({ *consumerDsLayout });
705 Move<VkPipeline> consumerPipeline = createGraphicsPipeline(*consumerLayout, *renderPass);
706
707 Move<VkPipelineLayout> resultLayout = createPipelineLayout<>({ *consumerDsLayout });
708 Move<VkCommandPool> resultPool = makeCommandPool(consumerIndex);
709 Move<VkPipeline> resultPipeline = createComputePipeline(*resultLayout, false);
710
711 Move<VkCommandPool> producerPool = makeCommandPool(producerIndex);
712 Move<VkCommandPool> consumerPool = makeCommandPool(consumerIndex);
713 Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
714 Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
715
716 beginCommandBuffer(vkd, *producerCmd);
717 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerPipeline);
718 vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producerLayout, 0, 1, &(*producerDs), 0, nullptr);
719 vkd.cmdDispatch(*producerCmd, deUint32(positions.size()), 1, 1);
720 endCommandBuffer(vkd, *producerCmd);
721
722 beginCommandBuffer(vkd, *consumerCmd);
723 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerPipeline);
724 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *resultPipeline);
725 vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *consumerLayout, 0, 1, &(*consumerDs), 0, nullptr);
726 vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *resultLayout, 0, 1, &(*consumerDs), 0, nullptr);
727 vkd.cmdBindVertexBuffers(*consumerCmd, 0, 1, vertexBuffer.getPtr(), &static_cast<const VkDeviceSize&>(0));
728
729 beginRenderPass(vkd, *consumerCmd, *renderPass, *framebuffer, makeRect2D(m_config.width, m_config.height), clearColor);
730 vkd.cmdDraw(*consumerCmd, deUint32(positions.size()), 1, 0, 0);
731 endRenderPass(vkd, *consumerCmd);
732 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
733 0u, nullptr, 0u, nullptr, 1u, &imageReadyBarrier);
734
735 vkd.cmdDispatch(*consumerCmd, m_config.width, m_config.height, 1);
736 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
737 1u, &resultReadyBarrier, 0u, nullptr, 0u, nullptr);
738 endCommandBuffer(vkd, *consumerCmd);
739
740 submitCommands(*producerCmd, *consumerCmd);
741
742 resultBuffer.invalidateAlloc(vkd, device);
743 const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), m_config.width, m_config.height, 1, resultBuffer.getHostPtr());
744 const deUint32 resultValue = resultBufferAccess.getPixelUint(0, 0).x();
745 const deUint32 expectedValue = 1;
746 const bool ok = (resultValue == expectedValue);
747 if (!ok)
748 {
749 m_context.getTestContext().getLog()
750 << tcu::TestLog::Message << "Expected value: " << expectedValue << ", got " << resultValue << tcu::TestLog::EndMessage;
751 }
752
753 return ok ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
754 }
755
iterate(void)756 tcu::TestStatus GPQInstance<VK_QUEUE_GRAPHICS_BIT, VK_QUEUE_COMPUTE_BIT>::iterate (void)
757 {
758 if (VK_SUCCESS != m_device.createResult)
759 {
760 if (VK_ERROR_NOT_PERMITTED_KHR == m_device.createResult)
761 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Custom device creation returned " + std::string(getResultName(m_device.createResult)));
762 throw NotSupportedError(m_device.createResult, getResultName(m_device.createResult), m_device.createExpression, m_device.createFileName, m_device.createFileLine);
763 }
764
765 const InstanceInterface& vki = m_context.getInstanceInterface();
766 const DeviceInterface& vkd = m_context.getDeviceInterface();
767 const VkPhysicalDevice phys = m_context.getPhysicalDevice();
768 const VkDevice device = m_device.handle;
769 Allocator& allocator = m_device.getAllocator();
770 const deUint32 producerIndex = m_device.queueFamilyIndexFrom;
771 const deUint32 consumerIndex = m_device.queueFamilyIndexTo;
772 const std::vector<deUint32> producerIndices { producerIndex };
773 const std::vector<deUint32> consumerIndices { consumerIndex };
774 const VkQueue producerQueue = m_device.queueFrom;
775
776 // stagging buffer for vertices
777 const std::vector<float> positions { +1.f, -1.f, -1.f, -1.f, 0.f, +1.f };
778 const VkBufferCreateInfo positionBuffInfo = makeBufferCreateInfo(positions.size() * sizeof(float), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, producerIndices);
779 BufferWithMemory positionsBuffer (vki, vkd, phys, device, allocator, positionBuffInfo, MemoryRequirement::HostVisible);
780 std::copy_n(positions.data(), positions.size(), begin<float>(positionsBuffer.getHostPtr()));
781 const VkDescriptorBufferInfo posDsBuffInfo = makeDescriptorBufferInfo(positionsBuffer.get(), 0, positionsBuffer.getSize());
782
783 // vertex buffer
784 VkBufferCreateFlags vertCreateFlags = 0;
785 if (m_config.enableProtected) vertCreateFlags |= VK_BUFFER_CREATE_PROTECTED_BIT;
786 if (m_config.enableSparseBinding) vertCreateFlags |= VK_BUFFER_CREATE_SPARSE_BINDING_BIT;
787 const VkBufferUsageFlags vertBuffUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
788 const MemoryRequirement vertMemReqs = (m_config.enableProtected ? MemoryRequirement::Protected : MemoryRequirement::Any);
789 const VkBufferCreateInfo vertBuffInfo = makeBufferCreateInfo(positionsBuffer.getSize(), vertBuffUsage, producerIndices, vertCreateFlags);
790 const BufferWithMemory vertexBuffer (vki, vkd, phys, device, allocator, vertBuffInfo, vertMemReqs, producerQueue);
791 const VkDescriptorBufferInfo vertDsBuffInfo = makeDescriptorBufferInfo(vertexBuffer.get(), 0ull, vertexBuffer.getSize());
792 const VkBufferMemoryBarrier producerReadyBarrier= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
793 vertexBuffer.get(), 0, vertexBuffer.getSize(), producerIndex, producerIndex);
794
795 // descriptor set for stagging and vertex buffers
796 Move<VkDescriptorPool> producerDsPool = DescriptorPoolBuilder()
797 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
798 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
799 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
800 Move<VkDescriptorSetLayout> producerDsLayout = DescriptorSetLayoutBuilder()
801 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
802 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
803 .build(vkd, device);
804 Move<VkDescriptorSet> producerDs = makeDescriptorSet(vkd, device, *producerDsPool, *producerDsLayout);
805 DescriptorSetUpdateBuilder()
806 .writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &posDsBuffInfo)
807 .writeSingle(*producerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &vertDsBuffInfo)
808 .update(vkd, device);
809
810 // producer image
811 const uint32_t clearComp = 97;
812 const VkClearValue clearColor = makeClearValueColorU32(clearComp, clearComp, clearComp, clearComp);
813 VkImageSubresourceRange imageResourceRange {};
814 const VkImageUsageFlags imageUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
815 de::MovePtr<ImageWithMemory> image = createImage(imageUsage, producerIndex, producerQueue);
816 Move<VkImageView> view = createView(**image, imageResourceRange);
817 Move<VkRenderPass> renderPass = makeRenderPass(vkd, device, m_config.format);
818 Move<VkFramebuffer> framebuffer = makeFramebuffer(vkd, device, *renderPass, *view, m_config.width, m_config.height);
819 const VkDescriptorImageInfo imageDsInfo = makeDescriptorImageInfo(VkSampler(0), *view, VK_IMAGE_LAYOUT_GENERAL);
820 const VkImageMemoryBarrier imageReadyBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT,
821 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL,
822 **image, imageResourceRange, producerIndex, producerIndex);
823
824 // stagging buffer for result
825 const VkDeviceSize resultBufferSize = (m_config.width * m_config.height * mapVkFormat(m_config.format).getPixelSize());
826 const VkBufferCreateInfo resultBufferInfo = makeBufferCreateInfo(resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, consumerIndices);
827 BufferWithMemory resultBuffer (vki, vkd, phys, device, allocator, resultBufferInfo, MemoryRequirement::HostVisible);
828 const VkDescriptorBufferInfo resultDsBuffInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, resultBufferSize);
829 const VkBufferMemoryBarrier resultReadyBarrier = makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
830 resultBuffer.get(), 0, resultBufferSize, consumerIndex, consumerIndex);
831
832 // descriptor set for consumer image and result buffer
833 Move<VkDescriptorPool> consumerDsPool = DescriptorPoolBuilder()
834 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
835 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
836 .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
837 Move<VkDescriptorSetLayout> consumerDsLayout = DescriptorSetLayoutBuilder()
838 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_ALL)
839 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL)
840 .build(vkd, device);
841 Move<VkDescriptorSet> consumerDs = makeDescriptorSet(vkd, device, *consumerDsPool, *consumerDsLayout);
842
843 DescriptorSetUpdateBuilder()
844 .writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageDsInfo)
845 .writeSingle(*consumerDs, DescriptorSetUpdateBuilder::Location::binding(1), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultDsBuffInfo)
846 .update(vkd, device);
847
848 Move<VkPipelineLayout> producer1Layout = createPipelineLayout<>({ *producerDsLayout });
849 Move<VkPipeline> producer1Pipeline = createComputePipeline(*producer1Layout, true);
850 Move<VkPipelineLayout> producer2Layout = createPipelineLayout<>({});
851 Move<VkPipeline> producer2Pipeline = createGraphicsPipeline(*producer2Layout, *renderPass);
852
853 Move<VkPipelineLayout> consumerLayout = createPipelineLayout<>({ *consumerDsLayout });
854 Move<VkPipeline> consumerPipeline = createComputePipeline(*consumerLayout, false);
855
856 Move<VkCommandPool> producerPool = makeCommandPool(producerIndex);
857 Move<VkCommandPool> consumerPool = makeCommandPool(consumerIndex);
858 Move<VkCommandBuffer> producerCmd = allocateCommandBuffer(vkd, device, *producerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
859 Move<VkCommandBuffer> consumerCmd = allocateCommandBuffer(vkd, device, *consumerPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
860
861
862 beginCommandBuffer(vkd, *producerCmd);
863 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producer1Pipeline);
864 vkd.cmdBindPipeline(*producerCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, *producer2Pipeline);
865 vkd.cmdBindVertexBuffers(*producerCmd, 0, 1, vertexBuffer.getPtr(), &static_cast<const VkDeviceSize&>(0));
866 vkd.cmdBindDescriptorSets(*producerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *producer1Layout, 0, 1, &producerDs.get(), 0, nullptr);
867 vkd.cmdDispatch(*producerCmd, deUint32(positions.size()), 1, 1);
868 vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0,
869 0, nullptr, 1, &producerReadyBarrier, 0, nullptr);
870 beginRenderPass(vkd, *producerCmd, *renderPass, *framebuffer, makeRect2D(m_config.width, m_config.height), clearColor);
871 vkd.cmdDraw(*producerCmd, deUint32(positions.size()), 1, 0, 0);
872 endRenderPass(vkd, *producerCmd);
873 vkd.cmdPipelineBarrier(*producerCmd, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0,
874 0u, nullptr, 0u, nullptr, 1u, &imageReadyBarrier);
875 endCommandBuffer(vkd, *producerCmd);
876
877 beginCommandBuffer(vkd, *consumerCmd);
878 vkd.cmdBindPipeline(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerPipeline);
879 vkd.cmdBindDescriptorSets(*consumerCmd, VK_PIPELINE_BIND_POINT_COMPUTE, *consumerLayout, 0, 1, &consumerDs.get(), 0, nullptr);
880 vkd.cmdDispatch(*consumerCmd, m_config.width, m_config.height, 1);
881 vkd.cmdPipelineBarrier(*consumerCmd, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
882 0, nullptr, 1, &resultReadyBarrier, 0, nullptr);
883 endCommandBuffer(vkd, *consumerCmd);
884
885 submitCommands(*producerCmd, *consumerCmd);
886
887 resultBuffer.invalidateAlloc(vkd, device);
888 const tcu::ConstPixelBufferAccess resultBufferAccess(mapVkFormat(m_config.format), m_config.width, m_config.height, 1, resultBuffer.getHostPtr());
889 const deUint32 resultValue = resultBufferAccess.getPixelUint(0, 0).x();
890 const deUint32 expectedValue = 1;
891 const bool ok = (resultValue == expectedValue);
892 if (!ok)
893 {
894 m_context.getTestContext().getLog()
895 << tcu::TestLog::Message << "Expected value: " << expectedValue << ", got " << resultValue << tcu::TestLog::EndMessage;
896 }
897
898 return ok ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
899 }
900
901 } // anonymous
902
createGlobalPriorityQueueTests(tcu::TestContext & testCtx)903 tcu::TestCaseGroup* createGlobalPriorityQueueTests (tcu::TestContext& testCtx)
904 {
905 typedef std::pair<VkQueueFlagBits, const char*> TransitionItem;
906 TransitionItem const transitions[]
907 {
908 { VK_QUEUE_GRAPHICS_BIT, "graphics" },
909 { VK_QUEUE_COMPUTE_BIT, "compute" },
910 };
911
912 auto mkGroupName = [](const TransitionItem& from, const TransitionItem& to) -> std::string
913 {
914 return std::string("from_") + from.second + std::string("_to_") + to.second;
915 };
916
917 std::pair<VkQueueFlags, const char*>
918 const modifiers[]
919 {
920 { 0, "no_modifiers" },
921 { VK_QUEUE_SPARSE_BINDING_BIT, "sparse" },
922 { VK_QUEUE_PROTECTED_BIT, "protected" }
923 };
924
925 std::pair<VkQueueGlobalPriorityKHR, const char*>
926 const prios[]
927 {
928 { VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR, "low" },
929 { VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR, "medium" },
930 { VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR, "high" },
931 { VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR, "realtime" },
932 };
933
934 std::pair<SyncType, const char*>
935 const syncs[]
936 {
937 { SyncType::None, "no_sync" },
938 { SyncType::Semaphore, "semaphore" },
939 };
940
941 const uint32_t dim0 = 34;
942 const uint32_t dim1 = 25;
943 bool swap = true;
944
945 auto rootGroup = new tcu::TestCaseGroup(testCtx, "global_priority_transition");
946
947 for (const auto& prio : prios)
948 {
949 auto prioGroup = new tcu::TestCaseGroup(testCtx, prio.second);
950
951 for (const auto& sync : syncs)
952 {
953 auto syncGroup = new tcu::TestCaseGroup(testCtx, sync.second);
954
955 for (const auto& mod : modifiers)
956 {
957 auto modGroup = new tcu::TestCaseGroup(testCtx, mod.second);
958
959 for (const auto& transitionFrom : transitions)
960 {
961 for (const auto& transitionTo : transitions)
962 {
963 if (transitionFrom != transitionTo)
964 {
965 TestConfig cfg{};
966 cfg.transitionFrom = transitionFrom.first;
967 cfg.transitionTo = transitionTo.first;
968 cfg.priorityFrom = prio.first;
969 cfg.priorityTo = prio.first;
970 cfg.syncType = sync.first;
971 cfg.enableProtected = (mod.first & VK_QUEUE_PROTECTED_BIT) != 0;
972 cfg.enableSparseBinding = (mod.first & VK_QUEUE_SPARSE_BINDING_BIT) != 0;
973 // Note that format is changing in GPQCase::checkSupport(...)
974 cfg.format = VK_FORMAT_R32G32B32A32_SFLOAT;
975 cfg.width = swap ? dim0 : dim1;
976 cfg.height = swap ? dim1 : dim0;
977
978 swap ^= true;
979
980 modGroup->addChild(new GPQCase(testCtx, mkGroupName(transitionFrom, transitionTo), cfg));
981 }
982 }
983 }
984 syncGroup->addChild(modGroup);
985 }
986 prioGroup->addChild(syncGroup);
987 }
988 rootGroup->addChild(prioGroup);
989 }
990
991 return rootGroup;
992 }
993
994 } // synchronization
995 } // vkt
996