1
0
mirror of https://github.com/libretro/RetroArch synced 2024-07-03 00:38:44 +00:00

Add "oga" graphics driver for odroid go advance

libgo2 improvements

- Expose rga scale mode as param for future use
- Cleanup whitespace
- Add option to disable managed surfaces and allow direct posting to drm
  driver

oga graphics driver

- Uses direct framebuffers in libgo2
- Bitmap font only supported for now
- Uses built-in bicubic filtering: graphics quality better than gl + bilinear
- Support for rotation
This commit is contained in:
valadaa48 2020-03-21 21:42:19 -04:00
parent f48c668447
commit 53fffbd670
9 changed files with 507 additions and 91 deletions

View File

@ -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
##################################

View File

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <stdbool.h>
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);

View File

@ -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;

View File

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdint.h>
#include <stdbool.h>
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

400
gfx/drivers/oga_gfx.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <gfx/video_frame.h>
#include <retro_assert.h>
#include "../../verbosity.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm/drm_fourcc.h>
#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 <go2/display.h>
#include <drm/drm_fourcc.h>
#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
};

View File

@ -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
}

View File

@ -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,

View File

@ -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

View File

@ -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;