diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c
index 988f8cbe38..341fce4e87 100644
--- a/frontend/drivers/platform_unix.c
+++ b/frontend/drivers/platform_unix.c
@@ -190,6 +190,33 @@ error:
/* forward declaration */
bool android_run_events(void *data);
+void android_dpi_get_density(char *s, size_t len)
+{
+ static bool inited_once = false;
+ static bool inited2_once = false;
+ static char string[PROP_VALUE_MAX] = {0};
+ static char string2[PROP_VALUE_MAX] = {0};
+ if (!inited_once)
+ {
+ system_property_get("getprop", "ro.sf.lcd_density", string);
+ inited_once = true;
+ }
+
+ if (!string_is_empty(string))
+ {
+ strlcpy(s, string, len);
+ return;
+ }
+
+ if (!inited2_once)
+ {
+ system_property_get("wm", "density", string2);
+ inited2_once = true;
+ }
+
+ strlcpy(s, string2, len);
+}
+
void android_app_write_cmd(struct android_app *android_app, int8_t cmd)
{
if (!android_app)
diff --git a/frontend/drivers/platform_unix.h b/frontend/drivers/platform_unix.h
index 8a0485e6bc..13d6007b1c 100644
--- a/frontend/drivers/platform_unix.h
+++ b/frontend/drivers/platform_unix.h
@@ -346,6 +346,8 @@ extern JNIEnv *jni_thread_getenv(void);
void android_app_write_cmd(struct android_app *android_app, int8_t cmd);
+void android_dpi_get_density(char *s, size_t len);
+
extern struct android_app *g_android;
#endif
diff --git a/gfx/drivers_context/android_ctx.c b/gfx/drivers_context/android_ctx.c
index a82edda523..d00fa211f2 100644
--- a/gfx/drivers_context/android_ctx.c
+++ b/gfx/drivers_context/android_ctx.c
@@ -33,10 +33,6 @@
#include "../common/gl_common.h"
#endif
-#ifdef HAVE_VULKAN
-#include "../common/vulkan_common.h"
-#endif
-
#include "../../frontend/frontend_driver.h"
#include "../../frontend/drivers/platform_unix.h"
#include "../../verbosity.h"
@@ -53,18 +49,8 @@ typedef struct
#ifdef HAVE_EGL
egl_ctx_data_t egl;
#endif
-#ifdef HAVE_VULKAN
- gfx_ctx_vulkan_data_t vk;
- unsigned width;
- unsigned height;
- int swap_interval;
-#endif
} android_ctx_data_t;
-
-/* Forward declaration */
-int system_property_get(const char *cmd, const char *args, char *value);
-
/* TODO/FIXME - static global */
static enum gfx_ctx_api android_api = GFX_CTX_NONE;
#ifdef HAVE_OPENGLES
@@ -74,33 +60,13 @@ static bool g_es3 = false;
static void android_gfx_ctx_destroy(void *data)
{
android_ctx_data_t *and = (android_ctx_data_t*)data;
-#ifdef HAVE_VULKAN
- struct android_app *android_app = (struct android_app*)g_android;
-#endif
if (!and)
return;
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- egl_destroy(&and->egl);
+ egl_destroy(&and->egl);
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- vulkan_context_destroy(&and->vk, android_app->window);
-
- if (and->vk.context.queue_lock)
- slock_free(and->vk.context.queue_lock);
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
free(data);
}
@@ -126,7 +92,8 @@ static void *android_gfx_ctx_init(void *video_driver)
};
#endif
struct android_app *android_app = (struct android_app*)g_android;
- android_ctx_data_t *and = (android_ctx_data_t*)calloc(1, sizeof(*and));
+ android_ctx_data_t *and = (android_ctx_data_t*)
+ calloc(1, sizeof(*and));
if (!android_app || !and)
return false;
@@ -136,56 +103,33 @@ static void *android_gfx_ctx_init(void *video_driver)
attribs[1] = EGL_OPENGL_ES3_BIT_KHR;
#endif
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- RARCH_LOG("Android EGL: GLES version = %d.\n", g_es3 ? 3 : 2);
+ RARCH_LOG("Android EGL: GLES version = %d.\n", g_es3 ? 3 : 2);
- if (!egl_init_context(&and->egl, EGL_NONE, EGL_DEFAULT_DISPLAY,
- &major, &minor, &n, attribs, NULL))
- {
- egl_report_error();
- goto error;
- }
-
- if (!egl_get_native_visual_id(&and->egl, &format))
- goto error;
-#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- if (!vulkan_context_init(&and->vk, VULKAN_WSI_ANDROID))
- goto error;
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
+ if (!egl_init_context(&and->egl, EGL_NONE, EGL_DEFAULT_DISPLAY,
+ &major, &minor, &n, attribs, NULL))
+ {
+ egl_report_error();
+ goto error;
}
+ if (!egl_get_native_visual_id(&and->egl, &format))
+ goto error;
+#endif
+
slock_lock(android_app->mutex);
if (!android_app->window)
- goto unlock_error;
-
- switch (android_api)
{
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
- ANativeWindow_setBuffersGeometry(android_app->window, 0, 0, format);
-
- break;
- case GFX_CTX_NONE:
- default:
- break;
+ slock_unlock(android_app->mutex);
+ android_gfx_ctx_destroy(and);
+ return NULL;
}
+ ANativeWindow_setBuffersGeometry(android_app->window, 0, 0, format);
+
slock_unlock(android_app->mutex);
return and;
-unlock_error:
- slock_unlock(android_app->mutex);
error:
android_gfx_ctx_destroy(and);
@@ -197,66 +141,23 @@ static void android_gfx_ctx_get_video_size(void *data,
{
android_ctx_data_t *and = (android_ctx_data_t*)data;
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- egl_get_video_size(&and->egl, width, height);
+ egl_get_video_size(&and->egl, width, height);
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- *width = and->width;
- *height = and->height;
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
}
static void android_gfx_ctx_check_window(void *data, bool *quit,
bool *resize, unsigned *width, unsigned *height)
{
-#ifdef HAVE_VULKAN
- struct android_app *android_app = (struct android_app*)g_android;
-#endif
-
unsigned new_width = 0;
unsigned new_height = 0;
android_ctx_data_t *and = (android_ctx_data_t*)data;
- *quit = false;
+ *quit = false;
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- egl_get_video_size(&and->egl, &new_width, &new_height);
+ egl_get_video_size(&and->egl, &new_width, &new_height);
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- if (android_app->content_rect.changed)
- {
- and->vk.need_new_swapchain = true;
- android_app->content_rect.changed = false;
- }
-
- /* Swapchains are recreated in set_resize as a
- * central place, so use that to trigger swapchain reinit. */
- *resize = and->vk.need_new_swapchain;
- new_width = android_app->content_rect.width;
- new_height = android_app->content_rect.height;
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
if (new_width != *width || new_height != *height)
{
@@ -270,54 +171,17 @@ static void android_gfx_ctx_check_window(void *data, bool *quit,
}
static bool android_gfx_ctx_set_resize(void *data,
- unsigned width, unsigned height)
-{
-#ifdef HAVE_VULKAN
- android_ctx_data_t *and = (android_ctx_data_t*)data;
- struct android_app *android_app = (struct android_app*)g_android;
-#endif
- (void)data;
- (void)width;
- (void)height;
-
- switch (android_api)
- {
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- and->width = android_app->content_rect.width;
- and->height = android_app->content_rect.height;
- RARCH_LOG("[Android]: Native window size: %u x %u.\n", and->width, and->height);
- if (!vulkan_create_swapchain(&and->vk, and->width, and->height, and->swap_interval))
- {
- RARCH_ERR("[Android]: Failed to update swapchain.\n");
- return false;
- }
-
- if (and->vk.created_new_swapchain)
- vulkan_acquire_next_image(&and->vk);
- and->vk.context.invalid_swapchain = true;
- and->vk.need_new_swapchain = false;
-#endif
- break;
-
- case GFX_CTX_NONE:
- default:
- break;
- }
-
- return false;
-}
+ unsigned width, unsigned height) { return false; }
static bool android_gfx_ctx_set_video_mode(void *data,
unsigned width, unsigned height,
bool fullscreen)
{
-#if defined(HAVE_OPENGLES) || defined(HAVE_VULKAN)
+#if defined(HAVE_OPENGLES)
struct android_app *android_app = (struct android_app*)g_android;
- android_ctx_data_t *and = (android_ctx_data_t*)data;
-#endif
-#if defined(HAVE_OPENGLES) && defined(HAVE_EGL)
- EGLint context_attributes[] = {
+ android_ctx_data_t *and = (android_ctx_data_t*)data;
+#if defined(HAVE_EGL)
+ EGLint context_attributes[] = {
EGL_CONTEXT_CLIENT_VERSION, g_es3 ? 3 : 2,
#if 0
EGL_CONTEXT_FLAGS_KHR, debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0,
@@ -325,10 +189,7 @@ static bool android_gfx_ctx_set_video_mode(void *data,
EGL_NONE
};
#endif
-
- (void)width;
- (void)height;
- (void)fullscreen;
+#endif
switch (android_api)
{
@@ -344,19 +205,6 @@ static bool android_gfx_ctx_set_video_mode(void *data,
if (!egl_create_surface(&and->egl, android_app->window))
return false;
-#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- and->width = ANativeWindow_getWidth(android_app->window);
- and->height = ANativeWindow_getHeight(android_app->window);
- RARCH_LOG("[Android]: Native window size: %u x %u.\n", and->width, and->height);
- if (!vulkan_surface_create(&and->vk, VULKAN_WSI_ANDROID, NULL, android_app->window,
- and->width, and->height, and->swap_interval))
- {
- RARCH_ERR("[Android]: Failed to create surface.\n");
- return false;
- }
#endif
break;
@@ -387,36 +235,20 @@ static bool android_gfx_ctx_bind_api(void *data,
enum gfx_ctx_api api, unsigned major, unsigned minor)
{
unsigned version;
-
android_api = api;
- switch (api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_OPENGLES
- version = major * 100 + minor;
- if (version > 300)
- return false;
- if (version < 300)
- g_es3 = false;
- else if (version == 300)
- g_es3 = true;
+ version = major * 100 + minor;
+ if (version > 300)
+ return false;
+ if (version < 300)
+ g_es3 = false;
+ else if (version == 300)
+ g_es3 = true;
- if (api == GFX_CTX_OPENGL_ES_API)
- return true;
+ if (api == GFX_CTX_OPENGL_ES_API)
+ return true;
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- return true;
-#else
- break;
-#endif
- case GFX_CTX_NONE:
- default:
- break;
- }
return false;
}
@@ -435,39 +267,7 @@ static bool android_gfx_ctx_has_focus(void *data)
return focused;
}
-static bool android_gfx_ctx_suppress_screensaver(void *data, bool enable)
-{
- (void)data;
- (void)enable;
- return false;
-}
-
-static void dpi_get_density(char *s, size_t len)
-{
- static bool inited_once = false;
- static bool inited2_once = false;
- static char string[PROP_VALUE_MAX] = {0};
- static char string2[PROP_VALUE_MAX] = {0};
- if (!inited_once)
- {
- system_property_get("getprop", "ro.sf.lcd_density", string);
- inited_once = true;
- }
-
- if (!string_is_empty(string))
- {
- strlcpy(s, string, len);
- return;
- }
-
- if (!inited2_once)
- {
- system_property_get("wm", "density", string2);
- inited2_once = true;
- }
-
- strlcpy(s, string2, len);
-}
+static bool android_gfx_ctx_suppress_screensaver(void *data, bool enable) { return false; }
static bool android_gfx_ctx_get_metrics(void *data,
enum display_metric_types type, float *value)
@@ -477,7 +277,6 @@ static bool android_gfx_ctx_get_metrics(void *data,
switch (type)
{
case DISPLAY_METRIC_MM_WIDTH:
- return false;
case DISPLAY_METRIC_MM_HEIGHT:
return false;
case DISPLAY_METRIC_DPI:
@@ -486,7 +285,7 @@ static bool android_gfx_ctx_get_metrics(void *data,
char density[PROP_VALUE_MAX];
density[0] = '\0';
- dpi_get_density(density, sizeof(density));
+ android_dpi_get_density(density, sizeof(density));
if (string_is_empty(density))
goto dpi_fallback;
dpi = atoi(density);
@@ -516,121 +315,44 @@ static void android_gfx_ctx_swap_buffers(void *data)
{
android_ctx_data_t *and = (android_ctx_data_t*)data;
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- egl_swap_buffers(&and->egl);
+ egl_swap_buffers(&and->egl);
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- vulkan_present(&and->vk, and->vk.context.current_swapchain_index);
- vulkan_acquire_next_image(&and->vk);
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
}
static void android_gfx_ctx_set_swap_interval(void *data, int swap_interval)
{
android_ctx_data_t *and = (android_ctx_data_t*)data;
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- egl_set_swap_interval(&and->egl, swap_interval);
+ egl_set_swap_interval(&and->egl, swap_interval);
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#ifdef HAVE_VULKAN
- if (and->swap_interval != swap_interval)
- {
- RARCH_LOG("[Vulkan]: Setting swap interval: %u.\n", swap_interval);
- and->swap_interval = swap_interval;
- if (and->vk.swapchain)
- and->vk.need_new_swapchain = true;
- }
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
}
static gfx_ctx_proc_t android_gfx_ctx_get_proc_address(const char *symbol)
{
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- return egl_get_proc_address(symbol);
+ return egl_get_proc_address(symbol);
#else
- break;
-#endif
- case GFX_CTX_NONE:
- default:
- break;
- }
-
return NULL;
+#endif
}
static void android_gfx_ctx_bind_hw_render(void *data, bool enable)
{
android_ctx_data_t *and = (android_ctx_data_t*)data;
-
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_EGL
- egl_bind_hw_render(&and->egl, enable);
+ egl_bind_hw_render(&and->egl, enable);
#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
}
-#ifdef HAVE_VULKAN
-static void *android_gfx_ctx_get_context_data(void *data)
-{
- android_ctx_data_t *and = (android_ctx_data_t*)data;
- return &and->vk.context;
-}
-#endif
-
static uint32_t android_gfx_ctx_get_flags(void *data)
{
uint32_t flags = 0;
- switch (android_api)
- {
- case GFX_CTX_OPENGL_API:
- case GFX_CTX_OPENGL_ES_API:
#ifdef HAVE_GLSL
- BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL);
+ BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL);
#endif
- break;
- case GFX_CTX_VULKAN_API:
-#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
- BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
-#endif
- break;
- case GFX_CTX_NONE:
- default:
- break;
- }
return flags;
}
@@ -667,10 +389,6 @@ const gfx_ctx_driver_t gfx_ctx_android = {
android_gfx_ctx_get_flags,
android_gfx_ctx_set_flags,
android_gfx_ctx_bind_hw_render,
-#ifdef HAVE_VULKAN
- android_gfx_ctx_get_context_data,
-#else
NULL,
-#endif
NULL
};
diff --git a/gfx/drivers_context/android_vk_ctx.c b/gfx/drivers_context/android_vk_ctx.c
new file mode 100644
index 0000000000..d959974a72
--- /dev/null
+++ b/gfx/drivers_context/android_vk_ctx.c
@@ -0,0 +1,329 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2017 - Daniel De Matteis
+ *
+ * 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
+
+#include
+#include
+#include
+
+#ifdef HAVE_CONFIG_H
+#include "../../config.h"
+#endif
+
+#include "../common/vulkan_common.h"
+
+#include "../../frontend/frontend_driver.h"
+#include "../../frontend/drivers/platform_unix.h"
+#include "../../verbosity.h"
+#include "../../configuration.h"
+
+typedef struct
+{
+ gfx_ctx_vulkan_data_t vk;
+ unsigned width;
+ unsigned height;
+ int swap_interval;
+} android_ctx_data_vk_t;
+
+static void android_gfx_ctx_vk_destroy(void *data)
+{
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+ struct android_app *android_app = (struct android_app*)g_android;
+
+ if (!and)
+ return;
+
+ vulkan_context_destroy(&and->vk, android_app->window);
+
+ if (and->vk.context.queue_lock)
+ slock_free(and->vk.context.queue_lock);
+
+ free(data);
+}
+
+static void *android_gfx_ctx_vk_init(void *video_driver)
+{
+ struct android_app *android_app = (struct android_app*)g_android;
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)calloc(1, sizeof(*and));
+
+ if (!android_app || !and)
+ return false;
+
+ if (!vulkan_context_init(&and->vk, VULKAN_WSI_ANDROID))
+ goto error;
+
+ slock_lock(android_app->mutex);
+ if (!android_app->window)
+ {
+ slock_unlock(android_app->mutex);
+ android_gfx_ctx_vk_destroy(and);
+ return NULL;
+ }
+
+ slock_unlock(android_app->mutex);
+ return and;
+
+error:
+ android_gfx_ctx_vk_destroy(and);
+
+ return NULL;
+}
+
+static void android_gfx_ctx_vk_get_video_size(void *data,
+ unsigned *width, unsigned *height)
+{
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+
+ *width = and->width;
+ *height = and->height;
+}
+
+static void android_gfx_ctx_vk_check_window(void *data, bool *quit,
+ bool *resize, unsigned *width, unsigned *height)
+{
+ struct android_app *android_app = (struct android_app*)g_android;
+
+ unsigned new_width = 0;
+ unsigned new_height = 0;
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+
+ *quit = false;
+
+ if (android_app->content_rect.changed)
+ {
+ and->vk.need_new_swapchain = true;
+ android_app->content_rect.changed = false;
+ }
+
+ /* Swapchains are recreated in set_resize as a
+ * central place, so use that to trigger swapchain reinit. */
+ *resize = and->vk.need_new_swapchain;
+ new_width = android_app->content_rect.width;
+ new_height = android_app->content_rect.height;
+
+ if (new_width != *width || new_height != *height)
+ {
+ RARCH_LOG("[Android]: Resizing (%u x %u) -> (%u x %u).\n",
+ *width, *height, new_width, new_height);
+
+ *width = new_width;
+ *height = new_height;
+ *resize = true;
+ }
+}
+
+static bool android_gfx_ctx_vk_set_resize(void *data,
+ unsigned width, unsigned height)
+{
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+ struct android_app *android_app = (struct android_app*)g_android;
+
+ and->width = android_app->content_rect.width;
+ and->height = android_app->content_rect.height;
+ RARCH_LOG("[Android]: Native window size: %u x %u.\n", and->width, and->height);
+ if (!vulkan_create_swapchain(&and->vk, and->width, and->height, and->swap_interval))
+ {
+ RARCH_ERR("[Android]: Failed to update swapchain.\n");
+ return false;
+ }
+
+ if (and->vk.created_new_swapchain)
+ vulkan_acquire_next_image(&and->vk);
+ and->vk.context.invalid_swapchain = true;
+ and->vk.need_new_swapchain = false;
+
+ return false;
+}
+
+static bool android_gfx_ctx_vk_set_video_mode(void *data,
+ unsigned width, unsigned height,
+ bool fullscreen)
+{
+ struct android_app *android_app = (struct android_app*)g_android;
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+
+ and->width = ANativeWindow_getWidth(android_app->window);
+ and->height = ANativeWindow_getHeight(android_app->window);
+ RARCH_LOG("[Android]: Native window size: %u x %u.\n", and->width, and->height);
+ if (!vulkan_surface_create(&and->vk, VULKAN_WSI_ANDROID, NULL, android_app->window,
+ and->width, and->height, and->swap_interval))
+ {
+ RARCH_ERR("[Android]: Failed to create surface.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static void android_gfx_ctx_vk_input_driver(void *data,
+ const char *joypad_name,
+ input_driver_t **input, void **input_data)
+{
+ void *androidinput = input_android.init(joypad_name);
+
+ *input = androidinput ? &input_android : NULL;
+ *input_data = androidinput;
+}
+
+static enum gfx_ctx_api android_gfx_ctx_vk_get_api(void *data)
+{
+ return GFX_CTX_VULKAN_API;
+}
+
+static bool android_gfx_ctx_vk_bind_api(void *data,
+ enum gfx_ctx_api api, unsigned major, unsigned minor)
+{
+ if (api == GFX_CTX_VULKAN_API)
+ return true;
+ return false;
+}
+
+static bool android_gfx_ctx_vk_has_focus(void *data)
+{
+ bool focused = false;
+ struct android_app *android_app = (struct android_app*)g_android;
+ if (!android_app)
+ return true;
+
+ slock_lock(android_app->mutex);
+ focused = !android_app->unfocused;
+ slock_unlock(android_app->mutex);
+
+ return focused;
+}
+
+static bool android_gfx_ctx_vk_suppress_screensaver(void *data, bool enable) { return false; }
+
+static bool android_gfx_ctx_vk_get_metrics(void *data,
+ enum display_metric_types type, float *value)
+{
+ static int dpi = -1;
+
+ switch (type)
+ {
+ case DISPLAY_METRIC_MM_WIDTH:
+ case DISPLAY_METRIC_MM_HEIGHT:
+ return false;
+ case DISPLAY_METRIC_DPI:
+ if (dpi == -1)
+ {
+ char density[PROP_VALUE_MAX];
+ density[0] = '\0';
+
+ android_dpi_get_density(density, sizeof(density));
+ if (string_is_empty(density))
+ goto dpi_fallback;
+ dpi = atoi(density);
+
+ if (dpi <= 0)
+ goto dpi_fallback;
+ }
+ *value = (float)dpi;
+ break;
+ case DISPLAY_METRIC_NONE:
+ default:
+ *value = 0;
+ return false;
+ }
+
+ return true;
+
+dpi_fallback:
+ /* add a fallback in case the device doesn't report DPI.
+ * Hopefully fixes issues with the moto G2. */
+ dpi = 90;
+ *value = (float)dpi;
+ return true;
+}
+
+static void android_gfx_ctx_vk_swap_buffers(void *data)
+{
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+
+ vulkan_present(&and->vk, and->vk.context.current_swapchain_index);
+ vulkan_acquire_next_image(&and->vk);
+}
+
+static void android_gfx_ctx_vk_set_swap_interval(void *data, int swap_interval)
+{
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+
+ if (and->swap_interval != swap_interval)
+ {
+ RARCH_LOG("[Vulkan]: Setting swap interval: %u.\n", swap_interval);
+ and->swap_interval = swap_interval;
+ if (and->vk.swapchain)
+ and->vk.need_new_swapchain = true;
+ }
+}
+
+static gfx_ctx_proc_t android_gfx_ctx_vk_get_proc_address(const char *symbol) { return NULL; }
+static void android_gfx_ctx_vk_bind_hw_render(void *data, bool enable) { }
+
+static void *android_gfx_ctx_vk_get_context_data(void *data)
+{
+ android_ctx_data_vk_t *and = (android_ctx_data_vk_t*)data;
+ return &and->vk.context;
+}
+
+static uint32_t android_gfx_ctx_vk_get_flags(void *data)
+{
+ uint32_t flags = 0;
+
+#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
+ BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
+#endif
+
+ return flags;
+}
+
+static void android_gfx_ctx_vk_set_flags(void *data, uint32_t flags) { }
+
+const gfx_ctx_driver_t gfx_ctx_vk_android = {
+ android_gfx_ctx_vk_init,
+ android_gfx_ctx_vk_destroy,
+ android_gfx_ctx_vk_get_api,
+ android_gfx_ctx_vk_bind_api,
+ android_gfx_ctx_vk_set_swap_interval,
+ android_gfx_ctx_vk_set_video_mode,
+ android_gfx_ctx_vk_get_video_size,
+ NULL, /* get_refresh_rate */
+ NULL, /* get_video_output_size */
+ NULL, /* get_video_output_prev */
+ NULL, /* get_video_output_next */
+ android_gfx_ctx_vk_get_metrics,
+ NULL,
+ NULL, /* update_title */
+ android_gfx_ctx_vk_check_window,
+ android_gfx_ctx_vk_set_resize,
+ android_gfx_ctx_vk_has_focus,
+ android_gfx_ctx_vk_suppress_screensaver,
+ false, /* has_windowed */
+ android_gfx_ctx_vk_swap_buffers,
+ android_gfx_ctx_vk_input_driver,
+ android_gfx_ctx_vk_get_proc_address,
+ NULL,
+ NULL,
+ NULL,
+ "android_vk",
+ android_gfx_ctx_vk_get_flags,
+ android_gfx_ctx_vk_set_flags,
+ android_gfx_ctx_vk_bind_hw_render,
+ android_gfx_ctx_vk_get_context_data,
+ NULL
+};
diff --git a/griffin/griffin.c b/griffin/griffin.c
index f5b538f2fc..a926670d47 100644
--- a/griffin/griffin.c
+++ b/griffin/griffin.c
@@ -248,6 +248,9 @@ VIDEO CONTEXT
#include "../gfx/drivers_context/ps3_ctx.c"
#elif defined(ANDROID)
#include "../gfx/drivers_context/android_ctx.c"
+#if defined(HAVE_VULKAN)
+#include "../gfx/drivers_context/android_vk_ctx.c"
+#endif
#include "../gfx/display_servers/dispserv_android.c"
#elif defined(__QNX__)
#include "../gfx/drivers_context/qnx_ctx.c"
diff --git a/retroarch.c b/retroarch.c
index c5c1e9418d..c0074a134d 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -580,6 +580,9 @@ static const gfx_ctx_driver_t *gfx_ctx_vk_drivers[] = {
#if defined(_WIN32) && !defined(__WINRT__)
&gfx_ctx_w_vk,
#endif
+#if defined(ANDROID)
+ &gfx_ctx_vk_android,
+#endif
#if defined(HAVE_VULKAN_DISPLAY)
&gfx_ctx_khr_display,
#endif
diff --git a/retroarch.h b/retroarch.h
index a94a65fcc8..ec09d8ffe1 100644
--- a/retroarch.h
+++ b/retroarch.h
@@ -1892,6 +1892,7 @@ extern const gfx_ctx_driver_t gfx_ctx_go2_drm;
extern const gfx_ctx_driver_t gfx_ctx_mali_fbdev;
extern const gfx_ctx_driver_t gfx_ctx_vivante_fbdev;
extern const gfx_ctx_driver_t gfx_ctx_android;
+extern const gfx_ctx_driver_t gfx_ctx_vk_android;
extern const gfx_ctx_driver_t gfx_ctx_ps3;
extern const gfx_ctx_driver_t gfx_ctx_w_vk;
extern const gfx_ctx_driver_t gfx_ctx_wgl;