1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <string.h>
25bf215546Sopenharmony_ci#include <stdlib.h>
26bf215546Sopenharmony_ci#include <assert.h>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <vulkan/vulkan.h>
29bf215546Sopenharmony_ci#include <vulkan/vk_layer.h>
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "git_sha1.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "imgui.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "overlay_params.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci#include "util/debug.h"
38bf215546Sopenharmony_ci#include "util/hash_table.h"
39bf215546Sopenharmony_ci#include "util/list.h"
40bf215546Sopenharmony_ci#include "util/ralloc.h"
41bf215546Sopenharmony_ci#include "util/os_time.h"
42bf215546Sopenharmony_ci#include "util/os_socket.h"
43bf215546Sopenharmony_ci#include "util/simple_mtx.h"
44bf215546Sopenharmony_ci#include "util/u_math.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci#include "vk_enum_to_str.h"
47bf215546Sopenharmony_ci#include "vk_dispatch_table.h"
48bf215546Sopenharmony_ci#include "vk_util.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci/* Mapped from VkInstace/VkPhysicalDevice */
51bf215546Sopenharmony_cistruct instance_data {
52bf215546Sopenharmony_ci   struct vk_instance_dispatch_table vtable;
53bf215546Sopenharmony_ci   struct vk_physical_device_dispatch_table pd_vtable;
54bf215546Sopenharmony_ci   VkInstance instance;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   struct overlay_params params;
57bf215546Sopenharmony_ci   bool pipeline_statistics_enabled;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   bool first_line_printed;
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   int control_client;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   /* Dumping of frame stats to a file has been enabled. */
64bf215546Sopenharmony_ci   bool capture_enabled;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   /* Dumping of frame stats to a file has been enabled and started. */
67bf215546Sopenharmony_ci   bool capture_started;
68bf215546Sopenharmony_ci};
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_cistruct frame_stat {
71bf215546Sopenharmony_ci   uint64_t stats[OVERLAY_PARAM_ENABLED_MAX];
72bf215546Sopenharmony_ci};
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci/* Mapped from VkDevice */
75bf215546Sopenharmony_cistruct queue_data;
76bf215546Sopenharmony_cistruct device_data {
77bf215546Sopenharmony_ci   struct instance_data *instance;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   PFN_vkSetDeviceLoaderData set_device_loader_data;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   struct vk_device_dispatch_table vtable;
82bf215546Sopenharmony_ci   VkPhysicalDevice physical_device;
83bf215546Sopenharmony_ci   VkDevice device;
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci   VkPhysicalDeviceProperties properties;
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   struct queue_data *graphic_queue;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   struct queue_data **queues;
90bf215546Sopenharmony_ci   uint32_t n_queues;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   /* For a single frame */
93bf215546Sopenharmony_ci   struct frame_stat frame_stats;
94bf215546Sopenharmony_ci};
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci/* Mapped from VkCommandBuffer */
97bf215546Sopenharmony_cistruct command_buffer_data {
98bf215546Sopenharmony_ci   struct device_data *device;
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   VkCommandBufferLevel level;
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   VkCommandBuffer cmd_buffer;
103bf215546Sopenharmony_ci   VkQueryPool pipeline_query_pool;
104bf215546Sopenharmony_ci   VkQueryPool timestamp_query_pool;
105bf215546Sopenharmony_ci   uint32_t query_index;
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   struct frame_stat stats;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   struct list_head link; /* link into queue_data::running_command_buffer */
110bf215546Sopenharmony_ci};
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci/* Mapped from VkQueue */
113bf215546Sopenharmony_cistruct queue_data {
114bf215546Sopenharmony_ci   struct device_data *device;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   VkQueue queue;
117bf215546Sopenharmony_ci   VkQueueFlags flags;
118bf215546Sopenharmony_ci   uint32_t family_index;
119bf215546Sopenharmony_ci   uint64_t timestamp_mask;
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   VkFence queries_fence;
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   struct list_head running_command_buffer;
124bf215546Sopenharmony_ci};
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_cistruct overlay_draw {
127bf215546Sopenharmony_ci   struct list_head link;
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   VkCommandBuffer command_buffer;
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   VkSemaphore cross_engine_semaphore;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   VkSemaphore semaphore;
134bf215546Sopenharmony_ci   VkFence fence;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   VkBuffer vertex_buffer;
137bf215546Sopenharmony_ci   VkDeviceMemory vertex_buffer_mem;
138bf215546Sopenharmony_ci   VkDeviceSize vertex_buffer_size;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   VkBuffer index_buffer;
141bf215546Sopenharmony_ci   VkDeviceMemory index_buffer_mem;
142bf215546Sopenharmony_ci   VkDeviceSize index_buffer_size;
143bf215546Sopenharmony_ci};
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci/* Mapped from VkSwapchainKHR */
146bf215546Sopenharmony_cistruct swapchain_data {
147bf215546Sopenharmony_ci   struct device_data *device;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci   VkSwapchainKHR swapchain;
150bf215546Sopenharmony_ci   unsigned width, height;
151bf215546Sopenharmony_ci   VkFormat format;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   uint32_t n_images;
154bf215546Sopenharmony_ci   VkImage *images;
155bf215546Sopenharmony_ci   VkImageView *image_views;
156bf215546Sopenharmony_ci   VkFramebuffer *framebuffers;
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   VkRenderPass render_pass;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci   VkDescriptorPool descriptor_pool;
161bf215546Sopenharmony_ci   VkDescriptorSetLayout descriptor_layout;
162bf215546Sopenharmony_ci   VkDescriptorSet descriptor_set;
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   VkSampler font_sampler;
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   VkPipelineLayout pipeline_layout;
167bf215546Sopenharmony_ci   VkPipeline pipeline;
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   VkCommandPool command_pool;
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   struct list_head draws; /* List of struct overlay_draw */
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   bool font_uploaded;
174bf215546Sopenharmony_ci   VkImage font_image;
175bf215546Sopenharmony_ci   VkImageView font_image_view;
176bf215546Sopenharmony_ci   VkDeviceMemory font_mem;
177bf215546Sopenharmony_ci   VkBuffer upload_font_buffer;
178bf215546Sopenharmony_ci   VkDeviceMemory upload_font_buffer_mem;
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   /**/
181bf215546Sopenharmony_ci   ImGuiContext* imgui_context;
182bf215546Sopenharmony_ci   ImVec2 window_size;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   /**/
185bf215546Sopenharmony_ci   uint64_t n_frames;
186bf215546Sopenharmony_ci   uint64_t last_present_time;
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci   unsigned n_frames_since_update;
189bf215546Sopenharmony_ci   uint64_t last_fps_update;
190bf215546Sopenharmony_ci   double fps;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   enum overlay_param_enabled stat_selector;
193bf215546Sopenharmony_ci   double time_dividor;
194bf215546Sopenharmony_ci   struct frame_stat stats_min, stats_max;
195bf215546Sopenharmony_ci   struct frame_stat frames_stats[200];
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci   /* Over a single frame */
198bf215546Sopenharmony_ci   struct frame_stat frame_stats;
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   /* Over fps_sampling_period */
201bf215546Sopenharmony_ci   struct frame_stat accumulated_stats;
202bf215546Sopenharmony_ci};
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_cistatic const VkQueryPipelineStatisticFlags overlay_query_flags =
205bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT |
206bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT |
207bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT |
208bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT |
209bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT |
210bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT |
211bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT |
212bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT |
213bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT |
214bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT |
215bf215546Sopenharmony_ci   VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
216bf215546Sopenharmony_ci#define OVERLAY_QUERY_COUNT (11)
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_cistatic struct hash_table_u64 *vk_object_to_data = NULL;
219bf215546Sopenharmony_cistatic simple_mtx_t vk_object_to_data_mutex = _SIMPLE_MTX_INITIALIZER_NP;
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_cithread_local ImGuiContext* __MesaImGui;
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_cistatic inline void ensure_vk_object_map(void)
224bf215546Sopenharmony_ci{
225bf215546Sopenharmony_ci   if (!vk_object_to_data)
226bf215546Sopenharmony_ci      vk_object_to_data = _mesa_hash_table_u64_create(NULL);
227bf215546Sopenharmony_ci}
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci#define HKEY(obj) ((uint64_t)(obj))
230bf215546Sopenharmony_ci#define FIND(type, obj) ((type *)find_object_data(HKEY(obj)))
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_cistatic void *find_object_data(uint64_t obj)
233bf215546Sopenharmony_ci{
234bf215546Sopenharmony_ci   simple_mtx_lock(&vk_object_to_data_mutex);
235bf215546Sopenharmony_ci   ensure_vk_object_map();
236bf215546Sopenharmony_ci   void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj);
237bf215546Sopenharmony_ci   simple_mtx_unlock(&vk_object_to_data_mutex);
238bf215546Sopenharmony_ci   return data;
239bf215546Sopenharmony_ci}
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_cistatic void map_object(uint64_t obj, void *data)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci   simple_mtx_lock(&vk_object_to_data_mutex);
244bf215546Sopenharmony_ci   ensure_vk_object_map();
245bf215546Sopenharmony_ci   _mesa_hash_table_u64_insert(vk_object_to_data, obj, data);
246bf215546Sopenharmony_ci   simple_mtx_unlock(&vk_object_to_data_mutex);
247bf215546Sopenharmony_ci}
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_cistatic void unmap_object(uint64_t obj)
250bf215546Sopenharmony_ci{
251bf215546Sopenharmony_ci   simple_mtx_lock(&vk_object_to_data_mutex);
252bf215546Sopenharmony_ci   _mesa_hash_table_u64_remove(vk_object_to_data, obj);
253bf215546Sopenharmony_ci   simple_mtx_unlock(&vk_object_to_data_mutex);
254bf215546Sopenharmony_ci}
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci/**/
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci#define VK_CHECK(expr) \
259bf215546Sopenharmony_ci   do { \
260bf215546Sopenharmony_ci      VkResult __result = (expr); \
261bf215546Sopenharmony_ci      if (__result != VK_SUCCESS) { \
262bf215546Sopenharmony_ci         fprintf(stderr, "'%s' line %i failed with %s\n", \
263bf215546Sopenharmony_ci                 #expr, __LINE__, vk_Result_to_str(__result)); \
264bf215546Sopenharmony_ci      } \
265bf215546Sopenharmony_ci   } while (0)
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci/**/
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_cistatic VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
270bf215546Sopenharmony_ci                                                          VkLayerFunction func)
271bf215546Sopenharmony_ci{
272bf215546Sopenharmony_ci   vk_foreach_struct_const(item, pCreateInfo->pNext) {
273bf215546Sopenharmony_ci      if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&
274bf215546Sopenharmony_ci          ((VkLayerInstanceCreateInfo *) item)->function == func)
275bf215546Sopenharmony_ci         return (VkLayerInstanceCreateInfo *) item;
276bf215546Sopenharmony_ci   }
277bf215546Sopenharmony_ci   unreachable("instance chain info not found");
278bf215546Sopenharmony_ci   return NULL;
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_cistatic VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,
282bf215546Sopenharmony_ci                                                      VkLayerFunction func)
283bf215546Sopenharmony_ci{
284bf215546Sopenharmony_ci   vk_foreach_struct_const(item, pCreateInfo->pNext) {
285bf215546Sopenharmony_ci      if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&
286bf215546Sopenharmony_ci          ((VkLayerDeviceCreateInfo *) item)->function == func)
287bf215546Sopenharmony_ci         return (VkLayerDeviceCreateInfo *)item;
288bf215546Sopenharmony_ci   }
289bf215546Sopenharmony_ci   unreachable("device chain info not found");
290bf215546Sopenharmony_ci   return NULL;
291bf215546Sopenharmony_ci}
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_cistatic struct VkBaseOutStructure *
294bf215546Sopenharmony_ciclone_chain(const struct VkBaseInStructure *chain)
295bf215546Sopenharmony_ci{
296bf215546Sopenharmony_ci   struct VkBaseOutStructure *head = NULL, *tail = NULL;
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   vk_foreach_struct_const(item, chain) {
299bf215546Sopenharmony_ci      size_t item_size = vk_structure_type_size(item);
300bf215546Sopenharmony_ci      struct VkBaseOutStructure *new_item =
301bf215546Sopenharmony_ci         (struct VkBaseOutStructure *)malloc(item_size);;
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci      memcpy(new_item, item, item_size);
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci      if (!head)
306bf215546Sopenharmony_ci         head = new_item;
307bf215546Sopenharmony_ci      if (tail)
308bf215546Sopenharmony_ci         tail->pNext = new_item;
309bf215546Sopenharmony_ci      tail = new_item;
310bf215546Sopenharmony_ci   }
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_ci   return head;
313bf215546Sopenharmony_ci}
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_cistatic void
316bf215546Sopenharmony_cifree_chain(struct VkBaseOutStructure *chain)
317bf215546Sopenharmony_ci{
318bf215546Sopenharmony_ci   while (chain) {
319bf215546Sopenharmony_ci      void *node = chain;
320bf215546Sopenharmony_ci      chain = chain->pNext;
321bf215546Sopenharmony_ci      free(node);
322bf215546Sopenharmony_ci   }
323bf215546Sopenharmony_ci}
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci/**/
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_cistatic struct instance_data *new_instance_data(VkInstance instance)
328bf215546Sopenharmony_ci{
329bf215546Sopenharmony_ci   struct instance_data *data = rzalloc(NULL, struct instance_data);
330bf215546Sopenharmony_ci   data->instance = instance;
331bf215546Sopenharmony_ci   data->control_client = -1;
332bf215546Sopenharmony_ci   map_object(HKEY(data->instance), data);
333bf215546Sopenharmony_ci   return data;
334bf215546Sopenharmony_ci}
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_cistatic void destroy_instance_data(struct instance_data *data)
337bf215546Sopenharmony_ci{
338bf215546Sopenharmony_ci   if (data->params.output_file)
339bf215546Sopenharmony_ci      fclose(data->params.output_file);
340bf215546Sopenharmony_ci   if (data->params.control >= 0)
341bf215546Sopenharmony_ci      os_socket_close(data->params.control);
342bf215546Sopenharmony_ci   unmap_object(HKEY(data->instance));
343bf215546Sopenharmony_ci   ralloc_free(data);
344bf215546Sopenharmony_ci}
345bf215546Sopenharmony_ci
346bf215546Sopenharmony_cistatic void instance_data_map_physical_devices(struct instance_data *instance_data,
347bf215546Sopenharmony_ci                                               bool map)
348bf215546Sopenharmony_ci{
349bf215546Sopenharmony_ci   uint32_t physicalDeviceCount = 0;
350bf215546Sopenharmony_ci   instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,
351bf215546Sopenharmony_ci                                                  &physicalDeviceCount,
352bf215546Sopenharmony_ci                                                  NULL);
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci   VkPhysicalDevice *physicalDevices = (VkPhysicalDevice *) malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
355bf215546Sopenharmony_ci   instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,
356bf215546Sopenharmony_ci                                                  &physicalDeviceCount,
357bf215546Sopenharmony_ci                                                  physicalDevices);
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   for (uint32_t i = 0; i < physicalDeviceCount; i++) {
360bf215546Sopenharmony_ci      if (map)
361bf215546Sopenharmony_ci         map_object(HKEY(physicalDevices[i]), instance_data);
362bf215546Sopenharmony_ci      else
363bf215546Sopenharmony_ci         unmap_object(HKEY(physicalDevices[i]));
364bf215546Sopenharmony_ci   }
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci   free(physicalDevices);
367bf215546Sopenharmony_ci}
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci/**/
370bf215546Sopenharmony_cistatic struct device_data *new_device_data(VkDevice device, struct instance_data *instance)
371bf215546Sopenharmony_ci{
372bf215546Sopenharmony_ci   struct device_data *data = rzalloc(NULL, struct device_data);
373bf215546Sopenharmony_ci   data->instance = instance;
374bf215546Sopenharmony_ci   data->device = device;
375bf215546Sopenharmony_ci   map_object(HKEY(data->device), data);
376bf215546Sopenharmony_ci   return data;
377bf215546Sopenharmony_ci}
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_cistatic struct queue_data *new_queue_data(VkQueue queue,
380bf215546Sopenharmony_ci                                         const VkQueueFamilyProperties *family_props,
381bf215546Sopenharmony_ci                                         uint32_t family_index,
382bf215546Sopenharmony_ci                                         struct device_data *device_data)
383bf215546Sopenharmony_ci{
384bf215546Sopenharmony_ci   struct queue_data *data = rzalloc(device_data, struct queue_data);
385bf215546Sopenharmony_ci   data->device = device_data;
386bf215546Sopenharmony_ci   data->queue = queue;
387bf215546Sopenharmony_ci   data->flags = family_props->queueFlags;
388bf215546Sopenharmony_ci   data->timestamp_mask = (1ull << family_props->timestampValidBits) - 1;
389bf215546Sopenharmony_ci   data->family_index = family_index;
390bf215546Sopenharmony_ci   list_inithead(&data->running_command_buffer);
391bf215546Sopenharmony_ci   map_object(HKEY(data->queue), data);
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   /* Fence synchronizing access to queries on that queue. */
394bf215546Sopenharmony_ci   VkFenceCreateInfo fence_info = {};
395bf215546Sopenharmony_ci   fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
396bf215546Sopenharmony_ci   fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
397bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateFence(device_data->device,
398bf215546Sopenharmony_ci                                            &fence_info,
399bf215546Sopenharmony_ci                                            NULL,
400bf215546Sopenharmony_ci                                            &data->queries_fence));
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci   if (data->flags & VK_QUEUE_GRAPHICS_BIT)
403bf215546Sopenharmony_ci      device_data->graphic_queue = data;
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_ci   return data;
406bf215546Sopenharmony_ci}
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_cistatic void destroy_queue(struct queue_data *data)
409bf215546Sopenharmony_ci{
410bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
411bf215546Sopenharmony_ci   device_data->vtable.DestroyFence(device_data->device, data->queries_fence, NULL);
412bf215546Sopenharmony_ci   unmap_object(HKEY(data->queue));
413bf215546Sopenharmony_ci   ralloc_free(data);
414bf215546Sopenharmony_ci}
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_cistatic void device_map_queues(struct device_data *data,
417bf215546Sopenharmony_ci                              const VkDeviceCreateInfo *pCreateInfo)
418bf215546Sopenharmony_ci{
419bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)
420bf215546Sopenharmony_ci      data->n_queues += pCreateInfo->pQueueCreateInfos[i].queueCount;
421bf215546Sopenharmony_ci   data->queues = ralloc_array(data, struct queue_data *, data->n_queues);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   struct instance_data *instance_data = data->instance;
424bf215546Sopenharmony_ci   uint32_t n_family_props;
425bf215546Sopenharmony_ci   instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device,
426bf215546Sopenharmony_ci                                                                   &n_family_props,
427bf215546Sopenharmony_ci                                                                   NULL);
428bf215546Sopenharmony_ci   VkQueueFamilyProperties *family_props =
429bf215546Sopenharmony_ci      (VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) * n_family_props);
430bf215546Sopenharmony_ci   instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device,
431bf215546Sopenharmony_ci                                                                   &n_family_props,
432bf215546Sopenharmony_ci                                                                   family_props);
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci   uint32_t queue_index = 0;
435bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
436bf215546Sopenharmony_ci      for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {
437bf215546Sopenharmony_ci         VkQueue queue;
438bf215546Sopenharmony_ci         data->vtable.GetDeviceQueue(data->device,
439bf215546Sopenharmony_ci                                     pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,
440bf215546Sopenharmony_ci                                     j, &queue);
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci         VK_CHECK(data->set_device_loader_data(data->device, queue));
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_ci         data->queues[queue_index++] =
445bf215546Sopenharmony_ci            new_queue_data(queue, &family_props[pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex],
446bf215546Sopenharmony_ci                           pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, data);
447bf215546Sopenharmony_ci      }
448bf215546Sopenharmony_ci   }
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_ci   free(family_props);
451bf215546Sopenharmony_ci}
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_cistatic void device_unmap_queues(struct device_data *data)
454bf215546Sopenharmony_ci{
455bf215546Sopenharmony_ci   for (uint32_t i = 0; i < data->n_queues; i++)
456bf215546Sopenharmony_ci      destroy_queue(data->queues[i]);
457bf215546Sopenharmony_ci}
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_cistatic void destroy_device_data(struct device_data *data)
460bf215546Sopenharmony_ci{
461bf215546Sopenharmony_ci   unmap_object(HKEY(data->device));
462bf215546Sopenharmony_ci   ralloc_free(data);
463bf215546Sopenharmony_ci}
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci/**/
466bf215546Sopenharmony_cistatic struct command_buffer_data *new_command_buffer_data(VkCommandBuffer cmd_buffer,
467bf215546Sopenharmony_ci                                                           VkCommandBufferLevel level,
468bf215546Sopenharmony_ci                                                           VkQueryPool pipeline_query_pool,
469bf215546Sopenharmony_ci                                                           VkQueryPool timestamp_query_pool,
470bf215546Sopenharmony_ci                                                           uint32_t query_index,
471bf215546Sopenharmony_ci                                                           struct device_data *device_data)
472bf215546Sopenharmony_ci{
473bf215546Sopenharmony_ci   struct command_buffer_data *data = rzalloc(NULL, struct command_buffer_data);
474bf215546Sopenharmony_ci   data->device = device_data;
475bf215546Sopenharmony_ci   data->cmd_buffer = cmd_buffer;
476bf215546Sopenharmony_ci   data->level = level;
477bf215546Sopenharmony_ci   data->pipeline_query_pool = pipeline_query_pool;
478bf215546Sopenharmony_ci   data->timestamp_query_pool = timestamp_query_pool;
479bf215546Sopenharmony_ci   data->query_index = query_index;
480bf215546Sopenharmony_ci   list_inithead(&data->link);
481bf215546Sopenharmony_ci   map_object(HKEY(data->cmd_buffer), data);
482bf215546Sopenharmony_ci   return data;
483bf215546Sopenharmony_ci}
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_cistatic void destroy_command_buffer_data(struct command_buffer_data *data)
486bf215546Sopenharmony_ci{
487bf215546Sopenharmony_ci   unmap_object(HKEY(data->cmd_buffer));
488bf215546Sopenharmony_ci   list_delinit(&data->link);
489bf215546Sopenharmony_ci   ralloc_free(data);
490bf215546Sopenharmony_ci}
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci/**/
493bf215546Sopenharmony_cistatic struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain,
494bf215546Sopenharmony_ci                                                 struct device_data *device_data)
495bf215546Sopenharmony_ci{
496bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
497bf215546Sopenharmony_ci   struct swapchain_data *data = rzalloc(NULL, struct swapchain_data);
498bf215546Sopenharmony_ci   data->device = device_data;
499bf215546Sopenharmony_ci   data->swapchain = swapchain;
500bf215546Sopenharmony_ci   data->window_size = ImVec2(instance_data->params.width, instance_data->params.height);
501bf215546Sopenharmony_ci   list_inithead(&data->draws);
502bf215546Sopenharmony_ci   map_object(HKEY(data->swapchain), data);
503bf215546Sopenharmony_ci   return data;
504bf215546Sopenharmony_ci}
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_cistatic void destroy_swapchain_data(struct swapchain_data *data)
507bf215546Sopenharmony_ci{
508bf215546Sopenharmony_ci   unmap_object(HKEY(data->swapchain));
509bf215546Sopenharmony_ci   ralloc_free(data);
510bf215546Sopenharmony_ci}
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_cistruct overlay_draw *get_overlay_draw(struct swapchain_data *data)
513bf215546Sopenharmony_ci{
514bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
515bf215546Sopenharmony_ci   struct overlay_draw *draw = list_is_empty(&data->draws) ?
516bf215546Sopenharmony_ci      NULL : list_first_entry(&data->draws, struct overlay_draw, link);
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   VkSemaphoreCreateInfo sem_info = {};
519bf215546Sopenharmony_ci   sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci   if (draw && device_data->vtable.GetFenceStatus(device_data->device, draw->fence) == VK_SUCCESS) {
522bf215546Sopenharmony_ci      list_del(&draw->link);
523bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.ResetFences(device_data->device,
524bf215546Sopenharmony_ci                                               1, &draw->fence));
525bf215546Sopenharmony_ci      list_addtail(&draw->link, &data->draws);
526bf215546Sopenharmony_ci      return draw;
527bf215546Sopenharmony_ci   }
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci   draw = rzalloc(data, struct overlay_draw);
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   VkCommandBufferAllocateInfo cmd_buffer_info = {};
532bf215546Sopenharmony_ci   cmd_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
533bf215546Sopenharmony_ci   cmd_buffer_info.commandPool = data->command_pool;
534bf215546Sopenharmony_ci   cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
535bf215546Sopenharmony_ci   cmd_buffer_info.commandBufferCount = 1;
536bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.AllocateCommandBuffers(device_data->device,
537bf215546Sopenharmony_ci                                                       &cmd_buffer_info,
538bf215546Sopenharmony_ci                                                       &draw->command_buffer));
539bf215546Sopenharmony_ci   VK_CHECK(device_data->set_device_loader_data(device_data->device,
540bf215546Sopenharmony_ci                                                draw->command_buffer));
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci   VkFenceCreateInfo fence_info = {};
544bf215546Sopenharmony_ci   fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
545bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateFence(device_data->device,
546bf215546Sopenharmony_ci                                            &fence_info,
547bf215546Sopenharmony_ci                                            NULL,
548bf215546Sopenharmony_ci                                            &draw->fence));
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,
551bf215546Sopenharmony_ci                                                NULL, &draw->semaphore));
552bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,
553bf215546Sopenharmony_ci                                                NULL, &draw->cross_engine_semaphore));
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci   list_addtail(&draw->link, &data->draws);
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci   return draw;
558bf215546Sopenharmony_ci}
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_cistatic const char *param_unit(enum overlay_param_enabled param)
561bf215546Sopenharmony_ci{
562bf215546Sopenharmony_ci   switch (param) {
563bf215546Sopenharmony_ci   case OVERLAY_PARAM_ENABLED_frame_timing:
564bf215546Sopenharmony_ci   case OVERLAY_PARAM_ENABLED_acquire_timing:
565bf215546Sopenharmony_ci   case OVERLAY_PARAM_ENABLED_present_timing:
566bf215546Sopenharmony_ci      return "(us)";
567bf215546Sopenharmony_ci   case OVERLAY_PARAM_ENABLED_gpu_timing:
568bf215546Sopenharmony_ci      return "(ns)";
569bf215546Sopenharmony_ci   default:
570bf215546Sopenharmony_ci      return "";
571bf215546Sopenharmony_ci   }
572bf215546Sopenharmony_ci}
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_cistatic void parse_command(struct instance_data *instance_data,
575bf215546Sopenharmony_ci                          const char *cmd, unsigned cmdlen,
576bf215546Sopenharmony_ci                          const char *param, unsigned paramlen)
577bf215546Sopenharmony_ci{
578bf215546Sopenharmony_ci   if (!strncmp(cmd, "capture", cmdlen)) {
579bf215546Sopenharmony_ci      int value = atoi(param);
580bf215546Sopenharmony_ci      bool enabled = value > 0;
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci      if (enabled) {
583bf215546Sopenharmony_ci         instance_data->capture_enabled = true;
584bf215546Sopenharmony_ci      } else {
585bf215546Sopenharmony_ci         instance_data->capture_enabled = false;
586bf215546Sopenharmony_ci         instance_data->capture_started = false;
587bf215546Sopenharmony_ci      }
588bf215546Sopenharmony_ci   }
589bf215546Sopenharmony_ci}
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci#define BUFSIZE 4096
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_ci/**
594bf215546Sopenharmony_ci * This function will process commands through the control file.
595bf215546Sopenharmony_ci *
596bf215546Sopenharmony_ci * A command starts with a colon, followed by the command, and followed by an
597bf215546Sopenharmony_ci * option '=' and a parameter.  It has to end with a semi-colon. A full command
598bf215546Sopenharmony_ci * + parameter looks like:
599bf215546Sopenharmony_ci *
600bf215546Sopenharmony_ci *    :cmd=param;
601bf215546Sopenharmony_ci */
602bf215546Sopenharmony_cistatic void process_char(struct instance_data *instance_data, char c)
603bf215546Sopenharmony_ci{
604bf215546Sopenharmony_ci   static char cmd[BUFSIZE];
605bf215546Sopenharmony_ci   static char param[BUFSIZE];
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci   static unsigned cmdpos = 0;
608bf215546Sopenharmony_ci   static unsigned parampos = 0;
609bf215546Sopenharmony_ci   static bool reading_cmd = false;
610bf215546Sopenharmony_ci   static bool reading_param = false;
611bf215546Sopenharmony_ci
612bf215546Sopenharmony_ci   switch (c) {
613bf215546Sopenharmony_ci   case ':':
614bf215546Sopenharmony_ci      cmdpos = 0;
615bf215546Sopenharmony_ci      parampos = 0;
616bf215546Sopenharmony_ci      reading_cmd = true;
617bf215546Sopenharmony_ci      reading_param = false;
618bf215546Sopenharmony_ci      break;
619bf215546Sopenharmony_ci   case ';':
620bf215546Sopenharmony_ci      if (!reading_cmd)
621bf215546Sopenharmony_ci         break;
622bf215546Sopenharmony_ci      cmd[cmdpos++] = '\0';
623bf215546Sopenharmony_ci      param[parampos++] = '\0';
624bf215546Sopenharmony_ci      parse_command(instance_data, cmd, cmdpos, param, parampos);
625bf215546Sopenharmony_ci      reading_cmd = false;
626bf215546Sopenharmony_ci      reading_param = false;
627bf215546Sopenharmony_ci      break;
628bf215546Sopenharmony_ci   case '=':
629bf215546Sopenharmony_ci      if (!reading_cmd)
630bf215546Sopenharmony_ci         break;
631bf215546Sopenharmony_ci      reading_param = true;
632bf215546Sopenharmony_ci      break;
633bf215546Sopenharmony_ci   default:
634bf215546Sopenharmony_ci      if (!reading_cmd)
635bf215546Sopenharmony_ci         break;
636bf215546Sopenharmony_ci
637bf215546Sopenharmony_ci      if (reading_param) {
638bf215546Sopenharmony_ci         /* overflow means an invalid parameter */
639bf215546Sopenharmony_ci         if (parampos >= BUFSIZE - 1) {
640bf215546Sopenharmony_ci            reading_cmd = false;
641bf215546Sopenharmony_ci            reading_param = false;
642bf215546Sopenharmony_ci            break;
643bf215546Sopenharmony_ci         }
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci         param[parampos++] = c;
646bf215546Sopenharmony_ci      } else {
647bf215546Sopenharmony_ci         /* overflow means an invalid command */
648bf215546Sopenharmony_ci         if (cmdpos >= BUFSIZE - 1) {
649bf215546Sopenharmony_ci            reading_cmd = false;
650bf215546Sopenharmony_ci            break;
651bf215546Sopenharmony_ci         }
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ci         cmd[cmdpos++] = c;
654bf215546Sopenharmony_ci      }
655bf215546Sopenharmony_ci   }
656bf215546Sopenharmony_ci}
657bf215546Sopenharmony_ci
658bf215546Sopenharmony_cistatic void control_send(struct instance_data *instance_data,
659bf215546Sopenharmony_ci                         const char *cmd, unsigned cmdlen,
660bf215546Sopenharmony_ci                         const char *param, unsigned paramlen)
661bf215546Sopenharmony_ci{
662bf215546Sopenharmony_ci   unsigned msglen = 0;
663bf215546Sopenharmony_ci   char buffer[BUFSIZE];
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci   assert(cmdlen + paramlen + 3 < BUFSIZE);
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ci   buffer[msglen++] = ':';
668bf215546Sopenharmony_ci
669bf215546Sopenharmony_ci   memcpy(&buffer[msglen], cmd, cmdlen);
670bf215546Sopenharmony_ci   msglen += cmdlen;
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   if (paramlen > 0) {
673bf215546Sopenharmony_ci      buffer[msglen++] = '=';
674bf215546Sopenharmony_ci      memcpy(&buffer[msglen], param, paramlen);
675bf215546Sopenharmony_ci      msglen += paramlen;
676bf215546Sopenharmony_ci      buffer[msglen++] = ';';
677bf215546Sopenharmony_ci   }
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_ci   os_socket_send(instance_data->control_client, buffer, msglen, 0);
680bf215546Sopenharmony_ci}
681bf215546Sopenharmony_ci
682bf215546Sopenharmony_cistatic void control_send_connection_string(struct device_data *device_data)
683bf215546Sopenharmony_ci{
684bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci   const char *controlVersionCmd = "MesaOverlayControlVersion";
687bf215546Sopenharmony_ci   const char *controlVersionString = "1";
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci   control_send(instance_data, controlVersionCmd, strlen(controlVersionCmd),
690bf215546Sopenharmony_ci                controlVersionString, strlen(controlVersionString));
691bf215546Sopenharmony_ci
692bf215546Sopenharmony_ci   const char *deviceCmd = "DeviceName";
693bf215546Sopenharmony_ci   const char *deviceName = device_data->properties.deviceName;
694bf215546Sopenharmony_ci
695bf215546Sopenharmony_ci   control_send(instance_data, deviceCmd, strlen(deviceCmd),
696bf215546Sopenharmony_ci                deviceName, strlen(deviceName));
697bf215546Sopenharmony_ci
698bf215546Sopenharmony_ci   const char *mesaVersionCmd = "MesaVersion";
699bf215546Sopenharmony_ci   const char *mesaVersionString = "Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
700bf215546Sopenharmony_ci
701bf215546Sopenharmony_ci   control_send(instance_data, mesaVersionCmd, strlen(mesaVersionCmd),
702bf215546Sopenharmony_ci                mesaVersionString, strlen(mesaVersionString));
703bf215546Sopenharmony_ci}
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_cistatic void control_client_check(struct device_data *device_data)
706bf215546Sopenharmony_ci{
707bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
708bf215546Sopenharmony_ci
709bf215546Sopenharmony_ci   /* Already connected, just return. */
710bf215546Sopenharmony_ci   if (instance_data->control_client >= 0)
711bf215546Sopenharmony_ci      return;
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci   int socket = os_socket_accept(instance_data->params.control);
714bf215546Sopenharmony_ci   if (socket == -1) {
715bf215546Sopenharmony_ci      if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED)
716bf215546Sopenharmony_ci         fprintf(stderr, "ERROR on socket: %s\n", strerror(errno));
717bf215546Sopenharmony_ci      return;
718bf215546Sopenharmony_ci   }
719bf215546Sopenharmony_ci
720bf215546Sopenharmony_ci   if (socket >= 0) {
721bf215546Sopenharmony_ci      os_socket_block(socket, false);
722bf215546Sopenharmony_ci      instance_data->control_client = socket;
723bf215546Sopenharmony_ci      control_send_connection_string(device_data);
724bf215546Sopenharmony_ci   }
725bf215546Sopenharmony_ci}
726bf215546Sopenharmony_ci
727bf215546Sopenharmony_cistatic void control_client_disconnected(struct instance_data *instance_data)
728bf215546Sopenharmony_ci{
729bf215546Sopenharmony_ci   os_socket_close(instance_data->control_client);
730bf215546Sopenharmony_ci   instance_data->control_client = -1;
731bf215546Sopenharmony_ci}
732bf215546Sopenharmony_ci
733bf215546Sopenharmony_cistatic void process_control_socket(struct instance_data *instance_data)
734bf215546Sopenharmony_ci{
735bf215546Sopenharmony_ci   const int client = instance_data->control_client;
736bf215546Sopenharmony_ci   if (client >= 0) {
737bf215546Sopenharmony_ci      char buf[BUFSIZE];
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci      while (true) {
740bf215546Sopenharmony_ci         ssize_t n = os_socket_recv(client, buf, BUFSIZE, 0);
741bf215546Sopenharmony_ci
742bf215546Sopenharmony_ci         if (n == -1) {
743bf215546Sopenharmony_ci            if (errno == EAGAIN || errno == EWOULDBLOCK) {
744bf215546Sopenharmony_ci               /* nothing to read, try again later */
745bf215546Sopenharmony_ci               break;
746bf215546Sopenharmony_ci            }
747bf215546Sopenharmony_ci
748bf215546Sopenharmony_ci            if (errno != ECONNRESET)
749bf215546Sopenharmony_ci               fprintf(stderr, "ERROR on connection: %s\n", strerror(errno));
750bf215546Sopenharmony_ci
751bf215546Sopenharmony_ci            control_client_disconnected(instance_data);
752bf215546Sopenharmony_ci         } else if (n == 0) {
753bf215546Sopenharmony_ci            /* recv() returns 0 when the client disconnects */
754bf215546Sopenharmony_ci            control_client_disconnected(instance_data);
755bf215546Sopenharmony_ci         }
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci         for (ssize_t i = 0; i < n; i++) {
758bf215546Sopenharmony_ci            process_char(instance_data, buf[i]);
759bf215546Sopenharmony_ci         }
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci         /* If we try to read BUFSIZE and receive BUFSIZE bytes from the
762bf215546Sopenharmony_ci          * socket, there's a good chance that there's still more data to be
763bf215546Sopenharmony_ci          * read, so we will try again. Otherwise, simply be done for this
764bf215546Sopenharmony_ci          * iteration and try again on the next frame.
765bf215546Sopenharmony_ci          */
766bf215546Sopenharmony_ci         if (n < BUFSIZE)
767bf215546Sopenharmony_ci            break;
768bf215546Sopenharmony_ci      }
769bf215546Sopenharmony_ci   }
770bf215546Sopenharmony_ci}
771bf215546Sopenharmony_ci
772bf215546Sopenharmony_cistatic void snapshot_swapchain_frame(struct swapchain_data *data)
773bf215546Sopenharmony_ci{
774bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
775bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
776bf215546Sopenharmony_ci   uint32_t f_idx = data->n_frames % ARRAY_SIZE(data->frames_stats);
777bf215546Sopenharmony_ci   uint64_t now = os_time_get(); /* us */
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci   if (instance_data->params.control >= 0) {
780bf215546Sopenharmony_ci      control_client_check(device_data);
781bf215546Sopenharmony_ci      process_control_socket(instance_data);
782bf215546Sopenharmony_ci   }
783bf215546Sopenharmony_ci
784bf215546Sopenharmony_ci   if (data->last_present_time) {
785bf215546Sopenharmony_ci      data->frame_stats.stats[OVERLAY_PARAM_ENABLED_frame_timing] =
786bf215546Sopenharmony_ci         now - data->last_present_time;
787bf215546Sopenharmony_ci   }
788bf215546Sopenharmony_ci
789bf215546Sopenharmony_ci   memset(&data->frames_stats[f_idx], 0, sizeof(data->frames_stats[f_idx]));
790bf215546Sopenharmony_ci   for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
791bf215546Sopenharmony_ci      data->frames_stats[f_idx].stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];
792bf215546Sopenharmony_ci      data->accumulated_stats.stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];
793bf215546Sopenharmony_ci   }
794bf215546Sopenharmony_ci
795bf215546Sopenharmony_ci   /* If capture has been enabled but it hasn't started yet, it means we are on
796bf215546Sopenharmony_ci    * the first snapshot after it has been enabled. At this point we want to
797bf215546Sopenharmony_ci    * use the stats captured so far to update the display, but we don't want
798bf215546Sopenharmony_ci    * this data to cause noise to the stats that we want to capture from now
799bf215546Sopenharmony_ci    * on.
800bf215546Sopenharmony_ci    *
801bf215546Sopenharmony_ci    * capture_begin == true will trigger an update of the fps on display, and a
802bf215546Sopenharmony_ci    * flush of the data, but no stats will be written to the output file. This
803bf215546Sopenharmony_ci    * way, we will have only stats from after the capture has been enabled
804bf215546Sopenharmony_ci    * written to the output_file.
805bf215546Sopenharmony_ci    */
806bf215546Sopenharmony_ci   const bool capture_begin =
807bf215546Sopenharmony_ci      instance_data->capture_enabled && !instance_data->capture_started;
808bf215546Sopenharmony_ci
809bf215546Sopenharmony_ci   if (data->last_fps_update) {
810bf215546Sopenharmony_ci      double elapsed = (double)(now - data->last_fps_update); /* us */
811bf215546Sopenharmony_ci      if (capture_begin ||
812bf215546Sopenharmony_ci          elapsed >= instance_data->params.fps_sampling_period) {
813bf215546Sopenharmony_ci         data->fps = 1000000.0f * data->n_frames_since_update / elapsed;
814bf215546Sopenharmony_ci         if (instance_data->capture_started) {
815bf215546Sopenharmony_ci            if (!instance_data->first_line_printed) {
816bf215546Sopenharmony_ci               bool first_column = true;
817bf215546Sopenharmony_ci
818bf215546Sopenharmony_ci               instance_data->first_line_printed = true;
819bf215546Sopenharmony_ci
820bf215546Sopenharmony_ci#define OVERLAY_PARAM_BOOL(name) \
821bf215546Sopenharmony_ci               if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_##name]) { \
822bf215546Sopenharmony_ci                  fprintf(instance_data->params.output_file, \
823bf215546Sopenharmony_ci                          "%s%s%s", first_column ? "" : ", ", #name, \
824bf215546Sopenharmony_ci                          param_unit(OVERLAY_PARAM_ENABLED_##name)); \
825bf215546Sopenharmony_ci                  first_column = false; \
826bf215546Sopenharmony_ci               }
827bf215546Sopenharmony_ci#define OVERLAY_PARAM_CUSTOM(name)
828bf215546Sopenharmony_ci               OVERLAY_PARAMS
829bf215546Sopenharmony_ci#undef OVERLAY_PARAM_BOOL
830bf215546Sopenharmony_ci#undef OVERLAY_PARAM_CUSTOM
831bf215546Sopenharmony_ci               fprintf(instance_data->params.output_file, "\n");
832bf215546Sopenharmony_ci            }
833bf215546Sopenharmony_ci
834bf215546Sopenharmony_ci            for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
835bf215546Sopenharmony_ci               if (!instance_data->params.enabled[s])
836bf215546Sopenharmony_ci                  continue;
837bf215546Sopenharmony_ci               if (s == OVERLAY_PARAM_ENABLED_fps) {
838bf215546Sopenharmony_ci                  fprintf(instance_data->params.output_file,
839bf215546Sopenharmony_ci                          "%s%.2f", s == 0 ? "" : ", ", data->fps);
840bf215546Sopenharmony_ci               } else {
841bf215546Sopenharmony_ci                  fprintf(instance_data->params.output_file,
842bf215546Sopenharmony_ci                          "%s%" PRIu64, s == 0 ? "" : ", ",
843bf215546Sopenharmony_ci                          data->accumulated_stats.stats[s]);
844bf215546Sopenharmony_ci               }
845bf215546Sopenharmony_ci            }
846bf215546Sopenharmony_ci            fprintf(instance_data->params.output_file, "\n");
847bf215546Sopenharmony_ci            fflush(instance_data->params.output_file);
848bf215546Sopenharmony_ci         }
849bf215546Sopenharmony_ci
850bf215546Sopenharmony_ci         memset(&data->accumulated_stats, 0, sizeof(data->accumulated_stats));
851bf215546Sopenharmony_ci         data->n_frames_since_update = 0;
852bf215546Sopenharmony_ci         data->last_fps_update = now;
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci         if (capture_begin)
855bf215546Sopenharmony_ci            instance_data->capture_started = true;
856bf215546Sopenharmony_ci      }
857bf215546Sopenharmony_ci   } else {
858bf215546Sopenharmony_ci      data->last_fps_update = now;
859bf215546Sopenharmony_ci   }
860bf215546Sopenharmony_ci
861bf215546Sopenharmony_ci   memset(&device_data->frame_stats, 0, sizeof(device_data->frame_stats));
862bf215546Sopenharmony_ci   memset(&data->frame_stats, 0, sizeof(device_data->frame_stats));
863bf215546Sopenharmony_ci
864bf215546Sopenharmony_ci   data->last_present_time = now;
865bf215546Sopenharmony_ci   data->n_frames++;
866bf215546Sopenharmony_ci   data->n_frames_since_update++;
867bf215546Sopenharmony_ci}
868bf215546Sopenharmony_ci
869bf215546Sopenharmony_cistatic float get_time_stat(void *_data, int _idx)
870bf215546Sopenharmony_ci{
871bf215546Sopenharmony_ci   struct swapchain_data *data = (struct swapchain_data *) _data;
872bf215546Sopenharmony_ci   if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames)
873bf215546Sopenharmony_ci      return 0.0f;
874bf215546Sopenharmony_ci   int idx = ARRAY_SIZE(data->frames_stats) +
875bf215546Sopenharmony_ci      data->n_frames < ARRAY_SIZE(data->frames_stats) ?
876bf215546Sopenharmony_ci      _idx - data->n_frames :
877bf215546Sopenharmony_ci      _idx + data->n_frames;
878bf215546Sopenharmony_ci   idx %= ARRAY_SIZE(data->frames_stats);
879bf215546Sopenharmony_ci   /* Time stats are in us. */
880bf215546Sopenharmony_ci   return data->frames_stats[idx].stats[data->stat_selector] / data->time_dividor;
881bf215546Sopenharmony_ci}
882bf215546Sopenharmony_ci
883bf215546Sopenharmony_cistatic float get_stat(void *_data, int _idx)
884bf215546Sopenharmony_ci{
885bf215546Sopenharmony_ci   struct swapchain_data *data = (struct swapchain_data *) _data;
886bf215546Sopenharmony_ci   if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames)
887bf215546Sopenharmony_ci      return 0.0f;
888bf215546Sopenharmony_ci   int idx = ARRAY_SIZE(data->frames_stats) +
889bf215546Sopenharmony_ci      data->n_frames < ARRAY_SIZE(data->frames_stats) ?
890bf215546Sopenharmony_ci      _idx - data->n_frames :
891bf215546Sopenharmony_ci      _idx + data->n_frames;
892bf215546Sopenharmony_ci   idx %= ARRAY_SIZE(data->frames_stats);
893bf215546Sopenharmony_ci   return data->frames_stats[idx].stats[data->stat_selector];
894bf215546Sopenharmony_ci}
895bf215546Sopenharmony_ci
896bf215546Sopenharmony_cistatic void position_layer(struct swapchain_data *data)
897bf215546Sopenharmony_ci
898bf215546Sopenharmony_ci{
899bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
900bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
901bf215546Sopenharmony_ci   const float margin = 10.0f;
902bf215546Sopenharmony_ci
903bf215546Sopenharmony_ci   ImGui::SetNextWindowBgAlpha(0.5);
904bf215546Sopenharmony_ci   ImGui::SetNextWindowSize(data->window_size, ImGuiCond_Always);
905bf215546Sopenharmony_ci   switch (instance_data->params.position) {
906bf215546Sopenharmony_ci   case LAYER_POSITION_TOP_LEFT:
907bf215546Sopenharmony_ci      ImGui::SetNextWindowPos(ImVec2(margin, margin), ImGuiCond_Always);
908bf215546Sopenharmony_ci      break;
909bf215546Sopenharmony_ci   case LAYER_POSITION_TOP_RIGHT:
910bf215546Sopenharmony_ci      ImGui::SetNextWindowPos(ImVec2(data->width - data->window_size.x - margin, margin),
911bf215546Sopenharmony_ci                              ImGuiCond_Always);
912bf215546Sopenharmony_ci      break;
913bf215546Sopenharmony_ci   case LAYER_POSITION_BOTTOM_LEFT:
914bf215546Sopenharmony_ci      ImGui::SetNextWindowPos(ImVec2(margin, data->height - data->window_size.y - margin),
915bf215546Sopenharmony_ci                              ImGuiCond_Always);
916bf215546Sopenharmony_ci      break;
917bf215546Sopenharmony_ci   case LAYER_POSITION_BOTTOM_RIGHT:
918bf215546Sopenharmony_ci      ImGui::SetNextWindowPos(ImVec2(data->width - data->window_size.x - margin,
919bf215546Sopenharmony_ci                                     data->height - data->window_size.y - margin),
920bf215546Sopenharmony_ci                              ImGuiCond_Always);
921bf215546Sopenharmony_ci      break;
922bf215546Sopenharmony_ci   }
923bf215546Sopenharmony_ci}
924bf215546Sopenharmony_ci
925bf215546Sopenharmony_cistatic void compute_swapchain_display(struct swapchain_data *data)
926bf215546Sopenharmony_ci{
927bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
928bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
929bf215546Sopenharmony_ci
930bf215546Sopenharmony_ci   ImGui::SetCurrentContext(data->imgui_context);
931bf215546Sopenharmony_ci   ImGui::NewFrame();
932bf215546Sopenharmony_ci   position_layer(data);
933bf215546Sopenharmony_ci   ImGui::Begin("Mesa overlay");
934bf215546Sopenharmony_ci   if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_device])
935bf215546Sopenharmony_ci      ImGui::Text("Device: %s", device_data->properties.deviceName);
936bf215546Sopenharmony_ci
937bf215546Sopenharmony_ci   if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_format]) {
938bf215546Sopenharmony_ci      const char *format_name = vk_Format_to_str(data->format);
939bf215546Sopenharmony_ci      format_name = format_name ? (format_name + strlen("VK_FORMAT_")) : "unknown";
940bf215546Sopenharmony_ci      ImGui::Text("Swapchain format: %s", format_name);
941bf215546Sopenharmony_ci   }
942bf215546Sopenharmony_ci   if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_frame])
943bf215546Sopenharmony_ci      ImGui::Text("Frames: %" PRIu64, data->n_frames);
944bf215546Sopenharmony_ci   if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_fps])
945bf215546Sopenharmony_ci      ImGui::Text("FPS: %.2f" , data->fps);
946bf215546Sopenharmony_ci
947bf215546Sopenharmony_ci   /* Recompute min/max */
948bf215546Sopenharmony_ci   for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
949bf215546Sopenharmony_ci      data->stats_min.stats[s] = UINT64_MAX;
950bf215546Sopenharmony_ci      data->stats_max.stats[s] = 0;
951bf215546Sopenharmony_ci   }
952bf215546Sopenharmony_ci   for (uint32_t f = 0; f < MIN2(data->n_frames, ARRAY_SIZE(data->frames_stats)); f++) {
953bf215546Sopenharmony_ci      for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
954bf215546Sopenharmony_ci         data->stats_min.stats[s] = MIN2(data->frames_stats[f].stats[s],
955bf215546Sopenharmony_ci                                         data->stats_min.stats[s]);
956bf215546Sopenharmony_ci         data->stats_max.stats[s] = MAX2(data->frames_stats[f].stats[s],
957bf215546Sopenharmony_ci                                         data->stats_max.stats[s]);
958bf215546Sopenharmony_ci      }
959bf215546Sopenharmony_ci   }
960bf215546Sopenharmony_ci   for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
961bf215546Sopenharmony_ci      assert(data->stats_min.stats[s] != UINT64_MAX);
962bf215546Sopenharmony_ci   }
963bf215546Sopenharmony_ci
964bf215546Sopenharmony_ci   for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {
965bf215546Sopenharmony_ci      if (!instance_data->params.enabled[s] ||
966bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_device ||
967bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_format ||
968bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_fps ||
969bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_frame)
970bf215546Sopenharmony_ci         continue;
971bf215546Sopenharmony_ci
972bf215546Sopenharmony_ci      char hash[40];
973bf215546Sopenharmony_ci      snprintf(hash, sizeof(hash), "##%s", overlay_param_names[s]);
974bf215546Sopenharmony_ci      data->stat_selector = (enum overlay_param_enabled) s;
975bf215546Sopenharmony_ci      data->time_dividor = 1000.0f;
976bf215546Sopenharmony_ci      if (s == OVERLAY_PARAM_ENABLED_gpu_timing)
977bf215546Sopenharmony_ci         data->time_dividor = 1000000.0f;
978bf215546Sopenharmony_ci
979bf215546Sopenharmony_ci      if (s == OVERLAY_PARAM_ENABLED_frame_timing ||
980bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_acquire_timing ||
981bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_present_timing ||
982bf215546Sopenharmony_ci          s == OVERLAY_PARAM_ENABLED_gpu_timing) {
983bf215546Sopenharmony_ci         double min_time = data->stats_min.stats[s] / data->time_dividor;
984bf215546Sopenharmony_ci         double max_time = data->stats_max.stats[s] / data->time_dividor;
985bf215546Sopenharmony_ci         ImGui::PlotHistogram(hash, get_time_stat, data,
986bf215546Sopenharmony_ci                              ARRAY_SIZE(data->frames_stats), 0,
987bf215546Sopenharmony_ci                              NULL, min_time, max_time,
988bf215546Sopenharmony_ci                              ImVec2(ImGui::GetContentRegionAvailWidth(), 30));
989bf215546Sopenharmony_ci         ImGui::Text("%s: %.3fms [%.3f, %.3f]", overlay_param_names[s],
990bf215546Sopenharmony_ci                     get_time_stat(data, ARRAY_SIZE(data->frames_stats) - 1),
991bf215546Sopenharmony_ci                     min_time, max_time);
992bf215546Sopenharmony_ci      } else {
993bf215546Sopenharmony_ci         ImGui::PlotHistogram(hash, get_stat, data,
994bf215546Sopenharmony_ci                              ARRAY_SIZE(data->frames_stats), 0,
995bf215546Sopenharmony_ci                              NULL,
996bf215546Sopenharmony_ci                              data->stats_min.stats[s],
997bf215546Sopenharmony_ci                              data->stats_max.stats[s],
998bf215546Sopenharmony_ci                              ImVec2(ImGui::GetContentRegionAvailWidth(), 30));
999bf215546Sopenharmony_ci         ImGui::Text("%s: %.0f [%" PRIu64 ", %" PRIu64 "]", overlay_param_names[s],
1000bf215546Sopenharmony_ci                     get_stat(data, ARRAY_SIZE(data->frames_stats) - 1),
1001bf215546Sopenharmony_ci                     data->stats_min.stats[s], data->stats_max.stats[s]);
1002bf215546Sopenharmony_ci      }
1003bf215546Sopenharmony_ci   }
1004bf215546Sopenharmony_ci   data->window_size = ImVec2(data->window_size.x, ImGui::GetCursorPosY() + 10.0f);
1005bf215546Sopenharmony_ci   ImGui::End();
1006bf215546Sopenharmony_ci   ImGui::EndFrame();
1007bf215546Sopenharmony_ci   ImGui::Render();
1008bf215546Sopenharmony_ci}
1009bf215546Sopenharmony_ci
1010bf215546Sopenharmony_cistatic uint32_t vk_memory_type(struct device_data *data,
1011bf215546Sopenharmony_ci                               VkMemoryPropertyFlags properties,
1012bf215546Sopenharmony_ci                               uint32_t type_bits)
1013bf215546Sopenharmony_ci{
1014bf215546Sopenharmony_ci    VkPhysicalDeviceMemoryProperties prop;
1015bf215546Sopenharmony_ci    data->instance->pd_vtable.GetPhysicalDeviceMemoryProperties(data->physical_device, &prop);
1016bf215546Sopenharmony_ci    for (uint32_t i = 0; i < prop.memoryTypeCount; i++)
1017bf215546Sopenharmony_ci        if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<<i))
1018bf215546Sopenharmony_ci            return i;
1019bf215546Sopenharmony_ci    return 0xFFFFFFFF; // Unable to find memoryType
1020bf215546Sopenharmony_ci}
1021bf215546Sopenharmony_ci
1022bf215546Sopenharmony_cistatic void ensure_swapchain_fonts(struct swapchain_data *data,
1023bf215546Sopenharmony_ci                                   VkCommandBuffer command_buffer)
1024bf215546Sopenharmony_ci{
1025bf215546Sopenharmony_ci   if (data->font_uploaded)
1026bf215546Sopenharmony_ci      return;
1027bf215546Sopenharmony_ci
1028bf215546Sopenharmony_ci   data->font_uploaded = true;
1029bf215546Sopenharmony_ci
1030bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
1031bf215546Sopenharmony_ci   ImGuiIO& io = ImGui::GetIO();
1032bf215546Sopenharmony_ci   unsigned char* pixels;
1033bf215546Sopenharmony_ci   int width, height;
1034bf215546Sopenharmony_ci   io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
1035bf215546Sopenharmony_ci   size_t upload_size = width * height * 4 * sizeof(char);
1036bf215546Sopenharmony_ci
1037bf215546Sopenharmony_ci   /* Upload buffer */
1038bf215546Sopenharmony_ci   VkBufferCreateInfo buffer_info = {};
1039bf215546Sopenharmony_ci   buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1040bf215546Sopenharmony_ci   buffer_info.size = upload_size;
1041bf215546Sopenharmony_ci   buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1042bf215546Sopenharmony_ci   buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1043bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateBuffer(device_data->device, &buffer_info,
1044bf215546Sopenharmony_ci                                             NULL, &data->upload_font_buffer));
1045bf215546Sopenharmony_ci   VkMemoryRequirements upload_buffer_req;
1046bf215546Sopenharmony_ci   device_data->vtable.GetBufferMemoryRequirements(device_data->device,
1047bf215546Sopenharmony_ci                                                   data->upload_font_buffer,
1048bf215546Sopenharmony_ci                                                   &upload_buffer_req);
1049bf215546Sopenharmony_ci   VkMemoryAllocateInfo upload_alloc_info = {};
1050bf215546Sopenharmony_ci   upload_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1051bf215546Sopenharmony_ci   upload_alloc_info.allocationSize = upload_buffer_req.size;
1052bf215546Sopenharmony_ci   upload_alloc_info.memoryTypeIndex = vk_memory_type(device_data,
1053bf215546Sopenharmony_ci                                                      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
1054bf215546Sopenharmony_ci                                                      upload_buffer_req.memoryTypeBits);
1055bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.AllocateMemory(device_data->device,
1056bf215546Sopenharmony_ci                                               &upload_alloc_info,
1057bf215546Sopenharmony_ci                                               NULL,
1058bf215546Sopenharmony_ci                                               &data->upload_font_buffer_mem));
1059bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.BindBufferMemory(device_data->device,
1060bf215546Sopenharmony_ci                                                 data->upload_font_buffer,
1061bf215546Sopenharmony_ci                                                 data->upload_font_buffer_mem, 0));
1062bf215546Sopenharmony_ci
1063bf215546Sopenharmony_ci   /* Upload to Buffer */
1064bf215546Sopenharmony_ci   char* map = NULL;
1065bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.MapMemory(device_data->device,
1066bf215546Sopenharmony_ci                                          data->upload_font_buffer_mem,
1067bf215546Sopenharmony_ci                                          0, upload_size, 0, (void**)(&map)));
1068bf215546Sopenharmony_ci   memcpy(map, pixels, upload_size);
1069bf215546Sopenharmony_ci   VkMappedMemoryRange range[1] = {};
1070bf215546Sopenharmony_ci   range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1071bf215546Sopenharmony_ci   range[0].memory = data->upload_font_buffer_mem;
1072bf215546Sopenharmony_ci   range[0].size = upload_size;
1073bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 1, range));
1074bf215546Sopenharmony_ci   device_data->vtable.UnmapMemory(device_data->device,
1075bf215546Sopenharmony_ci                                   data->upload_font_buffer_mem);
1076bf215546Sopenharmony_ci
1077bf215546Sopenharmony_ci   /* Copy buffer to image */
1078bf215546Sopenharmony_ci   VkImageMemoryBarrier copy_barrier[1] = {};
1079bf215546Sopenharmony_ci   copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1080bf215546Sopenharmony_ci   copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1081bf215546Sopenharmony_ci   copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1082bf215546Sopenharmony_ci   copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1083bf215546Sopenharmony_ci   copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1084bf215546Sopenharmony_ci   copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1085bf215546Sopenharmony_ci   copy_barrier[0].image = data->font_image;
1086bf215546Sopenharmony_ci   copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1087bf215546Sopenharmony_ci   copy_barrier[0].subresourceRange.levelCount = 1;
1088bf215546Sopenharmony_ci   copy_barrier[0].subresourceRange.layerCount = 1;
1089bf215546Sopenharmony_ci   device_data->vtable.CmdPipelineBarrier(command_buffer,
1090bf215546Sopenharmony_ci                                          VK_PIPELINE_STAGE_HOST_BIT,
1091bf215546Sopenharmony_ci                                          VK_PIPELINE_STAGE_TRANSFER_BIT,
1092bf215546Sopenharmony_ci                                          0, 0, NULL, 0, NULL,
1093bf215546Sopenharmony_ci                                          1, copy_barrier);
1094bf215546Sopenharmony_ci
1095bf215546Sopenharmony_ci   VkBufferImageCopy region = {};
1096bf215546Sopenharmony_ci   region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1097bf215546Sopenharmony_ci   region.imageSubresource.layerCount = 1;
1098bf215546Sopenharmony_ci   region.imageExtent.width = width;
1099bf215546Sopenharmony_ci   region.imageExtent.height = height;
1100bf215546Sopenharmony_ci   region.imageExtent.depth = 1;
1101bf215546Sopenharmony_ci   device_data->vtable.CmdCopyBufferToImage(command_buffer,
1102bf215546Sopenharmony_ci                                            data->upload_font_buffer,
1103bf215546Sopenharmony_ci                                            data->font_image,
1104bf215546Sopenharmony_ci                                            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1105bf215546Sopenharmony_ci                                            1, &region);
1106bf215546Sopenharmony_ci
1107bf215546Sopenharmony_ci   VkImageMemoryBarrier use_barrier[1] = {};
1108bf215546Sopenharmony_ci   use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1109bf215546Sopenharmony_ci   use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
1110bf215546Sopenharmony_ci   use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
1111bf215546Sopenharmony_ci   use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1112bf215546Sopenharmony_ci   use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1113bf215546Sopenharmony_ci   use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1114bf215546Sopenharmony_ci   use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1115bf215546Sopenharmony_ci   use_barrier[0].image = data->font_image;
1116bf215546Sopenharmony_ci   use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1117bf215546Sopenharmony_ci   use_barrier[0].subresourceRange.levelCount = 1;
1118bf215546Sopenharmony_ci   use_barrier[0].subresourceRange.layerCount = 1;
1119bf215546Sopenharmony_ci   device_data->vtable.CmdPipelineBarrier(command_buffer,
1120bf215546Sopenharmony_ci                                          VK_PIPELINE_STAGE_TRANSFER_BIT,
1121bf215546Sopenharmony_ci                                          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
1122bf215546Sopenharmony_ci                                          0,
1123bf215546Sopenharmony_ci                                          0, NULL,
1124bf215546Sopenharmony_ci                                          0, NULL,
1125bf215546Sopenharmony_ci                                          1, use_barrier);
1126bf215546Sopenharmony_ci
1127bf215546Sopenharmony_ci   /* Store our identifier */
1128bf215546Sopenharmony_ci   io.Fonts->TexID = (ImTextureID)(intptr_t)data->font_image;
1129bf215546Sopenharmony_ci}
1130bf215546Sopenharmony_ci
1131bf215546Sopenharmony_cistatic void CreateOrResizeBuffer(struct device_data *data,
1132bf215546Sopenharmony_ci                                 VkBuffer *buffer,
1133bf215546Sopenharmony_ci                                 VkDeviceMemory *buffer_memory,
1134bf215546Sopenharmony_ci                                 VkDeviceSize *buffer_size,
1135bf215546Sopenharmony_ci                                 size_t new_size, VkBufferUsageFlagBits usage)
1136bf215546Sopenharmony_ci{
1137bf215546Sopenharmony_ci    if (*buffer != VK_NULL_HANDLE)
1138bf215546Sopenharmony_ci        data->vtable.DestroyBuffer(data->device, *buffer, NULL);
1139bf215546Sopenharmony_ci    if (*buffer_memory)
1140bf215546Sopenharmony_ci        data->vtable.FreeMemory(data->device, *buffer_memory, NULL);
1141bf215546Sopenharmony_ci
1142bf215546Sopenharmony_ci    VkBufferCreateInfo buffer_info = {};
1143bf215546Sopenharmony_ci    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1144bf215546Sopenharmony_ci    buffer_info.size = new_size;
1145bf215546Sopenharmony_ci    buffer_info.usage = usage;
1146bf215546Sopenharmony_ci    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1147bf215546Sopenharmony_ci    VK_CHECK(data->vtable.CreateBuffer(data->device, &buffer_info, NULL, buffer));
1148bf215546Sopenharmony_ci
1149bf215546Sopenharmony_ci    VkMemoryRequirements req;
1150bf215546Sopenharmony_ci    data->vtable.GetBufferMemoryRequirements(data->device, *buffer, &req);
1151bf215546Sopenharmony_ci    VkMemoryAllocateInfo alloc_info = {};
1152bf215546Sopenharmony_ci    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1153bf215546Sopenharmony_ci    alloc_info.allocationSize = req.size;
1154bf215546Sopenharmony_ci    alloc_info.memoryTypeIndex =
1155bf215546Sopenharmony_ci       vk_memory_type(data, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);
1156bf215546Sopenharmony_ci    VK_CHECK(data->vtable.AllocateMemory(data->device, &alloc_info, NULL, buffer_memory));
1157bf215546Sopenharmony_ci
1158bf215546Sopenharmony_ci    VK_CHECK(data->vtable.BindBufferMemory(data->device, *buffer, *buffer_memory, 0));
1159bf215546Sopenharmony_ci    *buffer_size = new_size;
1160bf215546Sopenharmony_ci}
1161bf215546Sopenharmony_ci
1162bf215546Sopenharmony_cistatic struct overlay_draw *render_swapchain_display(struct swapchain_data *data,
1163bf215546Sopenharmony_ci                                                     struct queue_data *present_queue,
1164bf215546Sopenharmony_ci                                                     const VkSemaphore *wait_semaphores,
1165bf215546Sopenharmony_ci                                                     unsigned n_wait_semaphores,
1166bf215546Sopenharmony_ci                                                     unsigned image_index)
1167bf215546Sopenharmony_ci{
1168bf215546Sopenharmony_ci   ImDrawData* draw_data = ImGui::GetDrawData();
1169bf215546Sopenharmony_ci   if (draw_data->TotalVtxCount == 0)
1170bf215546Sopenharmony_ci      return NULL;
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
1173bf215546Sopenharmony_ci   struct overlay_draw *draw = get_overlay_draw(data);
1174bf215546Sopenharmony_ci
1175bf215546Sopenharmony_ci   device_data->vtable.ResetCommandBuffer(draw->command_buffer, 0);
1176bf215546Sopenharmony_ci
1177bf215546Sopenharmony_ci   VkRenderPassBeginInfo render_pass_info = {};
1178bf215546Sopenharmony_ci   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1179bf215546Sopenharmony_ci   render_pass_info.renderPass = data->render_pass;
1180bf215546Sopenharmony_ci   render_pass_info.framebuffer = data->framebuffers[image_index];
1181bf215546Sopenharmony_ci   render_pass_info.renderArea.extent.width = data->width;
1182bf215546Sopenharmony_ci   render_pass_info.renderArea.extent.height = data->height;
1183bf215546Sopenharmony_ci
1184bf215546Sopenharmony_ci   VkCommandBufferBeginInfo buffer_begin_info = {};
1185bf215546Sopenharmony_ci   buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_ci   device_data->vtable.BeginCommandBuffer(draw->command_buffer, &buffer_begin_info);
1188bf215546Sopenharmony_ci
1189bf215546Sopenharmony_ci   ensure_swapchain_fonts(data, draw->command_buffer);
1190bf215546Sopenharmony_ci
1191bf215546Sopenharmony_ci   /* Bounce the image to display back to color attachment layout for
1192bf215546Sopenharmony_ci    * rendering on top of it.
1193bf215546Sopenharmony_ci    */
1194bf215546Sopenharmony_ci   VkImageMemoryBarrier imb;
1195bf215546Sopenharmony_ci   imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1196bf215546Sopenharmony_ci   imb.pNext = nullptr;
1197bf215546Sopenharmony_ci   imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1198bf215546Sopenharmony_ci   imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1199bf215546Sopenharmony_ci   imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1200bf215546Sopenharmony_ci   imb.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1201bf215546Sopenharmony_ci   imb.image = data->images[image_index];
1202bf215546Sopenharmony_ci   imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1203bf215546Sopenharmony_ci   imb.subresourceRange.baseMipLevel = 0;
1204bf215546Sopenharmony_ci   imb.subresourceRange.levelCount = 1;
1205bf215546Sopenharmony_ci   imb.subresourceRange.baseArrayLayer = 0;
1206bf215546Sopenharmony_ci   imb.subresourceRange.layerCount = 1;
1207bf215546Sopenharmony_ci   imb.srcQueueFamilyIndex = present_queue->family_index;
1208bf215546Sopenharmony_ci   imb.dstQueueFamilyIndex = device_data->graphic_queue->family_index;
1209bf215546Sopenharmony_ci   device_data->vtable.CmdPipelineBarrier(draw->command_buffer,
1210bf215546Sopenharmony_ci                                          VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1211bf215546Sopenharmony_ci                                          VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1212bf215546Sopenharmony_ci                                          0,          /* dependency flags */
1213bf215546Sopenharmony_ci                                          0, nullptr, /* memory barriers */
1214bf215546Sopenharmony_ci                                          0, nullptr, /* buffer memory barriers */
1215bf215546Sopenharmony_ci                                          1, &imb);   /* image memory barriers */
1216bf215546Sopenharmony_ci
1217bf215546Sopenharmony_ci   device_data->vtable.CmdBeginRenderPass(draw->command_buffer, &render_pass_info,
1218bf215546Sopenharmony_ci                                          VK_SUBPASS_CONTENTS_INLINE);
1219bf215546Sopenharmony_ci
1220bf215546Sopenharmony_ci   /* Create/Resize vertex & index buffers */
1221bf215546Sopenharmony_ci   size_t vertex_size = ALIGN(draw_data->TotalVtxCount * sizeof(ImDrawVert), device_data->properties.limits.nonCoherentAtomSize);
1222bf215546Sopenharmony_ci   size_t index_size = ALIGN(draw_data->TotalIdxCount * sizeof(ImDrawIdx), device_data->properties.limits.nonCoherentAtomSize);
1223bf215546Sopenharmony_ci   if (draw->vertex_buffer_size < vertex_size) {
1224bf215546Sopenharmony_ci      CreateOrResizeBuffer(device_data,
1225bf215546Sopenharmony_ci                           &draw->vertex_buffer,
1226bf215546Sopenharmony_ci                           &draw->vertex_buffer_mem,
1227bf215546Sopenharmony_ci                           &draw->vertex_buffer_size,
1228bf215546Sopenharmony_ci                           vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1229bf215546Sopenharmony_ci   }
1230bf215546Sopenharmony_ci   if (draw->index_buffer_size < index_size) {
1231bf215546Sopenharmony_ci      CreateOrResizeBuffer(device_data,
1232bf215546Sopenharmony_ci                           &draw->index_buffer,
1233bf215546Sopenharmony_ci                           &draw->index_buffer_mem,
1234bf215546Sopenharmony_ci                           &draw->index_buffer_size,
1235bf215546Sopenharmony_ci                           index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1236bf215546Sopenharmony_ci   }
1237bf215546Sopenharmony_ci
1238bf215546Sopenharmony_ci    /* Upload vertex & index data */
1239bf215546Sopenharmony_ci    ImDrawVert* vtx_dst = NULL;
1240bf215546Sopenharmony_ci    ImDrawIdx* idx_dst = NULL;
1241bf215546Sopenharmony_ci    VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->vertex_buffer_mem,
1242bf215546Sopenharmony_ci                                           0, vertex_size, 0, (void**)(&vtx_dst)));
1243bf215546Sopenharmony_ci    VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->index_buffer_mem,
1244bf215546Sopenharmony_ci                                           0, index_size, 0, (void**)(&idx_dst)));
1245bf215546Sopenharmony_ci    for (int n = 0; n < draw_data->CmdListsCount; n++)
1246bf215546Sopenharmony_ci        {
1247bf215546Sopenharmony_ci           const ImDrawList* cmd_list = draw_data->CmdLists[n];
1248bf215546Sopenharmony_ci           memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
1249bf215546Sopenharmony_ci           memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
1250bf215546Sopenharmony_ci           vtx_dst += cmd_list->VtxBuffer.Size;
1251bf215546Sopenharmony_ci           idx_dst += cmd_list->IdxBuffer.Size;
1252bf215546Sopenharmony_ci        }
1253bf215546Sopenharmony_ci    VkMappedMemoryRange range[2] = {};
1254bf215546Sopenharmony_ci    range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1255bf215546Sopenharmony_ci    range[0].memory = draw->vertex_buffer_mem;
1256bf215546Sopenharmony_ci    range[0].size = VK_WHOLE_SIZE;
1257bf215546Sopenharmony_ci    range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1258bf215546Sopenharmony_ci    range[1].memory = draw->index_buffer_mem;
1259bf215546Sopenharmony_ci    range[1].size = VK_WHOLE_SIZE;
1260bf215546Sopenharmony_ci    VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 2, range));
1261bf215546Sopenharmony_ci    device_data->vtable.UnmapMemory(device_data->device, draw->vertex_buffer_mem);
1262bf215546Sopenharmony_ci    device_data->vtable.UnmapMemory(device_data->device, draw->index_buffer_mem);
1263bf215546Sopenharmony_ci
1264bf215546Sopenharmony_ci    /* Bind pipeline and descriptor sets */
1265bf215546Sopenharmony_ci    device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline);
1266bf215546Sopenharmony_ci    VkDescriptorSet desc_set[1] = { data->descriptor_set };
1267bf215546Sopenharmony_ci    device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
1268bf215546Sopenharmony_ci                                              data->pipeline_layout, 0, 1, desc_set, 0, NULL);
1269bf215546Sopenharmony_ci
1270bf215546Sopenharmony_ci    /* Bind vertex & index buffers */
1271bf215546Sopenharmony_ci    VkBuffer vertex_buffers[1] = { draw->vertex_buffer };
1272bf215546Sopenharmony_ci    VkDeviceSize vertex_offset[1] = { 0 };
1273bf215546Sopenharmony_ci    device_data->vtable.CmdBindVertexBuffers(draw->command_buffer, 0, 1, vertex_buffers, vertex_offset);
1274bf215546Sopenharmony_ci    device_data->vtable.CmdBindIndexBuffer(draw->command_buffer, draw->index_buffer, 0, VK_INDEX_TYPE_UINT16);
1275bf215546Sopenharmony_ci
1276bf215546Sopenharmony_ci    /* Setup viewport */
1277bf215546Sopenharmony_ci    VkViewport viewport;
1278bf215546Sopenharmony_ci    viewport.x = 0;
1279bf215546Sopenharmony_ci    viewport.y = 0;
1280bf215546Sopenharmony_ci    viewport.width = draw_data->DisplaySize.x;
1281bf215546Sopenharmony_ci    viewport.height = draw_data->DisplaySize.y;
1282bf215546Sopenharmony_ci    viewport.minDepth = 0.0f;
1283bf215546Sopenharmony_ci    viewport.maxDepth = 1.0f;
1284bf215546Sopenharmony_ci    device_data->vtable.CmdSetViewport(draw->command_buffer, 0, 1, &viewport);
1285bf215546Sopenharmony_ci
1286bf215546Sopenharmony_ci
1287bf215546Sopenharmony_ci    /* Setup scale and translation through push constants :
1288bf215546Sopenharmony_ci     *
1289bf215546Sopenharmony_ci     * Our visible imgui space lies from draw_data->DisplayPos (top left) to
1290bf215546Sopenharmony_ci     * draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin
1291bf215546Sopenharmony_ci     * is typically (0,0) for single viewport apps.
1292bf215546Sopenharmony_ci     */
1293bf215546Sopenharmony_ci    float scale[2];
1294bf215546Sopenharmony_ci    scale[0] = 2.0f / draw_data->DisplaySize.x;
1295bf215546Sopenharmony_ci    scale[1] = 2.0f / draw_data->DisplaySize.y;
1296bf215546Sopenharmony_ci    float translate[2];
1297bf215546Sopenharmony_ci    translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];
1298bf215546Sopenharmony_ci    translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];
1299bf215546Sopenharmony_ci    device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,
1300bf215546Sopenharmony_ci                                         VK_SHADER_STAGE_VERTEX_BIT,
1301bf215546Sopenharmony_ci                                         sizeof(float) * 0, sizeof(float) * 2, scale);
1302bf215546Sopenharmony_ci    device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,
1303bf215546Sopenharmony_ci                                         VK_SHADER_STAGE_VERTEX_BIT,
1304bf215546Sopenharmony_ci                                         sizeof(float) * 2, sizeof(float) * 2, translate);
1305bf215546Sopenharmony_ci
1306bf215546Sopenharmony_ci    // Render the command lists:
1307bf215546Sopenharmony_ci    int vtx_offset = 0;
1308bf215546Sopenharmony_ci    int idx_offset = 0;
1309bf215546Sopenharmony_ci    ImVec2 display_pos = draw_data->DisplayPos;
1310bf215546Sopenharmony_ci    for (int n = 0; n < draw_data->CmdListsCount; n++)
1311bf215546Sopenharmony_ci    {
1312bf215546Sopenharmony_ci        const ImDrawList* cmd_list = draw_data->CmdLists[n];
1313bf215546Sopenharmony_ci        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
1314bf215546Sopenharmony_ci        {
1315bf215546Sopenharmony_ci            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
1316bf215546Sopenharmony_ci            // Apply scissor/clipping rectangle
1317bf215546Sopenharmony_ci            // FIXME: We could clamp width/height based on clamped min/max values.
1318bf215546Sopenharmony_ci            VkRect2D scissor;
1319bf215546Sopenharmony_ci            scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0;
1320bf215546Sopenharmony_ci            scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0;
1321bf215546Sopenharmony_ci            scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
1322bf215546Sopenharmony_ci            scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?
1323bf215546Sopenharmony_ci            device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor);
1324bf215546Sopenharmony_ci
1325bf215546Sopenharmony_ci            // Draw
1326bf215546Sopenharmony_ci            device_data->vtable.CmdDrawIndexed(draw->command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);
1327bf215546Sopenharmony_ci
1328bf215546Sopenharmony_ci            idx_offset += pcmd->ElemCount;
1329bf215546Sopenharmony_ci        }
1330bf215546Sopenharmony_ci        vtx_offset += cmd_list->VtxBuffer.Size;
1331bf215546Sopenharmony_ci    }
1332bf215546Sopenharmony_ci
1333bf215546Sopenharmony_ci   device_data->vtable.CmdEndRenderPass(draw->command_buffer);
1334bf215546Sopenharmony_ci
1335bf215546Sopenharmony_ci   if (device_data->graphic_queue->family_index != present_queue->family_index)
1336bf215546Sopenharmony_ci   {
1337bf215546Sopenharmony_ci      /* Transfer the image back to the present queue family
1338bf215546Sopenharmony_ci       * image layout was already changed to present by the render pass
1339bf215546Sopenharmony_ci       */
1340bf215546Sopenharmony_ci      imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1341bf215546Sopenharmony_ci      imb.pNext = nullptr;
1342bf215546Sopenharmony_ci      imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1343bf215546Sopenharmony_ci      imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1344bf215546Sopenharmony_ci      imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1345bf215546Sopenharmony_ci      imb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1346bf215546Sopenharmony_ci      imb.image = data->images[image_index];
1347bf215546Sopenharmony_ci      imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1348bf215546Sopenharmony_ci      imb.subresourceRange.baseMipLevel = 0;
1349bf215546Sopenharmony_ci      imb.subresourceRange.levelCount = 1;
1350bf215546Sopenharmony_ci      imb.subresourceRange.baseArrayLayer = 0;
1351bf215546Sopenharmony_ci      imb.subresourceRange.layerCount = 1;
1352bf215546Sopenharmony_ci      imb.srcQueueFamilyIndex = device_data->graphic_queue->family_index;
1353bf215546Sopenharmony_ci      imb.dstQueueFamilyIndex = present_queue->family_index;
1354bf215546Sopenharmony_ci      device_data->vtable.CmdPipelineBarrier(draw->command_buffer,
1355bf215546Sopenharmony_ci                                             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1356bf215546Sopenharmony_ci                                             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1357bf215546Sopenharmony_ci                                             0,          /* dependency flags */
1358bf215546Sopenharmony_ci                                             0, nullptr, /* memory barriers */
1359bf215546Sopenharmony_ci                                             0, nullptr, /* buffer memory barriers */
1360bf215546Sopenharmony_ci                                             1, &imb);   /* image memory barriers */
1361bf215546Sopenharmony_ci   }
1362bf215546Sopenharmony_ci
1363bf215546Sopenharmony_ci   device_data->vtable.EndCommandBuffer(draw->command_buffer);
1364bf215546Sopenharmony_ci
1365bf215546Sopenharmony_ci   /* When presenting on a different queue than where we're drawing the
1366bf215546Sopenharmony_ci    * overlay *AND* when the application does not provide a semaphore to
1367bf215546Sopenharmony_ci    * vkQueuePresent, insert our own cross engine synchronization
1368bf215546Sopenharmony_ci    * semaphore.
1369bf215546Sopenharmony_ci    */
1370bf215546Sopenharmony_ci   if (n_wait_semaphores == 0 && device_data->graphic_queue->queue != present_queue->queue) {
1371bf215546Sopenharmony_ci      VkPipelineStageFlags stages_wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
1372bf215546Sopenharmony_ci      VkSubmitInfo submit_info = {};
1373bf215546Sopenharmony_ci      submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1374bf215546Sopenharmony_ci      submit_info.commandBufferCount = 0;
1375bf215546Sopenharmony_ci      submit_info.pWaitDstStageMask = &stages_wait;
1376bf215546Sopenharmony_ci      submit_info.waitSemaphoreCount = 0;
1377bf215546Sopenharmony_ci      submit_info.signalSemaphoreCount = 1;
1378bf215546Sopenharmony_ci      submit_info.pSignalSemaphores = &draw->cross_engine_semaphore;
1379bf215546Sopenharmony_ci
1380bf215546Sopenharmony_ci      device_data->vtable.QueueSubmit(present_queue->queue, 1, &submit_info, VK_NULL_HANDLE);
1381bf215546Sopenharmony_ci
1382bf215546Sopenharmony_ci      submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1383bf215546Sopenharmony_ci      submit_info.commandBufferCount = 1;
1384bf215546Sopenharmony_ci      submit_info.pWaitDstStageMask = &stages_wait;
1385bf215546Sopenharmony_ci      submit_info.pCommandBuffers = &draw->command_buffer;
1386bf215546Sopenharmony_ci      submit_info.waitSemaphoreCount = 1;
1387bf215546Sopenharmony_ci      submit_info.pWaitSemaphores = &draw->cross_engine_semaphore;
1388bf215546Sopenharmony_ci      submit_info.signalSemaphoreCount = 1;
1389bf215546Sopenharmony_ci      submit_info.pSignalSemaphores = &draw->semaphore;
1390bf215546Sopenharmony_ci
1391bf215546Sopenharmony_ci      device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);
1392bf215546Sopenharmony_ci   } else {
1393bf215546Sopenharmony_ci      VkPipelineStageFlags *stages_wait = (VkPipelineStageFlags*) malloc(sizeof(VkPipelineStageFlags) * n_wait_semaphores);
1394bf215546Sopenharmony_ci      for (unsigned i = 0; i < n_wait_semaphores; i++)
1395bf215546Sopenharmony_ci      {
1396bf215546Sopenharmony_ci         // wait in the fragment stage until the swapchain image is ready
1397bf215546Sopenharmony_ci         stages_wait[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
1398bf215546Sopenharmony_ci      }
1399bf215546Sopenharmony_ci
1400bf215546Sopenharmony_ci      VkSubmitInfo submit_info = {};
1401bf215546Sopenharmony_ci      submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1402bf215546Sopenharmony_ci      submit_info.commandBufferCount = 1;
1403bf215546Sopenharmony_ci      submit_info.pCommandBuffers = &draw->command_buffer;
1404bf215546Sopenharmony_ci      submit_info.pWaitDstStageMask = stages_wait;
1405bf215546Sopenharmony_ci      submit_info.waitSemaphoreCount = n_wait_semaphores;
1406bf215546Sopenharmony_ci      submit_info.pWaitSemaphores = wait_semaphores;
1407bf215546Sopenharmony_ci      submit_info.signalSemaphoreCount = 1;
1408bf215546Sopenharmony_ci      submit_info.pSignalSemaphores = &draw->semaphore;
1409bf215546Sopenharmony_ci
1410bf215546Sopenharmony_ci      device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);
1411bf215546Sopenharmony_ci
1412bf215546Sopenharmony_ci      free(stages_wait);
1413bf215546Sopenharmony_ci   }
1414bf215546Sopenharmony_ci
1415bf215546Sopenharmony_ci   return draw;
1416bf215546Sopenharmony_ci}
1417bf215546Sopenharmony_ci
1418bf215546Sopenharmony_cistatic const uint32_t overlay_vert_spv[] = {
1419bf215546Sopenharmony_ci#include "overlay.vert.spv.h"
1420bf215546Sopenharmony_ci};
1421bf215546Sopenharmony_cistatic const uint32_t overlay_frag_spv[] = {
1422bf215546Sopenharmony_ci#include "overlay.frag.spv.h"
1423bf215546Sopenharmony_ci};
1424bf215546Sopenharmony_ci
1425bf215546Sopenharmony_cistatic void setup_swapchain_data_pipeline(struct swapchain_data *data)
1426bf215546Sopenharmony_ci{
1427bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
1428bf215546Sopenharmony_ci   VkShaderModule vert_module, frag_module;
1429bf215546Sopenharmony_ci
1430bf215546Sopenharmony_ci   /* Create shader modules */
1431bf215546Sopenharmony_ci   VkShaderModuleCreateInfo vert_info = {};
1432bf215546Sopenharmony_ci   vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1433bf215546Sopenharmony_ci   vert_info.codeSize = sizeof(overlay_vert_spv);
1434bf215546Sopenharmony_ci   vert_info.pCode = overlay_vert_spv;
1435bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device,
1436bf215546Sopenharmony_ci                                                   &vert_info, NULL, &vert_module));
1437bf215546Sopenharmony_ci   VkShaderModuleCreateInfo frag_info = {};
1438bf215546Sopenharmony_ci   frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1439bf215546Sopenharmony_ci   frag_info.codeSize = sizeof(overlay_frag_spv);
1440bf215546Sopenharmony_ci   frag_info.pCode = (uint32_t*)overlay_frag_spv;
1441bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device,
1442bf215546Sopenharmony_ci                                                   &frag_info, NULL, &frag_module));
1443bf215546Sopenharmony_ci
1444bf215546Sopenharmony_ci   /* Font sampler */
1445bf215546Sopenharmony_ci   VkSamplerCreateInfo sampler_info = {};
1446bf215546Sopenharmony_ci   sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
1447bf215546Sopenharmony_ci   sampler_info.magFilter = VK_FILTER_LINEAR;
1448bf215546Sopenharmony_ci   sampler_info.minFilter = VK_FILTER_LINEAR;
1449bf215546Sopenharmony_ci   sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1450bf215546Sopenharmony_ci   sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1451bf215546Sopenharmony_ci   sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1452bf215546Sopenharmony_ci   sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1453bf215546Sopenharmony_ci   sampler_info.minLod = -1000;
1454bf215546Sopenharmony_ci   sampler_info.maxLod = 1000;
1455bf215546Sopenharmony_ci   sampler_info.maxAnisotropy = 1.0f;
1456bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateSampler(device_data->device, &sampler_info,
1457bf215546Sopenharmony_ci                                              NULL, &data->font_sampler));
1458bf215546Sopenharmony_ci
1459bf215546Sopenharmony_ci   /* Descriptor pool */
1460bf215546Sopenharmony_ci   VkDescriptorPoolSize sampler_pool_size = {};
1461bf215546Sopenharmony_ci   sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1462bf215546Sopenharmony_ci   sampler_pool_size.descriptorCount = 1;
1463bf215546Sopenharmony_ci   VkDescriptorPoolCreateInfo desc_pool_info = {};
1464bf215546Sopenharmony_ci   desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1465bf215546Sopenharmony_ci   desc_pool_info.maxSets = 1;
1466bf215546Sopenharmony_ci   desc_pool_info.poolSizeCount = 1;
1467bf215546Sopenharmony_ci   desc_pool_info.pPoolSizes = &sampler_pool_size;
1468bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateDescriptorPool(device_data->device,
1469bf215546Sopenharmony_ci                                                     &desc_pool_info,
1470bf215546Sopenharmony_ci                                                     NULL, &data->descriptor_pool));
1471bf215546Sopenharmony_ci
1472bf215546Sopenharmony_ci   /* Descriptor layout */
1473bf215546Sopenharmony_ci   VkSampler sampler[1] = { data->font_sampler };
1474bf215546Sopenharmony_ci   VkDescriptorSetLayoutBinding binding[1] = {};
1475bf215546Sopenharmony_ci   binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1476bf215546Sopenharmony_ci   binding[0].descriptorCount = 1;
1477bf215546Sopenharmony_ci   binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1478bf215546Sopenharmony_ci   binding[0].pImmutableSamplers = sampler;
1479bf215546Sopenharmony_ci   VkDescriptorSetLayoutCreateInfo set_layout_info = {};
1480bf215546Sopenharmony_ci   set_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1481bf215546Sopenharmony_ci   set_layout_info.bindingCount = 1;
1482bf215546Sopenharmony_ci   set_layout_info.pBindings = binding;
1483bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateDescriptorSetLayout(device_data->device,
1484bf215546Sopenharmony_ci                                                          &set_layout_info,
1485bf215546Sopenharmony_ci                                                          NULL, &data->descriptor_layout));
1486bf215546Sopenharmony_ci
1487bf215546Sopenharmony_ci   /* Descriptor set */
1488bf215546Sopenharmony_ci   VkDescriptorSetAllocateInfo alloc_info = {};
1489bf215546Sopenharmony_ci   alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
1490bf215546Sopenharmony_ci   alloc_info.descriptorPool = data->descriptor_pool;
1491bf215546Sopenharmony_ci   alloc_info.descriptorSetCount = 1;
1492bf215546Sopenharmony_ci   alloc_info.pSetLayouts = &data->descriptor_layout;
1493bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,
1494bf215546Sopenharmony_ci                                                       &alloc_info,
1495bf215546Sopenharmony_ci                                                       &data->descriptor_set));
1496bf215546Sopenharmony_ci
1497bf215546Sopenharmony_ci   /* Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full
1498bf215546Sopenharmony_ci    * 3d projection matrix
1499bf215546Sopenharmony_ci    */
1500bf215546Sopenharmony_ci   VkPushConstantRange push_constants[1] = {};
1501bf215546Sopenharmony_ci   push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1502bf215546Sopenharmony_ci   push_constants[0].offset = sizeof(float) * 0;
1503bf215546Sopenharmony_ci   push_constants[0].size = sizeof(float) * 4;
1504bf215546Sopenharmony_ci   VkPipelineLayoutCreateInfo layout_info = {};
1505bf215546Sopenharmony_ci   layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
1506bf215546Sopenharmony_ci   layout_info.setLayoutCount = 1;
1507bf215546Sopenharmony_ci   layout_info.pSetLayouts = &data->descriptor_layout;
1508bf215546Sopenharmony_ci   layout_info.pushConstantRangeCount = 1;
1509bf215546Sopenharmony_ci   layout_info.pPushConstantRanges = push_constants;
1510bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreatePipelineLayout(device_data->device,
1511bf215546Sopenharmony_ci                                                     &layout_info,
1512bf215546Sopenharmony_ci                                                     NULL, &data->pipeline_layout));
1513bf215546Sopenharmony_ci
1514bf215546Sopenharmony_ci   VkPipelineShaderStageCreateInfo stage[2] = {};
1515bf215546Sopenharmony_ci   stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1516bf215546Sopenharmony_ci   stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
1517bf215546Sopenharmony_ci   stage[0].module = vert_module;
1518bf215546Sopenharmony_ci   stage[0].pName = "main";
1519bf215546Sopenharmony_ci   stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1520bf215546Sopenharmony_ci   stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1521bf215546Sopenharmony_ci   stage[1].module = frag_module;
1522bf215546Sopenharmony_ci   stage[1].pName = "main";
1523bf215546Sopenharmony_ci
1524bf215546Sopenharmony_ci   VkVertexInputBindingDescription binding_desc[1] = {};
1525bf215546Sopenharmony_ci   binding_desc[0].stride = sizeof(ImDrawVert);
1526bf215546Sopenharmony_ci   binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1527bf215546Sopenharmony_ci
1528bf215546Sopenharmony_ci   VkVertexInputAttributeDescription attribute_desc[3] = {};
1529bf215546Sopenharmony_ci   attribute_desc[0].location = 0;
1530bf215546Sopenharmony_ci   attribute_desc[0].binding = binding_desc[0].binding;
1531bf215546Sopenharmony_ci   attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT;
1532bf215546Sopenharmony_ci   attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos);
1533bf215546Sopenharmony_ci   attribute_desc[1].location = 1;
1534bf215546Sopenharmony_ci   attribute_desc[1].binding = binding_desc[0].binding;
1535bf215546Sopenharmony_ci   attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;
1536bf215546Sopenharmony_ci   attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv);
1537bf215546Sopenharmony_ci   attribute_desc[2].location = 2;
1538bf215546Sopenharmony_ci   attribute_desc[2].binding = binding_desc[0].binding;
1539bf215546Sopenharmony_ci   attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM;
1540bf215546Sopenharmony_ci   attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col);
1541bf215546Sopenharmony_ci
1542bf215546Sopenharmony_ci   VkPipelineVertexInputStateCreateInfo vertex_info = {};
1543bf215546Sopenharmony_ci   vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1544bf215546Sopenharmony_ci   vertex_info.vertexBindingDescriptionCount = 1;
1545bf215546Sopenharmony_ci   vertex_info.pVertexBindingDescriptions = binding_desc;
1546bf215546Sopenharmony_ci   vertex_info.vertexAttributeDescriptionCount = 3;
1547bf215546Sopenharmony_ci   vertex_info.pVertexAttributeDescriptions = attribute_desc;
1548bf215546Sopenharmony_ci
1549bf215546Sopenharmony_ci   VkPipelineInputAssemblyStateCreateInfo ia_info = {};
1550bf215546Sopenharmony_ci   ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1551bf215546Sopenharmony_ci   ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1552bf215546Sopenharmony_ci
1553bf215546Sopenharmony_ci   VkPipelineViewportStateCreateInfo viewport_info = {};
1554bf215546Sopenharmony_ci   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1555bf215546Sopenharmony_ci   viewport_info.viewportCount = 1;
1556bf215546Sopenharmony_ci   viewport_info.scissorCount = 1;
1557bf215546Sopenharmony_ci
1558bf215546Sopenharmony_ci   VkPipelineRasterizationStateCreateInfo raster_info = {};
1559bf215546Sopenharmony_ci   raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1560bf215546Sopenharmony_ci   raster_info.polygonMode = VK_POLYGON_MODE_FILL;
1561bf215546Sopenharmony_ci   raster_info.cullMode = VK_CULL_MODE_NONE;
1562bf215546Sopenharmony_ci   raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
1563bf215546Sopenharmony_ci   raster_info.lineWidth = 1.0f;
1564bf215546Sopenharmony_ci
1565bf215546Sopenharmony_ci   VkPipelineMultisampleStateCreateInfo ms_info = {};
1566bf215546Sopenharmony_ci   ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1567bf215546Sopenharmony_ci   ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
1568bf215546Sopenharmony_ci
1569bf215546Sopenharmony_ci   VkPipelineColorBlendAttachmentState color_attachment[1] = {};
1570bf215546Sopenharmony_ci   color_attachment[0].blendEnable = VK_TRUE;
1571bf215546Sopenharmony_ci   color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
1572bf215546Sopenharmony_ci   color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
1573bf215546Sopenharmony_ci   color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD;
1574bf215546Sopenharmony_ci   color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
1575bf215546Sopenharmony_ci   color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
1576bf215546Sopenharmony_ci   color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD;
1577bf215546Sopenharmony_ci   color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
1578bf215546Sopenharmony_ci      VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
1579bf215546Sopenharmony_ci
1580bf215546Sopenharmony_ci   VkPipelineDepthStencilStateCreateInfo depth_info = {};
1581bf215546Sopenharmony_ci   depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1582bf215546Sopenharmony_ci
1583bf215546Sopenharmony_ci   VkPipelineColorBlendStateCreateInfo blend_info = {};
1584bf215546Sopenharmony_ci   blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1585bf215546Sopenharmony_ci   blend_info.attachmentCount = 1;
1586bf215546Sopenharmony_ci   blend_info.pAttachments = color_attachment;
1587bf215546Sopenharmony_ci
1588bf215546Sopenharmony_ci   VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
1589bf215546Sopenharmony_ci   VkPipelineDynamicStateCreateInfo dynamic_state = {};
1590bf215546Sopenharmony_ci   dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1591bf215546Sopenharmony_ci   dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states);
1592bf215546Sopenharmony_ci   dynamic_state.pDynamicStates = dynamic_states;
1593bf215546Sopenharmony_ci
1594bf215546Sopenharmony_ci   VkGraphicsPipelineCreateInfo info = {};
1595bf215546Sopenharmony_ci   info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1596bf215546Sopenharmony_ci   info.flags = 0;
1597bf215546Sopenharmony_ci   info.stageCount = 2;
1598bf215546Sopenharmony_ci   info.pStages = stage;
1599bf215546Sopenharmony_ci   info.pVertexInputState = &vertex_info;
1600bf215546Sopenharmony_ci   info.pInputAssemblyState = &ia_info;
1601bf215546Sopenharmony_ci   info.pViewportState = &viewport_info;
1602bf215546Sopenharmony_ci   info.pRasterizationState = &raster_info;
1603bf215546Sopenharmony_ci   info.pMultisampleState = &ms_info;
1604bf215546Sopenharmony_ci   info.pDepthStencilState = &depth_info;
1605bf215546Sopenharmony_ci   info.pColorBlendState = &blend_info;
1606bf215546Sopenharmony_ci   info.pDynamicState = &dynamic_state;
1607bf215546Sopenharmony_ci   info.layout = data->pipeline_layout;
1608bf215546Sopenharmony_ci   info.renderPass = data->render_pass;
1609bf215546Sopenharmony_ci   VK_CHECK(
1610bf215546Sopenharmony_ci      device_data->vtable.CreateGraphicsPipelines(device_data->device, VK_NULL_HANDLE,
1611bf215546Sopenharmony_ci                                                  1, &info,
1612bf215546Sopenharmony_ci                                                  NULL, &data->pipeline));
1613bf215546Sopenharmony_ci
1614bf215546Sopenharmony_ci   device_data->vtable.DestroyShaderModule(device_data->device, vert_module, NULL);
1615bf215546Sopenharmony_ci   device_data->vtable.DestroyShaderModule(device_data->device, frag_module, NULL);
1616bf215546Sopenharmony_ci
1617bf215546Sopenharmony_ci   ImGuiIO& io = ImGui::GetIO();
1618bf215546Sopenharmony_ci   unsigned char* pixels;
1619bf215546Sopenharmony_ci   int width, height;
1620bf215546Sopenharmony_ci   io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
1621bf215546Sopenharmony_ci
1622bf215546Sopenharmony_ci   /* Font image */
1623bf215546Sopenharmony_ci   VkImageCreateInfo image_info = {};
1624bf215546Sopenharmony_ci   image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1625bf215546Sopenharmony_ci   image_info.imageType = VK_IMAGE_TYPE_2D;
1626bf215546Sopenharmony_ci   image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
1627bf215546Sopenharmony_ci   image_info.extent.width = width;
1628bf215546Sopenharmony_ci   image_info.extent.height = height;
1629bf215546Sopenharmony_ci   image_info.extent.depth = 1;
1630bf215546Sopenharmony_ci   image_info.mipLevels = 1;
1631bf215546Sopenharmony_ci   image_info.arrayLayers = 1;
1632bf215546Sopenharmony_ci   image_info.samples = VK_SAMPLE_COUNT_1_BIT;
1633bf215546Sopenharmony_ci   image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
1634bf215546Sopenharmony_ci   image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1635bf215546Sopenharmony_ci   image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1636bf215546Sopenharmony_ci   image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1637bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info,
1638bf215546Sopenharmony_ci                                            NULL, &data->font_image));
1639bf215546Sopenharmony_ci   VkMemoryRequirements font_image_req;
1640bf215546Sopenharmony_ci   device_data->vtable.GetImageMemoryRequirements(device_data->device,
1641bf215546Sopenharmony_ci                                                  data->font_image, &font_image_req);
1642bf215546Sopenharmony_ci   VkMemoryAllocateInfo image_alloc_info = {};
1643bf215546Sopenharmony_ci   image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1644bf215546Sopenharmony_ci   image_alloc_info.allocationSize = font_image_req.size;
1645bf215546Sopenharmony_ci   image_alloc_info.memoryTypeIndex = vk_memory_type(device_data,
1646bf215546Sopenharmony_ci                                                     VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1647bf215546Sopenharmony_ci                                                     font_image_req.memoryTypeBits);
1648bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info,
1649bf215546Sopenharmony_ci                                               NULL, &data->font_mem));
1650bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.BindImageMemory(device_data->device,
1651bf215546Sopenharmony_ci                                                data->font_image,
1652bf215546Sopenharmony_ci                                                data->font_mem, 0));
1653bf215546Sopenharmony_ci
1654bf215546Sopenharmony_ci   /* Font image view */
1655bf215546Sopenharmony_ci   VkImageViewCreateInfo view_info = {};
1656bf215546Sopenharmony_ci   view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1657bf215546Sopenharmony_ci   view_info.image = data->font_image;
1658bf215546Sopenharmony_ci   view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
1659bf215546Sopenharmony_ci   view_info.format = VK_FORMAT_R8G8B8A8_UNORM;
1660bf215546Sopenharmony_ci   view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1661bf215546Sopenharmony_ci   view_info.subresourceRange.levelCount = 1;
1662bf215546Sopenharmony_ci   view_info.subresourceRange.layerCount = 1;
1663bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info,
1664bf215546Sopenharmony_ci                                                NULL, &data->font_image_view));
1665bf215546Sopenharmony_ci
1666bf215546Sopenharmony_ci   /* Descriptor set */
1667bf215546Sopenharmony_ci   VkDescriptorImageInfo desc_image[1] = {};
1668bf215546Sopenharmony_ci   desc_image[0].sampler = data->font_sampler;
1669bf215546Sopenharmony_ci   desc_image[0].imageView = data->font_image_view;
1670bf215546Sopenharmony_ci   desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1671bf215546Sopenharmony_ci   VkWriteDescriptorSet write_desc[1] = {};
1672bf215546Sopenharmony_ci   write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1673bf215546Sopenharmony_ci   write_desc[0].dstSet = data->descriptor_set;
1674bf215546Sopenharmony_ci   write_desc[0].descriptorCount = 1;
1675bf215546Sopenharmony_ci   write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1676bf215546Sopenharmony_ci   write_desc[0].pImageInfo = desc_image;
1677bf215546Sopenharmony_ci   device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL);
1678bf215546Sopenharmony_ci}
1679bf215546Sopenharmony_ci
1680bf215546Sopenharmony_cistatic void setup_swapchain_data(struct swapchain_data *data,
1681bf215546Sopenharmony_ci                                 const VkSwapchainCreateInfoKHR *pCreateInfo)
1682bf215546Sopenharmony_ci{
1683bf215546Sopenharmony_ci   data->width = pCreateInfo->imageExtent.width;
1684bf215546Sopenharmony_ci   data->height = pCreateInfo->imageExtent.height;
1685bf215546Sopenharmony_ci   data->format = pCreateInfo->imageFormat;
1686bf215546Sopenharmony_ci
1687bf215546Sopenharmony_ci   data->imgui_context = ImGui::CreateContext();
1688bf215546Sopenharmony_ci   ImGui::SetCurrentContext(data->imgui_context);
1689bf215546Sopenharmony_ci
1690bf215546Sopenharmony_ci   ImGui::GetIO().IniFilename = NULL;
1691bf215546Sopenharmony_ci   ImGui::GetIO().DisplaySize = ImVec2((float)data->width, (float)data->height);
1692bf215546Sopenharmony_ci
1693bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
1694bf215546Sopenharmony_ci
1695bf215546Sopenharmony_ci   /* Render pass */
1696bf215546Sopenharmony_ci   VkAttachmentDescription attachment_desc = {};
1697bf215546Sopenharmony_ci   attachment_desc.format = pCreateInfo->imageFormat;
1698bf215546Sopenharmony_ci   attachment_desc.samples = VK_SAMPLE_COUNT_1_BIT;
1699bf215546Sopenharmony_ci   attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1700bf215546Sopenharmony_ci   attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1701bf215546Sopenharmony_ci   attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1702bf215546Sopenharmony_ci   attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1703bf215546Sopenharmony_ci   attachment_desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1704bf215546Sopenharmony_ci   attachment_desc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1705bf215546Sopenharmony_ci   VkAttachmentReference color_attachment = {};
1706bf215546Sopenharmony_ci   color_attachment.attachment = 0;
1707bf215546Sopenharmony_ci   color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1708bf215546Sopenharmony_ci   VkSubpassDescription subpass = {};
1709bf215546Sopenharmony_ci   subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1710bf215546Sopenharmony_ci   subpass.colorAttachmentCount = 1;
1711bf215546Sopenharmony_ci   subpass.pColorAttachments = &color_attachment;
1712bf215546Sopenharmony_ci   VkSubpassDependency dependency = {};
1713bf215546Sopenharmony_ci   dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
1714bf215546Sopenharmony_ci   dependency.dstSubpass = 0;
1715bf215546Sopenharmony_ci   dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1716bf215546Sopenharmony_ci   dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1717bf215546Sopenharmony_ci   dependency.srcAccessMask = 0;
1718bf215546Sopenharmony_ci   dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1719bf215546Sopenharmony_ci   VkRenderPassCreateInfo render_pass_info = {};
1720bf215546Sopenharmony_ci   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1721bf215546Sopenharmony_ci   render_pass_info.attachmentCount = 1;
1722bf215546Sopenharmony_ci   render_pass_info.pAttachments = &attachment_desc;
1723bf215546Sopenharmony_ci   render_pass_info.subpassCount = 1;
1724bf215546Sopenharmony_ci   render_pass_info.pSubpasses = &subpass;
1725bf215546Sopenharmony_ci   render_pass_info.dependencyCount = 1;
1726bf215546Sopenharmony_ci   render_pass_info.pDependencies = &dependency;
1727bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateRenderPass(device_data->device,
1728bf215546Sopenharmony_ci                                                 &render_pass_info,
1729bf215546Sopenharmony_ci                                                 NULL, &data->render_pass));
1730bf215546Sopenharmony_ci
1731bf215546Sopenharmony_ci   setup_swapchain_data_pipeline(data);
1732bf215546Sopenharmony_ci
1733bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device,
1734bf215546Sopenharmony_ci                                                      data->swapchain,
1735bf215546Sopenharmony_ci                                                      &data->n_images,
1736bf215546Sopenharmony_ci                                                      NULL));
1737bf215546Sopenharmony_ci
1738bf215546Sopenharmony_ci   data->images = ralloc_array(data, VkImage, data->n_images);
1739bf215546Sopenharmony_ci   data->image_views = ralloc_array(data, VkImageView, data->n_images);
1740bf215546Sopenharmony_ci   data->framebuffers = ralloc_array(data, VkFramebuffer, data->n_images);
1741bf215546Sopenharmony_ci
1742bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device,
1743bf215546Sopenharmony_ci                                                      data->swapchain,
1744bf215546Sopenharmony_ci                                                      &data->n_images,
1745bf215546Sopenharmony_ci                                                      data->images));
1746bf215546Sopenharmony_ci
1747bf215546Sopenharmony_ci   /* Image views */
1748bf215546Sopenharmony_ci   VkImageViewCreateInfo view_info = {};
1749bf215546Sopenharmony_ci   view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1750bf215546Sopenharmony_ci   view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
1751bf215546Sopenharmony_ci   view_info.format = pCreateInfo->imageFormat;
1752bf215546Sopenharmony_ci   view_info.components.r = VK_COMPONENT_SWIZZLE_R;
1753bf215546Sopenharmony_ci   view_info.components.g = VK_COMPONENT_SWIZZLE_G;
1754bf215546Sopenharmony_ci   view_info.components.b = VK_COMPONENT_SWIZZLE_B;
1755bf215546Sopenharmony_ci   view_info.components.a = VK_COMPONENT_SWIZZLE_A;
1756bf215546Sopenharmony_ci   view_info.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
1757bf215546Sopenharmony_ci   for (uint32_t i = 0; i < data->n_images; i++) {
1758bf215546Sopenharmony_ci      view_info.image = data->images[i];
1759bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.CreateImageView(device_data->device,
1760bf215546Sopenharmony_ci                                                   &view_info, NULL,
1761bf215546Sopenharmony_ci                                                   &data->image_views[i]));
1762bf215546Sopenharmony_ci   }
1763bf215546Sopenharmony_ci
1764bf215546Sopenharmony_ci   /* Framebuffers */
1765bf215546Sopenharmony_ci   VkImageView attachment[1];
1766bf215546Sopenharmony_ci   VkFramebufferCreateInfo fb_info = {};
1767bf215546Sopenharmony_ci   fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1768bf215546Sopenharmony_ci   fb_info.renderPass = data->render_pass;
1769bf215546Sopenharmony_ci   fb_info.attachmentCount = 1;
1770bf215546Sopenharmony_ci   fb_info.pAttachments = attachment;
1771bf215546Sopenharmony_ci   fb_info.width = data->width;
1772bf215546Sopenharmony_ci   fb_info.height = data->height;
1773bf215546Sopenharmony_ci   fb_info.layers = 1;
1774bf215546Sopenharmony_ci   for (uint32_t i = 0; i < data->n_images; i++) {
1775bf215546Sopenharmony_ci      attachment[0] = data->image_views[i];
1776bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.CreateFramebuffer(device_data->device, &fb_info,
1777bf215546Sopenharmony_ci                                                     NULL, &data->framebuffers[i]));
1778bf215546Sopenharmony_ci   }
1779bf215546Sopenharmony_ci
1780bf215546Sopenharmony_ci   /* Command buffer pool */
1781bf215546Sopenharmony_ci   VkCommandPoolCreateInfo cmd_buffer_pool_info = {};
1782bf215546Sopenharmony_ci   cmd_buffer_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1783bf215546Sopenharmony_ci   cmd_buffer_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
1784bf215546Sopenharmony_ci   cmd_buffer_pool_info.queueFamilyIndex = device_data->graphic_queue->family_index;
1785bf215546Sopenharmony_ci   VK_CHECK(device_data->vtable.CreateCommandPool(device_data->device,
1786bf215546Sopenharmony_ci                                                  &cmd_buffer_pool_info,
1787bf215546Sopenharmony_ci                                                  NULL, &data->command_pool));
1788bf215546Sopenharmony_ci}
1789bf215546Sopenharmony_ci
1790bf215546Sopenharmony_cistatic void shutdown_swapchain_data(struct swapchain_data *data)
1791bf215546Sopenharmony_ci{
1792bf215546Sopenharmony_ci   struct device_data *device_data = data->device;
1793bf215546Sopenharmony_ci
1794bf215546Sopenharmony_ci   list_for_each_entry_safe(struct overlay_draw, draw, &data->draws, link) {
1795bf215546Sopenharmony_ci      device_data->vtable.DestroySemaphore(device_data->device, draw->cross_engine_semaphore, NULL);
1796bf215546Sopenharmony_ci      device_data->vtable.DestroySemaphore(device_data->device, draw->semaphore, NULL);
1797bf215546Sopenharmony_ci      device_data->vtable.DestroyFence(device_data->device, draw->fence, NULL);
1798bf215546Sopenharmony_ci      device_data->vtable.DestroyBuffer(device_data->device, draw->vertex_buffer, NULL);
1799bf215546Sopenharmony_ci      device_data->vtable.DestroyBuffer(device_data->device, draw->index_buffer, NULL);
1800bf215546Sopenharmony_ci      device_data->vtable.FreeMemory(device_data->device, draw->vertex_buffer_mem, NULL);
1801bf215546Sopenharmony_ci      device_data->vtable.FreeMemory(device_data->device, draw->index_buffer_mem, NULL);
1802bf215546Sopenharmony_ci   }
1803bf215546Sopenharmony_ci
1804bf215546Sopenharmony_ci   for (uint32_t i = 0; i < data->n_images; i++) {
1805bf215546Sopenharmony_ci      device_data->vtable.DestroyImageView(device_data->device, data->image_views[i], NULL);
1806bf215546Sopenharmony_ci      device_data->vtable.DestroyFramebuffer(device_data->device, data->framebuffers[i], NULL);
1807bf215546Sopenharmony_ci   }
1808bf215546Sopenharmony_ci
1809bf215546Sopenharmony_ci   device_data->vtable.DestroyRenderPass(device_data->device, data->render_pass, NULL);
1810bf215546Sopenharmony_ci
1811bf215546Sopenharmony_ci   device_data->vtable.DestroyCommandPool(device_data->device, data->command_pool, NULL);
1812bf215546Sopenharmony_ci
1813bf215546Sopenharmony_ci   device_data->vtable.DestroyPipeline(device_data->device, data->pipeline, NULL);
1814bf215546Sopenharmony_ci   device_data->vtable.DestroyPipelineLayout(device_data->device, data->pipeline_layout, NULL);
1815bf215546Sopenharmony_ci
1816bf215546Sopenharmony_ci   device_data->vtable.DestroyDescriptorPool(device_data->device,
1817bf215546Sopenharmony_ci                                             data->descriptor_pool, NULL);
1818bf215546Sopenharmony_ci   device_data->vtable.DestroyDescriptorSetLayout(device_data->device,
1819bf215546Sopenharmony_ci                                                  data->descriptor_layout, NULL);
1820bf215546Sopenharmony_ci
1821bf215546Sopenharmony_ci   device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL);
1822bf215546Sopenharmony_ci   device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL);
1823bf215546Sopenharmony_ci   device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL);
1824bf215546Sopenharmony_ci   device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL);
1825bf215546Sopenharmony_ci
1826bf215546Sopenharmony_ci   device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL);
1827bf215546Sopenharmony_ci   device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL);
1828bf215546Sopenharmony_ci
1829bf215546Sopenharmony_ci   ImGui::DestroyContext(data->imgui_context);
1830bf215546Sopenharmony_ci}
1831bf215546Sopenharmony_ci
1832bf215546Sopenharmony_cistatic struct overlay_draw *before_present(struct swapchain_data *swapchain_data,
1833bf215546Sopenharmony_ci                                           struct queue_data *present_queue,
1834bf215546Sopenharmony_ci                                           const VkSemaphore *wait_semaphores,
1835bf215546Sopenharmony_ci                                           unsigned n_wait_semaphores,
1836bf215546Sopenharmony_ci                                           unsigned imageIndex)
1837bf215546Sopenharmony_ci{
1838bf215546Sopenharmony_ci   struct instance_data *instance_data = swapchain_data->device->instance;
1839bf215546Sopenharmony_ci   struct overlay_draw *draw = NULL;
1840bf215546Sopenharmony_ci
1841bf215546Sopenharmony_ci   snapshot_swapchain_frame(swapchain_data);
1842bf215546Sopenharmony_ci
1843bf215546Sopenharmony_ci   if (!instance_data->params.no_display && swapchain_data->n_frames > 0) {
1844bf215546Sopenharmony_ci      compute_swapchain_display(swapchain_data);
1845bf215546Sopenharmony_ci      draw = render_swapchain_display(swapchain_data, present_queue,
1846bf215546Sopenharmony_ci                                      wait_semaphores, n_wait_semaphores,
1847bf215546Sopenharmony_ci                                      imageIndex);
1848bf215546Sopenharmony_ci   }
1849bf215546Sopenharmony_ci
1850bf215546Sopenharmony_ci   return draw;
1851bf215546Sopenharmony_ci}
1852bf215546Sopenharmony_ci
1853bf215546Sopenharmony_cistatic VkResult overlay_CreateSwapchainKHR(
1854bf215546Sopenharmony_ci    VkDevice                                    device,
1855bf215546Sopenharmony_ci    const VkSwapchainCreateInfoKHR*             pCreateInfo,
1856bf215546Sopenharmony_ci    const VkAllocationCallbacks*                pAllocator,
1857bf215546Sopenharmony_ci    VkSwapchainKHR*                             pSwapchain)
1858bf215546Sopenharmony_ci{
1859bf215546Sopenharmony_ci   struct device_data *device_data = FIND(struct device_data, device);
1860bf215546Sopenharmony_ci   VkResult result = device_data->vtable.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);
1861bf215546Sopenharmony_ci   if (result != VK_SUCCESS) return result;
1862bf215546Sopenharmony_ci
1863bf215546Sopenharmony_ci   struct swapchain_data *swapchain_data = new_swapchain_data(*pSwapchain, device_data);
1864bf215546Sopenharmony_ci   setup_swapchain_data(swapchain_data, pCreateInfo);
1865bf215546Sopenharmony_ci   return result;
1866bf215546Sopenharmony_ci}
1867bf215546Sopenharmony_ci
1868bf215546Sopenharmony_cistatic void overlay_DestroySwapchainKHR(
1869bf215546Sopenharmony_ci    VkDevice                                    device,
1870bf215546Sopenharmony_ci    VkSwapchainKHR                              swapchain,
1871bf215546Sopenharmony_ci    const VkAllocationCallbacks*                pAllocator)
1872bf215546Sopenharmony_ci{
1873bf215546Sopenharmony_ci   if (swapchain == VK_NULL_HANDLE) {
1874bf215546Sopenharmony_ci      struct device_data *device_data = FIND(struct device_data, device);
1875bf215546Sopenharmony_ci      device_data->vtable.DestroySwapchainKHR(device, swapchain, pAllocator);
1876bf215546Sopenharmony_ci      return;
1877bf215546Sopenharmony_ci   }
1878bf215546Sopenharmony_ci
1879bf215546Sopenharmony_ci   struct swapchain_data *swapchain_data =
1880bf215546Sopenharmony_ci      FIND(struct swapchain_data, swapchain);
1881bf215546Sopenharmony_ci
1882bf215546Sopenharmony_ci   shutdown_swapchain_data(swapchain_data);
1883bf215546Sopenharmony_ci   swapchain_data->device->vtable.DestroySwapchainKHR(device, swapchain, pAllocator);
1884bf215546Sopenharmony_ci   destroy_swapchain_data(swapchain_data);
1885bf215546Sopenharmony_ci}
1886bf215546Sopenharmony_ci
1887bf215546Sopenharmony_cistatic VkResult overlay_QueuePresentKHR(
1888bf215546Sopenharmony_ci    VkQueue                                     queue,
1889bf215546Sopenharmony_ci    const VkPresentInfoKHR*                     pPresentInfo)
1890bf215546Sopenharmony_ci{
1891bf215546Sopenharmony_ci   struct queue_data *queue_data = FIND(struct queue_data, queue);
1892bf215546Sopenharmony_ci   struct device_data *device_data = queue_data->device;
1893bf215546Sopenharmony_ci   struct instance_data *instance_data = device_data->instance;
1894bf215546Sopenharmony_ci   uint32_t query_results[OVERLAY_QUERY_COUNT];
1895bf215546Sopenharmony_ci
1896bf215546Sopenharmony_ci   device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_frame]++;
1897bf215546Sopenharmony_ci
1898bf215546Sopenharmony_ci   if (list_length(&queue_data->running_command_buffer) > 0) {
1899bf215546Sopenharmony_ci      /* Before getting the query results, make sure the operations have
1900bf215546Sopenharmony_ci       * completed.
1901bf215546Sopenharmony_ci       */
1902bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.ResetFences(device_data->device,
1903bf215546Sopenharmony_ci                                               1, &queue_data->queries_fence));
1904bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.QueueSubmit(queue, 0, NULL, queue_data->queries_fence));
1905bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.WaitForFences(device_data->device,
1906bf215546Sopenharmony_ci                                                 1, &queue_data->queries_fence,
1907bf215546Sopenharmony_ci                                                 VK_FALSE, UINT64_MAX));
1908bf215546Sopenharmony_ci
1909bf215546Sopenharmony_ci      /* Now get the results. */
1910bf215546Sopenharmony_ci      list_for_each_entry_safe(struct command_buffer_data, cmd_buffer_data,
1911bf215546Sopenharmony_ci                               &queue_data->running_command_buffer, link) {
1912bf215546Sopenharmony_ci         list_delinit(&cmd_buffer_data->link);
1913bf215546Sopenharmony_ci
1914bf215546Sopenharmony_ci         if (cmd_buffer_data->pipeline_query_pool) {
1915bf215546Sopenharmony_ci            memset(query_results, 0, sizeof(query_results));
1916bf215546Sopenharmony_ci            VK_CHECK(device_data->vtable.GetQueryPoolResults(device_data->device,
1917bf215546Sopenharmony_ci                                                             cmd_buffer_data->pipeline_query_pool,
1918bf215546Sopenharmony_ci                                                             cmd_buffer_data->query_index, 1,
1919bf215546Sopenharmony_ci                                                             sizeof(uint32_t) * OVERLAY_QUERY_COUNT,
1920bf215546Sopenharmony_ci                                                             query_results, 0, VK_QUERY_RESULT_WAIT_BIT));
1921bf215546Sopenharmony_ci
1922bf215546Sopenharmony_ci            for (uint32_t i = OVERLAY_PARAM_ENABLED_vertices;
1923bf215546Sopenharmony_ci                 i <= OVERLAY_PARAM_ENABLED_compute_invocations; i++) {
1924bf215546Sopenharmony_ci               device_data->frame_stats.stats[i] += query_results[i - OVERLAY_PARAM_ENABLED_vertices];
1925bf215546Sopenharmony_ci            }
1926bf215546Sopenharmony_ci         }
1927bf215546Sopenharmony_ci         if (cmd_buffer_data->timestamp_query_pool) {
1928bf215546Sopenharmony_ci            uint64_t gpu_timestamps[2] = { 0 };
1929bf215546Sopenharmony_ci            VK_CHECK(device_data->vtable.GetQueryPoolResults(device_data->device,
1930bf215546Sopenharmony_ci                                                             cmd_buffer_data->timestamp_query_pool,
1931bf215546Sopenharmony_ci                                                             cmd_buffer_data->query_index * 2, 2,
1932bf215546Sopenharmony_ci                                                             2 * sizeof(uint64_t), gpu_timestamps, sizeof(uint64_t),
1933bf215546Sopenharmony_ci                                                             VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT));
1934bf215546Sopenharmony_ci
1935bf215546Sopenharmony_ci            gpu_timestamps[0] &= queue_data->timestamp_mask;
1936bf215546Sopenharmony_ci            gpu_timestamps[1] &= queue_data->timestamp_mask;
1937bf215546Sopenharmony_ci            device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_gpu_timing] +=
1938bf215546Sopenharmony_ci               (gpu_timestamps[1] - gpu_timestamps[0]) *
1939bf215546Sopenharmony_ci               device_data->properties.limits.timestampPeriod;
1940bf215546Sopenharmony_ci         }
1941bf215546Sopenharmony_ci      }
1942bf215546Sopenharmony_ci   }
1943bf215546Sopenharmony_ci
1944bf215546Sopenharmony_ci   /* Otherwise we need to add our overlay drawing semaphore to the list of
1945bf215546Sopenharmony_ci    * semaphores to wait on. If we don't do that the presented picture might
1946bf215546Sopenharmony_ci    * be have incomplete overlay drawings.
1947bf215546Sopenharmony_ci    */
1948bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
1949bf215546Sopenharmony_ci   if (instance_data->params.no_display) {
1950bf215546Sopenharmony_ci      for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
1951bf215546Sopenharmony_ci         VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i];
1952bf215546Sopenharmony_ci         struct swapchain_data *swapchain_data =
1953bf215546Sopenharmony_ci            FIND(struct swapchain_data, swapchain);
1954bf215546Sopenharmony_ci
1955bf215546Sopenharmony_ci         uint32_t image_index = pPresentInfo->pImageIndices[i];
1956bf215546Sopenharmony_ci
1957bf215546Sopenharmony_ci         before_present(swapchain_data,
1958bf215546Sopenharmony_ci                        queue_data,
1959bf215546Sopenharmony_ci                        pPresentInfo->pWaitSemaphores,
1960bf215546Sopenharmony_ci                        pPresentInfo->waitSemaphoreCount,
1961bf215546Sopenharmony_ci                        image_index);
1962bf215546Sopenharmony_ci
1963bf215546Sopenharmony_ci         VkPresentInfoKHR present_info = *pPresentInfo;
1964bf215546Sopenharmony_ci         present_info.swapchainCount = 1;
1965bf215546Sopenharmony_ci         present_info.pSwapchains = &swapchain;
1966bf215546Sopenharmony_ci         present_info.pImageIndices = &image_index;
1967bf215546Sopenharmony_ci
1968bf215546Sopenharmony_ci         uint64_t ts0 = os_time_get();
1969bf215546Sopenharmony_ci         result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info);
1970bf215546Sopenharmony_ci         uint64_t ts1 = os_time_get();
1971bf215546Sopenharmony_ci         swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_present_timing] += ts1 - ts0;
1972bf215546Sopenharmony_ci      }
1973bf215546Sopenharmony_ci   } else {
1974bf215546Sopenharmony_ci      for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
1975bf215546Sopenharmony_ci         VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i];
1976bf215546Sopenharmony_ci         struct swapchain_data *swapchain_data =
1977bf215546Sopenharmony_ci            FIND(struct swapchain_data, swapchain);
1978bf215546Sopenharmony_ci
1979bf215546Sopenharmony_ci         uint32_t image_index = pPresentInfo->pImageIndices[i];
1980bf215546Sopenharmony_ci
1981bf215546Sopenharmony_ci         VkPresentInfoKHR present_info = *pPresentInfo;
1982bf215546Sopenharmony_ci         present_info.swapchainCount = 1;
1983bf215546Sopenharmony_ci         present_info.pSwapchains = &swapchain;
1984bf215546Sopenharmony_ci         present_info.pImageIndices = &image_index;
1985bf215546Sopenharmony_ci
1986bf215546Sopenharmony_ci         struct overlay_draw *draw = before_present(swapchain_data,
1987bf215546Sopenharmony_ci                                                    queue_data,
1988bf215546Sopenharmony_ci                                                    pPresentInfo->pWaitSemaphores,
1989bf215546Sopenharmony_ci                                                    pPresentInfo->waitSemaphoreCount,
1990bf215546Sopenharmony_ci                                                    image_index);
1991bf215546Sopenharmony_ci
1992bf215546Sopenharmony_ci         /* Because the submission of the overlay draw waits on the semaphores
1993bf215546Sopenharmony_ci          * handed for present, we don't need to have this present operation
1994bf215546Sopenharmony_ci          * wait on them as well, we can just wait on the overlay submission
1995bf215546Sopenharmony_ci          * semaphore.
1996bf215546Sopenharmony_ci          */
1997bf215546Sopenharmony_ci         present_info.pWaitSemaphores = &draw->semaphore;
1998bf215546Sopenharmony_ci         present_info.waitSemaphoreCount = 1;
1999bf215546Sopenharmony_ci
2000bf215546Sopenharmony_ci         uint64_t ts0 = os_time_get();
2001bf215546Sopenharmony_ci         VkResult chain_result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info);
2002bf215546Sopenharmony_ci         uint64_t ts1 = os_time_get();
2003bf215546Sopenharmony_ci         swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_present_timing] += ts1 - ts0;
2004bf215546Sopenharmony_ci         if (pPresentInfo->pResults)
2005bf215546Sopenharmony_ci            pPresentInfo->pResults[i] = chain_result;
2006bf215546Sopenharmony_ci         if (chain_result != VK_SUCCESS && result == VK_SUCCESS)
2007bf215546Sopenharmony_ci            result = chain_result;
2008bf215546Sopenharmony_ci      }
2009bf215546Sopenharmony_ci   }
2010bf215546Sopenharmony_ci   return result;
2011bf215546Sopenharmony_ci}
2012bf215546Sopenharmony_ci
2013bf215546Sopenharmony_cistatic VkResult overlay_AcquireNextImageKHR(
2014bf215546Sopenharmony_ci    VkDevice                                    device,
2015bf215546Sopenharmony_ci    VkSwapchainKHR                              swapchain,
2016bf215546Sopenharmony_ci    uint64_t                                    timeout,
2017bf215546Sopenharmony_ci    VkSemaphore                                 semaphore,
2018bf215546Sopenharmony_ci    VkFence                                     fence,
2019bf215546Sopenharmony_ci    uint32_t*                                   pImageIndex)
2020bf215546Sopenharmony_ci{
2021bf215546Sopenharmony_ci   struct swapchain_data *swapchain_data =
2022bf215546Sopenharmony_ci      FIND(struct swapchain_data, swapchain);
2023bf215546Sopenharmony_ci   struct device_data *device_data = swapchain_data->device;
2024bf215546Sopenharmony_ci
2025bf215546Sopenharmony_ci   uint64_t ts0 = os_time_get();
2026bf215546Sopenharmony_ci   VkResult result = device_data->vtable.AcquireNextImageKHR(device, swapchain, timeout,
2027bf215546Sopenharmony_ci                                                             semaphore, fence, pImageIndex);
2028bf215546Sopenharmony_ci   uint64_t ts1 = os_time_get();
2029bf215546Sopenharmony_ci
2030bf215546Sopenharmony_ci   swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire_timing] += ts1 - ts0;
2031bf215546Sopenharmony_ci   swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire]++;
2032bf215546Sopenharmony_ci
2033bf215546Sopenharmony_ci   return result;
2034bf215546Sopenharmony_ci}
2035bf215546Sopenharmony_ci
2036bf215546Sopenharmony_cistatic VkResult overlay_AcquireNextImage2KHR(
2037bf215546Sopenharmony_ci    VkDevice                                    device,
2038bf215546Sopenharmony_ci    const VkAcquireNextImageInfoKHR*            pAcquireInfo,
2039bf215546Sopenharmony_ci    uint32_t*                                   pImageIndex)
2040bf215546Sopenharmony_ci{
2041bf215546Sopenharmony_ci   struct swapchain_data *swapchain_data =
2042bf215546Sopenharmony_ci      FIND(struct swapchain_data, pAcquireInfo->swapchain);
2043bf215546Sopenharmony_ci   struct device_data *device_data = swapchain_data->device;
2044bf215546Sopenharmony_ci
2045bf215546Sopenharmony_ci   uint64_t ts0 = os_time_get();
2046bf215546Sopenharmony_ci   VkResult result = device_data->vtable.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
2047bf215546Sopenharmony_ci   uint64_t ts1 = os_time_get();
2048bf215546Sopenharmony_ci
2049bf215546Sopenharmony_ci   swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire_timing] += ts1 - ts0;
2050bf215546Sopenharmony_ci   swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire]++;
2051bf215546Sopenharmony_ci
2052bf215546Sopenharmony_ci   return result;
2053bf215546Sopenharmony_ci}
2054bf215546Sopenharmony_ci
2055bf215546Sopenharmony_cistatic void overlay_CmdDraw(
2056bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2057bf215546Sopenharmony_ci    uint32_t                                    vertexCount,
2058bf215546Sopenharmony_ci    uint32_t                                    instanceCount,
2059bf215546Sopenharmony_ci    uint32_t                                    firstVertex,
2060bf215546Sopenharmony_ci    uint32_t                                    firstInstance)
2061bf215546Sopenharmony_ci{
2062bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2063bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2064bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw]++;
2065bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2066bf215546Sopenharmony_ci   device_data->vtable.CmdDraw(commandBuffer, vertexCount, instanceCount,
2067bf215546Sopenharmony_ci                               firstVertex, firstInstance);
2068bf215546Sopenharmony_ci}
2069bf215546Sopenharmony_ci
2070bf215546Sopenharmony_cistatic void overlay_CmdDrawIndexed(
2071bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2072bf215546Sopenharmony_ci    uint32_t                                    indexCount,
2073bf215546Sopenharmony_ci    uint32_t                                    instanceCount,
2074bf215546Sopenharmony_ci    uint32_t                                    firstIndex,
2075bf215546Sopenharmony_ci    int32_t                                     vertexOffset,
2076bf215546Sopenharmony_ci    uint32_t                                    firstInstance)
2077bf215546Sopenharmony_ci{
2078bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2079bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2080bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indexed]++;
2081bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2082bf215546Sopenharmony_ci   device_data->vtable.CmdDrawIndexed(commandBuffer, indexCount, instanceCount,
2083bf215546Sopenharmony_ci                                      firstIndex, vertexOffset, firstInstance);
2084bf215546Sopenharmony_ci}
2085bf215546Sopenharmony_ci
2086bf215546Sopenharmony_cistatic void overlay_CmdDrawIndirect(
2087bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2088bf215546Sopenharmony_ci    VkBuffer                                    buffer,
2089bf215546Sopenharmony_ci    VkDeviceSize                                offset,
2090bf215546Sopenharmony_ci    uint32_t                                    drawCount,
2091bf215546Sopenharmony_ci    uint32_t                                    stride)
2092bf215546Sopenharmony_ci{
2093bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2094bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2095bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indirect]++;
2096bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2097bf215546Sopenharmony_ci   device_data->vtable.CmdDrawIndirect(commandBuffer, buffer, offset, drawCount, stride);
2098bf215546Sopenharmony_ci}
2099bf215546Sopenharmony_ci
2100bf215546Sopenharmony_cistatic void overlay_CmdDrawIndexedIndirect(
2101bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2102bf215546Sopenharmony_ci    VkBuffer                                    buffer,
2103bf215546Sopenharmony_ci    VkDeviceSize                                offset,
2104bf215546Sopenharmony_ci    uint32_t                                    drawCount,
2105bf215546Sopenharmony_ci    uint32_t                                    stride)
2106bf215546Sopenharmony_ci{
2107bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2108bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2109bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indexed_indirect]++;
2110bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2111bf215546Sopenharmony_ci   device_data->vtable.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, drawCount, stride);
2112bf215546Sopenharmony_ci}
2113bf215546Sopenharmony_ci
2114bf215546Sopenharmony_cistatic void overlay_CmdDrawIndirectCount(
2115bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2116bf215546Sopenharmony_ci    VkBuffer                                    buffer,
2117bf215546Sopenharmony_ci    VkDeviceSize                                offset,
2118bf215546Sopenharmony_ci    VkBuffer                                    countBuffer,
2119bf215546Sopenharmony_ci    VkDeviceSize                                countBufferOffset,
2120bf215546Sopenharmony_ci    uint32_t                                    maxDrawCount,
2121bf215546Sopenharmony_ci    uint32_t                                    stride)
2122bf215546Sopenharmony_ci{
2123bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2124bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2125bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indirect_count]++;
2126bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2127bf215546Sopenharmony_ci   device_data->vtable.CmdDrawIndirectCount(commandBuffer, buffer, offset,
2128bf215546Sopenharmony_ci                                            countBuffer, countBufferOffset,
2129bf215546Sopenharmony_ci                                            maxDrawCount, stride);
2130bf215546Sopenharmony_ci}
2131bf215546Sopenharmony_ci
2132bf215546Sopenharmony_cistatic void overlay_CmdDrawIndexedIndirectCount(
2133bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2134bf215546Sopenharmony_ci    VkBuffer                                    buffer,
2135bf215546Sopenharmony_ci    VkDeviceSize                                offset,
2136bf215546Sopenharmony_ci    VkBuffer                                    countBuffer,
2137bf215546Sopenharmony_ci    VkDeviceSize                                countBufferOffset,
2138bf215546Sopenharmony_ci    uint32_t                                    maxDrawCount,
2139bf215546Sopenharmony_ci    uint32_t                                    stride)
2140bf215546Sopenharmony_ci{
2141bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2142bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2143bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indexed_indirect_count]++;
2144bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2145bf215546Sopenharmony_ci   device_data->vtable.CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset,
2146bf215546Sopenharmony_ci                                                   countBuffer, countBufferOffset,
2147bf215546Sopenharmony_ci                                                   maxDrawCount, stride);
2148bf215546Sopenharmony_ci}
2149bf215546Sopenharmony_ci
2150bf215546Sopenharmony_cistatic void overlay_CmdDispatch(
2151bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2152bf215546Sopenharmony_ci    uint32_t                                    groupCountX,
2153bf215546Sopenharmony_ci    uint32_t                                    groupCountY,
2154bf215546Sopenharmony_ci    uint32_t                                    groupCountZ)
2155bf215546Sopenharmony_ci{
2156bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2157bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2158bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_dispatch]++;
2159bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2160bf215546Sopenharmony_ci   device_data->vtable.CmdDispatch(commandBuffer, groupCountX, groupCountY, groupCountZ);
2161bf215546Sopenharmony_ci}
2162bf215546Sopenharmony_ci
2163bf215546Sopenharmony_cistatic void overlay_CmdDispatchIndirect(
2164bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2165bf215546Sopenharmony_ci    VkBuffer                                    buffer,
2166bf215546Sopenharmony_ci    VkDeviceSize                                offset)
2167bf215546Sopenharmony_ci{
2168bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2169bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2170bf215546Sopenharmony_ci   cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_dispatch_indirect]++;
2171bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2172bf215546Sopenharmony_ci   device_data->vtable.CmdDispatchIndirect(commandBuffer, buffer, offset);
2173bf215546Sopenharmony_ci}
2174bf215546Sopenharmony_ci
2175bf215546Sopenharmony_cistatic void overlay_CmdBindPipeline(
2176bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2177bf215546Sopenharmony_ci    VkPipelineBindPoint                         pipelineBindPoint,
2178bf215546Sopenharmony_ci    VkPipeline                                  pipeline)
2179bf215546Sopenharmony_ci{
2180bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2181bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2182bf215546Sopenharmony_ci   switch (pipelineBindPoint) {
2183bf215546Sopenharmony_ci   case VK_PIPELINE_BIND_POINT_GRAPHICS: cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_pipeline_graphics]++; break;
2184bf215546Sopenharmony_ci   case VK_PIPELINE_BIND_POINT_COMPUTE: cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_pipeline_compute]++; break;
2185bf215546Sopenharmony_ci   case VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR: cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_pipeline_raytracing]++; break;
2186bf215546Sopenharmony_ci   default: break;
2187bf215546Sopenharmony_ci   }
2188bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2189bf215546Sopenharmony_ci   device_data->vtable.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
2190bf215546Sopenharmony_ci}
2191bf215546Sopenharmony_ci
2192bf215546Sopenharmony_cistatic VkResult overlay_BeginCommandBuffer(
2193bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2194bf215546Sopenharmony_ci    const VkCommandBufferBeginInfo*             pBeginInfo)
2195bf215546Sopenharmony_ci{
2196bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2197bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2198bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2199bf215546Sopenharmony_ci
2200bf215546Sopenharmony_ci   memset(&cmd_buffer_data->stats, 0, sizeof(cmd_buffer_data->stats));
2201bf215546Sopenharmony_ci
2202bf215546Sopenharmony_ci   /* We don't record any query in secondary command buffers, just make sure
2203bf215546Sopenharmony_ci    * we have the right inheritance.
2204bf215546Sopenharmony_ci    */
2205bf215546Sopenharmony_ci   if (cmd_buffer_data->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {
2206bf215546Sopenharmony_ci      VkCommandBufferBeginInfo *begin_info = (VkCommandBufferBeginInfo *)
2207bf215546Sopenharmony_ci         clone_chain((const struct VkBaseInStructure *)pBeginInfo);
2208bf215546Sopenharmony_ci      VkCommandBufferInheritanceInfo *parent_inhe_info = (VkCommandBufferInheritanceInfo *)
2209bf215546Sopenharmony_ci         vk_find_struct(begin_info, COMMAND_BUFFER_INHERITANCE_INFO);
2210bf215546Sopenharmony_ci      VkCommandBufferInheritanceInfo inhe_info = {
2211bf215546Sopenharmony_ci         VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
2212bf215546Sopenharmony_ci         NULL,
2213bf215546Sopenharmony_ci         VK_NULL_HANDLE,
2214bf215546Sopenharmony_ci         0,
2215bf215546Sopenharmony_ci         VK_NULL_HANDLE,
2216bf215546Sopenharmony_ci         VK_FALSE,
2217bf215546Sopenharmony_ci         0,
2218bf215546Sopenharmony_ci         overlay_query_flags,
2219bf215546Sopenharmony_ci      };
2220bf215546Sopenharmony_ci
2221bf215546Sopenharmony_ci      if (parent_inhe_info)
2222bf215546Sopenharmony_ci         parent_inhe_info->pipelineStatistics = overlay_query_flags;
2223bf215546Sopenharmony_ci      else {
2224bf215546Sopenharmony_ci         inhe_info.pNext = begin_info->pNext;
2225bf215546Sopenharmony_ci         begin_info->pNext = &inhe_info;
2226bf215546Sopenharmony_ci      }
2227bf215546Sopenharmony_ci
2228bf215546Sopenharmony_ci      VkResult result = device_data->vtable.BeginCommandBuffer(commandBuffer, pBeginInfo);
2229bf215546Sopenharmony_ci
2230bf215546Sopenharmony_ci      if (!parent_inhe_info)
2231bf215546Sopenharmony_ci         begin_info->pNext = inhe_info.pNext;
2232bf215546Sopenharmony_ci
2233bf215546Sopenharmony_ci      free_chain((struct VkBaseOutStructure *)begin_info);
2234bf215546Sopenharmony_ci
2235bf215546Sopenharmony_ci      return result;
2236bf215546Sopenharmony_ci   }
2237bf215546Sopenharmony_ci
2238bf215546Sopenharmony_ci   /* Otherwise record a begin query as first command. */
2239bf215546Sopenharmony_ci   VkResult result = device_data->vtable.BeginCommandBuffer(commandBuffer, pBeginInfo);
2240bf215546Sopenharmony_ci
2241bf215546Sopenharmony_ci   if (result == VK_SUCCESS) {
2242bf215546Sopenharmony_ci      if (cmd_buffer_data->pipeline_query_pool) {
2243bf215546Sopenharmony_ci         device_data->vtable.CmdResetQueryPool(commandBuffer,
2244bf215546Sopenharmony_ci                                               cmd_buffer_data->pipeline_query_pool,
2245bf215546Sopenharmony_ci                                               cmd_buffer_data->query_index, 1);
2246bf215546Sopenharmony_ci      }
2247bf215546Sopenharmony_ci      if (cmd_buffer_data->timestamp_query_pool) {
2248bf215546Sopenharmony_ci         device_data->vtable.CmdResetQueryPool(commandBuffer,
2249bf215546Sopenharmony_ci                                               cmd_buffer_data->timestamp_query_pool,
2250bf215546Sopenharmony_ci                                               cmd_buffer_data->query_index * 2, 2);
2251bf215546Sopenharmony_ci      }
2252bf215546Sopenharmony_ci      if (cmd_buffer_data->pipeline_query_pool) {
2253bf215546Sopenharmony_ci         device_data->vtable.CmdBeginQuery(commandBuffer,
2254bf215546Sopenharmony_ci                                           cmd_buffer_data->pipeline_query_pool,
2255bf215546Sopenharmony_ci                                           cmd_buffer_data->query_index, 0);
2256bf215546Sopenharmony_ci      }
2257bf215546Sopenharmony_ci      if (cmd_buffer_data->timestamp_query_pool) {
2258bf215546Sopenharmony_ci         device_data->vtable.CmdWriteTimestamp(commandBuffer,
2259bf215546Sopenharmony_ci                                               VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2260bf215546Sopenharmony_ci                                               cmd_buffer_data->timestamp_query_pool,
2261bf215546Sopenharmony_ci                                               cmd_buffer_data->query_index * 2);
2262bf215546Sopenharmony_ci      }
2263bf215546Sopenharmony_ci   }
2264bf215546Sopenharmony_ci
2265bf215546Sopenharmony_ci   return result;
2266bf215546Sopenharmony_ci}
2267bf215546Sopenharmony_ci
2268bf215546Sopenharmony_cistatic VkResult overlay_EndCommandBuffer(
2269bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer)
2270bf215546Sopenharmony_ci{
2271bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2272bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2273bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2274bf215546Sopenharmony_ci
2275bf215546Sopenharmony_ci   if (cmd_buffer_data->timestamp_query_pool) {
2276bf215546Sopenharmony_ci      device_data->vtable.CmdWriteTimestamp(commandBuffer,
2277bf215546Sopenharmony_ci                                            VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2278bf215546Sopenharmony_ci                                            cmd_buffer_data->timestamp_query_pool,
2279bf215546Sopenharmony_ci                                            cmd_buffer_data->query_index * 2 + 1);
2280bf215546Sopenharmony_ci   }
2281bf215546Sopenharmony_ci   if (cmd_buffer_data->pipeline_query_pool) {
2282bf215546Sopenharmony_ci      device_data->vtable.CmdEndQuery(commandBuffer,
2283bf215546Sopenharmony_ci                                      cmd_buffer_data->pipeline_query_pool,
2284bf215546Sopenharmony_ci                                      cmd_buffer_data->query_index);
2285bf215546Sopenharmony_ci   }
2286bf215546Sopenharmony_ci
2287bf215546Sopenharmony_ci   return device_data->vtable.EndCommandBuffer(commandBuffer);
2288bf215546Sopenharmony_ci}
2289bf215546Sopenharmony_ci
2290bf215546Sopenharmony_cistatic VkResult overlay_ResetCommandBuffer(
2291bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2292bf215546Sopenharmony_ci    VkCommandBufferResetFlags                   flags)
2293bf215546Sopenharmony_ci{
2294bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2295bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2296bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2297bf215546Sopenharmony_ci
2298bf215546Sopenharmony_ci   memset(&cmd_buffer_data->stats, 0, sizeof(cmd_buffer_data->stats));
2299bf215546Sopenharmony_ci
2300bf215546Sopenharmony_ci   return device_data->vtable.ResetCommandBuffer(commandBuffer, flags);
2301bf215546Sopenharmony_ci}
2302bf215546Sopenharmony_ci
2303bf215546Sopenharmony_cistatic void overlay_CmdExecuteCommands(
2304bf215546Sopenharmony_ci    VkCommandBuffer                             commandBuffer,
2305bf215546Sopenharmony_ci    uint32_t                                    commandBufferCount,
2306bf215546Sopenharmony_ci    const VkCommandBuffer*                      pCommandBuffers)
2307bf215546Sopenharmony_ci{
2308bf215546Sopenharmony_ci   struct command_buffer_data *cmd_buffer_data =
2309bf215546Sopenharmony_ci      FIND(struct command_buffer_data, commandBuffer);
2310bf215546Sopenharmony_ci   struct device_data *device_data = cmd_buffer_data->device;
2311bf215546Sopenharmony_ci
2312bf215546Sopenharmony_ci   /* Add the stats of the executed command buffers to the primary one. */
2313bf215546Sopenharmony_ci   for (uint32_t c = 0; c < commandBufferCount; c++) {
2314bf215546Sopenharmony_ci      struct command_buffer_data *sec_cmd_buffer_data =
2315bf215546Sopenharmony_ci         FIND(struct command_buffer_data, pCommandBuffers[c]);
2316bf215546Sopenharmony_ci
2317bf215546Sopenharmony_ci      for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++)
2318bf215546Sopenharmony_ci         cmd_buffer_data->stats.stats[s] += sec_cmd_buffer_data->stats.stats[s];
2319bf215546Sopenharmony_ci   }
2320bf215546Sopenharmony_ci
2321bf215546Sopenharmony_ci   device_data->vtable.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);
2322bf215546Sopenharmony_ci}
2323bf215546Sopenharmony_ci
2324bf215546Sopenharmony_cistatic VkResult overlay_AllocateCommandBuffers(
2325bf215546Sopenharmony_ci   VkDevice                           device,
2326bf215546Sopenharmony_ci   const VkCommandBufferAllocateInfo* pAllocateInfo,
2327bf215546Sopenharmony_ci   VkCommandBuffer*                   pCommandBuffers)
2328bf215546Sopenharmony_ci{
2329bf215546Sopenharmony_ci   struct device_data *device_data = FIND(struct device_data, device);
2330bf215546Sopenharmony_ci   VkResult result =
2331bf215546Sopenharmony_ci      device_data->vtable.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);
2332bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
2333bf215546Sopenharmony_ci      return result;
2334bf215546Sopenharmony_ci
2335bf215546Sopenharmony_ci   VkQueryPool pipeline_query_pool = VK_NULL_HANDLE;
2336bf215546Sopenharmony_ci   VkQueryPool timestamp_query_pool = VK_NULL_HANDLE;
2337bf215546Sopenharmony_ci   if (device_data->instance->pipeline_statistics_enabled &&
2338bf215546Sopenharmony_ci       pAllocateInfo->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
2339bf215546Sopenharmony_ci      VkQueryPoolCreateInfo pool_info = {
2340bf215546Sopenharmony_ci         VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
2341bf215546Sopenharmony_ci         NULL,
2342bf215546Sopenharmony_ci         0,
2343bf215546Sopenharmony_ci         VK_QUERY_TYPE_PIPELINE_STATISTICS,
2344bf215546Sopenharmony_ci         pAllocateInfo->commandBufferCount,
2345bf215546Sopenharmony_ci         overlay_query_flags,
2346bf215546Sopenharmony_ci      };
2347bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.CreateQueryPool(device_data->device, &pool_info,
2348bf215546Sopenharmony_ci                                                   NULL, &pipeline_query_pool));
2349bf215546Sopenharmony_ci   }
2350bf215546Sopenharmony_ci   if (device_data->instance->params.enabled[OVERLAY_PARAM_ENABLED_gpu_timing]) {
2351bf215546Sopenharmony_ci      VkQueryPoolCreateInfo pool_info = {
2352bf215546Sopenharmony_ci         VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
2353bf215546Sopenharmony_ci         NULL,
2354bf215546Sopenharmony_ci         0,
2355bf215546Sopenharmony_ci         VK_QUERY_TYPE_TIMESTAMP,
2356bf215546Sopenharmony_ci         pAllocateInfo->commandBufferCount * 2,
2357bf215546Sopenharmony_ci         0,
2358bf215546Sopenharmony_ci      };
2359bf215546Sopenharmony_ci      VK_CHECK(device_data->vtable.CreateQueryPool(device_data->device, &pool_info,
2360bf215546Sopenharmony_ci                                                   NULL, &timestamp_query_pool));
2361bf215546Sopenharmony_ci   }
2362bf215546Sopenharmony_ci
2363bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {
2364bf215546Sopenharmony_ci      new_command_buffer_data(pCommandBuffers[i], pAllocateInfo->level,
2365bf215546Sopenharmony_ci                              pipeline_query_pool, timestamp_query_pool,
2366bf215546Sopenharmony_ci                              i, device_data);
2367bf215546Sopenharmony_ci   }
2368bf215546Sopenharmony_ci
2369bf215546Sopenharmony_ci   if (pipeline_query_pool)
2370bf215546Sopenharmony_ci      map_object(HKEY(pipeline_query_pool), (void *)(uintptr_t) pAllocateInfo->commandBufferCount);
2371bf215546Sopenharmony_ci   if (timestamp_query_pool)
2372bf215546Sopenharmony_ci      map_object(HKEY(timestamp_query_pool), (void *)(uintptr_t) pAllocateInfo->commandBufferCount);
2373bf215546Sopenharmony_ci
2374bf215546Sopenharmony_ci   return result;
2375bf215546Sopenharmony_ci}
2376bf215546Sopenharmony_ci
2377bf215546Sopenharmony_cistatic void overlay_FreeCommandBuffers(
2378bf215546Sopenharmony_ci   VkDevice               device,
2379bf215546Sopenharmony_ci   VkCommandPool          commandPool,
2380bf215546Sopenharmony_ci   uint32_t               commandBufferCount,
2381bf215546Sopenharmony_ci   const VkCommandBuffer* pCommandBuffers)
2382bf215546Sopenharmony_ci{
2383bf215546Sopenharmony_ci   struct device_data *device_data = FIND(struct device_data, device);
2384bf215546Sopenharmony_ci   for (uint32_t i = 0; i < commandBufferCount; i++) {
2385bf215546Sopenharmony_ci      struct command_buffer_data *cmd_buffer_data =
2386bf215546Sopenharmony_ci         FIND(struct command_buffer_data, pCommandBuffers[i]);
2387bf215546Sopenharmony_ci
2388bf215546Sopenharmony_ci      /* It is legal to free a NULL command buffer*/
2389bf215546Sopenharmony_ci      if (!cmd_buffer_data)
2390bf215546Sopenharmony_ci         continue;
2391bf215546Sopenharmony_ci
2392bf215546Sopenharmony_ci      uint64_t count = (uintptr_t)find_object_data(HKEY(cmd_buffer_data->pipeline_query_pool));
2393bf215546Sopenharmony_ci      if (count == 1) {
2394bf215546Sopenharmony_ci         unmap_object(HKEY(cmd_buffer_data->pipeline_query_pool));
2395bf215546Sopenharmony_ci         device_data->vtable.DestroyQueryPool(device_data->device,
2396bf215546Sopenharmony_ci                                              cmd_buffer_data->pipeline_query_pool, NULL);
2397bf215546Sopenharmony_ci      } else if (count != 0) {
2398bf215546Sopenharmony_ci         map_object(HKEY(cmd_buffer_data->pipeline_query_pool), (void *)(uintptr_t)(count - 1));
2399bf215546Sopenharmony_ci      }
2400bf215546Sopenharmony_ci      count = (uintptr_t)find_object_data(HKEY(cmd_buffer_data->timestamp_query_pool));
2401bf215546Sopenharmony_ci      if (count == 1) {
2402bf215546Sopenharmony_ci         unmap_object(HKEY(cmd_buffer_data->timestamp_query_pool));
2403bf215546Sopenharmony_ci         device_data->vtable.DestroyQueryPool(device_data->device,
2404bf215546Sopenharmony_ci                                              cmd_buffer_data->timestamp_query_pool, NULL);
2405bf215546Sopenharmony_ci      } else if (count != 0) {
2406bf215546Sopenharmony_ci         map_object(HKEY(cmd_buffer_data->timestamp_query_pool), (void *)(uintptr_t)(count - 1));
2407bf215546Sopenharmony_ci      }
2408bf215546Sopenharmony_ci      destroy_command_buffer_data(cmd_buffer_data);
2409bf215546Sopenharmony_ci   }
2410bf215546Sopenharmony_ci
2411bf215546Sopenharmony_ci   device_data->vtable.FreeCommandBuffers(device, commandPool,
2412bf215546Sopenharmony_ci                                          commandBufferCount, pCommandBuffers);
2413bf215546Sopenharmony_ci}
2414bf215546Sopenharmony_ci
2415bf215546Sopenharmony_cistatic VkResult overlay_QueueSubmit(
2416bf215546Sopenharmony_ci    VkQueue                                     queue,
2417bf215546Sopenharmony_ci    uint32_t                                    submitCount,
2418bf215546Sopenharmony_ci    const VkSubmitInfo*                         pSubmits,
2419bf215546Sopenharmony_ci    VkFence                                     fence)
2420bf215546Sopenharmony_ci{
2421bf215546Sopenharmony_ci   struct queue_data *queue_data = FIND(struct queue_data, queue);
2422bf215546Sopenharmony_ci   struct device_data *device_data = queue_data->device;
2423bf215546Sopenharmony_ci
2424bf215546Sopenharmony_ci   device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_submit]++;
2425bf215546Sopenharmony_ci
2426bf215546Sopenharmony_ci   for (uint32_t s = 0; s < submitCount; s++) {
2427bf215546Sopenharmony_ci      for (uint32_t c = 0; c < pSubmits[s].commandBufferCount; c++) {
2428bf215546Sopenharmony_ci         struct command_buffer_data *cmd_buffer_data =
2429bf215546Sopenharmony_ci            FIND(struct command_buffer_data, pSubmits[s].pCommandBuffers[c]);
2430bf215546Sopenharmony_ci
2431bf215546Sopenharmony_ci         /* Merge the submitted command buffer stats into the device. */
2432bf215546Sopenharmony_ci         for (uint32_t st = 0; st < OVERLAY_PARAM_ENABLED_MAX; st++)
2433bf215546Sopenharmony_ci            device_data->frame_stats.stats[st] += cmd_buffer_data->stats.stats[st];
2434bf215546Sopenharmony_ci
2435bf215546Sopenharmony_ci         /* Attach the command buffer to the queue so we remember to read its
2436bf215546Sopenharmony_ci          * pipeline statistics & timestamps at QueuePresent().
2437bf215546Sopenharmony_ci          */
2438bf215546Sopenharmony_ci         if (!cmd_buffer_data->pipeline_query_pool &&
2439bf215546Sopenharmony_ci             !cmd_buffer_data->timestamp_query_pool)
2440bf215546Sopenharmony_ci            continue;
2441bf215546Sopenharmony_ci
2442bf215546Sopenharmony_ci         if (list_is_empty(&cmd_buffer_data->link)) {
2443bf215546Sopenharmony_ci            list_addtail(&cmd_buffer_data->link,
2444bf215546Sopenharmony_ci                         &queue_data->running_command_buffer);
2445bf215546Sopenharmony_ci         } else {
2446bf215546Sopenharmony_ci            fprintf(stderr, "Command buffer submitted multiple times before present.\n"
2447bf215546Sopenharmony_ci                    "This could lead to invalid data.\n");
2448bf215546Sopenharmony_ci         }
2449bf215546Sopenharmony_ci      }
2450bf215546Sopenharmony_ci   }
2451bf215546Sopenharmony_ci
2452bf215546Sopenharmony_ci   return device_data->vtable.QueueSubmit(queue, submitCount, pSubmits, fence);
2453bf215546Sopenharmony_ci}
2454bf215546Sopenharmony_ci
2455bf215546Sopenharmony_cistatic VkResult overlay_QueueSubmit2KHR(
2456bf215546Sopenharmony_ci    VkQueue                                     queue,
2457bf215546Sopenharmony_ci    uint32_t                                    submitCount,
2458bf215546Sopenharmony_ci    const VkSubmitInfo2*                        pSubmits,
2459bf215546Sopenharmony_ci    VkFence                                     fence)
2460bf215546Sopenharmony_ci{
2461bf215546Sopenharmony_ci   struct queue_data *queue_data = FIND(struct queue_data, queue);
2462bf215546Sopenharmony_ci   struct device_data *device_data = queue_data->device;
2463bf215546Sopenharmony_ci
2464bf215546Sopenharmony_ci   device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_submit]++;
2465bf215546Sopenharmony_ci
2466bf215546Sopenharmony_ci   for (uint32_t s = 0; s < submitCount; s++) {
2467bf215546Sopenharmony_ci      for (uint32_t c = 0; c < pSubmits[s].commandBufferInfoCount; c++) {
2468bf215546Sopenharmony_ci         struct command_buffer_data *cmd_buffer_data =
2469bf215546Sopenharmony_ci            FIND(struct command_buffer_data, pSubmits[s].pCommandBufferInfos[c].commandBuffer);
2470bf215546Sopenharmony_ci
2471bf215546Sopenharmony_ci         /* Merge the submitted command buffer stats into the device. */
2472bf215546Sopenharmony_ci         for (uint32_t st = 0; st < OVERLAY_PARAM_ENABLED_MAX; st++)
2473bf215546Sopenharmony_ci            device_data->frame_stats.stats[st] += cmd_buffer_data->stats.stats[st];
2474bf215546Sopenharmony_ci
2475bf215546Sopenharmony_ci         /* Attach the command buffer to the queue so we remember to read its
2476bf215546Sopenharmony_ci         * pipeline statistics & timestamps at QueuePresent().
2477bf215546Sopenharmony_ci         */
2478bf215546Sopenharmony_ci         if (!cmd_buffer_data->pipeline_query_pool &&
2479bf215546Sopenharmony_ci            !cmd_buffer_data->timestamp_query_pool)
2480bf215546Sopenharmony_ci            continue;
2481bf215546Sopenharmony_ci
2482bf215546Sopenharmony_ci         if (list_is_empty(&cmd_buffer_data->link)) {
2483bf215546Sopenharmony_ci            list_addtail(&cmd_buffer_data->link,
2484bf215546Sopenharmony_ci                        &queue_data->running_command_buffer);
2485bf215546Sopenharmony_ci         } else {
2486bf215546Sopenharmony_ci            fprintf(stderr, "Command buffer submitted multiple times before present.\n"
2487bf215546Sopenharmony_ci                  "This could lead to invalid data.\n");
2488bf215546Sopenharmony_ci         }
2489bf215546Sopenharmony_ci      }
2490bf215546Sopenharmony_ci   }
2491bf215546Sopenharmony_ci
2492bf215546Sopenharmony_ci   return device_data->vtable.QueueSubmit2KHR(queue, submitCount, pSubmits, fence);
2493bf215546Sopenharmony_ci}
2494bf215546Sopenharmony_ci
2495bf215546Sopenharmony_cistatic VkResult overlay_CreateDevice(
2496bf215546Sopenharmony_ci    VkPhysicalDevice                            physicalDevice,
2497bf215546Sopenharmony_ci    const VkDeviceCreateInfo*                   pCreateInfo,
2498bf215546Sopenharmony_ci    const VkAllocationCallbacks*                pAllocator,
2499bf215546Sopenharmony_ci    VkDevice*                                   pDevice)
2500bf215546Sopenharmony_ci{
2501bf215546Sopenharmony_ci   struct instance_data *instance_data =
2502bf215546Sopenharmony_ci      FIND(struct instance_data, physicalDevice);
2503bf215546Sopenharmony_ci   VkLayerDeviceCreateInfo *chain_info =
2504bf215546Sopenharmony_ci      get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
2505bf215546Sopenharmony_ci
2506bf215546Sopenharmony_ci   assert(chain_info->u.pLayerInfo);
2507bf215546Sopenharmony_ci   PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
2508bf215546Sopenharmony_ci   PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
2509bf215546Sopenharmony_ci   PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");
2510bf215546Sopenharmony_ci   if (fpCreateDevice == NULL) {
2511bf215546Sopenharmony_ci      return VK_ERROR_INITIALIZATION_FAILED;
2512bf215546Sopenharmony_ci   }
2513bf215546Sopenharmony_ci
2514bf215546Sopenharmony_ci   // Advance the link info for the next element on the chain
2515bf215546Sopenharmony_ci   chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
2516bf215546Sopenharmony_ci
2517bf215546Sopenharmony_ci   VkPhysicalDeviceFeatures device_features = {};
2518bf215546Sopenharmony_ci   VkPhysicalDeviceFeatures *device_features_ptr = NULL;
2519bf215546Sopenharmony_ci
2520bf215546Sopenharmony_ci   VkDeviceCreateInfo *device_info = (VkDeviceCreateInfo *)
2521bf215546Sopenharmony_ci      clone_chain((const struct VkBaseInStructure *)pCreateInfo);
2522bf215546Sopenharmony_ci
2523bf215546Sopenharmony_ci   VkPhysicalDeviceFeatures2 *device_features2 = (VkPhysicalDeviceFeatures2 *)
2524bf215546Sopenharmony_ci      vk_find_struct(device_info, PHYSICAL_DEVICE_FEATURES_2);
2525bf215546Sopenharmony_ci   if (device_features2) {
2526bf215546Sopenharmony_ci      /* Can't use device_info->pEnabledFeatures when VkPhysicalDeviceFeatures2 is present */
2527bf215546Sopenharmony_ci      device_features_ptr = &device_features2->features;
2528bf215546Sopenharmony_ci   } else {
2529bf215546Sopenharmony_ci      if (device_info->pEnabledFeatures)
2530bf215546Sopenharmony_ci         device_features = *(device_info->pEnabledFeatures);
2531bf215546Sopenharmony_ci      device_features_ptr = &device_features;
2532bf215546Sopenharmony_ci      device_info->pEnabledFeatures = &device_features;
2533bf215546Sopenharmony_ci   }
2534bf215546Sopenharmony_ci
2535bf215546Sopenharmony_ci   if (instance_data->pipeline_statistics_enabled) {
2536bf215546Sopenharmony_ci      device_features_ptr->inheritedQueries = true;
2537bf215546Sopenharmony_ci      device_features_ptr->pipelineStatisticsQuery = true;
2538bf215546Sopenharmony_ci   }
2539bf215546Sopenharmony_ci
2540bf215546Sopenharmony_ci
2541bf215546Sopenharmony_ci   VkResult result = fpCreateDevice(physicalDevice, device_info, pAllocator, pDevice);
2542bf215546Sopenharmony_ci   free_chain((struct VkBaseOutStructure *)device_info);
2543bf215546Sopenharmony_ci   if (result != VK_SUCCESS) return result;
2544bf215546Sopenharmony_ci
2545bf215546Sopenharmony_ci   struct device_data *device_data = new_device_data(*pDevice, instance_data);
2546bf215546Sopenharmony_ci   device_data->physical_device = physicalDevice;
2547bf215546Sopenharmony_ci   vk_device_dispatch_table_load(&device_data->vtable,
2548bf215546Sopenharmony_ci                                 fpGetDeviceProcAddr, *pDevice);
2549bf215546Sopenharmony_ci
2550bf215546Sopenharmony_ci   instance_data->pd_vtable.GetPhysicalDeviceProperties(device_data->physical_device,
2551bf215546Sopenharmony_ci                                                        &device_data->properties);
2552bf215546Sopenharmony_ci
2553bf215546Sopenharmony_ci   VkLayerDeviceCreateInfo *load_data_info =
2554bf215546Sopenharmony_ci      get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);
2555bf215546Sopenharmony_ci   device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;
2556bf215546Sopenharmony_ci
2557bf215546Sopenharmony_ci   device_map_queues(device_data, pCreateInfo);
2558bf215546Sopenharmony_ci
2559bf215546Sopenharmony_ci   return result;
2560bf215546Sopenharmony_ci}
2561bf215546Sopenharmony_ci
2562bf215546Sopenharmony_cistatic void overlay_DestroyDevice(
2563bf215546Sopenharmony_ci    VkDevice                                    device,
2564bf215546Sopenharmony_ci    const VkAllocationCallbacks*                pAllocator)
2565bf215546Sopenharmony_ci{
2566bf215546Sopenharmony_ci   struct device_data *device_data = FIND(struct device_data, device);
2567bf215546Sopenharmony_ci   device_unmap_queues(device_data);
2568bf215546Sopenharmony_ci   device_data->vtable.DestroyDevice(device, pAllocator);
2569bf215546Sopenharmony_ci   destroy_device_data(device_data);
2570bf215546Sopenharmony_ci}
2571bf215546Sopenharmony_ci
2572bf215546Sopenharmony_cistatic VkResult overlay_CreateInstance(
2573bf215546Sopenharmony_ci    const VkInstanceCreateInfo*                 pCreateInfo,
2574bf215546Sopenharmony_ci    const VkAllocationCallbacks*                pAllocator,
2575bf215546Sopenharmony_ci    VkInstance*                                 pInstance)
2576bf215546Sopenharmony_ci{
2577bf215546Sopenharmony_ci   VkLayerInstanceCreateInfo *chain_info =
2578bf215546Sopenharmony_ci      get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
2579bf215546Sopenharmony_ci
2580bf215546Sopenharmony_ci   assert(chain_info->u.pLayerInfo);
2581bf215546Sopenharmony_ci   PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =
2582bf215546Sopenharmony_ci      chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
2583bf215546Sopenharmony_ci   PFN_vkCreateInstance fpCreateInstance =
2584bf215546Sopenharmony_ci      (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
2585bf215546Sopenharmony_ci   if (fpCreateInstance == NULL) {
2586bf215546Sopenharmony_ci      return VK_ERROR_INITIALIZATION_FAILED;
2587bf215546Sopenharmony_ci   }
2588bf215546Sopenharmony_ci
2589bf215546Sopenharmony_ci   // Advance the link info for the next element on the chain
2590bf215546Sopenharmony_ci   chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
2591bf215546Sopenharmony_ci
2592bf215546Sopenharmony_ci   VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
2593bf215546Sopenharmony_ci   if (result != VK_SUCCESS) return result;
2594bf215546Sopenharmony_ci
2595bf215546Sopenharmony_ci   struct instance_data *instance_data = new_instance_data(*pInstance);
2596bf215546Sopenharmony_ci   vk_instance_dispatch_table_load(&instance_data->vtable,
2597bf215546Sopenharmony_ci                                   fpGetInstanceProcAddr,
2598bf215546Sopenharmony_ci                                   instance_data->instance);
2599bf215546Sopenharmony_ci   vk_physical_device_dispatch_table_load(&instance_data->pd_vtable,
2600bf215546Sopenharmony_ci                                          fpGetInstanceProcAddr,
2601bf215546Sopenharmony_ci                                          instance_data->instance);
2602bf215546Sopenharmony_ci   instance_data_map_physical_devices(instance_data, true);
2603bf215546Sopenharmony_ci
2604bf215546Sopenharmony_ci   parse_overlay_env(&instance_data->params, getenv("VK_LAYER_MESA_OVERLAY_CONFIG"));
2605bf215546Sopenharmony_ci
2606bf215546Sopenharmony_ci   /* If there's no control file, and an output_file was specified, start
2607bf215546Sopenharmony_ci    * capturing fps data right away.
2608bf215546Sopenharmony_ci    */
2609bf215546Sopenharmony_ci   instance_data->capture_enabled =
2610bf215546Sopenharmony_ci      instance_data->params.output_file && instance_data->params.control < 0;
2611bf215546Sopenharmony_ci   instance_data->capture_started = instance_data->capture_enabled;
2612bf215546Sopenharmony_ci
2613bf215546Sopenharmony_ci   for (int i = OVERLAY_PARAM_ENABLED_vertices;
2614bf215546Sopenharmony_ci        i <= OVERLAY_PARAM_ENABLED_compute_invocations; i++) {
2615bf215546Sopenharmony_ci      if (instance_data->params.enabled[i]) {
2616bf215546Sopenharmony_ci         instance_data->pipeline_statistics_enabled = true;
2617bf215546Sopenharmony_ci         break;
2618bf215546Sopenharmony_ci      }
2619bf215546Sopenharmony_ci   }
2620bf215546Sopenharmony_ci
2621bf215546Sopenharmony_ci   return result;
2622bf215546Sopenharmony_ci}
2623bf215546Sopenharmony_ci
2624bf215546Sopenharmony_cistatic void overlay_DestroyInstance(
2625bf215546Sopenharmony_ci    VkInstance                                  instance,
2626bf215546Sopenharmony_ci    const VkAllocationCallbacks*                pAllocator)
2627bf215546Sopenharmony_ci{
2628bf215546Sopenharmony_ci   struct instance_data *instance_data = FIND(struct instance_data, instance);
2629bf215546Sopenharmony_ci   instance_data_map_physical_devices(instance_data, false);
2630bf215546Sopenharmony_ci   instance_data->vtable.DestroyInstance(instance, pAllocator);
2631bf215546Sopenharmony_ci   destroy_instance_data(instance_data);
2632bf215546Sopenharmony_ci}
2633bf215546Sopenharmony_ci
2634bf215546Sopenharmony_cistatic const struct {
2635bf215546Sopenharmony_ci   const char *name;
2636bf215546Sopenharmony_ci   void *ptr;
2637bf215546Sopenharmony_ci} name_to_funcptr_map[] = {
2638bf215546Sopenharmony_ci   { "vkGetInstanceProcAddr", (void *) vkGetInstanceProcAddr },
2639bf215546Sopenharmony_ci   { "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr },
2640bf215546Sopenharmony_ci#define ADD_HOOK(fn) { "vk" # fn, (void *) overlay_ ## fn }
2641bf215546Sopenharmony_ci#define ADD_ALIAS_HOOK(alias, fn) { "vk" # alias, (void *) overlay_ ## fn }
2642bf215546Sopenharmony_ci   ADD_HOOK(AllocateCommandBuffers),
2643bf215546Sopenharmony_ci   ADD_HOOK(FreeCommandBuffers),
2644bf215546Sopenharmony_ci   ADD_HOOK(ResetCommandBuffer),
2645bf215546Sopenharmony_ci   ADD_HOOK(BeginCommandBuffer),
2646bf215546Sopenharmony_ci   ADD_HOOK(EndCommandBuffer),
2647bf215546Sopenharmony_ci   ADD_HOOK(CmdExecuteCommands),
2648bf215546Sopenharmony_ci
2649bf215546Sopenharmony_ci   ADD_HOOK(CmdDraw),
2650bf215546Sopenharmony_ci   ADD_HOOK(CmdDrawIndexed),
2651bf215546Sopenharmony_ci   ADD_HOOK(CmdDrawIndirect),
2652bf215546Sopenharmony_ci   ADD_HOOK(CmdDrawIndexedIndirect),
2653bf215546Sopenharmony_ci   ADD_HOOK(CmdDispatch),
2654bf215546Sopenharmony_ci   ADD_HOOK(CmdDispatchIndirect),
2655bf215546Sopenharmony_ci   ADD_HOOK(CmdDrawIndirectCount),
2656bf215546Sopenharmony_ci   ADD_ALIAS_HOOK(CmdDrawIndirectCountKHR, CmdDrawIndirectCount),
2657bf215546Sopenharmony_ci   ADD_HOOK(CmdDrawIndexedIndirectCount),
2658bf215546Sopenharmony_ci   ADD_ALIAS_HOOK(CmdDrawIndexedIndirectCountKHR, CmdDrawIndexedIndirectCount),
2659bf215546Sopenharmony_ci
2660bf215546Sopenharmony_ci   ADD_HOOK(CmdBindPipeline),
2661bf215546Sopenharmony_ci
2662bf215546Sopenharmony_ci   ADD_HOOK(CreateSwapchainKHR),
2663bf215546Sopenharmony_ci   ADD_HOOK(QueuePresentKHR),
2664bf215546Sopenharmony_ci   ADD_HOOK(DestroySwapchainKHR),
2665bf215546Sopenharmony_ci   ADD_HOOK(AcquireNextImageKHR),
2666bf215546Sopenharmony_ci   ADD_HOOK(AcquireNextImage2KHR),
2667bf215546Sopenharmony_ci
2668bf215546Sopenharmony_ci   ADD_HOOK(QueueSubmit),
2669bf215546Sopenharmony_ci   ADD_HOOK(QueueSubmit2KHR),
2670bf215546Sopenharmony_ci
2671bf215546Sopenharmony_ci   ADD_HOOK(CreateDevice),
2672bf215546Sopenharmony_ci   ADD_HOOK(DestroyDevice),
2673bf215546Sopenharmony_ci
2674bf215546Sopenharmony_ci   ADD_HOOK(CreateInstance),
2675bf215546Sopenharmony_ci   ADD_HOOK(DestroyInstance),
2676bf215546Sopenharmony_ci#undef ADD_HOOK
2677bf215546Sopenharmony_ci#undef ADD_ALIAS_HOOK
2678bf215546Sopenharmony_ci};
2679bf215546Sopenharmony_ci
2680bf215546Sopenharmony_cistatic void *find_ptr(const char *name)
2681bf215546Sopenharmony_ci{
2682bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {
2683bf215546Sopenharmony_ci      if (strcmp(name, name_to_funcptr_map[i].name) == 0)
2684bf215546Sopenharmony_ci         return name_to_funcptr_map[i].ptr;
2685bf215546Sopenharmony_ci   }
2686bf215546Sopenharmony_ci
2687bf215546Sopenharmony_ci   return NULL;
2688bf215546Sopenharmony_ci}
2689bf215546Sopenharmony_ci
2690bf215546Sopenharmony_ciVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev,
2691bf215546Sopenharmony_ci                                                                             const char *funcName)
2692bf215546Sopenharmony_ci{
2693bf215546Sopenharmony_ci   void *ptr = find_ptr(funcName);
2694bf215546Sopenharmony_ci   if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);
2695bf215546Sopenharmony_ci
2696bf215546Sopenharmony_ci   if (dev == NULL) return NULL;
2697bf215546Sopenharmony_ci
2698bf215546Sopenharmony_ci   struct device_data *device_data = FIND(struct device_data, dev);
2699bf215546Sopenharmony_ci   if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;
2700bf215546Sopenharmony_ci   return device_data->vtable.GetDeviceProcAddr(dev, funcName);
2701bf215546Sopenharmony_ci}
2702bf215546Sopenharmony_ci
2703bf215546Sopenharmony_ciVK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,
2704bf215546Sopenharmony_ci                                                                               const char *funcName)
2705bf215546Sopenharmony_ci{
2706bf215546Sopenharmony_ci   void *ptr = find_ptr(funcName);
2707bf215546Sopenharmony_ci   if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);
2708bf215546Sopenharmony_ci
2709bf215546Sopenharmony_ci   if (instance == NULL) return NULL;
2710bf215546Sopenharmony_ci
2711bf215546Sopenharmony_ci   struct instance_data *instance_data = FIND(struct instance_data, instance);
2712bf215546Sopenharmony_ci   if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;
2713bf215546Sopenharmony_ci   return instance_data->vtable.GetInstanceProcAddr(instance, funcName);
2714bf215546Sopenharmony_ci}
2715