Path: blob/21.2-virgl/src/vulkan/overlay-layer/overlay.cpp
7137 views
/*1* Copyright © 2019 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <string.h>24#include <stdlib.h>25#include <assert.h>2627#include <vulkan/vulkan.h>28#include <vulkan/vk_layer.h>2930#include "git_sha1.h"3132#include "imgui.h"3334#include "overlay_params.h"3536#include "util/debug.h"37#include "util/hash_table.h"38#include "util/list.h"39#include "util/ralloc.h"40#include "util/os_time.h"41#include "util/os_socket.h"42#include "util/simple_mtx.h"4344#include "vk_enum_to_str.h"45#include "vk_dispatch_table.h"46#include "vk_util.h"4748/* Mapped from VkInstace/VkPhysicalDevice */49struct instance_data {50struct vk_instance_dispatch_table vtable;51struct vk_physical_device_dispatch_table pd_vtable;52VkInstance instance;5354struct overlay_params params;55bool pipeline_statistics_enabled;5657bool first_line_printed;5859int control_client;6061/* Dumping of frame stats to a file has been enabled. */62bool capture_enabled;6364/* Dumping of frame stats to a file has been enabled and started. */65bool capture_started;66};6768struct frame_stat {69uint64_t stats[OVERLAY_PARAM_ENABLED_MAX];70};7172/* Mapped from VkDevice */73struct queue_data;74struct device_data {75struct instance_data *instance;7677PFN_vkSetDeviceLoaderData set_device_loader_data;7879struct vk_device_dispatch_table vtable;80VkPhysicalDevice physical_device;81VkDevice device;8283VkPhysicalDeviceProperties properties;8485struct queue_data *graphic_queue;8687struct queue_data **queues;88uint32_t n_queues;8990/* For a single frame */91struct frame_stat frame_stats;92};9394/* Mapped from VkCommandBuffer */95struct command_buffer_data {96struct device_data *device;9798VkCommandBufferLevel level;99100VkCommandBuffer cmd_buffer;101VkQueryPool pipeline_query_pool;102VkQueryPool timestamp_query_pool;103uint32_t query_index;104105struct frame_stat stats;106107struct list_head link; /* link into queue_data::running_command_buffer */108};109110/* Mapped from VkQueue */111struct queue_data {112struct device_data *device;113114VkQueue queue;115VkQueueFlags flags;116uint32_t family_index;117uint64_t timestamp_mask;118119VkFence queries_fence;120121struct list_head running_command_buffer;122};123124struct overlay_draw {125struct list_head link;126127VkCommandBuffer command_buffer;128129VkSemaphore cross_engine_semaphore;130131VkSemaphore semaphore;132VkFence fence;133134VkBuffer vertex_buffer;135VkDeviceMemory vertex_buffer_mem;136VkDeviceSize vertex_buffer_size;137138VkBuffer index_buffer;139VkDeviceMemory index_buffer_mem;140VkDeviceSize index_buffer_size;141};142143/* Mapped from VkSwapchainKHR */144struct swapchain_data {145struct device_data *device;146147VkSwapchainKHR swapchain;148unsigned width, height;149VkFormat format;150151uint32_t n_images;152VkImage *images;153VkImageView *image_views;154VkFramebuffer *framebuffers;155156VkRenderPass render_pass;157158VkDescriptorPool descriptor_pool;159VkDescriptorSetLayout descriptor_layout;160VkDescriptorSet descriptor_set;161162VkSampler font_sampler;163164VkPipelineLayout pipeline_layout;165VkPipeline pipeline;166167VkCommandPool command_pool;168169struct list_head draws; /* List of struct overlay_draw */170171bool font_uploaded;172VkImage font_image;173VkImageView font_image_view;174VkDeviceMemory font_mem;175VkBuffer upload_font_buffer;176VkDeviceMemory upload_font_buffer_mem;177178/**/179ImGuiContext* imgui_context;180ImVec2 window_size;181182/**/183uint64_t n_frames;184uint64_t last_present_time;185186unsigned n_frames_since_update;187uint64_t last_fps_update;188double fps;189190enum overlay_param_enabled stat_selector;191double time_dividor;192struct frame_stat stats_min, stats_max;193struct frame_stat frames_stats[200];194195/* Over a single frame */196struct frame_stat frame_stats;197198/* Over fps_sampling_period */199struct frame_stat accumulated_stats;200};201202static const VkQueryPipelineStatisticFlags overlay_query_flags =203VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT |204VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT |205VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT |206VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT |207VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT |208VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT |209VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT |210VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT |211VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT |212VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT |213VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;214#define OVERLAY_QUERY_COUNT (11)215216static struct hash_table_u64 *vk_object_to_data = NULL;217static simple_mtx_t vk_object_to_data_mutex = _SIMPLE_MTX_INITIALIZER_NP;218219thread_local ImGuiContext* __MesaImGui;220221static inline void ensure_vk_object_map(void)222{223if (!vk_object_to_data)224vk_object_to_data = _mesa_hash_table_u64_create(NULL);225}226227#define HKEY(obj) ((uint64_t)(obj))228#define FIND(type, obj) ((type *)find_object_data(HKEY(obj)))229230static void *find_object_data(uint64_t obj)231{232simple_mtx_lock(&vk_object_to_data_mutex);233ensure_vk_object_map();234void *data = _mesa_hash_table_u64_search(vk_object_to_data, obj);235simple_mtx_unlock(&vk_object_to_data_mutex);236return data;237}238239static void map_object(uint64_t obj, void *data)240{241simple_mtx_lock(&vk_object_to_data_mutex);242ensure_vk_object_map();243_mesa_hash_table_u64_insert(vk_object_to_data, obj, data);244simple_mtx_unlock(&vk_object_to_data_mutex);245}246247static void unmap_object(uint64_t obj)248{249simple_mtx_lock(&vk_object_to_data_mutex);250_mesa_hash_table_u64_remove(vk_object_to_data, obj);251simple_mtx_unlock(&vk_object_to_data_mutex);252}253254/**/255256#define VK_CHECK(expr) \257do { \258VkResult __result = (expr); \259if (__result != VK_SUCCESS) { \260fprintf(stderr, "'%s' line %i failed with %s\n", \261#expr, __LINE__, vk_Result_to_str(__result)); \262} \263} while (0)264265/**/266267static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,268VkLayerFunction func)269{270vk_foreach_struct(item, pCreateInfo->pNext) {271if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&272((VkLayerInstanceCreateInfo *) item)->function == func)273return (VkLayerInstanceCreateInfo *) item;274}275unreachable("instance chain info not found");276return NULL;277}278279static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,280VkLayerFunction func)281{282vk_foreach_struct(item, pCreateInfo->pNext) {283if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&284((VkLayerDeviceCreateInfo *) item)->function == func)285return (VkLayerDeviceCreateInfo *)item;286}287unreachable("device chain info not found");288return NULL;289}290291static struct VkBaseOutStructure *292clone_chain(const struct VkBaseInStructure *chain)293{294struct VkBaseOutStructure *head = NULL, *tail = NULL;295296vk_foreach_struct_const(item, chain) {297size_t item_size = vk_structure_type_size(item);298struct VkBaseOutStructure *new_item =299(struct VkBaseOutStructure *)malloc(item_size);;300301memcpy(new_item, item, item_size);302303if (!head)304head = new_item;305if (tail)306tail->pNext = new_item;307tail = new_item;308}309310return head;311}312313static void314free_chain(struct VkBaseOutStructure *chain)315{316while (chain) {317void *node = chain;318chain = chain->pNext;319free(node);320}321}322323/**/324325static struct instance_data *new_instance_data(VkInstance instance)326{327struct instance_data *data = rzalloc(NULL, struct instance_data);328data->instance = instance;329data->control_client = -1;330map_object(HKEY(data->instance), data);331return data;332}333334static void destroy_instance_data(struct instance_data *data)335{336if (data->params.output_file)337fclose(data->params.output_file);338if (data->params.control >= 0)339os_socket_close(data->params.control);340unmap_object(HKEY(data->instance));341ralloc_free(data);342}343344static void instance_data_map_physical_devices(struct instance_data *instance_data,345bool map)346{347uint32_t physicalDeviceCount = 0;348instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,349&physicalDeviceCount,350NULL);351352VkPhysicalDevice *physicalDevices = (VkPhysicalDevice *) malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);353instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,354&physicalDeviceCount,355physicalDevices);356357for (uint32_t i = 0; i < physicalDeviceCount; i++) {358if (map)359map_object(HKEY(physicalDevices[i]), instance_data);360else361unmap_object(HKEY(physicalDevices[i]));362}363364free(physicalDevices);365}366367/**/368static struct device_data *new_device_data(VkDevice device, struct instance_data *instance)369{370struct device_data *data = rzalloc(NULL, struct device_data);371data->instance = instance;372data->device = device;373map_object(HKEY(data->device), data);374return data;375}376377static struct queue_data *new_queue_data(VkQueue queue,378const VkQueueFamilyProperties *family_props,379uint32_t family_index,380struct device_data *device_data)381{382struct queue_data *data = rzalloc(device_data, struct queue_data);383data->device = device_data;384data->queue = queue;385data->flags = family_props->queueFlags;386data->timestamp_mask = (1ull << family_props->timestampValidBits) - 1;387data->family_index = family_index;388list_inithead(&data->running_command_buffer);389map_object(HKEY(data->queue), data);390391/* Fence synchronizing access to queries on that queue. */392VkFenceCreateInfo fence_info = {};393fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;394fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;395VK_CHECK(device_data->vtable.CreateFence(device_data->device,396&fence_info,397NULL,398&data->queries_fence));399400if (data->flags & VK_QUEUE_GRAPHICS_BIT)401device_data->graphic_queue = data;402403return data;404}405406static void destroy_queue(struct queue_data *data)407{408struct device_data *device_data = data->device;409device_data->vtable.DestroyFence(device_data->device, data->queries_fence, NULL);410unmap_object(HKEY(data->queue));411ralloc_free(data);412}413414static void device_map_queues(struct device_data *data,415const VkDeviceCreateInfo *pCreateInfo)416{417for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)418data->n_queues += pCreateInfo->pQueueCreateInfos[i].queueCount;419data->queues = ralloc_array(data, struct queue_data *, data->n_queues);420421struct instance_data *instance_data = data->instance;422uint32_t n_family_props;423instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device,424&n_family_props,425NULL);426VkQueueFamilyProperties *family_props =427(VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) * n_family_props);428instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device,429&n_family_props,430family_props);431432uint32_t queue_index = 0;433for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {434for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {435VkQueue queue;436data->vtable.GetDeviceQueue(data->device,437pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,438j, &queue);439440VK_CHECK(data->set_device_loader_data(data->device, queue));441442data->queues[queue_index++] =443new_queue_data(queue, &family_props[pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex],444pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, data);445}446}447448free(family_props);449}450451static void device_unmap_queues(struct device_data *data)452{453for (uint32_t i = 0; i < data->n_queues; i++)454destroy_queue(data->queues[i]);455}456457static void destroy_device_data(struct device_data *data)458{459unmap_object(HKEY(data->device));460ralloc_free(data);461}462463/**/464static struct command_buffer_data *new_command_buffer_data(VkCommandBuffer cmd_buffer,465VkCommandBufferLevel level,466VkQueryPool pipeline_query_pool,467VkQueryPool timestamp_query_pool,468uint32_t query_index,469struct device_data *device_data)470{471struct command_buffer_data *data = rzalloc(NULL, struct command_buffer_data);472data->device = device_data;473data->cmd_buffer = cmd_buffer;474data->level = level;475data->pipeline_query_pool = pipeline_query_pool;476data->timestamp_query_pool = timestamp_query_pool;477data->query_index = query_index;478list_inithead(&data->link);479map_object(HKEY(data->cmd_buffer), data);480return data;481}482483static void destroy_command_buffer_data(struct command_buffer_data *data)484{485unmap_object(HKEY(data->cmd_buffer));486list_delinit(&data->link);487ralloc_free(data);488}489490/**/491static struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain,492struct device_data *device_data)493{494struct instance_data *instance_data = device_data->instance;495struct swapchain_data *data = rzalloc(NULL, struct swapchain_data);496data->device = device_data;497data->swapchain = swapchain;498data->window_size = ImVec2(instance_data->params.width, instance_data->params.height);499list_inithead(&data->draws);500map_object(HKEY(data->swapchain), data);501return data;502}503504static void destroy_swapchain_data(struct swapchain_data *data)505{506unmap_object(HKEY(data->swapchain));507ralloc_free(data);508}509510struct overlay_draw *get_overlay_draw(struct swapchain_data *data)511{512struct device_data *device_data = data->device;513struct overlay_draw *draw = list_is_empty(&data->draws) ?514NULL : list_first_entry(&data->draws, struct overlay_draw, link);515516VkSemaphoreCreateInfo sem_info = {};517sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;518519if (draw && device_data->vtable.GetFenceStatus(device_data->device, draw->fence) == VK_SUCCESS) {520list_del(&draw->link);521VK_CHECK(device_data->vtable.ResetFences(device_data->device,5221, &draw->fence));523list_addtail(&draw->link, &data->draws);524return draw;525}526527draw = rzalloc(data, struct overlay_draw);528529VkCommandBufferAllocateInfo cmd_buffer_info = {};530cmd_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;531cmd_buffer_info.commandPool = data->command_pool;532cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;533cmd_buffer_info.commandBufferCount = 1;534VK_CHECK(device_data->vtable.AllocateCommandBuffers(device_data->device,535&cmd_buffer_info,536&draw->command_buffer));537VK_CHECK(device_data->set_device_loader_data(device_data->device,538draw->command_buffer));539540541VkFenceCreateInfo fence_info = {};542fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;543VK_CHECK(device_data->vtable.CreateFence(device_data->device,544&fence_info,545NULL,546&draw->fence));547548VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,549NULL, &draw->semaphore));550VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,551NULL, &draw->cross_engine_semaphore));552553list_addtail(&draw->link, &data->draws);554555return draw;556}557558static const char *param_unit(enum overlay_param_enabled param)559{560switch (param) {561case OVERLAY_PARAM_ENABLED_frame_timing:562case OVERLAY_PARAM_ENABLED_acquire_timing:563case OVERLAY_PARAM_ENABLED_present_timing:564return "(us)";565case OVERLAY_PARAM_ENABLED_gpu_timing:566return "(ns)";567default:568return "";569}570}571572static void parse_command(struct instance_data *instance_data,573const char *cmd, unsigned cmdlen,574const char *param, unsigned paramlen)575{576if (!strncmp(cmd, "capture", cmdlen)) {577int value = atoi(param);578bool enabled = value > 0;579580if (enabled) {581instance_data->capture_enabled = true;582} else {583instance_data->capture_enabled = false;584instance_data->capture_started = false;585}586}587}588589#define BUFSIZE 4096590591/**592* This function will process commands through the control file.593*594* A command starts with a colon, followed by the command, and followed by an595* option '=' and a parameter. It has to end with a semi-colon. A full command596* + parameter looks like:597*598* :cmd=param;599*/600static void process_char(struct instance_data *instance_data, char c)601{602static char cmd[BUFSIZE];603static char param[BUFSIZE];604605static unsigned cmdpos = 0;606static unsigned parampos = 0;607static bool reading_cmd = false;608static bool reading_param = false;609610switch (c) {611case ':':612cmdpos = 0;613parampos = 0;614reading_cmd = true;615reading_param = false;616break;617case ';':618if (!reading_cmd)619break;620cmd[cmdpos++] = '\0';621param[parampos++] = '\0';622parse_command(instance_data, cmd, cmdpos, param, parampos);623reading_cmd = false;624reading_param = false;625break;626case '=':627if (!reading_cmd)628break;629reading_param = true;630break;631default:632if (!reading_cmd)633break;634635if (reading_param) {636/* overflow means an invalid parameter */637if (parampos >= BUFSIZE - 1) {638reading_cmd = false;639reading_param = false;640break;641}642643param[parampos++] = c;644} else {645/* overflow means an invalid command */646if (cmdpos >= BUFSIZE - 1) {647reading_cmd = false;648break;649}650651cmd[cmdpos++] = c;652}653}654}655656static void control_send(struct instance_data *instance_data,657const char *cmd, unsigned cmdlen,658const char *param, unsigned paramlen)659{660unsigned msglen = 0;661char buffer[BUFSIZE];662663assert(cmdlen + paramlen + 3 < BUFSIZE);664665buffer[msglen++] = ':';666667memcpy(&buffer[msglen], cmd, cmdlen);668msglen += cmdlen;669670if (paramlen > 0) {671buffer[msglen++] = '=';672memcpy(&buffer[msglen], param, paramlen);673msglen += paramlen;674buffer[msglen++] = ';';675}676677os_socket_send(instance_data->control_client, buffer, msglen, 0);678}679680static void control_send_connection_string(struct device_data *device_data)681{682struct instance_data *instance_data = device_data->instance;683684const char *controlVersionCmd = "MesaOverlayControlVersion";685const char *controlVersionString = "1";686687control_send(instance_data, controlVersionCmd, strlen(controlVersionCmd),688controlVersionString, strlen(controlVersionString));689690const char *deviceCmd = "DeviceName";691const char *deviceName = device_data->properties.deviceName;692693control_send(instance_data, deviceCmd, strlen(deviceCmd),694deviceName, strlen(deviceName));695696const char *mesaVersionCmd = "MesaVersion";697const char *mesaVersionString = "Mesa " PACKAGE_VERSION MESA_GIT_SHA1;698699control_send(instance_data, mesaVersionCmd, strlen(mesaVersionCmd),700mesaVersionString, strlen(mesaVersionString));701}702703static void control_client_check(struct device_data *device_data)704{705struct instance_data *instance_data = device_data->instance;706707/* Already connected, just return. */708if (instance_data->control_client >= 0)709return;710711int socket = os_socket_accept(instance_data->params.control);712if (socket == -1) {713if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED)714fprintf(stderr, "ERROR on socket: %s\n", strerror(errno));715return;716}717718if (socket >= 0) {719os_socket_block(socket, false);720instance_data->control_client = socket;721control_send_connection_string(device_data);722}723}724725static void control_client_disconnected(struct instance_data *instance_data)726{727os_socket_close(instance_data->control_client);728instance_data->control_client = -1;729}730731static void process_control_socket(struct instance_data *instance_data)732{733const int client = instance_data->control_client;734if (client >= 0) {735char buf[BUFSIZE];736737while (true) {738ssize_t n = os_socket_recv(client, buf, BUFSIZE, 0);739740if (n == -1) {741if (errno == EAGAIN || errno == EWOULDBLOCK) {742/* nothing to read, try again later */743break;744}745746if (errno != ECONNRESET)747fprintf(stderr, "ERROR on connection: %s\n", strerror(errno));748749control_client_disconnected(instance_data);750} else if (n == 0) {751/* recv() returns 0 when the client disconnects */752control_client_disconnected(instance_data);753}754755for (ssize_t i = 0; i < n; i++) {756process_char(instance_data, buf[i]);757}758759/* If we try to read BUFSIZE and receive BUFSIZE bytes from the760* socket, there's a good chance that there's still more data to be761* read, so we will try again. Otherwise, simply be done for this762* iteration and try again on the next frame.763*/764if (n < BUFSIZE)765break;766}767}768}769770static void snapshot_swapchain_frame(struct swapchain_data *data)771{772struct device_data *device_data = data->device;773struct instance_data *instance_data = device_data->instance;774uint32_t f_idx = data->n_frames % ARRAY_SIZE(data->frames_stats);775uint64_t now = os_time_get(); /* us */776777if (instance_data->params.control >= 0) {778control_client_check(device_data);779process_control_socket(instance_data);780}781782if (data->last_present_time) {783data->frame_stats.stats[OVERLAY_PARAM_ENABLED_frame_timing] =784now - data->last_present_time;785}786787memset(&data->frames_stats[f_idx], 0, sizeof(data->frames_stats[f_idx]));788for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {789data->frames_stats[f_idx].stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];790data->accumulated_stats.stats[s] += device_data->frame_stats.stats[s] + data->frame_stats.stats[s];791}792793/* If capture has been enabled but it hasn't started yet, it means we are on794* the first snapshot after it has been enabled. At this point we want to795* use the stats captured so far to update the display, but we don't want796* this data to cause noise to the stats that we want to capture from now797* on.798*799* capture_begin == true will trigger an update of the fps on display, and a800* flush of the data, but no stats will be written to the output file. This801* way, we will have only stats from after the capture has been enabled802* written to the output_file.803*/804const bool capture_begin =805instance_data->capture_enabled && !instance_data->capture_started;806807if (data->last_fps_update) {808double elapsed = (double)(now - data->last_fps_update); /* us */809if (capture_begin ||810elapsed >= instance_data->params.fps_sampling_period) {811data->fps = 1000000.0f * data->n_frames_since_update / elapsed;812if (instance_data->capture_started) {813if (!instance_data->first_line_printed) {814bool first_column = true;815816instance_data->first_line_printed = true;817818#define OVERLAY_PARAM_BOOL(name) \819if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_##name]) { \820fprintf(instance_data->params.output_file, \821"%s%s%s", first_column ? "" : ", ", #name, \822param_unit(OVERLAY_PARAM_ENABLED_##name)); \823first_column = false; \824}825#define OVERLAY_PARAM_CUSTOM(name)826OVERLAY_PARAMS827#undef OVERLAY_PARAM_BOOL828#undef OVERLAY_PARAM_CUSTOM829fprintf(instance_data->params.output_file, "\n");830}831832for (int s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {833if (!instance_data->params.enabled[s])834continue;835if (s == OVERLAY_PARAM_ENABLED_fps) {836fprintf(instance_data->params.output_file,837"%s%.2f", s == 0 ? "" : ", ", data->fps);838} else {839fprintf(instance_data->params.output_file,840"%s%" PRIu64, s == 0 ? "" : ", ",841data->accumulated_stats.stats[s]);842}843}844fprintf(instance_data->params.output_file, "\n");845fflush(instance_data->params.output_file);846}847848memset(&data->accumulated_stats, 0, sizeof(data->accumulated_stats));849data->n_frames_since_update = 0;850data->last_fps_update = now;851852if (capture_begin)853instance_data->capture_started = true;854}855} else {856data->last_fps_update = now;857}858859memset(&device_data->frame_stats, 0, sizeof(device_data->frame_stats));860memset(&data->frame_stats, 0, sizeof(device_data->frame_stats));861862data->last_present_time = now;863data->n_frames++;864data->n_frames_since_update++;865}866867static float get_time_stat(void *_data, int _idx)868{869struct swapchain_data *data = (struct swapchain_data *) _data;870if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames)871return 0.0f;872int idx = ARRAY_SIZE(data->frames_stats) +873data->n_frames < ARRAY_SIZE(data->frames_stats) ?874_idx - data->n_frames :875_idx + data->n_frames;876idx %= ARRAY_SIZE(data->frames_stats);877/* Time stats are in us. */878return data->frames_stats[idx].stats[data->stat_selector] / data->time_dividor;879}880881static float get_stat(void *_data, int _idx)882{883struct swapchain_data *data = (struct swapchain_data *) _data;884if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames)885return 0.0f;886int idx = ARRAY_SIZE(data->frames_stats) +887data->n_frames < ARRAY_SIZE(data->frames_stats) ?888_idx - data->n_frames :889_idx + data->n_frames;890idx %= ARRAY_SIZE(data->frames_stats);891return data->frames_stats[idx].stats[data->stat_selector];892}893894static void position_layer(struct swapchain_data *data)895896{897struct device_data *device_data = data->device;898struct instance_data *instance_data = device_data->instance;899const float margin = 10.0f;900901ImGui::SetNextWindowBgAlpha(0.5);902ImGui::SetNextWindowSize(data->window_size, ImGuiCond_Always);903switch (instance_data->params.position) {904case LAYER_POSITION_TOP_LEFT:905ImGui::SetNextWindowPos(ImVec2(margin, margin), ImGuiCond_Always);906break;907case LAYER_POSITION_TOP_RIGHT:908ImGui::SetNextWindowPos(ImVec2(data->width - data->window_size.x - margin, margin),909ImGuiCond_Always);910break;911case LAYER_POSITION_BOTTOM_LEFT:912ImGui::SetNextWindowPos(ImVec2(margin, data->height - data->window_size.y - margin),913ImGuiCond_Always);914break;915case LAYER_POSITION_BOTTOM_RIGHT:916ImGui::SetNextWindowPos(ImVec2(data->width - data->window_size.x - margin,917data->height - data->window_size.y - margin),918ImGuiCond_Always);919break;920}921}922923static void compute_swapchain_display(struct swapchain_data *data)924{925struct device_data *device_data = data->device;926struct instance_data *instance_data = device_data->instance;927928ImGui::SetCurrentContext(data->imgui_context);929ImGui::NewFrame();930position_layer(data);931ImGui::Begin("Mesa overlay");932if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_device])933ImGui::Text("Device: %s", device_data->properties.deviceName);934935if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_format]) {936const char *format_name = vk_Format_to_str(data->format);937format_name = format_name ? (format_name + strlen("VK_FORMAT_")) : "unknown";938ImGui::Text("Swapchain format: %s", format_name);939}940if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_frame])941ImGui::Text("Frames: %" PRIu64, data->n_frames);942if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_fps])943ImGui::Text("FPS: %.2f" , data->fps);944945/* Recompute min/max */946for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {947data->stats_min.stats[s] = UINT64_MAX;948data->stats_max.stats[s] = 0;949}950for (uint32_t f = 0; f < MIN2(data->n_frames, ARRAY_SIZE(data->frames_stats)); f++) {951for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {952data->stats_min.stats[s] = MIN2(data->frames_stats[f].stats[s],953data->stats_min.stats[s]);954data->stats_max.stats[s] = MAX2(data->frames_stats[f].stats[s],955data->stats_max.stats[s]);956}957}958for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {959assert(data->stats_min.stats[s] != UINT64_MAX);960}961962for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++) {963if (!instance_data->params.enabled[s] ||964s == OVERLAY_PARAM_ENABLED_fps ||965s == OVERLAY_PARAM_ENABLED_frame)966continue;967968char hash[40];969snprintf(hash, sizeof(hash), "##%s", overlay_param_names[s]);970data->stat_selector = (enum overlay_param_enabled) s;971data->time_dividor = 1000.0f;972if (s == OVERLAY_PARAM_ENABLED_gpu_timing)973data->time_dividor = 1000000.0f;974975if (s == OVERLAY_PARAM_ENABLED_frame_timing ||976s == OVERLAY_PARAM_ENABLED_acquire_timing ||977s == OVERLAY_PARAM_ENABLED_present_timing ||978s == OVERLAY_PARAM_ENABLED_gpu_timing) {979double min_time = data->stats_min.stats[s] / data->time_dividor;980double max_time = data->stats_max.stats[s] / data->time_dividor;981ImGui::PlotHistogram(hash, get_time_stat, data,982ARRAY_SIZE(data->frames_stats), 0,983NULL, min_time, max_time,984ImVec2(ImGui::GetContentRegionAvailWidth(), 30));985ImGui::Text("%s: %.3fms [%.3f, %.3f]", overlay_param_names[s],986get_time_stat(data, ARRAY_SIZE(data->frames_stats) - 1),987min_time, max_time);988} else {989ImGui::PlotHistogram(hash, get_stat, data,990ARRAY_SIZE(data->frames_stats), 0,991NULL,992data->stats_min.stats[s],993data->stats_max.stats[s],994ImVec2(ImGui::GetContentRegionAvailWidth(), 30));995ImGui::Text("%s: %.0f [%" PRIu64 ", %" PRIu64 "]", overlay_param_names[s],996get_stat(data, ARRAY_SIZE(data->frames_stats) - 1),997data->stats_min.stats[s], data->stats_max.stats[s]);998}999}1000data->window_size = ImVec2(data->window_size.x, ImGui::GetCursorPosY() + 10.0f);1001ImGui::End();1002ImGui::EndFrame();1003ImGui::Render();1004}10051006static uint32_t vk_memory_type(struct device_data *data,1007VkMemoryPropertyFlags properties,1008uint32_t type_bits)1009{1010VkPhysicalDeviceMemoryProperties prop;1011data->instance->pd_vtable.GetPhysicalDeviceMemoryProperties(data->physical_device, &prop);1012for (uint32_t i = 0; i < prop.memoryTypeCount; i++)1013if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<<i))1014return i;1015return 0xFFFFFFFF; // Unable to find memoryType1016}10171018static void ensure_swapchain_fonts(struct swapchain_data *data,1019VkCommandBuffer command_buffer)1020{1021if (data->font_uploaded)1022return;10231024data->font_uploaded = true;10251026struct device_data *device_data = data->device;1027ImGuiIO& io = ImGui::GetIO();1028unsigned char* pixels;1029int width, height;1030io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);1031size_t upload_size = width * height * 4 * sizeof(char);10321033/* Upload buffer */1034VkBufferCreateInfo buffer_info = {};1035buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;1036buffer_info.size = upload_size;1037buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;1038buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;1039VK_CHECK(device_data->vtable.CreateBuffer(device_data->device, &buffer_info,1040NULL, &data->upload_font_buffer));1041VkMemoryRequirements upload_buffer_req;1042device_data->vtable.GetBufferMemoryRequirements(device_data->device,1043data->upload_font_buffer,1044&upload_buffer_req);1045VkMemoryAllocateInfo upload_alloc_info = {};1046upload_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;1047upload_alloc_info.allocationSize = upload_buffer_req.size;1048upload_alloc_info.memoryTypeIndex = vk_memory_type(device_data,1049VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,1050upload_buffer_req.memoryTypeBits);1051VK_CHECK(device_data->vtable.AllocateMemory(device_data->device,1052&upload_alloc_info,1053NULL,1054&data->upload_font_buffer_mem));1055VK_CHECK(device_data->vtable.BindBufferMemory(device_data->device,1056data->upload_font_buffer,1057data->upload_font_buffer_mem, 0));10581059/* Upload to Buffer */1060char* map = NULL;1061VK_CHECK(device_data->vtable.MapMemory(device_data->device,1062data->upload_font_buffer_mem,10630, upload_size, 0, (void**)(&map)));1064memcpy(map, pixels, upload_size);1065VkMappedMemoryRange range[1] = {};1066range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;1067range[0].memory = data->upload_font_buffer_mem;1068range[0].size = upload_size;1069VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 1, range));1070device_data->vtable.UnmapMemory(device_data->device,1071data->upload_font_buffer_mem);10721073/* Copy buffer to image */1074VkImageMemoryBarrier copy_barrier[1] = {};1075copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;1076copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;1077copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;1078copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;1079copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;1080copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;1081copy_barrier[0].image = data->font_image;1082copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1083copy_barrier[0].subresourceRange.levelCount = 1;1084copy_barrier[0].subresourceRange.layerCount = 1;1085device_data->vtable.CmdPipelineBarrier(command_buffer,1086VK_PIPELINE_STAGE_HOST_BIT,1087VK_PIPELINE_STAGE_TRANSFER_BIT,10880, 0, NULL, 0, NULL,10891, copy_barrier);10901091VkBufferImageCopy region = {};1092region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1093region.imageSubresource.layerCount = 1;1094region.imageExtent.width = width;1095region.imageExtent.height = height;1096region.imageExtent.depth = 1;1097device_data->vtable.CmdCopyBufferToImage(command_buffer,1098data->upload_font_buffer,1099data->font_image,1100VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,11011, ®ion);11021103VkImageMemoryBarrier use_barrier[1] = {};1104use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;1105use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;1106use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;1107use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;1108use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;1109use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;1110use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;1111use_barrier[0].image = data->font_image;1112use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1113use_barrier[0].subresourceRange.levelCount = 1;1114use_barrier[0].subresourceRange.layerCount = 1;1115device_data->vtable.CmdPipelineBarrier(command_buffer,1116VK_PIPELINE_STAGE_TRANSFER_BIT,1117VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,11180,11190, NULL,11200, NULL,11211, use_barrier);11221123/* Store our identifier */1124io.Fonts->TexID = (ImTextureID)(intptr_t)data->font_image;1125}11261127static void CreateOrResizeBuffer(struct device_data *data,1128VkBuffer *buffer,1129VkDeviceMemory *buffer_memory,1130VkDeviceSize *buffer_size,1131size_t new_size, VkBufferUsageFlagBits usage)1132{1133if (*buffer != VK_NULL_HANDLE)1134data->vtable.DestroyBuffer(data->device, *buffer, NULL);1135if (*buffer_memory)1136data->vtable.FreeMemory(data->device, *buffer_memory, NULL);11371138VkBufferCreateInfo buffer_info = {};1139buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;1140buffer_info.size = new_size;1141buffer_info.usage = usage;1142buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;1143VK_CHECK(data->vtable.CreateBuffer(data->device, &buffer_info, NULL, buffer));11441145VkMemoryRequirements req;1146data->vtable.GetBufferMemoryRequirements(data->device, *buffer, &req);1147VkMemoryAllocateInfo alloc_info = {};1148alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;1149alloc_info.allocationSize = req.size;1150alloc_info.memoryTypeIndex =1151vk_memory_type(data, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);1152VK_CHECK(data->vtable.AllocateMemory(data->device, &alloc_info, NULL, buffer_memory));11531154VK_CHECK(data->vtable.BindBufferMemory(data->device, *buffer, *buffer_memory, 0));1155*buffer_size = new_size;1156}11571158static struct overlay_draw *render_swapchain_display(struct swapchain_data *data,1159struct queue_data *present_queue,1160const VkSemaphore *wait_semaphores,1161unsigned n_wait_semaphores,1162unsigned image_index)1163{1164ImDrawData* draw_data = ImGui::GetDrawData();1165if (draw_data->TotalVtxCount == 0)1166return NULL;11671168struct device_data *device_data = data->device;1169struct overlay_draw *draw = get_overlay_draw(data);11701171device_data->vtable.ResetCommandBuffer(draw->command_buffer, 0);11721173VkRenderPassBeginInfo render_pass_info = {};1174render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;1175render_pass_info.renderPass = data->render_pass;1176render_pass_info.framebuffer = data->framebuffers[image_index];1177render_pass_info.renderArea.extent.width = data->width;1178render_pass_info.renderArea.extent.height = data->height;11791180VkCommandBufferBeginInfo buffer_begin_info = {};1181buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;11821183device_data->vtable.BeginCommandBuffer(draw->command_buffer, &buffer_begin_info);11841185ensure_swapchain_fonts(data, draw->command_buffer);11861187/* Bounce the image to display back to color attachment layout for1188* rendering on top of it.1189*/1190VkImageMemoryBarrier imb;1191imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;1192imb.pNext = nullptr;1193imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;1194imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;1195imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;1196imb.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;1197imb.image = data->images[image_index];1198imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1199imb.subresourceRange.baseMipLevel = 0;1200imb.subresourceRange.levelCount = 1;1201imb.subresourceRange.baseArrayLayer = 0;1202imb.subresourceRange.layerCount = 1;1203imb.srcQueueFamilyIndex = present_queue->family_index;1204imb.dstQueueFamilyIndex = device_data->graphic_queue->family_index;1205device_data->vtable.CmdPipelineBarrier(draw->command_buffer,1206VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,1207VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,12080, /* dependency flags */12090, nullptr, /* memory barriers */12100, nullptr, /* buffer memory barriers */12111, &imb); /* image memory barriers */12121213device_data->vtable.CmdBeginRenderPass(draw->command_buffer, &render_pass_info,1214VK_SUBPASS_CONTENTS_INLINE);12151216/* Create/Resize vertex & index buffers */1217size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);1218size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);1219if (draw->vertex_buffer_size < vertex_size) {1220CreateOrResizeBuffer(device_data,1221&draw->vertex_buffer,1222&draw->vertex_buffer_mem,1223&draw->vertex_buffer_size,1224vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);1225}1226if (draw->index_buffer_size < index_size) {1227CreateOrResizeBuffer(device_data,1228&draw->index_buffer,1229&draw->index_buffer_mem,1230&draw->index_buffer_size,1231index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);1232}12331234/* Upload vertex & index data */1235ImDrawVert* vtx_dst = NULL;1236ImDrawIdx* idx_dst = NULL;1237VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->vertex_buffer_mem,12380, vertex_size, 0, (void**)(&vtx_dst)));1239VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->index_buffer_mem,12400, index_size, 0, (void**)(&idx_dst)));1241for (int n = 0; n < draw_data->CmdListsCount; n++)1242{1243const ImDrawList* cmd_list = draw_data->CmdLists[n];1244memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));1245memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));1246vtx_dst += cmd_list->VtxBuffer.Size;1247idx_dst += cmd_list->IdxBuffer.Size;1248}1249VkMappedMemoryRange range[2] = {};1250range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;1251range[0].memory = draw->vertex_buffer_mem;1252range[0].size = VK_WHOLE_SIZE;1253range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;1254range[1].memory = draw->index_buffer_mem;1255range[1].size = VK_WHOLE_SIZE;1256VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 2, range));1257device_data->vtable.UnmapMemory(device_data->device, draw->vertex_buffer_mem);1258device_data->vtable.UnmapMemory(device_data->device, draw->index_buffer_mem);12591260/* Bind pipeline and descriptor sets */1261device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline);1262VkDescriptorSet desc_set[1] = { data->descriptor_set };1263device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,1264data->pipeline_layout, 0, 1, desc_set, 0, NULL);12651266/* Bind vertex & index buffers */1267VkBuffer vertex_buffers[1] = { draw->vertex_buffer };1268VkDeviceSize vertex_offset[1] = { 0 };1269device_data->vtable.CmdBindVertexBuffers(draw->command_buffer, 0, 1, vertex_buffers, vertex_offset);1270device_data->vtable.CmdBindIndexBuffer(draw->command_buffer, draw->index_buffer, 0, VK_INDEX_TYPE_UINT16);12711272/* Setup viewport */1273VkViewport viewport;1274viewport.x = 0;1275viewport.y = 0;1276viewport.width = draw_data->DisplaySize.x;1277viewport.height = draw_data->DisplaySize.y;1278viewport.minDepth = 0.0f;1279viewport.maxDepth = 1.0f;1280device_data->vtable.CmdSetViewport(draw->command_buffer, 0, 1, &viewport);128112821283/* Setup scale and translation through push constants :1284*1285* Our visible imgui space lies from draw_data->DisplayPos (top left) to1286* draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin1287* is typically (0,0) for single viewport apps.1288*/1289float scale[2];1290scale[0] = 2.0f / draw_data->DisplaySize.x;1291scale[1] = 2.0f / draw_data->DisplaySize.y;1292float translate[2];1293translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];1294translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];1295device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,1296VK_SHADER_STAGE_VERTEX_BIT,1297sizeof(float) * 0, sizeof(float) * 2, scale);1298device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,1299VK_SHADER_STAGE_VERTEX_BIT,1300sizeof(float) * 2, sizeof(float) * 2, translate);13011302// Render the command lists:1303int vtx_offset = 0;1304int idx_offset = 0;1305ImVec2 display_pos = draw_data->DisplayPos;1306for (int n = 0; n < draw_data->CmdListsCount; n++)1307{1308const ImDrawList* cmd_list = draw_data->CmdLists[n];1309for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)1310{1311const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];1312// Apply scissor/clipping rectangle1313// FIXME: We could clamp width/height based on clamped min/max values.1314VkRect2D scissor;1315scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0;1316scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0;1317scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);1318scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?1319device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor);13201321// Draw1322device_data->vtable.CmdDrawIndexed(draw->command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);13231324idx_offset += pcmd->ElemCount;1325}1326vtx_offset += cmd_list->VtxBuffer.Size;1327}13281329device_data->vtable.CmdEndRenderPass(draw->command_buffer);13301331if (device_data->graphic_queue->family_index != present_queue->family_index)1332{1333/* Transfer the image back to the present queue family1334* image layout was already changed to present by the render pass1335*/1336imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;1337imb.pNext = nullptr;1338imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;1339imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;1340imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;1341imb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;1342imb.image = data->images[image_index];1343imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1344imb.subresourceRange.baseMipLevel = 0;1345imb.subresourceRange.levelCount = 1;1346imb.subresourceRange.baseArrayLayer = 0;1347imb.subresourceRange.layerCount = 1;1348imb.srcQueueFamilyIndex = device_data->graphic_queue->family_index;1349imb.dstQueueFamilyIndex = present_queue->family_index;1350device_data->vtable.CmdPipelineBarrier(draw->command_buffer,1351VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,1352VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,13530, /* dependency flags */13540, nullptr, /* memory barriers */13550, nullptr, /* buffer memory barriers */13561, &imb); /* image memory barriers */1357}13581359device_data->vtable.EndCommandBuffer(draw->command_buffer);13601361/* When presenting on a different queue than where we're drawing the1362* overlay *AND* when the application does not provide a semaphore to1363* vkQueuePresent, insert our own cross engine synchronization1364* semaphore.1365*/1366if (n_wait_semaphores == 0 && device_data->graphic_queue->queue != present_queue->queue) {1367VkPipelineStageFlags stages_wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;1368VkSubmitInfo submit_info = {};1369submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;1370submit_info.commandBufferCount = 0;1371submit_info.pWaitDstStageMask = &stages_wait;1372submit_info.waitSemaphoreCount = 0;1373submit_info.signalSemaphoreCount = 1;1374submit_info.pSignalSemaphores = &draw->cross_engine_semaphore;13751376device_data->vtable.QueueSubmit(present_queue->queue, 1, &submit_info, VK_NULL_HANDLE);13771378submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;1379submit_info.commandBufferCount = 1;1380submit_info.pWaitDstStageMask = &stages_wait;1381submit_info.pCommandBuffers = &draw->command_buffer;1382submit_info.waitSemaphoreCount = 1;1383submit_info.pWaitSemaphores = &draw->cross_engine_semaphore;1384submit_info.signalSemaphoreCount = 1;1385submit_info.pSignalSemaphores = &draw->semaphore;13861387device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);1388} else {1389VkPipelineStageFlags *stages_wait = (VkPipelineStageFlags*) malloc(sizeof(VkPipelineStageFlags) * n_wait_semaphores);1390for (unsigned i = 0; i < n_wait_semaphores; i++)1391{1392// wait in the fragment stage until the swapchain image is ready1393stages_wait[i] = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;1394}13951396VkSubmitInfo submit_info = {};1397submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;1398submit_info.commandBufferCount = 1;1399submit_info.pCommandBuffers = &draw->command_buffer;1400submit_info.pWaitDstStageMask = stages_wait;1401submit_info.waitSemaphoreCount = n_wait_semaphores;1402submit_info.pWaitSemaphores = wait_semaphores;1403submit_info.signalSemaphoreCount = 1;1404submit_info.pSignalSemaphores = &draw->semaphore;14051406device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);14071408free(stages_wait);1409}14101411return draw;1412}14131414static const uint32_t overlay_vert_spv[] = {1415#include "overlay.vert.spv.h"1416};1417static const uint32_t overlay_frag_spv[] = {1418#include "overlay.frag.spv.h"1419};14201421static void setup_swapchain_data_pipeline(struct swapchain_data *data)1422{1423struct device_data *device_data = data->device;1424VkShaderModule vert_module, frag_module;14251426/* Create shader modules */1427VkShaderModuleCreateInfo vert_info = {};1428vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;1429vert_info.codeSize = sizeof(overlay_vert_spv);1430vert_info.pCode = overlay_vert_spv;1431VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device,1432&vert_info, NULL, &vert_module));1433VkShaderModuleCreateInfo frag_info = {};1434frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;1435frag_info.codeSize = sizeof(overlay_frag_spv);1436frag_info.pCode = (uint32_t*)overlay_frag_spv;1437VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device,1438&frag_info, NULL, &frag_module));14391440/* Font sampler */1441VkSamplerCreateInfo sampler_info = {};1442sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;1443sampler_info.magFilter = VK_FILTER_LINEAR;1444sampler_info.minFilter = VK_FILTER_LINEAR;1445sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;1446sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;1447sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;1448sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;1449sampler_info.minLod = -1000;1450sampler_info.maxLod = 1000;1451sampler_info.maxAnisotropy = 1.0f;1452VK_CHECK(device_data->vtable.CreateSampler(device_data->device, &sampler_info,1453NULL, &data->font_sampler));14541455/* Descriptor pool */1456VkDescriptorPoolSize sampler_pool_size = {};1457sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;1458sampler_pool_size.descriptorCount = 1;1459VkDescriptorPoolCreateInfo desc_pool_info = {};1460desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;1461desc_pool_info.maxSets = 1;1462desc_pool_info.poolSizeCount = 1;1463desc_pool_info.pPoolSizes = &sampler_pool_size;1464VK_CHECK(device_data->vtable.CreateDescriptorPool(device_data->device,1465&desc_pool_info,1466NULL, &data->descriptor_pool));14671468/* Descriptor layout */1469VkSampler sampler[1] = { data->font_sampler };1470VkDescriptorSetLayoutBinding binding[1] = {};1471binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;1472binding[0].descriptorCount = 1;1473binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;1474binding[0].pImmutableSamplers = sampler;1475VkDescriptorSetLayoutCreateInfo set_layout_info = {};1476set_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;1477set_layout_info.bindingCount = 1;1478set_layout_info.pBindings = binding;1479VK_CHECK(device_data->vtable.CreateDescriptorSetLayout(device_data->device,1480&set_layout_info,1481NULL, &data->descriptor_layout));14821483/* Descriptor set */1484VkDescriptorSetAllocateInfo alloc_info = {};1485alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;1486alloc_info.descriptorPool = data->descriptor_pool;1487alloc_info.descriptorSetCount = 1;1488alloc_info.pSetLayouts = &data->descriptor_layout;1489VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,1490&alloc_info,1491&data->descriptor_set));14921493/* Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full1494* 3d projection matrix1495*/1496VkPushConstantRange push_constants[1] = {};1497push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;1498push_constants[0].offset = sizeof(float) * 0;1499push_constants[0].size = sizeof(float) * 4;1500VkPipelineLayoutCreateInfo layout_info = {};1501layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;1502layout_info.setLayoutCount = 1;1503layout_info.pSetLayouts = &data->descriptor_layout;1504layout_info.pushConstantRangeCount = 1;1505layout_info.pPushConstantRanges = push_constants;1506VK_CHECK(device_data->vtable.CreatePipelineLayout(device_data->device,1507&layout_info,1508NULL, &data->pipeline_layout));15091510VkPipelineShaderStageCreateInfo stage[2] = {};1511stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;1512stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT;1513stage[0].module = vert_module;1514stage[0].pName = "main";1515stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;1516stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;1517stage[1].module = frag_module;1518stage[1].pName = "main";15191520VkVertexInputBindingDescription binding_desc[1] = {};1521binding_desc[0].stride = sizeof(ImDrawVert);1522binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;15231524VkVertexInputAttributeDescription attribute_desc[3] = {};1525attribute_desc[0].location = 0;1526attribute_desc[0].binding = binding_desc[0].binding;1527attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT;1528attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos);1529attribute_desc[1].location = 1;1530attribute_desc[1].binding = binding_desc[0].binding;1531attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;1532attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv);1533attribute_desc[2].location = 2;1534attribute_desc[2].binding = binding_desc[0].binding;1535attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM;1536attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col);15371538VkPipelineVertexInputStateCreateInfo vertex_info = {};1539vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;1540vertex_info.vertexBindingDescriptionCount = 1;1541vertex_info.pVertexBindingDescriptions = binding_desc;1542vertex_info.vertexAttributeDescriptionCount = 3;1543vertex_info.pVertexAttributeDescriptions = attribute_desc;15441545VkPipelineInputAssemblyStateCreateInfo ia_info = {};1546ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;1547ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;15481549VkPipelineViewportStateCreateInfo viewport_info = {};1550viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;1551viewport_info.viewportCount = 1;1552viewport_info.scissorCount = 1;15531554VkPipelineRasterizationStateCreateInfo raster_info = {};1555raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;1556raster_info.polygonMode = VK_POLYGON_MODE_FILL;1557raster_info.cullMode = VK_CULL_MODE_NONE;1558raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;1559raster_info.lineWidth = 1.0f;15601561VkPipelineMultisampleStateCreateInfo ms_info = {};1562ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;1563ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;15641565VkPipelineColorBlendAttachmentState color_attachment[1] = {};1566color_attachment[0].blendEnable = VK_TRUE;1567color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;1568color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;1569color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD;1570color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;1571color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;1572color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD;1573color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT |1574VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;15751576VkPipelineDepthStencilStateCreateInfo depth_info = {};1577depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;15781579VkPipelineColorBlendStateCreateInfo blend_info = {};1580blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;1581blend_info.attachmentCount = 1;1582blend_info.pAttachments = color_attachment;15831584VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };1585VkPipelineDynamicStateCreateInfo dynamic_state = {};1586dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;1587dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states);1588dynamic_state.pDynamicStates = dynamic_states;15891590VkGraphicsPipelineCreateInfo info = {};1591info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;1592info.flags = 0;1593info.stageCount = 2;1594info.pStages = stage;1595info.pVertexInputState = &vertex_info;1596info.pInputAssemblyState = &ia_info;1597info.pViewportState = &viewport_info;1598info.pRasterizationState = &raster_info;1599info.pMultisampleState = &ms_info;1600info.pDepthStencilState = &depth_info;1601info.pColorBlendState = &blend_info;1602info.pDynamicState = &dynamic_state;1603info.layout = data->pipeline_layout;1604info.renderPass = data->render_pass;1605VK_CHECK(1606device_data->vtable.CreateGraphicsPipelines(device_data->device, VK_NULL_HANDLE,16071, &info,1608NULL, &data->pipeline));16091610device_data->vtable.DestroyShaderModule(device_data->device, vert_module, NULL);1611device_data->vtable.DestroyShaderModule(device_data->device, frag_module, NULL);16121613ImGuiIO& io = ImGui::GetIO();1614unsigned char* pixels;1615int width, height;1616io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);16171618/* Font image */1619VkImageCreateInfo image_info = {};1620image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;1621image_info.imageType = VK_IMAGE_TYPE_2D;1622image_info.format = VK_FORMAT_R8G8B8A8_UNORM;1623image_info.extent.width = width;1624image_info.extent.height = height;1625image_info.extent.depth = 1;1626image_info.mipLevels = 1;1627image_info.arrayLayers = 1;1628image_info.samples = VK_SAMPLE_COUNT_1_BIT;1629image_info.tiling = VK_IMAGE_TILING_OPTIMAL;1630image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;1631image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;1632image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;1633VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info,1634NULL, &data->font_image));1635VkMemoryRequirements font_image_req;1636device_data->vtable.GetImageMemoryRequirements(device_data->device,1637data->font_image, &font_image_req);1638VkMemoryAllocateInfo image_alloc_info = {};1639image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;1640image_alloc_info.allocationSize = font_image_req.size;1641image_alloc_info.memoryTypeIndex = vk_memory_type(device_data,1642VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,1643font_image_req.memoryTypeBits);1644VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info,1645NULL, &data->font_mem));1646VK_CHECK(device_data->vtable.BindImageMemory(device_data->device,1647data->font_image,1648data->font_mem, 0));16491650/* Font image view */1651VkImageViewCreateInfo view_info = {};1652view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;1653view_info.image = data->font_image;1654view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;1655view_info.format = VK_FORMAT_R8G8B8A8_UNORM;1656view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;1657view_info.subresourceRange.levelCount = 1;1658view_info.subresourceRange.layerCount = 1;1659VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info,1660NULL, &data->font_image_view));16611662/* Descriptor set */1663VkDescriptorImageInfo desc_image[1] = {};1664desc_image[0].sampler = data->font_sampler;1665desc_image[0].imageView = data->font_image_view;1666desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;1667VkWriteDescriptorSet write_desc[1] = {};1668write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;1669write_desc[0].dstSet = data->descriptor_set;1670write_desc[0].descriptorCount = 1;1671write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;1672write_desc[0].pImageInfo = desc_image;1673device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL);1674}16751676static void setup_swapchain_data(struct swapchain_data *data,1677const VkSwapchainCreateInfoKHR *pCreateInfo)1678{1679data->width = pCreateInfo->imageExtent.width;1680data->height = pCreateInfo->imageExtent.height;1681data->format = pCreateInfo->imageFormat;16821683data->imgui_context = ImGui::CreateContext();1684ImGui::SetCurrentContext(data->imgui_context);16851686ImGui::GetIO().IniFilename = NULL;1687ImGui::GetIO().DisplaySize = ImVec2((float)data->width, (float)data->height);16881689struct device_data *device_data = data->device;16901691/* Render pass */1692VkAttachmentDescription attachment_desc = {};1693attachment_desc.format = pCreateInfo->imageFormat;1694attachment_desc.samples = VK_SAMPLE_COUNT_1_BIT;1695attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;1696attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;1697attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;1698attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;1699attachment_desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;1700attachment_desc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;1701VkAttachmentReference color_attachment = {};1702color_attachment.attachment = 0;1703color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;1704VkSubpassDescription subpass = {};1705subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;1706subpass.colorAttachmentCount = 1;1707subpass.pColorAttachments = &color_attachment;1708VkSubpassDependency dependency = {};1709dependency.srcSubpass = VK_SUBPASS_EXTERNAL;1710dependency.dstSubpass = 0;1711dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;1712dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;1713dependency.srcAccessMask = 0;1714dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;1715VkRenderPassCreateInfo render_pass_info = {};1716render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;1717render_pass_info.attachmentCount = 1;1718render_pass_info.pAttachments = &attachment_desc;1719render_pass_info.subpassCount = 1;1720render_pass_info.pSubpasses = &subpass;1721render_pass_info.dependencyCount = 1;1722render_pass_info.pDependencies = &dependency;1723VK_CHECK(device_data->vtable.CreateRenderPass(device_data->device,1724&render_pass_info,1725NULL, &data->render_pass));17261727setup_swapchain_data_pipeline(data);17281729VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device,1730data->swapchain,1731&data->n_images,1732NULL));17331734data->images = ralloc_array(data, VkImage, data->n_images);1735data->image_views = ralloc_array(data, VkImageView, data->n_images);1736data->framebuffers = ralloc_array(data, VkFramebuffer, data->n_images);17371738VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device,1739data->swapchain,1740&data->n_images,1741data->images));17421743/* Image views */1744VkImageViewCreateInfo view_info = {};1745view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;1746view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;1747view_info.format = pCreateInfo->imageFormat;1748view_info.components.r = VK_COMPONENT_SWIZZLE_R;1749view_info.components.g = VK_COMPONENT_SWIZZLE_G;1750view_info.components.b = VK_COMPONENT_SWIZZLE_B;1751view_info.components.a = VK_COMPONENT_SWIZZLE_A;1752view_info.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };1753for (uint32_t i = 0; i < data->n_images; i++) {1754view_info.image = data->images[i];1755VK_CHECK(device_data->vtable.CreateImageView(device_data->device,1756&view_info, NULL,1757&data->image_views[i]));1758}17591760/* Framebuffers */1761VkImageView attachment[1];1762VkFramebufferCreateInfo fb_info = {};1763fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;1764fb_info.renderPass = data->render_pass;1765fb_info.attachmentCount = 1;1766fb_info.pAttachments = attachment;1767fb_info.width = data->width;1768fb_info.height = data->height;1769fb_info.layers = 1;1770for (uint32_t i = 0; i < data->n_images; i++) {1771attachment[0] = data->image_views[i];1772VK_CHECK(device_data->vtable.CreateFramebuffer(device_data->device, &fb_info,1773NULL, &data->framebuffers[i]));1774}17751776/* Command buffer pool */1777VkCommandPoolCreateInfo cmd_buffer_pool_info = {};1778cmd_buffer_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;1779cmd_buffer_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;1780cmd_buffer_pool_info.queueFamilyIndex = device_data->graphic_queue->family_index;1781VK_CHECK(device_data->vtable.CreateCommandPool(device_data->device,1782&cmd_buffer_pool_info,1783NULL, &data->command_pool));1784}17851786static void shutdown_swapchain_data(struct swapchain_data *data)1787{1788struct device_data *device_data = data->device;17891790list_for_each_entry_safe(struct overlay_draw, draw, &data->draws, link) {1791device_data->vtable.DestroySemaphore(device_data->device, draw->cross_engine_semaphore, NULL);1792device_data->vtable.DestroySemaphore(device_data->device, draw->semaphore, NULL);1793device_data->vtable.DestroyFence(device_data->device, draw->fence, NULL);1794device_data->vtable.DestroyBuffer(device_data->device, draw->vertex_buffer, NULL);1795device_data->vtable.DestroyBuffer(device_data->device, draw->index_buffer, NULL);1796device_data->vtable.FreeMemory(device_data->device, draw->vertex_buffer_mem, NULL);1797device_data->vtable.FreeMemory(device_data->device, draw->index_buffer_mem, NULL);1798}17991800for (uint32_t i = 0; i < data->n_images; i++) {1801device_data->vtable.DestroyImageView(device_data->device, data->image_views[i], NULL);1802device_data->vtable.DestroyFramebuffer(device_data->device, data->framebuffers[i], NULL);1803}18041805device_data->vtable.DestroyRenderPass(device_data->device, data->render_pass, NULL);18061807device_data->vtable.DestroyCommandPool(device_data->device, data->command_pool, NULL);18081809device_data->vtable.DestroyPipeline(device_data->device, data->pipeline, NULL);1810device_data->vtable.DestroyPipelineLayout(device_data->device, data->pipeline_layout, NULL);18111812device_data->vtable.DestroyDescriptorPool(device_data->device,1813data->descriptor_pool, NULL);1814device_data->vtable.DestroyDescriptorSetLayout(device_data->device,1815data->descriptor_layout, NULL);18161817device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL);1818device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL);1819device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL);1820device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL);18211822device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL);1823device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL);18241825ImGui::DestroyContext(data->imgui_context);1826}18271828static struct overlay_draw *before_present(struct swapchain_data *swapchain_data,1829struct queue_data *present_queue,1830const VkSemaphore *wait_semaphores,1831unsigned n_wait_semaphores,1832unsigned imageIndex)1833{1834struct instance_data *instance_data = swapchain_data->device->instance;1835struct overlay_draw *draw = NULL;18361837snapshot_swapchain_frame(swapchain_data);18381839if (!instance_data->params.no_display && swapchain_data->n_frames > 0) {1840compute_swapchain_display(swapchain_data);1841draw = render_swapchain_display(swapchain_data, present_queue,1842wait_semaphores, n_wait_semaphores,1843imageIndex);1844}18451846return draw;1847}18481849static VkResult overlay_CreateSwapchainKHR(1850VkDevice device,1851const VkSwapchainCreateInfoKHR* pCreateInfo,1852const VkAllocationCallbacks* pAllocator,1853VkSwapchainKHR* pSwapchain)1854{1855struct device_data *device_data = FIND(struct device_data, device);1856VkResult result = device_data->vtable.CreateSwapchainKHR(device, pCreateInfo, pAllocator, pSwapchain);1857if (result != VK_SUCCESS) return result;18581859struct swapchain_data *swapchain_data = new_swapchain_data(*pSwapchain, device_data);1860setup_swapchain_data(swapchain_data, pCreateInfo);1861return result;1862}18631864static void overlay_DestroySwapchainKHR(1865VkDevice device,1866VkSwapchainKHR swapchain,1867const VkAllocationCallbacks* pAllocator)1868{1869if (swapchain == VK_NULL_HANDLE) {1870struct device_data *device_data = FIND(struct device_data, device);1871device_data->vtable.DestroySwapchainKHR(device, swapchain, pAllocator);1872return;1873}18741875struct swapchain_data *swapchain_data =1876FIND(struct swapchain_data, swapchain);18771878shutdown_swapchain_data(swapchain_data);1879swapchain_data->device->vtable.DestroySwapchainKHR(device, swapchain, pAllocator);1880destroy_swapchain_data(swapchain_data);1881}18821883static VkResult overlay_QueuePresentKHR(1884VkQueue queue,1885const VkPresentInfoKHR* pPresentInfo)1886{1887struct queue_data *queue_data = FIND(struct queue_data, queue);1888struct device_data *device_data = queue_data->device;1889struct instance_data *instance_data = device_data->instance;1890uint32_t query_results[OVERLAY_QUERY_COUNT];18911892device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_frame]++;18931894if (list_length(&queue_data->running_command_buffer) > 0) {1895/* Before getting the query results, make sure the operations have1896* completed.1897*/1898VK_CHECK(device_data->vtable.ResetFences(device_data->device,18991, &queue_data->queries_fence));1900VK_CHECK(device_data->vtable.QueueSubmit(queue, 0, NULL, queue_data->queries_fence));1901VK_CHECK(device_data->vtable.WaitForFences(device_data->device,19021, &queue_data->queries_fence,1903VK_FALSE, UINT64_MAX));19041905/* Now get the results. */1906list_for_each_entry_safe(struct command_buffer_data, cmd_buffer_data,1907&queue_data->running_command_buffer, link) {1908list_delinit(&cmd_buffer_data->link);19091910if (cmd_buffer_data->pipeline_query_pool) {1911memset(query_results, 0, sizeof(query_results));1912VK_CHECK(device_data->vtable.GetQueryPoolResults(device_data->device,1913cmd_buffer_data->pipeline_query_pool,1914cmd_buffer_data->query_index, 1,1915sizeof(uint32_t) * OVERLAY_QUERY_COUNT,1916query_results, 0, VK_QUERY_RESULT_WAIT_BIT));19171918for (uint32_t i = OVERLAY_PARAM_ENABLED_vertices;1919i <= OVERLAY_PARAM_ENABLED_compute_invocations; i++) {1920device_data->frame_stats.stats[i] += query_results[i - OVERLAY_PARAM_ENABLED_vertices];1921}1922}1923if (cmd_buffer_data->timestamp_query_pool) {1924uint64_t gpu_timestamps[2] = { 0 };1925VK_CHECK(device_data->vtable.GetQueryPoolResults(device_data->device,1926cmd_buffer_data->timestamp_query_pool,1927cmd_buffer_data->query_index * 2, 2,19282 * sizeof(uint64_t), gpu_timestamps, sizeof(uint64_t),1929VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_64_BIT));19301931gpu_timestamps[0] &= queue_data->timestamp_mask;1932gpu_timestamps[1] &= queue_data->timestamp_mask;1933device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_gpu_timing] +=1934(gpu_timestamps[1] - gpu_timestamps[0]) *1935device_data->properties.limits.timestampPeriod;1936}1937}1938}19391940/* Otherwise we need to add our overlay drawing semaphore to the list of1941* semaphores to wait on. If we don't do that the presented picture might1942* be have incomplete overlay drawings.1943*/1944VkResult result = VK_SUCCESS;1945if (instance_data->params.no_display) {1946for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {1947VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i];1948struct swapchain_data *swapchain_data =1949FIND(struct swapchain_data, swapchain);19501951uint32_t image_index = pPresentInfo->pImageIndices[i];19521953before_present(swapchain_data,1954queue_data,1955pPresentInfo->pWaitSemaphores,1956pPresentInfo->waitSemaphoreCount,1957image_index);19581959VkPresentInfoKHR present_info = *pPresentInfo;1960present_info.swapchainCount = 1;1961present_info.pSwapchains = &swapchain;1962present_info.pImageIndices = &image_index;19631964uint64_t ts0 = os_time_get();1965result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info);1966uint64_t ts1 = os_time_get();1967swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_present_timing] += ts1 - ts0;1968}1969} else {1970for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {1971VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i];1972struct swapchain_data *swapchain_data =1973FIND(struct swapchain_data, swapchain);19741975uint32_t image_index = pPresentInfo->pImageIndices[i];19761977VkPresentInfoKHR present_info = *pPresentInfo;1978present_info.swapchainCount = 1;1979present_info.pSwapchains = &swapchain;1980present_info.pImageIndices = &image_index;19811982struct overlay_draw *draw = before_present(swapchain_data,1983queue_data,1984pPresentInfo->pWaitSemaphores,1985pPresentInfo->waitSemaphoreCount,1986image_index);19871988/* Because the submission of the overlay draw waits on the semaphores1989* handed for present, we don't need to have this present operation1990* wait on them as well, we can just wait on the overlay submission1991* semaphore.1992*/1993present_info.pWaitSemaphores = &draw->semaphore;1994present_info.waitSemaphoreCount = 1;19951996uint64_t ts0 = os_time_get();1997VkResult chain_result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info);1998uint64_t ts1 = os_time_get();1999swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_present_timing] += ts1 - ts0;2000if (pPresentInfo->pResults)2001pPresentInfo->pResults[i] = chain_result;2002if (chain_result != VK_SUCCESS && result == VK_SUCCESS)2003result = chain_result;2004}2005}2006return result;2007}20082009static VkResult overlay_AcquireNextImageKHR(2010VkDevice device,2011VkSwapchainKHR swapchain,2012uint64_t timeout,2013VkSemaphore semaphore,2014VkFence fence,2015uint32_t* pImageIndex)2016{2017struct swapchain_data *swapchain_data =2018FIND(struct swapchain_data, swapchain);2019struct device_data *device_data = swapchain_data->device;20202021uint64_t ts0 = os_time_get();2022VkResult result = device_data->vtable.AcquireNextImageKHR(device, swapchain, timeout,2023semaphore, fence, pImageIndex);2024uint64_t ts1 = os_time_get();20252026swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire_timing] += ts1 - ts0;2027swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire]++;20282029return result;2030}20312032static VkResult overlay_AcquireNextImage2KHR(2033VkDevice device,2034const VkAcquireNextImageInfoKHR* pAcquireInfo,2035uint32_t* pImageIndex)2036{2037struct swapchain_data *swapchain_data =2038FIND(struct swapchain_data, pAcquireInfo->swapchain);2039struct device_data *device_data = swapchain_data->device;20402041uint64_t ts0 = os_time_get();2042VkResult result = device_data->vtable.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);2043uint64_t ts1 = os_time_get();20442045swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire_timing] += ts1 - ts0;2046swapchain_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_acquire]++;20472048return result;2049}20502051static void overlay_CmdDraw(2052VkCommandBuffer commandBuffer,2053uint32_t vertexCount,2054uint32_t instanceCount,2055uint32_t firstVertex,2056uint32_t firstInstance)2057{2058struct command_buffer_data *cmd_buffer_data =2059FIND(struct command_buffer_data, commandBuffer);2060cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw]++;2061struct device_data *device_data = cmd_buffer_data->device;2062device_data->vtable.CmdDraw(commandBuffer, vertexCount, instanceCount,2063firstVertex, firstInstance);2064}20652066static void overlay_CmdDrawIndexed(2067VkCommandBuffer commandBuffer,2068uint32_t indexCount,2069uint32_t instanceCount,2070uint32_t firstIndex,2071int32_t vertexOffset,2072uint32_t firstInstance)2073{2074struct command_buffer_data *cmd_buffer_data =2075FIND(struct command_buffer_data, commandBuffer);2076cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indexed]++;2077struct device_data *device_data = cmd_buffer_data->device;2078device_data->vtable.CmdDrawIndexed(commandBuffer, indexCount, instanceCount,2079firstIndex, vertexOffset, firstInstance);2080}20812082static void overlay_CmdDrawIndirect(2083VkCommandBuffer commandBuffer,2084VkBuffer buffer,2085VkDeviceSize offset,2086uint32_t drawCount,2087uint32_t stride)2088{2089struct command_buffer_data *cmd_buffer_data =2090FIND(struct command_buffer_data, commandBuffer);2091cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indirect]++;2092struct device_data *device_data = cmd_buffer_data->device;2093device_data->vtable.CmdDrawIndirect(commandBuffer, buffer, offset, drawCount, stride);2094}20952096static void overlay_CmdDrawIndexedIndirect(2097VkCommandBuffer commandBuffer,2098VkBuffer buffer,2099VkDeviceSize offset,2100uint32_t drawCount,2101uint32_t stride)2102{2103struct command_buffer_data *cmd_buffer_data =2104FIND(struct command_buffer_data, commandBuffer);2105cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indexed_indirect]++;2106struct device_data *device_data = cmd_buffer_data->device;2107device_data->vtable.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, drawCount, stride);2108}21092110static void overlay_CmdDrawIndirectCount(2111VkCommandBuffer commandBuffer,2112VkBuffer buffer,2113VkDeviceSize offset,2114VkBuffer countBuffer,2115VkDeviceSize countBufferOffset,2116uint32_t maxDrawCount,2117uint32_t stride)2118{2119struct command_buffer_data *cmd_buffer_data =2120FIND(struct command_buffer_data, commandBuffer);2121cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indirect_count]++;2122struct device_data *device_data = cmd_buffer_data->device;2123device_data->vtable.CmdDrawIndirectCount(commandBuffer, buffer, offset,2124countBuffer, countBufferOffset,2125maxDrawCount, stride);2126}21272128static void overlay_CmdDrawIndexedIndirectCount(2129VkCommandBuffer commandBuffer,2130VkBuffer buffer,2131VkDeviceSize offset,2132VkBuffer countBuffer,2133VkDeviceSize countBufferOffset,2134uint32_t maxDrawCount,2135uint32_t stride)2136{2137struct command_buffer_data *cmd_buffer_data =2138FIND(struct command_buffer_data, commandBuffer);2139cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_draw_indexed_indirect_count]++;2140struct device_data *device_data = cmd_buffer_data->device;2141device_data->vtable.CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset,2142countBuffer, countBufferOffset,2143maxDrawCount, stride);2144}21452146static void overlay_CmdDispatch(2147VkCommandBuffer commandBuffer,2148uint32_t groupCountX,2149uint32_t groupCountY,2150uint32_t groupCountZ)2151{2152struct command_buffer_data *cmd_buffer_data =2153FIND(struct command_buffer_data, commandBuffer);2154cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_dispatch]++;2155struct device_data *device_data = cmd_buffer_data->device;2156device_data->vtable.CmdDispatch(commandBuffer, groupCountX, groupCountY, groupCountZ);2157}21582159static void overlay_CmdDispatchIndirect(2160VkCommandBuffer commandBuffer,2161VkBuffer buffer,2162VkDeviceSize offset)2163{2164struct command_buffer_data *cmd_buffer_data =2165FIND(struct command_buffer_data, commandBuffer);2166cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_dispatch_indirect]++;2167struct device_data *device_data = cmd_buffer_data->device;2168device_data->vtable.CmdDispatchIndirect(commandBuffer, buffer, offset);2169}21702171static void overlay_CmdBindPipeline(2172VkCommandBuffer commandBuffer,2173VkPipelineBindPoint pipelineBindPoint,2174VkPipeline pipeline)2175{2176struct command_buffer_data *cmd_buffer_data =2177FIND(struct command_buffer_data, commandBuffer);2178switch (pipelineBindPoint) {2179case VK_PIPELINE_BIND_POINT_GRAPHICS: cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_pipeline_graphics]++; break;2180case VK_PIPELINE_BIND_POINT_COMPUTE: cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_pipeline_compute]++; break;2181case VK_PIPELINE_BIND_POINT_RAY_TRACING_NV: cmd_buffer_data->stats.stats[OVERLAY_PARAM_ENABLED_pipeline_raytracing]++; break;2182default: break;2183}2184struct device_data *device_data = cmd_buffer_data->device;2185device_data->vtable.CmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);2186}21872188static VkResult overlay_BeginCommandBuffer(2189VkCommandBuffer commandBuffer,2190const VkCommandBufferBeginInfo* pBeginInfo)2191{2192struct command_buffer_data *cmd_buffer_data =2193FIND(struct command_buffer_data, commandBuffer);2194struct device_data *device_data = cmd_buffer_data->device;21952196memset(&cmd_buffer_data->stats, 0, sizeof(cmd_buffer_data->stats));21972198/* We don't record any query in secondary command buffers, just make sure2199* we have the right inheritance.2200*/2201if (cmd_buffer_data->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) {2202VkCommandBufferBeginInfo *begin_info = (VkCommandBufferBeginInfo *)2203clone_chain((const struct VkBaseInStructure *)pBeginInfo);2204VkCommandBufferInheritanceInfo *parent_inhe_info = (VkCommandBufferInheritanceInfo *)2205vk_find_struct(begin_info, COMMAND_BUFFER_INHERITANCE_INFO);2206VkCommandBufferInheritanceInfo inhe_info = {2207VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,2208NULL,2209VK_NULL_HANDLE,22100,2211VK_NULL_HANDLE,2212VK_FALSE,22130,2214overlay_query_flags,2215};22162217if (parent_inhe_info)2218parent_inhe_info->pipelineStatistics = overlay_query_flags;2219else {2220inhe_info.pNext = begin_info->pNext;2221begin_info->pNext = &inhe_info;2222}22232224VkResult result = device_data->vtable.BeginCommandBuffer(commandBuffer, pBeginInfo);22252226if (!parent_inhe_info)2227begin_info->pNext = inhe_info.pNext;22282229free_chain((struct VkBaseOutStructure *)begin_info);22302231return result;2232}22332234/* Otherwise record a begin query as first command. */2235VkResult result = device_data->vtable.BeginCommandBuffer(commandBuffer, pBeginInfo);22362237if (result == VK_SUCCESS) {2238if (cmd_buffer_data->pipeline_query_pool) {2239device_data->vtable.CmdResetQueryPool(commandBuffer,2240cmd_buffer_data->pipeline_query_pool,2241cmd_buffer_data->query_index, 1);2242}2243if (cmd_buffer_data->timestamp_query_pool) {2244device_data->vtable.CmdResetQueryPool(commandBuffer,2245cmd_buffer_data->timestamp_query_pool,2246cmd_buffer_data->query_index * 2, 2);2247}2248if (cmd_buffer_data->pipeline_query_pool) {2249device_data->vtable.CmdBeginQuery(commandBuffer,2250cmd_buffer_data->pipeline_query_pool,2251cmd_buffer_data->query_index, 0);2252}2253if (cmd_buffer_data->timestamp_query_pool) {2254device_data->vtable.CmdWriteTimestamp(commandBuffer,2255VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,2256cmd_buffer_data->timestamp_query_pool,2257cmd_buffer_data->query_index * 2);2258}2259}22602261return result;2262}22632264static VkResult overlay_EndCommandBuffer(2265VkCommandBuffer commandBuffer)2266{2267struct command_buffer_data *cmd_buffer_data =2268FIND(struct command_buffer_data, commandBuffer);2269struct device_data *device_data = cmd_buffer_data->device;22702271if (cmd_buffer_data->timestamp_query_pool) {2272device_data->vtable.CmdWriteTimestamp(commandBuffer,2273VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,2274cmd_buffer_data->timestamp_query_pool,2275cmd_buffer_data->query_index * 2 + 1);2276}2277if (cmd_buffer_data->pipeline_query_pool) {2278device_data->vtable.CmdEndQuery(commandBuffer,2279cmd_buffer_data->pipeline_query_pool,2280cmd_buffer_data->query_index);2281}22822283return device_data->vtable.EndCommandBuffer(commandBuffer);2284}22852286static VkResult overlay_ResetCommandBuffer(2287VkCommandBuffer commandBuffer,2288VkCommandBufferResetFlags flags)2289{2290struct command_buffer_data *cmd_buffer_data =2291FIND(struct command_buffer_data, commandBuffer);2292struct device_data *device_data = cmd_buffer_data->device;22932294memset(&cmd_buffer_data->stats, 0, sizeof(cmd_buffer_data->stats));22952296return device_data->vtable.ResetCommandBuffer(commandBuffer, flags);2297}22982299static void overlay_CmdExecuteCommands(2300VkCommandBuffer commandBuffer,2301uint32_t commandBufferCount,2302const VkCommandBuffer* pCommandBuffers)2303{2304struct command_buffer_data *cmd_buffer_data =2305FIND(struct command_buffer_data, commandBuffer);2306struct device_data *device_data = cmd_buffer_data->device;23072308/* Add the stats of the executed command buffers to the primary one. */2309for (uint32_t c = 0; c < commandBufferCount; c++) {2310struct command_buffer_data *sec_cmd_buffer_data =2311FIND(struct command_buffer_data, pCommandBuffers[c]);23122313for (uint32_t s = 0; s < OVERLAY_PARAM_ENABLED_MAX; s++)2314cmd_buffer_data->stats.stats[s] += sec_cmd_buffer_data->stats.stats[s];2315}23162317device_data->vtable.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);2318}23192320static VkResult overlay_AllocateCommandBuffers(2321VkDevice device,2322const VkCommandBufferAllocateInfo* pAllocateInfo,2323VkCommandBuffer* pCommandBuffers)2324{2325struct device_data *device_data = FIND(struct device_data, device);2326VkResult result =2327device_data->vtable.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);2328if (result != VK_SUCCESS)2329return result;23302331VkQueryPool pipeline_query_pool = VK_NULL_HANDLE;2332VkQueryPool timestamp_query_pool = VK_NULL_HANDLE;2333if (device_data->instance->pipeline_statistics_enabled &&2334pAllocateInfo->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {2335VkQueryPoolCreateInfo pool_info = {2336VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,2337NULL,23380,2339VK_QUERY_TYPE_PIPELINE_STATISTICS,2340pAllocateInfo->commandBufferCount,2341overlay_query_flags,2342};2343VK_CHECK(device_data->vtable.CreateQueryPool(device_data->device, &pool_info,2344NULL, &pipeline_query_pool));2345}2346if (device_data->instance->params.enabled[OVERLAY_PARAM_ENABLED_gpu_timing]) {2347VkQueryPoolCreateInfo pool_info = {2348VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,2349NULL,23500,2351VK_QUERY_TYPE_TIMESTAMP,2352pAllocateInfo->commandBufferCount * 2,23530,2354};2355VK_CHECK(device_data->vtable.CreateQueryPool(device_data->device, &pool_info,2356NULL, ×tamp_query_pool));2357}23582359for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {2360new_command_buffer_data(pCommandBuffers[i], pAllocateInfo->level,2361pipeline_query_pool, timestamp_query_pool,2362i, device_data);2363}23642365if (pipeline_query_pool)2366map_object(HKEY(pipeline_query_pool), (void *)(uintptr_t) pAllocateInfo->commandBufferCount);2367if (timestamp_query_pool)2368map_object(HKEY(timestamp_query_pool), (void *)(uintptr_t) pAllocateInfo->commandBufferCount);23692370return result;2371}23722373static void overlay_FreeCommandBuffers(2374VkDevice device,2375VkCommandPool commandPool,2376uint32_t commandBufferCount,2377const VkCommandBuffer* pCommandBuffers)2378{2379struct device_data *device_data = FIND(struct device_data, device);2380for (uint32_t i = 0; i < commandBufferCount; i++) {2381struct command_buffer_data *cmd_buffer_data =2382FIND(struct command_buffer_data, pCommandBuffers[i]);23832384/* It is legal to free a NULL command buffer*/2385if (!cmd_buffer_data)2386continue;23872388uint64_t count = (uintptr_t)find_object_data(HKEY(cmd_buffer_data->pipeline_query_pool));2389if (count == 1) {2390unmap_object(HKEY(cmd_buffer_data->pipeline_query_pool));2391device_data->vtable.DestroyQueryPool(device_data->device,2392cmd_buffer_data->pipeline_query_pool, NULL);2393} else if (count != 0) {2394map_object(HKEY(cmd_buffer_data->pipeline_query_pool), (void *)(uintptr_t)(count - 1));2395}2396count = (uintptr_t)find_object_data(HKEY(cmd_buffer_data->timestamp_query_pool));2397if (count == 1) {2398unmap_object(HKEY(cmd_buffer_data->timestamp_query_pool));2399device_data->vtable.DestroyQueryPool(device_data->device,2400cmd_buffer_data->timestamp_query_pool, NULL);2401} else if (count != 0) {2402map_object(HKEY(cmd_buffer_data->timestamp_query_pool), (void *)(uintptr_t)(count - 1));2403}2404destroy_command_buffer_data(cmd_buffer_data);2405}24062407device_data->vtable.FreeCommandBuffers(device, commandPool,2408commandBufferCount, pCommandBuffers);2409}24102411static VkResult overlay_QueueSubmit(2412VkQueue queue,2413uint32_t submitCount,2414const VkSubmitInfo* pSubmits,2415VkFence fence)2416{2417struct queue_data *queue_data = FIND(struct queue_data, queue);2418struct device_data *device_data = queue_data->device;24192420device_data->frame_stats.stats[OVERLAY_PARAM_ENABLED_submit]++;24212422for (uint32_t s = 0; s < submitCount; s++) {2423for (uint32_t c = 0; c < pSubmits[s].commandBufferCount; c++) {2424struct command_buffer_data *cmd_buffer_data =2425FIND(struct command_buffer_data, pSubmits[s].pCommandBuffers[c]);24262427/* Merge the submitted command buffer stats into the device. */2428for (uint32_t st = 0; st < OVERLAY_PARAM_ENABLED_MAX; st++)2429device_data->frame_stats.stats[st] += cmd_buffer_data->stats.stats[st];24302431/* Attach the command buffer to the queue so we remember to read its2432* pipeline statistics & timestamps at QueuePresent().2433*/2434if (!cmd_buffer_data->pipeline_query_pool &&2435!cmd_buffer_data->timestamp_query_pool)2436continue;24372438if (list_is_empty(&cmd_buffer_data->link)) {2439list_addtail(&cmd_buffer_data->link,2440&queue_data->running_command_buffer);2441} else {2442fprintf(stderr, "Command buffer submitted multiple times before present.\n"2443"This could lead to invalid data.\n");2444}2445}2446}24472448return device_data->vtable.QueueSubmit(queue, submitCount, pSubmits, fence);2449}24502451static VkResult overlay_CreateDevice(2452VkPhysicalDevice physicalDevice,2453const VkDeviceCreateInfo* pCreateInfo,2454const VkAllocationCallbacks* pAllocator,2455VkDevice* pDevice)2456{2457struct instance_data *instance_data =2458FIND(struct instance_data, physicalDevice);2459VkLayerDeviceCreateInfo *chain_info =2460get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);24612462assert(chain_info->u.pLayerInfo);2463PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;2464PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;2465PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(NULL, "vkCreateDevice");2466if (fpCreateDevice == NULL) {2467return VK_ERROR_INITIALIZATION_FAILED;2468}24692470// Advance the link info for the next element on the chain2471chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;24722473VkPhysicalDeviceFeatures device_features = {};2474VkPhysicalDeviceFeatures *device_features_ptr = NULL;24752476VkDeviceCreateInfo *device_info = (VkDeviceCreateInfo *)2477clone_chain((const struct VkBaseInStructure *)pCreateInfo);24782479VkPhysicalDeviceFeatures2 *device_features2 = (VkPhysicalDeviceFeatures2 *)2480vk_find_struct(device_info, PHYSICAL_DEVICE_FEATURES_2);2481if (device_features2) {2482/* Can't use device_info->pEnabledFeatures when VkPhysicalDeviceFeatures2 is present */2483device_features_ptr = &device_features2->features;2484} else {2485if (device_info->pEnabledFeatures)2486device_features = *(device_info->pEnabledFeatures);2487device_features_ptr = &device_features;2488device_info->pEnabledFeatures = &device_features;2489}24902491if (instance_data->pipeline_statistics_enabled) {2492device_features_ptr->inheritedQueries = true;2493device_features_ptr->pipelineStatisticsQuery = true;2494}249524962497VkResult result = fpCreateDevice(physicalDevice, device_info, pAllocator, pDevice);2498free_chain((struct VkBaseOutStructure *)device_info);2499if (result != VK_SUCCESS) return result;25002501struct device_data *device_data = new_device_data(*pDevice, instance_data);2502device_data->physical_device = physicalDevice;2503vk_device_dispatch_table_load(&device_data->vtable,2504fpGetDeviceProcAddr, *pDevice);25052506instance_data->pd_vtable.GetPhysicalDeviceProperties(device_data->physical_device,2507&device_data->properties);25082509VkLayerDeviceCreateInfo *load_data_info =2510get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);2511device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;25122513device_map_queues(device_data, pCreateInfo);25142515return result;2516}25172518static void overlay_DestroyDevice(2519VkDevice device,2520const VkAllocationCallbacks* pAllocator)2521{2522struct device_data *device_data = FIND(struct device_data, device);2523device_unmap_queues(device_data);2524device_data->vtable.DestroyDevice(device, pAllocator);2525destroy_device_data(device_data);2526}25272528static VkResult overlay_CreateInstance(2529const VkInstanceCreateInfo* pCreateInfo,2530const VkAllocationCallbacks* pAllocator,2531VkInstance* pInstance)2532{2533VkLayerInstanceCreateInfo *chain_info =2534get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);25352536assert(chain_info->u.pLayerInfo);2537PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =2538chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;2539PFN_vkCreateInstance fpCreateInstance =2540(PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");2541if (fpCreateInstance == NULL) {2542return VK_ERROR_INITIALIZATION_FAILED;2543}25442545// Advance the link info for the next element on the chain2546chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;25472548VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);2549if (result != VK_SUCCESS) return result;25502551struct instance_data *instance_data = new_instance_data(*pInstance);2552vk_instance_dispatch_table_load(&instance_data->vtable,2553fpGetInstanceProcAddr,2554instance_data->instance);2555vk_physical_device_dispatch_table_load(&instance_data->pd_vtable,2556fpGetInstanceProcAddr,2557instance_data->instance);2558instance_data_map_physical_devices(instance_data, true);25592560parse_overlay_env(&instance_data->params, getenv("VK_LAYER_MESA_OVERLAY_CONFIG"));25612562/* If there's no control file, and an output_file was specified, start2563* capturing fps data right away.2564*/2565instance_data->capture_enabled =2566instance_data->params.output_file && instance_data->params.control < 0;2567instance_data->capture_started = instance_data->capture_enabled;25682569for (int i = OVERLAY_PARAM_ENABLED_vertices;2570i <= OVERLAY_PARAM_ENABLED_compute_invocations; i++) {2571if (instance_data->params.enabled[i]) {2572instance_data->pipeline_statistics_enabled = true;2573break;2574}2575}25762577return result;2578}25792580static void overlay_DestroyInstance(2581VkInstance instance,2582const VkAllocationCallbacks* pAllocator)2583{2584struct instance_data *instance_data = FIND(struct instance_data, instance);2585instance_data_map_physical_devices(instance_data, false);2586instance_data->vtable.DestroyInstance(instance, pAllocator);2587destroy_instance_data(instance_data);2588}25892590static const struct {2591const char *name;2592void *ptr;2593} name_to_funcptr_map[] = {2594{ "vkGetInstanceProcAddr", (void *) vkGetInstanceProcAddr },2595{ "vkGetDeviceProcAddr", (void *) vkGetDeviceProcAddr },2596#define ADD_HOOK(fn) { "vk" # fn, (void *) overlay_ ## fn }2597#define ADD_ALIAS_HOOK(alias, fn) { "vk" # alias, (void *) overlay_ ## fn }2598ADD_HOOK(AllocateCommandBuffers),2599ADD_HOOK(FreeCommandBuffers),2600ADD_HOOK(ResetCommandBuffer),2601ADD_HOOK(BeginCommandBuffer),2602ADD_HOOK(EndCommandBuffer),2603ADD_HOOK(CmdExecuteCommands),26042605ADD_HOOK(CmdDraw),2606ADD_HOOK(CmdDrawIndexed),2607ADD_HOOK(CmdDrawIndirect),2608ADD_HOOK(CmdDrawIndexedIndirect),2609ADD_HOOK(CmdDispatch),2610ADD_HOOK(CmdDispatchIndirect),2611ADD_HOOK(CmdDrawIndirectCount),2612ADD_ALIAS_HOOK(CmdDrawIndirectCountKHR, CmdDrawIndirectCount),2613ADD_HOOK(CmdDrawIndexedIndirectCount),2614ADD_ALIAS_HOOK(CmdDrawIndexedIndirectCountKHR, CmdDrawIndexedIndirectCount),26152616ADD_HOOK(CmdBindPipeline),26172618ADD_HOOK(CreateSwapchainKHR),2619ADD_HOOK(QueuePresentKHR),2620ADD_HOOK(DestroySwapchainKHR),2621ADD_HOOK(AcquireNextImageKHR),2622ADD_HOOK(AcquireNextImage2KHR),26232624ADD_HOOK(QueueSubmit),26252626ADD_HOOK(CreateDevice),2627ADD_HOOK(DestroyDevice),26282629ADD_HOOK(CreateInstance),2630ADD_HOOK(DestroyInstance),2631#undef ADD_HOOK2632#undef ADD_ALIAS_HOOK2633};26342635static void *find_ptr(const char *name)2636{2637for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {2638if (strcmp(name, name_to_funcptr_map[i].name) == 0)2639return name_to_funcptr_map[i].ptr;2640}26412642return NULL;2643}26442645VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice dev,2646const char *funcName)2647{2648void *ptr = find_ptr(funcName);2649if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);26502651if (dev == NULL) return NULL;26522653struct device_data *device_data = FIND(struct device_data, dev);2654if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;2655return device_data->vtable.GetDeviceProcAddr(dev, funcName);2656}26572658VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,2659const char *funcName)2660{2661void *ptr = find_ptr(funcName);2662if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);26632664if (instance == NULL) return NULL;26652666struct instance_data *instance_data = FIND(struct instance_data, instance);2667if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;2668return instance_data->vtable.GetInstanceProcAddr(instance, funcName);2669}267026712672