mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 21:32:45 +00:00
oga_gfx: rewrite
- Drop libgo2 dep - Use more features of RGA - Triple buffer instead of double buffer - Rewrite of message code to support surface caching, transluceny, and multiline message support. Messages also don't scale with the emulation frame anymore and are drawn directly to the frame buffer. - Better support for aspect ratios
This commit is contained in:
parent
6c496eeaab
commit
7015e199bb
@ -17,10 +17,12 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <gfx/video_frame.h>
|
||||
#include <retro_assert.h>
|
||||
#include "../../verbosity.h"
|
||||
#include <fcntl.h>
|
||||
#include <rga/RgaApi.h>
|
||||
#include <rga/RockchipRgaMacro.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
@ -40,46 +42,281 @@
|
||||
#include "../../configuration.h"
|
||||
#include "../../retroarch.h"
|
||||
|
||||
#include <go2/display.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 NATIVE_ASPECT_RATIO 1.5
|
||||
|
||||
#define NUM_PAGES 2
|
||||
#define NUM_PAGES 3
|
||||
|
||||
typedef struct oga_rect {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
} oga_rect_t;
|
||||
|
||||
typedef struct oga_surface
|
||||
{
|
||||
uint8_t* map;
|
||||
int width;
|
||||
int height;
|
||||
int pitch;
|
||||
int prime_fd;
|
||||
int rk_format;
|
||||
|
||||
int display_fd;
|
||||
uint32_t handle;
|
||||
} oga_surface_t;
|
||||
|
||||
typedef struct oga_framebuf
|
||||
{
|
||||
oga_surface_t* surface;
|
||||
uint32_t fb_id;
|
||||
} oga_framebuf_t;
|
||||
|
||||
typedef struct oga_video
|
||||
{
|
||||
go2_presenter_t* presenter;
|
||||
go2_display_t* display;
|
||||
go2_surface_t* frame;
|
||||
int fd;
|
||||
uint32_t connector_id;
|
||||
drmModeModeInfo mode;
|
||||
// uint32_t width;
|
||||
// uint32_t height;
|
||||
uint32_t crtc_id;
|
||||
|
||||
go2_frame_buffer_t* frameBuffer[NUM_PAGES];
|
||||
oga_surface_t* frame_surface;
|
||||
oga_surface_t* menu_surface;
|
||||
|
||||
oga_framebuf_t* pages[NUM_PAGES];
|
||||
int cur_page;
|
||||
int scale_mode;
|
||||
int rotation;
|
||||
bool threaded;
|
||||
|
||||
oga_surface_t* msg_surface;
|
||||
const font_renderer_driver_t *font_driver;
|
||||
void *font;
|
||||
int msg_width;
|
||||
int msg_height;
|
||||
char last_msg[1024];
|
||||
|
||||
go2_surface_t* menu_surface;
|
||||
const void* menu_frame;
|
||||
unsigned menu_width;
|
||||
unsigned menu_height;
|
||||
unsigned menu_pitch;
|
||||
|
||||
char menu_buf[NATIVE_WIDTH*NATIVE_HEIGHT*4];
|
||||
int bpp;
|
||||
} oga_video_t;
|
||||
|
||||
go2_rotation_t oga_rotation = GO2_ROTATION_DEGREES_0;
|
||||
bool oga_create_display(oga_video_t* vid)
|
||||
{
|
||||
int i, ret;
|
||||
drmModeConnector* connector;
|
||||
|
||||
vid->fd = open("/dev/dri/card0", O_RDWR);
|
||||
if (vid->fd < 0)
|
||||
{
|
||||
RARCH_ERR("open /dev/dri/card0 failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
drmModeRes* resources = drmModeGetResources(vid->fd);
|
||||
if (!resources)
|
||||
{
|
||||
RARCH_ERR("drmModeGetResources failed: %s\n", strerror(errno));
|
||||
goto err_01;
|
||||
}
|
||||
|
||||
for (i = 0; i < resources->count_connectors; i++)
|
||||
{
|
||||
connector = drmModeGetConnector(vid->fd, resources->connectors[i]);
|
||||
if (connector->connection == DRM_MODE_CONNECTED) {
|
||||
break;
|
||||
}
|
||||
|
||||
drmModeFreeConnector(connector);
|
||||
connector = NULL;
|
||||
}
|
||||
|
||||
if (!connector)
|
||||
{
|
||||
RARCH_ERR("DRM_MODE_CONNECTED not found.\n");
|
||||
goto err_02;
|
||||
}
|
||||
|
||||
vid->connector_id = connector->connector_id;
|
||||
|
||||
// Find prefered mode
|
||||
drmModeModeInfo* mode;
|
||||
for (i = 0; i < connector->count_modes; i++)
|
||||
{
|
||||
drmModeModeInfo *current_mode = &connector->modes[i];
|
||||
if (current_mode->type & DRM_MODE_TYPE_PREFERRED)
|
||||
{
|
||||
mode = current_mode;
|
||||
break;
|
||||
}
|
||||
|
||||
mode = NULL;
|
||||
}
|
||||
|
||||
if (!mode)
|
||||
{
|
||||
RARCH_ERR("DRM_MODE_TYPE_PREFERRED not found.\n");
|
||||
goto err_03;
|
||||
}
|
||||
|
||||
vid->mode = *mode;
|
||||
// vid->width = mode->hdisplay;
|
||||
// vid->height = mode->vdisplay;
|
||||
|
||||
// Find encoder
|
||||
drmModeEncoder* encoder;
|
||||
for (i = 0; i < resources->count_encoders; i++)
|
||||
{
|
||||
encoder = drmModeGetEncoder(vid->fd, resources->encoders[i]);
|
||||
if (encoder->encoder_id == connector->encoder_id)
|
||||
break;
|
||||
|
||||
drmModeFreeEncoder(encoder);
|
||||
encoder = NULL;
|
||||
}
|
||||
|
||||
if (!encoder)
|
||||
{
|
||||
RARCH_ERR("could not find encoder!\n");
|
||||
goto err_03;
|
||||
}
|
||||
|
||||
vid->crtc_id = encoder->crtc_id;
|
||||
|
||||
drmModeFreeEncoder(encoder);
|
||||
drmModeFreeConnector(connector);
|
||||
drmModeFreeResources(resources);
|
||||
|
||||
return true;
|
||||
|
||||
err_03:
|
||||
drmModeFreeConnector(connector);
|
||||
|
||||
err_02:
|
||||
drmModeFreeResources(resources);
|
||||
|
||||
err_01:
|
||||
close(vid->fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
oga_surface_t* oga_create_surface(int display_fd, int width, int height, int rk_format)
|
||||
{
|
||||
oga_surface_t* surface = calloc(1, sizeof(oga_surface_t));
|
||||
if (!surface)
|
||||
{
|
||||
RARCH_ERR("Error allocating surface\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drm_mode_create_dumb args = {0};
|
||||
args.width = width;
|
||||
args.height = height;
|
||||
args.bpp = rk_format == RK_FORMAT_BGRA_8888 ? 32 : 16;
|
||||
args.flags = 0;
|
||||
|
||||
if (drmIoctl(display_fd, DRM_IOCTL_MODE_CREATE_DUMB, &args) < 0)
|
||||
{
|
||||
RARCH_ERR("DRM_IOCTL_MODE_CREATE_DUMB failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
surface->display_fd = display_fd;
|
||||
surface->handle = args.handle;
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->pitch = args.pitch;
|
||||
surface->rk_format = rk_format;
|
||||
|
||||
if (drmPrimeHandleToFD(display_fd, surface->handle, DRM_RDWR | DRM_CLOEXEC, &surface->prime_fd) < 0)
|
||||
{
|
||||
RARCH_ERR("drmPrimeHandleToFD failed.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
surface->map = mmap(NULL, args.size, PROT_READ | PROT_WRITE, MAP_SHARED, surface->prime_fd, 0);
|
||||
if (surface->map == MAP_FAILED)
|
||||
{
|
||||
RARCH_LOG("mmap failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return surface;
|
||||
|
||||
out:
|
||||
free(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void oga_destroy_surface(oga_surface_t* surface)
|
||||
{
|
||||
struct drm_mode_destroy_dumb args = { 0 };
|
||||
int io;
|
||||
|
||||
args.handle = surface->handle;
|
||||
|
||||
io = drmIoctl(surface->display_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &args);
|
||||
if (io < 0)
|
||||
RARCH_ERR("DRM_IOCTL_MODE_DESTROY_DUMB failed.\n");
|
||||
|
||||
free(surface);
|
||||
}
|
||||
|
||||
oga_framebuf_t* oga_create_framebuf(oga_surface_t* surface)
|
||||
{
|
||||
oga_framebuf_t* framebuf = calloc(1, sizeof(oga_framebuf_t));
|
||||
int ret;
|
||||
|
||||
if (!framebuf)
|
||||
{
|
||||
RARCH_ERR("Error allocating framebuf\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
framebuf->surface = surface;
|
||||
|
||||
const uint32_t handles[4] = {surface->handle, 0, 0, 0};
|
||||
const uint32_t pitches[4] = {surface->pitch, 0, 0, 0};
|
||||
const uint32_t offsets[4] = {0, 0, 0, 0};
|
||||
|
||||
ret = drmModeAddFB2(surface->display_fd,
|
||||
surface->width,
|
||||
surface->height,
|
||||
surface->rk_format == RK_FORMAT_BGRA_8888 ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_RGB565,
|
||||
handles,
|
||||
pitches,
|
||||
offsets,
|
||||
&framebuf->fb_id,
|
||||
0);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
RARCH_ERR("drmModeAddFB2 failed.\n");
|
||||
free(framebuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return framebuf;
|
||||
}
|
||||
|
||||
void oga_destroy_framebuf(oga_framebuf_t* framebuf)
|
||||
{
|
||||
if (drmModeRmFB(framebuf->surface->display_fd, framebuf->fb_id) != 0)
|
||||
RARCH_ERR("drmModeRmFB failed.\n");
|
||||
|
||||
oga_destroy_surface(framebuf->surface);
|
||||
free(framebuf);
|
||||
}
|
||||
|
||||
static void oga_gfx_free(void *data)
|
||||
{
|
||||
unsigned i;
|
||||
oga_video_t *vid = (oga_video_t*)data;
|
||||
unsigned i;
|
||||
|
||||
if (!vid)
|
||||
return;
|
||||
@ -91,18 +328,13 @@ static void oga_gfx_free(void *data)
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_PAGES; ++i)
|
||||
{
|
||||
go2_frame_buffer_t* frameBuffer = vid->frameBuffer[i];
|
||||
go2_surface_t* surface = go2_frame_buffer_surface_get(frameBuffer);
|
||||
oga_destroy_framebuf(vid->pages[i]);
|
||||
|
||||
go2_frame_buffer_destroy(frameBuffer);
|
||||
go2_surface_destroy(surface);
|
||||
}
|
||||
oga_destroy_surface(vid->frame_surface);
|
||||
oga_destroy_surface(vid->msg_surface);
|
||||
oga_destroy_surface(vid->menu_surface);
|
||||
|
||||
go2_surface_destroy(vid->frame);
|
||||
go2_surface_destroy(vid->menu_surface);
|
||||
go2_presenter_destroy(vid->presenter);
|
||||
go2_display_destroy(vid->display);
|
||||
close(vid->fd);
|
||||
|
||||
free(vid);
|
||||
vid = NULL;
|
||||
@ -113,7 +345,7 @@ static void *oga_gfx_init(const video_info_t *video,
|
||||
{
|
||||
oga_video_t *vid = NULL;
|
||||
settings_t *settings = config_get_ptr();
|
||||
struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
|
||||
int i;
|
||||
|
||||
frontend_driver_install_signal_handler();
|
||||
|
||||
@ -130,28 +362,41 @@ static void *oga_gfx_init(const video_info_t *video,
|
||||
}
|
||||
|
||||
vid = (oga_video_t*)calloc(1, sizeof(*vid));
|
||||
if (!vid)
|
||||
{
|
||||
RARCH_ERR("Error allocating vid\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vid->menu_frame = NULL;
|
||||
vid->menu_width = 0;
|
||||
vid->menu_height = 0;
|
||||
vid->menu_pitch = 0;
|
||||
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_XRGB8888);
|
||||
vid->font = NULL;
|
||||
vid->font_driver = NULL;
|
||||
if (!oga_create_display(vid))
|
||||
{
|
||||
RARCH_ERR("Error initializing drm\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RARCH_LOG("oga_gfx_init video %dx%d rgb32 %d smooth %d ctx_scaling %d"
|
||||
" input_scale %u force_aspect %d fullscreen %d threaded %d\n",
|
||||
video->width, video->height, video->rgb32, video->smooth, video->ctx_scaling,
|
||||
video->input_scale, video->force_aspect, video->fullscreen, video->is_threaded);
|
||||
|
||||
vid->menu_surface = oga_create_surface(vid->fd, NATIVE_WIDTH, NATIVE_HEIGHT, RK_FORMAT_BGRA_8888);
|
||||
vid->threaded = video->is_threaded;
|
||||
vid->bpp = video->rgb32 ? 4 : 2;
|
||||
|
||||
int aw = MAX(ALIGN(av_info->geometry.max_width, 32), NATIVE_WIDTH);
|
||||
int ah = MAX(ALIGN(av_info->geometry.max_height, 32), NATIVE_HEIGHT);
|
||||
/*
|
||||
* From RGA2 documentation:
|
||||
*
|
||||
* 0 CATROM
|
||||
* 1 MITCHELL
|
||||
* 2 HERMITE
|
||||
* 3 B-SPLINE
|
||||
*/
|
||||
vid->scale_mode = video->ctx_scaling << 1 | video->smooth;
|
||||
vid->rotation = 0;
|
||||
|
||||
RARCH_LOG("oga_gfx_init video %dx%d rgb32 %d smooth %d input_scale %u force_aspect %d"
|
||||
" fullscreen %d aw %d ah %d rgb %d threaded %d\n",
|
||||
video->width, video->height, video->rgb32, video->smooth, video->input_scale,
|
||||
video->force_aspect, video->fullscreen, aw, ah, video->rgb32, video->is_threaded);
|
||||
|
||||
vid->frame = go2_surface_create(vid->display, aw, ah, video->rgb32 ? DRM_FORMAT_XRGB8888 : DRM_FORMAT_RGB565);
|
||||
vid->frame_surface = oga_create_surface(vid->fd, NATIVE_WIDTH, NATIVE_HEIGHT, vid->bpp == 4 ? RK_FORMAT_BGRA_8888 : RK_FORMAT_RGB_565);
|
||||
vid->msg_surface = oga_create_surface(vid->fd, NATIVE_WIDTH, NATIVE_HEIGHT, RK_FORMAT_BGRA_8888);
|
||||
vid->last_msg[0] = 0;
|
||||
|
||||
/* bitmap only for now */
|
||||
if (settings->bools.video_font_enable)
|
||||
@ -160,17 +405,34 @@ static void *oga_gfx_init(const video_info_t *video,
|
||||
vid->font = vid->font_driver->init("", settings->floats.video_font_size);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_PAGES; ++i)
|
||||
for (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);
|
||||
oga_surface_t* surface = oga_create_surface(vid->fd, NATIVE_HEIGHT, NATIVE_WIDTH, RK_FORMAT_BGRA_8888);
|
||||
vid->pages[i] = oga_create_framebuf(surface);
|
||||
if (!vid->pages[i])
|
||||
return NULL;
|
||||
}
|
||||
vid->cur_page = 0;
|
||||
|
||||
return vid;
|
||||
}
|
||||
|
||||
static void rga_clear_surface(oga_surface_t* surface, int color)
|
||||
{
|
||||
rga_info_t dst = { 0 };
|
||||
dst.fd = surface->prime_fd;
|
||||
dst.mmuFlag = 1;
|
||||
dst.rect.xoffset = 0;
|
||||
dst.rect.yoffset = 0;
|
||||
dst.rect.width = surface->width;
|
||||
dst.rect.height = surface->height;
|
||||
dst.rect.wstride = dst.rect.width;
|
||||
dst.rect.hstride = dst.rect.height;
|
||||
dst.rect.format = surface->rk_format;
|
||||
dst.color = color;
|
||||
|
||||
c_RkRgaColorFill(&dst);
|
||||
}
|
||||
|
||||
int get_message_width(oga_video_t* vid, const char* msg)
|
||||
{
|
||||
int width = 0;
|
||||
@ -185,50 +447,104 @@ int get_message_width(oga_video_t* vid, const char* msg)
|
||||
return width;
|
||||
}
|
||||
|
||||
static void render_msg(oga_video_t* vid,
|
||||
go2_surface_t* surface, const char* msg, int width, int bpp)
|
||||
static bool render_msg(oga_video_t* vid, const char* msg)
|
||||
{
|
||||
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 - msg_width);
|
||||
int dest_stride = go2_surface_stride_get(surface);
|
||||
const char *c = msg;
|
||||
const struct font_atlas* atlas;
|
||||
uint32_t* fb;
|
||||
const char *c = msg;
|
||||
int dest_x = 0;
|
||||
int dest_y = 0;
|
||||
int dest_stride;
|
||||
|
||||
if (strcmp(msg, vid->last_msg) == 0)
|
||||
return true;
|
||||
|
||||
strncpy(vid->last_msg, c, sizeof(vid->last_msg)-1);
|
||||
rga_clear_surface(vid->msg_surface, 0);
|
||||
|
||||
atlas = vid->font_driver->get_atlas(vid->font);
|
||||
fb = (uint32_t*)vid->msg_surface->map;
|
||||
dest_stride = vid->msg_surface->pitch / 4;
|
||||
vid->msg_width = vid->msg_height = 0;
|
||||
|
||||
while (*c)
|
||||
{
|
||||
const struct font_glyph* g = vid->font_driver->get_glyph(vid->font, *c);
|
||||
|
||||
if (!g)
|
||||
continue;
|
||||
if (dest_x >= width)
|
||||
break;
|
||||
|
||||
if (vid->msg_height == 0)
|
||||
vid->msg_height = g->height;
|
||||
|
||||
if (dest_x >= NATIVE_WIDTH) {
|
||||
dest_x = 0;
|
||||
dest_y += g->height;
|
||||
vid->msg_height += g->height;
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t* dest = fb + dest_y * dest_stride + dest_x;
|
||||
|
||||
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;
|
||||
}
|
||||
uint32_t px = (x < g->width) ? *(source++) : 0x00;
|
||||
*(dest++) = (0xCD << 24) | (px << 16) | (px << 8) | px;
|
||||
}
|
||||
dest += dest_stride - g->advance_x * bpp;
|
||||
dest += dest_stride - g->advance_x;
|
||||
source += atlas->width - g->width;
|
||||
}
|
||||
|
||||
c++;
|
||||
dest_x += g->advance_x;
|
||||
|
||||
if (vid->msg_width < dest_x)
|
||||
vid->msg_width = MIN(dest_x, vid->msg_surface->width);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void oga_blit(oga_surface_t* src, int sx, int sy, int sw, int sh,
|
||||
oga_surface_t* dst, int dx, int dy, int dw, int dh,
|
||||
int rotation, int scale_mode, unsigned int blend)
|
||||
{
|
||||
rga_info_t s = {
|
||||
.fd = src->prime_fd,
|
||||
.rect = { sx, sy, sw, sh, src->width, src->height, src->rk_format },
|
||||
.rotation = rotation,
|
||||
.mmuFlag = 1,
|
||||
.scale_mode = scale_mode,
|
||||
.blend = blend,
|
||||
};
|
||||
|
||||
rga_info_t d = {
|
||||
.fd = dst->prime_fd,
|
||||
.rect = { dx, dy, dw, dh, dst->width, dst->height, dst->rk_format },
|
||||
.mmuFlag = 1,
|
||||
};
|
||||
|
||||
c_RkRgaBlit(&s, &d, NULL);
|
||||
}
|
||||
|
||||
void oga_calc_bounds(oga_rect_t* r, int width, int height, float aspect)
|
||||
{
|
||||
if (NATIVE_ASPECT_RATIO >= aspect)
|
||||
{
|
||||
r->h = NATIVE_HEIGHT;
|
||||
r->w = MIN(NATIVE_WIDTH, (NATIVE_HEIGHT * aspect + 0.5));
|
||||
r->x = (NATIVE_WIDTH - r->w) / 2 + 0.5;
|
||||
r->y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r->w = NATIVE_WIDTH;
|
||||
r->h = MIN(NATIVE_HEIGHT, (NATIVE_WIDTH / aspect + 0.5));
|
||||
r->x = 0;
|
||||
r->y = (NATIVE_HEIGHT - r->h) / 2 + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,93 +552,82 @@ 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)
|
||||
{
|
||||
int out_w, out_h;
|
||||
int yy, stride, dst_stride;
|
||||
int out_x = 0;
|
||||
int out_y = 0;
|
||||
go2_display_t *display = NULL;
|
||||
go2_frame_buffer_t *dstFrameBuffer = NULL;
|
||||
go2_surface_t *dstSurface = NULL;
|
||||
uint8_t *dst = NULL;
|
||||
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;
|
||||
#ifdef HAVE_MENU
|
||||
bool menu_is_alive = video_info->menu_is_alive;
|
||||
#endif
|
||||
bool input_driver_nonblock_state = video_info->input_driver_nonblock_state;
|
||||
oga_video_t *vid = (oga_video_t*)data;
|
||||
oga_framebuf_t* page = vid->pages[vid->cur_page];
|
||||
oga_surface_t *page_surface = page->surface;
|
||||
float aspect_ratio = video_driver_get_aspect_ratio();
|
||||
bool blit_msg = false;
|
||||
|
||||
if (unlikely(!frame || width == 0 || height == 0))
|
||||
return true;
|
||||
|
||||
if (unlikely(input_driver_nonblock_state) && !vid->threaded)
|
||||
if (unlikely(video_info->input_driver_nonblock_state) && !vid->threaded)
|
||||
{
|
||||
if (frame_count % 4 != 0)
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
if (unlikely(menu_is_alive))
|
||||
if (msg && msg[0] && vid->font)
|
||||
blit_msg = render_msg(vid, msg);
|
||||
|
||||
rga_clear_surface(page_surface, 0);
|
||||
|
||||
if (likely(!video_info->menu_is_alive))
|
||||
{
|
||||
if (unlikely(vid->menu_width == 0))
|
||||
return true;
|
||||
menu_driver_frame(menu_is_alive, video_info);
|
||||
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;
|
||||
int w = pitch / vid->bpp;
|
||||
if (unlikely(w != vid->frame_surface->width || height != vid->frame_surface->height))
|
||||
{
|
||||
oga_destroy_surface(vid->frame_surface);
|
||||
vid->frame_surface = oga_create_surface(vid->fd, w, height, vid->bpp == 4 ? RK_FORMAT_BGRA_8888 : RK_FORMAT_RGB_565);
|
||||
}
|
||||
|
||||
memcpy(vid->frame_surface->map, frame, pitch * height);
|
||||
|
||||
oga_rect_t r;
|
||||
oga_calc_bounds(&r, width, height, aspect_ratio);
|
||||
|
||||
unsigned int blend = video_info->runloop_is_paused ? 0x800105 : 0;
|
||||
|
||||
oga_blit(vid->frame_surface, 0, 0, width, height,
|
||||
page_surface, r.y, r.x, r.h, r.w, vid->rotation, vid->scale_mode, blend);
|
||||
}
|
||||
#ifdef HAVE_MENU
|
||||
else
|
||||
{
|
||||
menu_driver_frame(true, video_info);
|
||||
|
||||
width = vid->menu_surface->width;
|
||||
height = vid->menu_surface->height;
|
||||
|
||||
aspect_ratio = (float)width / height;
|
||||
|
||||
oga_rect_t r;
|
||||
oga_calc_bounds(&r, width, height, aspect_ratio);
|
||||
oga_blit(vid->menu_surface, 0, 0, width, height,
|
||||
page_surface, r.y, r.x, r.h, r.w, HAL_TRANSFORM_ROT_270, vid->scale_mode, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* copy buffer to surface */
|
||||
dst = (uint8_t*)go2_surface_map(dst_surface);
|
||||
yy = height;
|
||||
stride = width * bpp;
|
||||
dst_stride = go2_surface_stride_get(dst_surface);
|
||||
|
||||
while (yy > 0)
|
||||
if (blit_msg)
|
||||
{
|
||||
memcpy(dst, src, stride);
|
||||
src += pitch;
|
||||
dst += dst_stride;
|
||||
--yy;
|
||||
oga_blit(vid->msg_surface, 0, 0, vid->msg_width, vid->msg_height,
|
||||
page_surface, 0, 0, vid->msg_height, vid->msg_width,
|
||||
HAL_TRANSFORM_ROT_270, vid->scale_mode, 0xff0105);
|
||||
}
|
||||
|
||||
out_w = NATIVE_WIDTH;
|
||||
out_h = NATIVE_HEIGHT;
|
||||
if (unlikely(drmModeSetCrtc(vid->fd, vid->crtc_id, page->fb_id, 0, 0, &vid->connector_id, 1, &vid->mode) != 0))
|
||||
RARCH_ERR("drmModeSetCrtc failed.\n");
|
||||
|
||||
if ((out_w != width || out_h != height))
|
||||
{
|
||||
out_w = MIN(out_h * video_driver_get_aspect_ratio() + 0.5, NATIVE_WIDTH);
|
||||
out_x = MAX((NATIVE_WIDTH - out_w) / 2, 0);
|
||||
}
|
||||
|
||||
if (msg && vid->font)
|
||||
render_msg(vid, dst_surface, msg, width, bpp);
|
||||
|
||||
dstFrameBuffer = vid->frameBuffer[vid->cur_page];
|
||||
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,
|
||||
!menu_is_alive ? oga_rotation : GO2_ROTATION_DEGREES_270, 2);
|
||||
|
||||
display = go2_presenter_display_get(vid->presenter);
|
||||
go2_display_present(display, dstFrameBuffer);
|
||||
vid->cur_page = !vid->cur_page;
|
||||
vid->cur_page = (vid->cur_page + 1) % NUM_PAGES;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void oga_set_texture_frame(void *data, const void *frame, bool rgb32,
|
||||
static void oga_gfx_set_texture_frame(void *data, const void *frame, bool rgb32,
|
||||
unsigned width, unsigned height, float alpha)
|
||||
{
|
||||
unsigned i, j;
|
||||
oga_video_t *vid = (oga_video_t*)data;
|
||||
unsigned i, j;
|
||||
/* Borrowed from drm_gfx
|
||||
*
|
||||
* We have to go on a pixel format conversion adventure
|
||||
@ -332,16 +637,19 @@ static void oga_set_texture_frame(void *data, const void *frame, bool rgb32,
|
||||
unsigned int dst_pitch = width * 4;
|
||||
unsigned int dst_width = width;
|
||||
uint32_t line[dst_width];
|
||||
char *frame_output;
|
||||
|
||||
if (vid->menu_surface->width != width || vid->menu_surface->height != height)
|
||||
{
|
||||
// RARCH_LOG("oga_set_texture_frame rgb32 %d width %hu height %hu alpha %f\n",
|
||||
// rgb32, width, height, alpha);
|
||||
|
||||
oga_destroy_surface(vid->menu_surface);
|
||||
vid->menu_surface = oga_create_surface(vid->fd, width, height, RK_FORMAT_BGRA_8888);
|
||||
}
|
||||
|
||||
/* The output pixel array with the converted pixels. */
|
||||
char *frame_output = vid->menu_buf;
|
||||
|
||||
/* Remember, memcpy() works with 8bits pointers for increments. */
|
||||
char *dst_base_addr = frame_output;
|
||||
|
||||
vid->menu_width = width;
|
||||
vid->menu_height = height;
|
||||
vid->menu_pitch = width * 4;
|
||||
frame_output = (char*)vid->menu_surface->map;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
@ -353,20 +661,24 @@ static void oga_set_texture_frame(void *data, const void *frame, bool rgb32,
|
||||
uint32_t R = (src_pix << 8) & 0x00FF0000;
|
||||
uint32_t G = (src_pix << 4) & 0x0000FF00;
|
||||
uint32_t B = (src_pix << 0) & 0x000000FF;
|
||||
line[j] = (0 | R | G | B);
|
||||
line[j] = (0x00 | R | G | B);
|
||||
}
|
||||
memcpy(dst_base_addr + (dst_pitch * i), (char*)line, dst_pitch);
|
||||
memcpy(frame_output + (dst_pitch * i), (char*)line, dst_pitch);
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!vid->menu_frame))
|
||||
vid->menu_frame = frame_output;
|
||||
static void oga_gfx_texture_enable(void *data, bool state, bool full_screen)
|
||||
{
|
||||
(void)data;
|
||||
(void)state;
|
||||
(void)full_screen;
|
||||
}
|
||||
|
||||
static void oga_gfx_set_nonblock_state(void *a, bool b, bool c, unsigned d) { }
|
||||
|
||||
static bool oga_gfx_alive(void *data)
|
||||
{
|
||||
return !frontend_driver_get_signal_handler_state();
|
||||
return !frontend_driver_get_signal_handler_state();
|
||||
}
|
||||
|
||||
static bool oga_gfx_focus(void *data) { return true; }
|
||||
@ -376,12 +688,47 @@ static bool oga_gfx_has_windowed(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 = NATIVE_WIDTH;
|
||||
vp->full_width = NATIVE_WIDTH;
|
||||
vp->height = NATIVE_HEIGHT;
|
||||
vp->full_height = NATIVE_HEIGHT;
|
||||
if (unlikely(!vid))
|
||||
return;
|
||||
|
||||
vp->x = vp->y = 0;
|
||||
vp->width = vp->full_width = NATIVE_WIDTH;
|
||||
vp->height = vp->full_height = NATIVE_HEIGHT;
|
||||
}
|
||||
|
||||
static bool oga_gfx_set_shader(void *data, enum rarch_shader_type type, const char *path)
|
||||
{
|
||||
(void)data;
|
||||
(void)type;
|
||||
(void)path;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void oga_set_rotation(void *data, unsigned rotation)
|
||||
{
|
||||
oga_video_t *vid = (oga_video_t*)data;
|
||||
if (!vid)
|
||||
return;
|
||||
|
||||
switch (rotation)
|
||||
{
|
||||
case 0:
|
||||
vid->rotation = HAL_TRANSFORM_ROT_270;
|
||||
break;
|
||||
case 1:
|
||||
vid->rotation = HAL_TRANSFORM_ROT_180;
|
||||
break;
|
||||
case 2:
|
||||
vid->rotation = HAL_TRANSFORM_ROT_90;
|
||||
break;
|
||||
case 3:
|
||||
vid->rotation = 0;
|
||||
break;
|
||||
default:
|
||||
RARCH_ERR("Unhandled rotation %hu\n", rotation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const video_poke_interface_t oga_poke_interface = {
|
||||
@ -398,8 +745,8 @@ static const video_poke_interface_t oga_poke_interface = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
oga_set_texture_frame,
|
||||
NULL,
|
||||
oga_gfx_set_texture_frame,
|
||||
oga_gfx_texture_enable,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
@ -408,31 +755,7 @@ static const video_poke_interface_t oga_poke_interface = {
|
||||
NULL
|
||||
};
|
||||
|
||||
void oga_set_rotation(void *data, unsigned rotation)
|
||||
{
|
||||
/* called before init? */
|
||||
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)
|
||||
static void oga_get_poke_interface(void *data, const video_poke_interface_t **iface)
|
||||
{
|
||||
*iface = &oga_poke_interface;
|
||||
}
|
||||
@ -445,7 +768,7 @@ video_driver_t video_oga = {
|
||||
oga_gfx_focus,
|
||||
oga_gfx_suppress_screensaver,
|
||||
oga_gfx_has_windowed,
|
||||
NULL,
|
||||
oga_gfx_set_shader,
|
||||
oga_gfx_free,
|
||||
"oga",
|
||||
NULL,
|
||||
|
Loading…
x
Reference in New Issue
Block a user