From 517adc153a98437ca230b1bc2617ea7e50b066fc Mon Sep 17 00:00:00 2001 From: icex2 Date: Fri, 19 Mar 2021 22:19:32 +0100 Subject: [PATCH] patch/gfx: Implement scaling using different screen and viewport resolutions Define a set of fixed modes covering our use-cases to allow rendering 4:3 games to a pillarbox on widescreen monitors. --- Dockerfile | 32 ++++++++------ src/main/hook/patch/gfx.c | 91 +++++++++++++++++++++++++++++++++++++++ src/main/hook/patch/gfx.h | 23 ++++++++-- 3 files changed, 128 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0b80944..7125fc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,20 +5,24 @@ LABEL description="Build environment for pumptools" # Install build dependencies, multilib to get 32-bit versions RUN dpkg --add-architecture i386 -RUN apt-get update && apt-get install -y \ - g++-multilib \ - gcc-multilib \ - zip \ - cmake \ - make \ - git \ - libc6-dev-i386 \ - libusb-1.0-0-dev:i386 \ - libusb-dev:i386 \ - libasound2-dev:i386 \ - libconfig++-dev:i386 \ - libx11-dev:i386 \ - libcurl4-gnutls-dev:i386 +RUN apt-get update +RUN apt-get install -y g++-multilib +RUN apt-get install -y gcc-multilib +RUN apt-get install -y zip +RUN apt-get install -y cmake +RUN apt-get install -y make +RUN apt-get install -y git +RUN apt-get install -y libc6-dev-i386 +RUN apt-get install -y libusb-1.0-0-dev:i386 +RUN apt-get install -y libusb-dev:i386 +RUN apt-get install -y libasound2-dev:i386 +RUN apt-get install -y libconfig++-dev:i386 +RUN apt-get install -y libx11-dev:i386 +RUN apt-get install -y libcurl4-gnutls-dev:i386 +RUN apt-get install -y libglu1-mesa-dev:i386 + +# Delete apt-cache to reduce image size +RUN rm -rf /var/lib/apt/lists/* # Copy files for building to container RUN mkdir /pumptools diff --git a/src/main/hook/patch/gfx.c b/src/main/hook/patch/gfx.c index 0c94c75..55c0c3e 100644 --- a/src/main/hook/patch/gfx.c +++ b/src/main/hook/patch/gfx.c @@ -2,6 +2,10 @@ #include #include +#include + +// OpenGL 3.x+ +#include #include "capnhook/hook/lib.h" @@ -26,11 +30,21 @@ typedef Window (*XCreateWindow_t)( typedef Display *(*XOpenDisplay_t)(const char *display_name); typedef XVisualInfo *(*glXChooseVisual_t)( Display *dpy, int screen, int *attribList); +typedef void (*glViewport_t)(GLint x, GLint y, GLsizei width, GLsizei height); static bool patch_gfx_initialized; static XCreateWindow_t patch_gfx_real_XCreateWindow; static XOpenDisplay_t patch_gfx_real_XOpenDisplay; static glXChooseVisual_t patch_gfx_real_GlXChooseVisual; +static glViewport_t patch_gfx_real_glViewport; + +static bool _patch_gfx_scaling_enabled; +static uint16_t _patch_gfx_screen_width; +static uint16_t _patch_gfx_screen_height; +static uint16_t _patch_gfx_viewport_width; +static uint16_t _patch_gfx_viewport_height; +static uint16_t _patch_gfx_viewport_pos_x; +static uint16_t _patch_gfx_viewport_pos_y; static char *patch_gfx_attrib_list_to_str(int *attrib_list) { @@ -82,6 +96,11 @@ Window XCreateWindow( } } + if (_patch_gfx_scaling_enabled) { + width = _patch_gfx_screen_width; + height = _patch_gfx_screen_height; + } + return patch_gfx_real_XCreateWindow( display, parent, @@ -152,8 +171,80 @@ XVisualInfo *glXChooseVisual(Display *dpy, int screen, int *attribList) return res; } +void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (!patch_gfx_real_glViewport) { + void* handle = cnh_lib_load("libGL.so"); + + patch_gfx_real_glViewport = + (glViewport_t) cnh_lib_get_func_addr_handle(handle, "glViewport"); + } + + // 0/0 at the bottom left + if (_patch_gfx_scaling_enabled) { + x = _patch_gfx_viewport_pos_x; + y = _patch_gfx_viewport_pos_y; + width = _patch_gfx_viewport_width; + height = _patch_gfx_viewport_height; + } + + patch_gfx_real_glViewport(x, y, width, height); +} + void patch_gfx_init() { + _patch_gfx_scaling_enabled = false; patch_gfx_initialized = true; log_info("Initialized"); } + +// Note, consider improving scaling, see http://www.david-amador.com/2013/04/opengl-2d-independent-resolution-rendering/ +void patch_gfx_scale(enum patch_gfx_scale_mode scale_mode) +{ + switch (scale_mode) { + case PATCH_GFX_SCALE_MODE_SD_480_TO_PILLARBOX_HD_720: + _patch_gfx_screen_width = 1280; + _patch_gfx_screen_height = 720; + _patch_gfx_viewport_width = 960; + _patch_gfx_viewport_height = 720; + _patch_gfx_viewport_pos_x = 160; + _patch_gfx_viewport_pos_y = 0; + break; + + case PATCH_GFX_SCALE_MODE_SD_480_TO_PILLARBOX_HD_1080: + _patch_gfx_screen_width = 1920; + _patch_gfx_screen_height = 1080; + _patch_gfx_viewport_width = 1440; + _patch_gfx_viewport_height = 1080; + _patch_gfx_viewport_pos_x = 240; + _patch_gfx_viewport_pos_y = 0; + break; + + case PATCH_GFX_SCALE_MODE_SD_480_TO_SD_960: + _patch_gfx_screen_width = 1280; + _patch_gfx_screen_height = 960; + _patch_gfx_viewport_width = 1280; + _patch_gfx_viewport_height = 960; + _patch_gfx_viewport_pos_x = 0; + _patch_gfx_viewport_pos_y = 0; + break; + + case PATCH_GFX_SCALE_MODE_HD_720_TO_HD_1080: + _patch_gfx_screen_width = 1920; + _patch_gfx_screen_height = 1080; + _patch_gfx_viewport_width = 1920; + _patch_gfx_viewport_height = 1080; + _patch_gfx_viewport_pos_x = 0; + _patch_gfx_viewport_pos_y = 0; + break; + + case PATCH_GFX_SCALE_MODE_INVALID: + default: + log_error("Invalid scale mode: %d. Scaling disabled", scale_mode); + return; + } + + log_info("Scaling enabled, mode: %d", scale_mode); + + _patch_gfx_scaling_enabled = true; +} diff --git a/src/main/hook/patch/gfx.h b/src/main/hook/patch/gfx.h index e77f877..b2303a6 100644 --- a/src/main/hook/patch/gfx.h +++ b/src/main/hook/patch/gfx.h @@ -1,12 +1,27 @@ +#pragma once + /** - * Hook module to run the games on non NVIDIA cards + * Different modes for scaling different source resolutions to target + * resolutions including keeping the aspect ratio */ -#ifndef PATCH_GFX_H -#define PATCH_GFX_H +enum patch_gfx_scale_mode { + PATCH_GFX_SCALE_MODE_INVALID = 0, + PATCH_GFX_SCALE_MODE_SD_480_TO_PILLARBOX_HD_720 = 1, + PATCH_GFX_SCALE_MODE_SD_480_TO_PILLARBOX_HD_1080 = 2, + PATCH_GFX_SCALE_MODE_SD_480_TO_SD_960 = 3, + PATCH_GFX_SCALE_MODE_HD_720_TO_HD_1080 = 4, +}; /** * Initialize the patch module + * + * This takes care of running the games on non NVIDIA cards */ void patch_gfx_init(); -#endif \ No newline at end of file +/** + * Scale the rendered output according to the given mode (see enum) + * + * @param scale_mode The scaling mode to apply + */ +void patch_gfx_scale(enum patch_gfx_scale_mode scale_mode);