diff --git a/Makefile b/Makefile index 133228de2a..81240ccc0b 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,10 @@ ifneq ($(findstring DOS,$(OS)),) LDFLAGS += -lemu endif +ifneq ($(findstring FPGA,$(OS)),) + DEFINES += -DHAVE_FPGA +endif + ifneq ($(findstring Win32,$(OS)),) LDFLAGS += -static-libgcc -lwinmm endif diff --git a/Makefile.common b/Makefile.common index c935d711e9..a4a967f2ec 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1912,6 +1912,13 @@ ifeq ($(HAVE_NETWORKING), 1) endif endif +ifneq ($(findstring FPGA,$(OS)),) + OBJ += gfx/drivers/fpga_gfx.o \ + gfx/drivers_context/fpga_ctx.o \ + gfx/drivers_font/fpga_font.o \ + menu/drivers_display/menu_display_fpga.o +endif + ifneq ($(findstring Win32,$(OS)),) OBJ += media/rarch.o \ gfx/common/win32_common.o \ diff --git a/configuration.c b/configuration.c index 910112c8ac..ecc6835869 100644 --- a/configuration.c +++ b/configuration.c @@ -166,6 +166,7 @@ enum video_driver_enum VIDEO_CACA, VIDEO_GDI, VIDEO_VGA, + VIDEO_FPGA, VIDEO_NULL }; @@ -364,6 +365,8 @@ static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL2; static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GDI; #elif defined(DJGPP) static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_VGA; +#elif defined(HAVE_FPGA) +static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_FPGA; #elif defined(HAVE_DYLIB) && !defined(ANDROID) static enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_EXT; #else @@ -827,6 +830,8 @@ const char *config_get_default_video(void) return "gdi"; case VIDEO_VGA: return "vga"; + case VIDEO_FPGA: + return "fpga"; case VIDEO_NULL: break; } diff --git a/gfx/drivers/fpga_gfx.c b/gfx/drivers/fpga_gfx.c new file mode 100644 index 0000000000..0f7c82ae6d --- /dev/null +++ b/gfx/drivers/fpga_gfx.c @@ -0,0 +1,584 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <retro_miscellaneous.h> + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#include "../font_driver.h" + +#include "../../driver.h" +#include "../../configuration.h" +#include "../../verbosity.h" +#include "../common/fpga_common.h" + +typedef struct RegOp +{ + int fd; + void *ptr; + int only_mmap; + int only_munmap; +} RegOp; + +static unsigned char *fpga_menu_frame = NULL; +static unsigned fpga_menu_width = 0; +static unsigned fpga_menu_height = 0; +static unsigned fpga_menu_pitch = 0; +static unsigned fpga_video_width = 0; +static unsigned fpga_video_height = 0; +static unsigned fpga_video_pitch = 0; +static unsigned fpga_video_bits = 0; +static unsigned fpga_menu_bits = 0; +static bool fpga_rgb32 = false; +static bool fpga_menu_rgb32 = false; +static RegOp regOp; + +static unsigned int get_memory_size(void) +{ + FILE *size_fp; + unsigned int size; + + /* this file holds the memory range needed to map the framebuffer into + * kernel address space, it is specified in the device tree + */ + size_fp = fopen("/sys/class/uio/uio0/maps/map0/size", "r"); + + if (!size_fp) + { + RARCH_ERR("unable to open the uio size file\n"); + exit(1); + } + + fscanf(size_fp, "0x%08X", &size); + fclose(size_fp); + + return size; +} + +static void do_mmap_op(RegOp *regOp) +{ + if (regOp->only_munmap == 0) + { + regOp->fd = open("/dev/uio0", O_RDWR); + + if (regOp->fd < 1) + return; + + regOp->ptr = mmap(NULL, get_memory_size(), PROT_READ|PROT_WRITE, MAP_SHARED, regOp->fd, 0); + + if (regOp->ptr == MAP_FAILED) + { + RARCH_ERR("could not mmap() memory\n"); + exit(1); + } + } + + if (regOp->only_mmap == 0) + { + if (munmap(regOp->ptr, get_memory_size()) == -1) + { + RARCH_ERR("could not munmap() memory\n"); + exit(1); + } + + close(regOp->fd); + } + + return; +} + +static void fpga_gfx_create(fpga_t *fpga) +{ + memset(®Op, 0, sizeof(regOp)); + + regOp.only_mmap = 1; + + do_mmap_op(®Op); + + fpga->framebuffer = ((volatile unsigned*)regOp.ptr); +} + +static void *fpga_gfx_init(const video_info_t *video, + const input_driver_t **input, void **input_data) +{ + unsigned full_x, full_y; + gfx_ctx_input_t inp; + gfx_ctx_mode_t mode; + const gfx_ctx_driver_t *ctx_driver = NULL; + unsigned win_width = 0, win_height = 0; + unsigned temp_width = 0, temp_height = 0; + settings_t *settings = config_get_ptr(); + fpga_t *fpga = (fpga_t*)calloc(1, sizeof(*fpga)); + + *input = NULL; + *input_data = NULL; + + fpga_video_width = video->width; + fpga_video_height = video->height; + fpga_rgb32 = video->rgb32; + + fpga_video_bits = video->rgb32 ? 32 : 16; + + if (video->rgb32) + fpga_video_pitch = video->width * 4; + else + fpga_video_pitch = video->width * 2; + + fpga_gfx_create(fpga); + + ctx_driver = video_context_driver_init_first(fpga, + settings->arrays.video_context_driver, + GFX_CTX_FPGA_API, 1, 0, false); + if (!ctx_driver) + goto error; + + video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver); + + RARCH_LOG("[FPGA]: Found FPGA context: %s\n", ctx_driver->ident); + + video_context_driver_get_video_size(&mode); + + full_x = mode.width; + full_y = mode.height; + mode.width = 0; + mode.height = 0; + + RARCH_LOG("[FPGA]: Detecting screen resolution %ux%u.\n", full_x, full_y); + + win_width = video->width; + win_height = video->height; + + if (video->fullscreen && (win_width == 0) && (win_height == 0)) + { + win_width = full_x; + win_height = full_y; + } + + mode.width = win_width; + mode.height = win_height; + mode.fullscreen = video->fullscreen; + + if (!video_context_driver_set_video_mode(&mode)) + goto error; + + mode.width = 0; + mode.height = 0; + + video_context_driver_get_video_size(&mode); + + temp_width = mode.width; + temp_height = mode.height; + mode.width = 0; + mode.height = 0; + + /* Get real known video size, which might have been altered by context. */ + + if (temp_width != 0 && temp_height != 0) + video_driver_set_size(&temp_width, &temp_height); + + video_driver_get_size(&temp_width, &temp_height); + + RARCH_LOG("[FPGA]: Using resolution %ux%u\n", temp_width, temp_height); + + inp.input = input; + inp.input_data = input_data; + + video_context_driver_input_driver(&inp); + + if (settings->bools.video_font_enable) + font_driver_init_osd(NULL, false, + video->is_threaded, + FONT_DRIVER_RENDER_FPGA); + + RARCH_LOG("[FPGA]: Init complete.\n"); + + return fpga; + +error: + video_context_driver_destroy(); + if (fpga) + free(fpga); + return NULL; +} + +static bool fpga_gfx_frame(void *data, const void *frame, + unsigned frame_width, unsigned frame_height, uint64_t frame_count, + unsigned pitch, const char *msg, video_frame_info_t *video_info) +{ + gfx_ctx_mode_t mode; + const void *frame_to_copy = frame; + unsigned width = 0; + unsigned height = 0; + unsigned bits = fpga_video_bits; + bool draw = true; + fpga_t *fpga = (fpga_t*)data; + + if (!frame || !frame_width || !frame_height) + return true; + +#ifdef HAVE_MENU + menu_driver_frame(video_info); +#endif + + if (fpga_video_width != frame_width || fpga_video_height != frame_height || fpga_video_pitch != pitch) + { + if (frame_width > 4 && frame_height > 4) + { + fpga_video_width = frame_width; + fpga_video_height = frame_height; + fpga_video_pitch = pitch; + } + } + + if (fpga_menu_frame && video_info->menu_is_alive) + { + frame_to_copy = fpga_menu_frame; + width = fpga_menu_width; + height = fpga_menu_height; + pitch = fpga_menu_pitch; + bits = fpga_menu_bits; + } + else + { + width = fpga_video_width; + height = fpga_video_height; + pitch = fpga_video_pitch; + + if (frame_width == 4 && frame_height == 4 && (frame_width < width && frame_height < height)) + draw = false; + + if (video_info->menu_is_alive) + draw = false; + } + + video_context_driver_get_video_size(&mode); + + if (draw) + { + if (bits == 16) + { + if (frame_to_copy == fpga_menu_frame) + { + /* RGBX4444 color bits for RGUI */ + unsigned x, y; + + for (y = 0; y < FB_HEIGHT; y++) + { + for (x = 0; x < FB_WIDTH; x++) + { + /* scale incoming frame to fit the screen */ + unsigned scaled_x = (width * x) / FB_WIDTH; + unsigned scaled_y = (height * y) / FB_HEIGHT; + unsigned short pixel = ((unsigned short*)frame_to_copy)[width * scaled_y + scaled_x]; + + /* convert RGBX444 to XRGB8888 */ + unsigned r = ((pixel & 0xF000) >> 12); + unsigned g = ((pixel & 0x0F00) >> 8); + unsigned b = ((pixel & 0x00F0) >> 4); + + fpga->framebuffer[FB_WIDTH * y + x] = (r << 20) | (b << 12) | (g << 4); + } + } + } + else + { + /* RGB565 color bits for core */ + unsigned x, y; + + for (y = 0; y < FB_HEIGHT; y++) + { + for (x = 0; x < FB_WIDTH; x++) + { + /* scale incoming frame to fit the screen */ + unsigned scaled_x = (width * x) / FB_WIDTH; + unsigned scaled_y = (height * y) / FB_HEIGHT; + unsigned short pixel = ((unsigned short*)frame_to_copy)[width * scaled_y + scaled_x]; + + /* convert RGB565 to XRBG8888 */ + unsigned r = ((pixel & 0xF800) >> 11); + unsigned g = ((pixel & 0x07E0) >> 5); + unsigned b = ((pixel & 0x001F) >> 0); + + fpga->framebuffer[FB_WIDTH * y + x] = (r << 19) | (b << 11) | (g << 2); + } + } + } + } + else + { + /* TODO/FIXME: handle 32-bit core output */ + } + } + + if (msg) + font_driver_render_msg(video_info, NULL, msg, NULL); + + return true; +} + +static void fpga_gfx_set_nonblock_state(void *data, bool toggle) +{ + (void)data; + (void)toggle; +} + +static bool fpga_gfx_alive(void *data) +{ + gfx_ctx_size_t size_data; + unsigned temp_width = 0; + unsigned temp_height = 0; + bool quit = false; + bool resize = false; + + /* Needed because some context drivers don't track their sizes */ + video_driver_get_size(&temp_width, &temp_height); + + size_data.quit = &quit; + size_data.resize = &resize; + size_data.width = &temp_width; + size_data.height = &temp_height; + + video_context_driver_check_window(&size_data); + + if (temp_width != 0 && temp_height != 0) + video_driver_set_size(&temp_width, &temp_height); + + return true; +} + +static bool fpga_gfx_focus(void *data) +{ + (void)data; + return true; +} + +static bool fpga_gfx_suppress_screensaver(void *data, bool enable) +{ + (void)data; + (void)enable; + return false; +} + +static bool fpga_gfx_has_windowed(void *data) +{ + (void)data; + return true; +} + +static void fpga_gfx_free(void *data) +{ + fpga_t *fpga = (fpga_t*)data; + + if (fpga_menu_frame) + { + free(fpga_menu_frame); + fpga_menu_frame = NULL; + } + + if (!fpga) + return; + + font_driver_free_osd(); + video_context_driver_free(); + + free(fpga); + + regOp.only_mmap = 0; + regOp.only_munmap = 1; + + do_mmap_op(®Op); +} + +static bool fpga_gfx_set_shader(void *data, + enum rarch_shader_type type, const char *path) +{ + (void)data; + (void)type; + (void)path; + + return false; +} + +static void fpga_gfx_set_rotation(void *data, + unsigned rotation) +{ + (void)data; + (void)rotation; +} + +static void fpga_gfx_viewport_info(void *data, + struct video_viewport *vp) +{ + (void)data; + (void)vp; +} + +static bool fpga_gfx_read_viewport(void *data, uint8_t *buffer, bool is_idle) +{ + (void)data; + (void)buffer; + + return true; +} + +static void fpga_set_texture_frame(void *data, + const void *frame, bool rgb32, unsigned width, unsigned height, + float alpha) +{ + unsigned pitch = width * 2; + + if (rgb32) + pitch = width * 4; + + if (fpga_menu_frame) + { + free(fpga_menu_frame); + fpga_menu_frame = NULL; + } + + if (!fpga_menu_frame || fpga_menu_width != width || fpga_menu_height != height || fpga_menu_pitch != pitch) + if (pitch && height) + fpga_menu_frame = (unsigned char*)malloc(pitch * height); + + if (fpga_menu_frame && frame && pitch && height) + { + memcpy(fpga_menu_frame, frame, pitch * height); + fpga_menu_width = width; + fpga_menu_height = height; + fpga_menu_pitch = pitch; + fpga_menu_bits = rgb32 ? 32 : 16; + } +} + +static void fpga_set_osd_msg(void *data, + video_frame_info_t *video_info, + const char *msg, + const void *params, void *font) +{ + font_driver_render_msg(video_info, font, msg, params); +} + +static void fpga_get_video_output_size(void *data, + unsigned *width, unsigned *height) +{ + gfx_ctx_size_t size_data; + size_data.width = width; + size_data.height = height; + video_context_driver_get_video_output_size(&size_data); +} + +static void fpga_get_video_output_prev(void *data) +{ + video_context_driver_get_video_output_prev(); +} + +static void fpga_get_video_output_next(void *data) +{ + video_context_driver_get_video_output_next(); +} + +static void fpga_set_video_mode(void *data, unsigned width, unsigned height, + bool fullscreen) +{ + gfx_ctx_mode_t mode; + + mode.width = width; + mode.height = height; + mode.fullscreen = fullscreen; + + video_context_driver_set_video_mode(&mode); +} + +static const video_poke_interface_t fpga_poke_interface = { + NULL, + NULL, + fpga_set_video_mode, + NULL, + fpga_get_video_output_size, + fpga_get_video_output_prev, + fpga_get_video_output_next, + NULL, + NULL, + NULL, + NULL, +#if defined(HAVE_MENU) + fpga_set_texture_frame, + NULL, + fpga_set_osd_msg, + NULL, +#else + NULL, + NULL, + NULL, + NULL, +#endif + + NULL, +#ifdef HAVE_MENU + NULL, +#endif +}; + +static void fpga_gfx_get_poke_interface(void *data, + const video_poke_interface_t **iface) +{ + (void)data; + *iface = &fpga_poke_interface; +} + +static void fpga_gfx_set_viewport(void *data, unsigned viewport_width, + unsigned viewport_height, bool force_full, bool allow_rotate) +{ +} + +bool fpga_has_menu_frame(void) +{ + return (fpga_menu_frame != NULL); +} + +video_driver_t video_fpga = { + fpga_gfx_init, + fpga_gfx_frame, + fpga_gfx_set_nonblock_state, + fpga_gfx_alive, + fpga_gfx_focus, + fpga_gfx_suppress_screensaver, + fpga_gfx_has_windowed, + fpga_gfx_set_shader, + fpga_gfx_free, + "fpga", + fpga_gfx_set_viewport, + fpga_gfx_set_rotation, + fpga_gfx_viewport_info, + fpga_gfx_read_viewport, + NULL, /* read_frame_raw */ + +#ifdef HAVE_OVERLAY + NULL, /* overlay_interface */ +#endif + fpga_gfx_get_poke_interface, +}; diff --git a/gfx/drivers_context/fpga_ctx.c b/gfx/drivers_context/fpga_ctx.c new file mode 100644 index 0000000000..d83417a356 --- /dev/null +++ b/gfx/drivers_context/fpga_ctx.c @@ -0,0 +1,198 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/* FPGA context. */ + +#include <string.h> +#include <math.h> + +#include <string/stdstring.h> + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#include "../../configuration.h" +#include "../../dynamic.h" +#include "../../verbosity.h" +#include "../video_driver.h" +#include "../common/fpga_common.h" + +static unsigned g_resize_width = FB_WIDTH; +static unsigned g_resize_height = FB_HEIGHT; + +static void gfx_ctx_fpga_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height, bool is_shutdown) +{ +} + +static bool gfx_ctx_fpga_set_resize(void *data, + unsigned width, unsigned height) +{ + (void)data; + (void)width; + (void)height; + + return false; +} + +static void gfx_ctx_fpga_update_window_title(void *data, void *data2) +{ + char title[128]; + + title[0] = '\0'; + + video_driver_get_window_title(title, sizeof(title)); +} + +static void gfx_ctx_fpga_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + (void)data; + + *width = g_resize_width; + *height = g_resize_height; +} + +static void *gfx_ctx_fpga_init(video_frame_info_t *video_info, void *video_driver) +{ + (void)video_driver; + + return (void*)"fpga"; +} + +static void gfx_ctx_fpga_destroy(void *data) +{ + (void)data; +} + +static bool gfx_ctx_fpga_set_video_mode(void *data, + video_frame_info_t *video_info, + unsigned width, unsigned height, + bool fullscreen) +{ + if (false) + goto error; + + return true; + +error: + gfx_ctx_fpga_destroy(data); + return false; +} + + +static void gfx_ctx_fpga_input_driver(void *data, + const char *joypad_name, + const input_driver_t **input, void **input_data) +{ + (void)data; + settings_t *settings = config_get_ptr(); +} + +static bool gfx_ctx_fpga_has_focus(void *data) +{ + return true; +} + +static bool gfx_ctx_fpga_suppress_screensaver(void *data, bool enable) +{ + return true; +} + +static bool gfx_ctx_fpga_has_windowed(void *data) +{ + (void)data; + + return true; +} + +static bool gfx_ctx_fpga_get_metrics(void *data, + enum display_metric_types type, float *value) +{ + return true; +} + +static bool gfx_ctx_fpga_bind_api(void *data, + enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + (void)data; + + return true; +} + +static void gfx_ctx_fpga_show_mouse(void *data, bool state) +{ + (void)data; +} + +static void gfx_ctx_fpga_swap_interval(void *data, unsigned interval) +{ + (void)data; + (void)interval; +} + +static void gfx_ctx_fpga_set_flags(void *data, uint32_t flags) +{ + (void)data; + (void)flags; +} + +static uint32_t gfx_ctx_fpga_get_flags(void *data) +{ + uint32_t flags = 0; + BIT32_SET(flags, GFX_CTX_FLAGS_NONE); + return flags; +} + +static void gfx_ctx_fpga_swap_buffers(void *data, void *data2) +{ + (void)data; +} + +const gfx_ctx_driver_t gfx_ctx_fpga = { + gfx_ctx_fpga_init, + gfx_ctx_fpga_destroy, + gfx_ctx_fpga_bind_api, + gfx_ctx_fpga_swap_interval, + gfx_ctx_fpga_set_video_mode, + gfx_ctx_fpga_get_video_size, + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + gfx_ctx_fpga_get_metrics, + NULL, + gfx_ctx_fpga_update_window_title, + gfx_ctx_fpga_check_window, + gfx_ctx_fpga_set_resize, + gfx_ctx_fpga_has_focus, + gfx_ctx_fpga_suppress_screensaver, + gfx_ctx_fpga_has_windowed, + gfx_ctx_fpga_swap_buffers, + gfx_ctx_fpga_input_driver, + NULL, + NULL, + NULL, + gfx_ctx_fpga_show_mouse, + "fpga", + gfx_ctx_fpga_get_flags, + gfx_ctx_fpga_set_flags, + NULL, + NULL, + NULL +}; + diff --git a/gfx/drivers_font/fpga_font.c b/gfx/drivers_font/fpga_font.c new file mode 100644 index 0000000000..33e7caffeb --- /dev/null +++ b/gfx/drivers_font/fpga_font.c @@ -0,0 +1,153 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <string/stdstring.h> +#include <encodings/utf.h> + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#include "../font_driver.h" +#include "../video_driver.h" +#include "../../configuration.h" +#include "../../verbosity.h" +#include "../common/fpga_common.h" + +typedef struct +{ + const font_renderer_driver_t *fpga_font_driver; + void *fpga_font_data; + fpga_t *fpga; +} fpga_raster_t; + +static void *fpga_init_font(void *data, + const char *font_path, float font_size, + bool is_threaded) +{ + fpga_raster_t *font = (fpga_raster_t*)calloc(1, sizeof(*font)); + + if (!font) + return NULL; + + font->fpga = (fpga_t*)data; + + font_size = 1; + + if (!font_renderer_create_default((const void**)&font->fpga_font_driver, + &font->fpga_font_data, font_path, font_size)) + { + RARCH_WARN("Couldn't initialize font renderer.\n"); + return NULL; + } + + return font; +} + +static void fpga_render_free_font(void *data, bool is_threaded) +{ + (void)data; + (void)is_threaded; +} + +static int fpga_get_message_width(void *data, const char *msg, + unsigned msg_len, float scale) +{ + return 0; +} + +static const struct font_glyph *fpga_font_get_glyph( + void *data, uint32_t code) +{ + return NULL; +} + +static void fpga_render_msg( + video_frame_info_t *video_info, + void *data, const char *msg, + const void *userdata) +{ + float x, y, scale; + fpga_raster_t *font = (fpga_raster_t*)data; + unsigned newX, newY, len; + unsigned align; + const struct font_params *params = (const struct font_params*)userdata; + unsigned width = video_info->width; + unsigned height = video_info->height; + + if (!font || string_is_empty(msg)) + return; + + if (params) + { + x = params->x; + y = params->y; + scale = params->scale; + align = params->text_align; + } + else + { + x = video_info->font_msg_pos_x; + y = video_info->font_msg_pos_y; + scale = 1.0f; + align = TEXT_ALIGN_LEFT; + } + + if (!font->fpga) + return; + + len = utf8len(msg); + + switch (align) + { + case TEXT_ALIGN_LEFT: + newX = x * width * scale; + break; + case TEXT_ALIGN_RIGHT: + newX = (x * width * scale) - len; + break; + case TEXT_ALIGN_CENTER: + newX = (x * width * scale) - (len / 2); + break; + default: + break; + } + + /* TODO: draw osd msg */ +} + +static void fpga_font_flush_block(unsigned width, unsigned height, void* data) +{ + (void)data; +} + +static void fpga_font_bind_block(void* data, void* userdata) +{ + (void)data; +} + +font_renderer_t fpga_font = { + fpga_init_font, + fpga_render_free_font, + fpga_render_msg, + "fpga font", + fpga_font_get_glyph, /* get_glyph */ + fpga_font_bind_block, /* bind_block */ + fpga_font_flush_block, /* flush */ + fpga_get_message_width /* get_message_width */ +}; diff --git a/gfx/font_driver.h b/gfx/font_driver.h index bea9809a15..780905ac5d 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -177,6 +177,7 @@ extern font_renderer_t d3d12_font; extern font_renderer_t caca_font; extern font_renderer_t gdi_font; extern font_renderer_t vga_font; +extern font_renderer_t fpga_font; extern font_renderer_t sixel_font; extern font_renderer_t switch_font; diff --git a/gfx/video_defines.h b/gfx/video_defines.h index edecf11233..a460c17556 100644 --- a/gfx/video_defines.h +++ b/gfx/video_defines.h @@ -101,6 +101,7 @@ enum font_driver_render_api FONT_DRIVER_RENDER_NETWORK_VIDEO, FONT_DRIVER_RENDER_GDI, FONT_DRIVER_RENDER_VGA, + FONT_DRIVER_RENDER_FPGA, FONT_DRIVER_RENDER_SWITCH }; diff --git a/menu/drivers_display/menu_display_fpga.c b/menu/drivers_display/menu_display_fpga.c new file mode 100644 index 0000000000..2249e4c9f3 --- /dev/null +++ b/menu/drivers_display/menu_display_fpga.c @@ -0,0 +1,106 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <time.h> + +#include <queues/message_queue.h> +#include <retro_miscellaneous.h> + +#include "../../config.def.h" +#include "../../gfx/font_driver.h" +#include "../../gfx/video_driver.h" + +#include "../menu_driver.h" + +static void *menu_display_fpga_get_default_mvp(void) +{ + return NULL; +} + +static void menu_display_fpga_blend_begin(void) +{ +} + +static void menu_display_fpga_blend_end(void) +{ +} + +static void menu_display_fpga_draw(void *data) +{ + (void)data; +} + +static void menu_display_fpga_draw_pipeline(void *data) +{ + (void)data; +} + +static void menu_display_fpga_viewport(void *data) +{ + (void)data; +} + +static void menu_display_fpga_restore_clear_color(void) +{ +} + +static void menu_display_fpga_clear_color(menu_display_ctx_clearcolor_t *clearcolor) +{ + (void)clearcolor; + + menu_display_fpga_restore_clear_color(); +} + +static bool menu_display_fpga_font_init_first( + void **font_handle, void *video_data, + const char *font_path, float font_size, + bool is_threaded) +{ + font_data_t **handle = (font_data_t**)font_handle; + *handle = font_driver_init_first(video_data, + font_path, font_size, true, + is_threaded, + FONT_DRIVER_RENDER_FPGA); + return *handle; +} + +static const float *menu_display_fpga_get_default_vertices(void) +{ + static float dummy[16] = {0.0f}; + return &dummy[0]; +} + +static const float *menu_display_fpga_get_default_tex_coords(void) +{ + static float dummy[16] = {0.0f}; + return &dummy[0]; +} + +menu_display_ctx_driver_t menu_display_ctx_fpga = { + menu_display_fpga_draw, + menu_display_fpga_draw_pipeline, + menu_display_fpga_viewport, + menu_display_fpga_blend_begin, + menu_display_fpga_blend_end, + menu_display_fpga_restore_clear_color, + menu_display_fpga_clear_color, + menu_display_fpga_get_default_mvp, + menu_display_fpga_get_default_vertices, + menu_display_fpga_get_default_tex_coords, + menu_display_fpga_font_init_first, + MENU_VIDEO_DRIVER_FPGA, + "menu_display_fpga", +}; diff --git a/menu/menu_defines.h b/menu/menu_defines.h index 50e2dca678..47de53f339 100644 --- a/menu/menu_defines.h +++ b/menu/menu_defines.h @@ -228,7 +228,8 @@ enum menu_display_driver_type MENU_VIDEO_DRIVER_SIXEL, MENU_VIDEO_DRIVER_GDI, MENU_VIDEO_DRIVER_SWITCH, - MENU_VIDEO_DRIVER_VGA + MENU_VIDEO_DRIVER_VGA, + MENU_VIDEO_DRIVER_FPGA }; enum rgui_thumbnail_scaler diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 40b74a84fc..b43857937d 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -166,6 +166,9 @@ static menu_display_ctx_driver_t *menu_display_ctx_drivers[] = { #endif #ifdef HAVE_CACA &menu_display_ctx_caca, +#endif +#ifdef HAVE_FPGA + &menu_display_ctx_fpga, #endif &menu_display_ctx_null, NULL, @@ -1641,6 +1644,10 @@ static bool menu_display_check_compatibility( if (string_is_equal(video_driver, "vga")) return true; break; + case MENU_VIDEO_DRIVER_FPGA: + if (string_is_equal(video_driver, "fpga")) + return true; + break; case MENU_VIDEO_DRIVER_SWITCH: if (string_is_equal(video_driver, "switch")) return true; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 426efe47a1..8e11b61b0a 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -711,6 +711,7 @@ extern menu_display_ctx_driver_t menu_display_ctx_wiiu; extern menu_display_ctx_driver_t menu_display_ctx_caca; extern menu_display_ctx_driver_t menu_display_ctx_gdi; extern menu_display_ctx_driver_t menu_display_ctx_vga; +extern menu_display_ctx_driver_t menu_display_ctx_fpga; extern menu_display_ctx_driver_t menu_display_ctx_switch; extern menu_display_ctx_driver_t menu_display_ctx_sixel; extern menu_display_ctx_driver_t menu_display_ctx_null; diff --git a/retroarch.c b/retroarch.c index a3472e9cad..2cade385bd 100644 --- a/retroarch.c +++ b/retroarch.c @@ -431,6 +431,9 @@ static const video_driver_t *video_drivers[] = { #ifdef DJGPP &video_vga, #endif +#ifdef HAVE_FPGA + &video_fpga, +#endif #ifdef HAVE_SIXEL &video_sixel, #endif @@ -517,6 +520,9 @@ static const gfx_ctx_driver_t *gfx_ctx_drivers[] = { #endif #ifdef HAVE_NETWORK_VIDEO &gfx_ctx_network, +#endif +#if defined(HAVE_FPGA) + &gfx_ctx_fpga, #endif &gfx_ctx_null, NULL diff --git a/retroarch.h b/retroarch.h index 62071faed5..b10d7bbb42 100644 --- a/retroarch.h +++ b/retroarch.h @@ -839,6 +839,7 @@ enum gfx_ctx_api GFX_CTX_NETWORK_VIDEO_API, GFX_CTX_METAL_API, GFX_CTX_GDI_API, + GFX_CTX_FPGA_API, GFX_CTX_GX_API, GFX_CTX_GX2_API }; @@ -1942,6 +1943,7 @@ extern video_driver_t video_xshm; extern video_driver_t video_caca; extern video_driver_t video_gdi; extern video_driver_t video_vga; +extern video_driver_t video_fpga; extern video_driver_t video_sixel; extern video_driver_t video_network; extern video_driver_t video_null; @@ -1965,6 +1967,7 @@ extern const gfx_ctx_driver_t gfx_ctx_emscripten; extern const gfx_ctx_driver_t gfx_ctx_opendingux_fbdev; extern const gfx_ctx_driver_t gfx_ctx_khr_display; extern const gfx_ctx_driver_t gfx_ctx_gdi; +extern const gfx_ctx_driver_t gfx_ctx_fpga; extern const gfx_ctx_driver_t gfx_ctx_sixel; extern const gfx_ctx_driver_t gfx_ctx_network; extern const gfx_ctx_driver_t switch_ctx;