diff --git a/file.c b/file.c
index c57f6c043b..91cdafeee5 100644
--- a/file.c
+++ b/file.c
@@ -1,685 +1,682 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2012 - 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 .
- */
-
-#include "file.h"
-#include "general.h"
-#include
-#include "boolean.h"
-#include "libretro.h"
-#include
-#include
-#include "dynamic.h"
-#include "movie.h"
-#include "patch.h"
-#include "compat/strl.h"
-#include "hash.h"
-
-#if defined(_WIN32) && !defined(_XBOX)
-#include
-#include
-#include
-#elif defined(_XBOX)
-#include
-#define setmode _setmode
-#define INVALID_FILE_ATTRIBUTES -1
-#endif
-
-// Generic file loader.
-ssize_t read_file(const char *path, void **buf)
-{
- void *rom_buf = NULL;
- FILE *file = fopen(path, "rb");
- ssize_t rc = 0;
- size_t len = 0;
- if (!file)
- goto error;
-
- fseek(file, 0, SEEK_END);
- len = ftell(file);
- rewind(file);
- rom_buf = malloc(len + 1);
- if (!rom_buf)
- {
- RARCH_ERR("Couldn't allocate memory.\n");
- goto error;
- }
-
- if ((rc = fread(rom_buf, 1, len, file)) < (ssize_t)len)
- RARCH_WARN("Didn't read whole file.\n");
-
- *buf = rom_buf;
- // Allow for easy reading of strings to be safe.
- // Will only work with sane character formatting (Unix).
- ((char*)rom_buf)[len] = '\0';
- fclose(file);
- return rc;
-
-error:
- if (file)
- fclose(file);
- free(rom_buf);
- *buf = NULL;
- return -1;
-}
-
-// Reads file content as one string.
-bool read_file_string(const char *path, char **buf)
-{
- *buf = NULL;
- FILE *file = fopen(path, "r");
- size_t len = 0;
- char *ptr = NULL;
-
- if (!file)
- goto error;
-
- fseek(file, 0, SEEK_END);
- len = ftell(file) + 2; // Takes account of being able to read in EOF and '\0' at end.
- rewind(file);
-
- *buf = (char*)calloc(len, sizeof(char));
- if (!*buf)
- goto error;
-
- ptr = *buf;
-
- while (ptr && !feof(file))
- {
- size_t bufsize = (size_t)(((ptrdiff_t)*buf + (ptrdiff_t)len) - (ptrdiff_t)ptr);
- fgets(ptr, bufsize, file);
-
- ptr += strlen(ptr);
- }
-
- ptr = strchr(ptr, EOF);
- if (ptr)
- *ptr = '\0';
-
- fclose(file);
- return true;
-
-error:
- if (file)
- fclose(file);
- if (*buf)
- free(*buf);
- return false;
-}
-
-static void patch_rom(uint8_t **buf, ssize_t *size)
-{
- uint8_t *ret_buf = *buf;
- ssize_t ret_size = *size;
-
- const char *patch_desc = NULL;
- const char *patch_path = NULL;
- patch_error_t err = PATCH_UNKNOWN;
- patch_func_t func = NULL;
-
- ssize_t patch_size = 0;
- void *patch_data = NULL;
- bool success = false;
-
- if (g_extern.ups_pref + g_extern.bps_pref + g_extern.ips_pref > 1)
- {
- RARCH_WARN("Several patches are explicitly defined, ignoring all ...\n");
- return;
- }
-
- bool allow_bps = !g_extern.ups_pref && !g_extern.ips_pref;
- bool allow_ups = !g_extern.bps_pref && !g_extern.ips_pref;
- bool allow_ips = !g_extern.ups_pref && !g_extern.bps_pref;
-
- if (allow_ups && *g_extern.ups_name && (patch_size = read_file(g_extern.ups_name, &patch_data)) >= 0)
- {
- patch_desc = "UPS";
- patch_path = g_extern.ups_name;
- func = ups_apply_patch;
- }
- else if (allow_bps && *g_extern.bps_name && (patch_size = read_file(g_extern.bps_name, &patch_data)) >= 0)
- {
- patch_desc = "BPS";
- patch_path = g_extern.bps_name;
- func = bps_apply_patch;
- }
- else if (allow_ips && *g_extern.ips_name && (patch_size = read_file(g_extern.ips_name, &patch_data)) >= 0)
- {
- patch_desc = "IPS";
- patch_path = g_extern.ips_name;
- func = ips_apply_patch;
- }
- else
- {
- RARCH_LOG("Did not find a valid ROM patch.\n");
- return;
- }
-
- RARCH_LOG("Found %s file in \"%s\", attempting to patch ...\n", patch_desc, patch_path);
-
- size_t target_size = ret_size * 4; // Just to be sure ...
- uint8_t *patched_rom = (uint8_t*)malloc(target_size);
- if (!patched_rom)
- {
- RARCH_ERR("Failed to allocate memory for patched ROM ...\n");
- goto error;
- }
-
- err = func((const uint8_t*)patch_data, patch_size, ret_buf, ret_size, patched_rom, &target_size);
- if (err == PATCH_SUCCESS)
- {
- RARCH_LOG("ROM patched successfully (%s).\n", patch_desc);
- success = true;
- }
- else
- RARCH_ERR("Failed to patch %s: Error #%u\n", patch_desc, (unsigned)err);
-
- if (success)
- {
- free(ret_buf);
- *buf = patched_rom;
- *size = target_size;
- }
-
- if (patch_data)
- free(patch_data);
-
- return;
-
-error:
- *buf = ret_buf;
- *size = ret_size;
- if (patch_data)
- free(patch_data);
-}
-
-// Load SNES rom only. Applies a hack for headered ROMs.
-static ssize_t read_rom_file(FILE *file, void **buf)
-{
- ssize_t ret = 0;
- uint8_t *ret_buf = NULL;
-
- if (file == NULL) // stdin
- {
-#if defined(_WIN32) && !defined(_XBOX)
-//TODO: Warning on MSVC 2012 - warning C4996: 'setmode':
-//The POSIX name for this item is deprecated. Instead,
-//use the ISO C++ conformant name: _setmode
- setmode(0, O_BINARY);
-#endif
-
- RARCH_LOG("Reading ROM from stdin ...\n");
- size_t buf_size = 0xFFFFF; // Some initial guesstimate.
- size_t buf_ptr = 0;
- uint8_t *rom_buf = (uint8_t*)malloc(buf_size);
- if (rom_buf == NULL)
- {
- RARCH_ERR("Couldn't allocate memory.\n");
- return -1;
- }
-
- for (;;)
- {
- size_t ret = fread(rom_buf + buf_ptr, 1, buf_size - buf_ptr, stdin);
- buf_ptr += ret;
-
- // We've reached the end
- if (buf_ptr < buf_size)
- break;
-
- rom_buf = (uint8_t*)realloc(rom_buf, buf_size * 2);
- if (rom_buf == NULL)
- {
- RARCH_ERR("Couldn't allocate memory.\n");
- return -1;
- }
-
- buf_size *= 2;
- }
-
- ret_buf = rom_buf;
- ret = buf_ptr;
- }
- else
- {
- fseek(file, 0, SEEK_END);
- ret = ftell(file);
- rewind(file);
-
- void *rom_buf = malloc(ret);
- if (rom_buf == NULL)
- {
- RARCH_ERR("Couldn't allocate memory.\n");
- return -1;
- }
-
- if (fread(rom_buf, 1, ret, file) < (size_t)ret)
- {
- RARCH_ERR("Didn't read whole file.\n");
- free(rom_buf);
- return -1;
- }
-
- ret_buf = (uint8_t*)rom_buf;
- }
-
- if (!g_extern.block_patch)
- {
- // Attempt to apply a patch.
- patch_rom(&ret_buf, &ret);
- }
-
- // Remove copier header if present (512 first bytes).
- if ((ret & 0x7fff) == 512)
- {
- memmove(ret_buf, ret_buf + 512, ret - 512);
- ret -= 512;
- }
-
- g_extern.cart_crc = crc32_calculate(ret_buf, ret);
-#ifdef HAVE_XML
- sha256_hash(g_extern.sha256, ret_buf, ret);
- RARCH_LOG("SHA256 sum: %s\n", g_extern.sha256);
-#endif
- *buf = ret_buf;
- return ret;
-}
-
-
-// Dump stuff to file.
-static bool dump_to_file(const char *path, const void *data, size_t size)
-{
- FILE *file = fopen(path, "wb");
- if (!file)
- return false;
- else
- {
- bool ret = fwrite(data, 1, size, file) == size;
- fclose(file);
- return ret;
- }
-}
-
-static const char *ramtype2str(int type)
-{
- switch (type)
- {
- case RETRO_MEMORY_SAVE_RAM:
- case RETRO_MEMORY_SNES_GAME_BOY_RAM:
- case RETRO_MEMORY_SNES_BSX_RAM:
- return ".srm";
-
- case RETRO_MEMORY_RTC:
- case RETRO_MEMORY_SNES_GAME_BOY_RTC:
- return ".rtc";
-
- case RETRO_MEMORY_SNES_BSX_PRAM:
- return ".pram";
-
- case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
- return ".aram";
- case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
- return ".bram";
-
- default:
- return "";
- }
-}
-
-// Attempt to save valuable RAM data somewhere ...
-static void dump_to_file_desperate(const void *data, size_t size, int type)
-{
-#if defined(_WIN32) && !defined(_XBOX)
- const char *base = getenv("APPDATA");
-#elif defined(__CELLOS_LV2__) || defined(_XBOX)
- const char *base = NULL;
-#else
- const char *base = getenv("HOME");
-#endif
-
- if (!base)
- goto error;
-
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "%s/RetroArch-recovery-", base);
- char timebuf[PATH_MAX];
-
- time_t time_;
- time(&time_);
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d-%H-%M-%S", localtime(&time_));
- strlcat(path, timebuf, sizeof(path));
- strlcat(path, ramtype2str(type), sizeof(path));
-
- if (dump_to_file(path, data, size))
- RARCH_WARN("Succeeded in saving RAM data to \"%s\".\n", path);
- else
- goto error;
-
- return;
-
-error:
- RARCH_WARN("Failed ... Cannot recover save file.\n");
-}
-
-bool save_state(const char *path)
-{
- RARCH_LOG("Saving state: \"%s\".\n", path);
- size_t size = pretro_serialize_size();
- if (size == 0)
- return false;
-
- void *data = malloc(size);
- if (!data)
- {
- RARCH_ERR("Failed to allocate memory for save state buffer.\n");
- return false;
- }
-
- RARCH_LOG("State size: %d bytes.\n", (int)size);
- bool ret = pretro_serialize(data, size);
- if (ret)
- ret = dump_to_file(path, data, size);
-
- if (!ret)
- RARCH_ERR("Failed to save state to \"%s\".\n", path);
-
- free(data);
- return ret;
-}
-
-bool load_state(const char *path)
-{
- RARCH_LOG("Loading state: \"%s\".\n", path);
- void *buf = NULL;
- ssize_t size = read_file(path, &buf);
-
- if (size < 0)
- {
- RARCH_ERR("Failed to load state from \"%s\".\n", path);
- return false;
- }
-
- bool ret = true;
- RARCH_LOG("State size: %u bytes.\n", (unsigned)size);
-
- void *block_buf[2] = {NULL, NULL};
- int block_type[2] = {-1, -1};
- size_t block_size[2] = {0};
-
- if (g_settings.block_sram_overwrite)
- {
- RARCH_LOG("Blocking SRAM overwrite.\n");
- switch (g_extern.game_type)
- {
- case RARCH_CART_NORMAL:
- block_type[0] = RETRO_MEMORY_SAVE_RAM;
- block_type[1] = RETRO_MEMORY_RTC;
- break;
-
- case RARCH_CART_BSX:
- case RARCH_CART_BSX_SLOTTED:
- block_type[0] = RETRO_MEMORY_SNES_BSX_RAM;
- block_type[1] = RETRO_MEMORY_SNES_BSX_PRAM;
- break;
-
- case RARCH_CART_SUFAMI:
- block_type[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
- block_type[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
- break;
-
- case RARCH_CART_SGB:
- block_type[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
- block_type[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
- break;
- }
- }
-
- for (unsigned i = 0; i < 2; i++)
- if (block_type[i] != -1)
- block_size[i] = pretro_get_memory_size(block_type[i]);
-
- for (unsigned i = 0; i < 2; i++)
- if (block_size[i])
- block_buf[i] = malloc(block_size[i]);
-
- // Backup current SRAM which is overwritten by unserialize.
- for (unsigned i = 0; i < 2; i++)
- {
- if (block_buf[i])
- {
- const void *ptr = pretro_get_memory_data(block_type[i]);
- if (ptr)
- memcpy(block_buf[i], ptr, block_size[i]);
- }
- }
-
- ret = pretro_unserialize(buf, size);
-
- // Flush back :D
- for (unsigned i = 0; i < 2 && ret; i++)
- {
- if (block_buf[i])
- {
- void *ptr = pretro_get_memory_data(block_type[i]);
- if (ptr)
- memcpy(ptr, block_buf[i], block_size[i]);
- }
- }
-
- for (unsigned i = 0; i < 2; i++)
- if (block_buf[i])
- free(block_buf[i]);
-
- free(buf);
- return ret;
-}
-
-void load_ram_file(const char *path, int type)
-{
- size_t size = pretro_get_memory_size(type);
- void *data = pretro_get_memory_data(type);
-
- if (size == 0 || !data)
- return;
-
- void *buf = NULL;
- ssize_t rc = read_file(path, &buf);
- if (rc > 0 && rc <= (ssize_t)size)
- memcpy(data, buf, rc);
-
- free(buf);
-}
-
-void save_ram_file(const char *path, int type)
-{
- size_t size = pretro_get_memory_size(type);
- void *data = pretro_get_memory_data(type);
-
- if (data && size > 0)
- {
- if (!dump_to_file(path, data, size))
- {
- RARCH_ERR("Failed to save SRAM.\n");
- RARCH_WARN("Attempting to recover ...\n");
- dump_to_file_desperate(data, size, type);
- }
- }
-}
-
-static char *load_xml_map(const char *path)
-{
- char *xml_buf = NULL;
- if (*path)
- {
- if (read_file_string(path, &xml_buf))
- RARCH_LOG("Found XML memory map in \"%s\"\n", path);
- }
-
- return xml_buf;
-}
-
-#define MAX_ROMS 4
-
-static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms)
-{
- bool ret = true;
-
- if (roms == 0)
- return false;
-
- if (roms > MAX_ROMS)
- return false;
-
- void *rom_buf[MAX_ROMS] = {NULL};
- ssize_t rom_len[MAX_ROMS] = {0};
- struct retro_game_info info[MAX_ROMS] = {{NULL}};
-
- if (!g_extern.system.info.need_fullpath)
- {
- if ((rom_len[0] = read_rom_file(g_extern.rom_file, &rom_buf[0])) == -1)
- {
- RARCH_ERR("Could not read ROM file.\n");
- return false;
- }
-
- if (g_extern.rom_file)
- fclose(g_extern.rom_file);
-
- RARCH_LOG("ROM size: %u bytes.\n", (unsigned)rom_len[0]);
- }
- else
- {
- if (!g_extern.rom_file)
- {
- RARCH_ERR("Implementation requires a full path to be set, cannot load ROM from stdin. Aborting ...\n");
- return false;
- }
-
- fclose(g_extern.rom_file);
- RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n");
- }
-
- char *xml_buf = load_xml_map(g_extern.xml_name);
-
- info[0].path = rom_paths[0];
- info[0].data = rom_buf[0];
- info[0].size = rom_len[0];
- info[0].meta = xml_buf;
-
- for (size_t i = 1; i < roms; i++)
- {
- if (rom_paths[i] &&
- !g_extern.system.info.need_fullpath &&
- (rom_len[i] = read_file(rom_paths[i], &rom_buf[i])) == -1)
- {
- RARCH_ERR("Could not read ROM file: \"%s\".\n", rom_paths[i]);
- ret = false;
- goto end;
- }
-
- info[i].path = rom_paths[i];
- info[i].data = rom_buf[i];
- info[i].size = rom_len[i];
- }
-
- if (rom_type == 0)
- ret = pretro_load_game(&info[0]);
- else
- ret = pretro_load_game_special(rom_type, info, roms);
-
- if (!ret)
- RARCH_ERR("Failed to load game.\n");
-
-end:
- for (unsigned i = 0; i < MAX_ROMS; i++)
- free(rom_buf[i]);
- free(xml_buf);
-
- return ret;
-}
-
-static bool load_normal_rom(void)
-{
- const char *path = *g_extern.fullpath ? g_extern.fullpath : NULL;
- return load_roms(0, &path, 1);
-}
-
-static bool load_sgb_rom(void)
-{
- const char *path[2] = {
- *g_extern.fullpath ? g_extern.fullpath : NULL,
- g_extern.gb_rom_path
- };
-
- return load_roms(RETRO_GAME_TYPE_SUPER_GAME_BOY, path, 2);
-}
-
-static bool load_bsx_rom(bool slotted)
-{
- const char *path[2] = {
- *g_extern.fullpath ? g_extern.fullpath : NULL,
- g_extern.bsx_rom_path
- };
-
- return load_roms(slotted ? RETRO_GAME_TYPE_BSX_SLOTTED : RETRO_GAME_TYPE_BSX, path, 2);
-}
-
-static bool load_sufami_rom(void)
-{
- const char *path[3] = {
- *g_extern.fullpath ? g_extern.fullpath : NULL,
- *g_extern.sufami_rom_path[0] ? g_extern.sufami_rom_path[0] : NULL,
- *g_extern.sufami_rom_path[1] ? g_extern.sufami_rom_path[1] : NULL,
- };
-
- return load_roms(RETRO_GAME_TYPE_SUFAMI_TURBO, path, 3);
-}
-
-bool init_rom_file(enum rarch_game_type type)
-{
- switch (type)
- {
- case RARCH_CART_SGB:
- if (!load_sgb_rom())
- return false;
- break;
-
- case RARCH_CART_NORMAL:
- if (!load_normal_rom())
- return false;
- break;
-
- case RARCH_CART_BSX:
- if (!load_bsx_rom(false))
- return false;
- break;
-
- case RARCH_CART_BSX_SLOTTED:
- if (!load_bsx_rom(true))
- return false;
- break;
-
- case RARCH_CART_SUFAMI:
- if (!load_sufami_rom())
- return false;
- break;
-
- default:
- RARCH_ERR("Invalid ROM type.\n");
- return false;
- }
-
- return true;
-}
-
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - 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 .
+ */
+
+#include "file.h"
+#include "general.h"
+#include
+#include "boolean.h"
+#include "libretro.h"
+#include
+#include
+#include "dynamic.h"
+#include "movie.h"
+#include "patch.h"
+#include "compat/strl.h"
+#include "hash.h"
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include
+#include
+#include
+#elif defined(_XBOX)
+#include
+#define setmode _setmode
+#define INVALID_FILE_ATTRIBUTES -1
+#endif
+
+// Generic file loader.
+ssize_t read_file(const char *path, void **buf)
+{
+ void *rom_buf = NULL;
+ FILE *file = fopen(path, "rb");
+ ssize_t rc = 0;
+ size_t len = 0;
+ if (!file)
+ goto error;
+
+ fseek(file, 0, SEEK_END);
+ len = ftell(file);
+ rewind(file);
+ rom_buf = malloc(len + 1);
+ if (!rom_buf)
+ {
+ RARCH_ERR("Couldn't allocate memory.\n");
+ goto error;
+ }
+
+ if ((rc = fread(rom_buf, 1, len, file)) < (ssize_t)len)
+ RARCH_WARN("Didn't read whole file.\n");
+
+ *buf = rom_buf;
+ // Allow for easy reading of strings to be safe.
+ // Will only work with sane character formatting (Unix).
+ ((char*)rom_buf)[len] = '\0';
+ fclose(file);
+ return rc;
+
+error:
+ if (file)
+ fclose(file);
+ free(rom_buf);
+ *buf = NULL;
+ return -1;
+}
+
+// Reads file content as one string.
+bool read_file_string(const char *path, char **buf)
+{
+ *buf = NULL;
+ FILE *file = fopen(path, "r");
+ size_t len = 0;
+ char *ptr = NULL;
+
+ if (!file)
+ goto error;
+
+ fseek(file, 0, SEEK_END);
+ len = ftell(file) + 2; // Takes account of being able to read in EOF and '\0' at end.
+ rewind(file);
+
+ *buf = (char*)calloc(len, sizeof(char));
+ if (!*buf)
+ goto error;
+
+ ptr = *buf;
+
+ while (ptr && !feof(file))
+ {
+ size_t bufsize = (size_t)(((ptrdiff_t)*buf + (ptrdiff_t)len) - (ptrdiff_t)ptr);
+ fgets(ptr, bufsize, file);
+
+ ptr += strlen(ptr);
+ }
+
+ ptr = strchr(ptr, EOF);
+ if (ptr)
+ *ptr = '\0';
+
+ fclose(file);
+ return true;
+
+error:
+ if (file)
+ fclose(file);
+ if (*buf)
+ free(*buf);
+ return false;
+}
+
+static void patch_rom(uint8_t **buf, ssize_t *size)
+{
+ uint8_t *ret_buf = *buf;
+ ssize_t ret_size = *size;
+
+ const char *patch_desc = NULL;
+ const char *patch_path = NULL;
+ patch_error_t err = PATCH_UNKNOWN;
+ patch_func_t func = NULL;
+
+ ssize_t patch_size = 0;
+ void *patch_data = NULL;
+ bool success = false;
+
+ if (g_extern.ups_pref + g_extern.bps_pref + g_extern.ips_pref > 1)
+ {
+ RARCH_WARN("Several patches are explicitly defined, ignoring all ...\n");
+ return;
+ }
+
+ bool allow_bps = !g_extern.ups_pref && !g_extern.ips_pref;
+ bool allow_ups = !g_extern.bps_pref && !g_extern.ips_pref;
+ bool allow_ips = !g_extern.ups_pref && !g_extern.bps_pref;
+
+ if (allow_ups && *g_extern.ups_name && (patch_size = read_file(g_extern.ups_name, &patch_data)) >= 0)
+ {
+ patch_desc = "UPS";
+ patch_path = g_extern.ups_name;
+ func = ups_apply_patch;
+ }
+ else if (allow_bps && *g_extern.bps_name && (patch_size = read_file(g_extern.bps_name, &patch_data)) >= 0)
+ {
+ patch_desc = "BPS";
+ patch_path = g_extern.bps_name;
+ func = bps_apply_patch;
+ }
+ else if (allow_ips && *g_extern.ips_name && (patch_size = read_file(g_extern.ips_name, &patch_data)) >= 0)
+ {
+ patch_desc = "IPS";
+ patch_path = g_extern.ips_name;
+ func = ips_apply_patch;
+ }
+ else
+ {
+ RARCH_LOG("Did not find a valid ROM patch.\n");
+ return;
+ }
+
+ RARCH_LOG("Found %s file in \"%s\", attempting to patch ...\n", patch_desc, patch_path);
+
+ size_t target_size = ret_size * 4; // Just to be sure ...
+ uint8_t *patched_rom = (uint8_t*)malloc(target_size);
+ if (!patched_rom)
+ {
+ RARCH_ERR("Failed to allocate memory for patched ROM ...\n");
+ goto error;
+ }
+
+ err = func((const uint8_t*)patch_data, patch_size, ret_buf, ret_size, patched_rom, &target_size);
+ if (err == PATCH_SUCCESS)
+ {
+ RARCH_LOG("ROM patched successfully (%s).\n", patch_desc);
+ success = true;
+ }
+ else
+ RARCH_ERR("Failed to patch %s: Error #%u\n", patch_desc, (unsigned)err);
+
+ if (success)
+ {
+ free(ret_buf);
+ *buf = patched_rom;
+ *size = target_size;
+ }
+
+ if (patch_data)
+ free(patch_data);
+
+ return;
+
+error:
+ *buf = ret_buf;
+ *size = ret_size;
+ if (patch_data)
+ free(patch_data);
+}
+
+// Load SNES rom only. Applies a hack for headered ROMs.
+static ssize_t read_rom_file(FILE *file, void **buf)
+{
+ ssize_t ret = 0;
+ uint8_t *ret_buf = NULL;
+
+ if (file == NULL) // stdin
+ {
+#if defined(_WIN32) && !defined(_XBOX)
+ _setmode(0, O_BINARY);
+#endif
+
+ RARCH_LOG("Reading ROM from stdin ...\n");
+ size_t buf_size = 0xFFFFF; // Some initial guesstimate.
+ size_t buf_ptr = 0;
+ uint8_t *rom_buf = (uint8_t*)malloc(buf_size);
+ if (rom_buf == NULL)
+ {
+ RARCH_ERR("Couldn't allocate memory.\n");
+ return -1;
+ }
+
+ for (;;)
+ {
+ size_t ret = fread(rom_buf + buf_ptr, 1, buf_size - buf_ptr, stdin);
+ buf_ptr += ret;
+
+ // We've reached the end
+ if (buf_ptr < buf_size)
+ break;
+
+ rom_buf = (uint8_t*)realloc(rom_buf, buf_size * 2);
+ if (rom_buf == NULL)
+ {
+ RARCH_ERR("Couldn't allocate memory.\n");
+ return -1;
+ }
+
+ buf_size *= 2;
+ }
+
+ ret_buf = rom_buf;
+ ret = buf_ptr;
+ }
+ else
+ {
+ fseek(file, 0, SEEK_END);
+ ret = ftell(file);
+ rewind(file);
+
+ void *rom_buf = malloc(ret);
+ if (rom_buf == NULL)
+ {
+ RARCH_ERR("Couldn't allocate memory.\n");
+ return -1;
+ }
+
+ if (fread(rom_buf, 1, ret, file) < (size_t)ret)
+ {
+ RARCH_ERR("Didn't read whole file.\n");
+ free(rom_buf);
+ return -1;
+ }
+
+ ret_buf = (uint8_t*)rom_buf;
+ }
+
+ if (!g_extern.block_patch)
+ {
+ // Attempt to apply a patch.
+ patch_rom(&ret_buf, &ret);
+ }
+
+ // Remove copier header if present (512 first bytes).
+ if ((ret & 0x7fff) == 512)
+ {
+ memmove(ret_buf, ret_buf + 512, ret - 512);
+ ret -= 512;
+ }
+
+ g_extern.cart_crc = crc32_calculate(ret_buf, ret);
+#ifdef HAVE_XML
+ sha256_hash(g_extern.sha256, ret_buf, ret);
+ RARCH_LOG("SHA256 sum: %s\n", g_extern.sha256);
+#endif
+ *buf = ret_buf;
+ return ret;
+}
+
+
+// Dump stuff to file.
+static bool dump_to_file(const char *path, const void *data, size_t size)
+{
+ FILE *file = fopen(path, "wb");
+ if (!file)
+ return false;
+ else
+ {
+ bool ret = fwrite(data, 1, size, file) == size;
+ fclose(file);
+ return ret;
+ }
+}
+
+static const char *ramtype2str(int type)
+{
+ switch (type)
+ {
+ case RETRO_MEMORY_SAVE_RAM:
+ case RETRO_MEMORY_SNES_GAME_BOY_RAM:
+ case RETRO_MEMORY_SNES_BSX_RAM:
+ return ".srm";
+
+ case RETRO_MEMORY_RTC:
+ case RETRO_MEMORY_SNES_GAME_BOY_RTC:
+ return ".rtc";
+
+ case RETRO_MEMORY_SNES_BSX_PRAM:
+ return ".pram";
+
+ case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
+ return ".aram";
+ case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
+ return ".bram";
+
+ default:
+ return "";
+ }
+}
+
+// Attempt to save valuable RAM data somewhere ...
+static void dump_to_file_desperate(const void *data, size_t size, int type)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+ const char *base = getenv("APPDATA");
+#elif defined(__CELLOS_LV2__) || defined(_XBOX)
+ const char *base = NULL;
+#else
+ const char *base = getenv("HOME");
+#endif
+
+ if (!base)
+ goto error;
+
+ char path[PATH_MAX];
+ snprintf(path, sizeof(path), "%s/RetroArch-recovery-", base);
+ char timebuf[PATH_MAX];
+
+ time_t time_;
+ time(&time_);
+ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d-%H-%M-%S", localtime(&time_));
+ strlcat(path, timebuf, sizeof(path));
+ strlcat(path, ramtype2str(type), sizeof(path));
+
+ if (dump_to_file(path, data, size))
+ RARCH_WARN("Succeeded in saving RAM data to \"%s\".\n", path);
+ else
+ goto error;
+
+ return;
+
+error:
+ RARCH_WARN("Failed ... Cannot recover save file.\n");
+}
+
+bool save_state(const char *path)
+{
+ RARCH_LOG("Saving state: \"%s\".\n", path);
+ size_t size = pretro_serialize_size();
+ if (size == 0)
+ return false;
+
+ void *data = malloc(size);
+ if (!data)
+ {
+ RARCH_ERR("Failed to allocate memory for save state buffer.\n");
+ return false;
+ }
+
+ RARCH_LOG("State size: %d bytes.\n", (int)size);
+ bool ret = pretro_serialize(data, size);
+ if (ret)
+ ret = dump_to_file(path, data, size);
+
+ if (!ret)
+ RARCH_ERR("Failed to save state to \"%s\".\n", path);
+
+ free(data);
+ return ret;
+}
+
+bool load_state(const char *path)
+{
+ RARCH_LOG("Loading state: \"%s\".\n", path);
+ void *buf = NULL;
+ ssize_t size = read_file(path, &buf);
+
+ if (size < 0)
+ {
+ RARCH_ERR("Failed to load state from \"%s\".\n", path);
+ return false;
+ }
+
+ bool ret = true;
+ RARCH_LOG("State size: %u bytes.\n", (unsigned)size);
+
+ void *block_buf[2] = {NULL, NULL};
+ int block_type[2] = {-1, -1};
+ size_t block_size[2] = {0};
+
+ if (g_settings.block_sram_overwrite)
+ {
+ RARCH_LOG("Blocking SRAM overwrite.\n");
+ switch (g_extern.game_type)
+ {
+ case RARCH_CART_NORMAL:
+ block_type[0] = RETRO_MEMORY_SAVE_RAM;
+ block_type[1] = RETRO_MEMORY_RTC;
+ break;
+
+ case RARCH_CART_BSX:
+ case RARCH_CART_BSX_SLOTTED:
+ block_type[0] = RETRO_MEMORY_SNES_BSX_RAM;
+ block_type[1] = RETRO_MEMORY_SNES_BSX_PRAM;
+ break;
+
+ case RARCH_CART_SUFAMI:
+ block_type[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
+ block_type[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
+ break;
+
+ case RARCH_CART_SGB:
+ block_type[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
+ block_type[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
+ break;
+ }
+ }
+
+ for (unsigned i = 0; i < 2; i++)
+ if (block_type[i] != -1)
+ block_size[i] = pretro_get_memory_size(block_type[i]);
+
+ for (unsigned i = 0; i < 2; i++)
+ if (block_size[i])
+ block_buf[i] = malloc(block_size[i]);
+
+ // Backup current SRAM which is overwritten by unserialize.
+ for (unsigned i = 0; i < 2; i++)
+ {
+ if (block_buf[i])
+ {
+ const void *ptr = pretro_get_memory_data(block_type[i]);
+ if (ptr)
+ memcpy(block_buf[i], ptr, block_size[i]);
+ }
+ }
+
+ ret = pretro_unserialize(buf, size);
+
+ // Flush back :D
+ for (unsigned i = 0; i < 2 && ret; i++)
+ {
+ if (block_buf[i])
+ {
+ void *ptr = pretro_get_memory_data(block_type[i]);
+ if (ptr)
+ memcpy(ptr, block_buf[i], block_size[i]);
+ }
+ }
+
+ for (unsigned i = 0; i < 2; i++)
+ if (block_buf[i])
+ free(block_buf[i]);
+
+ free(buf);
+ return ret;
+}
+
+void load_ram_file(const char *path, int type)
+{
+ size_t size = pretro_get_memory_size(type);
+ void *data = pretro_get_memory_data(type);
+
+ if (size == 0 || !data)
+ return;
+
+ void *buf = NULL;
+ ssize_t rc = read_file(path, &buf);
+ if (rc > 0 && rc <= (ssize_t)size)
+ memcpy(data, buf, rc);
+
+ free(buf);
+}
+
+void save_ram_file(const char *path, int type)
+{
+ size_t size = pretro_get_memory_size(type);
+ void *data = pretro_get_memory_data(type);
+
+ if (data && size > 0)
+ {
+ if (!dump_to_file(path, data, size))
+ {
+ RARCH_ERR("Failed to save SRAM.\n");
+ RARCH_WARN("Attempting to recover ...\n");
+ dump_to_file_desperate(data, size, type);
+ }
+ }
+}
+
+static char *load_xml_map(const char *path)
+{
+ char *xml_buf = NULL;
+ if (*path)
+ {
+ if (read_file_string(path, &xml_buf))
+ RARCH_LOG("Found XML memory map in \"%s\"\n", path);
+ }
+
+ return xml_buf;
+}
+
+#define MAX_ROMS 4
+
+static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms)
+{
+ bool ret = true;
+
+ if (roms == 0)
+ return false;
+
+ if (roms > MAX_ROMS)
+ return false;
+
+ void *rom_buf[MAX_ROMS] = {NULL};
+ ssize_t rom_len[MAX_ROMS] = {0};
+ struct retro_game_info info[MAX_ROMS] = {{NULL}};
+
+ if (!g_extern.system.info.need_fullpath)
+ {
+ if ((rom_len[0] = read_rom_file(g_extern.rom_file, &rom_buf[0])) == -1)
+ {
+ RARCH_ERR("Could not read ROM file.\n");
+ return false;
+ }
+
+ if (g_extern.rom_file)
+ fclose(g_extern.rom_file);
+
+ RARCH_LOG("ROM size: %u bytes.\n", (unsigned)rom_len[0]);
+ }
+ else
+ {
+ if (!g_extern.rom_file)
+ {
+ RARCH_ERR("Implementation requires a full path to be set, cannot load ROM from stdin. Aborting ...\n");
+ return false;
+ }
+
+ fclose(g_extern.rom_file);
+ RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n");
+ }
+
+ char *xml_buf = load_xml_map(g_extern.xml_name);
+
+ info[0].path = rom_paths[0];
+ info[0].data = rom_buf[0];
+ info[0].size = rom_len[0];
+ info[0].meta = xml_buf;
+
+ for (size_t i = 1; i < roms; i++)
+ {
+ if (rom_paths[i] &&
+ !g_extern.system.info.need_fullpath &&
+ (rom_len[i] = read_file(rom_paths[i], &rom_buf[i])) == -1)
+ {
+ RARCH_ERR("Could not read ROM file: \"%s\".\n", rom_paths[i]);
+ ret = false;
+ goto end;
+ }
+
+ info[i].path = rom_paths[i];
+ info[i].data = rom_buf[i];
+ info[i].size = rom_len[i];
+ }
+
+ if (rom_type == 0)
+ ret = pretro_load_game(&info[0]);
+ else
+ ret = pretro_load_game_special(rom_type, info, roms);
+
+ if (!ret)
+ RARCH_ERR("Failed to load game.\n");
+
+end:
+ for (unsigned i = 0; i < MAX_ROMS; i++)
+ free(rom_buf[i]);
+ free(xml_buf);
+
+ return ret;
+}
+
+static bool load_normal_rom(void)
+{
+ const char *path = *g_extern.fullpath ? g_extern.fullpath : NULL;
+ return load_roms(0, &path, 1);
+}
+
+static bool load_sgb_rom(void)
+{
+ const char *path[2] = {
+ *g_extern.fullpath ? g_extern.fullpath : NULL,
+ g_extern.gb_rom_path
+ };
+
+ return load_roms(RETRO_GAME_TYPE_SUPER_GAME_BOY, path, 2);
+}
+
+static bool load_bsx_rom(bool slotted)
+{
+ const char *path[2] = {
+ *g_extern.fullpath ? g_extern.fullpath : NULL,
+ g_extern.bsx_rom_path
+ };
+
+ return load_roms(slotted ? RETRO_GAME_TYPE_BSX_SLOTTED : RETRO_GAME_TYPE_BSX, path, 2);
+}
+
+static bool load_sufami_rom(void)
+{
+ const char *path[3] = {
+ *g_extern.fullpath ? g_extern.fullpath : NULL,
+ *g_extern.sufami_rom_path[0] ? g_extern.sufami_rom_path[0] : NULL,
+ *g_extern.sufami_rom_path[1] ? g_extern.sufami_rom_path[1] : NULL,
+ };
+
+ return load_roms(RETRO_GAME_TYPE_SUFAMI_TURBO, path, 3);
+}
+
+bool init_rom_file(enum rarch_game_type type)
+{
+ switch (type)
+ {
+ case RARCH_CART_SGB:
+ if (!load_sgb_rom())
+ return false;
+ break;
+
+ case RARCH_CART_NORMAL:
+ if (!load_normal_rom())
+ return false;
+ break;
+
+ case RARCH_CART_BSX:
+ if (!load_bsx_rom(false))
+ return false;
+ break;
+
+ case RARCH_CART_BSX_SLOTTED:
+ if (!load_bsx_rom(true))
+ return false;
+ break;
+
+ case RARCH_CART_SUFAMI:
+ if (!load_sufami_rom())
+ return false;
+ break;
+
+ default:
+ RARCH_ERR("Invalid ROM type.\n");
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/gfx/context/wgl_ctx.c b/gfx/context/wgl_ctx.c
index 0914555278..e21b3b4316 100644
--- a/gfx/context/wgl_ctx.c
+++ b/gfx/context/wgl_ctx.c
@@ -1,456 +1,449 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
- * Copyright (C) 2011-2012 - 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 .
- */
-
-// Win32/WGL context.
-
-// TODO: Rewrite initializer lists - not supported on MSVC 2010/2012
-
-#include "../../driver.h"
-#include "../gfx_context.h"
-#include "../gl_common.h"
-#include "../gfx_common.h"
-#include
-
-#define IDI_ICON 1
-#define MAX_MONITORS 9
-
-static HWND g_hwnd;
-static HGLRC g_hrc;
-static HDC g_hdc;
-static HMONITOR g_last_hm;
-static HMONITOR g_all_hms[MAX_MONITORS];
-static unsigned g_num_mons;
-
-static bool g_quit;
-static bool g_inited;
-static unsigned g_interval;
-
-static unsigned g_resize_width;
-static unsigned g_resize_height;
-static bool g_resized;
-
-static bool g_restore_desktop;
-
-static void gfx_ctx_get_video_size(unsigned *width, unsigned *height);
-static void gfx_ctx_destroy(void);
-
-static BOOL (APIENTRY *p_swap_interval)(int);
-
-static void setup_pixel_format(HDC hdc)
-{
- PIXELFORMATDESCRIPTOR pfd = {0};
- pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = 32;
- pfd.cDepthBits = 0;
- pfd.cStencilBits = 0;
- pfd.iLayerType = PFD_MAIN_PLANE;
-
- SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
-}
-
-static void create_gl_context(HWND hwnd)
-{
- g_hdc = GetDC(hwnd);
- setup_pixel_format(g_hdc);
-
- g_hrc = wglCreateContext(g_hdc);
- if (g_hrc)
- {
- if (wglMakeCurrent(g_hdc, g_hrc))
- g_inited = true;
- else
- g_quit = true;
- }
- else
- g_quit = true;
-}
-
-static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
- WPARAM wparam, LPARAM lparam)
-{
- switch (message)
- {
- case WM_SYSCOMMAND:
- // Prevent screensavers, etc, while running.
- switch (wparam)
- {
- case SC_SCREENSAVE:
- case SC_MONITORPOWER:
- return 0;
- }
- break;
-
- case WM_SYSKEYDOWN:
- switch (wparam)
- {
- case VK_F10:
- case VK_MENU:
- case VK_RSHIFT:
- return 0;
- }
- break;
-
- case WM_CREATE:
- create_gl_context(hwnd);
- return 0;
-
- case WM_CLOSE:
- case WM_DESTROY:
- case WM_QUIT:
- g_quit = true;
- return 0;
-
- case WM_SIZE:
- // Do not send resize message if we minimize.
- if (wparam != SIZE_MAXHIDE && wparam != SIZE_MINIMIZED)
- {
- g_resize_width = LOWORD(lparam);
- g_resize_height = HIWORD(lparam);
- g_resized = true;
- }
- return 0;
- }
-
- return DefWindowProc(hwnd, message, wparam, lparam);
-}
-
-static void gfx_ctx_swap_interval(unsigned interval)
-{
- g_interval = interval;
-
- if (g_hrc && p_swap_interval)
- {
- RARCH_LOG("[WGL]: wglSwapInterval(%u)\n", g_interval);
- if (!p_swap_interval(g_interval))
- RARCH_WARN("[WGL]: wglSwapInterval() failed.\n");
- }
-}
-
-static void gfx_ctx_check_window(bool *quit,
- bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
-{
- (void)frame_count;
-
- MSG msg;
- while (PeekMessage(&msg, g_hwnd, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- *quit = g_quit;
- if (g_resized)
- {
- *resize = true;
- *width = g_resize_width;
- *height = g_resize_height;
- g_resized = false;
- }
-}
-
-static void gfx_ctx_swap_buffers(void)
-{
- SwapBuffers(g_hdc);
-}
-
-static void gfx_ctx_set_resize(unsigned width, unsigned height)
-{
- (void)width;
- (void)height;
-}
-
-static void gfx_ctx_update_window_title(bool reset)
-{
- if (reset)
- gfx_window_title_reset();
-
- char buf[128];
- if (gfx_window_title(buf, sizeof(buf)))
- SetWindowText(g_hwnd, buf);
-}
-
-static void gfx_ctx_get_video_size(unsigned *width, unsigned *height)
-{
- if (!g_hwnd)
- {
- RECT screen_rect;
- GetClientRect(GetDesktopWindow(), &screen_rect);
- *width = screen_rect.right - screen_rect.left;
- *height = screen_rect.bottom - screen_rect.top;
- }
- else
- {
- *width = g_resize_width;
- *height = g_resize_height;
- }
-}
-
-BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
-{
- g_all_hms[g_num_mons++] = hMonitor;
- return TRUE;
-}
-
-static bool gfx_ctx_init(void)
-{
- if (g_inited)
- return false;
-
- g_quit = false;
- g_restore_desktop = false;
-
- g_num_mons = 0;
- EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, 0);
-
- WNDCLASSEX wndclass = {0};
- wndclass.cbSize = sizeof(wndclass);
- wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
- wndclass.lpfnWndProc = WndProc;
- wndclass.hInstance = GetModuleHandle(NULL);
- wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
- wndclass.lpszClassName = "RetroArch";
- wndclass.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON));
- wndclass.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);
-
- if (!RegisterClassEx(&wndclass))
- return false;
-
- return true;
-}
-
-static bool set_fullscreen(unsigned width, unsigned height, char *dev_name)
-{
- DEVMODE devmode;
- memset(&devmode, 0, sizeof(devmode));
- devmode.dmSize = sizeof(DEVMODE);
- devmode.dmPelsWidth = width;
- devmode.dmPelsHeight = height;
- devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
-
- RARCH_LOG("[WGL]: Setting fullscreen to %ux%u on device %s.\n", width, height, dev_name);
- return ChangeDisplaySettingsEx(dev_name, &devmode, NULL, CDS_FULLSCREEN, NULL) == DISP_CHANGE_SUCCESSFUL;
-}
-
-static void show_cursor(bool show)
-{
- if (show)
- while (ShowCursor(TRUE) < 0);
- else
- while (ShowCursor(FALSE) >= 0);
-}
-
-static bool gfx_ctx_set_video_mode(
- unsigned width, unsigned height,
- unsigned bits, bool fullscreen)
-{
- (void)bits;
-
- DWORD style;
-#if defined(_WIN32)
- MONITORINFOEX current_mon;
-#else
- MONITORINFOEX current_mon = {{0}};
-#endif
- current_mon.cbSize = sizeof(MONITORINFOEX);
- if (!g_last_hm)
- g_last_hm = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST);
- HMONITOR hm_to_use = g_last_hm;
-
- unsigned fs_monitor = g_settings.video.monitor_index;
- if (fs_monitor && fs_monitor <= g_num_mons && g_all_hms[fs_monitor - 1])
- hm_to_use = g_all_hms[fs_monitor - 1];
-
- GetMonitorInfo(hm_to_use, (MONITORINFO*)¤t_mon);
-
- g_resize_width = width;
- g_resize_height = height;
-
- bool windowed_full = g_settings.video.windowed_fullscreen;
- if (fullscreen)
- {
- if (windowed_full)
- {
- style = WS_EX_TOPMOST | WS_POPUP;
- g_resize_width = width = current_mon.rcMonitor.right - current_mon.rcMonitor.left;
- g_resize_height = height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top;
- }
- else
- {
- style = WS_POPUP | WS_VISIBLE;
-
- if (!set_fullscreen(width, height, current_mon.szDevice))
- goto error;
-
- // display settings might have changed, get new coordinates
- GetMonitorInfo(hm_to_use, (MONITORINFO*)¤t_mon);
- g_restore_desktop = true;
- }
- }
- else
- {
- style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
- RECT rect = {0};
- rect.right = width;
- rect.bottom = height;
- AdjustWindowRect(&rect, style, FALSE);
- width = rect.right - rect.left;
- height = rect.bottom - rect.top;
- }
-
- g_hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style,
- fullscreen ? current_mon.rcMonitor.left : CW_USEDEFAULT,
- fullscreen ? current_mon.rcMonitor.top : CW_USEDEFAULT,
- width, height,
- NULL, NULL, NULL, NULL);
-
- if (!g_hwnd)
- goto error;
-
- gfx_ctx_update_window_title(true);
-
- if (!fullscreen || windowed_full)
- {
- ShowWindow(g_hwnd, SW_RESTORE);
- UpdateWindow(g_hwnd);
- SetForegroundWindow(g_hwnd);
- SetFocus(g_hwnd);
- }
-
- show_cursor(!fullscreen);
-
- // Wait until GL context is created (or failed to do so ...)
- MSG msg;
- while (!g_inited && !g_quit && GetMessage(&msg, g_hwnd, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- if (g_quit)
- goto error;
-
- p_swap_interval = (BOOL (APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT");
-
- gfx_ctx_swap_interval(g_interval);
-
- driver.display_type = RARCH_DISPLAY_WIN32;
- driver.video_display = 0;
- driver.video_window = (uintptr_t)g_hwnd;
-
- return true;
-
-error:
- gfx_ctx_destroy();
- return false;
-}
-
-static void gfx_ctx_destroy(void)
-{
- if (g_hrc)
- {
- wglMakeCurrent(NULL, NULL);
- wglDeleteContext(g_hrc);
- g_hrc = NULL;
- }
-
- if (g_hwnd && g_hdc)
- {
- ReleaseDC(g_hwnd, g_hdc);
- g_hdc = NULL;
- }
-
- if (g_hwnd)
- {
- g_last_hm = MonitorFromWindow(g_hwnd, MONITOR_DEFAULTTONEAREST);
- DestroyWindow(g_hwnd);
- UnregisterClass("RetroArch", GetModuleHandle(NULL));
- g_hwnd = NULL;
- }
-
- if (g_restore_desktop)
- {
-#if defined(_WIN32)
- MONITORINFOEX current_mon;
-#else
- MONITORINFOEX current_mon = {{0}};
-#endif
- current_mon.cbSize = sizeof(MONITORINFOEX);
- GetMonitorInfo(g_last_hm, (MONITORINFO*)¤t_mon);
- ChangeDisplaySettingsEx(current_mon.szDevice, NULL, NULL, 0, NULL);
- g_restore_desktop = false;
- }
-
- g_inited = false;
-}
-
-static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data)
-{
- void *dinput = input_dinput.init();
- *input = dinput ? &input_dinput : NULL;
- *input_data = dinput;
-}
-
-static bool gfx_ctx_has_focus(void)
-{
- if (!g_inited)
- return false;
-
- return GetFocus() == g_hwnd;
-}
-
-static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol)
-{
- return (gfx_ctx_proc_t)wglGetProcAddress(symbol);
-}
-
-static bool gfx_ctx_bind_api(enum gfx_ctx_api api)
-{
- return api == GFX_CTX_OPENGL_API;
-}
-
-static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video)
-{
- return false;
-}
-
-static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle)
-{
- return false;
-}
-
-const gfx_ctx_driver_t gfx_ctx_wgl = {
- gfx_ctx_init,
- gfx_ctx_destroy,
- gfx_ctx_bind_api,
- gfx_ctx_swap_interval,
- gfx_ctx_set_video_mode,
- gfx_ctx_get_video_size,
- NULL,
- gfx_ctx_update_window_title,
- gfx_ctx_check_window,
- gfx_ctx_set_resize,
- gfx_ctx_has_focus,
- gfx_ctx_swap_buffers,
- gfx_ctx_input_driver,
- gfx_ctx_get_proc_address,
- gfx_ctx_init_egl_image_buffer,
- gfx_ctx_write_egl_image,
- "wgl",
-};
-
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2012 - 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 .
+ */
+
+// Win32/WGL context.
+
+#include "../../driver.h"
+#include "../gfx_context.h"
+#include "../gl_common.h"
+#include "../gfx_common.h"
+#include
+#include
+
+#define IDI_ICON 1
+#define MAX_MONITORS 9
+
+static HWND g_hwnd;
+static HGLRC g_hrc;
+static HDC g_hdc;
+static HMONITOR g_last_hm;
+static HMONITOR g_all_hms[MAX_MONITORS];
+static unsigned g_num_mons;
+
+static bool g_quit;
+static bool g_inited;
+static unsigned g_interval;
+
+static unsigned g_resize_width;
+static unsigned g_resize_height;
+static bool g_resized;
+
+static bool g_restore_desktop;
+
+static void gfx_ctx_get_video_size(unsigned *width, unsigned *height);
+static void gfx_ctx_destroy(void);
+
+static BOOL (APIENTRY *p_swap_interval)(int);
+
+static void setup_pixel_format(HDC hdc)
+{
+ PIXELFORMATDESCRIPTOR pfd = {0};
+ pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 32;
+ pfd.cDepthBits = 0;
+ pfd.cStencilBits = 0;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+
+ SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
+}
+
+static void create_gl_context(HWND hwnd)
+{
+ g_hdc = GetDC(hwnd);
+ setup_pixel_format(g_hdc);
+
+ g_hrc = wglCreateContext(g_hdc);
+ if (g_hrc)
+ {
+ if (wglMakeCurrent(g_hdc, g_hrc))
+ g_inited = true;
+ else
+ g_quit = true;
+ }
+ else
+ g_quit = true;
+}
+
+static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
+ WPARAM wparam, LPARAM lparam)
+{
+ switch (message)
+ {
+ case WM_SYSCOMMAND:
+ // Prevent screensavers, etc, while running.
+ switch (wparam)
+ {
+ case SC_SCREENSAVE:
+ case SC_MONITORPOWER:
+ return 0;
+ }
+ break;
+
+ case WM_SYSKEYDOWN:
+ switch (wparam)
+ {
+ case VK_F10:
+ case VK_MENU:
+ case VK_RSHIFT:
+ return 0;
+ }
+ break;
+
+ case WM_CREATE:
+ create_gl_context(hwnd);
+ return 0;
+
+ case WM_CLOSE:
+ case WM_DESTROY:
+ case WM_QUIT:
+ g_quit = true;
+ return 0;
+
+ case WM_SIZE:
+ // Do not send resize message if we minimize.
+ if (wparam != SIZE_MAXHIDE && wparam != SIZE_MINIMIZED)
+ {
+ g_resize_width = LOWORD(lparam);
+ g_resize_height = HIWORD(lparam);
+ g_resized = true;
+ }
+ return 0;
+ }
+
+ return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+static void gfx_ctx_swap_interval(unsigned interval)
+{
+ g_interval = interval;
+
+ if (g_hrc && p_swap_interval)
+ {
+ RARCH_LOG("[WGL]: wglSwapInterval(%u)\n", g_interval);
+ if (!p_swap_interval(g_interval))
+ RARCH_WARN("[WGL]: wglSwapInterval() failed.\n");
+ }
+}
+
+static void gfx_ctx_check_window(bool *quit,
+ bool *resize, unsigned *width, unsigned *height, unsigned frame_count)
+{
+ (void)frame_count;
+
+ MSG msg;
+ while (PeekMessage(&msg, g_hwnd, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ *quit = g_quit;
+ if (g_resized)
+ {
+ *resize = true;
+ *width = g_resize_width;
+ *height = g_resize_height;
+ g_resized = false;
+ }
+}
+
+static void gfx_ctx_swap_buffers(void)
+{
+ SwapBuffers(g_hdc);
+}
+
+static void gfx_ctx_set_resize(unsigned width, unsigned height)
+{
+ (void)width;
+ (void)height;
+}
+
+static void gfx_ctx_update_window_title(bool reset)
+{
+ if (reset)
+ gfx_window_title_reset();
+
+ char buf[128];
+ if (gfx_window_title(buf, sizeof(buf)))
+ SetWindowText(g_hwnd, buf);
+}
+
+static void gfx_ctx_get_video_size(unsigned *width, unsigned *height)
+{
+ if (!g_hwnd)
+ {
+ RECT screen_rect;
+ GetClientRect(GetDesktopWindow(), &screen_rect);
+ *width = screen_rect.right - screen_rect.left;
+ *height = screen_rect.bottom - screen_rect.top;
+ }
+ else
+ {
+ *width = g_resize_width;
+ *height = g_resize_height;
+ }
+}
+
+BOOL CALLBACK monitor_enum_proc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
+{
+ g_all_hms[g_num_mons++] = hMonitor;
+ return TRUE;
+}
+
+static bool gfx_ctx_init(void)
+{
+ if (g_inited)
+ return false;
+
+ g_quit = false;
+ g_restore_desktop = false;
+
+ g_num_mons = 0;
+ EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, 0);
+
+ WNDCLASSEX wndclass = {0};
+ wndclass.cbSize = sizeof(wndclass);
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ wndclass.lpfnWndProc = WndProc;
+ wndclass.hInstance = GetModuleHandle(NULL);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.lpszClassName = "RetroArch";
+ wndclass.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON));
+ wndclass.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);
+
+ if (!RegisterClassEx(&wndclass))
+ return false;
+
+ return true;
+}
+
+static bool set_fullscreen(unsigned width, unsigned height, char *dev_name)
+{
+ DEVMODE devmode;
+ memset(&devmode, 0, sizeof(devmode));
+ devmode.dmSize = sizeof(DEVMODE);
+ devmode.dmPelsWidth = width;
+ devmode.dmPelsHeight = height;
+ devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
+
+ RARCH_LOG("[WGL]: Setting fullscreen to %ux%u on device %s.\n", width, height, dev_name);
+ return ChangeDisplaySettingsEx(dev_name, &devmode, NULL, CDS_FULLSCREEN, NULL) == DISP_CHANGE_SUCCESSFUL;
+}
+
+static void show_cursor(bool show)
+{
+ if (show)
+ while (ShowCursor(TRUE) < 0);
+ else
+ while (ShowCursor(FALSE) >= 0);
+}
+
+static bool gfx_ctx_set_video_mode(
+ unsigned width, unsigned height,
+ unsigned bits, bool fullscreen)
+{
+ (void)bits;
+
+ DWORD style;
+ MONITORINFOEX current_mon;
+ memset(¤t_mon, 0, sizeof(current_mon));
+ current_mon.cbSize = sizeof(MONITORINFOEX);
+ if (!g_last_hm)
+ g_last_hm = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST);
+ HMONITOR hm_to_use = g_last_hm;
+
+ unsigned fs_monitor = g_settings.video.monitor_index;
+ if (fs_monitor && fs_monitor <= g_num_mons && g_all_hms[fs_monitor - 1])
+ hm_to_use = g_all_hms[fs_monitor - 1];
+
+ GetMonitorInfo(hm_to_use, (MONITORINFO*)¤t_mon);
+
+ g_resize_width = width;
+ g_resize_height = height;
+
+ bool windowed_full = g_settings.video.windowed_fullscreen;
+ if (fullscreen)
+ {
+ if (windowed_full)
+ {
+ style = WS_EX_TOPMOST | WS_POPUP;
+ g_resize_width = width = current_mon.rcMonitor.right - current_mon.rcMonitor.left;
+ g_resize_height = height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top;
+ }
+ else
+ {
+ style = WS_POPUP | WS_VISIBLE;
+
+ if (!set_fullscreen(width, height, current_mon.szDevice))
+ goto error;
+
+ // display settings might have changed, get new coordinates
+ GetMonitorInfo(hm_to_use, (MONITORINFO*)¤t_mon);
+ g_restore_desktop = true;
+ }
+ }
+ else
+ {
+ style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+ RECT rect = {0};
+ rect.right = width;
+ rect.bottom = height;
+ AdjustWindowRect(&rect, style, FALSE);
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+ }
+
+ g_hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", style,
+ fullscreen ? current_mon.rcMonitor.left : CW_USEDEFAULT,
+ fullscreen ? current_mon.rcMonitor.top : CW_USEDEFAULT,
+ width, height,
+ NULL, NULL, NULL, NULL);
+
+ if (!g_hwnd)
+ goto error;
+
+ gfx_ctx_update_window_title(true);
+
+ if (!fullscreen || windowed_full)
+ {
+ ShowWindow(g_hwnd, SW_RESTORE);
+ UpdateWindow(g_hwnd);
+ SetForegroundWindow(g_hwnd);
+ SetFocus(g_hwnd);
+ }
+
+ show_cursor(!fullscreen);
+
+ // Wait until GL context is created (or failed to do so ...)
+ MSG msg;
+ while (!g_inited && !g_quit && GetMessage(&msg, g_hwnd, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ if (g_quit)
+ goto error;
+
+ p_swap_interval = (BOOL (APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT");
+
+ gfx_ctx_swap_interval(g_interval);
+
+ driver.display_type = RARCH_DISPLAY_WIN32;
+ driver.video_display = 0;
+ driver.video_window = (uintptr_t)g_hwnd;
+
+ return true;
+
+error:
+ gfx_ctx_destroy();
+ return false;
+}
+
+static void gfx_ctx_destroy(void)
+{
+ if (g_hrc)
+ {
+ wglMakeCurrent(NULL, NULL);
+ wglDeleteContext(g_hrc);
+ g_hrc = NULL;
+ }
+
+ if (g_hwnd && g_hdc)
+ {
+ ReleaseDC(g_hwnd, g_hdc);
+ g_hdc = NULL;
+ }
+
+ if (g_hwnd)
+ {
+ g_last_hm = MonitorFromWindow(g_hwnd, MONITOR_DEFAULTTONEAREST);
+ DestroyWindow(g_hwnd);
+ UnregisterClass("RetroArch", GetModuleHandle(NULL));
+ g_hwnd = NULL;
+ }
+
+ if (g_restore_desktop)
+ {
+ MONITORINFOEX current_mon;
+ memset(¤t_mon, 0, sizeof(current_mon));
+ current_mon.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(g_last_hm, (MONITORINFO*)¤t_mon);
+ ChangeDisplaySettingsEx(current_mon.szDevice, NULL, NULL, 0, NULL);
+ g_restore_desktop = false;
+ }
+
+ g_inited = false;
+}
+
+static void gfx_ctx_input_driver(const input_driver_t **input, void **input_data)
+{
+ void *dinput = input_dinput.init();
+ *input = dinput ? &input_dinput : NULL;
+ *input_data = dinput;
+}
+
+static bool gfx_ctx_has_focus(void)
+{
+ if (!g_inited)
+ return false;
+
+ return GetFocus() == g_hwnd;
+}
+
+static gfx_ctx_proc_t gfx_ctx_get_proc_address(const char *symbol)
+{
+ return (gfx_ctx_proc_t)wglGetProcAddress(symbol);
+}
+
+static bool gfx_ctx_bind_api(enum gfx_ctx_api api)
+{
+ return api == GFX_CTX_OPENGL_API;
+}
+
+static bool gfx_ctx_init_egl_image_buffer(const video_info_t *video)
+{
+ return false;
+}
+
+static bool gfx_ctx_write_egl_image(const void *frame, unsigned width, unsigned height, unsigned pitch, bool rgb32, unsigned index, void **image_handle)
+{
+ return false;
+}
+
+const gfx_ctx_driver_t gfx_ctx_wgl = {
+ gfx_ctx_init,
+ gfx_ctx_destroy,
+ gfx_ctx_bind_api,
+ gfx_ctx_swap_interval,
+ gfx_ctx_set_video_mode,
+ gfx_ctx_get_video_size,
+ NULL,
+ gfx_ctx_update_window_title,
+ gfx_ctx_check_window,
+ gfx_ctx_set_resize,
+ gfx_ctx_has_focus,
+ gfx_ctx_swap_buffers,
+ gfx_ctx_input_driver,
+ gfx_ctx_get_proc_address,
+ gfx_ctx_init_egl_image_buffer,
+ gfx_ctx_write_egl_image,
+ "wgl",
+};
+
diff --git a/gfx/scaler/scaler_int.c b/gfx/scaler/scaler_int.c
index 1faa0b8e17..4b3e6c7959 100644
--- a/gfx/scaler/scaler_int.c
+++ b/gfx/scaler/scaler_int.c
@@ -1,275 +1,275 @@
-/* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2012 - 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 .
- */
-
-#include "scaler_int.h"
-
-#ifdef SCALER_NO_SIMD
-#undef __SSE2__
-#endif
-
-#if defined(__SSE2__)
-#include
-#endif
-
-static inline uint64_t build_argb64(uint16_t a, uint16_t r, uint16_t g, uint16_t b)
-{
- return ((uint64_t)a << 48) | ((uint64_t)r << 32) | ((uint64_t)g << 16) | ((uint64_t)b << 0);
-}
-
-static inline uint8_t clamp_8bit(int16_t col)
-{
- if (col > 255)
- return 255;
- else if (col < 0)
- return 0;
- else
- return (uint8_t)col;
-}
-
-// ARGB8888 scaler is split in two:
-//
-// First, horizontal scaler is applied.
-// Here, all 8-bit channels are expanded to 16-bit. Values are then shifted 7 to left to occupy 15 bits.
-// The sign bit is kept empty as we have to do signed multiplication for the filter.
-// A mulhi [(a * b) >> 16] is applied which loses some precision, but is very efficient for SIMD.
-// It is accurate enough for 8-bit purposes.
-//
-// The fixed point 1.0 for filter is (1 << 14). After horizontal scale, the output is kept
-// with 16-bit channels, and will now have 13 bits of precision as [(a * (1 << 14)) >> 16] is effectively a right shift by 2.
-//
-// Vertical scaler takes the 13 bit channels, and performs the same mulhi steps.
-// Another 2 bits of precision is lost, which ends up as 11 bits.
-// Scaling is now complete. Channels are shifted right by 3, and saturated into 8-bit values.
-//
-// The C version of scalers perform the exact same operations as the SIMD code for testing purposes.
-
-#if defined(__SSE2__)
-void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
-{
- const uint64_t *input = ctx->scaled.frame;
- uint32_t *output = (uint32_t*)output_;
-
- const int16_t *filter_vert = ctx->vert.filter;
-
- for (int h = 0; h < ctx->out_height; h++, filter_vert += ctx->vert.filter_stride, output += stride >> 2)
- {
- const uint64_t *input_base = input + ctx->vert.filter_pos[h] * (ctx->scaled.stride >> 3);
-
- for (int w = 0; w < ctx->out_width; w++)
- {
- __m128i res = _mm_setzero_si128();
-
- const uint64_t *input_base_y = input_base + w;
-
- size_t y;
- for (y = 0; (y + 1) < ctx->vert.filter_len; y += 2, input_base_y += (ctx->scaled.stride >> 2))
- {
- __m128i coeff = _mm_set_epi64x(filter_vert[y + 1] * 0x0001000100010001ll, filter_vert[y + 0] * 0x0001000100010001ll);
- __m128i col = _mm_set_epi64x(input_base_y[ctx->scaled.stride >> 3], input_base_y[0]);
-
- res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
- }
-
- for (; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))
- {
- __m128i coeff = _mm_set_epi64x(0, filter_vert[y] * 0x0001000100010001ll);
- __m128i col = _mm_set_epi64x(0, input_base_y[0]);
-
- res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
- }
-
- res = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
- res = _mm_srai_epi16(res, (7 - 2 - 2));
-
- __m128i final = _mm_packus_epi16(res, res);
-
- output[w] = _mm_cvtsi128_si32(final);
- }
- }
-}
-#else
-void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
-{
- const uint64_t *input = ctx->scaled.frame;
- uint32_t *output = (uint32_t*)output_;
-
- const int16_t *filter_vert = ctx->vert.filter;
-
- for (int h = 0; h < ctx->out_height; h++, filter_vert += ctx->vert.filter_stride, output += stride >> 2)
- {
- const uint64_t *input_base = input + ctx->vert.filter_pos[h] * (ctx->scaled.stride >> 3);
-
- for (int w = 0; w < ctx->out_width; w++)
- {
- int16_t res_a = 0;
- int16_t res_r = 0;
- int16_t res_g = 0;
- int16_t res_b = 0;
-
- const uint64_t *input_base_y = input_base + w;
- for (size_t y = 0; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))
- {
- uint64_t col = *input_base_y;
-
- int16_t a = (col >> 48) & 0xffff;
- int16_t r = (col >> 32) & 0xffff;
- int16_t g = (col >> 16) & 0xffff;
- int16_t b = (col >> 0) & 0xffff;
-
- int16_t coeff = filter_vert[y];
-
- res_a += (a * coeff) >> 16;
- res_r += (r * coeff) >> 16;
- res_g += (g * coeff) >> 16;
- res_b += (b * coeff) >> 16;
- }
-
- res_a >>= (7 - 2 - 2);
- res_r >>= (7 - 2 - 2);
- res_g >>= (7 - 2 - 2);
- res_b >>= (7 - 2 - 2);
-
- output[w] = (clamp_8bit(res_a) << 24) | (clamp_8bit(res_r) << 16) | (clamp_8bit(res_g) << 8) | (clamp_8bit(res_b) << 0);
- }
- }
-}
-#endif
-
-#if defined(__SSE2__)
-void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
-{
- const uint32_t *input = (const uint32_t*)input_;
- uint64_t *output = ctx->scaled.frame;
-
- for (int h = 0; h < ctx->scaled.height; h++, input += stride >> 2, output += ctx->scaled.stride >> 3)
- {
- const int16_t *filter_horiz = ctx->horiz.filter;
-
- for (int w = 0; w < ctx->scaled.width; w++, filter_horiz += ctx->horiz.filter_stride)
- {
- __m128i res = _mm_setzero_si128();
-
- const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];
-
- size_t x;
- for (x = 0; (x + 1) < ctx->horiz.filter_len; x += 2)
- {
- __m128i coeff = _mm_set_epi64x(filter_horiz[x + 1] * 0x0001000100010001ll, filter_horiz[x + 0] * 0x0001000100010001ll);
-
- __m128i col = _mm_unpacklo_epi8(_mm_set_epi64x(0,
- ((uint64_t)input_base_x[x + 1] << 32) | input_base_x[x + 0]), _mm_setzero_si128());
-
- col = _mm_slli_epi16(col, 7);
- res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
- }
-
- for (; x < ctx->horiz.filter_len; x++)
- {
- __m128i coeff = _mm_set_epi64x(0, filter_horiz[x] * 0x0001000100010001ll);
- __m128i col = _mm_unpacklo_epi8(_mm_set_epi32(0, 0, 0, input_base_x[x]), _mm_setzero_si128());
-
- col = _mm_slli_epi16(col, 7);
- res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
- }
-
- res = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
-
-#ifdef __x86_64__
- output[w] = _mm_cvtsi128_si64(res);
-#else // 32-bit doesn't have si64. Do it in two steps.
- union
- {
- uint32_t *u32;
- uint64_t *u64;
- } u;
- u.u64 = output + w;
- u.u32[0] = _mm_cvtsi128_si32(res);
- u.u32[1] = _mm_cvtsi128_si32(_mm_srli_si128(res, 4));
-#endif
- }
- }
-}
-#else
-void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
-{
- const uint32_t *input = (uint32_t*)input_;
- uint64_t *output = ctx->scaled.frame;
-
- for (int h = 0; h < ctx->scaled.height; h++, input += stride >> 2, output += ctx->scaled.stride >> 3)
- {
- const int16_t *filter_horiz = ctx->horiz.filter;
-
- for (int w = 0; w < ctx->scaled.width; w++, filter_horiz += ctx->horiz.filter_stride)
- {
- const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];
-
- int16_t res_a = 0;
- int16_t res_r = 0;
- int16_t res_g = 0;
- int16_t res_b = 0;
-
- for (size_t x = 0; x < ctx->horiz.filter_len; x++)
- {
- uint32_t col = input_base_x[x];
-
- int16_t a = (col >> (24 - 7)) & (0xff << 7);
- int16_t r = (col >> (16 - 7)) & (0xff << 7);
- int16_t g = (col >> ( 8 - 7)) & (0xff << 7);
- int16_t b = (col << ( 0 + 7)) & (0xff << 7);
-
- int16_t coeff = filter_horiz[x];
-
- res_a += (a * coeff) >> 16;
- res_r += (r * coeff) >> 16;
- res_g += (g * coeff) >> 16;
- res_b += (b * coeff) >> 16;
- }
-
- output[w] = build_argb64(res_a, res_r, res_g, res_b);
- }
- }
-}
-#endif
-
-void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
- void *output_, const void *input_,
- int out_width, int out_height,
- int in_width, int in_height,
- int out_stride, int in_stride)
-{
- (void)ctx;
- int x_pos = (1 << 15) * in_width / out_width - (1 << 15);
- int x_step = (1 << 16) * in_width / out_width;
- int y_pos = (1 << 15) * in_height / out_height - (1 << 15);
- int y_step = (1 << 16) * in_height / out_height;
-
- if (x_pos < 0)
- x_pos = 0;
- if (y_pos < 0)
- y_pos = 0;
-
- const uint32_t *input = (const uint32_t*)input_;
- uint32_t *output = (uint32_t*)output_;
-
- for (int h = 0; h < out_height; h++, y_pos += y_step, output += out_stride >> 2)
- {
- int x = x_pos;
- const uint32_t *inp = input + (y_pos >> 16) * (in_stride >> 2);
-
- for (int w = 0; w < out_width; w++, x += x_step)
- output[w] = inp[x >> 16];
- }
-}
-
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2012 - 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 .
+ */
+
+#include "scaler_int.h"
+
+#ifdef SCALER_NO_SIMD
+#undef __SSE2__
+#endif
+
+#if defined(__SSE2__)
+#include
+#endif
+
+static inline uint64_t build_argb64(uint16_t a, uint16_t r, uint16_t g, uint16_t b)
+{
+ return ((uint64_t)a << 48) | ((uint64_t)r << 32) | ((uint64_t)g << 16) | ((uint64_t)b << 0);
+}
+
+static inline uint8_t clamp_8bit(int16_t col)
+{
+ if (col > 255)
+ return 255;
+ else if (col < 0)
+ return 0;
+ else
+ return (uint8_t)col;
+}
+
+// ARGB8888 scaler is split in two:
+//
+// First, horizontal scaler is applied.
+// Here, all 8-bit channels are expanded to 16-bit. Values are then shifted 7 to left to occupy 15 bits.
+// The sign bit is kept empty as we have to do signed multiplication for the filter.
+// A mulhi [(a * b) >> 16] is applied which loses some precision, but is very efficient for SIMD.
+// It is accurate enough for 8-bit purposes.
+//
+// The fixed point 1.0 for filter is (1 << 14). After horizontal scale, the output is kept
+// with 16-bit channels, and will now have 13 bits of precision as [(a * (1 << 14)) >> 16] is effectively a right shift by 2.
+//
+// Vertical scaler takes the 13 bit channels, and performs the same mulhi steps.
+// Another 2 bits of precision is lost, which ends up as 11 bits.
+// Scaling is now complete. Channels are shifted right by 3, and saturated into 8-bit values.
+//
+// The C version of scalers perform the exact same operations as the SIMD code for testing purposes.
+
+#if defined(__SSE2__)
+void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
+{
+ const uint64_t *input = ctx->scaled.frame;
+ uint32_t *output = (uint32_t*)output_;
+
+ const int16_t *filter_vert = ctx->vert.filter;
+
+ for (int h = 0; h < ctx->out_height; h++, filter_vert += ctx->vert.filter_stride, output += stride >> 2)
+ {
+ const uint64_t *input_base = input + ctx->vert.filter_pos[h] * (ctx->scaled.stride >> 3);
+
+ for (int w = 0; w < ctx->out_width; w++)
+ {
+ __m128i res = _mm_setzero_si128();
+
+ const uint64_t *input_base_y = input_base + w;
+
+ size_t y;
+ for (y = 0; (y + 1) < ctx->vert.filter_len; y += 2, input_base_y += (ctx->scaled.stride >> 2))
+ {
+ __m128i coeff = _mm_set_epi64x(filter_vert[y + 1] * 0x0001000100010001ll, filter_vert[y + 0] * 0x0001000100010001ll);
+ __m128i col = _mm_set_epi64x(input_base_y[ctx->scaled.stride >> 3], input_base_y[0]);
+
+ res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+ }
+
+ for (; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))
+ {
+ __m128i coeff = _mm_set_epi64x(0, filter_vert[y] * 0x0001000100010001ll);
+ __m128i col = _mm_set_epi64x(0, input_base_y[0]);
+
+ res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+ }
+
+ res = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
+ res = _mm_srai_epi16(res, (7 - 2 - 2));
+
+ __m128i final = _mm_packus_epi16(res, res);
+
+ output[w] = _mm_cvtsi128_si32(final);
+ }
+ }
+}
+#else
+void scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)
+{
+ const uint64_t *input = ctx->scaled.frame;
+ uint32_t *output = (uint32_t*)output_;
+
+ const int16_t *filter_vert = ctx->vert.filter;
+
+ for (int h = 0; h < ctx->out_height; h++, filter_vert += ctx->vert.filter_stride, output += stride >> 2)
+ {
+ const uint64_t *input_base = input + ctx->vert.filter_pos[h] * (ctx->scaled.stride >> 3);
+
+ for (int w = 0; w < ctx->out_width; w++)
+ {
+ int16_t res_a = 0;
+ int16_t res_r = 0;
+ int16_t res_g = 0;
+ int16_t res_b = 0;
+
+ const uint64_t *input_base_y = input_base + w;
+ for (size_t y = 0; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))
+ {
+ uint64_t col = *input_base_y;
+
+ int16_t a = (col >> 48) & 0xffff;
+ int16_t r = (col >> 32) & 0xffff;
+ int16_t g = (col >> 16) & 0xffff;
+ int16_t b = (col >> 0) & 0xffff;
+
+ int16_t coeff = filter_vert[y];
+
+ res_a += (a * coeff) >> 16;
+ res_r += (r * coeff) >> 16;
+ res_g += (g * coeff) >> 16;
+ res_b += (b * coeff) >> 16;
+ }
+
+ res_a >>= (7 - 2 - 2);
+ res_r >>= (7 - 2 - 2);
+ res_g >>= (7 - 2 - 2);
+ res_b >>= (7 - 2 - 2);
+
+ output[w] = (clamp_8bit(res_a) << 24) | (clamp_8bit(res_r) << 16) | (clamp_8bit(res_g) << 8) | (clamp_8bit(res_b) << 0);
+ }
+ }
+}
+#endif
+
+#if defined(__SSE2__)
+void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
+{
+ const uint32_t *input = (const uint32_t*)input_;
+ uint64_t *output = ctx->scaled.frame;
+
+ for (int h = 0; h < ctx->scaled.height; h++, input += stride >> 2, output += ctx->scaled.stride >> 3)
+ {
+ const int16_t *filter_horiz = ctx->horiz.filter;
+
+ for (int w = 0; w < ctx->scaled.width; w++, filter_horiz += ctx->horiz.filter_stride)
+ {
+ __m128i res = _mm_setzero_si128();
+
+ const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];
+
+ size_t x;
+ for (x = 0; (x + 1) < ctx->horiz.filter_len; x += 2)
+ {
+ __m128i coeff = _mm_set_epi64x(filter_horiz[x + 1] * 0x0001000100010001ll, filter_horiz[x + 0] * 0x0001000100010001ll);
+
+ __m128i col = _mm_unpacklo_epi8(_mm_set_epi64x(0,
+ ((uint64_t)input_base_x[x + 1] << 32) | input_base_x[x + 0]), _mm_setzero_si128());
+
+ col = _mm_slli_epi16(col, 7);
+ res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+ }
+
+ for (; x < ctx->horiz.filter_len; x++)
+ {
+ __m128i coeff = _mm_set_epi64x(0, filter_horiz[x] * 0x0001000100010001ll);
+ __m128i col = _mm_unpacklo_epi8(_mm_set_epi32(0, 0, 0, input_base_x[x]), _mm_setzero_si128());
+
+ col = _mm_slli_epi16(col, 7);
+ res = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);
+ }
+
+ res = _mm_adds_epi16(_mm_srli_si128(res, 8), res);
+
+#ifdef __x86_64__
+ output[w] = _mm_cvtsi128_si64(res);
+#else // 32-bit doesn't have si64. Do it in two steps.
+ union
+ {
+ uint32_t *u32;
+ uint64_t *u64;
+ } u;
+ u.u64 = output + w;
+ u.u32[0] = _mm_cvtsi128_si32(res);
+ u.u32[1] = _mm_cvtsi128_si32(_mm_srli_si128(res, 4));
+#endif
+ }
+ }
+}
+#else
+void scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)
+{
+ const uint32_t *input = (uint32_t*)input_;
+ uint64_t *output = ctx->scaled.frame;
+
+ for (int h = 0; h < ctx->scaled.height; h++, input += stride >> 2, output += ctx->scaled.stride >> 3)
+ {
+ const int16_t *filter_horiz = ctx->horiz.filter;
+
+ for (int w = 0; w < ctx->scaled.width; w++, filter_horiz += ctx->horiz.filter_stride)
+ {
+ const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];
+
+ int16_t res_a = 0;
+ int16_t res_r = 0;
+ int16_t res_g = 0;
+ int16_t res_b = 0;
+
+ for (size_t x = 0; x < ctx->horiz.filter_len; x++)
+ {
+ uint32_t col = input_base_x[x];
+
+ int16_t a = (col >> (24 - 7)) & (0xff << 7);
+ int16_t r = (col >> (16 - 7)) & (0xff << 7);
+ int16_t g = (col >> ( 8 - 7)) & (0xff << 7);
+ int16_t b = (col << ( 0 + 7)) & (0xff << 7);
+
+ int16_t coeff = filter_horiz[x];
+
+ res_a += (a * coeff) >> 16;
+ res_r += (r * coeff) >> 16;
+ res_g += (g * coeff) >> 16;
+ res_b += (b * coeff) >> 16;
+ }
+
+ output[w] = build_argb64(res_a, res_r, res_g, res_b);
+ }
+ }
+}
+#endif
+
+void scaler_argb8888_point_special(const struct scaler_ctx *ctx,
+ void *output_, const void *input_,
+ int out_width, int out_height,
+ int in_width, int in_height,
+ int out_stride, int in_stride)
+{
+ (void)ctx;
+ int x_pos = (1 << 15) * in_width / out_width - (1 << 15);
+ int x_step = (1 << 16) * in_width / out_width;
+ int y_pos = (1 << 15) * in_height / out_height - (1 << 15);
+ int y_step = (1 << 16) * in_height / out_height;
+
+ if (x_pos < 0)
+ x_pos = 0;
+ if (y_pos < 0)
+ y_pos = 0;
+
+ const uint32_t *input = (const uint32_t*)input_;
+ uint32_t *output = (uint32_t*)output_;
+
+ for (int h = 0; h < out_height; h++, y_pos += y_step, output += out_stride >> 2)
+ {
+ int x = x_pos;
+ const uint32_t *inp = input + (y_pos >> 16) * (in_stride >> 2);
+
+ for (int w = 0; w < out_width; w++, x += x_step)
+ output[w] = inp[x >> 16];
+ }
+}
+