mirror of
https://github.com/CTCaer/RetroArch.git
synced 2024-12-22 10:49:02 +00:00
Merge pull request #3197 from Themaister/khr_display
Initial implementation of VK_KHR_display backend.
This commit is contained in:
commit
eacd59b841
@ -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 \
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
277
gfx/drivers_context/khr_display_ctx.c
Normal file
277
gfx/drivers_context/khr_display_ctx.c
Normal 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,
|
||||||
|
};
|
||||||
|
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user