Merge pull request #3197 from Themaister/khr_display

Initial implementation of VK_KHR_display backend.
This commit is contained in:
Twinaphex 2016-07-07 19:36:58 +02:00 committed by GitHub
commit eacd59b841
8 changed files with 572 additions and 54 deletions

View File

@ -842,6 +842,7 @@ ifeq ($(HAVE_VULKAN), 1)
OBJ += gfx/drivers/vulkan.o \ OBJ += gfx/drivers/vulkan.o \
gfx/common/vulkan_common.o \ gfx/common/vulkan_common.o \
gfx/drivers_context/khr_display_ctx.o \
libretro-common/vulkan/vulkan_symbol_wrapper.o \ libretro-common/vulkan/vulkan_symbol_wrapper.o \
gfx/drivers_font/vulkan_raster_font.o \ gfx/drivers_font/vulkan_raster_font.o \
gfx/drivers_shader/shader_vulkan.o \ gfx/drivers_shader/shader_vulkan.o \

View File

@ -43,7 +43,7 @@ else
CFLAGS += -O3 CFLAGS += -O3
endif endif
CFLAGS += -std=gnu99 CFLAGS += -std=gnu99 -I../../gfx/include
OBJECTS := libretro-test.o ../../libretro-common/vulkan/vulkan_symbol_wrapper.o OBJECTS := libretro-test.o ../../libretro-common/vulkan/vulkan_symbol_wrapper.o
CFLAGS += -Wall -pedantic $(fpic) CFLAGS += -Wall -pedantic $(fpic)

View File

@ -1202,6 +1202,47 @@ end:
return ret; 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) static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
{ {
bool use_device_ext; bool use_device_ext;
@ -1209,9 +1250,7 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
VkResult res; VkResult res;
unsigned i; unsigned i;
static const float one = 1.0f; static const float one = 1.0f;
uint32_t gpu_count = 1;
bool found_queue = false; bool found_queue = false;
VkPhysicalDevice *gpus = NULL;
VkPhysicalDeviceFeatures features = { false }; VkPhysicalDeviceFeatures features = { false };
VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; 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 }; const VkPhysicalDeviceFeatures features = { 0 };
bool ret = iface->create_device(&context, vk->context.instance, bool ret = iface->create_device(&context, vk->context.instance,
VK_NULL_HANDLE, vk->context.gpu,
vk->vk_surface, vk->vk_surface,
vulkan_symbol_wrapper_instance_proc_addr(), vulkan_symbol_wrapper_instance_proc_addr(),
device_extensions, device_extensions,
@ -1287,39 +1326,8 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk)
cached_destroy_device = NULL; cached_destroy_device = NULL;
} }
if (vk->context.gpu == VK_NULL_HANDLE) if (!vulkan_context_init_gpu(vk))
{ return false;
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);
}
vkGetPhysicalDeviceProperties(vk->context.gpu, vkGetPhysicalDeviceProperties(vk->context.gpu,
&vk->context.gpu_properties); &vk->context.gpu_properties);
@ -1435,12 +1443,13 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
VkResult res; VkResult res;
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
const char *instance_extensions[4];
unsigned ext_count = 0;
#ifdef VULKAN_DEBUG #ifdef VULKAN_DEBUG
const char *instance_extensions[3]; instance_extensions[ext_count++] = "VK_EXT_debug_report";
instance_extensions[2] = "VK_EXT_debug_report";
static const char *instance_layers[] = { "VK_LAYER_LUNARG_standard_validation" }; static const char *instance_layers[] = { "VK_LAYER_LUNARG_standard_validation" };
#else
const char *instance_extensions[2];
#endif #endif
bool use_instance_ext; bool use_instance_ext;
@ -1459,31 +1468,33 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
iface = NULL; iface = NULL;
} }
instance_extensions[0] = "VK_KHR_surface"; instance_extensions[ext_count++] = "VK_KHR_surface";
switch (type) switch (type)
{ {
case VULKAN_WSI_WAYLAND: case VULKAN_WSI_WAYLAND:
instance_extensions[1] = "VK_KHR_wayland_surface"; instance_extensions[ext_count++] = "VK_KHR_wayland_surface";
break; break;
case VULKAN_WSI_ANDROID: case VULKAN_WSI_ANDROID:
instance_extensions[1] = "VK_KHR_android_surface"; instance_extensions[ext_count++] = "VK_KHR_android_surface";
break; break;
case VULKAN_WSI_WIN32: case VULKAN_WSI_WIN32:
instance_extensions[1] = "VK_KHR_win32_surface"; instance_extensions[ext_count++] = "VK_KHR_win32_surface";
break; break;
case VULKAN_WSI_XLIB: case VULKAN_WSI_XLIB:
instance_extensions[1] = "VK_KHR_xlib_surface"; instance_extensions[ext_count++] = "VK_KHR_xlib_surface";
break; break;
case VULKAN_WSI_XCB: case VULKAN_WSI_XCB:
instance_extensions[1] = "VK_KHR_xcb_surface"; instance_extensions[ext_count++] = "VK_KHR_xcb_surface";
break; break;
case VULKAN_WSI_MIR: 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; break;
case VULKAN_WSI_NONE: case VULKAN_WSI_NONE:
default: default:
instance_extensions[1] = NULL;
break; break;
} }
@ -1521,7 +1532,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
return false; 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.pApplicationName = "RetroArch";
app.applicationVersion = 0; app.applicationVersion = 0;
@ -1530,7 +1541,7 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
app.apiVersion = VK_MAKE_VERSION(1, 0, 18); app.apiVersion = VK_MAKE_VERSION(1, 0, 18);
info.pApplicationInfo = &app; 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; info.ppEnabledExtensionNames = use_instance_ext ? instance_extensions : NULL;
#ifdef VULKAN_DEBUG #ifdef VULKAN_DEBUG
info.enabledLayerCount = ARRAY_SIZE(instance_layers); info.enabledLayerCount = ARRAY_SIZE(instance_layers);
@ -1608,6 +1619,214 @@ bool vulkan_context_init(gfx_ctx_vulkan_data_t *vk,
return true; return true;
} }
static bool vulkan_update_display_mode(
unsigned *width,
unsigned *height,
const VkDisplayModePropertiesKHR *mode,
const struct vulkan_display_surface_info *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,
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;
/* 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,
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);
#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];
if (vulkan_update_display_mode(width, height, mode, info))
best_mode = modes[i].displayMode;
}
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, bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
enum vulkan_wsi_type type, enum vulkan_wsi_type type,
void *display, void *surface, void *display, void *surface,
@ -1751,6 +1970,14 @@ bool vulkan_surface_create(gfx_ctx_vulkan_data_t *vk,
} }
#endif #endif
break; 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: case VULKAN_WSI_NONE:
default: default:
return false; return false;

View File

@ -82,7 +82,8 @@ enum vulkan_wsi_type
VULKAN_WSI_ANDROID, VULKAN_WSI_ANDROID,
VULKAN_WSI_WIN32, VULKAN_WSI_WIN32,
VULKAN_WSI_XCB, VULKAN_WSI_XCB,
VULKAN_WSI_XLIB VULKAN_WSI_XLIB,
VULKAN_WSI_DISPLAY
}; };
typedef struct vulkan_context typedef struct vulkan_context
@ -125,6 +126,12 @@ typedef struct gfx_ctx_vulkan_data
bool need_new_swapchain; bool need_new_swapchain;
} gfx_ctx_vulkan_data_t; } gfx_ctx_vulkan_data_t;
struct vulkan_display_surface_info
{
unsigned width;
unsigned height;
};
struct vk_color struct vk_color
{ {
float r, g, b, a; float r, g, b, a;

View File

@ -0,0 +1,277 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <signal.h>
#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 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;
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)
{
struct sigaction sa;
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;
}
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:
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) || g_khr_quit)
*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,
};

View File

@ -177,8 +177,10 @@ static void display_handle_mode(void *data,
wl->width = width; wl->width = width;
wl->height = height; wl->height = height;
RARCH_LOG("[Wayland]: Video mode: %d x %d @ %d Hz.\n", /* Certain older Wayland implementations report in Hz,
width, height, refresh); * 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, static void display_handle_done(void *data,

View File

@ -80,6 +80,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = {
#endif #endif
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
&gfx_ctx_emscripten, &gfx_ctx_emscripten,
#endif
#ifdef HAVE_VULKAN
&gfx_ctx_khr_display,
#endif #endif
&gfx_ctx_null, &gfx_ctx_null,
NULL NULL

View File

@ -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_cocoagl;
extern const gfx_ctx_driver_t gfx_ctx_emscripten; 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_opendingux_fbdev;
extern const gfx_ctx_driver_t gfx_ctx_khr_display;
extern const gfx_ctx_driver_t gfx_ctx_null; extern const gfx_ctx_driver_t gfx_ctx_null;
/** /**