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