diff --git a/gfx/drivers/oga_gfx.c b/gfx/drivers/oga_gfx.c index 920626db3a..c5edb4ae7c 100644 --- a/gfx/drivers/oga_gfx.c +++ b/gfx/drivers/oga_gfx.c @@ -17,10 +17,12 @@ #include #include +#include -#include -#include #include "../../verbosity.h" +#include +#include +#include #include #include #include @@ -40,46 +42,281 @@ #include "../../configuration.h" #include "../../retroarch.h" -#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 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,