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