/* RetroArch - A frontend for libretro. * Copyright (C) 2013-2014 - Tobias Jakobi * Copyright (C) 2013-2014 - Daniel Mehrwald * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- * ation, either version 3 of the License, or (at your option) any later version. * * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with RetroArch. * If not, see . */ #include #include #include #include #include "../general.h" #include "gfx_common.h" #include "fonts/fonts.h" /* Rename to LIMA_GFX_DEBUG to enable debugging code. */ #define NO_LIMA_GFX_DEBUG 1 /* Current limare only natively supports a limited amount of formats for texture * * data. We compensate for this limitation by swizzling the texture data in the * * pixel shader. */ #define LIMA_TEXEL_FORMAT_BGR_565 0x0e #define LIMA_TEXEL_FORMAT_RGBA_5551 0x0f #define LIMA_TEXEL_FORMAT_RGBA_4444 0x10 #define LIMA_TEXEL_FORMAT_RGBA_8888 0x16 /* Limare is currently unable to deallocate individual texture objects and * * only allows to destroy all objects at once. * * We only create a maximum of 12 objects, before doing a full "reset", or * * sooner, under the condition that limare's texture memory runs out. */ static const unsigned num_max_textures = 12; typedef struct limare_state limare_state_t; typedef struct limare_texture { unsigned width; unsigned height; int handle; unsigned format; bool rgui; } limare_texture_t; typedef struct vec2f { float x, y; } vec2f_t; typedef struct vec3f { float x, y, z; } vec3f_t; /* Create three shader programs. One is for displaying only the emulator core pixel data. * * The other two are for displaying the RGUI, where the pixel data can be provided in * * two different formats. Current RetroArch only seems to ever use a single format, but * * this is not set in stone, therefore making two programs necessary. */ typedef struct limare_data { limare_state_t *state; int program; int program_rgui_rgba16; int program_rgui_rgba32; float screen_aspect; float frame_aspect; unsigned upload_format; unsigned upload_bpp; /* bytes per pixel */ vec3f_t *vertices; vec2f_t *coords; /* Generic buffer to create contiguous pixel data for limare * or to use for font blitting. */ void *buffer; unsigned buffer_size; limare_texture_t **textures; unsigned texture_slots; limare_texture_t *cur_texture; limare_texture_t *cur_texture_rgui; unsigned font_width; unsigned font_height; limare_texture_t *font_texture; } limare_data_t; /* Header for simple vertex shader. */ static const char *vshader_src = "attribute vec4 in_vertex;\n" "attribute vec2 in_coord;\n" "\n" "varying vec2 coord;\n" "\n" "void main()\n" "{\n" " gl_Position = in_vertex;\n" " coord = in_coord;\n" "}\n"; /* Header for simple fragment shader. */ static const char *fshader_header_src = "precision highp float;\n" "\n" "varying vec2 coord;\n" "\n" "uniform sampler2D in_texture;\n" "\n"; /* Main (template) for simple fragment shader. */ static const char *fshader_main_src = "void main()\n" "{\n" " vec3 pixel = texture2D(in_texture, coord)%s;\n" " gl_FragColor = vec4(pixel, 1.0);\n" "}\n"; /* Header for RGUI fragment shader. */ /* Use mediump, which makes uColor into a (single-precision) float[4]. */ static const char *fshader_rgui_header_src = "precision mediump float;\n" "\n" "varying vec2 coord;\n" "uniform vec4 uColor;\n" "\n" "uniform sampler2D in_texture;\n" "\n"; /* Main (template) for RGUI fragment shader. */ static const char *fshader_rgui_main_src = "void main()\n" "{\n" " vec4 pixel = texture2D(in_texture, coord)%s;\n" " gl_FragColor = pixel * uColor;\n" "}\n"; static inline void put_pixel_rgba4444(uint16_t *p, unsigned r, unsigned g, unsigned b, unsigned a) { *p = (a >> 4) | ((b >> 4) << 4) | ((g >> 4) << 8) | ((r >> 4) << 12); } static inline unsigned align_common(unsigned i, unsigned j) { return (i + j - 1) & ~(j - 1); } static float get_screen_aspect(limare_state_t *state) { unsigned w = 0, h = 0; limare_buffer_size(state, &w, &h); if (w != 0 && h != 0) { return (float)w / (float)h; } return 0.0f; } static void apply_aspect(limare_data_t *pdata, float ratio) { vec3f_t *vertices = pdata->vertices; float x, y; if (fabsf(pdata->screen_aspect - pdata->frame_aspect) < 0.0001f) { x = 1.0f; y = 1.0f; } else { if (pdata->screen_aspect > pdata->frame_aspect) { x = pdata->frame_aspect / pdata->screen_aspect; y = 1.0f; } else { x = 1.0f; y = pdata->screen_aspect / pdata->frame_aspect; } } /* TODO: use ratio parameter */ vertices[0].x = vertices[2].x = -x; vertices[1].x = vertices[3].x = x; vertices[0].y = vertices[1].y = -y; vertices[2].y = vertices[3].y = y; } static int destroy_textures(limare_data_t *pdata) { unsigned i; int ret; pdata->cur_texture = NULL; pdata->cur_texture_rgui = NULL; for (i = 0; i < pdata->texture_slots; ++i) { free(pdata->textures[i]); pdata->textures[i] = NULL; } ret = limare_texture_cleanup(pdata->state); pdata->texture_slots = 0; return ret; } static limare_texture_t *get_texture_handle(limare_data_t *pdata, unsigned width, unsigned height, unsigned format) { unsigned i; format = (format == 0) ? pdata->upload_format : format; for (i = 0; i < pdata->texture_slots; ++i) { if (pdata->textures[i]->width == width && pdata->textures[i]->height == height && pdata->textures[i]->format == format) return pdata->textures[i]; } if (pdata->texture_slots == num_max_textures) { /* All texture slots are used, do a reset. */ if (destroy_textures(pdata)) { RARCH_ERR("video_lima: failed to reset texture storage\n"); } } return NULL; } static limare_texture_t *add_texture(limare_data_t *pdata, unsigned width, unsigned height, const void *pixels, unsigned format) { int texture = -1; unsigned retries = 2; const unsigned i = pdata->texture_slots; format = (format == 0) ? pdata->upload_format : format; /* limare_texture_upload returns -1 when the upload fails for some reason. */ while (texture == -1 && retries > 0) { texture = limare_texture_upload(pdata->state, pixels, width, height, format, 0); if (texture != -1) break; destroy_textures(pdata); retries--; } if (texture == -1) return NULL; /* Set magnification to linear and minification to nearest, since we will * * probably only ever scale the image to larger dimensions. Also set * * wrap mode for both coords to clamp, which should eliminate some artifacts. */ limare_texture_parameters(pdata->state, texture, GL_LINEAR, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE); pdata->textures[i] = calloc(1, sizeof(limare_texture_t)); pdata->textures[i]->width = width; pdata->textures[i]->height = height; pdata->textures[i]->handle = texture; pdata->textures[i]->format = format; pdata->texture_slots++; return pdata->textures[i]; } static const void *make_contiguous(limare_data_t *pdata, unsigned width, unsigned height, const void *pixels, unsigned bpp, unsigned pitch) { unsigned i; unsigned full_pitch; bpp = (bpp == 0) ? pdata->upload_bpp : bpp; full_pitch = width * bpp; if (full_pitch == pitch) return pixels; RARCH_LOG("video_lima: input buffer not contiguous\n"); /* Enlarge our buffer, if it is currently too small. */ if (pdata->buffer_size < full_pitch * height) { const unsigned aligned_size = align_common(full_pitch * height, 16); free(pdata->buffer); pdata->buffer = NULL; posix_memalign(&pdata->buffer, 16, aligned_size); if (pdata->buffer == NULL) { RARCH_ERR("video_lima: failed to allocate buffer to make pixel data contiguous\n"); return NULL; } pdata->buffer_size = aligned_size; } for (i = 0; i < height; ++i) { memcpy(pdata->buffer + i * full_pitch, pixels + i * pitch, full_pitch); } return pdata->buffer; } #ifdef LIMA_GFX_DEBUG static void print_status(limare_data_t *pdata) { unsigned i; RARCH_LOG("video_lima: upload format = 0x%x, upload bpp = %u\n", pdata->upload_format, pdata->upload_bpp); RARCH_LOG("video_lima: buffer at %p, buffer size = %u\n", pdata->buffer, pdata->buffer_size); RARCH_LOG("video_lima: used texture slots = %u (from %u)\n", pdata->texture_slots, num_max_textures); for (i = 0; i < pdata->texture_slots; ++i) { RARCH_LOG("video_lima: texture slot %u, width = %u, height = %u, handle = %u, format = 0x%x\n", i, pdata->textures[i]->width, pdata->textures[i]->height, pdata->textures[i]->handle, pdata->textures[i]->format); } } #endif static void destroy_data(limare_data_t *pdata) { free(pdata->vertices); free(pdata->coords); } static int setup_data(limare_data_t *pdata) { static const unsigned num_verts = 4; static const unsigned num_coords = 4 * 4; unsigned i; static const vec3f_t vertices[4] = { {-1.0f, -1.0f, 0.0f}, { 1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, { 1.0f, 1.0f, 0.0f} }; static const vec2f_t coords[16] = { {0.0f, 1.0f}, {1.0f, 1.0f}, /* 0 degrees */ {0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 1.0f}, /* 90 degrees */ {1.0f, 0.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f}, /* 180 degrees */ {1.0f, 1.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}, /* 270 degrees */ {0.0f, 1.0f}, {0.0f, 0.0f} }; pdata->vertices = calloc(num_verts, sizeof(vec3f_t)); if (pdata->vertices == NULL) goto fail; pdata->coords = calloc(num_coords, sizeof(vec2f_t)); if (pdata->coords == NULL) goto fail; for (i = 0; i < num_verts; ++i) { pdata->vertices[i] = vertices[i]; } for (i = 0; i < num_coords; ++i) { pdata->coords[i] = coords[i]; } return 0; fail: return -1; } static int create_programs(limare_data_t *pdata) { char tmpbufm[1024]; /* temp buffer for main function */ char tmpbuf[1024]; /* temp buffer for whole program */ const char* swz = (pdata->upload_bpp == 4) ? ".bgr" : ".rgb"; /* Create shader program for regular operation first. */ pdata->program = limare_program_new(pdata->state); if (pdata->program < 0) goto fail; snprintf(tmpbufm, 1024, fshader_main_src, swz); strncpy(tmpbuf, fshader_header_src, 1024); strcat(tmpbuf, tmpbufm); if (vertex_shader_attach(pdata->state, pdata->program, vshader_src)) goto fail; if (fragment_shader_attach(pdata->state, pdata->program, tmpbuf)) goto fail; if (limare_link(pdata->state)) goto fail; /* Create shader program for RGUI with RGBA4444 pixel data. */ pdata->program_rgui_rgba16 = limare_program_new(pdata->state); if (pdata->program_rgui_rgba16 < 0) goto fail; snprintf(tmpbufm, 1024, fshader_rgui_main_src, ".abgr"); strncpy(tmpbuf, fshader_rgui_header_src, 1024); strcat(tmpbuf, tmpbufm); if (vertex_shader_attach(pdata->state, pdata->program_rgui_rgba16, vshader_src)) goto fail; if (fragment_shader_attach(pdata->state, pdata->program_rgui_rgba16, tmpbuf)) goto fail; if (limare_link(pdata->state)) goto fail; /* Create shader program for RGUI with RGBA8888 pixel data. */ pdata->program_rgui_rgba32 = limare_program_new(pdata->state); if (pdata->program_rgui_rgba32 < 0) goto fail; snprintf(tmpbufm, 1024, fshader_rgui_main_src, ".abgr"); strncpy(tmpbuf, fshader_rgui_header_src, 1024); strcat(tmpbuf, tmpbufm); if (vertex_shader_attach(pdata->state, pdata->program_rgui_rgba32, vshader_src)) goto fail; if (fragment_shader_attach(pdata->state, pdata->program_rgui_rgba32, tmpbuf)) goto fail; if (limare_link(pdata->state)) goto fail; return 0; fail: return -1; } static void put_glyph_rgba4444(limare_data_t *pdata, const uint8_t *src, uint8_t *f_rgb, unsigned g_width, unsigned g_height, unsigned g_pitch, unsigned dst_x, unsigned dst_y) { unsigned x, y; uint16_t *dst; dst = (uint16_t*)pdata->buffer + dst_y * pdata->font_width + dst_x; for (y = 0; y < g_height; ++y, src += g_pitch, dst += pdata->font_width) { for (x = 0; x < g_width; ++x) { const uint8_t blend = src[x]; if (blend != 0) put_pixel_rgba4444(&dst[x], f_rgb[0], f_rgb[1], f_rgb[2], blend); } } } typedef struct lima_video { limare_data_t *lima; void *font; const font_renderer_driver_t *font_driver; uint8_t font_rgb[4]; /* current dimensions */ unsigned width; unsigned height; /* RGUI data */ int rgui_rotation; float rgui_alpha; bool rgui_active; bool rgui_rgb32; bool aspect_changed; } lima_video_t; static void lima_gfx_free(void *data) { lima_video_t *vid = data; if (!vid) return; if (vid->lima && vid->lima->state) limare_finish(vid->lima->state); if (vid->font) vid->font_driver->free(vid->font); destroy_data(vid->lima); destroy_textures(vid->lima); free(vid->lima->textures); free(vid->lima); free(vid); } static void lima_init_font(lima_video_t *vid, const char *font_path, unsigned font_size) { if (!g_settings.video.font_enable) return; if (font_renderer_create_default(&vid->font_driver, &vid->font)) { int r = g_settings.video.msg_color_r * 255; int g = g_settings.video.msg_color_g * 255; int b = g_settings.video.msg_color_b * 255; vid->font_rgb[0] = r < 0 ? 0 : (r > 255 ? 255 : r); vid->font_rgb[1] = g < 0 ? 0 : (g > 255 ? 255 : g); vid->font_rgb[2] = b < 0 ? 0 : (b > 255 ? 255 : b); } else { RARCH_LOG("video_lima: font init failed\n"); } } static void lima_render_msg(lima_video_t *vid, const char *msg) { struct font_output_list out; struct font_output *head; unsigned req_size; limare_data_t *lima = vid->lima; const int msg_base_x = g_settings.video.msg_pos_x * lima->font_width; const int msg_base_y = (1.0 - g_settings.video.msg_pos_y) * lima->font_height; if (vid->font == NULL) return; /* Font texture uses RGBA4444 pixel data (2 bytes per pixel). */ req_size = lima->font_width * lima->font_height * 2; if (lima->buffer_size < req_size) { const unsigned aligned_size = align_common(req_size, 16); free(lima->buffer); lima->buffer = NULL; posix_memalign(&lima->buffer, 16, aligned_size); if (lima->buffer == NULL) { RARCH_ERR("video_lima: failed to allocate buffer to render fonts\n"); return; } lima->buffer_size = aligned_size; } memset(lima->buffer, 0, req_size); vid->font_driver->render_msg(vid->font, msg, &out); for (head = out.head; head; head = head->next) { int base_x = msg_base_x + head->off_x; int base_y = msg_base_y - head->off_y - head->height; const int max_width = lima->font_width - base_x; const int max_height = lima->font_height - base_y; int glyph_width = head->width; int glyph_height = head->height; const uint8_t *src = head->output; if (base_x < 0) { src -= base_x; glyph_width += base_x; base_x = 0; } if (base_y < 0) { src -= base_y * (int)head->pitch; glyph_height += base_y; base_y = 0; } if (max_width <= 0 || max_height <= 0) continue; if (glyph_width > max_width) glyph_width = max_width; if (glyph_height > max_height) glyph_height = max_height; put_glyph_rgba4444(lima, src, vid->font_rgb, glyph_width, glyph_height, head->pitch, base_x, base_y); } vid->font_driver->free_output(vid->font, &out); } static void *lima_gfx_init(const video_info_t *video, const input_driver_t **input, void **input_data) { lima_video_t *vid = NULL; limare_data_t *lima = NULL; void *lima_input = NULL; struct limare_windowsys_drm limare_config = { 0 }; vid = calloc(1, sizeof(lima_video_t)); if (!vid) return NULL; vid->rgui_alpha = 1.0f; lima = calloc(1, sizeof(limare_data_t)); if (!lima) goto fail; /* Request the Exynos DRM backend for rendering. */ limare_config.type = LIMARE_WINDOWSYS_DRM; limare_config.connector_index = g_settings.video.monitor_index; lima->state = limare_init(&limare_config); if (!lima->state) { RARCH_ERR("video_lima: limare initialization failed\n"); goto fail; } limare_buffer_clear(lima->state); if (limare_state_setup(lima->state, g_settings.video.fullscreen_x, g_settings.video.fullscreen_y, 0xff000000)) { RARCH_ERR("video_lima: limare state setup failed\n"); goto fail_lima; } lima->screen_aspect = get_screen_aspect(lima->state); lima->font_height = 368; lima->font_width = align_common((unsigned)(lima->screen_aspect * (float)lima->font_height), 16); lima->upload_format = video->rgb32 ? LIMA_TEXEL_FORMAT_RGBA_8888 : LIMA_TEXEL_FORMAT_BGR_565; lima->upload_bpp = video->rgb32 ? 4 : 2; limare_enable(lima->state, GL_DEPTH_TEST); limare_depth_func(lima->state, GL_ALWAYS); limare_depth_mask(lima->state, GL_TRUE); limare_enable(lima->state, GL_CULL_FACE); limare_blend_func(lima->state, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if (setup_data(lima)) { RARCH_ERR("video_lima: data setup failed\n"); goto fail_lima; } if (create_programs(lima)) { RARCH_ERR("video_lima: creating shader programs failed\n"); goto fail_lima; } lima->textures = calloc(num_max_textures, sizeof(limare_texture_t*)); if (input && input_data) { *input = NULL; *input_data = NULL; } vid->lima = lima; lima_init_font(vid, g_settings.video.font_path, g_settings.video.font_size); return vid; fail_lima: limare_finish(lima->state); fail: free(lima); free(vid); return NULL; } static bool lima_gfx_frame(void *data, const void *frame, unsigned width, unsigned height, unsigned pitch, const char *msg) { lima_video_t *vid; const void *pixels; limare_data_t *lima; bool upload_frame = true; vid = data; /* Check if neither RGUI nor emulator framebuffer is to be displayed. */ if (!vid->rgui_active && frame == NULL) return true; lima = vid->lima; if (frame != NULL) { /* Handle resolution changes from the emulation core. */ if (width != vid->width || height != vid->height) { limare_texture_t *tex; if (width == 0 || height == 0) return true; RARCH_LOG("video_lima: resolution was changed by core to %ux%u\n", width, height); tex = get_texture_handle(lima, width, height, 0); if (tex == NULL) { pixels = make_contiguous(lima, width, height, frame, 0, pitch); tex = add_texture(lima, width, height, pixels, 0); if (tex == NULL) { RARCH_ERR("video_lima: failed to allocate new texture with dimensions %ux%u\n", width, height); return false; } upload_frame = false; /* pixel data already got uploaded during texture allocation */ } lima->cur_texture = tex; vid->width = width; vid->height = height; lima->frame_aspect = (float)width / (float)height; vid->aspect_changed = true; } if (upload_frame) { pixels = make_contiguous(lima, width, height, frame, 0, pitch); limare_texture_mipmap_upload(lima->state, lima->cur_texture->handle, 0, pixels); } } if (g_settings.fps_show) { char buffer[128], buffer_fps[128]; gfx_get_fps(buffer, sizeof(buffer), g_settings.fps_show ? buffer_fps : NULL, sizeof(buffer_fps)); msg_queue_push(g_extern.msg_queue, buffer_fps, 1, 1); } if (vid->aspect_changed) { apply_aspect(lima, g_extern.system.aspect_ratio); vid->aspect_changed = false; } limare_frame_new(lima->state); if (lima->cur_texture != NULL) { limare_program_current(lima->state, lima->program); limare_attribute_pointer(lima->state, "in_vertex", LIMARE_ATTRIB_FLOAT, 3, 0, 4, lima->vertices); limare_attribute_pointer(lima->state, "in_coord", LIMARE_ATTRIB_FLOAT, 2, 0, 4, lima->coords + vid->rgui_rotation * 4); limare_texture_attach(lima->state, "in_texture", lima->cur_texture->handle); if (limare_draw_arrays(lima->state, GL_TRIANGLE_STRIP, 0, 4)) return false; } /* Handle font rendering. */ if (msg) { bool upload_font = true; /* Both font_vertices and font_color are constant, but we can't make them * * const, since limare_attribute_pointer expects (non-const) void pointers. */ static vec3f_t font_vertices[4] = { {-1.0f, -1.0f, 0.0f}, { 1.0f, -1.0f, 0.0f}, {-1.0f, 1.0f, 0.0f}, { 1.0f, 1.0f, 0.0f} }; static float font_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; lima_render_msg(vid, msg); if (lima->font_texture == NULL) { lima->font_texture = add_texture(lima, lima->font_width, lima->font_height, lima->buffer, LIMA_TEXEL_FORMAT_RGBA_4444); upload_font = false; } if (upload_font) limare_texture_mipmap_upload(lima->state, lima->font_texture->handle, 0, lima->buffer); /* We re-use the RGBA16 RGUI program here. */ limare_program_current(lima->state, lima->program_rgui_rgba16); limare_attribute_pointer(lima->state, "in_vertex", LIMARE_ATTRIB_FLOAT, 3, 0, 4, font_vertices); limare_attribute_pointer(lima->state, "in_coord", LIMARE_ATTRIB_FLOAT, 2, 0, 4, lima->coords + vid->rgui_rotation * 4); limare_texture_attach(lima->state, "in_texture", lima->font_texture->handle); limare_uniform_attach(lima->state, "uColor", 4, font_color); limare_enable(lima->state, GL_BLEND); if (limare_draw_arrays(lima->state, GL_TRIANGLE_STRIP, 0, 4)) return false; limare_disable(lima->state, GL_BLEND); } if (vid->rgui_active && lima->cur_texture_rgui != NULL) { float color[4] = {1.0f, 1.0f, 1.0f, vid->rgui_alpha}; if (vid->rgui_rgb32) limare_program_current(lima->state, lima->program_rgui_rgba32); else limare_program_current(lima->state, lima->program_rgui_rgba16); limare_attribute_pointer(lima->state, "in_vertex", LIMARE_ATTRIB_FLOAT, 3, 0, 4, lima->vertices); limare_attribute_pointer(lima->state, "in_coord", LIMARE_ATTRIB_FLOAT, 2, 0, 4, lima->coords + vid->rgui_rotation * 4); limare_texture_attach(lima->state, "in_texture", lima->cur_texture_rgui->handle); limare_uniform_attach(lima->state, "uColor", 4, color); limare_enable(lima->state, GL_BLEND); if (limare_draw_arrays(lima->state, GL_TRIANGLE_STRIP, 0, 4)) return false; limare_disable(lima->state, GL_BLEND); } if (limare_frame_flush(lima->state)) return false; limare_buffer_swap(lima->state); g_extern.frame_count++; #ifdef LIMA_GFX_DEBUG print_status(lima); #endif return true; } static void lima_gfx_set_nonblock_state(void *data, bool state) { (void)data; /* limare doesn't export vsync control yet */ (void)state; } static bool lima_gfx_alive(void *data) { (void)data; return true; /* always alive */ } static bool lima_gfx_focus(void *data) { (void)data; return true; /* limare doesn't use windowing, so we always have focus */ } static void lima_gfx_set_rotation(void *data, unsigned rotation) { lima_video_t *vid = data; vid->rgui_rotation = rotation; } static void lima_gfx_viewport_info(void *data, struct rarch_viewport *vp) { lima_video_t *vid = data; vp->x = vp->y = 0; vp->width = vp->full_width = vid->width; vp->height = vp->full_height = vid->height; } static void lima_set_aspect_ratio(void *data, unsigned aspect_ratio_idx) { lima_video_t *vid = data; switch (aspect_ratio_idx) { case ASPECT_RATIO_SQUARE: gfx_set_square_pixel_viewport(g_extern.system.av_info.geometry.base_width, g_extern.system.av_info.geometry.base_height); break; case ASPECT_RATIO_CORE: gfx_set_core_viewport(); break; case ASPECT_RATIO_CONFIG: gfx_set_config_viewport(); break; default: break; } g_extern.system.aspect_ratio = aspectratio_lut[aspect_ratio_idx].value; vid->aspect_changed = true; } static void lima_apply_state_changes(void *data) { (void)data; } static void lima_set_texture_frame(void *data, const void *frame, bool rgb32, unsigned width, unsigned height, float alpha) { lima_video_t *vid = data; limare_texture_t* tex; const unsigned format = rgb32 ? LIMA_TEXEL_FORMAT_RGBA_8888 : LIMA_TEXEL_FORMAT_RGBA_4444; vid->rgui_rgb32 = rgb32; vid->rgui_alpha = alpha; tex = vid->lima->cur_texture_rgui; /* Current RGUI doesn't change dimensions, so we should hit this most of the time. */ if (tex != NULL && tex->width == width && tex->height == height && tex->format == format) goto upload; if (tex == NULL) { tex = get_texture_handle(vid->lima, width, height, format); if (tex == NULL) { tex = add_texture(vid->lima, width, height, frame, format); if (tex != NULL) { vid->lima->cur_texture_rgui = tex; goto upload; } RARCH_ERR("video_lima: failed to allocate new RGUI texture with dimensions %ux%u\n", width, height); } } return; upload: limare_texture_mipmap_upload(vid->lima->state, tex->handle, 0, frame); } static void lima_set_texture_enable(void *data, bool state, bool full_screen) { lima_video_t *vid = data; vid->rgui_active = state; } static void lima_set_osd_msg(void *data, const char *msg, void *userdata) { lima_video_t *vid = data; /* TODO: what does this do? */ (void)msg; (void)userdata; } static void lima_show_mouse(void *data, bool state) { (void)data; } static const video_poke_interface_t lima_poke_interface = { NULL, /* set_filtering */ #ifdef HAVE_FBO NULL, /* get_current_framebuffer */ NULL, /* get_proc_address */ #endif lima_set_aspect_ratio, lima_apply_state_changes, #if defined(HAVE_RGUI) || defined(HAVE_RMENU) /* TODO: only HAVE_MENU i think */ lima_set_texture_frame, lima_set_texture_enable, #endif lima_set_osd_msg, lima_show_mouse }; static void lima_gfx_get_poke_interface(void *data, const video_poke_interface_t **iface) { (void)data; *iface = &lima_poke_interface; } const video_driver_t video_lima = { lima_gfx_init, lima_gfx_frame, lima_gfx_set_nonblock_state, lima_gfx_alive, lima_gfx_focus, NULL, /* set_shader */ lima_gfx_free, "lima", #ifdef HAVE_MENU NULL, /* restart */ #endif lima_gfx_set_rotation, lima_gfx_viewport_info, NULL, /* read_viewport */ #ifdef HAVE_OVERLAY NULL, /* overlay_interface */ #endif lima_gfx_get_poke_interface };