diff --git a/Makefile.common b/Makefile.common index e1b6b8a2fb..80b14de44d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2116,6 +2116,7 @@ ifeq ($(HAVE_ODROIDGO2), 1) LIBS += -lrga -lpng -lz INCLUDE_DIRS += -I$(DEPS_DIR)/libgo2/include OBJ += $(DEPS_DIR)/libgo2/src/display.o \ - $(DEPS_DIR)/libgo2/src/queue.o + $(DEPS_DIR)/libgo2/src/queue.o \ + gfx/drivers/oga_gfx.o endif ################################## diff --git a/deps/libgo2/include/go2/display.h b/deps/libgo2/include/go2/display.h index cbe30a9c2a..b2da20a47e 100644 --- a/deps/libgo2/include/go2/display.h +++ b/deps/libgo2/include/go2/display.h @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include +#include typedef struct go2_display go2_display_t; @@ -78,18 +79,19 @@ void* go2_surface_map(go2_surface_t* surface); void go2_surface_unmap(go2_surface_t* surface); void go2_surface_blit(go2_surface_t* srcSurface, int srcX, int srcY, int srcWidth, int srcHeight, go2_surface_t* dstSurface, int dstX, int dstY, int dstWidth, int dstHeight, - go2_rotation_t rotation); + go2_rotation_t rotation, int scale_mode); int go2_surface_save_as_png(go2_surface_t* surface, const char* filename); go2_frame_buffer_t* go2_frame_buffer_create(go2_surface_t* surface); void go2_frame_buffer_destroy(go2_frame_buffer_t* frame_buffer); go2_surface_t* go2_frame_buffer_surface_get(go2_frame_buffer_t* frame_buffer); +go2_display_t* go2_presenter_display_get(go2_presenter_t* presenter); -go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color); +go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color, bool managed); void go2_presenter_destroy(go2_presenter_t* presenter); -void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation); +void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation, int scale_mode); go2_context_t* go2_context_create(go2_display_t* display, int width, int height, const go2_context_attributes_t* attributes); diff --git a/deps/libgo2/src/display.c b/deps/libgo2/src/display.c index 52b2827cae..b91cf0624b 100644 --- a/deps/libgo2/src/display.c +++ b/deps/libgo2/src/display.c @@ -71,7 +71,6 @@ typedef struct go2_surface int stride; uint32_t format; int prime_fd; - bool is_mapped; uint8_t* map; } go2_surface_t; @@ -93,6 +92,7 @@ typedef struct go2_presenter sem_t freeSem; sem_t usedSem; volatile bool terminating; + bool managed; } go2_presenter_t; @@ -100,7 +100,6 @@ go2_display_t* go2_display_create() { int i; - go2_display_t* result = malloc(sizeof(*result)); if (!result) { @@ -121,7 +120,7 @@ go2_display_t* go2_display_create() drmModeRes* resources = drmModeGetResources(result->fd); - if (!resources) + if (!resources) { printf("drmModeGetResources failed: %s\n", strerror(errno)); goto err_01; @@ -164,7 +163,7 @@ go2_display_t* go2_display_create() mode = NULL; } - if (!mode) + if (!mode) { printf("DRM_MODE_TYPE_PREFERRED not found.\n"); goto err_03; @@ -184,7 +183,7 @@ go2_display_t* go2_display_create() { break; } - + drmModeFreeEncoder(encoder); encoder = NULL; } @@ -195,13 +194,13 @@ go2_display_t* go2_display_create() printf("could not find encoder!\n"); goto err_03; } - + result->crtc_id = encoder->crtc_id; drmModeFreeEncoder(encoder); drmModeFreeConnector(connector); drmModeFreeResources(resources); - + return result; @@ -243,7 +242,7 @@ void go2_display_present(go2_display_t* display, go2_frame_buffer_t* frame_buffe int ret = drmModeSetCrtc(display->fd, display->crtc_id, frame_buffer->fb_id, 0, 0, &display->connector_id, 1, &display->mode); if (ret) { - printf("drmModeSetCrtc failed.\n"); + printf("drmModeSetCrtc failed.\n"); } } @@ -285,7 +284,7 @@ uint32_t go2_display_backlight_get(go2_display_t* display) value = atoi(buffer); } - close(fd); + close(fd); } float percent = value / (float)max * 100.0f; @@ -298,7 +297,7 @@ void go2_display_backlight_set(go2_display_t* display, uint32_t value) int max = 255; char buffer[BACKLIGHT_BUFFER_SIZE + 1]; - + if (value > 100) value = 100; fd = open(BACKLIGHT_BRIGHTNESS_MAX_NAME, O_RDONLY); @@ -331,13 +330,13 @@ void go2_display_backlight_set(go2_display_t* display, uint32_t value) printf("go2_display_backlight_set write failed.\n"); } - close(fd); + close(fd); } else { printf("go2_display_backlight_set open failed.\n"); } - + } @@ -371,7 +370,7 @@ int go2_drm_format_get_bpp(uint32_t format) case DRM_FORMAT_BGR565: result = 16; break; - + case DRM_FORMAT_RGB888: case DRM_FORMAT_BGR888: @@ -443,6 +442,7 @@ go2_surface_t* go2_surface_create(go2_display_t* display, int width, int height, result->height = height; result->stride = args.pitch; result->format = format; + result->map = NULL; return result; @@ -459,7 +459,7 @@ void go2_surface_destroy(go2_surface_t* surface) int io = drmIoctl(surface->display->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &args); if (io < 0) { - printf("DRM_IOCTL_MODE_DESTROY_DUMB failed.\n"); + printf("DRM_IOCTL_MODE_DESTROY_DUMB failed.\n"); } free(surface); @@ -511,10 +511,9 @@ out: void* go2_surface_map(go2_surface_t* surface) { - if (surface->is_mapped) + if (surface->map) return surface->map; - int prime_fd = go2_surface_prime_fd(surface); surface->map = mmap(NULL, surface->size, PROT_READ | PROT_WRITE, MAP_SHARED, prime_fd, 0); if (surface->map == MAP_FAILED) @@ -523,17 +522,14 @@ void* go2_surface_map(go2_surface_t* surface) return NULL; } - surface->is_mapped = true; return surface->map; } void go2_surface_unmap(go2_surface_t* surface) { - if (surface->is_mapped) + if (surface->map) { munmap(surface->map, surface->size); - - surface->is_mapped = false; surface->map = NULL; } } @@ -545,29 +541,29 @@ static uint32_t go2_rkformat_get(uint32_t drm_fourcc) { case DRM_FORMAT_RGBA8888: return RK_FORMAT_RGBA_8888; - + case DRM_FORMAT_RGBX8888: return RK_FORMAT_RGBX_8888; - + case DRM_FORMAT_RGB888: return RK_FORMAT_RGB_888; - + case DRM_FORMAT_ARGB8888: case DRM_FORMAT_XRGB8888: return RK_FORMAT_BGRA_8888; - + case DRM_FORMAT_RGB565: return RK_FORMAT_RGB_565; case DRM_FORMAT_RGBA5551: return RK_FORMAT_RGBA_5551; - + case DRM_FORMAT_RGBA4444: return RK_FORMAT_RGBA_4444; case DRM_FORMAT_BGR888: return RK_FORMAT_BGR_888; - + default: printf("RKFORMAT not supported. "); printf("drm_fourcc=%c%c%c%c\n", drm_fourcc & 0xff, drm_fourcc >> 8 & 0xff, drm_fourcc >> 16 & 0xff, drm_fourcc >> 24); @@ -577,7 +573,7 @@ static uint32_t go2_rkformat_get(uint32_t drm_fourcc) void go2_surface_blit(go2_surface_t* srcSurface, int srcX, int srcY, int srcWidth, int srcHeight, go2_surface_t* dstSurface, int dstX, int dstY, int dstWidth, int dstHeight, - go2_rotation_t rotation) + go2_rotation_t rotation, int scale_mode) { rga_info_t dst = { 0 }; dst.fd = go2_surface_prime_fd(dstSurface); @@ -634,13 +630,12 @@ void go2_surface_blit(go2_surface_t* srcSurface, int srcX, int srcY, int srcWidt B_SPLINE = 0x3, }; /*bicubic coefficient*/ #endif - src.scale_mode = 2; - + src.scale_mode = scale_mode; int ret = c_RkRgaBlit(&src, &dst, NULL); if (ret) { - printf("c_RkRgaBlit failed.\n"); + printf("c_RkRgaBlit failed.\n"); } } @@ -652,14 +647,14 @@ int go2_surface_save_as_png(go2_surface_t* surface, const char* filename) png_byte color_type = 0; - png_byte bit_depth = 0; + png_byte bit_depth = 0; switch (surface->format) - { + { case DRM_FORMAT_RGBA8888: color_type = PNG_COLOR_TYPE_RGBA; bit_depth = 8; break; - + case DRM_FORMAT_RGB888: color_type = PNG_COLOR_TYPE_RGB; bit_depth = 8; @@ -733,7 +728,7 @@ int go2_surface_save_as_png(go2_surface_t* surface, const char* filename) /* write bytes */ png_bytep src = (png_bytep)go2_surface_map(surface); - row_pointers = malloc(sizeof(png_bytep) * surface->height); + row_pointers = malloc(sizeof(png_bytep) * surface->height); for (int y = 0; y < surface->height; ++y) { row_pointers[y] = src + (surface->stride * y); @@ -891,14 +886,19 @@ static void* go2_presenter_renderloop(void* arg) sem_post(&presenter->freeSem); } - prevFrameBuffer = dstFrameBuffer; + prevFrameBuffer = dstFrameBuffer; } return NULL; } -go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color) +go2_display_t* go2_presenter_display_get(go2_presenter_t* presenter) +{ + return presenter->display; +} + +go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color, bool managed) { go2_presenter_t* result = malloc(sizeof(*result)); if (!result) @@ -913,67 +913,74 @@ go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, u result->display = display; result->format = format; result->background_color = background_color; - result->freeFrameBuffers = go2_queue_create(BUFFER_COUNT); - result->usedFrameBuffers = go2_queue_create(BUFFER_COUNT); + result->managed = managed; + if (managed) { + result->freeFrameBuffers = go2_queue_create(BUFFER_COUNT); + result->usedFrameBuffers = go2_queue_create(BUFFER_COUNT); - int width = go2_display_width_get(display); - int height = go2_display_height_get(display); + int width = go2_display_width_get(display); + int height = go2_display_height_get(display); - for (int i = 0; i < BUFFER_COUNT; ++i) - { - go2_surface_t* surface = go2_surface_create(display, width, height, format); - go2_frame_buffer_t* frameBuffer = go2_frame_buffer_create(surface); + for (int i = 0; i < BUFFER_COUNT; ++i) + { + go2_surface_t* surface = go2_surface_create(display, width, height, format); + go2_frame_buffer_t* frameBuffer = go2_frame_buffer_create(surface); - go2_queue_push(result->freeFrameBuffers, frameBuffer); + go2_queue_push(result->freeFrameBuffers, frameBuffer); + } + + sem_init(&result->usedSem, 0, 0); + sem_init(&result->freeSem, 0, BUFFER_COUNT); + + pthread_mutex_init(&result->queueMutex, NULL); + + pthread_create(&result->renderThread, NULL, go2_presenter_renderloop, result); + } + else { + result->freeFrameBuffers = go2_queue_create(0); + result->usedFrameBuffers = go2_queue_create(0); } - - - sem_init(&result->usedSem, 0, 0); - sem_init(&result->freeSem, 0, BUFFER_COUNT); - - pthread_mutex_init(&result->queueMutex, NULL); - - pthread_create(&result->renderThread, NULL, go2_presenter_renderloop, result); return result; } void go2_presenter_destroy(go2_presenter_t* presenter) { - presenter->terminating = true; - sem_post(&presenter->usedSem); + if (presenter->managed) { + presenter->terminating = true; + sem_post(&presenter->usedSem); - pthread_join(presenter->renderThread, NULL); - pthread_mutex_destroy(&presenter->queueMutex); + pthread_join(presenter->renderThread, NULL); + pthread_mutex_destroy(&presenter->queueMutex); - sem_destroy(&presenter->freeSem); - sem_destroy(&presenter->usedSem); + sem_destroy(&presenter->freeSem); + sem_destroy(&presenter->usedSem); - - while(go2_queue_count_get(presenter->usedFrameBuffers) > 0) - { - go2_frame_buffer_t* frameBuffer = go2_queue_pop(presenter->usedFrameBuffers); - - go2_surface_t* surface = frameBuffer->surface; - - go2_frame_buffer_destroy(frameBuffer); - go2_surface_destroy(surface); - } + while(go2_queue_count_get(presenter->usedFrameBuffers) > 0) + { + go2_frame_buffer_t* frameBuffer = go2_queue_pop(presenter->usedFrameBuffers); - while(go2_queue_count_get(presenter->freeFrameBuffers) > 0) - { - go2_frame_buffer_t* frameBuffer = go2_queue_pop(presenter->freeFrameBuffers); - - go2_surface_t* surface = frameBuffer->surface; + go2_surface_t* surface = frameBuffer->surface; - go2_frame_buffer_destroy(frameBuffer); - go2_surface_destroy(surface); + go2_frame_buffer_destroy(frameBuffer); + go2_surface_destroy(surface); + } + + while(go2_queue_count_get(presenter->freeFrameBuffers) > 0) + { + go2_frame_buffer_t* frameBuffer = go2_queue_pop(presenter->freeFrameBuffers); + + go2_surface_t* surface = frameBuffer->surface; + + go2_frame_buffer_destroy(frameBuffer); + go2_surface_destroy(surface); + } } free(presenter); } -void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation) +void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation, int scale_mode) { sem_wait(&presenter->freeSem); @@ -1012,7 +1019,7 @@ void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int } - go2_surface_blit(surface, srcX, srcY, srcWidth, srcHeight, dstSurface, dstX, dstY, dstWidth, dstHeight, rotation); + go2_surface_blit(surface, srcX, srcY, srcWidth, srcHeight, dstSurface, dstX, dstY, dstWidth, dstHeight, rotation, scale_mode); pthread_mutex_lock(&presenter->queueMutex); @@ -1022,8 +1029,6 @@ void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int sem_post(&presenter->usedSem); } - - #define BUFFER_MAX (3) typedef struct buffer_surface_pair @@ -1034,7 +1039,7 @@ typedef struct buffer_surface_pair typedef struct go2_context { - go2_display_t* display; + go2_display_t* display; int width; int height; go2_context_attributes_t attributes; diff --git a/deps/libgo2/src/display.h b/deps/libgo2/src/display.h index cbe30a9c2a..2427f296a3 100644 --- a/deps/libgo2/src/display.h +++ b/deps/libgo2/src/display.h @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include +#include typedef struct go2_display go2_display_t; @@ -78,7 +79,7 @@ void* go2_surface_map(go2_surface_t* surface); void go2_surface_unmap(go2_surface_t* surface); void go2_surface_blit(go2_surface_t* srcSurface, int srcX, int srcY, int srcWidth, int srcHeight, go2_surface_t* dstSurface, int dstX, int dstY, int dstWidth, int dstHeight, - go2_rotation_t rotation); + go2_rotation_t rotation, int scale_mode); int go2_surface_save_as_png(go2_surface_t* surface, const char* filename); @@ -87,9 +88,10 @@ void go2_frame_buffer_destroy(go2_frame_buffer_t* frame_buffer); go2_surface_t* go2_frame_buffer_surface_get(go2_frame_buffer_t* frame_buffer); -go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color); +go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color, bool managed); void go2_presenter_destroy(go2_presenter_t* presenter); -void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation); +void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation, int scale_mode); +go2_display_t* go2_presenter_display_get(go2_presenter_t* presenter); go2_context_t* go2_context_create(go2_display_t* display, int width, int height, const go2_context_attributes_t* attributes); @@ -100,6 +102,8 @@ void go2_context_swap_buffers(go2_context_t* context); go2_surface_t* go2_context_surface_lock(go2_context_t* context); void go2_context_surface_unlock(go2_context_t* context, go2_surface_t* surface); +go2_frame_buffer_t* go2_frame_buffer_create(go2_surface_t* surface); + #ifdef __cplusplus } #endif diff --git a/gfx/drivers/oga_gfx.c b/gfx/drivers/oga_gfx.c new file mode 100644 index 0000000000..022f9f9c6c --- /dev/null +++ b/gfx/drivers/oga_gfx.c @@ -0,0 +1,400 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2011-2017 - Higor Euripedes + * + * 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 +#include + +#include +#include +#include "../../verbosity.h" +#include +#include +#include + +#include "../font_driver.h" + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#include "../../configuration.h" +#include "../../retroarch.h" + +#include +#include + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) + +#define NATIVE_WIDTH 480 +#define NATIVE_HEIGHT 320 + +#define NUM_PAGES 2 + +typedef struct oga_video +{ + go2_presenter_t* presenter; + go2_display_t* display; + go2_surface_t* frame; + + go2_frame_buffer_t* frameBuffer[NUM_PAGES]; + int cur_page; + + const font_renderer_driver_t *font_driver; + void *font; + + go2_surface_t* menu_surface; + const void* menu_frame; + unsigned menu_width; + unsigned menu_height; + unsigned menu_pitch; +} oga_video_t; + +go2_rotation_t oga_rotation = GO2_ROTATION_DEGREES_0; + +static void oga_gfx_free(void *data) +{ + oga_video_t *vid = (oga_video_t*)data; + if (!vid) + return; + + if (vid->font) { + vid->font_driver->free(vid->font); + vid->font_driver = NULL; + } + + for (int i = 0; i < NUM_PAGES; ++i) + { + go2_frame_buffer_t* frameBuffer = vid->frameBuffer[i]; + go2_surface_t* surface = go2_frame_buffer_surface_get(frameBuffer); + + go2_frame_buffer_destroy(frameBuffer); + go2_surface_destroy(surface); + } + + go2_surface_destroy(vid->frame); + go2_surface_destroy(vid->menu_surface); + go2_presenter_destroy(vid->presenter); + go2_display_destroy(vid->display); + + free(vid); + vid = NULL; +} + +static void *oga_gfx_init(const video_info_t *video, + input_driver_t **input, void **input_data) +{ + oga_video_t *vid = NULL; + settings_t *settings = config_get_ptr(); + struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); + + if (input && input_data) { + void* udev = input_udev.init(settings->arrays.input_joypad_driver); + if (udev) { + *input = &input_udev; + *input_data = udev; + } + else + *input = NULL; + } + + vid = (oga_video_t*)calloc(1, sizeof(*vid)); + + vid->menu_frame = NULL; + vid->display = go2_display_create(); + vid->presenter = go2_presenter_create(vid->display, DRM_FORMAT_RGB565, 0xff000000, false); + vid->menu_surface = go2_surface_create(vid->display, NATIVE_WIDTH, NATIVE_HEIGHT, DRM_FORMAT_RGB565); + vid->font = NULL; + vid->font_driver = NULL; + + int aw = MAX(ALIGN(av_info->geometry.max_width, 32), NATIVE_WIDTH); + int ah = MAX(ALIGN(av_info->geometry.max_height, 32), NATIVE_HEIGHT); + + printf("oga_gfx_init video %dx%d rgb32 %d smooth %d input_scale %u force_aspect %d fullscreen %d aw %d ah %d rgb %d\n", + video->width, video->height, video->rgb32, video->smooth, video->input_scale, video->force_aspect, + video->fullscreen, aw, ah, video->rgb32); + + vid->frame = go2_surface_create(vid->display, aw, ah, video->rgb32 ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_RGB565); + + // bitmap only for now + if (settings->bools.video_font_enable) { + vid->font_driver = &bitmap_font_renderer; + vid->font = vid->font_driver->init("", settings->floats.video_font_size); + } + + for (int i = 0; i < NUM_PAGES; ++i) + { + go2_surface_t* surface = go2_surface_create(vid->display, NATIVE_HEIGHT, NATIVE_WIDTH, + video->rgb32 ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_XRGB8888); + vid->frameBuffer[i] = go2_frame_buffer_create(surface); + } + vid->cur_page = 0; + + return vid; +} + +int get_message_width(oga_video_t* vid, const char* msg) +{ + int width = 0; + for (const char* c = msg; *c; c++) + { + const struct font_glyph* glyph = vid->font_driver->get_glyph(vid->font, *c); + if (unlikely(!glyph)) + continue; + + width += glyph->advance_x; + } + return width; +} + +static void render_msg(oga_video_t* vid, go2_surface_t* surface, const char* msg, int width, int bpp) +{ + const struct font_atlas* atlas = vid->font_driver->get_atlas(vid->font); + int msg_width = get_message_width(vid, msg); + int dest_x = MAX(0, width - get_message_width(vid, msg)); + + const char* c = msg; + while (*c) { + const struct font_glyph* g = vid->font_driver->get_glyph(vid->font, *c); + if (!g) + continue; + if (dest_x + g->advance_x >= width) + break; + + const uint8_t* source = atlas->buffer + g->atlas_offset_y * atlas->width + g->atlas_offset_x; + uint8_t* dest = (uint8_t*)go2_surface_map(surface) + dest_x * bpp; + + for (int y = 0; y < g->height; y++) { + for (int x = 0; x < g->advance_x; x++) { + uint8_t px = (x < g->width) ? *(source++) : 0x00; + if (bpp == 4) { + *(dest++) = px; + *(dest++) = px; + *(dest++) = px; + *(dest++) = px; + } + else { + *(dest++) = px; + *(dest++) = px; + } + } + dest += go2_surface_stride_get(surface) - g->advance_x * bpp; + source += atlas->width - g->width; + } + + c++; + dest_x += g->advance_x; + } +} + +static bool oga_gfx_frame(void *data, const void *frame, unsigned width, + unsigned height, uint64_t frame_count, + unsigned pitch, const char *msg, video_frame_info_t *video_info) +{ + oga_video_t* vid = (oga_video_t*)data; + go2_surface_t* dst_surface = vid->frame; + uint8_t* src = (uint8_t*)frame; + int bpp = go2_drm_format_get_bpp(go2_surface_format_get(dst_surface)) / 8; + + if (unlikely(video_info->menu_is_alive)) { +#ifdef HAVE_MENU + menu_driver_frame(video_info); +#endif + dst_surface = vid->menu_surface; + src = (uint8_t*)vid->menu_frame; + width = vid->menu_width; + height = vid->menu_height; + pitch = vid->menu_pitch; + bpp = vid->menu_pitch / vid->menu_width; + } + + if (unlikely(!frame || width == 0 || height == 0)) + return true; + + // copy buffer to surface + uint8_t* dst = (uint8_t*)go2_surface_map(dst_surface); + int yy = height; + int stride = width * bpp; + while (yy > 0) { + memcpy(dst, src, stride); + src += pitch; + dst += go2_surface_stride_get(dst_surface); + --yy; + } + + int out_w = NATIVE_WIDTH; + int out_h = NATIVE_HEIGHT; + int out_x = 0; + int out_y = 0; + + if ((out_w != width || out_h != height)) + { + out_w = MIN(out_h * video_driver_get_aspect_ratio(), NATIVE_WIDTH); + out_x = MAX((NATIVE_WIDTH - out_w) / 2, 0); + } + + if (msg && vid->font) { + render_msg(vid, dst_surface, msg, width, bpp); + } + + go2_frame_buffer_t* dstFrameBuffer = vid->frameBuffer[vid->cur_page]; + go2_surface_t* dstSurface = go2_frame_buffer_surface_get(dstFrameBuffer); + + go2_surface_blit(dst_surface, 0, 0, width, height, + dstSurface, out_y, out_x, out_h, out_w, + !video_info->menu_is_alive ? oga_rotation : GO2_ROTATION_DEGREES_270, 2); + + go2_display_t* display = go2_presenter_display_get(vid->presenter); + go2_display_present(display, dstFrameBuffer); + vid->cur_page = !vid->cur_page; + + return true; +} + +static void oga_set_texture_frame(void *data, const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha) +{ + oga_video_t *vid = (oga_video_t*)data; + + vid->menu_width = width; + vid->menu_height = height; + vid->menu_pitch = width * (rgb32 ? 4 : 2); + + if (unlikely(!vid->menu_frame)) + vid->menu_frame = frame; +} + +static void oga_gfx_set_nonblock_state(void *a, bool b, bool c, unsigned d) +{ +} + +static bool oga_gfx_alive(void *data) +{ + return true; +} + +static bool oga_gfx_focus(void *data) +{ + (void)data; + return true; +} + +static bool oga_gfx_suppress_screensaver(void *data, bool enable) +{ + (void)data; + (void)enable; + return false; +} + +static bool oga_gfx_has_windowed(void *data) +{ + (void)data; + return false; +} + +static void oga_gfx_viewport_info(void *data, struct video_viewport *vp) +{ + oga_video_t *vid = (oga_video_t*)data; + vp->x = 0; + vp->y = 0; + vp->width = vp->full_width = NATIVE_WIDTH; + vp->height = vp->full_height = NATIVE_HEIGHT; +} + +static const video_poke_interface_t oga_poke_interface = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + oga_set_texture_frame, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +void oga_set_rotation(void *data, unsigned rotation) +{ + // called before init? + (void)data; + switch (rotation) { + case 0: + oga_rotation = GO2_ROTATION_DEGREES_270; + break; + case 1: + oga_rotation = GO2_ROTATION_DEGREES_180; + break; + case 2: + oga_rotation = GO2_ROTATION_DEGREES_90; + break; + case 3: + oga_rotation = GO2_ROTATION_DEGREES_0; + break; + default: + RARCH_ERR("Unhandled rotation %hu\n", rotation); + break; + } +} + +static void oga_get_poke_interface(void *data, const video_poke_interface_t **iface) +{ + (void)data; + *iface = &oga_poke_interface; +} + +video_driver_t video_oga = { + oga_gfx_init, + oga_gfx_frame, + oga_gfx_set_nonblock_state, + oga_gfx_alive, + oga_gfx_focus, + oga_gfx_suppress_screensaver, + oga_gfx_has_windowed, + NULL, + oga_gfx_free, + "oga", + NULL, + oga_set_rotation, + oga_gfx_viewport_info, + NULL, + NULL, +#ifdef HAVE_OVERLAY + NULL, +#endif +#ifdef HAVE_VIDEO_LAYOUT + NULL, +#endif + oga_get_poke_interface +}; diff --git a/gfx/drivers_context/drm_ctx.c b/gfx/drivers_context/drm_ctx.c index 135c3b2ad2..dfda72f822 100644 --- a/gfx/drivers_context/drm_ctx.c +++ b/gfx/drivers_context/drm_ctx.c @@ -262,7 +262,7 @@ static void gfx_ctx_drm_swap_buffers(void *data) surface, 0, 0, 480, 320, 0, 0, 320, 480, - GO2_ROTATION_DEGREES_270); + GO2_ROTATION_DEGREES_270, 2); go2_context_surface_unlock(drm->context, surface); #endif break; @@ -488,7 +488,7 @@ error: return NULL; #else drm->display = go2_display_create(); - drm->presenter = go2_presenter_create(drm->display, DRM_FORMAT_RGB565, 0xff080808); + drm->presenter = go2_presenter_create(drm->display, DRM_FORMAT_RGB565, 0xff000000, true); return drm; #endif } diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 8753d5ceda..1e2682009a 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -35,7 +35,7 @@ static const font_renderer_driver_t *font_backends[] = { &coretext_font_renderer, #endif #ifdef HAVE_STB_FONT -#if defined(VITA) || defined(WIIU) || defined(ANDROID) || (defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) && _MSC_VER >= 1400) || (defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER)) || defined(__CELLOS_LV2__) || defined(HAVE_LIBNX) || defined(__linux__) || defined (HAVE_EMSCRIPTEN) || defined(__APPLE__) +#if defined(VITA) || defined(WIIU) || defined(ANDROID) || (defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) && _MSC_VER >= 1400) || (defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER)) || defined(__CELLOS_LV2__) || defined(HAVE_LIBNX) || defined(__linux__) || defined (HAVE_EMSCRIPTEN) || defined(__APPLE__) || defined(HAVE_ODROIDGO2) &stb_unicode_font_renderer, #else &stb_font_renderer, diff --git a/retroarch.c b/retroarch.c index 77110aa6c7..b48ce9ee59 100644 --- a/retroarch.c +++ b/retroarch.c @@ -483,6 +483,9 @@ static const video_driver_t *video_drivers[] = { #ifdef SWITCH &video_switch, #endif +#ifdef HAVE_ODROIDGO2 + &video_oga, +#endif #if defined(HAVE_SDL) && !defined(HAVE_SDL_DINGUX) &video_sdl, #endif diff --git a/retroarch.h b/retroarch.h index d3dc4488ec..626ff54a71 100644 --- a/retroarch.h +++ b/retroarch.h @@ -1886,6 +1886,7 @@ 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_oga; extern const gfx_ctx_driver_t gfx_ctx_osmesa; extern const gfx_ctx_driver_t gfx_ctx_sdl_gl;