1/*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 Google 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 21 * \brief Platform Synchronization tests 22 *//*--------------------------------------------------------------------*/ 23 24#include "vktSynchronizationSmokeTests.hpp" 25#include "vktSynchronizationUtil.hpp" 26 27#include "vktTestCaseUtil.hpp" 28#include "vktCustomInstancesDevices.hpp" 29 30#include "vkPlatform.hpp" 31#include "vkStrUtil.hpp" 32#include "vkRef.hpp" 33#include "vkRefUtil.hpp" 34#include "vkDeviceUtil.hpp" 35#include "vkSafetyCriticalUtil.hpp" 36 37#include "tcuTestLog.hpp" 38#include "tcuFormatUtil.hpp" 39#include "tcuCommandLine.hpp" 40 41#include "deUniquePtr.hpp" 42#include "deThread.hpp" 43#include "vkMemUtil.hpp" 44#include "vkQueryUtil.hpp" 45#include "vkPrograms.hpp" 46#include "vkTypeUtil.hpp" 47#include "vkCmdUtil.hpp" 48 49#include <limits> 50 51namespace vkt 52{ 53namespace synchronization 54{ 55 56using namespace vk; 57using namespace tcu; 58 59namespace 60{ 61 62using std::vector; 63using std::string; 64using tcu::TestLog; 65using de::MovePtr; 66 67static const deUint64 DEFAULT_TIMEOUT = 2ull*1000*1000*1000; //!< 2 seconds in nanoseconds 68 69struct SemaphoreTestConfig 70{ 71 SynchronizationType synchronizationType; 72 VkSemaphoreType semaphoreType; 73}; 74 75void initShaders(SourceCollections& shaderCollection, SemaphoreTestConfig) 76{ 77 shaderCollection.glslSources.add("glslvert") << 78 glu::VertexSource( 79 "#version 310 es\n" 80 "precision mediump float;\n" 81 "layout (location = 0) in vec4 vertexPosition;\n" 82 "void main()\n" 83 "{\n" 84 " gl_Position = vertexPosition;\n" 85 "}\n"); 86 87 shaderCollection.glslSources.add("glslfrag") << 88 glu::FragmentSource( 89 "#version 310 es\n" 90 "precision mediump float;\n" 91 "layout (location = 0) out vec4 outputColor;\n" 92 "void main()\n" 93 "{\n" 94 " outputColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 95 "}\n"); 96} 97 98void buildShaders(SourceCollections& shaderCollection) 99{ 100 initShaders(shaderCollection, { SynchronizationType::LEGACY, VK_SEMAPHORE_TYPE_BINARY }); 101} 102 103Move<VkDevice> createTestDevice (Context& context, SemaphoreTestConfig& config, const VkInstance& instance, const InstanceInterface& vki, deUint32* outQueueFamilyIndex) 104{ 105 const PlatformInterface& vkp = context.getPlatformInterface(); 106 VkPhysicalDevice physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine()); 107 bool validationEnabled = context.getTestContext().getCommandLine().isValidationEnabled(); 108 VkDeviceQueueCreateInfo queueInfo; 109 VkDeviceCreateInfo deviceInfo; 110 size_t queueNdx; 111 const deUint32 queueCount = 2u; 112 const float queuePriority[queueCount] = { 1.0f, 1.0f }; 113 114 const vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vki, physicalDevice); 115 const VkPhysicalDeviceFeatures physicalDeviceFeatures = getPhysicalDeviceFeatures(vki, physicalDevice); 116 VkPhysicalDeviceFeatures2 physicalDeviceFeatures2 { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, DE_NULL, physicalDeviceFeatures }; 117 VkPhysicalDeviceSynchronization2FeaturesKHR synchronization2Features { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR, DE_NULL, DE_TRUE }; 118 VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreFeatures { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES, DE_NULL, DE_TRUE }; 119 void** nextPtr = &physicalDeviceFeatures2.pNext; 120 121 for (queueNdx = 0; queueNdx < queueProps.size(); queueNdx++) 122 { 123 if ((queueProps[queueNdx].queueFlags & VK_QUEUE_GRAPHICS_BIT) == VK_QUEUE_GRAPHICS_BIT && (queueProps[queueNdx].queueCount >= queueCount)) 124 break; 125 } 126 127 if (queueNdx >= queueProps.size()) 128 { 129 // No queue family index found 130 std::ostringstream msg; 131 msg << "Cannot create device with " << queueCount << " graphics queues"; 132 133 throw tcu::NotSupportedError(msg.str()); 134 } 135 136 deMemset(&queueInfo, 0, sizeof(queueInfo)); 137 deMemset(&deviceInfo, 0, sizeof(deviceInfo)); 138 139 deMemset(&queueInfo, 0xcd, sizeof(queueInfo)); 140 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 141 queueInfo.pNext = DE_NULL; 142 queueInfo.flags = (VkDeviceQueueCreateFlags)0u; 143 queueInfo.queueFamilyIndex = (deUint32)queueNdx; 144 queueInfo.queueCount = queueCount; 145 queueInfo.pQueuePriorities = queuePriority; 146 147 vector<const char*> deviceExtensions; 148 bool useFeatures2 = false; 149 if (config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) 150 { 151 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_timeline_semaphore")) 152 deviceExtensions.push_back("VK_KHR_timeline_semaphore"); 153 addToChainVulkanStructure(&nextPtr, timelineSemaphoreFeatures); 154 useFeatures2 = true; 155 } 156 if (config.synchronizationType == SynchronizationType::SYNCHRONIZATION2) 157 { 158 deviceExtensions.push_back("VK_KHR_synchronization2"); 159 addToChainVulkanStructure(&nextPtr, synchronization2Features); 160 useFeatures2 = true; 161 } 162 163 void* pNext = !useFeatures2 ? DE_NULL : &physicalDeviceFeatures2; 164#ifdef CTS_USES_VULKANSC 165 VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo(); 166 memReservationInfo.pNext = pNext; 167 pNext = &memReservationInfo; 168 169 VkPhysicalDeviceVulkanSC10Features sc10Features = createDefaultSC10Features(); 170 sc10Features.pNext = pNext; 171 pNext = &sc10Features; 172 173 VkPipelineCacheCreateInfo pcCI; 174 std::vector<VkPipelinePoolSize> poolSizes; 175 if (context.getTestContext().getCommandLine().isSubProcess()) 176 { 177 if (context.getResourceInterface()->getCacheDataSize() > 0) 178 { 179 pcCI = 180 { 181 VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType; 182 DE_NULL, // const void* pNext; 183 VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT | 184 VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT, // VkPipelineCacheCreateFlags flags; 185 context.getResourceInterface()->getCacheDataSize(), // deUintptr initialDataSize; 186 context.getResourceInterface()->getCacheData() // const void* pInitialData; 187 }; 188 memReservationInfo.pipelineCacheCreateInfoCount = 1; 189 memReservationInfo.pPipelineCacheCreateInfos = &pcCI; 190 } 191 192 poolSizes = context.getResourceInterface()->getPipelinePoolSizes(); 193 if (!poolSizes.empty()) 194 { 195 memReservationInfo.pipelinePoolSizeCount = deUint32(poolSizes.size()); 196 memReservationInfo.pPipelinePoolSizes = poolSizes.data(); 197 } 198 } 199#endif // CTS_USES_VULKANSC 200 201 deMemset(&deviceInfo, 0xcd, sizeof(deviceInfo)); 202 deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 203 deviceInfo.pNext = pNext; 204 deviceInfo.flags = (VkDeviceCreateFlags)0u; 205 deviceInfo.queueCreateInfoCount = 1u; 206 deviceInfo.pQueueCreateInfos = &queueInfo; 207 deviceInfo.enabledExtensionCount = static_cast<deUint32>(deviceExtensions.size()); 208 deviceInfo.ppEnabledExtensionNames = deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0]; 209 deviceInfo.enabledLayerCount = 0u; 210 deviceInfo.ppEnabledLayerNames = DE_NULL; 211 deviceInfo.pEnabledFeatures = !useFeatures2 ? &physicalDeviceFeatures : DE_NULL; 212 213 *outQueueFamilyIndex = queueInfo.queueFamilyIndex; 214 215 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceInfo); 216} 217 218struct BufferParameters 219{ 220 const void* memory; 221 VkDeviceSize size; 222 VkBufferUsageFlags usage; 223 VkSharingMode sharingMode; 224 deUint32 queueFamilyCount; 225 const deUint32* queueFamilyIndex; 226 VkAccessFlags inputBarrierFlags; 227}; 228 229struct Buffer 230{ 231 MovePtr<Allocation> allocation; 232 vector<VkMemoryBarrier> memoryBarrier; 233 vk::Move<VkBuffer> buffer; 234}; 235 236void createVulkanBuffer (const DeviceInterface& vkd, VkDevice device, Allocator& allocator, const BufferParameters& bufferParameters, Buffer& buffer, MemoryRequirement visibility) 237{ 238 VkBufferCreateInfo bufferCreateParams; 239 240 deMemset(&bufferCreateParams, 0xcd, sizeof(bufferCreateParams)); 241 bufferCreateParams.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 242 bufferCreateParams.pNext = DE_NULL; 243 bufferCreateParams.flags = 0; 244 bufferCreateParams.size = bufferParameters.size; 245 bufferCreateParams.usage = bufferParameters.usage; 246 bufferCreateParams.sharingMode = bufferParameters.sharingMode; 247 bufferCreateParams.queueFamilyIndexCount = bufferParameters.queueFamilyCount; 248 bufferCreateParams.pQueueFamilyIndices = bufferParameters.queueFamilyIndex; 249 250 buffer.buffer = createBuffer(vkd, device, &bufferCreateParams); 251 buffer.allocation = allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer.buffer), visibility); 252 253 VK_CHECK(vkd.bindBufferMemory(device, *buffer.buffer, buffer.allocation->getMemory(), buffer.allocation->getOffset())); 254 255 // If caller provides a host memory buffer for the allocation, then go 256 // ahead and copy the provided data into the allocation and update the 257 // barrier list with the associated access 258 if (bufferParameters.memory != DE_NULL) 259 { 260 VkMemoryBarrier barrier; 261 262 deMemcpy(buffer.allocation->getHostPtr(), bufferParameters.memory, (size_t)bufferParameters.size); 263 flushAlloc(vkd, device, *buffer.allocation); 264 265 deMemset(&barrier, 0xcd, sizeof(barrier)); 266 barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; 267 barrier.pNext = DE_NULL; 268 barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; 269 barrier.dstAccessMask = bufferParameters.inputBarrierFlags; 270 271 buffer.memoryBarrier.push_back(barrier); 272 } 273} 274 275struct ImageParameters 276{ 277 VkImageType imageType; 278 VkFormat format; 279 VkExtent3D extent3D; 280 deUint32 mipLevels; 281 VkSampleCountFlagBits samples; 282 VkImageTiling tiling; 283 VkBufferUsageFlags usage; 284 VkSharingMode sharingMode; 285 deUint32 queueFamilyCount; 286 const deUint32* queueFamilyNdxList; 287 VkImageLayout initialLayout; 288 VkImageLayout finalLayout; 289 VkAccessFlags barrierInputMask; 290}; 291 292struct Image 293{ 294 vk::Move<VkImage> image; 295 vk::Move<VkImageView> imageView; 296 MovePtr<Allocation> allocation; 297 vector<VkImageMemoryBarrier> imageMemoryBarrier; 298}; 299 300void createVulkanImage (const DeviceInterface& vkd, VkDevice device, Allocator& allocator, const ImageParameters& imageParameters, Image& image, MemoryRequirement visibility) 301{ 302 VkComponentMapping componentMap; 303 VkImageSubresourceRange subresourceRange; 304 VkImageViewCreateInfo imageViewCreateInfo; 305 VkImageCreateInfo imageCreateParams; 306 VkImageMemoryBarrier imageBarrier; 307 308 deMemset(&imageCreateParams, 0xcd, sizeof(imageCreateParams)); 309 imageCreateParams.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 310 imageCreateParams.pNext = DE_NULL; 311 imageCreateParams.flags = 0; 312 imageCreateParams.imageType = imageParameters.imageType; 313 imageCreateParams.format = imageParameters.format; 314 imageCreateParams.extent = imageParameters.extent3D; 315 imageCreateParams.mipLevels = imageParameters.mipLevels; 316 imageCreateParams.arrayLayers = 1; 317 imageCreateParams.samples = imageParameters.samples; 318 imageCreateParams.tiling = imageParameters.tiling; 319 imageCreateParams.usage = imageParameters.usage; 320 imageCreateParams.sharingMode = imageParameters.sharingMode; 321 imageCreateParams.queueFamilyIndexCount = imageParameters.queueFamilyCount; 322 imageCreateParams.pQueueFamilyIndices = imageParameters.queueFamilyNdxList; 323 imageCreateParams.initialLayout = imageParameters.initialLayout; 324 325 image.image = createImage(vkd, device, &imageCreateParams); 326 image.allocation = allocator.allocate(getImageMemoryRequirements(vkd, device, *image.image), visibility); 327 328 VK_CHECK(vkd.bindImageMemory(device, *image.image, image.allocation->getMemory(), image.allocation->getOffset())); 329 330 componentMap.r = VK_COMPONENT_SWIZZLE_R; 331 componentMap.g = VK_COMPONENT_SWIZZLE_G; 332 componentMap.b = VK_COMPONENT_SWIZZLE_B; 333 componentMap.a = VK_COMPONENT_SWIZZLE_A; 334 335 subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 336 subresourceRange.baseMipLevel = 0; 337 subresourceRange.levelCount = imageParameters.mipLevels; 338 subresourceRange.baseArrayLayer = 0; 339 subresourceRange.layerCount = 1; 340 341 deMemset(&imageViewCreateInfo, 0xcd, sizeof(imageViewCreateInfo)); 342 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 343 imageViewCreateInfo.pNext = DE_NULL; 344 imageViewCreateInfo.flags = 0; 345 imageViewCreateInfo.image = image.image.get(); 346 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 347 imageViewCreateInfo.format = imageParameters.format; 348 imageViewCreateInfo.components = componentMap; 349 imageViewCreateInfo.subresourceRange = subresourceRange; 350 351 image.imageView = createImageView(vkd, device, &imageViewCreateInfo); 352 353 deMemset(&imageBarrier, 0xcd, sizeof(imageBarrier)); 354 imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 355 imageBarrier.pNext = DE_NULL; 356 imageBarrier.srcAccessMask = 0; 357 imageBarrier.dstAccessMask = imageParameters.barrierInputMask; 358 imageBarrier.oldLayout = imageParameters.initialLayout; 359 imageBarrier.newLayout = imageParameters.finalLayout; 360 imageBarrier.srcQueueFamilyIndex = imageParameters.queueFamilyNdxList[0]; 361 imageBarrier.dstQueueFamilyIndex = imageParameters.queueFamilyNdxList[imageParameters.queueFamilyCount-1]; 362 imageBarrier.image = image.image.get(); 363 imageBarrier.subresourceRange = subresourceRange; 364 365 image.imageMemoryBarrier.push_back(imageBarrier); 366} 367 368struct RenderPassParameters 369{ 370 VkFormat colorFormat; 371 VkSampleCountFlagBits colorSamples; 372}; 373 374void createColorOnlyRenderPass (const DeviceInterface& vkd, VkDevice device, const RenderPassParameters& renderPassParameters, vk::Move<VkRenderPass>& renderPass) 375{ 376 VkAttachmentDescription colorAttachmentDesc; 377 VkAttachmentReference colorAttachmentRef; 378 VkAttachmentReference stencilAttachmentRef; 379 VkSubpassDescription subpassDesc; 380 VkRenderPassCreateInfo renderPassParams; 381 VkRenderPass newRenderPass; 382 383 colorAttachmentDesc.flags = 0; 384 colorAttachmentDesc.format = renderPassParameters.colorFormat; 385 colorAttachmentDesc.samples = renderPassParameters.colorSamples; 386 colorAttachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 387 colorAttachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; 388 colorAttachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 389 colorAttachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 390 colorAttachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 391 colorAttachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 392 393 colorAttachmentRef.attachment = 0; 394 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 395 396 stencilAttachmentRef.attachment = VK_ATTACHMENT_UNUSED; 397 stencilAttachmentRef.layout = VK_IMAGE_LAYOUT_UNDEFINED; 398 399 subpassDesc.flags = 0; 400 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 401 subpassDesc.inputAttachmentCount = 0; 402 subpassDesc.pInputAttachments = DE_NULL; 403 subpassDesc.colorAttachmentCount = 1; 404 subpassDesc.pColorAttachments = &colorAttachmentRef; 405 subpassDesc.pResolveAttachments = DE_NULL; 406 subpassDesc.pDepthStencilAttachment = &stencilAttachmentRef; 407 subpassDesc.preserveAttachmentCount = 0; 408 subpassDesc.pPreserveAttachments = DE_NULL; 409 410 deMemset(&renderPassParams, 0xcd, sizeof(renderPassParams)); 411 renderPassParams.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 412 renderPassParams.pNext = DE_NULL; 413 renderPassParams.flags = 0; 414 renderPassParams.attachmentCount = 1; 415 renderPassParams.pAttachments = &colorAttachmentDesc; 416 renderPassParams.subpassCount = 1; 417 renderPassParams.pSubpasses = &subpassDesc; 418 renderPassParams.dependencyCount = 0; 419 renderPassParams.pDependencies = DE_NULL; 420 421 renderPass = createRenderPass(vkd, device, &renderPassParams); 422} 423 424struct ShaderDescParams 425{ 426 VkShaderModule shaderModule; 427 VkShaderStageFlagBits stage; 428}; 429 430struct VertexDesc 431{ 432 deUint32 location; 433 VkFormat format; 434 deUint32 stride; 435 deUint32 offset; 436}; 437 438void createVertexInfo (const vector<VertexDesc>& vertexDesc, vector<VkVertexInputBindingDescription>& bindingList, vector<VkVertexInputAttributeDescription>& attrList, VkPipelineVertexInputStateCreateInfo& vertexInputState) 439{ 440 for (vector<VertexDesc>::const_iterator vertDescIter = vertexDesc.begin(); vertDescIter != vertexDesc.end(); vertDescIter++) 441 { 442 deUint32 bindingId = 0; 443 VkVertexInputBindingDescription bindingDesc; 444 VkVertexInputAttributeDescription attrDesc; 445 446 bindingDesc.binding = bindingId; 447 bindingDesc.stride = vertDescIter->stride; 448 bindingDesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 449 bindingList.push_back(bindingDesc); 450 451 attrDesc.location = vertDescIter->location; 452 attrDesc.binding = bindingId; 453 attrDesc.format = vertDescIter->format; 454 attrDesc.offset = vertDescIter->offset; 455 attrList.push_back(attrDesc); 456 457 bindingId++; 458 } 459 460 deMemset(&vertexInputState, 0xcd, sizeof(vertexInputState)); 461 vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 462 vertexInputState.pNext = DE_NULL; 463 vertexInputState.flags = 0u; 464 vertexInputState.vertexBindingDescriptionCount = (deUint32)bindingList.size(); 465 vertexInputState.pVertexBindingDescriptions = &bindingList[0]; 466 vertexInputState.vertexAttributeDescriptionCount = (deUint32)attrList.size(); 467 vertexInputState.pVertexAttributeDescriptions = &attrList[0]; 468} 469 470void createCommandBuffer (const DeviceInterface& deviceInterface, const VkDevice device, const deUint32 queueFamilyNdx, vk::Move<VkCommandBuffer>* commandBufferRef, vk::Move<VkCommandPool>* commandPoolRef) 471{ 472 vk::Move<VkCommandPool> commandPool; 473 VkCommandBufferAllocateInfo commandBufferInfo; 474 VkCommandBuffer commandBuffer; 475 476 commandPool = createCommandPool(deviceInterface, device, 0u, queueFamilyNdx); 477 478 deMemset(&commandBufferInfo, 0xcd, sizeof(commandBufferInfo)); 479 commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 480 commandBufferInfo.pNext = DE_NULL; 481 commandBufferInfo.commandPool = commandPool.get(); 482 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 483 commandBufferInfo.commandBufferCount = 1; 484 485 VK_CHECK(deviceInterface.allocateCommandBuffers(device, &commandBufferInfo, &commandBuffer)); 486 *commandBufferRef = vk::Move<VkCommandBuffer>(vk::check<VkCommandBuffer>(commandBuffer), Deleter<VkCommandBuffer>(deviceInterface, device, commandPool.get())); 487 *commandPoolRef = commandPool; 488} 489 490void createFences (const DeviceInterface& deviceInterface, VkDevice device, bool signaled, deUint32 numFences, VkFence* fence) 491{ 492 VkFenceCreateInfo fenceState; 493 VkFenceCreateFlags signalFlag = signaled ? VK_FENCE_CREATE_SIGNALED_BIT : 0; 494 495 deMemset(&fenceState, 0xcd, sizeof(fenceState)); 496 fenceState.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 497 fenceState.pNext = DE_NULL; 498 fenceState.flags = signalFlag; 499 500 for (deUint32 ndx = 0; ndx < numFences; ndx++) 501 VK_CHECK(deviceInterface.createFence(device, &fenceState, DE_NULL, &fence[ndx])); 502} 503 504void destroyFences (const DeviceInterface& deviceInterface, VkDevice device, deUint32 numFences, VkFence* fence) 505{ 506 for (deUint32 ndx = 0; ndx < numFences; ndx++) 507 deviceInterface.destroyFence(device, fence[ndx], DE_NULL); 508} 509 510struct RenderInfo 511{ 512 deInt32 width; 513 deInt32 height; 514 deUint32 vertexBufferSize; 515 VkBuffer vertexBuffer; 516 VkImage image; 517 VkCommandBuffer commandBuffer; 518 VkRenderPass renderPass; 519 VkFramebuffer framebuffer; 520 VkPipeline pipeline; 521 deUint32 mipLevels; 522 const deUint32* queueFamilyNdxList; 523 deUint32 queueFamilyNdxCount; 524 bool waitEvent; 525 VkEvent event; 526 vector<VkImageMemoryBarrier>* barriers; 527}; 528 529void recordRenderPass (const DeviceInterface& deviceInterface, const RenderInfo& renderInfo) 530{ 531 const VkDeviceSize bindingOffset = 0; 532 VkImageMemoryBarrier renderBarrier; 533 534 if (renderInfo.waitEvent) 535 deviceInterface.cmdWaitEvents(renderInfo.commandBuffer, 1, &renderInfo.event, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, DE_NULL, 0, DE_NULL, 0, DE_NULL); 536 537 beginRenderPass(deviceInterface, renderInfo.commandBuffer, renderInfo.renderPass, renderInfo.framebuffer, makeRect2D(0, 0, renderInfo.width, renderInfo.height), tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); 538 deviceInterface.cmdBindPipeline(renderInfo.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderInfo.pipeline); 539 deviceInterface.cmdBindVertexBuffers(renderInfo.commandBuffer, 0u, 1u, &renderInfo.vertexBuffer, &bindingOffset); 540 deviceInterface.cmdDraw(renderInfo.commandBuffer, renderInfo.vertexBufferSize, 1, 0, 0); 541 endRenderPass(deviceInterface, renderInfo.commandBuffer); 542 543 deMemset(&renderBarrier, 0xcd, sizeof(renderBarrier)); 544 renderBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 545 renderBarrier.pNext = DE_NULL; 546 renderBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 547 renderBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 548 renderBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 549 renderBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; 550 renderBarrier.srcQueueFamilyIndex = renderInfo.queueFamilyNdxList[0]; 551 renderBarrier.dstQueueFamilyIndex = renderInfo.queueFamilyNdxList[renderInfo.queueFamilyNdxCount-1]; 552 renderBarrier.image = renderInfo.image; 553 renderBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 554 renderBarrier.subresourceRange.baseMipLevel = 0; 555 renderBarrier.subresourceRange.levelCount = renderInfo.mipLevels; 556 renderBarrier.subresourceRange.baseArrayLayer = 0; 557 renderBarrier.subresourceRange.layerCount = 1; 558 renderInfo.barriers->push_back(renderBarrier); 559} 560 561struct TransferInfo 562{ 563 VkCommandBuffer commandBuffer; 564 deUint32 width; 565 deUint32 height; 566 VkImage image; 567 VkBuffer buffer; 568 VkDeviceSize size; 569 deUint32 mipLevel; 570 VkOffset3D imageOffset; 571 vector<VkBufferMemoryBarrier>* barriers; 572}; 573 574void copyToCPU (const DeviceInterface& vkd, TransferInfo* transferInfo) 575{ 576 VkBufferImageCopy copyState; 577 578 copyState.bufferOffset = 0; 579 copyState.bufferRowLength = transferInfo->width; 580 copyState.bufferImageHeight = transferInfo->height; 581 copyState.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 582 copyState.imageSubresource.mipLevel = transferInfo->mipLevel; 583 copyState.imageSubresource.baseArrayLayer = 0; 584 copyState.imageSubresource.layerCount = 1; 585 copyState.imageOffset = transferInfo->imageOffset; 586 copyState.imageExtent.width = (deInt32)(transferInfo->width); 587 copyState.imageExtent.height = (deInt32)(transferInfo->height); 588 copyState.imageExtent.depth = 1; 589 590 vkd.cmdCopyImageToBuffer(transferInfo->commandBuffer, transferInfo->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, transferInfo->buffer, 1, ©State); 591 592 { 593 VkBufferMemoryBarrier bufferBarrier; 594 deMemset(&bufferBarrier, 0xcd, sizeof(bufferBarrier)); 595 bufferBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 596 bufferBarrier.pNext = DE_NULL; 597 bufferBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 598 bufferBarrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT; 599 bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 600 bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 601 bufferBarrier.buffer = transferInfo->buffer; 602 bufferBarrier.offset = 0; 603 bufferBarrier.size = transferInfo->size; 604 transferInfo->barriers->push_back(bufferBarrier); 605 } 606} 607 608struct TestContext 609{ 610 const DeviceInterface& vkd; 611 const VkDevice device; 612 const deUint32 queueFamilyIndex; 613 const BinaryCollection& binaryCollection; 614 Allocator& allocator; 615 de::SharedPtr<vk::ResourceInterface> resourceInterface; 616 617 const tcu::Vec4* vertices; 618 deUint32 numVertices; 619 tcu::IVec2 renderDimension; 620 VkFence fences[2]; 621 VkDeviceSize renderSize; 622 MovePtr<Allocation> renderReadBuffer; 623 MovePtr<Allocation> vertexBufferAllocation; 624 vk::Move<VkBuffer> vertexBuffer; 625 vk::Move<VkBuffer> renderBuffer; 626 bool waitEvent; 627 VkEvent event; 628 vk::Move<VkImage> image; 629 vk::Move<VkImageView> imageView; 630 vk::Move<VkFramebuffer> framebuffer; 631 vk::Move<VkCommandPool> commandPool; 632 vk::Move<VkCommandBuffer> cmdBuffer; 633 vk::Move<VkRenderPass> renderPass; 634 vk::Move<VkPipelineCache> pipelineCache; 635 vk::Move<VkPipeline> pipeline; 636 MovePtr<Allocation> imageAllocation; 637 638 TestContext (const DeviceInterface& vkd_, 639 const VkDevice device_, 640 deUint32 queueFamilyIndex_, 641 const BinaryCollection& binaryCollection_, 642 Allocator& allocator_, 643 de::SharedPtr<vk::ResourceInterface> resourceInterface_) 644 : vkd (vkd_) 645 , device (device_) 646 , queueFamilyIndex (queueFamilyIndex_) 647 , binaryCollection (binaryCollection_) 648 , allocator (allocator_) 649 , resourceInterface (resourceInterface_) 650 , vertices (0) 651 , numVertices (0) 652 , renderSize (0) 653 , waitEvent (false) 654 { 655 createFences(vkd, device, false, DE_LENGTH_OF_ARRAY(fences), fences); 656 } 657 658 ~TestContext() 659 { 660 destroyFences(vkd, device, DE_LENGTH_OF_ARRAY(fences), fences); 661 } 662}; 663 664void generateWork (TestContext& testContext) 665{ 666 const DeviceInterface& deviceInterface = testContext.vkd; 667 const deUint32 queueFamilyNdx = testContext.queueFamilyIndex; 668 669 // \note VkShaderModule is consumed by vkCreate*Pipelines() so it can be deleted 670 // as pipeline has been constructed. 671 const vk::Unique<VkShaderModule> vertShaderModule (createShaderModule(deviceInterface, 672 testContext.device, 673 testContext.binaryCollection.get("glslvert"), 674 (VkShaderModuleCreateFlags)0)); 675 676 const vk::Unique<VkShaderModule> fragShaderModule (createShaderModule(deviceInterface, 677 testContext.device, 678 testContext.binaryCollection.get("glslfrag"), 679 (VkShaderModuleCreateFlags)0)); 680 const VkPipelineShaderStageCreateInfo shaderStageParams[] = 681 { 682 { 683 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 684 DE_NULL, 685 (VkPipelineShaderStageCreateFlags)0, 686 VK_SHADER_STAGE_VERTEX_BIT, 687 *vertShaderModule, 688 "main", 689 (const VkSpecializationInfo*)DE_NULL, 690 }, 691 { 692 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 693 DE_NULL, 694 (VkPipelineShaderStageCreateFlags)0, 695 VK_SHADER_STAGE_FRAGMENT_BIT, 696 *fragShaderModule, 697 "main", 698 (const VkSpecializationInfo*)DE_NULL, 699 } 700 }; 701 702 vk::Move<VkPipelineLayout> layout; 703 vector<ShaderDescParams> shaderDescParams; 704 VertexDesc vertexDesc; 705 vector<VertexDesc> vertexDescList; 706 vector<VkVertexInputAttributeDescription> attrList; 707 vector<VkBufferMemoryBarrier> bufferMemoryBarrier; 708 deUint32 memoryBarrierNdx; 709 deUint32 bufferMemoryBarrierNdx; 710 deUint32 imageMemoryBarrierNdx; 711 vector<VkVertexInputBindingDescription> bindingList; 712 VkPipelineVertexInputStateCreateInfo vertexInputState; 713 VkPipelineInputAssemblyStateCreateInfo inputAssemblyState; 714 VkPipelineDepthStencilStateCreateInfo depthStencilState; 715 VkPipelineColorBlendAttachmentState blendAttachment; 716 VkPipelineColorBlendStateCreateInfo blendState; 717 VkPipelineLayoutCreateInfo pipelineLayoutState; 718 VkGraphicsPipelineCreateInfo pipelineState; 719 VkPipelineCacheCreateInfo cacheState; 720 VkViewport viewport; 721 VkPipelineViewportStateCreateInfo viewportInfo; 722 VkRect2D scissor; 723 BufferParameters bufferParameters; 724 Buffer buffer; 725 RenderInfo renderInfo; 726 ImageParameters imageParameters; 727 Image image; 728 VkPipelineRasterizationStateCreateInfo rasterState; 729 VkPipelineMultisampleStateCreateInfo multisampleState; 730 VkFramebufferCreateInfo fbState; 731 VkCommandBufferBeginInfo commandBufRecordState; 732 VkCommandBufferInheritanceInfo inheritanceInfo; 733 RenderPassParameters renderPassParameters; 734 TransferInfo transferInfo; 735 vector<void*> barrierList; 736 VkExtent3D extent; 737 vector<VkMemoryBarrier> memoryBarriers; 738 vector<VkBufferMemoryBarrier> bufferBarriers; 739 vector<VkImageMemoryBarrier> imageBarriers; 740 741 memoryBarrierNdx = 0; 742 bufferMemoryBarrierNdx = 0; 743 imageMemoryBarrierNdx = 0; 744 buffer.memoryBarrier.resize(memoryBarrierNdx); 745 bufferMemoryBarrier.resize(bufferMemoryBarrierNdx); 746 image.imageMemoryBarrier.resize(imageMemoryBarrierNdx); 747 748 memoryBarriers.resize(0); 749 bufferBarriers.resize(0); 750 imageBarriers.resize(0); 751 752 bufferParameters.memory = testContext.vertices; 753 bufferParameters.size = testContext.numVertices * sizeof(tcu::Vec4); 754 bufferParameters.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; 755 bufferParameters.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 756 bufferParameters.queueFamilyCount = 1; 757 bufferParameters.queueFamilyIndex = &queueFamilyNdx; 758 bufferParameters.inputBarrierFlags = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 759 createVulkanBuffer(deviceInterface, testContext.device, testContext.allocator, bufferParameters, buffer, MemoryRequirement::HostVisible); 760 testContext.vertexBufferAllocation = buffer.allocation; 761 testContext.vertexBuffer = buffer.buffer; 762 763 bufferParameters.memory = DE_NULL; 764 bufferParameters.size = testContext.renderSize; 765 bufferParameters.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; 766 bufferParameters.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 767 bufferParameters.queueFamilyCount = 1; 768 bufferParameters.queueFamilyIndex = &queueFamilyNdx; 769 bufferParameters.inputBarrierFlags = 0; 770 createVulkanBuffer(deviceInterface, testContext.device, testContext.allocator, bufferParameters, buffer, MemoryRequirement::HostVisible); 771 testContext.renderReadBuffer = buffer.allocation; 772 testContext.renderBuffer = buffer.buffer; 773 774 extent.width = testContext.renderDimension.x(); 775 extent.height = testContext.renderDimension.y(); 776 extent.depth = 1; 777 778 imageParameters.imageType = VK_IMAGE_TYPE_2D; 779 imageParameters.format = VK_FORMAT_R8G8B8A8_UNORM; 780 imageParameters.extent3D = extent; 781 imageParameters.mipLevels = 1; 782 imageParameters.samples = VK_SAMPLE_COUNT_1_BIT; 783 imageParameters.tiling = VK_IMAGE_TILING_OPTIMAL; 784 imageParameters.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT; 785 imageParameters.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 786 imageParameters.queueFamilyCount = 1; 787 imageParameters.queueFamilyNdxList = &queueFamilyNdx; 788 imageParameters.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 789 imageParameters.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 790 imageParameters.barrierInputMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 791 createVulkanImage(deviceInterface, testContext.device, testContext.allocator, imageParameters, image, MemoryRequirement::Any); 792 testContext.imageAllocation = image.allocation; 793 testContext.image = image.image; 794 795 for (size_t ndx = 0; ndx < image.imageMemoryBarrier.size(); ++ndx) 796 imageBarriers.push_back(image.imageMemoryBarrier[ndx]); 797 798 renderPassParameters.colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 799 renderPassParameters.colorSamples = VK_SAMPLE_COUNT_1_BIT; 800 createColorOnlyRenderPass(deviceInterface, testContext.device, renderPassParameters, testContext.renderPass); 801 802 vertexDesc.location = 0; 803 vertexDesc.format = VK_FORMAT_R32G32B32A32_SFLOAT; 804 vertexDesc.stride = sizeof(tcu::Vec4); 805 vertexDesc.offset = 0; 806 vertexDescList.push_back(vertexDesc); 807 808 createVertexInfo(vertexDescList, bindingList, attrList, vertexInputState); 809 810 deMemset(&inputAssemblyState, 0xcd, sizeof(inputAssemblyState)); 811 inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 812 inputAssemblyState.pNext = DE_NULL; 813 inputAssemblyState.flags = 0u; 814 inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 815 inputAssemblyState.primitiveRestartEnable = false; 816 817 viewport.x = 0; 818 viewport.y = 0; 819 viewport.width = (float)testContext.renderDimension.x(); 820 viewport.height = (float)testContext.renderDimension.y(); 821 viewport.minDepth = 0; 822 viewport.maxDepth = 1; 823 824 scissor.offset.x = 0; 825 scissor.offset.y = 0; 826 scissor.extent.width = testContext.renderDimension.x(); 827 scissor.extent.height = testContext.renderDimension.y(); 828 829 deMemset(&viewportInfo, 0xcd, sizeof(viewportInfo)); 830 viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 831 viewportInfo.pNext = DE_NULL; 832 viewportInfo.flags = 0; 833 viewportInfo.viewportCount = 1; 834 viewportInfo.pViewports = &viewport; 835 viewportInfo.scissorCount = 1; 836 viewportInfo.pScissors = &scissor; 837 838 deMemset(&rasterState, 0xcd, sizeof(rasterState)); 839 rasterState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 840 rasterState.pNext = DE_NULL; 841 rasterState.flags = 0; 842 rasterState.depthClampEnable = VK_FALSE; 843 rasterState.rasterizerDiscardEnable = VK_FALSE; 844 rasterState.polygonMode = VK_POLYGON_MODE_FILL; 845 rasterState.cullMode = VK_CULL_MODE_NONE; 846 rasterState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 847 rasterState.depthBiasEnable = VK_FALSE; 848 rasterState.lineWidth = 1; 849 850 deMemset(&multisampleState, 0xcd, sizeof(multisampleState)); 851 multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 852 multisampleState.pNext = DE_NULL; 853 multisampleState.flags = 0; 854 multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 855 multisampleState.sampleShadingEnable = VK_FALSE; 856 multisampleState.pSampleMask = DE_NULL; 857 multisampleState.alphaToCoverageEnable = VK_FALSE; 858 multisampleState.alphaToOneEnable = VK_FALSE; 859 860 deMemset(&depthStencilState, 0xcd, sizeof(depthStencilState)); 861 depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 862 depthStencilState.pNext = DE_NULL; 863 depthStencilState.flags = 0; 864 depthStencilState.depthTestEnable = VK_FALSE; 865 depthStencilState.depthWriteEnable = VK_FALSE; 866 depthStencilState.depthCompareOp = VK_COMPARE_OP_ALWAYS; 867 depthStencilState.depthBoundsTestEnable = VK_FALSE; 868 depthStencilState.stencilTestEnable = VK_FALSE; 869 depthStencilState.front.failOp = VK_STENCIL_OP_KEEP; 870 depthStencilState.front.passOp = VK_STENCIL_OP_KEEP; 871 depthStencilState.front.depthFailOp = VK_STENCIL_OP_KEEP; 872 depthStencilState.front.compareOp = VK_COMPARE_OP_ALWAYS; 873 depthStencilState.front.compareMask = 0u; 874 depthStencilState.front.writeMask = 0u; 875 depthStencilState.front.reference = 0u; 876 depthStencilState.back = depthStencilState.front; 877 878 deMemset(&blendAttachment, 0xcd, sizeof(blendAttachment)); 879 blendAttachment.blendEnable = VK_FALSE; 880 blendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; 881 blendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; 882 blendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; 883 blendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; 884 blendAttachment.colorBlendOp = VK_BLEND_OP_ADD; 885 blendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; 886 blendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 887 888 deMemset(&blendState, 0xcd, sizeof(blendState)); 889 blendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 890 blendState.pNext = DE_NULL; 891 blendState.flags = 0; 892 blendState.logicOpEnable = VK_FALSE; 893 blendState.logicOp = VK_LOGIC_OP_COPY; 894 blendState.attachmentCount = 1; 895 blendState.pAttachments = &blendAttachment; 896 897 deMemset(&pipelineLayoutState, 0xcd, sizeof(pipelineLayoutState)); 898 pipelineLayoutState.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 899 pipelineLayoutState.pNext = DE_NULL; 900 pipelineLayoutState.flags = 0; 901 pipelineLayoutState.setLayoutCount = 0; 902 pipelineLayoutState.pSetLayouts = DE_NULL; 903 pipelineLayoutState.pushConstantRangeCount = 0; 904 pipelineLayoutState.pPushConstantRanges = DE_NULL; 905 layout = createPipelineLayout(deviceInterface, testContext.device, &pipelineLayoutState, DE_NULL); 906 907 deMemset(&pipelineState, 0xcd, sizeof(pipelineState)); 908 pipelineState.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 909 pipelineState.pNext = DE_NULL; 910 pipelineState.flags = 0; 911 pipelineState.stageCount = DE_LENGTH_OF_ARRAY(shaderStageParams); 912 pipelineState.pStages = &shaderStageParams[0]; 913 pipelineState.pVertexInputState = &vertexInputState; 914 pipelineState.pInputAssemblyState = &inputAssemblyState; 915 pipelineState.pTessellationState = DE_NULL; 916 pipelineState.pViewportState = &viewportInfo; 917 pipelineState.pRasterizationState = &rasterState; 918 pipelineState.pMultisampleState = &multisampleState; 919 pipelineState.pDepthStencilState = &depthStencilState; 920 pipelineState.pColorBlendState = &blendState; 921 pipelineState.pDynamicState = (const VkPipelineDynamicStateCreateInfo*)DE_NULL; 922 pipelineState.layout = layout.get(); 923 pipelineState.renderPass = testContext.renderPass.get(); 924 pipelineState.subpass = 0; 925 pipelineState.basePipelineHandle = DE_NULL; 926 pipelineState.basePipelineIndex = 0; 927 928 deMemset(&cacheState, 0xcd, sizeof(cacheState)); 929 cacheState.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; 930 cacheState.pNext = DE_NULL; 931#ifndef CTS_USES_VULKANSC 932 cacheState.flags = (VkPipelineCacheCreateFlags)0u; 933 cacheState.initialDataSize = 0; 934 cacheState.pInitialData = DE_NULL; 935#else 936 cacheState.flags = VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT | VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT; 937 cacheState.initialDataSize = testContext.resourceInterface->getCacheDataSize(); 938 cacheState.pInitialData = testContext.resourceInterface->getCacheData(); 939#endif 940 941 testContext.pipelineCache = createPipelineCache(deviceInterface, testContext.device, &cacheState); 942 testContext.pipeline = createGraphicsPipeline(deviceInterface, testContext.device, testContext.pipelineCache.get(), &pipelineState); 943 944 deMemset(&fbState, 0xcd, sizeof(fbState)); 945 fbState.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 946 fbState.pNext = DE_NULL; 947 fbState.flags = 0; 948 fbState.renderPass = testContext.renderPass.get(); 949 fbState.attachmentCount = 1; 950 fbState.pAttachments = &image.imageView.get(); 951 fbState.width = (deUint32)testContext.renderDimension.x(); 952 fbState.height = (deUint32)testContext.renderDimension.y(); 953 fbState.layers = 1; 954 955 testContext.framebuffer = createFramebuffer(deviceInterface, testContext.device, &fbState); 956 testContext.imageView = image.imageView; 957 958 deMemset(&inheritanceInfo, 0xcd, sizeof(inheritanceInfo)); 959 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; 960 inheritanceInfo.pNext = DE_NULL; 961 inheritanceInfo.renderPass = testContext.renderPass.get(); 962 inheritanceInfo.subpass = 0; 963 inheritanceInfo.framebuffer = *testContext.framebuffer; 964 inheritanceInfo.occlusionQueryEnable = VK_FALSE; 965 inheritanceInfo.queryFlags = 0u; 966 inheritanceInfo.pipelineStatistics = 0u; 967 968 deMemset(&commandBufRecordState, 0xcd, sizeof(commandBufRecordState)); 969 commandBufRecordState.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 970 commandBufRecordState.pNext = DE_NULL; 971 commandBufRecordState.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 972 commandBufRecordState.pInheritanceInfo = &inheritanceInfo; 973 VK_CHECK(deviceInterface.beginCommandBuffer(testContext.cmdBuffer.get(), &commandBufRecordState)); 974 975 deviceInterface.cmdPipelineBarrier( testContext.cmdBuffer.get(), 976 VK_PIPELINE_STAGE_HOST_BIT, 977 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 978 false, 979 (deUint32)memoryBarriers.size(), (memoryBarriers.empty() ? DE_NULL : &memoryBarriers[0]), 980 (deUint32)bufferBarriers.size(), (bufferBarriers.empty() ? DE_NULL : &bufferBarriers[0]), 981 (deUint32)imageBarriers.size(), (imageBarriers.empty() ? DE_NULL : &imageBarriers[0])); 982 983 memoryBarriers.resize(0); 984 bufferBarriers.resize(0); 985 imageBarriers.resize(0); 986 987 renderInfo.width = testContext.renderDimension.x(); 988 renderInfo.height = testContext.renderDimension.y(); 989 renderInfo.vertexBufferSize = testContext.numVertices; 990 renderInfo.vertexBuffer = testContext.vertexBuffer.get(); 991 renderInfo.image = testContext.image.get(); 992 renderInfo.commandBuffer = testContext.cmdBuffer.get(); 993 renderInfo.renderPass = testContext.renderPass.get(); 994 renderInfo.framebuffer = *testContext.framebuffer; 995 renderInfo.pipeline = *testContext.pipeline; 996 renderInfo.mipLevels = 1; 997 renderInfo.queueFamilyNdxList = &queueFamilyNdx; 998 renderInfo.queueFamilyNdxCount = 1; 999 renderInfo.waitEvent = testContext.waitEvent; 1000 renderInfo.event = testContext.event; 1001 renderInfo.barriers = &imageBarriers; 1002 recordRenderPass(deviceInterface, renderInfo); 1003 1004 deviceInterface.cmdPipelineBarrier( renderInfo.commandBuffer, 1005 VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 1006 VK_PIPELINE_STAGE_TRANSFER_BIT, 1007 false, 1008 (deUint32)memoryBarriers.size(), (memoryBarriers.empty() ? DE_NULL : &memoryBarriers[0]), 1009 (deUint32)bufferBarriers.size(), (bufferBarriers.empty() ? DE_NULL : &bufferBarriers[0]), 1010 (deUint32)imageBarriers.size(), (imageBarriers.empty() ? DE_NULL : &imageBarriers[0])); 1011 1012 memoryBarriers.resize(0); 1013 bufferBarriers.resize(0); 1014 imageBarriers.resize(0); 1015 1016 transferInfo.commandBuffer = renderInfo.commandBuffer; 1017 transferInfo.width = testContext.renderDimension.x(); 1018 transferInfo.height = testContext.renderDimension.y(); 1019 transferInfo.image = renderInfo.image; 1020 transferInfo.buffer = testContext.renderBuffer.get(); 1021 transferInfo.size = testContext.renderSize; 1022 transferInfo.mipLevel = 0; 1023 transferInfo.imageOffset.x = 0; 1024 transferInfo.imageOffset.y = 0; 1025 transferInfo.imageOffset.z = 0; 1026 transferInfo.barriers = &bufferBarriers; 1027 copyToCPU(deviceInterface, &transferInfo); 1028 1029 deviceInterface.cmdPipelineBarrier( transferInfo.commandBuffer, 1030 VK_PIPELINE_STAGE_TRANSFER_BIT, 1031 VK_PIPELINE_STAGE_HOST_BIT, 1032 false, 1033 (deUint32)memoryBarriers.size(), (memoryBarriers.empty() ? DE_NULL : &memoryBarriers[0]), 1034 (deUint32)bufferBarriers.size(), (bufferBarriers.empty() ? DE_NULL : &bufferBarriers[0]), 1035 (deUint32)imageBarriers.size(), (imageBarriers.empty() ? DE_NULL : &imageBarriers[0])); 1036 1037 memoryBarriers.resize(0); 1038 bufferBarriers.resize(0); 1039 imageBarriers.resize(0); 1040 1041 endCommandBuffer(deviceInterface, transferInfo.commandBuffer); 1042} 1043 1044tcu::TestStatus testFences (Context& context) 1045{ 1046 TestLog& log = context.getTestContext().getLog(); 1047 const DeviceInterface& deviceInterface = context.getDeviceInterface(); 1048 const VkQueue queue = context.getUniversalQueue(); 1049 const deUint32 queueFamilyIdx = context.getUniversalQueueFamilyIndex(); 1050 VkDevice device = context.getDevice(); 1051 VkResult waitStatus; 1052 VkResult fenceStatus; 1053 TestContext testContext (deviceInterface, device, queueFamilyIdx, context.getBinaryCollection(), context.getDefaultAllocator(), context.getResourceInterface()); 1054 void* resultImage; 1055 1056 const tcu::Vec4 vertices[] = 1057 { 1058 tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f), 1059 tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f), 1060 tcu::Vec4( 0.0f, -0.5f, 0.0f, 1.0f) 1061 }; 1062 1063 testContext.vertices = vertices; 1064 testContext.numVertices = DE_LENGTH_OF_ARRAY(vertices); 1065 testContext.renderDimension = tcu::IVec2(256, 256); 1066 testContext.renderSize = sizeof(deUint32) * testContext.renderDimension.x() * testContext.renderDimension.y(); 1067 1068 createCommandBuffer(deviceInterface, device, queueFamilyIdx, &testContext.cmdBuffer, &testContext.commandPool); 1069 generateWork(testContext); 1070 1071 // Default status is unsignaled 1072 fenceStatus = deviceInterface.getFenceStatus(device, testContext.fences[0]); 1073 if (fenceStatus != VK_NOT_READY) 1074 { 1075 log << TestLog::Message << "testSynchronizationPrimitives fence 0 should be reset but status is " << getResultName(fenceStatus) << TestLog::EndMessage; 1076 return tcu::TestStatus::fail("Fence in incorrect state"); 1077 } 1078 fenceStatus = deviceInterface.getFenceStatus(device, testContext.fences[1]); 1079 if (fenceStatus != VK_NOT_READY) 1080 { 1081 log << TestLog::Message << "testSynchronizationPrimitives fence 1 should be reset but status is " << getResultName(fenceStatus) << TestLog::EndMessage; 1082 return tcu::TestStatus::fail("Fence in incorrect state"); 1083 } 1084 1085 VkSubmitInfo submitInfo { VK_STRUCTURE_TYPE_SUBMIT_INFO, DE_NULL, 0u, DE_NULL, DE_NULL, 1u, &testContext.cmdBuffer.get(), 0, DE_NULL }; 1086 VK_CHECK(deviceInterface.queueSubmit(queue, 1, &submitInfo, testContext.fences[0])); 1087 1088 // Wait with timeout = 0 1089 waitStatus = deviceInterface.waitForFences(device, 1, &testContext.fences[0], true, 0u); 1090 if (waitStatus != VK_SUCCESS && waitStatus != VK_TIMEOUT) 1091 { 1092 // Will most likely end with VK_TIMEOUT 1093 log << TestLog::Message << "testSynchPrimitives failed to wait for a single fence" << TestLog::EndMessage; 1094 return tcu::TestStatus::fail("Failed to wait for a single fence"); 1095 } 1096 1097 // Wait with a reasonable timeout 1098 waitStatus = deviceInterface.waitForFences(device, 1, &testContext.fences[0], true, DEFAULT_TIMEOUT); 1099 if (waitStatus != VK_SUCCESS && waitStatus != VK_TIMEOUT) 1100 { 1101 // \note Wait can end with a timeout if DEFAULT_TIMEOUT is not sufficient 1102 log << TestLog::Message << "testSynchPrimitives failed to wait for a single fence" << TestLog::EndMessage; 1103 return tcu::TestStatus::fail("Failed to wait for a single fence"); 1104 } 1105 1106 // Wait for work on fences[0] to actually complete 1107 waitStatus = deviceInterface.waitForFences(device, 1, &testContext.fences[0], true, std::numeric_limits<deUint64>::max()); 1108 if (waitStatus != VK_SUCCESS) 1109 { 1110 log << TestLog::Message << "testSynchPrimitives failed to wait for a fence" << TestLog::EndMessage; 1111 return tcu::TestStatus::fail("failed to wait for a fence"); 1112 } 1113 1114 // Wait until timeout on a fence that has not been submitted 1115 waitStatus = deviceInterface.waitForFences(device, 1, &testContext.fences[1], true, 1); 1116 if (waitStatus != VK_TIMEOUT) 1117 { 1118 log << TestLog::Message << "testSyncPrimitives failed to timeout on wait for single fence" << TestLog::EndMessage; 1119 return tcu::TestStatus::fail("failed to timeout on wait for single fence"); 1120 } 1121 1122 // Check that the fence is signaled after the wait 1123 fenceStatus = deviceInterface.getFenceStatus(device, testContext.fences[0]); 1124 if (fenceStatus != VK_SUCCESS) 1125 { 1126 log << TestLog::Message << "testSynchronizationPrimitives fence should be signaled but status is " << getResultName(fenceStatus) << TestLog::EndMessage; 1127 return tcu::TestStatus::fail("Fence in incorrect state"); 1128 } 1129 1130 invalidateAlloc(deviceInterface, device, *testContext.renderReadBuffer); 1131 resultImage = testContext.renderReadBuffer->getHostPtr(); 1132 1133 log << TestLog::Image( "result", 1134 "result", 1135 tcu::ConstPixelBufferAccess(tcu::TextureFormat( 1136 tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1137 testContext.renderDimension.x(), 1138 testContext.renderDimension.y(), 1139 1, 1140 resultImage)); 1141 1142 return TestStatus::pass("synchronization-fences passed"); 1143} 1144 1145tcu::TestStatus testSemaphores (Context& context, SemaphoreTestConfig config) 1146{ 1147 if (config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE && !context.getTimelineSemaphoreFeatures().timelineSemaphore) 1148 TCU_THROW(NotSupportedError, "Timeline semaphore not supported"); 1149 1150 TestLog& log = context.getTestContext().getLog(); 1151 const PlatformInterface& platformInterface = context.getPlatformInterface(); 1152 const auto instance = context.getInstance(); 1153 const auto& instanceDriver = context.getInstanceInterface(); 1154 const VkPhysicalDevice physicalDevice = chooseDevice(instanceDriver, instance, context.getTestContext().getCommandLine()); 1155 deUint32 queueFamilyIdx; 1156 bool isTimelineSemaphore (config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE); 1157 vk::Move<VkDevice> device (createTestDevice(context, config, instance, instanceDriver, &queueFamilyIdx)); 1158 1159#ifndef CTS_USES_VULKANSC 1160 de::MovePtr<vk::DeviceDriver> deviceInterfacePtr = de::MovePtr<DeviceDriver>(new DeviceDriver(platformInterface, instance, *device, context.getUsedApiVersion())); 1161#else 1162 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceInterfacePtr = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(platformInterface, instance, *device, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(), context.getUsedApiVersion()), vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device)); 1163#endif // CTS_USES_VULKANSC 1164 const DeviceDriver& deviceDriver = *deviceInterfacePtr; 1165 SimpleAllocator allocator (deviceDriver, 1166 *device, 1167 getPhysicalDeviceMemoryProperties(instanceDriver, physicalDevice)); 1168 const VkQueue queue[2] = 1169 { 1170 getDeviceQueue(deviceDriver, *device, queueFamilyIdx, 0), 1171 getDeviceQueue(deviceDriver, *device, queueFamilyIdx, 1) 1172 }; 1173 VkResult testStatus; 1174 TestContext testContext1 (deviceDriver, device.get(), queueFamilyIdx, context.getBinaryCollection(), allocator, context.getResourceInterface()); 1175 TestContext testContext2 (deviceDriver, device.get(), queueFamilyIdx, context.getBinaryCollection(), allocator, context.getResourceInterface()); 1176 Unique<VkSemaphore> semaphore (createSemaphoreType(deviceDriver, *device, config.semaphoreType)); 1177 VkSemaphoreSubmitInfoKHR waitSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(*semaphore, 1u, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR); 1178 VkSemaphoreSubmitInfoKHR signalSemaphoreSubmitInfo = makeCommonSemaphoreSubmitInfo(*semaphore, 1u, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR); 1179 1180 const tcu::Vec4 vertices1[] = 1181 { 1182 tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f), 1183 tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f), 1184 tcu::Vec4( 0.0f, -0.5f, 0.0f, 1.0f) 1185 }; 1186 1187 const tcu::Vec4 vertices2[] = 1188 { 1189 tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f), 1190 tcu::Vec4(+0.5f, -0.5f, 0.0f, 1.0f), 1191 tcu::Vec4( 0.0f, +0.5f, 0.0f, 1.0f) 1192 }; 1193 1194 testContext1.vertices = vertices1; 1195 testContext1.numVertices = DE_LENGTH_OF_ARRAY(vertices1); 1196 testContext1.renderDimension = tcu::IVec2(256, 256); 1197 testContext1.renderSize = sizeof(deUint32) * testContext1.renderDimension.x() * testContext1.renderDimension.y(); 1198 1199 testContext2.vertices = vertices2; 1200 testContext2.numVertices = DE_LENGTH_OF_ARRAY(vertices2); 1201 testContext2.renderDimension = tcu::IVec2(256, 256); 1202 testContext2.renderSize = sizeof(deUint32) * testContext2.renderDimension.x() * testContext2.renderDimension.y(); 1203 1204 createCommandBuffer(deviceDriver, device.get(), queueFamilyIdx, &testContext1.cmdBuffer, &testContext1.commandPool); 1205 generateWork(testContext1); 1206 1207 createCommandBuffer(deviceDriver, device.get(), queueFamilyIdx, &testContext2.cmdBuffer, &testContext2.commandPool); 1208 generateWork(testContext2); 1209 1210 { 1211 VkCommandBufferSubmitInfoKHR commandBufferSubmitInfo = makeCommonCommandBufferSubmitInfo(testContext1.cmdBuffer.get()); 1212 SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.synchronizationType, deviceDriver, isTimelineSemaphore); 1213 synchronizationWrapper->addSubmitInfo( 1214 0u, // deUint32 waitSemaphoreInfoCount 1215 DE_NULL, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos 1216 1u, // deUint32 commandBufferInfoCount 1217 &commandBufferSubmitInfo, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos 1218 1u, // deUint32 signalSemaphoreInfoCount 1219 &signalSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos 1220 DE_FALSE, 1221 isTimelineSemaphore 1222 ); 1223 1224 VK_CHECK(synchronizationWrapper->queueSubmit(queue[0], testContext1.fences[0])); 1225 } 1226 1227 testStatus = deviceDriver.waitForFences(device.get(), 1, &testContext1.fences[0], true, std::numeric_limits<deUint64>::max()); 1228 if (testStatus != VK_SUCCESS) 1229 { 1230 log << TestLog::Message << "testSynchPrimitives failed to wait for a set fence" << TestLog::EndMessage; 1231 return tcu::TestStatus::fail("failed to wait for a set fence"); 1232 } 1233 1234 invalidateAlloc(deviceDriver, device.get(), *testContext1.renderReadBuffer); 1235 void* resultImage = testContext1.renderReadBuffer->getHostPtr(); 1236 1237 log << TestLog::Image( "result", 1238 "result", 1239 tcu::ConstPixelBufferAccess(tcu::TextureFormat( 1240 tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1241 testContext1.renderDimension.x(), 1242 testContext1.renderDimension.y(), 1243 1, 1244 resultImage)); 1245 1246 // The difference between the second submit info is that it will use a unique cmd buffer. 1247 // First submit signals a semaphore but not wait on a semaphore, the other waits on the 1248 // semaphore but not signal it. 1249 { 1250 VkCommandBufferSubmitInfoKHR commandBufferSubmitInfo = makeCommonCommandBufferSubmitInfo(testContext2.cmdBuffer.get()); 1251 SynchronizationWrapperPtr synchronizationWrapper = getSynchronizationWrapper(config.synchronizationType, deviceDriver, isTimelineSemaphore); 1252 synchronizationWrapper->addSubmitInfo( 1253 1u, // deUint32 waitSemaphoreInfoCount 1254 &waitSemaphoreSubmitInfo, // const VkSemaphoreSubmitInfoKHR* pWaitSemaphoreInfos 1255 1u, // deUint32 commandBufferInfoCount 1256 &commandBufferSubmitInfo, // const VkCommandBufferSubmitInfoKHR* pCommandBufferInfos 1257 0u, // deUint32 signalSemaphoreInfoCount 1258 DE_NULL, // const VkSemaphoreSubmitInfoKHR* pSignalSemaphoreInfos 1259 isTimelineSemaphore 1260 ); 1261 1262 VK_CHECK(synchronizationWrapper->queueSubmit(queue[1], testContext2.fences[0])); 1263 } 1264 1265 testStatus = deviceDriver.waitForFences(device.get(), 1, &testContext2.fences[0], true, std::numeric_limits<deUint64>::max()); 1266 if (testStatus != VK_SUCCESS) 1267 { 1268 log << TestLog::Message << "testSynchPrimitives failed to wait for a set fence" << TestLog::EndMessage; 1269 return tcu::TestStatus::fail("failed to wait for a set fence"); 1270 } 1271 1272 invalidateAlloc(deviceDriver, device.get(), *testContext2.renderReadBuffer); 1273 resultImage = testContext2.renderReadBuffer->getHostPtr(); 1274 1275 log << TestLog::Image( "result", 1276 "result", 1277 tcu::ConstPixelBufferAccess(tcu::TextureFormat( 1278 tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1279 testContext2.renderDimension.x(), 1280 testContext2.renderDimension.y(), 1281 1, 1282 resultImage)); 1283 1284 return tcu::TestStatus::pass("synchronization-semaphores passed"); 1285} 1286 1287void checkSupport(Context& context, SemaphoreTestConfig config) 1288{ 1289 if (config.semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE) 1290 context.requireDeviceFunctionality("VK_KHR_timeline_semaphore"); 1291 if (config.synchronizationType == SynchronizationType::SYNCHRONIZATION2) 1292 context.requireDeviceFunctionality("VK_KHR_synchronization2"); 1293} 1294 1295} // anonymous 1296 1297tcu::TestCaseGroup* createSmokeTests (tcu::TestContext& textCtx) 1298{ 1299 SynchronizationType type (SynchronizationType::LEGACY); 1300 de::MovePtr<tcu::TestCaseGroup> smokeTests (new tcu::TestCaseGroup(textCtx, "smoke")); 1301 1302 addFunctionCaseWithPrograms(smokeTests.get(), "fences", buildShaders, testFences); 1303 addFunctionCaseWithPrograms(smokeTests.get(), "binary_semaphores", checkSupport, initShaders, testSemaphores, SemaphoreTestConfig { type, VK_SEMAPHORE_TYPE_BINARY }); 1304 addFunctionCaseWithPrograms(smokeTests.get(), "timeline_semaphores", checkSupport, initShaders, testSemaphores, SemaphoreTestConfig { type, VK_SEMAPHORE_TYPE_TIMELINE }); 1305 1306 return smokeTests.release(); 1307} 1308 1309tcu::TestCaseGroup* createSynchronization2SmokeTests(tcu::TestContext& textCtx) 1310{ 1311 SynchronizationType type (SynchronizationType::SYNCHRONIZATION2); 1312 de::MovePtr<tcu::TestCaseGroup> smokeTests (new tcu::TestCaseGroup(textCtx, "smoke")); 1313 1314 addFunctionCaseWithPrograms(smokeTests.get(), "binary_semaphores", checkSupport, initShaders, testSemaphores, SemaphoreTestConfig { type, VK_SEMAPHORE_TYPE_BINARY }); 1315 addFunctionCaseWithPrograms(smokeTests.get(), "timeline_semaphores", checkSupport, initShaders, testSemaphores, SemaphoreTestConfig { type, VK_SEMAPHORE_TYPE_TIMELINE }); 1316 1317 return smokeTests.release(); 1318} 1319 1320} // synchronization 1321} // vkt 1322