From e9046dd06f6f4fe7116640b4ebafaa5b626957e1 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 6 Jul 2016 19:37:47 +0200 Subject: [PATCH 1/6] Begin implementing VK_KHR_display. --- gfx/common/vulkan_common.c | 61 +++++++++++++++++++++++++++++--------- gfx/common/vulkan_common.h | 9 +++++- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 9f1ad5ad03..db5e216a7c 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1435,12 +1435,13 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, VkResult res; VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; + + const char *instance_extensions[4]; + unsigned ext_count = 0; + #ifdef VULKAN_DEBUG - const char *instance_extensions[3]; - instance_extensions[2] = "VK_EXT_debug_report"; + instance_extensions[ext_count++] = "VK_EXT_debug_report"; static const char *instance_layers[] = { "VK_LAYER_LUNARG_standard_validation" }; -#else - const char *instance_extensions[2]; #endif bool use_instance_ext; @@ -1459,31 +1460,33 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, iface = NULL; } - instance_extensions[0] = "VK_KHR_surface"; + instance_extensions[ext_count++] = "VK_KHR_surface"; switch (type) { case VULKAN_WSI_WAYLAND: - instance_extensions[1] = "VK_KHR_wayland_surface"; + instance_extensions[ext_count++] = "VK_KHR_wayland_surface"; break; case VULKAN_WSI_ANDROID: - instance_extensions[1] = "VK_KHR_android_surface"; + instance_extensions[ext_count++] = "VK_KHR_android_surface"; break; case VULKAN_WSI_WIN32: - instance_extensions[1] = "VK_KHR_win32_surface"; + instance_extensions[ext_count++] = "VK_KHR_win32_surface"; break; case VULKAN_WSI_XLIB: - instance_extensions[1] = "VK_KHR_xlib_surface"; + instance_extensions[ext_count++] = "VK_KHR_xlib_surface"; break; case VULKAN_WSI_XCB: - instance_extensions[1] = "VK_KHR_xcb_surface"; + instance_extensions[ext_count++] = "VK_KHR_xcb_surface"; break; case VULKAN_WSI_MIR: - instance_extensions[1] = "VK_KHR_mir_surface"; + instance_extensions[ext_count++] = "VK_KHR_mir_surface"; + break; + case VULKAN_WSI_DISPLAY: + instance_extensions[ext_count++] = "VK_KHR_display"; break; case VULKAN_WSI_NONE: default: - instance_extensions[1] = NULL; break; } @@ -1521,7 +1524,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, return false; } - use_instance_ext = vulkan_find_instance_extensions(instance_extensions, ARRAY_SIZE(instance_extensions)); + use_instance_ext = vulkan_find_instance_extensions(instance_extensions, ext_count); app.pApplicationName = "RetroArch"; app.applicationVersion = 0; @@ -1530,7 +1533,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, app.apiVersion = VK_MAKE_VERSION(1, 0, 18); info.pApplicationInfo = &app; - info.enabledExtensionCount = use_instance_ext ? ARRAY_SIZE(instance_extensions) : 0; + info.enabledExtensionCount = use_instance_ext ? ext_count : 0; info.ppEnabledExtensionNames = use_instance_ext ? instance_extensions : NULL; #ifdef VULKAN_DEBUG info.enabledLayerCount = ARRAY_SIZE(instance_layers); @@ -1608,6 +1611,28 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, return true; } +static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, + unsigned *width, unsigned *height, + const struct vulkan_display_surface_info *info) +{ + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkGetPhysicalDeviceDisplayPropertiesKHR); + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkGetPhysicalDeviceDisplayPlanePropertiesKHR); + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkGetDisplayPlaneSupportedDisplaysKHR); + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkGetDisplayModePropertiesKHR); + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkCreateDisplayModeKHR); + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkGetDisplayPlaneCapabilitiesKHR); + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, + vkCreateDisplayPlaneSurfaceKHR); + + return false; +} + bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk, enum vulkan_wsi_type type, void *display, void *surface, @@ -1751,6 +1776,14 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk, } #endif break; + case VULKAN_WSI_DISPLAY: + { + if (!vulkan_create_display_surface(vk, + &width, &height, + (const struct vulkan_display_surface_info*)display)) + return false; + } + break; case VULKAN_WSI_NONE: default: return false; diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h index 7a87d6c032..7e69ca3e7c 100644 --- a/gfx/common/vulkan_common.h +++ b/gfx/common/vulkan_common.h @@ -82,7 +82,8 @@ enum vulkan_wsi_type VULKAN_WSI_ANDROID, VULKAN_WSI_WIN32, VULKAN_WSI_XCB, - VULKAN_WSI_XLIB + VULKAN_WSI_XLIB, + VULKAN_WSI_DISPLAY }; typedef struct vulkan_context @@ -125,6 +126,12 @@ typedef struct gfx_ctx_vulkan_data bool need_new_swapchain; } gfx_ctx_vulkan_data_t; +struct vulkan_display_surface_info +{ + unsigned width; + unsigned height; +}; + struct vk_color { float r, g, b, a; From d2fafc54512c32e52e238666df6986e65ce8119f Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 6 Jul 2016 20:27:39 +0200 Subject: [PATCH 2/6] Sketch out vulkan_create_display_surface. --- gfx/common/vulkan_common.c | 153 ++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index db5e216a7c..9f88032508 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1611,10 +1611,36 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, return true; } +static void vulkan_update_display_mode(VkDisplayModeKHR *best_mode, + unsigned *width, + unsigned *height, + const VkDisplayModePropertiesKHR *mode, + const struct vulkan_display_surface_info *info) +{ + *best_mode = VK_NULL_HANDLE; + *width = 0; + *height = 0; + (void)mode; + (void)info; +} + static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, unsigned *width, unsigned *height, const struct vulkan_display_surface_info *info) { + bool ret = true; + uint32_t display_count = 0; + uint32_t plane_count = 0; + VkDisplayPropertiesKHR *displays = NULL; + VkDisplayPlanePropertiesKHR *planes = NULL; + uint32_t mode_count = 0; + VkDisplayModePropertiesKHR *modes = NULL; + unsigned dpy, i, j; + uint32_t best_plane = UINT32_MAX; + VkDisplayPlaneAlphaFlagsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + VkDisplaySurfaceCreateInfoKHR create_info = { VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR }; + VkDisplayModeKHR best_mode = VK_NULL_HANDLE; + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkGetPhysicalDeviceDisplayPropertiesKHR); VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, @@ -1630,7 +1656,132 @@ static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkCreateDisplayPlaneSurfaceKHR); - return false; +#define GOTO_FAIL() do { \ + ret = false; \ + goto end; \ +} while(0) + + if (vkGetPhysicalDeviceDisplayPropertiesKHR(vk->context.gpu, &display_count, NULL) != VK_SUCCESS) + GOTO_FAIL(); + displays = (VkDisplayPropertiesKHR*)calloc(display_count, sizeof(*displays)); + if (!displays) + GOTO_FAIL(); + if (vkGetPhysicalDeviceDisplayPropertiesKHR(vk->context.gpu, &display_count, displays) != VK_SUCCESS) + GOTO_FAIL(); + + if (vkGetPhysicalDeviceDisplayPlanePropertiesKHR(vk->context.gpu, &plane_count, NULL) != VK_SUCCESS) + GOTO_FAIL(); + planes = (VkDisplayPlanePropertiesKHR*)calloc(plane_count, sizeof(*planes)); + if (!planes) + GOTO_FAIL(); + if (vkGetPhysicalDeviceDisplayPlanePropertiesKHR(vk->context.gpu, &plane_count, planes) != VK_SUCCESS) + GOTO_FAIL(); + + for (dpy = 0; dpy < display_count; dpy++) + { + VkDisplayKHR display = displays[dpy].display; + best_mode = VK_NULL_HANDLE; + best_plane = UINT32_MAX; + + if (vkGetDisplayModePropertiesKHR(vk->context.gpu, + display, &mode_count, NULL) != VK_SUCCESS) + GOTO_FAIL(); + + modes = (VkDisplayModePropertiesKHR*)calloc(mode_count, sizeof(*modes)); + if (!modes) + GOTO_FAIL(); + + if (vkGetDisplayModePropertiesKHR(vk->context.gpu, + display, &mode_count, modes) != VK_SUCCESS) + GOTO_FAIL(); + + for (i = 0; i < mode_count; i++) + { + const VkDisplayModePropertiesKHR *mode = &modes[i]; + vulkan_update_display_mode(&best_mode, width, height, mode, info); + } + + free(modes); + modes = NULL; + mode_count = 0; + + if (best_mode == VK_NULL_HANDLE) + continue; + + for (i = 0; i < plane_count; i++) + { + uint32_t supported_count = 0; + VkDisplayKHR *supported = NULL; + VkDisplayPlaneCapabilitiesKHR plane_caps; + vkGetDisplayPlaneSupportedDisplaysKHR(vk->context.gpu, i, &supported_count, NULL); + if (!supported_count) + continue; + + supported = (VkDisplayKHR*)calloc(supported_count, sizeof(*supported)); + if (!supported) + GOTO_FAIL(); + + vkGetDisplayPlaneSupportedDisplaysKHR(vk->context.gpu, i, &supported_count, + supported); + + for (j = 0; j < supported_count; j++) + { + if (supported[j] == display) + { + if (best_plane == UINT32_MAX) + best_plane = j; + break; + } + } + + free(supported); + supported = NULL; + + if (j == supported_count) + continue; + + if (planes[i].currentDisplay == VK_NULL_HANDLE || + planes[i].currentDisplay == display) + best_plane = j; + else + continue; + + vkGetDisplayPlaneCapabilitiesKHR(vk->context.gpu, + best_mode, i, &plane_caps); + + if (plane_caps.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR) + { + best_plane = j; + alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + goto out; + } + } + } +out: + + if (best_mode == VK_NULL_HANDLE) + GOTO_FAIL(); + if (best_plane == UINT32_MAX) + GOTO_FAIL(); + + create_info.displayMode = best_mode; + create_info.planeIndex = best_plane; + create_info.planeStackIndex = planes[best_plane].currentStackIndex; + create_info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + create_info.globalAlpha = 1.0f; + create_info.alphaMode = alpha_mode; + create_info.imageExtent.width = *width; + create_info.imageExtent.height = *height; + + if (vkCreateDisplayPlaneSurfaceKHR(vk->context.instance, + &create_info, NULL, &vk->vk_surface) != VK_SUCCESS) + GOTO_FAIL(); + +end: + free(displays); + free(planes); + free(modes); + return ret; } bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk, From 471d06d1338fa86bee8dfdd2329fc26231cb2441 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Wed, 6 Jul 2016 23:22:13 +0200 Subject: [PATCH 3/6] Fix Wayland refresh rate logging. --- gfx/drivers_context/wayland_ctx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gfx/drivers_context/wayland_ctx.c b/gfx/drivers_context/wayland_ctx.c index 66b7dbbdc9..4b336c9896 100644 --- a/gfx/drivers_context/wayland_ctx.c +++ b/gfx/drivers_context/wayland_ctx.c @@ -177,8 +177,10 @@ static void display_handle_mode(void *data, wl->width = width; wl->height = height; - RARCH_LOG("[Wayland]: Video mode: %d x %d @ %d Hz.\n", - width, height, refresh); + /* Certain older Wayland implementations report in Hz, + * but it should be mHz. */ + RARCH_LOG("[Wayland]: Video mode: %d x %d @ %.4f Hz.\n", + width, height, refresh > 1000 ? refresh / 1000.0 : (double)refresh); } static void display_handle_done(void *data, From d382e1069e3de35fe5da006c713eabb106e788ee Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 7 Jul 2016 16:50:41 +0000 Subject: [PATCH 4/6] Basic VK_KHR_display integration works! :) --- Makefile.common | 1 + gfx/common/vulkan_common.c | 129 ++++++++----- gfx/drivers_context/khr_display_ctx.c | 260 ++++++++++++++++++++++++++ gfx/video_context_driver.c | 3 + gfx/video_context_driver.h | 1 + 5 files changed, 351 insertions(+), 43 deletions(-) create mode 100644 gfx/drivers_context/khr_display_ctx.c diff --git a/Makefile.common b/Makefile.common index b21ac70dff..5b28285af0 100644 --- a/Makefile.common +++ b/Makefile.common @@ -842,6 +842,7 @@ ifeq ($(HAVE_VULKAN), 1) OBJ += gfx/drivers/vulkan.o \ gfx/common/vulkan_common.o \ + gfx/drivers_context/khr_display_ctx.o \ libretro-common/vulkan/vulkan_symbol_wrapper.o \ gfx/drivers_font/vulkan_raster_font.o \ gfx/drivers_shader/shader_vulkan.o \ diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 9f88032508..331121218a 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1202,6 +1202,47 @@ end: return ret; } +static bool vulkan_context_init_gpu(gfx_ctx_vulkan_data_t *vk) +{ + uint32_t gpu_count = 0; + VkPhysicalDevice *gpus = NULL; + + if (vk->context.gpu != VK_NULL_HANDLE) + return true; + + if (vkEnumeratePhysicalDevices(vk->context.instance, + &gpu_count, NULL) != VK_SUCCESS) + { + RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n"); + return false; + } + + gpus = (VkPhysicalDevice*)calloc(gpu_count, sizeof(*gpus)); + if (!gpus) + { + RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n"); + return false; + } + + if (vkEnumeratePhysicalDevices(vk->context.instance, + &gpu_count, gpus) != VK_SUCCESS) + { + RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n"); + return false; + } + + if (gpu_count < 1) + { + RARCH_ERR("[Vulkan]: Failed to enumerate Vulkan physical device.\n"); + free(gpus); + return false; + } + + vk->context.gpu = gpus[0]; + free(gpus); + return true; +} + static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) { bool use_device_ext; @@ -1209,9 +1250,7 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) VkResult res; unsigned i; static const float one = 1.0f; - uint32_t gpu_count = 1; bool found_queue = false; - VkPhysicalDevice *gpus = NULL; VkPhysicalDeviceFeatures features = { false }; VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; @@ -1246,7 +1285,7 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) const VkPhysicalDeviceFeatures features = { 0 }; bool ret = iface->create_device(&context, vk->context.instance, - VK_NULL_HANDLE, + vk->context.gpu, vk->vk_surface, vulkan_symbol_wrapper_instance_proc_addr(), device_extensions, @@ -1287,39 +1326,8 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) cached_destroy_device = NULL; } - if (vk->context.gpu == VK_NULL_HANDLE) - { - if (vkEnumeratePhysicalDevices(vk->context.instance, - &gpu_count, NULL) != VK_SUCCESS) - { - RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n"); - return false; - } - - gpus = (VkPhysicalDevice*)calloc(gpu_count, sizeof(*gpus)); - if (!gpus) - { - RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n"); - return false; - } - - if (vkEnumeratePhysicalDevices(vk->context.instance, - &gpu_count, gpus) != VK_SUCCESS) - { - RARCH_ERR("[Vulkan]: Failed to enumerate physical devices.\n"); - return false; - } - - if (gpu_count < 1) - { - RARCH_ERR("[Vulkan]: Failed to enumerate Vulkan physical device.\n"); - free(gpus); - return false; - } - - vk->context.gpu = gpus[0]; - free(gpus); - } + if (!vulkan_context_init_gpu(vk)) + return false; vkGetPhysicalDeviceProperties(vk->context.gpu, &vk->context.gpu_properties); @@ -1611,17 +1619,47 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk, return true; } -static void vulkan_update_display_mode(VkDisplayModeKHR *best_mode, +static bool vulkan_update_display_mode( unsigned *width, unsigned *height, const VkDisplayModePropertiesKHR *mode, const struct vulkan_display_surface_info *info) { - *best_mode = VK_NULL_HANDLE; - *width = 0; - *height = 0; - (void)mode; - (void)info; + unsigned visible_width = mode->parameters.visibleRegion.width; + unsigned visible_height = mode->parameters.visibleRegion.height; + + if (!info->width || !info->height) + { + /* Strategy here is to pick something which is largest resolution. */ + unsigned area = visible_width * visible_height; + if (area > (*width) * (*height)) + { + *width = visible_width; + *height = visible_height; + return true; + } + else + return false; + } + else + { + /* For particular resolutions, find the closest. */ + int delta_x = (int)info->width - (int)visible_width; + int delta_y = (int)info->height - (int)visible_height; + int old_delta_x = (int)info->width - (int)*width; + int old_delta_y = (int)info->height - (int)*height; + + int dist = delta_x * delta_x + delta_y * delta_y; + int old_dist = old_delta_x * old_delta_x + old_delta_y * old_delta_y; + if (dist < old_dist) + { + *width = visible_width; + *height = visible_height; + return true; + } + else + return false; + } } static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, @@ -1641,6 +1679,10 @@ static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, VkDisplaySurfaceCreateInfoKHR create_info = { VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR }; VkDisplayModeKHR best_mode = VK_NULL_HANDLE; + /* We need to decide on GPU here to be able to query support. */ + if (!vulkan_context_init_gpu(vk)) + return false; + VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, vkGetPhysicalDeviceDisplayPropertiesKHR); VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(vk->context.instance, @@ -1698,7 +1740,8 @@ static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, for (i = 0; i < mode_count; i++) { const VkDisplayModePropertiesKHR *mode = &modes[i]; - vulkan_update_display_mode(&best_mode, width, height, mode, info); + if (vulkan_update_display_mode(width, height, mode, info)) + best_mode = modes[i].displayMode; } free(modes); diff --git a/gfx/drivers_context/khr_display_ctx.c b/gfx/drivers_context/khr_display_ctx.c new file mode 100644 index 0000000000..1ab7ec45e8 --- /dev/null +++ b/gfx/drivers_context/khr_display_ctx.c @@ -0,0 +1,260 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2016 - Hans-Kristian Arntzen + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include "../../driver.h" +#include "../../general.h" +#include "../../runloop.h" +#include "../common/vulkan_common.h" + +typedef struct +{ + gfx_ctx_vulkan_data_t vk; + unsigned swap_interval; + unsigned width; + unsigned height; +} khr_display_ctx_data_t; + +static void gfx_ctx_khr_display_destroy(void *data) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + if (!khr) + return; + + vulkan_context_destroy(&khr->vk, true); +#ifdef HAVE_THREADS + if (khr->vk.context.queue_lock) + slock_free(khr->vk.context.queue_lock); +#endif + free(khr); +} + +static void gfx_ctx_khr_display_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + + *width = khr->width; + *height = khr->height; +} + +static void *gfx_ctx_khr_display_init(void *video_driver) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)calloc(1, sizeof(*khr)); + if (!khr) + return NULL; + + if (!vulkan_context_init(&khr->vk, VULKAN_WSI_DISPLAY)) + { + RARCH_ERR("[Vulkan]: Failed to create Vulkan context.\n"); + goto error; + } + + return khr; + +error: + gfx_ctx_khr_display_destroy(khr); + return NULL; +} + +static void gfx_ctx_khr_display_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height, unsigned frame_count) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + (void)frame_count; + + *resize = khr->vk.need_new_swapchain; + + if (khr->width != *width || khr->height != *height) + { + *width = khr->width; + *height = khr->height; + *resize = true; + } + + if (runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL)) + *quit = true; +} + +static bool gfx_ctx_khr_display_set_resize(void *data, + unsigned width, unsigned height) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + + khr->width = width; + khr->height = height; + if (!vulkan_create_swapchain(&khr->vk, khr->width, khr->height, khr->swap_interval)) + { + RARCH_ERR("[Vulkan]: Failed to update swapchain.\n"); + return false; + } + + khr->vk.context.invalid_swapchain = true; + khr->vk.need_new_swapchain = false; + return false; +} + +static void gfx_ctx_khr_display_update_window_title(void *data) +{ + char buf[128] = {0}; + char buf_fps[128] = {0}; + settings_t *settings = config_get_ptr(); + + (void)data; + + video_monitor_get_fps(buf, sizeof(buf), + buf_fps, sizeof(buf_fps)); + if (settings->fps_show) + runloop_msg_queue_push(buf_fps, 1, 1, false); +} + +static bool gfx_ctx_khr_display_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + + if (!fullscreen) + { + width = 0; + height = 0; + } + + struct vulkan_display_surface_info info = { width, height }; + if (!vulkan_surface_create(&khr->vk, VULKAN_WSI_DISPLAY, &info, NULL, + 0, 0, khr->swap_interval)) + { + RARCH_ERR("[Vulkan]: Failed to create KHR_display surface.\n"); + goto error; + } + + khr->width = khr->vk.context.swapchain_width; + khr->height = khr->vk.context.swapchain_height; + + return true; + +error: + gfx_ctx_khr_display_destroy(data); + return false; +} + +static void gfx_ctx_khr_display_input_driver(void *data, + const input_driver_t **input, void **input_data) +{ + (void)data; + *input = NULL; + *input_data = NULL; +} + +static bool gfx_ctx_khr_display_bind_api(void *data, + enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + (void)data; + (void)major; + (void)minor; + return api == GFX_CTX_VULKAN_API; +} + +static bool gfx_ctx_khr_display_has_focus(void *data) +{ + (void)data; + return true; +} + +static bool gfx_ctx_khr_display_suppress_screensaver(void *data, bool enable) +{ + (void)data; + (void)enable; + return false; +} + +static bool gfx_ctx_khr_display_has_windowed(void *data) +{ + (void)data; + return false; +} + +static void gfx_ctx_khr_display_set_swap_interval(void *data, unsigned swap_interval) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + if (khr->swap_interval != swap_interval) + { + khr->swap_interval = swap_interval; + if (khr->vk.swapchain) + khr->vk.need_new_swapchain = true; + } +} + +static void gfx_ctx_khr_display_swap_buffers(void *data) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + vulkan_present(&khr->vk, khr->vk.context.current_swapchain_index); + vulkan_acquire_next_image(&khr->vk); +} + +static gfx_ctx_proc_t gfx_ctx_khr_display_get_proc_address(const char *symbol) +{ + return NULL; +} + +static uint32_t gfx_ctx_khr_display_get_flags(void *data) +{ + uint32_t flags = 0; + BIT32_SET(flags, GFX_CTX_FLAGS_NONE); + return flags; +} + +static void gfx_ctx_khr_display_set_flags(void *data, uint32_t flags) +{ + (void)data; +} + +static void *gfx_ctx_khr_display_get_context_data(void *data) +{ + khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; + return &khr->vk.context; +} + +const gfx_ctx_driver_t gfx_ctx_khr_display = { + gfx_ctx_khr_display_init, + gfx_ctx_khr_display_destroy, + gfx_ctx_khr_display_bind_api, + gfx_ctx_khr_display_set_swap_interval, + gfx_ctx_khr_display_set_video_mode, + gfx_ctx_khr_display_get_video_size, + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + NULL, /* get_metrics */ + NULL, + gfx_ctx_khr_display_update_window_title, + gfx_ctx_khr_display_check_window, + gfx_ctx_khr_display_set_resize, + gfx_ctx_khr_display_has_focus, + gfx_ctx_khr_display_suppress_screensaver, + gfx_ctx_khr_display_has_windowed, + gfx_ctx_khr_display_swap_buffers, + gfx_ctx_khr_display_input_driver, + gfx_ctx_khr_display_get_proc_address, + NULL, + NULL, + NULL, + "khr_display", + gfx_ctx_khr_display_get_flags, + gfx_ctx_khr_display_set_flags, + NULL, + gfx_ctx_khr_display_get_context_data, +}; + diff --git a/gfx/video_context_driver.c b/gfx/video_context_driver.c index 6df37d8023..a2cb8a196d 100644 --- a/gfx/video_context_driver.c +++ b/gfx/video_context_driver.c @@ -80,6 +80,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { #endif #ifdef EMSCRIPTEN &gfx_ctx_emscripten, +#endif +#ifdef HAVE_VULKAN + &gfx_ctx_khr_display, #endif &gfx_ctx_null, NULL diff --git a/gfx/video_context_driver.h b/gfx/video_context_driver.h index c98ca0ebb2..e4bba14826 100644 --- a/gfx/video_context_driver.h +++ b/gfx/video_context_driver.h @@ -243,6 +243,7 @@ extern const gfx_ctx_driver_t gfx_ctx_cgl; extern const gfx_ctx_driver_t gfx_ctx_cocoagl; extern const gfx_ctx_driver_t gfx_ctx_emscripten; extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; +extern const gfx_ctx_driver_t gfx_ctx_khr_display; extern const gfx_ctx_driver_t gfx_ctx_null; /** From af52f1532f7df172bb61da963f6b2cd603e5c22e Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 7 Jul 2016 16:56:07 +0000 Subject: [PATCH 5/6] Fix Vulkan test core build with includes. --- cores/libretro-test-vulkan/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/libretro-test-vulkan/Makefile b/cores/libretro-test-vulkan/Makefile index db8f8c735d..c41feb44f4 100644 --- a/cores/libretro-test-vulkan/Makefile +++ b/cores/libretro-test-vulkan/Makefile @@ -43,7 +43,7 @@ else CFLAGS += -O3 endif -CFLAGS += -std=gnu99 +CFLAGS += -std=gnu99 -I../../gfx/include OBJECTS := libretro-test.o ../../libretro-common/vulkan/vulkan_symbol_wrapper.o CFLAGS += -Wall -pedantic $(fpic) From c561d8c4e612a4f74c7a4dabd77277b35a495d66 Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Thu, 7 Jul 2016 19:32:09 +0200 Subject: [PATCH 6/6] Install sighandler for khr_display backend. --- gfx/drivers_context/khr_display_ctx.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/gfx/drivers_context/khr_display_ctx.c b/gfx/drivers_context/khr_display_ctx.c index 1ab7ec45e8..b4c0b8f209 100644 --- a/gfx/drivers_context/khr_display_ctx.c +++ b/gfx/drivers_context/khr_display_ctx.c @@ -14,6 +14,7 @@ */ #include +#include #include "../../driver.h" #include "../../general.h" #include "../../runloop.h" @@ -27,6 +28,14 @@ typedef struct unsigned height; } khr_display_ctx_data_t; +static volatile sig_atomic_t g_khr_quit; +static void khr_sighandler(int sig) +{ + if (g_khr_quit) + exit(1); + g_khr_quit = 1; +} + static void gfx_ctx_khr_display_destroy(void *data) { khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)data; @@ -52,6 +61,7 @@ static void gfx_ctx_khr_display_get_video_size(void *data, static void *gfx_ctx_khr_display_init(void *video_driver) { + struct sigaction sa; khr_display_ctx_data_t *khr = (khr_display_ctx_data_t*)calloc(1, sizeof(*khr)); if (!khr) return NULL; @@ -62,6 +72,13 @@ static void *gfx_ctx_khr_display_init(void *video_driver) goto error; } + sa.sa_sigaction = NULL; + sa.sa_handler = khr_sighandler; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + return khr; error: @@ -84,7 +101,7 @@ static void gfx_ctx_khr_display_check_window(void *data, bool *quit, *resize = true; } - if (runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL)) + if (runloop_ctl(RUNLOOP_CTL_IS_SHUTDOWN, NULL) || g_khr_quit) *quit = true; }