mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 13:20:30 +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:
parent
f48c668447
commit
53fffbd670
@ -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
|
||||
##################################
|
||||
|
8
deps/libgo2/include/go2/display.h
vendored
8
deps/libgo2/include/go2/display.h
vendored
@ -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);
|
||||
|
167
deps/libgo2/src/display.c
vendored
167
deps/libgo2/src/display.c
vendored
@ -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;
|
||||
|
10
deps/libgo2/src/display.h
vendored
10
deps/libgo2/src/display.h
vendored
@ -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
400
gfx/drivers/oga_gfx.c
Normal 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
|
||||
};
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user