xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawConcurrentTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Concurrent draw tests
23  * Tests that create queue for rendering as well as queue for
24  * compute, and trigger work on both pipelines at the same time,
25  * and finally verify that the results are as expected.
26  *//*--------------------------------------------------------------------*/
27 
28 #include "vktDrawConcurrentTests.hpp"
29 
30 #include "vktCustomInstancesDevices.hpp"
31 #include "vktTestCaseUtil.hpp"
32 #include "vktDrawTestCaseUtil.hpp"
33 #include "../compute/vktComputeTestsUtil.hpp"
34 
35 #include "vktDrawBaseClass.hpp"
36 
37 #include "tcuTestLog.hpp"
38 #include "tcuResource.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuRGBA.hpp"
42 
43 #include "vkDefs.hpp"
44 #include "vkCmdUtil.hpp"
45 #include "vkQueryUtil.hpp"
46 #include "vkBuilderUtil.hpp"
47 #include "vkBarrierUtil.hpp"
48 #include "vkObjUtil.hpp"
49 #include "vkDeviceUtil.hpp"
50 #include "vkSafetyCriticalUtil.hpp"
51 #include "vkBufferWithMemory.hpp"
52 
53 #include "deRandom.hpp"
54 
55 using namespace vk;
56 
57 namespace vkt
58 {
59 namespace Draw
60 {
61 namespace
62 {
63 
64 class ConcurrentDraw : public DrawTestsBaseClass
65 {
66 public:
67     typedef TestSpecBase TestSpec;
68     ConcurrentDraw(Context &context, TestSpec testSpec);
69     virtual tcu::TestStatus iterate(void);
70 };
71 
ConcurrentDraw(Context & context,TestSpec testSpec)72 ConcurrentDraw::ConcurrentDraw(Context &context, TestSpec testSpec)
73     : DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
74                          testSpec.groupParams, testSpec.topology)
75 {
76     m_data.push_back(VertexElementData(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
77     m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
78 
79     int refVertexIndex = 2;
80 
81     for (int i = 0; i < 1000; i++)
82     {
83         m_data.push_back(
84             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
85         m_data.push_back(
86             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
87         m_data.push_back(
88             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
89         m_data.push_back(
90             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
91         m_data.push_back(
92             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
93         m_data.push_back(
94             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
95     }
96     m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
97 
98     initialize();
99 }
100 
iterate(void)101 tcu::TestStatus ConcurrentDraw::iterate(void)
102 {
103     enum
104     {
105         NO_MATCH_FOUND     = ~((uint32_t)0),
106         ERROR_NONE         = 0,
107         ERROR_WAIT_COMPUTE = 1,
108         ERROR_WAIT_DRAW    = 2
109     };
110 
111     struct Queue
112     {
113         VkQueue queue;
114         uint32_t queueFamilyIndex;
115     };
116 
117     const uint32_t numValues = 1024;
118     const CustomInstance instance(createCustomInstanceFromContext(m_context));
119     const InstanceDriver &instanceDriver(instance.getDriver());
120     const VkPhysicalDevice physicalDevice =
121         chooseDevice(instanceDriver, instance, m_context.getTestContext().getCommandLine());
122     //
123     // const InstanceInterface& instance = m_context.getInstanceInterface();
124     // const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
125     const auto validation = m_context.getTestContext().getCommandLine().isValidationEnabled();
126     tcu::TestLog &log     = m_context.getTestContext().getLog();
127     Move<VkDevice> computeDevice;
128     std::vector<VkQueueFamilyProperties> queueFamilyProperties;
129     VkDeviceCreateInfo deviceInfo;
130     VkPhysicalDeviceFeatures deviceFeatures;
131     const float queuePriority = 1.0f;
132     VkDeviceQueueCreateInfo queueInfos;
133     Queue computeQueue = {DE_NULL, (uint32_t)NO_MATCH_FOUND};
134 
135     // Set up compute
136 
137     queueFamilyProperties = getPhysicalDeviceQueueFamilyProperties(instanceDriver, physicalDevice);
138 
139     for (uint32_t queueNdx = 0; queueNdx < queueFamilyProperties.size(); ++queueNdx)
140     {
141         if (queueFamilyProperties[queueNdx].queueFlags & VK_QUEUE_COMPUTE_BIT)
142         {
143             if (computeQueue.queueFamilyIndex == NO_MATCH_FOUND)
144                 computeQueue.queueFamilyIndex = queueNdx;
145         }
146     }
147 
148     if (computeQueue.queueFamilyIndex == NO_MATCH_FOUND)
149         TCU_THROW(NotSupportedError, "Compute queue couldn't be created");
150 
151     VkDeviceQueueCreateInfo queueInfo;
152     deMemset(&queueInfo, 0, sizeof(queueInfo));
153 
154     queueInfo.sType            = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
155     queueInfo.pNext            = DE_NULL;
156     queueInfo.flags            = (VkDeviceQueueCreateFlags)0u;
157     queueInfo.queueFamilyIndex = computeQueue.queueFamilyIndex;
158     queueInfo.queueCount       = 1;
159     queueInfo.pQueuePriorities = &queuePriority;
160 
161     queueInfos = queueInfo;
162 
163     deMemset(&deviceInfo, 0, sizeof(deviceInfo));
164     instanceDriver.getPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
165 
166     void *pNext = DE_NULL;
167 #ifdef CTS_USES_VULKANSC
168     VkDeviceObjectReservationCreateInfo memReservationInfo =
169         m_context.getTestContext().getCommandLine().isSubProcess() ? m_context.getResourceInterface()->getStatMax() :
170                                                                      resetDeviceObjectReservationCreateInfo();
171     memReservationInfo.pNext = pNext;
172     pNext                    = &memReservationInfo;
173 
174     VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features();
175     sc10Features.pNext                              = pNext;
176     pNext                                           = &sc10Features;
177 
178     VkPipelineCacheCreateInfo pcCI;
179     std::vector<VkPipelinePoolSize> poolSizes;
180     if (m_context.getTestContext().getCommandLine().isSubProcess())
181     {
182         if (m_context.getResourceInterface()->getCacheDataSize() > 0)
183         {
184             pcCI = {
185                 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType;
186                 DE_NULL,                                      // const void* pNext;
187                 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
188                     VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags;
189                 m_context.getResourceInterface()->getCacheDataSize(),     // uintptr_t initialDataSize;
190                 m_context.getResourceInterface()->getCacheData()          // const void* pInitialData;
191             };
192             memReservationInfo.pipelineCacheCreateInfoCount = 1;
193             memReservationInfo.pPipelineCacheCreateInfos    = &pcCI;
194         }
195 
196         poolSizes = m_context.getResourceInterface()->getPipelinePoolSizes();
197         if (!poolSizes.empty())
198         {
199             memReservationInfo.pipelinePoolSizeCount = uint32_t(poolSizes.size());
200             memReservationInfo.pPipelinePoolSizes    = poolSizes.data();
201         }
202     }
203 #endif // CTS_USES_VULKANSC
204 
205     deviceInfo.sType                   = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
206     deviceInfo.pNext                   = pNext;
207     deviceInfo.enabledExtensionCount   = 0u;
208     deviceInfo.ppEnabledExtensionNames = DE_NULL;
209     deviceInfo.enabledLayerCount       = 0u;
210     deviceInfo.ppEnabledLayerNames     = DE_NULL;
211     deviceInfo.pEnabledFeatures        = &deviceFeatures;
212     deviceInfo.queueCreateInfoCount    = 1;
213     deviceInfo.pQueueCreateInfos       = &queueInfos;
214 
215     computeDevice = createCustomDevice(validation, m_context.getPlatformInterface(), instance, instanceDriver,
216                                        physicalDevice, &deviceInfo);
217 
218 #ifndef CTS_USES_VULKANSC
219     de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<vk::DeviceDriver>(
220         new vk::DeviceDriver(m_context.getPlatformInterface(), instance, *computeDevice, m_context.getUsedApiVersion(),
221                              m_context.getTestContext().getCommandLine()));
222 #else
223     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
224         de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
225             new DeviceDriverSC(m_context.getPlatformInterface(), instance, *computeDevice,
226                                m_context.getTestContext().getCommandLine(), m_context.getResourceInterface(),
227                                m_context.getDeviceVulkanSC10Properties(), m_context.getDeviceProperties(),
228                                m_context.getUsedApiVersion()),
229             vk::DeinitDeviceDeleter(m_context.getResourceInterface().get(), *computeDevice));
230 #endif // CTS_USES_VULKANSC
231     vk::DeviceInterface &vk = *deviceDriver;
232 
233     vk.getDeviceQueue(*computeDevice, computeQueue.queueFamilyIndex, 0, &computeQueue.queue);
234 
235     // Create an input/output buffer
236     const VkPhysicalDeviceMemoryProperties memoryProperties =
237         getPhysicalDeviceMemoryProperties(instanceDriver, physicalDevice);
238 
239     de::MovePtr<SimpleAllocator> allocator =
240         de::MovePtr<SimpleAllocator>(new SimpleAllocator(vk, *computeDevice, memoryProperties));
241     const VkDeviceSize bufferSizeBytes = sizeof(uint32_t) * numValues;
242     const vk::BufferWithMemory buffer(vk, *computeDevice, *allocator,
243                                       makeBufferCreateInfo(bufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
244                                       MemoryRequirement::HostVisible);
245 
246     // Fill the buffer with data
247 
248     typedef std::vector<uint32_t> data_vector_t;
249     data_vector_t inputData(numValues);
250 
251     {
252         de::Random rnd(0x82ce7f);
253         const Allocation &bufferAllocation = buffer.getAllocation();
254         uint32_t *bufferPtr                = static_cast<uint32_t *>(bufferAllocation.getHostPtr());
255 
256         for (uint32_t i = 0; i < numValues; ++i)
257         {
258             uint32_t val = rnd.getUint32();
259             inputData[i] = val;
260             *bufferPtr++ = val;
261         }
262 
263         flushAlloc(vk, *computeDevice, bufferAllocation);
264     }
265 
266     // Create descriptor set
267 
268     const Unique<VkDescriptorSetLayout> descriptorSetLayout(
269         DescriptorSetLayoutBuilder()
270             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
271             .build(vk, *computeDevice));
272 
273     const Unique<VkDescriptorPool> descriptorPool(
274         DescriptorPoolBuilder()
275             .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
276             .build(vk, *computeDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
277 
278     const Unique<VkDescriptorSet> descriptorSet(
279         makeDescriptorSet(vk, *computeDevice, *descriptorPool, *descriptorSetLayout));
280 
281     const VkDescriptorBufferInfo bufferDescriptorInfo = makeDescriptorBufferInfo(*buffer, 0ull, bufferSizeBytes);
282     DescriptorSetUpdateBuilder()
283         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
284                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
285         .update(vk, *computeDevice);
286 
287     // Perform the computation
288 
289     const Unique<VkShaderModule> shaderModule(createShaderModule(
290         vk, *computeDevice, m_context.getBinaryCollection().get("vulkan/draw/ConcurrentPayload.comp"), 0u));
291 
292     const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, *computeDevice, *descriptorSetLayout));
293     const Unique<VkPipeline> pipeline(makeComputePipeline(vk, *computeDevice, *pipelineLayout, *shaderModule));
294     const VkBufferMemoryBarrier hostWriteBarrier =
295         makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, *buffer, 0ull, bufferSizeBytes);
296     const VkBufferMemoryBarrier shaderWriteBarrier =
297         makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *buffer, 0ull, bufferSizeBytes);
298     const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, *computeDevice, computeQueue.queueFamilyIndex));
299     const Unique<VkCommandBuffer> computeCommandBuffer(
300         allocateCommandBuffer(vk, *computeDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
301 
302     // Compute command buffer
303 
304     beginCommandBuffer(vk, *computeCommandBuffer);
305     vk.cmdBindPipeline(*computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
306     vk.cmdBindDescriptorSets(*computeCommandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
307                              &descriptorSet.get(), 0u, DE_NULL);
308     vk.cmdPipelineBarrier(*computeCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
309                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &hostWriteBarrier, 0,
310                           (const VkImageMemoryBarrier *)DE_NULL);
311     vk.cmdDispatch(*computeCommandBuffer, 1, 1, 1);
312     vk.cmdPipelineBarrier(*computeCommandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
313                           (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &shaderWriteBarrier, 0,
314                           (const VkImageMemoryBarrier *)DE_NULL);
315     endCommandBuffer(vk, *computeCommandBuffer);
316 
317     const VkSubmitInfo submitInfo = {
318         VK_STRUCTURE_TYPE_SUBMIT_INFO,         // sType
319         DE_NULL,                               // pNext
320         0u,                                    // waitSemaphoreCount
321         DE_NULL,                               // pWaitSemaphores
322         (const VkPipelineStageFlags *)DE_NULL, // pWaitDstStageMask
323         1u,                                    // commandBufferCount
324         &computeCommandBuffer.get(),           // pCommandBuffers
325         0u,                                    // signalSemaphoreCount
326         DE_NULL                                // pSignalSemaphores
327     };
328 
329     // Set up draw
330 
331     const VkQueue drawQueue               = m_context.getUniversalQueue();
332     const VkDevice drawDevice             = m_context.getDevice();
333     const VkDeviceSize vertexBufferOffset = 0;
334     const VkBuffer vertexBuffer           = m_vertexBuffer->object();
335 
336 #ifndef CTS_USES_VULKANSC
337     if (m_groupParams->useSecondaryCmdBuffer)
338     {
339         // record secondary command buffer
340         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
341         {
342             beginSecondaryCmdBuffer(m_vk, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
343             beginDynamicRender(*m_secCmdBuffer);
344         }
345         else
346             beginSecondaryCmdBuffer(m_vk);
347 
348         m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
349         m_vk.cmdBindPipeline(*m_secCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
350         m_vk.cmdDraw(*m_secCmdBuffer, 6, 1, 2, 0);
351 
352         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
353             endDynamicRender(*m_secCmdBuffer);
354 
355         endCommandBuffer(m_vk, *m_secCmdBuffer);
356 
357         // record primary command buffer
358         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
359         preRenderBarriers();
360 
361         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
362             beginDynamicRender(*m_cmdBuffer, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
363 
364         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
365 
366         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
367             endDynamicRender(*m_cmdBuffer);
368 
369         endCommandBuffer(m_vk, *m_cmdBuffer);
370     }
371     else if (m_groupParams->useDynamicRendering)
372     {
373         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
374         preRenderBarriers();
375         beginDynamicRender(*m_cmdBuffer);
376 
377         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
378         m_vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
379         m_vk.cmdDraw(*m_cmdBuffer, 6, 1, 2, 0);
380 
381         endDynamicRender(*m_cmdBuffer);
382         endCommandBuffer(m_vk, *m_cmdBuffer);
383     }
384 #endif // CTS_USES_VULKANSC
385 
386     if (!m_groupParams->useDynamicRendering)
387     {
388         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
389         preRenderBarriers();
390         beginLegacyRender(*m_cmdBuffer);
391 
392         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
393         m_vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
394         m_vk.cmdDraw(*m_cmdBuffer, 6, 1, 2, 0);
395 
396         endLegacyRender(*m_cmdBuffer);
397         endCommandBuffer(m_vk, *m_cmdBuffer);
398     }
399 
400     const VkCommandBuffer drawCommandBuffer = m_cmdBuffer.get();
401     const bool useDeviceGroups              = false;
402     const uint32_t deviceMask               = 1u;
403     const Unique<VkFence> drawFence(createFence(vk, drawDevice));
404 
405     VkDeviceGroupSubmitInfo deviceGroupSubmitInfo = {
406         VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO, // VkStructureType sType;
407         DE_NULL,                                    // const void* pNext;
408         0u,                                         // uint32_t waitSemaphoreCount;
409         DE_NULL,                                    // const uint32_t* pWaitSemaphoreDeviceIndices;
410         1u,                                         // uint32_t commandBufferCount;
411         &deviceMask,                                // const uint32_t* pCommandBufferDeviceMasks;
412         0u,                                         // uint32_t signalSemaphoreCount;
413         DE_NULL,                                    // const uint32_t* pSignalSemaphoreDeviceIndices;
414     };
415 
416     const VkSubmitInfo drawSubmitInfo = {
417         VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType sType;
418         useDeviceGroups ? &deviceGroupSubmitInfo : DE_NULL, // const void* pNext;
419         0u,                                                 // uint32_t waitSemaphoreCount;
420         DE_NULL,                                            // const VkSemaphore* pWaitSemaphores;
421         (const VkPipelineStageFlags *)DE_NULL,              // const VkPipelineStageFlags* pWaitDstStageMask;
422         1u,                                                 // uint32_t commandBufferCount;
423         &drawCommandBuffer,                                 // const VkCommandBuffer* pCommandBuffers;
424         0u,                                                 // uint32_t signalSemaphoreCount;
425         DE_NULL,                                            // const VkSemaphore* pSignalSemaphores;
426     };
427 
428     const Unique<VkFence> computeFence(createFence(vk, *computeDevice));
429 
430     // Submit both compute and draw queues
431     VK_CHECK(vk.queueSubmit(computeQueue.queue, 1u, &submitInfo, *computeFence));
432     VK_CHECK(vk.queueSubmit(drawQueue, 1u, &drawSubmitInfo, *drawFence));
433 
434     int err = ERROR_NONE;
435 
436     if (VK_SUCCESS != vk.waitForFences(*computeDevice, 1u, &computeFence.get(), true, ~0ull))
437         err = ERROR_WAIT_COMPUTE;
438 
439     if (VK_SUCCESS != vk.waitForFences(drawDevice, 1u, &drawFence.get(), true, ~0ull))
440         err = ERROR_WAIT_DRAW;
441 
442         // Have to wait for all fences before calling fail, or some fence may be left hanging.
443 
444 #ifdef CTS_USES_VULKANSC
445     if (m_context.getTestContext().getCommandLine().isSubProcess())
446 #endif // CTS_USES_VULKANSC
447     {
448         if (err == ERROR_WAIT_COMPUTE)
449         {
450             return tcu::TestStatus::fail("Failed waiting for compute queue fence.");
451         }
452 
453         if (err == ERROR_WAIT_DRAW)
454         {
455             return tcu::TestStatus::fail("Failed waiting for draw queue fence.");
456         }
457 
458         // Validation - compute
459 
460         const Allocation &bufferAllocation = buffer.getAllocation();
461         invalidateAlloc(vk, *computeDevice, bufferAllocation);
462         const uint32_t *bufferPtr = static_cast<uint32_t *>(bufferAllocation.getHostPtr());
463 
464         for (uint32_t ndx = 0; ndx < numValues; ++ndx)
465         {
466             const uint32_t res = bufferPtr[ndx];
467             const uint32_t inp = inputData[ndx];
468             const uint32_t ref = ~inp;
469 
470             if (res != ref)
471             {
472                 std::ostringstream msg;
473                 msg << "Comparison failed (compute) for InOut.values[" << ndx << "] ref:" << ref << " res:" << res
474                     << " inp:" << inp;
475                 return tcu::TestStatus::fail(msg.str());
476             }
477         }
478     }
479 
480     // Validation - draw
481 
482     tcu::Texture2D referenceFrame(mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
483                                   (int)(0.5f + static_cast<float>(HEIGHT)));
484 
485     referenceFrame.allocLevel(0);
486 
487     const int32_t frameWidth  = referenceFrame.getWidth();
488     const int32_t frameHeight = referenceFrame.getHeight();
489 
490     tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
491 
492     ReferenceImageCoordinates refCoords;
493 
494     for (int y = 0; y < frameHeight; y++)
495     {
496         const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
497 
498         for (int x = 0; x < frameWidth; x++)
499         {
500             const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
501 
502             if ((yCoord >= refCoords.bottom && yCoord <= refCoords.top && xCoord >= refCoords.left &&
503                  xCoord <= refCoords.right))
504                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
505         }
506     }
507 
508     const VkOffset3D zeroOffset = {0, 0, 0};
509     const tcu::ConstPixelBufferAccess renderedFrame =
510         m_colorTargetImage->readSurface(drawQueue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
511                                         WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
512 
513     qpTestResult res = QP_TEST_RESULT_PASS;
514 
515     if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame, 0.05f,
516                            tcu::COMPARE_LOG_RESULT))
517     {
518         res = QP_TEST_RESULT_FAIL;
519     }
520     return tcu::TestStatus(res, qpGetTestResultName(res));
521 }
522 
checkSupport(Context & context,ConcurrentDraw::TestSpec testSpec)523 void checkSupport(Context &context, ConcurrentDraw::TestSpec testSpec)
524 {
525     if (testSpec.groupParams->useDynamicRendering)
526         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
527 }
528 
529 } // namespace
530 
ConcurrentDrawTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)531 ConcurrentDrawTests::ConcurrentDrawTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
532     : TestCaseGroup(testCtx, "concurrent")
533     , m_groupParams(groupParams)
534 {
535     /* Left blank on purpose */
536 }
537 
init(void)538 void ConcurrentDrawTests::init(void)
539 {
540     ConcurrentDraw::TestSpec testSpec{{{glu::SHADERTYPE_VERTEX, "vulkan/draw/VertexFetch.vert"},
541                                        {glu::SHADERTYPE_FRAGMENT, "vulkan/draw/VertexFetch.frag"},
542                                        {glu::SHADERTYPE_COMPUTE, "vulkan/draw/ConcurrentPayload.comp"}},
543                                       VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
544                                       m_groupParams};
545 
546     addChild(new InstanceFactory<ConcurrentDraw, FunctionSupport1<ConcurrentDraw::TestSpec>>(
547         m_testCtx, "compute_and_triangle_list", testSpec,
548         FunctionSupport1<ConcurrentDraw::TestSpec>::Args(checkSupport, testSpec)));
549 }
550 
551 } // namespace Draw
552 } // namespace vkt
553