From 35c4770c9b8929a3bb0457255fb57581f4a4f064 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 1 Sep 2017 20:52:58 -0400 Subject: [PATCH] gdi: manually convert RGB444 to RGB555 to get around BI_BITFIELDS limitation on non-NT platforms --- gfx/drivers/gdi_gfx.c | 88 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/gfx/drivers/gdi_gfx.c b/gfx/drivers/gdi_gfx.c index 22f430ada4..9810646e3d 100644 --- a/gfx/drivers/gdi_gfx.c +++ b/gfx/drivers/gdi_gfx.c @@ -30,6 +30,7 @@ #include "../../driver.h" #include "../../configuration.h" #include "../../verbosity.h" +#include "../../frontend/frontend_driver.h" #include "../common/gdi_common.h" #if defined(_WIN32) && !defined(_XBOX) @@ -47,9 +48,31 @@ static unsigned gdi_video_bits = 0; static unsigned gdi_menu_bits = 0; static bool gdi_rgb32 = false; static bool gdi_menu_rgb32 = false; +static int gdi_win_major = 0; +static int gdi_win_minor = 0; +static bool gdi_lte_win98 = false; +static unsigned short *gdi_temp_buf = NULL; static void gdi_gfx_create(void) { + char os[64] = {0}; + + frontend_ctx_driver_t *ctx = frontend_get_ptr(); + + if (!ctx || !ctx->get_os) + { + RARCH_ERR("[GDI] No frontend driver found.\n"); + return; + } + + ctx->get_os(os, sizeof(os), &gdi_win_major, &gdi_win_minor); + + // Are we running on Windows 98 or below? + if (gdi_win_major < 4 || (gdi_win_major == 4 && gdi_win_minor <= 10)) + { + RARCH_LOG("[GDI] Win98 or lower detected, using slow frame conversion method for RGB444.\n"); + gdi_lte_win98 = true; + } } static void *gdi_gfx_init(const video_info_t *video, @@ -226,6 +249,16 @@ static bool gdi_gfx_frame(void *data, const void *frame, gdi->video_height = height; gdi->bmp = CreateCompatibleBitmap(gdi->winDC, gdi->video_width, gdi->video_height); gdi->bmp_old = (HBITMAP)SelectObject(gdi->memDC, gdi->bmp); + + if (gdi_lte_win98) + { + if (gdi_temp_buf) + { + free(gdi_temp_buf); + } + + gdi_temp_buf = (unsigned short*)malloc(width * height * sizeof(unsigned short)); + } } video_context_driver_get_video_size(&mode); @@ -244,24 +277,45 @@ static bool gdi_gfx_frame(void *data, const void *frame, if (bits == 16) { - unsigned *masks = (unsigned*)info->bmiColors; - - info->bmiHeader.biCompression = BI_BITFIELDS; - - /* default 16-bit format on Windows is XRGB1555 */ - if (frame_to_copy == gdi_menu_frame) + if (gdi_lte_win98 && gdi_temp_buf) { - /* map RGB444 color bits for RGUI */ - masks[0] = 0xF000; - masks[1] = 0x0F00; - masks[2] = 0x00F0; + /* Win98 and below cannot use BI_BITFIELDS with RGB444, + * so convert it to RGB555 first. */ + unsigned x, y; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + unsigned short pixel = ((unsigned short*)frame_to_copy)[width * y + x]; + gdi_temp_buf[width * y + x] = (pixel & 0xF000) >> 1 | (pixel & 0x0F00) >> 2 | (pixel & 0x00F0) >> 3; + } + } + + frame_to_copy = gdi_temp_buf; + info->bmiHeader.biCompression = BI_RGB; } else { - /* map RGB565 color bits for core */ - masks[0] = 0xF800; - masks[1] = 0x07E0; - masks[2] = 0x001F; + unsigned *masks = (unsigned*)info->bmiColors; + + info->bmiHeader.biCompression = BI_BITFIELDS; + + /* default 16-bit format on Windows is XRGB1555 */ + if (frame_to_copy == gdi_menu_frame) + { + /* map RGB444 color bits for RGUI */ + masks[0] = 0xF000; + masks[1] = 0x0F00; + masks[2] = 0x00F0; + } + else + { + /* map RGB565 color bits for core */ + masks[0] = 0xF800; + masks[1] = 0x07E0; + masks[2] = 0x001F; + } } } else @@ -348,6 +402,12 @@ static void gdi_gfx_free(void *data) gdi_menu_frame = NULL; } + if (gdi_temp_buf) + { + free(gdi_temp_buf); + gdi_temp_buf = NULL; + } + if (!gdi) return;