1cb93a386Sopenharmony_ci// Copyright 2018 The SwiftShader Authors. All Rights Reserved. 2cb93a386Sopenharmony_ci// 3cb93a386Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4cb93a386Sopenharmony_ci// you may not use this file except in compliance with the License. 5cb93a386Sopenharmony_ci// You may obtain a copy of the License at 6cb93a386Sopenharmony_ci// 7cb93a386Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8cb93a386Sopenharmony_ci// 9cb93a386Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10cb93a386Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11cb93a386Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cb93a386Sopenharmony_ci// See the License for the specific language governing permissions and 13cb93a386Sopenharmony_ci// limitations under the License. 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci#include "VkQueue.hpp" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include "VkCommandBuffer.hpp" 18cb93a386Sopenharmony_ci#include "VkFence.hpp" 19cb93a386Sopenharmony_ci#include "VkSemaphore.hpp" 20cb93a386Sopenharmony_ci#include "VkStringify.hpp" 21cb93a386Sopenharmony_ci#include "VkTimelineSemaphore.hpp" 22cb93a386Sopenharmony_ci#include "Device/Renderer.hpp" 23cb93a386Sopenharmony_ci#include "WSI/VkSwapchainKHR.hpp" 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci#include "marl/defer.h" 26cb93a386Sopenharmony_ci#include "marl/scheduler.h" 27cb93a386Sopenharmony_ci#include "marl/thread.h" 28cb93a386Sopenharmony_ci#include "marl/trace.h" 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#include <cstring> 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_cinamespace vk { 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ciQueue::SubmitInfo *Queue::DeepCopySubmitInfo(uint32_t submitCount, const VkSubmitInfo *pSubmits) 35cb93a386Sopenharmony_ci{ 36cb93a386Sopenharmony_ci size_t submitSize = sizeof(SubmitInfo) * submitCount; 37cb93a386Sopenharmony_ci size_t totalSize = submitSize; 38cb93a386Sopenharmony_ci for(uint32_t i = 0; i < submitCount; i++) 39cb93a386Sopenharmony_ci { 40cb93a386Sopenharmony_ci totalSize += pSubmits[i].waitSemaphoreCount * sizeof(VkSemaphore); 41cb93a386Sopenharmony_ci totalSize += pSubmits[i].waitSemaphoreCount * sizeof(VkPipelineStageFlags); 42cb93a386Sopenharmony_ci totalSize += pSubmits[i].signalSemaphoreCount * sizeof(VkSemaphore); 43cb93a386Sopenharmony_ci totalSize += pSubmits[i].commandBufferCount * sizeof(VkCommandBuffer); 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci for(const auto *extension = reinterpret_cast<const VkBaseInStructure *>(pSubmits[i].pNext); 46cb93a386Sopenharmony_ci extension != nullptr; extension = reinterpret_cast<const VkBaseInStructure *>(extension->pNext)) 47cb93a386Sopenharmony_ci { 48cb93a386Sopenharmony_ci switch(extension->sType) 49cb93a386Sopenharmony_ci { 50cb93a386Sopenharmony_ci case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: 51cb93a386Sopenharmony_ci { 52cb93a386Sopenharmony_ci const auto *tlsSubmitInfo = reinterpret_cast<const VkTimelineSemaphoreSubmitInfo *>(extension); 53cb93a386Sopenharmony_ci totalSize += tlsSubmitInfo->waitSemaphoreValueCount * sizeof(uint64_t); 54cb93a386Sopenharmony_ci totalSize += tlsSubmitInfo->signalSemaphoreValueCount * sizeof(uint64_t); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci break; 57cb93a386Sopenharmony_ci case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: 58cb93a386Sopenharmony_ci // SwiftShader doesn't use device group submit info because it only supports a single physical device. 59cb93a386Sopenharmony_ci // However, this extension is core in Vulkan 1.1, so we must treat it as a valid structure type. 60cb93a386Sopenharmony_ci break; 61cb93a386Sopenharmony_ci case VK_STRUCTURE_TYPE_MAX_ENUM: 62cb93a386Sopenharmony_ci // dEQP tests that this value is ignored. 63cb93a386Sopenharmony_ci break; 64cb93a386Sopenharmony_ci default: 65cb93a386Sopenharmony_ci UNSUPPORTED("submitInfo[%d]->pNext sType: %s", i, vk::Stringify(extension->sType).c_str()); 66cb93a386Sopenharmony_ci break; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci uint8_t *mem = static_cast<uint8_t *>( 72cb93a386Sopenharmony_ci vk::allocateHostMemory(totalSize, vk::REQUIRED_MEMORY_ALIGNMENT, vk::NULL_ALLOCATION_CALLBACKS, vk::Fence::GetAllocationScope())); 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci auto submits = new(mem) SubmitInfo[submitCount]; 75cb93a386Sopenharmony_ci mem += submitSize; 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci for(uint32_t i = 0; i < submitCount; i++) 78cb93a386Sopenharmony_ci { 79cb93a386Sopenharmony_ci submits[i].commandBufferCount = pSubmits[i].commandBufferCount; 80cb93a386Sopenharmony_ci submits[i].signalSemaphoreCount = pSubmits[i].signalSemaphoreCount; 81cb93a386Sopenharmony_ci submits[i].waitSemaphoreCount = pSubmits[i].waitSemaphoreCount; 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci submits[i].pWaitSemaphores = nullptr; 84cb93a386Sopenharmony_ci submits[i].pWaitDstStageMask = nullptr; 85cb93a386Sopenharmony_ci submits[i].pSignalSemaphores = nullptr; 86cb93a386Sopenharmony_ci submits[i].pCommandBuffers = nullptr; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci if(pSubmits[i].waitSemaphoreCount > 0) 89cb93a386Sopenharmony_ci { 90cb93a386Sopenharmony_ci size_t size = pSubmits[i].waitSemaphoreCount * sizeof(VkSemaphore); 91cb93a386Sopenharmony_ci submits[i].pWaitSemaphores = reinterpret_cast<const VkSemaphore *>(mem); 92cb93a386Sopenharmony_ci memcpy(mem, pSubmits[i].pWaitSemaphores, size); 93cb93a386Sopenharmony_ci mem += size; 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci size = pSubmits[i].waitSemaphoreCount * sizeof(VkPipelineStageFlags); 96cb93a386Sopenharmony_ci submits[i].pWaitDstStageMask = reinterpret_cast<const VkPipelineStageFlags *>(mem); 97cb93a386Sopenharmony_ci memcpy(mem, pSubmits[i].pWaitDstStageMask, size); 98cb93a386Sopenharmony_ci mem += size; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci if(pSubmits[i].signalSemaphoreCount > 0) 102cb93a386Sopenharmony_ci { 103cb93a386Sopenharmony_ci size_t size = pSubmits[i].signalSemaphoreCount * sizeof(VkSemaphore); 104cb93a386Sopenharmony_ci submits[i].pSignalSemaphores = reinterpret_cast<const VkSemaphore *>(mem); 105cb93a386Sopenharmony_ci memcpy(mem, pSubmits[i].pSignalSemaphores, size); 106cb93a386Sopenharmony_ci mem += size; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci if(pSubmits[i].commandBufferCount > 0) 110cb93a386Sopenharmony_ci { 111cb93a386Sopenharmony_ci size_t size = pSubmits[i].commandBufferCount * sizeof(VkCommandBuffer); 112cb93a386Sopenharmony_ci submits[i].pCommandBuffers = reinterpret_cast<const VkCommandBuffer *>(mem); 113cb93a386Sopenharmony_ci memcpy(mem, pSubmits[i].pCommandBuffers, size); 114cb93a386Sopenharmony_ci mem += size; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci submits[i].waitSemaphoreValueCount = 0; 118cb93a386Sopenharmony_ci submits[i].pWaitSemaphoreValues = nullptr; 119cb93a386Sopenharmony_ci submits[i].signalSemaphoreValueCount = 0; 120cb93a386Sopenharmony_ci submits[i].pSignalSemaphoreValues = nullptr; 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci for(const auto *extension = reinterpret_cast<const VkBaseInStructure *>(pSubmits[i].pNext); 123cb93a386Sopenharmony_ci extension != nullptr; extension = reinterpret_cast<const VkBaseInStructure *>(extension->pNext)) 124cb93a386Sopenharmony_ci { 125cb93a386Sopenharmony_ci switch(extension->sType) 126cb93a386Sopenharmony_ci { 127cb93a386Sopenharmony_ci case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO: 128cb93a386Sopenharmony_ci { 129cb93a386Sopenharmony_ci const VkTimelineSemaphoreSubmitInfo *tlsSubmitInfo = reinterpret_cast<const VkTimelineSemaphoreSubmitInfo *>(extension); 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci if(tlsSubmitInfo->waitSemaphoreValueCount > 0) 132cb93a386Sopenharmony_ci { 133cb93a386Sopenharmony_ci submits[i].waitSemaphoreValueCount = tlsSubmitInfo->waitSemaphoreValueCount; 134cb93a386Sopenharmony_ci size_t size = tlsSubmitInfo->waitSemaphoreValueCount * sizeof(uint64_t); 135cb93a386Sopenharmony_ci submits[i].pWaitSemaphoreValues = reinterpret_cast<uint64_t *>(mem); 136cb93a386Sopenharmony_ci memcpy(mem, tlsSubmitInfo->pWaitSemaphoreValues, size); 137cb93a386Sopenharmony_ci mem += size; 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci if(tlsSubmitInfo->signalSemaphoreValueCount > 0) 141cb93a386Sopenharmony_ci { 142cb93a386Sopenharmony_ci submits[i].signalSemaphoreValueCount = tlsSubmitInfo->signalSemaphoreValueCount; 143cb93a386Sopenharmony_ci size_t size = tlsSubmitInfo->signalSemaphoreValueCount * sizeof(uint64_t); 144cb93a386Sopenharmony_ci submits[i].pSignalSemaphoreValues = reinterpret_cast<uint64_t *>(mem); 145cb93a386Sopenharmony_ci memcpy(mem, tlsSubmitInfo->pSignalSemaphoreValues, size); 146cb93a386Sopenharmony_ci mem += size; 147cb93a386Sopenharmony_ci } 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci break; 150cb93a386Sopenharmony_ci case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO: 151cb93a386Sopenharmony_ci // SwiftShader doesn't use device group submit info because it only supports a single physical device. 152cb93a386Sopenharmony_ci // However, this extension is core in Vulkan 1.1, so we must treat it as a valid structure type. 153cb93a386Sopenharmony_ci break; 154cb93a386Sopenharmony_ci case VK_STRUCTURE_TYPE_MAX_ENUM: 155cb93a386Sopenharmony_ci // dEQP tests that this value is ignored. 156cb93a386Sopenharmony_ci break; 157cb93a386Sopenharmony_ci default: 158cb93a386Sopenharmony_ci UNSUPPORTED("submitInfo[%d]->pNext sType: %s", i, vk::Stringify(extension->sType).c_str()); 159cb93a386Sopenharmony_ci break; 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci return submits; 165cb93a386Sopenharmony_ci} 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ciQueue::Queue(Device *device, marl::Scheduler *scheduler) 168cb93a386Sopenharmony_ci : device(device) 169cb93a386Sopenharmony_ci{ 170cb93a386Sopenharmony_ci queueThread = std::thread(&Queue::taskLoop, this, scheduler); 171cb93a386Sopenharmony_ci} 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ciQueue::~Queue() 174cb93a386Sopenharmony_ci{ 175cb93a386Sopenharmony_ci Task task; 176cb93a386Sopenharmony_ci task.type = Task::KILL_THREAD; 177cb93a386Sopenharmony_ci pending.put(task); 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci queueThread.join(); 180cb93a386Sopenharmony_ci ASSERT_MSG(pending.count() == 0, "queue has work after worker thread shutdown"); 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci garbageCollect(); 183cb93a386Sopenharmony_ci} 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ciVkResult Queue::submit(uint32_t submitCount, const VkSubmitInfo *pSubmits, Fence *fence) 186cb93a386Sopenharmony_ci{ 187cb93a386Sopenharmony_ci garbageCollect(); 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci Task task; 190cb93a386Sopenharmony_ci task.submitCount = submitCount; 191cb93a386Sopenharmony_ci task.pSubmits = DeepCopySubmitInfo(submitCount, pSubmits); 192cb93a386Sopenharmony_ci if(fence) 193cb93a386Sopenharmony_ci { 194cb93a386Sopenharmony_ci task.events = fence->getCountedEvent(); 195cb93a386Sopenharmony_ci task.events->add(); 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci pending.put(task); 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci return VK_SUCCESS; 201cb93a386Sopenharmony_ci} 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_civoid Queue::submitQueue(const Task &task) 204cb93a386Sopenharmony_ci{ 205cb93a386Sopenharmony_ci if(renderer == nullptr) 206cb93a386Sopenharmony_ci { 207cb93a386Sopenharmony_ci renderer.reset(new sw::Renderer(device)); 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci for(uint32_t i = 0; i < task.submitCount; i++) 211cb93a386Sopenharmony_ci { 212cb93a386Sopenharmony_ci SubmitInfo &submitInfo = task.pSubmits[i]; 213cb93a386Sopenharmony_ci for(uint32_t j = 0; j < submitInfo.waitSemaphoreCount; j++) 214cb93a386Sopenharmony_ci { 215cb93a386Sopenharmony_ci if(auto *sem = DynamicCast<TimelineSemaphore>(submitInfo.pWaitSemaphores[j])) 216cb93a386Sopenharmony_ci { 217cb93a386Sopenharmony_ci ASSERT(j < submitInfo.waitSemaphoreValueCount); 218cb93a386Sopenharmony_ci sem->wait(submitInfo.pWaitSemaphoreValues[j]); 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci else if(auto *sem = DynamicCast<BinarySemaphore>(submitInfo.pWaitSemaphores[j])) 221cb93a386Sopenharmony_ci { 222cb93a386Sopenharmony_ci sem->wait(submitInfo.pWaitDstStageMask[j]); 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci else 225cb93a386Sopenharmony_ci { 226cb93a386Sopenharmony_ci UNSUPPORTED("Unknown semaphore type"); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci { 231cb93a386Sopenharmony_ci CommandBuffer::ExecutionState executionState; 232cb93a386Sopenharmony_ci executionState.renderer = renderer.get(); 233cb93a386Sopenharmony_ci executionState.events = task.events.get(); 234cb93a386Sopenharmony_ci for(uint32_t j = 0; j < submitInfo.commandBufferCount; j++) 235cb93a386Sopenharmony_ci { 236cb93a386Sopenharmony_ci Cast(submitInfo.pCommandBuffers[j])->submit(executionState); 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci for(uint32_t j = 0; j < submitInfo.signalSemaphoreCount; j++) 241cb93a386Sopenharmony_ci { 242cb93a386Sopenharmony_ci if(auto *sem = DynamicCast<TimelineSemaphore>(submitInfo.pSignalSemaphores[j])) 243cb93a386Sopenharmony_ci { 244cb93a386Sopenharmony_ci ASSERT(j < submitInfo.signalSemaphoreValueCount); 245cb93a386Sopenharmony_ci sem->signal(submitInfo.pSignalSemaphoreValues[j]); 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci else if(auto *sem = DynamicCast<BinarySemaphore>(submitInfo.pSignalSemaphores[j])) 248cb93a386Sopenharmony_ci { 249cb93a386Sopenharmony_ci sem->signal(); 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci else 252cb93a386Sopenharmony_ci { 253cb93a386Sopenharmony_ci UNSUPPORTED("Unknown semaphore type"); 254cb93a386Sopenharmony_ci } 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci 258cb93a386Sopenharmony_ci if(task.pSubmits) 259cb93a386Sopenharmony_ci { 260cb93a386Sopenharmony_ci toDelete.put(task.pSubmits); 261cb93a386Sopenharmony_ci } 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci if(task.events) 264cb93a386Sopenharmony_ci { 265cb93a386Sopenharmony_ci // TODO: fix renderer signaling so that work submitted separately from (but before) a fence 266cb93a386Sopenharmony_ci // is guaranteed complete by the time the fence signals. 267cb93a386Sopenharmony_ci renderer->synchronize(); 268cb93a386Sopenharmony_ci task.events->done(); 269cb93a386Sopenharmony_ci } 270cb93a386Sopenharmony_ci} 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_civoid Queue::taskLoop(marl::Scheduler *scheduler) 273cb93a386Sopenharmony_ci{ 274cb93a386Sopenharmony_ci marl::Thread::setName("Queue<%p>", this); 275cb93a386Sopenharmony_ci scheduler->bind(); 276cb93a386Sopenharmony_ci defer(scheduler->unbind()); 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci while(true) 279cb93a386Sopenharmony_ci { 280cb93a386Sopenharmony_ci Task task = pending.take(); 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci switch(task.type) 283cb93a386Sopenharmony_ci { 284cb93a386Sopenharmony_ci case Task::KILL_THREAD: 285cb93a386Sopenharmony_ci ASSERT_MSG(pending.count() == 0, "queue has remaining work!"); 286cb93a386Sopenharmony_ci return; 287cb93a386Sopenharmony_ci case Task::SUBMIT_QUEUE: 288cb93a386Sopenharmony_ci submitQueue(task); 289cb93a386Sopenharmony_ci break; 290cb93a386Sopenharmony_ci default: 291cb93a386Sopenharmony_ci UNREACHABLE("task.type %d", static_cast<int>(task.type)); 292cb93a386Sopenharmony_ci break; 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci} 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ciVkResult Queue::waitIdle() 298cb93a386Sopenharmony_ci{ 299cb93a386Sopenharmony_ci // Wait for task queue to flush. 300cb93a386Sopenharmony_ci auto event = std::make_shared<sw::CountedEvent>(); 301cb93a386Sopenharmony_ci event->add(); // done() is called at the end of submitQueue() 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci Task task; 304cb93a386Sopenharmony_ci task.events = event; 305cb93a386Sopenharmony_ci pending.put(task); 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci event->wait(); 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci garbageCollect(); 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci return VK_SUCCESS; 312cb93a386Sopenharmony_ci} 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_civoid Queue::garbageCollect() 315cb93a386Sopenharmony_ci{ 316cb93a386Sopenharmony_ci while(true) 317cb93a386Sopenharmony_ci { 318cb93a386Sopenharmony_ci auto v = toDelete.tryTake(); 319cb93a386Sopenharmony_ci if(!v.second) { break; } 320cb93a386Sopenharmony_ci vk::freeHostMemory(v.first, NULL_ALLOCATION_CALLBACKS); 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci} 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci#ifndef __ANDROID__ 325cb93a386Sopenharmony_ciVkResult Queue::present(const VkPresentInfoKHR *presentInfo) 326cb93a386Sopenharmony_ci{ 327cb93a386Sopenharmony_ci // This is a hack to deal with screen tearing for now. 328cb93a386Sopenharmony_ci // Need to correctly implement threading using VkSemaphore 329cb93a386Sopenharmony_ci // to get rid of it. b/132458423 330cb93a386Sopenharmony_ci waitIdle(); 331cb93a386Sopenharmony_ci 332cb93a386Sopenharmony_ci for(uint32_t i = 0; i < presentInfo->waitSemaphoreCount; i++) 333cb93a386Sopenharmony_ci { 334cb93a386Sopenharmony_ci auto *semaphore = vk::DynamicCast<BinarySemaphore>(presentInfo->pWaitSemaphores[i]); 335cb93a386Sopenharmony_ci semaphore->wait(); 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci 338cb93a386Sopenharmony_ci VkResult commandResult = VK_SUCCESS; 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci for(uint32_t i = 0; i < presentInfo->swapchainCount; i++) 341cb93a386Sopenharmony_ci { 342cb93a386Sopenharmony_ci auto *swapchain = vk::Cast(presentInfo->pSwapchains[i]); 343cb93a386Sopenharmony_ci VkResult perSwapchainResult = swapchain->present(presentInfo->pImageIndices[i]); 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci if(presentInfo->pResults) 346cb93a386Sopenharmony_ci { 347cb93a386Sopenharmony_ci presentInfo->pResults[i] = perSwapchainResult; 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci 350cb93a386Sopenharmony_ci // Keep track of the worst result code. VK_SUBOPTIMAL_KHR is a success code so it should 351cb93a386Sopenharmony_ci // not override failure codes, but should not get replaced by a VK_SUCCESS result itself. 352cb93a386Sopenharmony_ci if(perSwapchainResult != VK_SUCCESS) 353cb93a386Sopenharmony_ci { 354cb93a386Sopenharmony_ci if(commandResult == VK_SUCCESS || commandResult == VK_SUBOPTIMAL_KHR) 355cb93a386Sopenharmony_ci { 356cb93a386Sopenharmony_ci commandResult = perSwapchainResult; 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci } 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci 361cb93a386Sopenharmony_ci return commandResult; 362cb93a386Sopenharmony_ci} 363cb93a386Sopenharmony_ci#endif 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_civoid Queue::beginDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo) 366cb93a386Sopenharmony_ci{ 367cb93a386Sopenharmony_ci // Optional debug label region 368cb93a386Sopenharmony_ci} 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_civoid Queue::endDebugUtilsLabel() 371cb93a386Sopenharmony_ci{ 372cb93a386Sopenharmony_ci // Close debug label region opened with beginDebugUtilsLabel() 373cb93a386Sopenharmony_ci} 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_civoid Queue::insertDebugUtilsLabel(const VkDebugUtilsLabelEXT *pLabelInfo) 376cb93a386Sopenharmony_ci{ 377cb93a386Sopenharmony_ci // Optional single debug label 378cb93a386Sopenharmony_ci} 379cb93a386Sopenharmony_ci 380cb93a386Sopenharmony_ci} // namespace vk 381