diff --git a/Makefile.common b/Makefile.common index ba5064da1b..80871d0e3d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1118,7 +1118,12 @@ OBJ += gfx/drivers_context/gfx_null_ctx.o ifeq ($(HAVE_KMS), 1) HAVE_AND_WILL_USE_DRM = 1 + +ifeq ($(HAVE_ODROIDGO2), 1) + OBJ += gfx/drivers_context/drm_go2_ctx.o +else OBJ += gfx/drivers_context/drm_ctx.o +endif DEF_FLAGS += $(GBM_CFLAGS) $(DRM_CFLAGS) LIBS += $(GBM_LIBS) $(DRM_LIBS) endif diff --git a/config.def.h b/config.def.h index 67cc9aa3d2..2737824b2b 100644 --- a/config.def.h +++ b/config.def.h @@ -340,6 +340,9 @@ #define DEFAULT_VIDEO_SMOOTH false #endif +/* Graphics context specific scaling */ +#define DEFAULT_VIDEO_CTX_SCALING false + /* On resize and fullscreen, rendering area will stay 4:3 */ #define DEFAULT_FORCE_ASPECT true diff --git a/configuration.c b/configuration.c index 6c918c598d..fcd8fb4519 100644 --- a/configuration.c +++ b/configuration.c @@ -1402,6 +1402,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("video_crop_overscan", &settings->bools.video_crop_overscan, true, DEFAULT_CROP_OVERSCAN, false); SETTING_BOOL("video_scale_integer", &settings->bools.video_scale_integer, true, DEFAULT_SCALE_INTEGER, false); SETTING_BOOL("video_smooth", &settings->bools.video_smooth, true, DEFAULT_VIDEO_SMOOTH, false); + SETTING_BOOL("video_ctx_scaling", &settings->bools.video_ctx_scaling, true, DEFAULT_VIDEO_CTX_SCALING, false); SETTING_BOOL("video_force_aspect", &settings->bools.video_force_aspect, true, DEFAULT_FORCE_ASPECT, false); SETTING_BOOL("video_threaded", video_driver_get_threaded(), true, DEFAULT_VIDEO_THREADED, false); SETTING_BOOL("video_shared_context", &settings->bools.video_shared_context, true, DEFAULT_VIDEO_SHARED_CONTEXT, false); diff --git a/configuration.h b/configuration.h index 445856b713..a86052f2f1 100644 --- a/configuration.h +++ b/configuration.h @@ -91,6 +91,7 @@ typedef struct settings bool video_black_frame_insertion; bool video_vfilter; bool video_smooth; + bool video_ctx_scaling; bool video_force_aspect; bool video_crop_overscan; bool video_aspect_ratio_auto; diff --git a/gfx/drivers/ctr_gfx.c b/gfx/drivers/ctr_gfx.c index f223fc8ba4..a7c4318267 100644 --- a/gfx/drivers/ctr_gfx.c +++ b/gfx/drivers/ctr_gfx.c @@ -1072,7 +1072,7 @@ static void ctr_set_rotation(void* data, unsigned rotation) ctr->rotation = rotation; ctr->should_resize = true; } -static void ctr_set_filtering(void* data, unsigned index, bool smooth) +static void ctr_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling) { ctr_video_t* ctr = (ctr_video_t*)data; diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index ba0546b730..8b15738328 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -236,7 +236,7 @@ static void d3d10_get_overlay_interface(void* data, const video_overlay_interfac } #endif -static void d3d10_set_filtering(void* data, unsigned index, bool smooth) +static void d3d10_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling) { unsigned i; d3d10_video_t* d3d10 = (d3d10_video_t*)data; @@ -784,7 +784,7 @@ static void *d3d10_gfx_init(const video_info_t* video, } } - d3d10_set_filtering(d3d10, 0, video->smooth); + d3d10_set_filtering(d3d10, 0, video->smooth, video->ctx_scaling); { D3D10_BUFFER_DESC desc; diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index cd4db5b4f0..ab7232e78b 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -254,7 +254,7 @@ static void d3d11_get_overlay_interface(void* data, const video_overlay_interfac } #endif -static void d3d11_set_filtering(void* data, unsigned index, bool smooth) +static void d3d11_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling) { unsigned i; d3d11_video_t* d3d11 = (d3d11_video_t*)data; @@ -859,7 +859,7 @@ static void *d3d11_gfx_init(const video_info_t* video, } } - d3d11_set_filtering(d3d11, 0, video->smooth); + d3d11_set_filtering(d3d11, 0, video->smooth, video->ctx_scaling); { D3D11_BUFFER_DESC desc; diff --git a/gfx/drivers/d3d12.c b/gfx/drivers/d3d12.c index 64d37569b6..74c12da9cc 100644 --- a/gfx/drivers/d3d12.c +++ b/gfx/drivers/d3d12.c @@ -224,7 +224,7 @@ static void d3d12_get_overlay_interface(void* data, const video_overlay_interfac } #endif -static void d3d12_set_filtering(void* data, unsigned index, bool smooth) +static void d3d12_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling) { int i; d3d12_video_t* d3d12 = (d3d12_video_t*)data; @@ -958,7 +958,7 @@ static void *d3d12_gfx_init(const video_info_t* video, #endif d3d12_init_samplers(d3d12); - d3d12_set_filtering(d3d12, 0, video->smooth); + d3d12_set_filtering(d3d12, 0, video->smooth, video->ctx_scaling); d3d12_create_fullscreen_quad_vbo(d3d12->device, &d3d12->frame.vbo_view, &d3d12->frame.vbo); d3d12_create_fullscreen_quad_vbo(d3d12->device, &d3d12->menu.vbo_view, &d3d12->menu.vbo); diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 6abbfef78e..b1d2eaf3a9 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -783,6 +783,11 @@ static void gl2_create_fbo_texture(gl_t *gl, bool smooth = false; settings_t *settings = config_get_ptr(); bool video_smooth = settings->bools.video_smooth; + bool video_ctx_scaling = settings->bools.video_ctx_scaling; +#if HAVE_ODROIDGO2 + if (video_ctx_scaling) + video_smooth = false; +#endif bool force_srgb_disable = settings->bools.video_force_srgb_disable; GLuint base_filt = video_smooth ? GL_LINEAR : GL_NEAREST; GLuint base_mip_filt = video_smooth ? @@ -3833,6 +3838,12 @@ static void *gl2_init(const video_info_t *video, gl->tex_w = gl->tex_h = (RARCH_SCALE_BASE * video->input_scale); gl->keep_aspect = video->force_aspect; +#if defined(HAVE_ODROIDGO2) + if (settings->bools.video_ctx_scaling) + gl->keep_aspect = false; + else +#endif + /* Apparently need to set viewport for passes * when we aren't using FBOs. */ gl2_set_shader_viewports(gl); @@ -3985,6 +3996,12 @@ static void gl2_update_tex_filter_frame(gl_t *gl) bool smooth = false; settings_t *settings = config_get_ptr(); bool video_smooth = settings->bools.video_smooth; + bool video_ctx_scaling = settings->bools.video_ctx_scaling; + +#ifdef HAVE_ODROIDGO2 + if (video_ctx_scaling) + video_smooth = false; +#endif gl2_context_bind_hw_render(gl, false); @@ -4345,6 +4362,10 @@ static void gl2_set_aspect_ratio(void *data, unsigned aspect_ratio_idx) return; gl->keep_aspect = true; +#if defined(HAVE_ODROIDGO2) + if (config_get_ptr()->bools.video_ctx_scaling) + gl->keep_aspect = false; +#endif gl->should_resize = true; } diff --git a/gfx/drivers/gx2_gfx.c b/gfx/drivers/gx2_gfx.c index 013ff5d4da..d0bf29ec8e 100644 --- a/gfx/drivers/gx2_gfx.c +++ b/gfx/drivers/gx2_gfx.c @@ -1600,7 +1600,7 @@ static void wiiu_gfx_unload_texture(void *data, uintptr_t handle) MEM2_free(texture->surface.image); free(texture); } -static void wiiu_gfx_set_filtering(void *data, unsigned index, bool smooth) +static void wiiu_gfx_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { wiiu_video_t *wiiu = (wiiu_video_t *) data; diff --git a/gfx/drivers/metal.m b/gfx/drivers/metal.m index 2a4ccac4e3..8ca56d686a 100644 --- a/gfx/drivers/metal.m +++ b/gfx/drivers/metal.m @@ -235,7 +235,7 @@ static float metal_get_refresh_rate(void *data) return 0.0f; } -static void metal_set_filtering(void *data, unsigned index, bool smooth) +static void metal_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { MetalDriver *md = (__bridge MetalDriver *)data; [md.frameView setFilteringIndex:index smooth:smooth]; diff --git a/gfx/drivers/ps2_gfx.c b/gfx/drivers/ps2_gfx.c index 35573faa65..5d6f86146b 100644 --- a/gfx/drivers/ps2_gfx.c +++ b/gfx/drivers/ps2_gfx.c @@ -400,7 +400,7 @@ static void ps2_gfx_free(void *data) static bool ps2_gfx_set_shader(void *data, enum rarch_shader_type type, const char *path) { return false; } -static void ps2_set_filtering(void *data, unsigned index, bool smooth) +static void ps2_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { ps2_video_t *ps2 = (ps2_video_t*)data; diff --git a/gfx/drivers/psp1_gfx.c b/gfx/drivers/psp1_gfx.c index bf0b74664f..3fd759e8ae 100644 --- a/gfx/drivers/psp1_gfx.c +++ b/gfx/drivers/psp1_gfx.c @@ -737,7 +737,7 @@ static void psp_set_rotation(void *data, unsigned rotation) psp->rotation = rotation; psp->should_resize = true; } -static void psp_set_filtering(void *data, unsigned index, bool smooth) +static void psp_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { psp1_video_t *psp = (psp1_video_t*)data; diff --git a/gfx/drivers/sdl2_gfx.c b/gfx/drivers/sdl2_gfx.c index b8ccbc4551..572cb6a5e7 100644 --- a/gfx/drivers/sdl2_gfx.c +++ b/gfx/drivers/sdl2_gfx.c @@ -628,7 +628,7 @@ static bool sdl2_gfx_read_viewport(void *data, uint8_t *buffer, bool is_idle) return true; } -static void sdl2_poke_set_filtering(void *data, unsigned index, bool smooth) +static void sdl2_poke_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { sdl2_video_t *vid = (sdl2_video_t*)data; vid->video.smooth = smooth; diff --git a/gfx/drivers/sdl_dingux_gfx.c b/gfx/drivers/sdl_dingux_gfx.c index 369417837e..352293de68 100644 --- a/gfx/drivers/sdl_dingux_gfx.c +++ b/gfx/drivers/sdl_dingux_gfx.c @@ -272,7 +272,7 @@ static void sdl_dingux_gfx_viewport_info(void *data, struct video_viewport *vp) vp->height = vp->full_height = vid->screen->h; } -static void sdl_dingux_set_filtering(void *data, unsigned index, bool smooth) +static void sdl_dingux_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { (void)data; } diff --git a/gfx/drivers/sdl_gfx.c b/gfx/drivers/sdl_gfx.c index b2148db4d8..43b7221305 100644 --- a/gfx/drivers/sdl_gfx.c +++ b/gfx/drivers/sdl_gfx.c @@ -459,7 +459,7 @@ static void sdl_gfx_viewport_info(void *data, struct video_viewport *vp) vp->height = vp->full_height = vid->screen->h; } -static void sdl_set_filtering(void *data, unsigned index, bool smooth) +static void sdl_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { sdl_video_t *vid = (sdl_video_t*)data; vid->scaler.scaler_type = smooth ? SCALER_TYPE_BILINEAR : SCALER_TYPE_POINT; diff --git a/gfx/drivers/vita2d_gfx.c b/gfx/drivers/vita2d_gfx.c index e0906c3449..1c36e8e918 100644 --- a/gfx/drivers/vita2d_gfx.c +++ b/gfx/drivers/vita2d_gfx.c @@ -579,7 +579,7 @@ static void vita2d_gfx_viewport_info(void *data, *vp = vita->vp; } -static void vita_set_filtering(void *data, unsigned index, bool smooth) +static void vita_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { vita_video_t *vita = (vita_video_t *)data; diff --git a/gfx/drivers/xshm_gfx.c b/gfx/drivers/xshm_gfx.c index e70611fcfd..1da7e9b2cf 100644 --- a/gfx/drivers/xshm_gfx.c +++ b/gfx/drivers/xshm_gfx.c @@ -140,7 +140,7 @@ static void xshm_gfx_free(void *data) } -static void xshm_poke_set_filtering(void *data, unsigned index, bool smooth) +static void xshm_poke_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) { } diff --git a/gfx/drivers_context/drm_ctx.c b/gfx/drivers_context/drm_ctx.c index dfda72f822..e1c8db1d78 100644 --- a/gfx/drivers_context/drm_ctx.c +++ b/gfx/drivers_context/drm_ctx.c @@ -42,11 +42,6 @@ #include "../../frontend/frontend_driver.h" #include "../common/drm_common.h" -#ifdef HAVE_ODROIDGO2 -#include -#include -#endif - #ifdef HAVE_EGL #include "../common/egl_common.h" #endif @@ -73,27 +68,19 @@ static enum gfx_ctx_api drm_api = GFX_CTX_NONE; -#ifndef HAVE_ODROIDGO2 static struct gbm_bo *g_bo = NULL; static struct gbm_bo *g_next_bo = NULL; static struct gbm_surface *g_gbm_surface = NULL; static struct gbm_device *g_gbm_dev = NULL; static bool waiting_for_flip = false; -#endif typedef struct gfx_ctx_drm_data { #ifdef HAVE_EGL egl_ctx_data_t egl; #endif -#ifndef HAVE_ODROIDGO2 int fd; -#else - go2_display_t* display; - go2_presenter_t* presenter; - go2_context_t* context; -#endif int interval; unsigned fb_width; unsigned fb_height; @@ -101,7 +88,6 @@ typedef struct gfx_ctx_drm_data bool core_hw_context_enable; } gfx_ctx_drm_data_t; -#ifndef HAVE_ODROIDGO2 struct drm_fb { struct gbm_bo *bo; @@ -148,6 +134,26 @@ error: return NULL; } +static void gfx_ctx_drm_swap_interval(void *data, int interval) +{ + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + drm->interval = interval; + + if (interval > 1) + RARCH_WARN("[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); +} + +static void gfx_ctx_drm_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height) +{ + (void)data; + (void)width; + (void)height; + + *resize = false; + *quit = (bool)frontend_driver_get_signal_handler_state(); +} + static void drm_flip_handler(int fd, unsigned frame, unsigned sec, unsigned usec, void *data) { @@ -222,56 +228,7 @@ static bool gfx_ctx_drm_queue_flip(void) /* Failed to queue page flip. */ return false; } -#endif -static void gfx_ctx_drm_swap_interval(void *data, int interval) -{ - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - drm->interval = interval; - - if (interval > 1) - RARCH_WARN("[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); -} - -static void gfx_ctx_drm_check_window(void *data, bool *quit, - bool *resize, unsigned *width, unsigned *height) -{ - (void)data; - (void)width; - (void)height; - - *resize = false; - *quit = (bool)frontend_driver_get_signal_handler_state(); -} - -#ifdef HAVE_ODROIDGO2 -static void gfx_ctx_drm_swap_buffers(void *data) -{ - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - - switch (drm_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - case GFX_CTX_OPENVG_API: -#ifdef HAVE_EGL - go2_context_swap_buffers(drm->context); - - go2_surface_t* surface = go2_context_surface_lock(drm->context); - go2_presenter_post(drm->presenter, - surface, - 0, 0, 480, 320, - 0, 0, 320, 480, - GO2_ROTATION_DEGREES_270, 2); - go2_context_surface_unlock(drm->context, surface); -#endif - break; - default: - printf("unhandled gfx_ctx_drm_swap_buffers\n"); - break; - } -} -#else static void gfx_ctx_drm_swap_buffers(void *data) { gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; @@ -309,6 +266,18 @@ static void gfx_ctx_drm_swap_buffers(void *data) gfx_ctx_drm_wait_flip(true); } +static void gfx_ctx_drm_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; + + if (!drm) + return; + + *width = drm->fb_width; + *height = drm->fb_height; +} + static void free_drm_resources(gfx_ctx_drm_data_t *drm) { if (!drm) @@ -338,21 +307,7 @@ static void free_drm_resources(gfx_ctx_drm_data_t *drm) g_gbm_dev = NULL; g_drm_fd = -1; } -#endif -static void gfx_ctx_drm_get_video_size(void *data, - unsigned *width, unsigned *height) -{ - gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; - - if (!drm) - return; - - *width = drm->fb_width; - *height = drm->fb_height; -} - -#ifndef HAVE_ODROIDGO2 static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t *drm) { if (!drm) @@ -387,17 +342,14 @@ static void gfx_ctx_drm_destroy_resources(gfx_ctx_drm_data_t *drm) g_bo = NULL; g_next_bo = NULL; } -#endif static void *gfx_ctx_drm_init(void *video_driver) { -#ifndef HAVE_ODROIDGO2 int fd, i; unsigned monitor_index; unsigned gpu_index = 0; const char *gpu = NULL; struct string_list *gpu_descriptors = NULL; -#endif settings_t *settings = config_get_ptr(); gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*) calloc(1, sizeof(gfx_ctx_drm_data_t)); @@ -405,8 +357,6 @@ static void *gfx_ctx_drm_init(void *video_driver) if (!drm) return NULL; - -#ifndef HAVE_ODROIDGO2 drm->fd = -1; gpu_descriptors = dir_list_new("/dev/dri", NULL, false, true, false, false); @@ -486,14 +436,8 @@ error: free(drm); return NULL; -#else - drm->display = go2_display_create(); - drm->presenter = go2_presenter_create(drm->display, DRM_FORMAT_RGB565, 0xff000000, true); - return drm; -#endif } -#ifndef HAVE_ODROIDGO2 static EGLint *gfx_ctx_drm_egl_fill_attribs( gfx_ctx_drm_data_t *drm, EGLint *attr) { @@ -562,9 +506,7 @@ static EGLint *gfx_ctx_drm_egl_fill_attribs( *attr = EGL_NONE; return attr; } -#endif -#ifndef HAVE_ODROIDGO2 #ifdef HAVE_EGL static bool gbm_choose_xrgb8888_cb(void *display_data, EGLDisplay dpy, EGLConfig config) { @@ -587,8 +529,6 @@ static bool gbm_choose_xrgb8888_cb(void *display_data, EGLDisplay dpy, EGLConfig return id == GBM_FORMAT_XRGB8888; } -#endif -#endif #define DRM_EGL_ATTRIBS_BASE \ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \ @@ -598,7 +538,6 @@ static bool gbm_choose_xrgb8888_cb(void *display_data, EGLDisplay dpy, EGLConfig EGL_ALPHA_SIZE, 0, \ EGL_DEPTH_SIZE, 0 -#ifndef HAVE_ODROIDGO2 static bool gfx_ctx_drm_egl_set_video_mode(gfx_ctx_drm_data_t *drm) { const EGLint *attrib_ptr = NULL; @@ -705,11 +644,9 @@ static bool gfx_ctx_drm_set_video_mode(void *data, unsigned width, unsigned height, bool fullscreen) { -#ifndef HAVE_ODROIDGO2 float refresh_mod; int i, ret = 0; struct drm_fb *fb = NULL; -#endif gfx_ctx_drm_data_t *drm = (gfx_ctx_drm_data_t*)data; settings_t *settings = config_get_ptr(); bool black_frame_insertion = settings->bools.video_black_frame_insertion; @@ -720,7 +657,6 @@ static bool gfx_ctx_drm_set_video_mode(void *data, frontend_driver_install_signal_handler(); -#ifndef HAVE_ODROIDGO2 /* If we use black frame insertion, * we fake a 60 Hz monitor for 120 Hz one, * etc, so try to match that. */ @@ -777,13 +713,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data, drm->fb_height, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); -#else - /* Hardcoded odroidgo2 display resolution */ - drm->fb_width = 480; - drm->fb_height = 320; -#endif -#ifndef HAVE_ODROIDGO2 if (!g_gbm_surface) { RARCH_ERR("[KMS/EGL]: Couldn't create GBM surface.\n"); @@ -826,25 +756,6 @@ error: free(drm); return false; -#else - go2_context_attributes_t attr; - attr.major = 3; - attr.minor = 2; - attr.red_bits = 8; - attr.green_bits = 8; - attr.blue_bits = 8; - attr.alpha_bits = 8; - attr.depth_bits = 0; - attr.stencil_bits = 0; - - /* Hardcoded odroidgo2 display resolution */ - drm->context = go2_context_create(drm->display, 480, 320, &attr); - go2_context_make_current(drm->context); - - glClear(GL_COLOR_BUFFER_BIT); - - return true; -#endif } static void gfx_ctx_drm_destroy(void *data) @@ -854,22 +765,8 @@ static void gfx_ctx_drm_destroy(void *data) if (!drm) return; -#ifndef HAVE_ODROIDGO2 gfx_ctx_drm_destroy_resources(drm); free(drm); -#else - if (drm->context) - { - go2_context_destroy(drm->context); - drm->context = NULL; - } - - go2_presenter_destroy(drm->presenter); - drm->presenter = NULL; - - go2_display_destroy(drm->display); - drm->display = NULL; -#endif } static void gfx_ctx_drm_input_driver(void *data, diff --git a/gfx/drivers_context/drm_go2_ctx.c b/gfx/drivers_context/drm_go2_ctx.c new file mode 100644 index 0000000000..40b060c69d --- /dev/null +++ b/gfx/drivers_context/drm_go2_ctx.c @@ -0,0 +1,447 @@ +/* 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 . + */ + +/* KMS/DRM context, running without any window manager. + * Based on kmscube example by Rob Clark. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "../../configuration.h" +#include "../../verbosity.h" +#include "../../frontend/frontend_driver.h" +#include "../common/drm_common.h" + +#include +#include + +#ifdef HAVE_EGL +#include "../common/egl_common.h" +#endif + +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) +#include "../common/gl_common.h" +#endif + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifdef HAVE_OPENGLES + +#ifndef EGL_OPENGL_ES3_BIT_KHR +#define EGL_OPENGL_ES3_BIT_KHR 0x0040 +#endif + +#endif + +#ifndef EGL_PLATFORM_GBM_KHR +#define EGL_PLATFORM_GBM_KHR 0x31D7 +#endif + +static enum gfx_ctx_api drm_api = GFX_CTX_NONE; + +typedef struct gfx_ctx_go2_drm_data +{ +#ifdef HAVE_EGL + egl_ctx_data_t egl; +#endif + go2_display_t* display; + go2_presenter_t* presenter; + go2_context_t* context; + unsigned fb_width; + unsigned fb_height; + unsigned ctx_w; + unsigned ctx_h; + bool core_hw_context_enable; +} gfx_ctx_go2_drm_data_t; + +static unsigned native_width = 480; +static unsigned native_height = 320; + +static void gfx_ctx_go2_drm_input_driver(void *data, + const char *joypad_name, + input_driver_t **input, void **input_data) +{ +#ifdef HAVE_UDEV + /* Try to set it to udev instead */ + void *udev = input_udev.init(joypad_name); + if (udev) + { + *input = &input_udev; + *input_data = udev; + return; + } +#endif + + *input = NULL; + *input_data = NULL; +} + +static gfx_ctx_proc_t gfx_ctx_go2_drm_get_proc_address(const char *symbol) +{ + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + return egl_get_proc_address(symbol); +#endif + case GFX_CTX_NONE: + default: + break; + } + + return NULL; +} + +static void *gfx_ctx_go2_drm_init(void *video_driver) +{ + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*) + calloc(1, sizeof(gfx_ctx_go2_drm_data_t)); + + if (!drm) + return NULL; + + drm->display = go2_display_create(); + drm->presenter = go2_presenter_create(drm->display, DRM_FORMAT_RGB565, 0xff000000, true); + + return drm; +} + +static void gfx_ctx_go2_drm_destroy(void *data) +{ + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + if (!drm) return; + + if (drm->context) + { + go2_context_destroy(drm->context); + drm->context = NULL; + } + + go2_presenter_destroy(drm->presenter); + drm->presenter = NULL; + + go2_display_destroy(drm->display); + drm->display = NULL; +} + +static enum gfx_ctx_api gfx_ctx_go2_drm_get_api(void *data) +{ + return drm_api; +} + +static bool gfx_ctx_go2_drm_bind_api(void *video_driver, + enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + (void)video_driver; + + drm_api = api; +#ifdef HAVE_EGL + g_egl_major = major; + g_egl_minor = minor; +#endif + + switch (api) + { + case GFX_CTX_OPENGL_API: +#if defined(HAVE_EGL) && defined(HAVE_OPENGL) + +#ifndef EGL_KHR_create_context + if ((major * 1000 + minor) >= 3001) + return false; +#endif + return egl_bind_api(EGL_OPENGL_API); +#else + break; +#endif + case GFX_CTX_OPENGL_ES_API: +#if defined(HAVE_EGL) && defined(HAVE_OPENGLES) + +#ifndef EGL_KHR_create_context + if (major >= 3) + return false; +#endif + return egl_bind_api(EGL_OPENGL_ES_API); +#else + break; +#endif + case GFX_CTX_OPENVG_API: +#if defined(HAVE_EGL) && defined(HAVE_VG) + return egl_bind_api(EGL_OPENVG_API); +#endif + case GFX_CTX_NONE: + default: + break; + } + + return false; +} + +static void gfx_ctx_go2_drm_swap_interval(void *data, int interval) +{ + (void)data; + (void)interval; + + if (interval > 1) + RARCH_WARN("[KMS]: Swap intervals > 1 currently not supported. Will use swap interval of 1.\n"); +} + +static bool gfx_ctx_go2_drm_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) +{ + struct retro_system_av_info *av_info = NULL; + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + + if (!drm) + return false; + + av_info = video_viewport_get_system_av_info(); + + frontend_driver_install_signal_handler(); + + settings_t *settings = config_get_ptr(); + bool use_ctx_scaling = settings->bools.video_ctx_scaling; + + if (use_ctx_scaling && !menu_driver_is_alive()) + { + drm->fb_width = av_info->geometry.base_width; + drm->fb_height = av_info->geometry.base_height; + } + else + { + drm->fb_width = native_width; + drm->fb_height = native_height; + } + + if (!drm->context) + { + go2_context_attributes_t attr; + attr.major = 3; + attr.minor = 2; + attr.red_bits = 8; + attr.green_bits = 8; + attr.blue_bits = 8; + attr.alpha_bits = 8; + attr.depth_bits = 0; + attr.stencil_bits = 0; + + drm->ctx_w = MAX(av_info->geometry.max_width, native_width); + drm->ctx_h = MAX(av_info->geometry.max_height, native_height); + + drm->context = go2_context_create(drm->display, drm->ctx_w, drm->ctx_h, &attr); + } + + go2_context_make_current(drm->context); + + glClear(GL_COLOR_BUFFER_BIT); + + return true; +} + +static void gfx_ctx_go2_drm_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height) +{ + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + struct retro_system_av_info* av_info = video_viewport_get_system_av_info(); + settings_t *settings = config_get_ptr(); + bool use_ctx_scaling = settings->bools.video_ctx_scaling; + + unsigned w; + unsigned h; + + if (use_ctx_scaling && !menu_driver_is_alive()) + { + w = av_info->geometry.base_width; + h = av_info->geometry.base_height; + } + else + { + w = native_width; + h = native_height; + } + + if (*width != w || *height != h) + { + *width = drm->fb_width = w; + *height = drm->fb_height = h; + *resize = false; + } + + *quit = (bool)frontend_driver_get_signal_handler_state(); +} + +static bool gfx_ctx_go2_drm_has_focus(void *data) +{ + return true; +} + +static bool gfx_ctx_go2_drm_suppress_screensaver(void *data, bool enable) +{ + (void)data; + (void)enable; + return false; +} + +int ss = 0; + +void (*swap_buffers)(void*); +static void gfx_ctx_go2_drm_swap_buffers(void *data) +{ + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + + int out_w = native_width; + int out_h = native_height; + int out_x = 0; + int out_y = 0; + + int src_w = drm->fb_width; + int src_h = drm->fb_height; + int src_x = 0; + int src_y = drm->ctx_h - drm->fb_height; + + if (out_w != src_w || out_h != src_h) + { + out_w = out_h * video_driver_get_aspect_ratio(); + out_w = (out_w > 480) ? 480 : out_w; + out_x = (480 - out_w) / 2; + if (out_x < 0) + out_x = 0; + } + + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + go2_context_swap_buffers(drm->context); + + go2_surface_t* surface = go2_context_surface_lock(drm->context); + go2_presenter_post(drm->presenter, + surface, + src_x, src_y, src_w, src_h, + out_y, out_x, out_h, out_w, + GO2_ROTATION_DEGREES_270, 2); + go2_context_surface_unlock(drm->context, surface); +#endif + break; + default: + printf("unhandled gfx_ctx_go2_drm_swap_buffers\n"); + break; + } +} + +static uint32_t gfx_ctx_go2_drm_get_flags(void *data) +{ + uint32_t flags = 0; + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + + BIT32_SET(flags, GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES); + + if (drm->core_hw_context_enable) + BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT); + + if (string_is_equal(video_driver_get_ident(), "glcore")) + { +#if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS) + BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG); +#endif + } + else + BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_GLSL); + + return flags; +} + +static void gfx_ctx_go2_drm_set_flags(void *data, uint32_t flags) +{ + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) + drm->core_hw_context_enable = true; +} + +static void gfx_ctx_go2_drm_bind_hw_render(void *data, bool enable) +{ + gfx_ctx_go2_drm_data_t *drm = (gfx_ctx_go2_drm_data_t*)data; + + switch (drm_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + case GFX_CTX_OPENVG_API: +#ifdef HAVE_EGL + egl_bind_hw_render(&drm->egl, enable); +#endif + break; + case GFX_CTX_NONE: + default: + break; + } +} + +const gfx_ctx_driver_t gfx_ctx_go2_drm = { + gfx_ctx_go2_drm_init, + gfx_ctx_go2_drm_destroy, + gfx_ctx_go2_drm_get_api, + gfx_ctx_go2_drm_bind_api, + gfx_ctx_go2_drm_swap_interval, + gfx_ctx_go2_drm_set_video_mode, + NULL, /* get_video_size */ + drm_get_refresh_rate, + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + NULL, /* get_metrics */ + NULL, + NULL, /* update_title */ + gfx_ctx_go2_drm_check_window, + NULL, /* set_resize */ + gfx_ctx_go2_drm_has_focus, + gfx_ctx_go2_drm_suppress_screensaver, + false, /* has_windowed */ + gfx_ctx_go2_drm_swap_buffers, + gfx_ctx_go2_drm_input_driver, + gfx_ctx_go2_drm_get_proc_address, + NULL, + NULL, + NULL, + "kms", + gfx_ctx_go2_drm_get_flags, + gfx_ctx_go2_drm_set_flags, + gfx_ctx_go2_drm_bind_hw_render, + NULL, + NULL +}; diff --git a/gfx/video_thread_wrapper.c b/gfx/video_thread_wrapper.c index b451ee8015..910bd8aa74 100644 --- a/gfx/video_thread_wrapper.c +++ b/gfx/video_thread_wrapper.c @@ -117,6 +117,7 @@ struct thread_packet { unsigned index; bool smooth; + bool ctx_scaling; } filtering; struct @@ -499,7 +500,8 @@ static bool video_thread_handle_packet( if (thr->poke && thr->poke->set_filtering) thr->poke->set_filtering(thr->driver_data, pkt.data.filtering.index, - pkt.data.filtering.smooth); + pkt.data.filtering.smooth, + pkt.data.filtering.ctx_scaling); video_thread_reply(thr, &pkt); break; @@ -1078,7 +1080,7 @@ static void thread_set_video_mode(void *data, unsigned width, unsigned height, video_thread_send_and_wait_user_to_thread(thr, &pkt); } -static void thread_set_filtering(void *data, unsigned idx, bool smooth) +static void thread_set_filtering(void *data, unsigned idx, bool smooth, bool ctx_scaling) { thread_video_t *thr = (thread_video_t*)data; thread_packet_t pkt = { CMD_POKE_SET_FILTERING }; diff --git a/intl/msg_hash_ar.c b/intl/msg_hash_ar.c index 1c1a62d443..ec4b333fdb 100644 --- a/intl/msg_hash_ar.c +++ b/intl/msg_hash_ar.c @@ -1685,6 +1685,15 @@ int menu_hash_get_help_ar_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Shows current date and/or time inside menu."); diff --git a/intl/msg_hash_chs.c b/intl/msg_hash_chs.c index c9bc0a2c7e..fc40f16f21 100644 --- a/intl/msg_hash_chs.c +++ b/intl/msg_hash_chs.c @@ -1503,6 +1503,15 @@ int menu_hash_get_help_chs_enum(enum msg_hash_enums msg, char *s, size_t len) "用双线性过滤使图像平滑。 \n" "如果你使用了渲染器,请关闭它。"); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "在菜单中显示当前日期和时间。"); diff --git a/intl/msg_hash_cht.c b/intl/msg_hash_cht.c index ad12ecb256..93317531ba 100644 --- a/intl/msg_hash_cht.c +++ b/intl/msg_hash_cht.c @@ -1548,6 +1548,15 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "在選單內顯示當前日期或時間."); diff --git a/intl/msg_hash_de.c b/intl/msg_hash_de.c index ce086882ec..3da859ca4f 100644 --- a/intl/msg_hash_de.c +++ b/intl/msg_hash_de.c @@ -1683,6 +1683,15 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "Bild mit bilinearer Filterung glätten. \n" "Sollte deaktiviert werden, wenn Shader verwendet werden."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Zeigt das aktuelle Datum/die aktuelle Zeit im Menü an."); diff --git a/intl/msg_hash_el.c b/intl/msg_hash_el.c index 045d1d8a40..73d86ad189 100644 --- a/intl/msg_hash_el.c +++ b/intl/msg_hash_el.c @@ -1752,6 +1752,15 @@ int menu_hash_get_help_el_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Shows current date and/or time inside menu."); diff --git a/intl/msg_hash_es.c b/intl/msg_hash_es.c index 183dc687db..710c18b9e2 100644 --- a/intl/msg_hash_es.c +++ b/intl/msg_hash_es.c @@ -1934,6 +1934,15 @@ int menu_hash_get_help_es_enum(enum msg_hash_enums msg, char *s, size_t len) "Suaviza la imagen con un filtro bilineal.\n" "Desactiva esta opción si utilizas shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Muestra la fecha o la hora actuales\n" diff --git a/intl/msg_hash_fr.c b/intl/msg_hash_fr.c index 1f8c27867c..a1bc982177 100644 --- a/intl/msg_hash_fr.c +++ b/intl/msg_hash_fr.c @@ -1805,6 +1805,15 @@ int menu_hash_get_help_fr_enum(enum msg_hash_enums msg, char *s, size_t len) "Lisse l'image avec le filtrage bilinéaire. \n" "Devrait être désactivé si vous utilisez des shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Affiche la date et/ou l'heure locale dans le menu."); diff --git a/intl/msg_hash_ja.c b/intl/msg_hash_ja.c index fa87b1a58e..312edea4dd 100644 --- a/intl/msg_hash_ja.c +++ b/intl/msg_hash_ja.c @@ -1775,6 +1775,15 @@ int menu_hash_get_help_jp_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Shows current date and/or time inside menu."); diff --git a/intl/msg_hash_ko.c b/intl/msg_hash_ko.c index 10be4eb39f..f602794cde 100644 --- a/intl/msg_hash_ko.c +++ b/intl/msg_hash_ko.c @@ -1780,6 +1780,15 @@ int menu_hash_get_help_ko_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Shows current date and/or time inside menu."); diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 0ff89c39f8..b3c4f8851c 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1508,6 +1508,8 @@ MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHARED_CONTEXT, "video_shared_context") MSG_HASH(MENU_ENUM_LABEL_VIDEO_SMOOTH, "video_smooth") +MSG_HASH(MENU_ENUM_LABEL_VIDEO_CTX_SCALING, + "video_ctx_scaling") MSG_HASH(MENU_ENUM_LABEL_VIDEO_SOFT_FILTER, "soft_filter") MSG_HASH(MENU_ENUM_LABEL_VIDEO_SWAP_INTERVAL, diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index 935fc3ca05..0837046657 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -1581,6 +1581,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, "Activeer Gedeelde Hardware Context") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, "Bilinear Filtering") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CTX_SCALING, +#ifdef HAVE_ODROIDGO2 + "RGA Scaling" +#else + "Context Specific Scaling" +#endif +) MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, "Soft Filter Enable") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, diff --git a/intl/msg_hash_pt_br.c b/intl/msg_hash_pt_br.c index 7b86a6fd99..fb89e52f15 100644 --- a/intl/msg_hash_pt_br.c +++ b/intl/msg_hash_pt_br.c @@ -1861,6 +1861,15 @@ int menu_hash_get_help_pt_br_enum(enum msg_hash_enums msg, char *s, size_t len) "Suaviza a imagem com filtragem bilinear. \n" "Deve ser desativado se estiver usando shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Exibir data e/ou hora atuais dentro do menu."); diff --git a/intl/msg_hash_tr.c b/intl/msg_hash_tr.c index 11a95432d4..851fc295f7 100644 --- a/intl/msg_hash_tr.c +++ b/intl/msg_hash_tr.c @@ -1745,6 +1745,15 @@ int menu_hash_get_help_tr_enum(enum msg_hash_enums msg, char *s, size_t len) "Resmi bilinear filtreleme ile pürüzsüzleştirir. \n" "Gölgelendiriciler kullanılıyorsa devre dışı bırakılmalıdır."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Menü içindeki geçerli tarihi ve/veya saati gösterir."); diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index b0a04e2b2c..7fd7d525b9 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1800,6 +1800,15 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Shows current date and/or time inside menu."); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 628f5702de..390cb17767 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -4316,6 +4316,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, "Bilinear Filtering" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_CTX_SCALING, +#ifdef HAVE_ODROIDGO2 + "RGA Scaling" +#else + "Context Specific Scaling" +#endif + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, "Soft Filter" @@ -6079,6 +6087,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, "Adds a slight blur to the image to take the edge off of the hard pixel edges. This option has very little impact on performance." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_CTX_SCALING, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_FILTER, "Apply a CPU-powered video filter.\n" diff --git a/intl/msg_hash_vn.c b/intl/msg_hash_vn.c index 19f92a7cac..a840f09e1a 100644 --- a/intl/msg_hash_vn.c +++ b/intl/msg_hash_vn.c @@ -1581,6 +1581,15 @@ int menu_hash_get_help_vn_enum(enum msg_hash_enums msg, char *s, size_t len) "Smoothens picture with bilinear filtering. \n" "Should be disabled if using shaders."); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + snprintf(s, len, +#ifdef HAVE_ODROIDGO2 + "RGA scaling and bicubic filtering. May break widgets." +#else + "Hardware context scaling (if available)." +#endif + ); + break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, "Shows current date and/or time inside menu."); diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index ad5a988121..ac4d214e6d 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -282,6 +282,7 @@ default_sublabel_macro(action_bind_sublabel_audio_max_timing_skew, MENU_ default_sublabel_macro(action_bind_sublabel_pause_nonactive, MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE) default_sublabel_macro(action_bind_sublabel_video_disable_composition, MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION) default_sublabel_macro(action_bind_sublabel_video_smooth, MENU_ENUM_SUBLABEL_VIDEO_SMOOTH) +default_sublabel_macro(action_bind_sublabel_video_ctx_scaling, MENU_ENUM_SUBLABEL_VIDEO_CTX_SCALING) default_sublabel_macro(action_bind_sublabel_history_list_enable, MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE) default_sublabel_macro(action_bind_sublabel_content_history_size, MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE) default_sublabel_macro(action_bind_sublabel_content_favorites_size, MENU_ENUM_SUBLABEL_CONTENT_FAVORITES_SIZE) @@ -2580,6 +2581,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_VIDEO_SMOOTH: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_smooth); break; + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_ctx_scaling); + break; case MENU_ENUM_LABEL_VIDEO_FONT_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_onscreen_notifications_enable); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index d3af5f04c8..766ad0df6c 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4679,6 +4679,10 @@ unsigned menu_displaylist_build_list( MENU_ENUM_LABEL_VIDEO_SMOOTH, PARSE_ONLY_BOOL, false) == 0) count++; + if (menu_displaylist_parse_settings_enum(list, + MENU_ENUM_LABEL_VIDEO_CTX_SCALING, + PARSE_ONLY_BOOL, false) == 0) + count++; if (menu_displaylist_parse_settings_enum(list, MENU_ENUM_LABEL_VIDEO_SHADER_DELAY, PARSE_ONLY_UINT, false) == 0) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 47bd1352be..5bebf9364b 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -6770,7 +6770,8 @@ void general_write_handler(rarch_setting_t *setting) } break; case MENU_ENUM_LABEL_VIDEO_SMOOTH: - video_driver_set_filtering(1, settings->bools.video_smooth); + case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: + video_driver_set_filtering(1, settings->bools.video_ctx_scaling, settings->bools.video_ctx_scaling); break; case MENU_ENUM_LABEL_VIDEO_ROTATION: { @@ -10262,6 +10263,25 @@ static bool setting_append_list( ); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_REINIT); +#ifdef HAVE_ODROIDGO2 + CONFIG_BOOL( + list, list_info, + &settings->bools.video_ctx_scaling, + MENU_ENUM_LABEL_VIDEO_CTX_SCALING, + MENU_ENUM_LABEL_VALUE_VIDEO_CTX_SCALING, + DEFAULT_VIDEO_CTX_SCALING, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE + ); + menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_REINIT); +#endif + CONFIG_UINT( list, list_info, &settings->uints.video_rotation, diff --git a/msg_hash.h b/msg_hash.h index 5bb6203bf6..cd261207f7 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -922,6 +922,7 @@ enum msg_hash_enums MENU_LABEL(VIDEO_SCALE), MENU_LABEL(VIDEO_RECORD_THREADS), MENU_LABEL(VIDEO_SMOOTH), + MENU_LABEL(VIDEO_CTX_SCALING), MENU_LABEL(VIDEO_CROP_OVERSCAN), diff --git a/retroarch.c b/retroarch.c index b48ce9ee59..02c83dba49 100644 --- a/retroarch.c +++ b/retroarch.c @@ -592,8 +592,12 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { &gfx_ctx_x_egl, #endif #if defined(HAVE_KMS) +#if defined(HAVE_ODROIDGO2) + &gfx_ctx_go2_drm, +#else &gfx_ctx_drm, #endif +#endif #if defined(ANDROID) &gfx_ctx_android, #endif @@ -22560,6 +22564,9 @@ static bool video_driver_init_internal(bool *video_is_threaded) video.vfilter = settings->bools.video_vfilter; #endif video.smooth = settings->bools.video_smooth; +#ifdef HAVE_ODROIDGO2 + video.ctx_scaling = settings->bools.video_ctx_scaling; +#endif video.input_scale = scale; video.font_size = settings->floats.video_font_size; video.path_font = settings->paths.path_font; @@ -22769,10 +22776,10 @@ void *video_driver_read_frame_raw(unsigned *width, height, pitch); } -void video_driver_set_filtering(unsigned index, bool smooth) +void video_driver_set_filtering(unsigned index, bool smooth, bool ctx_scaling) { if (video_driver_poke && video_driver_poke->set_filtering) - video_driver_poke->set_filtering(video_driver_data, index, smooth); + video_driver_poke->set_filtering(video_driver_data, index, smooth, ctx_scaling); } void video_driver_cached_frame_set(const void *data, unsigned width, diff --git a/retroarch.h b/retroarch.h index 626ff54a71..d4cbc8ff3f 100644 --- a/retroarch.h +++ b/retroarch.h @@ -1052,6 +1052,8 @@ typedef struct video_info * otherwise nearest filtering. */ bool smooth; + bool ctx_scaling; + bool is_threaded; /* Use 32bit RGBA rather than native RGB565/XBGR1555. @@ -1381,7 +1383,7 @@ typedef struct video_poke_interface void (*set_video_mode)(void *data, unsigned width, unsigned height, bool fullscreen); float (*get_refresh_rate)(void *data); - void (*set_filtering)(void *data, unsigned index, bool smooth); + void (*set_filtering)(void *data, unsigned index, bool smooth, bool ctx_scaling); void (*get_video_output_size)(void *data, unsigned *width, unsigned *height); @@ -1619,7 +1621,7 @@ const video_layout_render_interface_t *video_driver_layout_render_interface(void void * video_driver_read_frame_raw(unsigned *width, unsigned *height, size_t *pitch); -void video_driver_set_filtering(unsigned index, bool smooth); +void video_driver_set_filtering(unsigned index, bool smooth, bool ctx_scaling); const char *video_driver_get_ident(void); @@ -1895,6 +1897,7 @@ extern const gfx_ctx_driver_t gfx_ctx_uwp; extern const gfx_ctx_driver_t gfx_ctx_wayland; extern const gfx_ctx_driver_t gfx_ctx_x; extern const gfx_ctx_driver_t gfx_ctx_drm; +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; diff --git a/ui/drivers/qt/options/video.cpp b/ui/drivers/qt/options/video.cpp index 9055bcf812..b7dd43d5ce 100644 --- a/ui/drivers/qt/options/video.cpp +++ b/ui/drivers/qt/options/video.cpp @@ -141,6 +141,7 @@ QWidget *VideoPage::widget() miscGroup->add(MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION); miscGroup->add(MENU_ENUM_LABEL_VIDEO_GPU_SCREENSHOT); miscGroup->add(MENU_ENUM_LABEL_VIDEO_SMOOTH); + miscGroup->add(MENU_ENUM_LABEL_VIDEO_CTX_SCALING); miscGroup->add(MENU_ENUM_LABEL_VIDEO_SHADER_DELAY); syncMiscLayout->addWidget(syncGroup);