2015-04-01 22:14:13 +01:00
|
|
|
/* RetroArch - A frontend for libretro.
|
2017-01-22 13:40:32 +01:00
|
|
|
* Copyright (C) 2014-2017 - Ali Bouhlel
|
2015-04-01 22:14:13 +01:00
|
|
|
*
|
|
|
|
* 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 <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <malloc.h>
|
2015-11-22 13:32:46 +01:00
|
|
|
|
|
|
|
#include <3ds.h>
|
|
|
|
|
|
|
|
#include <retro_inline.h>
|
2017-06-28 04:41:38 +02:00
|
|
|
#include <retro_math.h>
|
2016-09-29 20:14:12 +01:00
|
|
|
#include <formats/image.h>
|
2015-11-22 13:32:46 +01:00
|
|
|
|
2016-09-11 14:46:53 +02:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "../../config.h"
|
|
|
|
#endif
|
|
|
|
|
2017-01-18 22:20:47 +01:00
|
|
|
#ifdef HAVE_MENU
|
|
|
|
#include "../../menu/menu_driver.h"
|
|
|
|
#endif
|
2021-03-23 22:03:44 +01:00
|
|
|
#ifdef HAVE_GFX_WIDGETS
|
|
|
|
#include "../gfx_widgets.h"
|
|
|
|
#endif
|
2017-01-18 22:20:47 +01:00
|
|
|
|
2017-01-19 17:17:20 +01:00
|
|
|
#include "../font_driver.h"
|
2016-09-28 18:09:17 +01:00
|
|
|
#include "../../ctr/gpu_old.h"
|
2015-04-05 20:40:35 +01:00
|
|
|
#include "ctr_gu.h"
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-09-05 18:31:32 +02:00
|
|
|
#include "../../configuration.h"
|
2016-05-09 20:30:47 +02:00
|
|
|
#include "../../command.h"
|
2016-09-11 16:43:56 +02:00
|
|
|
#include "../../driver.h"
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-11-22 13:32:46 +01:00
|
|
|
#include "../../retroarch.h"
|
2016-09-29 20:14:12 +01:00
|
|
|
#include "../../verbosity.h"
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
#include "../common/ctr_common.h"
|
2016-10-10 22:25:25 +01:00
|
|
|
#ifndef HAVE_THREADS
|
|
|
|
#include "../../tasks/tasks_internal.h"
|
|
|
|
#endif
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
CTR_TEXTURE_BOTTOM_MENU,
|
|
|
|
CTR_TEXTURE_STATE_THUMBNAIL,
|
|
|
|
CTR_TEXTURE_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
/* TODO/FIXME - global referenced outside */
|
|
|
|
extern uint64_t lifecycle_state;
|
|
|
|
|
2018-11-14 16:38:52 +00:00
|
|
|
/* An annoyance...
|
|
|
|
* Have to keep track of bottom screen enable state
|
|
|
|
* externally, otherwise cannot detect current state
|
|
|
|
* when reinitialising... */
|
2019-09-19 20:49:26 -07:00
|
|
|
bool ctr_bottom_screen_enabled = true;
|
2021-09-06 01:16:16 +02:00
|
|
|
int fadeCount = 256;
|
|
|
|
|
|
|
|
static void ctr_set_bottom_screen_enable(bool enabled, bool idle);
|
2018-11-14 16:38:52 +00:00
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
static INLINE void ctr_check_3D_slider(ctr_video_t* ctr, ctr_video_mode_enum video_mode)
|
2016-04-17 20:10:21 +01:00
|
|
|
{
|
2017-01-10 21:15:52 +01:00
|
|
|
float slider_val = *(float*)0x1FF81080;
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
if (slider_val == 0.0f)
|
2016-04-17 20:10:21 +01:00
|
|
|
{
|
2019-04-15 17:05:55 +01:00
|
|
|
ctr->video_mode = CTR_VIDEO_MODE_2D;
|
|
|
|
ctr->enable_3d = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (video_mode)
|
|
|
|
{
|
|
|
|
case CTR_VIDEO_MODE_3D:
|
|
|
|
{
|
|
|
|
s16 offset = slider_val * 10.0f;
|
|
|
|
|
|
|
|
ctr->video_mode = CTR_VIDEO_MODE_3D;
|
|
|
|
|
|
|
|
ctr->frame_coords[1] = ctr->frame_coords[0];
|
|
|
|
ctr->frame_coords[2] = ctr->frame_coords[0];
|
|
|
|
|
|
|
|
ctr->frame_coords[1].x0 -= offset;
|
|
|
|
ctr->frame_coords[1].x1 -= offset;
|
|
|
|
ctr->frame_coords[2].x0 += offset;
|
|
|
|
ctr->frame_coords[2].x1 += offset;
|
|
|
|
|
|
|
|
GSPGPU_FlushDataCache(ctr->frame_coords, 3 * sizeof(ctr_vertex_t));
|
|
|
|
|
|
|
|
if (ctr->supports_parallax_disable)
|
2017-01-10 21:15:52 +01:00
|
|
|
ctr_set_parallax_layer(true);
|
2019-04-15 17:05:55 +01:00
|
|
|
ctr->enable_3d = true;
|
|
|
|
}
|
|
|
|
break;
|
2020-06-02 10:28:00 +03:00
|
|
|
case CTR_VIDEO_MODE_2D_400X240:
|
|
|
|
case CTR_VIDEO_MODE_2D_800X240:
|
2019-04-15 17:05:55 +01:00
|
|
|
if (ctr->supports_parallax_disable)
|
|
|
|
{
|
|
|
|
ctr->video_mode = video_mode;
|
|
|
|
ctr_set_parallax_layer(false);
|
|
|
|
ctr->enable_3d = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctr->video_mode = CTR_VIDEO_MODE_2D;
|
|
|
|
ctr->enable_3d = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CTR_VIDEO_MODE_2D:
|
|
|
|
default:
|
|
|
|
ctr->video_mode = CTR_VIDEO_MODE_2D;
|
2021-10-13 12:31:43 +01:00
|
|
|
if (ctr->supports_parallax_disable)
|
|
|
|
ctr_set_parallax_layer(false);
|
2019-04-15 17:05:55 +01:00
|
|
|
ctr->enable_3d = false;
|
|
|
|
break;
|
2016-04-17 20:10:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-14 00:19:38 +01:00
|
|
|
static INLINE void ctr_set_screen_coords(ctr_video_t * ctr)
|
|
|
|
{
|
|
|
|
if (ctr->rotation == 0)
|
|
|
|
{
|
|
|
|
ctr->frame_coords->x0 = ctr->vp.x;
|
|
|
|
ctr->frame_coords->y0 = ctr->vp.y;
|
|
|
|
ctr->frame_coords->x1 = ctr->vp.x + ctr->vp.width;
|
|
|
|
ctr->frame_coords->y1 = ctr->vp.y + ctr->vp.height;
|
|
|
|
}
|
|
|
|
else if (ctr->rotation == 1) /* 90° */
|
|
|
|
{
|
2017-06-11 18:12:37 -07:00
|
|
|
ctr->frame_coords->x0 = ctr->vp.x;
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->frame_coords->y0 = ctr->vp.y;
|
2017-06-11 18:12:37 -07:00
|
|
|
ctr->frame_coords->x1 = ctr->vp.x + ctr->vp.width;
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->frame_coords->y1 = ctr->vp.y + ctr->vp.height;
|
|
|
|
}
|
|
|
|
else if (ctr->rotation == 2) /* 180° */
|
|
|
|
{
|
|
|
|
ctr->frame_coords->x1 = ctr->vp.x;
|
|
|
|
ctr->frame_coords->y1 = ctr->vp.y;
|
|
|
|
ctr->frame_coords->x0 = ctr->vp.x + ctr->vp.width;
|
|
|
|
ctr->frame_coords->y0 = ctr->vp.y + ctr->vp.height;
|
|
|
|
}
|
|
|
|
else /* 270° */
|
|
|
|
{
|
2017-06-11 18:12:37 -07:00
|
|
|
ctr->frame_coords->x1 = ctr->vp.x;
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->frame_coords->y1 = ctr->vp.y;
|
2017-06-11 18:12:37 -07:00
|
|
|
ctr->frame_coords->x0 = ctr->vp.x + ctr->vp.width;
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->frame_coords->y0 = ctr->vp.y + ctr->vp.height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-04 22:50:59 +02:00
|
|
|
#ifdef HAVE_OVERLAY
|
|
|
|
static void ctr_render_overlay(void *data);
|
|
|
|
static void ctr_free_overlay(ctr_video_t *ctr)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; i < ctr->overlays; i++)
|
|
|
|
{
|
|
|
|
linearFree(ctr->overlay[i].frame_coords);
|
2021-04-24 15:36:03 +02:00
|
|
|
linearFree(ctr->overlay[i].texture.data);
|
2021-04-04 22:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
free(ctr->overlay);
|
|
|
|
ctr->overlay = NULL;
|
|
|
|
ctr->overlays = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-03-09 16:15:53 +01:00
|
|
|
static void ctr_update_viewport(
|
|
|
|
ctr_video_t* ctr,
|
|
|
|
settings_t *settings,
|
2020-03-10 19:52:05 +01:00
|
|
|
int custom_vp_x,
|
|
|
|
int custom_vp_y,
|
|
|
|
unsigned custom_vp_width,
|
|
|
|
unsigned custom_vp_height
|
|
|
|
)
|
2015-09-14 00:19:38 +01:00
|
|
|
{
|
2020-02-18 14:51:40 +01:00
|
|
|
int x = 0;
|
|
|
|
int y = 0;
|
|
|
|
float width = ctr->vp.full_width;
|
|
|
|
float height = ctr->vp.full_height;
|
|
|
|
float desired_aspect = video_driver_get_aspect_ratio();
|
|
|
|
bool video_scale_integer = settings->bools.video_scale_integer;
|
|
|
|
unsigned aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
|
2016-10-02 20:37:14 +02:00
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
if (ctr->rotation & 0x1)
|
2016-04-17 15:30:44 +01:00
|
|
|
desired_aspect = 1.0 / desired_aspect;
|
|
|
|
|
2020-02-18 14:51:40 +01:00
|
|
|
if (video_scale_integer)
|
2015-09-14 00:19:38 +01:00
|
|
|
{
|
|
|
|
video_viewport_get_scaled_integer(&ctr->vp, ctr->vp.full_width,
|
2016-04-17 15:30:44 +01:00
|
|
|
ctr->vp.full_height, desired_aspect, ctr->keep_aspect);
|
2015-09-14 00:19:38 +01:00
|
|
|
}
|
|
|
|
else if (ctr->keep_aspect)
|
|
|
|
{
|
|
|
|
#if defined(HAVE_MENU)
|
2020-02-18 14:51:40 +01:00
|
|
|
if (aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
|
2015-09-14 00:19:38 +01:00
|
|
|
{
|
2020-03-10 19:52:05 +01:00
|
|
|
x = custom_vp_x;
|
|
|
|
y = custom_vp_y;
|
|
|
|
width = custom_vp_width;
|
|
|
|
height = custom_vp_height;
|
2015-09-14 00:19:38 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2015-09-29 18:08:33 +02:00
|
|
|
float delta;
|
2016-10-02 20:37:14 +02:00
|
|
|
float device_aspect = ((float)ctr->vp.full_width) / ctr->vp.full_height;
|
2015-09-29 18:08:33 +02:00
|
|
|
|
2015-09-14 00:19:38 +01:00
|
|
|
if (fabsf(device_aspect - desired_aspect) < 0.0001f)
|
|
|
|
{
|
|
|
|
/* If the aspect ratios of screen and desired aspect
|
|
|
|
* ratio are sufficiently equal (floating point stuff),
|
|
|
|
* assume they are actually equal.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
else if (device_aspect > desired_aspect)
|
|
|
|
{
|
|
|
|
delta = (desired_aspect / device_aspect - 1.0f)
|
|
|
|
/ 2.0f + 0.5f;
|
|
|
|
x = (int)roundf(width * (0.5f - delta));
|
|
|
|
width = (unsigned)roundf(2.0f * width * delta);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delta = (device_aspect / desired_aspect - 1.0f)
|
|
|
|
/ 2.0f + 0.5f;
|
|
|
|
y = (int)roundf(height * (0.5f - delta));
|
|
|
|
height = (unsigned)roundf(2.0f * height * delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctr->vp.x = x;
|
|
|
|
ctr->vp.y = y;
|
|
|
|
ctr->vp.width = width;
|
|
|
|
ctr->vp.height = height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctr->vp.x = ctr->vp.y = 0;
|
|
|
|
ctr->vp.width = width;
|
|
|
|
ctr->vp.height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctr_set_screen_coords(ctr);
|
|
|
|
|
|
|
|
ctr->should_resize = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
static const char *ctr_texture_path(unsigned id)
|
|
|
|
{
|
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case CTR_TEXTURE_BOTTOM_MENU:
|
|
|
|
return "ctr/bottom_menu.png";
|
|
|
|
case CTR_TEXTURE_STATE_THUMBNAIL:
|
|
|
|
{
|
|
|
|
static char texture_path[PATH_MAX_LENGTH];
|
|
|
|
|
|
|
|
char state_path[PATH_MAX_LENGTH];
|
|
|
|
if (!retroarch_get_current_savestate_path(state_path,
|
|
|
|
sizeof(state_path)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
snprintf(texture_path, sizeof(texture_path),
|
|
|
|
"%s.png", state_path);
|
|
|
|
|
|
|
|
return path_basename(texture_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_update_state_date(void *data)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
time_t now = time(NULL);
|
|
|
|
|
|
|
|
struct tm *t = localtime(&now);
|
|
|
|
sprintf(ctr->state_date, "%02d/%02d/%d",
|
|
|
|
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ctr_update_state_date_from_file(void *data)
|
|
|
|
{
|
|
|
|
char state_path[PATH_MAX_LENGTH];
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (!retroarch_get_current_savestate_path(state_path, sizeof(state_path)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
#ifdef USE_CTRULIB_2
|
|
|
|
time_t mtime;
|
|
|
|
bool file_exists = archive_getmtime(state_path + 5, &mtime) == 0;
|
|
|
|
#else
|
|
|
|
u64 mtime;
|
|
|
|
bool file_exists = sdmc_getmtime(state_path + 5, &mtime) == 0;
|
|
|
|
#endif
|
|
|
|
if (!file_exists)
|
|
|
|
{
|
|
|
|
ctr->state_data_exist = false;
|
|
|
|
snprintf(ctr->state_date, sizeof(ctr->state_date), "00/00/0000");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctr->state_data_exist = true;
|
|
|
|
|
|
|
|
#ifdef USE_CTRULIB_2
|
|
|
|
struct tm *t = localtime(&mtime);
|
|
|
|
#else
|
|
|
|
time_t ft = mtime;
|
|
|
|
struct tm *t = localtime(&ft);
|
|
|
|
#endif
|
|
|
|
sprintf(ctr->state_date, "%02d/%02d/%d",
|
|
|
|
t->tm_mon + 1, t->tm_mday, t->tm_year + 1900);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_state_thumbnail_geom(void *data)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t *) data;
|
|
|
|
struct ctr_bottom_texture_data *o = NULL;
|
|
|
|
const int target_width = 120;
|
|
|
|
const int target_height = 90;
|
|
|
|
unsigned width, height;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
o = &ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
|
|
|
|
|
|
|
if (!o)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
if (!texture)
|
|
|
|
return;
|
|
|
|
|
|
|
|
float scale = (float) target_width / texture->active_width;
|
|
|
|
if (target_width > texture->active_width * scale) {
|
|
|
|
scale = (float) (target_width + 1) / texture->active_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
o->frame_coords->u0 = 0;
|
|
|
|
o->frame_coords->v0 = 0;
|
|
|
|
o->frame_coords->u1 = texture->active_width;
|
|
|
|
o->frame_coords->v1 = texture->active_height;
|
|
|
|
|
|
|
|
int x_offset = 184;
|
|
|
|
int y_offset = 46 + (target_height - texture->active_height * scale) / 2;
|
|
|
|
|
|
|
|
o->frame_coords->x0 = x_offset;
|
|
|
|
o->frame_coords->y0 = y_offset;
|
|
|
|
o->frame_coords->x1 = o->frame_coords->x0 + texture->active_width * scale;
|
|
|
|
o->frame_coords->y1 = o->frame_coords->y0 + texture->active_height * scale;
|
|
|
|
|
|
|
|
ctr_set_scale_vector(&o->scale_vector,
|
|
|
|
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
|
|
|
|
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
|
|
|
texture->width,
|
|
|
|
texture->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ctr_load_bottom_texture(void *data)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
const char *dir_assets;
|
|
|
|
|
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
|
|
|
settings_t *settings = config_get_ptr();
|
|
|
|
|
|
|
|
for (i = 0; i < CTR_TEXTURE_LAST; i++)
|
|
|
|
{
|
|
|
|
if (i == CTR_TEXTURE_STATE_THUMBNAIL)
|
|
|
|
dir_assets = dir_get_ptr(RARCH_DIR_SAVESTATE);
|
|
|
|
else
|
|
|
|
dir_assets = settings->paths.directory_assets;
|
|
|
|
|
|
|
|
if (gfx_display_reset_textures_list(
|
|
|
|
ctr_texture_path(i), dir_assets,
|
|
|
|
&ctr->bottom_textures[i].texture,
|
|
|
|
TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
|
|
|
{
|
|
|
|
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[i];
|
|
|
|
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
|
|
|
|
|
|
|
if (i == CTR_TEXTURE_STATE_THUMBNAIL)
|
|
|
|
{
|
|
|
|
ctr_state_thumbnail_geom(ctr);
|
|
|
|
ctr->render_state_from_png_file = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
|
|
|
|
o->frame_coords->u0 = 0;
|
|
|
|
o->frame_coords->v0 = 0;
|
|
|
|
o->frame_coords->u1 = texture->width;
|
|
|
|
o->frame_coords->v1 = texture->height;
|
|
|
|
|
|
|
|
o->frame_coords->x0 = 0;
|
|
|
|
o->frame_coords->y0 = 0;
|
|
|
|
o->frame_coords->x1 = o->frame_coords->x0 + texture->width;
|
|
|
|
o->frame_coords->y1 = o->frame_coords->y0 + texture->height;
|
|
|
|
|
|
|
|
ctr_set_scale_vector(&o->scale_vector,
|
|
|
|
CTR_BOTTOM_FRAMEBUFFER_WIDTH,
|
|
|
|
CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
|
|
|
texture->width,
|
|
|
|
texture->height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (i == CTR_TEXTURE_BOTTOM_MENU)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void save_state_to_file(void *data)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
char state_path[PATH_MAX_LENGTH];
|
2021-09-09 01:01:07 +09:00
|
|
|
retroarch_get_current_savestate_path(state_path, sizeof(state_path));
|
2021-09-04 01:14:03 +09:00
|
|
|
|
|
|
|
command_event(CMD_EVENT_RAM_STATE_TO_FILE, state_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bottom_menu_control(void* data, bool lcd_bottom)
|
|
|
|
{
|
|
|
|
touchPosition state_tmp_touch;
|
|
|
|
uint32_t state_tmp = 0;
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
settings_t *settings = config_get_ptr();
|
|
|
|
int config_slot = settings->ints.state_slot;
|
|
|
|
|
|
|
|
if (!ctr->init_bottom_menu)
|
|
|
|
{
|
|
|
|
if (ctr_load_bottom_texture(ctr))
|
|
|
|
{
|
|
|
|
ctr_update_state_date_from_file(ctr);
|
|
|
|
ctr->bottom_menu = CTR_BOTTOM_MENU_DEFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctr->init_bottom_menu = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
|
2021-09-28 12:56:10 +02:00
|
|
|
if (!retroarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
2021-09-06 01:16:16 +02:00
|
|
|
{
|
|
|
|
if (!ctr->bottom_is_idle)
|
|
|
|
{
|
|
|
|
ctr->bottom_is_idle = true;
|
|
|
|
ctr_set_bottom_screen_enable(false, ctr->bottom_is_idle);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
state_tmp = hidKeysDown();
|
|
|
|
hidTouchRead(&state_tmp_touch);
|
2021-09-06 01:16:16 +02:00
|
|
|
if (!state_tmp)
|
|
|
|
{
|
|
|
|
if (!ctr->bottom_check_idle && !ctr->bottom_is_idle)
|
|
|
|
{
|
|
|
|
ctr->idle_timestamp = svcGetSystemTick();
|
|
|
|
ctr->bottom_check_idle = true;
|
|
|
|
}
|
|
|
|
}
|
2021-09-04 01:14:03 +09:00
|
|
|
if (state_tmp & KEY_TOUCH)
|
|
|
|
{
|
|
|
|
#ifdef CONSOLE_LOG
|
|
|
|
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!lcd_bottom ||
|
|
|
|
ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE)
|
|
|
|
{
|
|
|
|
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-09-06 01:16:16 +02:00
|
|
|
if (ctr->bottom_is_idle)
|
|
|
|
{
|
|
|
|
ctr->bottom_is_idle = false;
|
|
|
|
ctr->bottom_is_fading = false;
|
|
|
|
fadeCount = 256;
|
|
|
|
ctr_set_bottom_screen_enable(true,true);
|
|
|
|
}
|
|
|
|
else if (ctr->bottom_check_idle)
|
|
|
|
{
|
|
|
|
ctr->bottom_check_idle = false;
|
|
|
|
ctr->bottom_is_fading = false;
|
|
|
|
fadeCount = 256;
|
|
|
|
}
|
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
switch (ctr->bottom_menu)
|
|
|
|
{
|
|
|
|
case CTR_BOTTOM_MENU_DEFAULT:
|
|
|
|
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
break;
|
|
|
|
case CTR_BOTTOM_MENU_SELECT:
|
|
|
|
if (state_tmp_touch.px > 8 &&
|
|
|
|
state_tmp_touch.px < 164 &&
|
|
|
|
state_tmp_touch.py > 9 &&
|
|
|
|
state_tmp_touch.py < 86)
|
|
|
|
{
|
|
|
|
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
}
|
|
|
|
else if (state_tmp_touch.px > 8 &&
|
|
|
|
state_tmp_touch.px < 164 &&
|
|
|
|
state_tmp_touch.py > 99 &&
|
|
|
|
state_tmp_touch.py < 230)
|
|
|
|
{
|
|
|
|
char screenshot_full_path[PATH_MAX_LENGTH];
|
|
|
|
|
|
|
|
struct ctr_bottom_texture_data *o =
|
|
|
|
&ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
|
|
|
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
if (texture)
|
|
|
|
linearFree(texture->data);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
o->texture = (uintptr_t) calloc(1, sizeof(ctr_texture_t));
|
|
|
|
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
|
|
|
texture = (ctr_texture_t *) o->texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
texture->width = ctr->texture_width;
|
|
|
|
texture->height = ctr->texture_width;
|
|
|
|
texture->active_width = ctr->frame_coords->u1;
|
|
|
|
texture->active_height = ctr->frame_coords->v1;
|
|
|
|
|
|
|
|
texture->data = linearAlloc(
|
|
|
|
ctr->texture_width * ctr->texture_height *
|
|
|
|
(ctr->rgb32? 4:2));
|
|
|
|
|
|
|
|
memcpy(texture->data, ctr->texture_swizzled,
|
|
|
|
ctr->texture_width * ctr->texture_height *
|
|
|
|
(ctr->rgb32? 4:2));
|
|
|
|
|
|
|
|
ctr_state_thumbnail_geom(ctr);
|
|
|
|
|
|
|
|
ctr->state_data_exist = true;
|
|
|
|
ctr->render_state_from_png_file = false;
|
|
|
|
|
|
|
|
ctr_update_state_date(ctr);
|
|
|
|
|
|
|
|
command_event(CMD_EVENT_SAVE_STATE_TO_RAM, NULL);
|
|
|
|
|
|
|
|
if (settings->bools.savestate_thumbnail_enable)
|
|
|
|
{
|
|
|
|
sprintf(screenshot_full_path, "%s/%s",
|
|
|
|
dir_get_ptr(RARCH_DIR_SAVESTATE),
|
|
|
|
ctr_texture_path(CTR_TEXTURE_STATE_THUMBNAIL));
|
|
|
|
|
|
|
|
take_screenshot(NULL, screenshot_full_path, true,
|
|
|
|
video_driver_cached_frame_has_valid_framebuffer(),
|
|
|
|
true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
}
|
|
|
|
else if (state_tmp_touch.px > 176 &&
|
|
|
|
state_tmp_touch.px < 311 &&
|
|
|
|
state_tmp_touch.py > 9 &&
|
|
|
|
state_tmp_touch.py < 230 &&
|
|
|
|
ctr->state_data_exist)
|
|
|
|
{
|
2021-09-09 01:01:07 +09:00
|
|
|
if (!command_event(CMD_EVENT_LOAD_STATE_FROM_RAM, NULL))
|
2021-09-04 01:14:03 +09:00
|
|
|
command_event(CMD_EVENT_LOAD_STATE, NULL);
|
|
|
|
BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-09-06 01:16:16 +02:00
|
|
|
ctr->bottom_check_idle = false;
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->refresh_bottom_menu = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctr->bottom_menu == CTR_BOTTOM_MENU_NOT_AVAILABLE ||
|
2021-09-28 12:56:10 +02:00
|
|
|
!retroarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
2021-09-04 01:14:03 +09:00
|
|
|
return;
|
|
|
|
|
2021-09-09 01:01:07 +09:00
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
if (ctr->state_slot != config_slot)
|
|
|
|
{
|
2021-09-09 01:01:07 +09:00
|
|
|
save_state_to_file(ctr);
|
2021-09-04 01:14:03 +09:00
|
|
|
|
|
|
|
ctr->state_slot = config_slot;
|
|
|
|
|
|
|
|
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
|
|
|
|
if (texture)
|
|
|
|
{
|
|
|
|
linearFree(texture->data);
|
|
|
|
linearFree(o->frame_coords);
|
|
|
|
o->texture = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctr_update_state_date_from_file(ctr))
|
|
|
|
{
|
|
|
|
if(gfx_display_reset_textures_list(
|
|
|
|
ctr_texture_path(CTR_TEXTURE_STATE_THUMBNAIL),
|
|
|
|
dir_get_ptr(RARCH_DIR_SAVESTATE),
|
|
|
|
&o->texture,
|
|
|
|
TEXTURE_FILTER_MIPMAP_LINEAR, NULL, NULL))
|
|
|
|
{
|
|
|
|
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
|
|
|
ctr_state_thumbnail_geom(ctr);
|
|
|
|
ctr->render_state_from_png_file = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctr->refresh_bottom_menu = true;
|
|
|
|
}
|
|
|
|
|
2021-09-28 10:27:00 +02:00
|
|
|
#ifdef HAVE_MENU
|
|
|
|
if (menu_state_get_ptr()->alive)
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->bottom_menu = CTR_BOTTOM_MENU_SELECT;
|
|
|
|
else
|
2021-09-28 10:27:00 +02:00
|
|
|
#endif
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->bottom_menu = CTR_BOTTOM_MENU_DEFAULT;
|
|
|
|
|
|
|
|
if (ctr->prev_bottom_menu != ctr->bottom_menu)
|
|
|
|
{
|
2021-09-28 10:27:00 +02:00
|
|
|
ctr->prev_bottom_menu = ctr->bottom_menu;
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->refresh_bottom_menu = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void font_driver_render_msg_bottom(
|
|
|
|
void *data,
|
|
|
|
const char *msg,
|
|
|
|
const void *_params,
|
|
|
|
void *font_data)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
ctr->render_font_bottom = true;
|
|
|
|
font_driver_render_msg(ctr, msg, _params, font_data);
|
|
|
|
ctr->render_font_bottom = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_render_bottom_screen(void *data)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (!ctr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!ctr->refresh_bottom_menu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
struct font_params params = { 0, };
|
|
|
|
params.text_align = TEXT_ALIGN_CENTER;
|
|
|
|
params.color = COLOR_ABGR(255, 255, 255, 255);
|
|
|
|
|
|
|
|
switch (ctr->bottom_menu)
|
|
|
|
{
|
|
|
|
case CTR_BOTTOM_MENU_NOT_AVAILABLE:
|
|
|
|
{
|
|
|
|
params.scale = 1.6f;
|
|
|
|
params.x = 0.0f;
|
|
|
|
params.y = 0.5f;
|
|
|
|
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_ASSET_NOT_FOUND),
|
|
|
|
¶ms, NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CTR_BOTTOM_MENU_DEFAULT:
|
|
|
|
{
|
|
|
|
params.scale = 1.6f;
|
|
|
|
params.x = 0.0f;
|
|
|
|
params.y = 0.5f;
|
|
|
|
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_DEFAULT),
|
|
|
|
¶ms, NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case CTR_BOTTOM_MENU_SELECT:
|
|
|
|
{
|
|
|
|
params.scale = 1.48f;
|
|
|
|
params.color = COLOR_ABGR(255, 255, 255, 255);
|
|
|
|
|
|
|
|
/* draw state thumbnail */
|
|
|
|
if (ctr->state_data_exist) {
|
|
|
|
struct ctr_bottom_texture_data *o = (struct ctr_bottom_texture_data*)
|
|
|
|
&ctr->bottom_textures[CTR_TEXTURE_STATE_THUMBNAIL];
|
|
|
|
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
if (texture)
|
|
|
|
{
|
|
|
|
GPU_TEXCOLOR colorType = GPU_RGBA8;
|
|
|
|
if (!ctr->render_state_from_png_file && !ctr->rgb32)
|
|
|
|
colorType = GPU_RGB565;
|
|
|
|
|
|
|
|
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(texture->data),
|
|
|
|
texture->width, texture->height,
|
|
|
|
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
|
|
|
|
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
|
|
|
colorType);
|
|
|
|
|
|
|
|
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
|
|
|
ctrGuSetVertexShaderFloatUniform(0, (float*)&o->scale_vector, 1);
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(o->frame_coords));
|
|
|
|
|
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
|
|
|
|
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
|
|
|
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
params.x = 0.266f;
|
|
|
|
params.y = 0.64f;
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_NO_STATE_THUMBNAIL),
|
|
|
|
¶ms, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
params.x = 0.266f;
|
|
|
|
params.y = 0.64f;
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_NO_STATE_DATA),
|
|
|
|
¶ms, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* draw bottom menu */
|
|
|
|
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[CTR_TEXTURE_BOTTOM_MENU];
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
|
|
|
|
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(texture->data),
|
|
|
|
texture->width, texture->height,
|
|
|
|
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
|
|
|
|
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
|
|
|
GPU_RGBA8);
|
|
|
|
|
|
|
|
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
|
|
|
ctrGuSetVertexShaderFloatUniform(0, (float*)&o->scale_vector, 1);
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(o->frame_coords));
|
|
|
|
|
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.bottom),
|
|
|
|
0, 0, CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
|
|
|
CTR_BOTTOM_FRAMEBUFFER_WIDTH);
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
|
|
|
|
/* draw resume game */
|
|
|
|
params.x = -0.178f;
|
|
|
|
params.y = 0.78f;
|
|
|
|
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_RESUME),
|
|
|
|
¶ms, NULL);
|
|
|
|
|
|
|
|
/* draw create restore point */
|
|
|
|
params.x = -0.178f;
|
|
|
|
params.y = 0.33f;
|
|
|
|
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_SAVE_STATE),
|
|
|
|
¶ms, NULL);
|
|
|
|
|
|
|
|
/* draw load restore point */
|
|
|
|
params.x = 0.266f;
|
|
|
|
params.y = 0.24f;
|
|
|
|
|
|
|
|
font_driver_render_msg_bottom(ctr,
|
|
|
|
msg_hash_to_str(MSG_3DS_BOTTOM_MENU_LOAD_STATE),
|
|
|
|
¶ms, NULL);
|
|
|
|
|
|
|
|
/* draw date */
|
|
|
|
params.x = 0.266f;
|
|
|
|
params.y = 0.87f;
|
|
|
|
font_driver_render_msg_bottom(ctr, ctr->state_date,
|
|
|
|
¶ms, NULL);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-06 01:16:16 +02:00
|
|
|
// graphic function originates from here:
|
|
|
|
// https://github.com/smealum/3ds_hb_menu/blob/master/source/gfx.c
|
|
|
|
void ctr_fade_bottom_screen(gfxScreen_t screen, gfx3dSide_t side, u32 f)
|
|
|
|
{
|
|
|
|
u16 fbWidth, fbHeight;
|
|
|
|
u8* fbAdr=gfxGetFramebuffer(screen, side, &fbWidth, &fbHeight);
|
|
|
|
|
|
|
|
int i; for(i=0; i<fbWidth*fbHeight/2; i++)
|
|
|
|
{
|
|
|
|
*fbAdr=(*fbAdr*f)>>8;fbAdr++;
|
|
|
|
*fbAdr=(*fbAdr*f)>>8;fbAdr++;
|
|
|
|
*fbAdr=(*fbAdr*f)>>8;fbAdr++;
|
|
|
|
*fbAdr=(*fbAdr*f)>>8;fbAdr++;
|
|
|
|
*fbAdr=(*fbAdr*f)>>8;fbAdr++;
|
|
|
|
*fbAdr=(*fbAdr*f)>>8;fbAdr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_set_bottom_screen_idle(ctr_video_t * ctr)
|
|
|
|
{
|
|
|
|
if (ctr->bottom_menu == CTR_BOTTOM_MENU_SELECT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
u64 elapsed_tick = ( svcGetSystemTick() - ctr->idle_timestamp );
|
|
|
|
if ( elapsed_tick > 2000000000 )
|
|
|
|
{
|
|
|
|
if (!ctr->bottom_is_fading)
|
|
|
|
{
|
|
|
|
ctr->bottom_is_fading = true;
|
|
|
|
ctr->refresh_bottom_menu = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( fadeCount > 0 )
|
|
|
|
{
|
|
|
|
fadeCount--;
|
|
|
|
ctr_fade_bottom_screen(GFX_BOTTOM, GFX_LEFT, fadeCount);
|
|
|
|
|
|
|
|
if ( fadeCount <= 128 )
|
|
|
|
{
|
|
|
|
ctr->bottom_is_idle = true;
|
|
|
|
ctr->bottom_is_fading = false;
|
|
|
|
ctr->bottom_check_idle = false;
|
|
|
|
fadeCount = 256;
|
|
|
|
ctr_set_bottom_screen_enable(false,true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_set_bottom_screen_enable(bool enabled, bool idle)
|
2021-09-04 01:14:03 +09:00
|
|
|
{
|
|
|
|
Handle lcd_handle;
|
|
|
|
u8 not_2DS;
|
|
|
|
|
|
|
|
CFGU_GetModelNintendo2DS(¬_2DS);
|
|
|
|
if(not_2DS && srvGetServiceHandle(&lcd_handle, "gsp::Lcd") >= 0)
|
|
|
|
{
|
|
|
|
u32 *cmdbuf = getThreadCommandBuffer();
|
|
|
|
cmdbuf[0] = enabled? 0x00110040: 0x00120040;
|
|
|
|
cmdbuf[1] = 2;
|
|
|
|
svcSendSyncRequest(lcd_handle);
|
|
|
|
svcCloseHandle(lcd_handle);
|
|
|
|
}
|
|
|
|
|
2021-09-06 01:16:16 +02:00
|
|
|
if (!idle)
|
|
|
|
ctr_bottom_screen_enabled = enabled;
|
2021-09-04 01:14:03 +09:00
|
|
|
}
|
|
|
|
|
2015-11-19 23:15:48 +01:00
|
|
|
static void ctr_lcd_aptHook(APT_HookType hook, void* param)
|
2015-10-06 19:56:11 +01:00
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)param;
|
2016-10-04 15:49:55 +01:00
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
if (!ctr)
|
2015-10-06 19:56:11 +01:00
|
|
|
return;
|
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
if (hook == APTHOOK_ONRESTORE)
|
2016-04-18 16:38:32 +01:00
|
|
|
{
|
|
|
|
GPUCMD_SetBufferOffset(0);
|
|
|
|
shaderProgramUse(&ctr->shader);
|
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
2016-04-18 16:38:32 +01:00
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT, CTR_TOP_FRAMEBUFFER_WIDTH);
|
|
|
|
|
|
|
|
GPU_DepthMap(-1.0f, 0.0f);
|
|
|
|
GPU_SetFaceCulling(GPU_CULL_NONE);
|
|
|
|
GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
|
|
|
|
GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
|
|
|
GPU_SetBlendingColor(0, 0, 0, 0);
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR);
|
2016-04-18 16:38:32 +01:00
|
|
|
GPUCMD_AddMaskedWrite(GPUREG_EARLYDEPTH_TEST1, 0x1, 0);
|
|
|
|
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_TEST2, 0);
|
|
|
|
GPU_SetAlphaBlending(GPU_BLEND_ADD, GPU_BLEND_ADD,
|
|
|
|
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA,
|
|
|
|
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00);
|
|
|
|
GPU_SetTextureEnable(GPU_TEXUNIT0);
|
|
|
|
GPU_SetTexEnv(0, GPU_TEXTURE0, GPU_TEXTURE0, 0, 0, GPU_REPLACE, GPU_REPLACE, 0);
|
|
|
|
GPU_SetTexEnv(1, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(2, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(3, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(4, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(5, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
ctrGuSetAttributeBuffers(2,
|
|
|
|
VIRT_TO_PHYS(ctr->menu.frame_coords),
|
|
|
|
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 0 |
|
|
|
|
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 4,
|
|
|
|
sizeof(ctr_vertex_t));
|
2017-12-25 08:51:50 +01:00
|
|
|
GPU_Finalize();
|
2016-04-18 16:38:32 +01:00
|
|
|
ctrGuFlushAndRun(true);
|
|
|
|
gspWaitForEvent(GSPGPU_EVENT_P3D, false);
|
2016-09-30 16:16:18 +01:00
|
|
|
ctr->p3d_event_pending = false;
|
2016-04-18 16:38:32 +01:00
|
|
|
}
|
|
|
|
|
2021-09-28 10:27:00 +02:00
|
|
|
switch (hook)
|
2016-04-18 16:38:32 +01:00
|
|
|
{
|
2021-09-28 10:27:00 +02:00
|
|
|
case APTHOOK_ONSUSPEND:
|
|
|
|
if (ctr->video_mode == CTR_VIDEO_MODE_2D_400X240)
|
|
|
|
{
|
|
|
|
memcpy(gfxTopRightFramebuffers[ctr->current_buffer_top],
|
|
|
|
gfxTopLeftFramebuffers[ctr->current_buffer_top],
|
|
|
|
400 * 240 * 3);
|
|
|
|
GSPGPU_FlushDataCache(gfxTopRightFramebuffers[ctr->current_buffer_top], 400 * 240 * 3);
|
|
|
|
}
|
|
|
|
if (ctr->supports_parallax_disable)
|
|
|
|
ctr_set_parallax_layer(*(float*)0x1FF81080 != 0.0);
|
|
|
|
ctr_set_bottom_screen_enable(true, ctr->bottom_is_idle);
|
|
|
|
save_state_to_file(ctr);
|
|
|
|
break;
|
|
|
|
case APTHOOK_ONRESTORE:
|
|
|
|
case APTHOOK_ONWAKEUP:
|
|
|
|
ctr_set_bottom_screen_enable(false, ctr->bottom_is_idle);
|
|
|
|
save_state_to_file(ctr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2016-04-18 16:38:32 +01:00
|
|
|
}
|
|
|
|
|
2020-07-28 15:03:43 +09:00
|
|
|
|
2021-09-28 10:27:00 +02:00
|
|
|
#ifdef HAVE_MENU
|
|
|
|
if (menu_state_get_ptr()->alive)
|
2020-07-28 15:03:43 +09:00
|
|
|
return;
|
2021-09-28 10:27:00 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (hook)
|
2020-07-28 15:03:43 +09:00
|
|
|
{
|
2021-09-28 10:27:00 +02:00
|
|
|
case APTHOOK_ONSUSPEND:
|
|
|
|
case APTHOOK_ONSLEEP:
|
|
|
|
command_event(CMD_EVENT_AUDIO_STOP, NULL);
|
|
|
|
break;
|
|
|
|
case APTHOOK_ONRESTORE:
|
|
|
|
case APTHOOK_ONWAKEUP:
|
|
|
|
command_event(CMD_EVENT_AUDIO_START, NULL);
|
|
|
|
break;
|
2020-07-28 15:03:43 +09:00
|
|
|
}
|
2015-10-06 19:56:11 +01:00
|
|
|
}
|
2016-10-10 22:25:25 +01:00
|
|
|
|
|
|
|
static void ctr_vsync_hook(ctr_video_t* ctr)
|
|
|
|
{
|
|
|
|
ctr->vsync_event_pending = false;
|
|
|
|
}
|
2021-09-28 10:27:00 +02:00
|
|
|
|
2016-10-10 22:25:25 +01:00
|
|
|
#ifndef HAVE_THREADS
|
|
|
|
static bool ctr_tasks_finder(retro_task_t *task,void *userdata)
|
|
|
|
{
|
|
|
|
return task;
|
|
|
|
}
|
2021-09-28 10:27:00 +02:00
|
|
|
|
2016-10-10 22:25:25 +01:00
|
|
|
task_finder_data_t ctr_tasks_finder_data = {ctr_tasks_finder, NULL};
|
|
|
|
#endif
|
|
|
|
|
2018-11-14 16:38:52 +00:00
|
|
|
|
2017-04-24 12:25:14 +02:00
|
|
|
static void* ctr_init(const video_info_t* video,
|
2019-07-27 02:21:24 +02:00
|
|
|
input_driver_t** input, void** input_data)
|
2015-04-01 22:14:13 +01:00
|
|
|
{
|
2021-09-04 01:14:03 +09:00
|
|
|
size_t i;
|
2015-12-11 11:00:12 +01:00
|
|
|
float refresh_rate;
|
2019-04-15 17:05:55 +01:00
|
|
|
u8 device_model = 0xFF;
|
|
|
|
void* ctrinput = NULL;
|
2018-11-14 16:38:52 +00:00
|
|
|
settings_t *settings = config_get_ptr();
|
2020-02-19 00:23:33 +01:00
|
|
|
bool lcd_bottom = settings->bools.video_3ds_lcd_bottom;
|
2019-04-15 17:05:55 +01:00
|
|
|
ctr_video_t* ctr = (ctr_video_t*)linearAlloc(sizeof(ctr_video_t));
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
if (!ctr)
|
|
|
|
return NULL;
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
memset(ctr, 0, sizeof(ctr_video_t));
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->vp.x = 0;
|
|
|
|
ctr->vp.y = 0;
|
|
|
|
ctr->vp.width = CTR_TOP_FRAMEBUFFER_WIDTH;
|
|
|
|
ctr->vp.height = CTR_TOP_FRAMEBUFFER_HEIGHT;
|
|
|
|
ctr->vp.full_width = CTR_TOP_FRAMEBUFFER_WIDTH;
|
|
|
|
ctr->vp.full_height = CTR_TOP_FRAMEBUFFER_HEIGHT;
|
2020-01-31 03:47:50 +01:00
|
|
|
video_driver_set_size(ctr->vp.width, ctr->vp.height);
|
2015-09-14 00:19:38 +01:00
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
ctr->drawbuffers.top.left = vramAlloc(CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT * 2 * sizeof(uint32_t));
|
|
|
|
ctr->drawbuffers.top.right = (void*)((uint32_t*)ctr->drawbuffers.top.left + CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT);
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->drawbuffers.bottom = vramAlloc(CTR_BOTTOM_FRAMEBUFFER_WIDTH * CTR_BOTTOM_FRAMEBUFFER_HEIGHT * 2 * sizeof(uint32_t));
|
2015-09-14 00:19:38 +01:00
|
|
|
|
2016-10-10 22:25:25 +01:00
|
|
|
ctr->display_list_size = 0x4000;
|
2015-04-05 20:40:35 +01:00
|
|
|
ctr->display_list = linearAlloc(ctr->display_list_size * sizeof(uint32_t));
|
|
|
|
GPU_Reset(NULL, ctr->display_list, ctr->display_list_size);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-09-29 20:14:12 +01:00
|
|
|
ctr->vertex_cache.size = 0x1000;
|
|
|
|
ctr->vertex_cache.buffer = linearAlloc(ctr->vertex_cache.size * sizeof(ctr_vertex_t));
|
|
|
|
ctr->vertex_cache.current = ctr->vertex_cache.buffer;
|
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->bottom_textures = (struct ctr_bottom_texture_data *)calloc(CTR_TEXTURE_LAST,
|
|
|
|
sizeof(*ctr->bottom_textures));
|
|
|
|
|
|
|
|
ctr->init_bottom_menu = false;
|
|
|
|
ctr->state_data_exist = false;
|
|
|
|
ctr->render_font_bottom = false;
|
|
|
|
ctr->refresh_bottom_menu = true;
|
|
|
|
ctr->render_state_from_png_file = false;
|
|
|
|
ctr->bottom_menu = CTR_BOTTOM_MENU_NOT_AVAILABLE;
|
|
|
|
ctr->prev_bottom_menu = CTR_BOTTOM_MENU_NOT_AVAILABLE;
|
2021-09-06 01:16:16 +02:00
|
|
|
ctr->bottom_check_idle = false;
|
|
|
|
ctr->bottom_is_idle = false;
|
|
|
|
ctr->bottom_is_fading = false;
|
|
|
|
ctr->idle_timestamp = 0;
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->state_slot = settings->ints.state_slot;
|
|
|
|
|
|
|
|
snprintf(ctr->state_date, sizeof(ctr->state_date), "%s", "00/00/0000");
|
|
|
|
ctr->state_date[CTR_STATE_DATE_SIZE - 1] = '\0';
|
|
|
|
|
2015-10-20 16:03:39 +01:00
|
|
|
ctr->rgb32 = video->rgb32;
|
2015-10-20 12:34:53 +01:00
|
|
|
ctr->texture_width = video->input_scale * RARCH_SCALE_BASE;
|
|
|
|
ctr->texture_height = video->input_scale * RARCH_SCALE_BASE;
|
2015-04-05 20:40:35 +01:00
|
|
|
ctr->texture_linear =
|
2015-10-20 16:03:39 +01:00
|
|
|
linearMemAlign(ctr->texture_width * ctr->texture_height * (ctr->rgb32? 4:2), 128);
|
2015-04-05 20:40:35 +01:00
|
|
|
ctr->texture_swizzled =
|
2015-10-20 16:03:39 +01:00
|
|
|
linearMemAlign(ctr->texture_width * ctr->texture_height * (ctr->rgb32? 4:2), 128);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-04-18 15:55:34 +01:00
|
|
|
ctr->frame_coords = linearAlloc(3 * sizeof(ctr_vertex_t));
|
2015-04-08 18:59:41 +01:00
|
|
|
ctr->frame_coords->x0 = 0;
|
|
|
|
ctr->frame_coords->y0 = 0;
|
|
|
|
ctr->frame_coords->x1 = CTR_TOP_FRAMEBUFFER_WIDTH;
|
|
|
|
ctr->frame_coords->y1 = CTR_TOP_FRAMEBUFFER_HEIGHT;
|
2016-04-17 15:30:44 +01:00
|
|
|
ctr->frame_coords->u0 = 0;
|
|
|
|
ctr->frame_coords->v0 = 0;
|
|
|
|
ctr->frame_coords->u1 = CTR_TOP_FRAMEBUFFER_WIDTH;
|
|
|
|
ctr->frame_coords->v1 = CTR_TOP_FRAMEBUFFER_HEIGHT;
|
2015-10-21 15:41:06 +01:00
|
|
|
GSPGPU_FlushDataCache(ctr->frame_coords, sizeof(ctr_vertex_t));
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
ctr->menu.texture_width = 512;
|
|
|
|
ctr->menu.texture_height = 512;
|
|
|
|
ctr->menu.texture_linear =
|
2015-10-20 12:34:53 +01:00
|
|
|
linearMemAlign(ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t), 128);
|
2015-04-05 20:40:35 +01:00
|
|
|
ctr->menu.texture_swizzled =
|
2015-10-20 12:34:53 +01:00
|
|
|
linearMemAlign(ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t), 128);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-04-18 15:55:34 +01:00
|
|
|
ctr->menu.frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
2015-04-08 18:59:41 +01:00
|
|
|
|
|
|
|
ctr->menu.frame_coords->x0 = 40;
|
|
|
|
ctr->menu.frame_coords->y0 = 0;
|
|
|
|
ctr->menu.frame_coords->x1 = CTR_TOP_FRAMEBUFFER_WIDTH - 40;
|
|
|
|
ctr->menu.frame_coords->y1 = CTR_TOP_FRAMEBUFFER_HEIGHT;
|
2016-04-17 15:30:44 +01:00
|
|
|
ctr->menu.frame_coords->u0 = 0;
|
|
|
|
ctr->menu.frame_coords->v0 = 0;
|
|
|
|
ctr->menu.frame_coords->u1 = CTR_TOP_FRAMEBUFFER_WIDTH - 80;
|
|
|
|
ctr->menu.frame_coords->v1 = CTR_TOP_FRAMEBUFFER_HEIGHT;
|
2015-10-21 15:41:06 +01:00
|
|
|
GSPGPU_FlushDataCache(ctr->menu.frame_coords, sizeof(ctr_vertex_t));
|
2015-04-08 18:59:41 +01:00
|
|
|
|
|
|
|
ctr_set_scale_vector(&ctr->scale_vector,
|
|
|
|
CTR_TOP_FRAMEBUFFER_WIDTH, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
ctr->texture_width, ctr->texture_height);
|
|
|
|
ctr_set_scale_vector(&ctr->menu.scale_vector,
|
|
|
|
CTR_TOP_FRAMEBUFFER_WIDTH, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
ctr->menu.texture_width, ctr->menu.texture_height);
|
|
|
|
|
2016-10-13 12:16:07 +01:00
|
|
|
memset(ctr->texture_linear, 0x00, ctr->texture_width * ctr->texture_height * (ctr->rgb32? 4:2));
|
2017-01-23 01:37:19 +01:00
|
|
|
#if 0
|
|
|
|
memset(ctr->menu.texture_swizzled , 0x00, ctr->menu.texture_width * ctr->menu.texture_height * 2);
|
|
|
|
#endif
|
2016-10-13 12:16:07 +01:00
|
|
|
|
2016-04-16 20:26:05 +01:00
|
|
|
ctr->dvlb = DVLB_ParseFile((u32*)ctr_sprite_shbin, ctr_sprite_shbin_size);
|
2015-04-08 18:59:41 +01:00
|
|
|
ctrGuSetVshGsh(&ctr->shader, ctr->dvlb, 2, 2);
|
|
|
|
shaderProgramUse(&ctr->shader);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
2015-04-08 18:59:41 +01:00
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT, CTR_TOP_FRAMEBUFFER_WIDTH);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-08 18:59:41 +01:00
|
|
|
GPU_DepthMap(-1.0f, 0.0f);
|
|
|
|
GPU_SetFaceCulling(GPU_CULL_NONE);
|
|
|
|
GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
|
2015-09-07 18:31:30 +01:00
|
|
|
GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP);
|
2015-04-08 18:59:41 +01:00
|
|
|
GPU_SetBlendingColor(0, 0, 0, 0);
|
2017-01-23 01:37:19 +01:00
|
|
|
#if 0
|
|
|
|
GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL);
|
|
|
|
#endif
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR);
|
2017-01-23 01:37:19 +01:00
|
|
|
#if 0
|
|
|
|
GPU_SetDepthTestAndWriteMask(true, GPU_ALWAYS, GPU_WRITE_ALL);
|
|
|
|
#endif
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-12-21 13:41:18 -05:00
|
|
|
GPUCMD_AddMaskedWrite(GPUREG_EARLYDEPTH_TEST1, 0x1, 0);
|
|
|
|
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_TEST2, 0);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-08 18:59:41 +01:00
|
|
|
GPU_SetAlphaBlending(GPU_BLEND_ADD, GPU_BLEND_ADD,
|
|
|
|
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA,
|
|
|
|
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-08 18:59:41 +01:00
|
|
|
GPU_SetTextureEnable(GPU_TEXUNIT0);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-04-16 22:38:13 +01:00
|
|
|
GPU_SetTexEnv(0, GPU_TEXTURE0, GPU_TEXTURE0, 0, 0, GPU_REPLACE, GPU_REPLACE, 0);
|
|
|
|
GPU_SetTexEnv(1, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(2, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(3, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(4, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(5, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-08 18:59:41 +01:00
|
|
|
ctrGuSetAttributeBuffers(2,
|
|
|
|
VIRT_TO_PHYS(ctr->menu.frame_coords),
|
|
|
|
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 0 |
|
2016-04-17 15:30:44 +01:00
|
|
|
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 4,
|
2015-04-08 18:59:41 +01:00
|
|
|
sizeof(ctr_vertex_t));
|
2017-12-25 08:51:50 +01:00
|
|
|
GPU_Finalize();
|
2015-04-13 01:50:00 +01:00
|
|
|
ctrGuFlushAndRun(true);
|
2017-01-10 21:15:52 +01:00
|
|
|
|
2016-10-13 12:16:07 +01:00
|
|
|
ctr->p3d_event_pending = true;
|
|
|
|
ctr->ppf_event_pending = false;
|
2015-04-01 22:14:13 +01:00
|
|
|
|
|
|
|
if (input && input_data)
|
|
|
|
{
|
2020-08-30 05:29:32 +02:00
|
|
|
ctrinput = input_driver_init_wrap(&input_ctr, settings->arrays.input_joypad_driver);
|
2017-01-10 21:15:52 +01:00
|
|
|
*input = ctrinput ? &input_ctr : NULL;
|
|
|
|
*input_data = ctrinput;
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->keep_aspect = true;
|
|
|
|
ctr->should_resize = true;
|
2015-10-20 16:03:39 +01:00
|
|
|
ctr->smooth = video->smooth;
|
|
|
|
ctr->vsync = video->vsync;
|
2016-04-17 20:10:21 +01:00
|
|
|
ctr->current_buffer_top = 0;
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->current_buffer_bottom = 0;
|
2015-09-14 00:19:38 +01:00
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
/* Only O3DS and O3DSXL support running in 'dual-framebuffer'
|
|
|
|
* mode with the parallax barrier disabled
|
|
|
|
* (i.e. these are the only platforms that can use
|
2020-06-02 10:28:00 +03:00
|
|
|
* CTR_VIDEO_MODE_2D_400X240 and CTR_VIDEO_MODE_2D_800X240) */
|
2019-04-15 17:05:55 +01:00
|
|
|
CFGU_GetSystemModel(&device_model); /* (0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL) */
|
|
|
|
ctr->supports_parallax_disable = (device_model == 0) || (device_model == 1);
|
|
|
|
|
2015-12-11 11:00:12 +01:00
|
|
|
refresh_rate = (32730.0 * 8192.0) / 4481134.0;
|
2015-09-28 20:09:07 +01:00
|
|
|
|
2015-12-11 11:00:12 +01:00
|
|
|
driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &refresh_rate);
|
2015-10-06 19:56:11 +01:00
|
|
|
aptHook(&ctr->lcd_aptHook, ctr_lcd_aptHook, ctr);
|
|
|
|
|
2020-02-16 21:59:03 +01:00
|
|
|
font_driver_init_osd(ctr, video,
|
|
|
|
false,
|
2017-04-29 16:52:52 +02:00
|
|
|
video->is_threaded,
|
|
|
|
FONT_DRIVER_RENDER_CTR);
|
2016-09-29 20:14:12 +01:00
|
|
|
|
2020-02-18 14:51:40 +01:00
|
|
|
ctr->msg_rendering_enabled = false;
|
2016-10-13 12:16:07 +01:00
|
|
|
ctr->menu_texture_frame_enable = false;
|
2020-02-18 14:51:40 +01:00
|
|
|
ctr->menu_texture_enable = false;
|
2016-09-29 20:14:12 +01:00
|
|
|
|
2018-11-14 16:38:52 +00:00
|
|
|
/* Set bottom screen enable state, if required */
|
2020-02-19 00:23:33 +01:00
|
|
|
if (lcd_bottom != ctr_bottom_screen_enabled)
|
2021-09-06 01:16:16 +02:00
|
|
|
ctr_set_bottom_screen_enable(lcd_bottom, false);
|
2018-11-14 16:38:52 +00:00
|
|
|
|
2020-02-18 14:51:40 +01:00
|
|
|
gspSetEventCallback(GSPGPU_EVENT_VBlank0,
|
|
|
|
(ThreadFunc)ctr_vsync_hook, ctr, false);
|
2016-10-10 22:25:25 +01:00
|
|
|
|
2015-04-01 22:14:13 +01:00
|
|
|
return ctr;
|
|
|
|
}
|
2015-04-13 01:50:00 +01:00
|
|
|
|
2017-01-19 16:30:40 +01:00
|
|
|
#if 0
|
|
|
|
#define CTR_INSPECT_MEMORY_USAGE
|
|
|
|
#endif
|
|
|
|
|
2015-04-01 22:14:13 +01:00
|
|
|
static bool ctr_frame(void* data, const void* frame,
|
2016-09-29 20:14:12 +01:00
|
|
|
unsigned width, unsigned height,
|
2015-08-03 23:01:07 +02:00
|
|
|
uint64_t frame_count,
|
2017-01-18 17:41:27 +01:00
|
|
|
unsigned pitch, const char* msg, video_frame_info_t *video_info)
|
2015-04-01 22:14:13 +01:00
|
|
|
{
|
2015-04-02 04:00:26 +01:00
|
|
|
static uint64_t currentTick,lastTick;
|
2021-09-04 01:14:03 +09:00
|
|
|
extern GSPGPU_FramebufferInfo topFramebufferInfo, bottomFramebufferInfo;
|
2017-01-25 16:53:06 +01:00
|
|
|
extern u8* gfxSharedMemory;
|
|
|
|
extern u8 gfxThreadID;
|
2020-02-18 14:51:40 +01:00
|
|
|
uint32_t diff;
|
2020-03-09 16:15:53 +01:00
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
static float fps = 0.0;
|
|
|
|
static int total_frames = 0;
|
|
|
|
static int frames = 0;
|
|
|
|
settings_t *settings = config_get_ptr();
|
|
|
|
unsigned disp_mode = settings->uints.video_3ds_display_mode;
|
|
|
|
bool statistics_show = video_info->statistics_show;
|
|
|
|
const char *stat_text = video_info->stat_text;
|
|
|
|
float video_refresh_rate = video_info->refresh_rate;
|
|
|
|
struct font_params *osd_params = (struct font_params*)
|
|
|
|
&video_info->osd_stat_params;
|
2020-03-10 19:52:05 +01:00
|
|
|
int custom_vp_x = video_info->custom_vp_x;
|
|
|
|
int custom_vp_y = video_info->custom_vp_y;
|
|
|
|
unsigned custom_vp_width = video_info->custom_vp_width;
|
|
|
|
unsigned custom_vp_height = video_info->custom_vp_height;
|
2020-08-03 16:33:54 +02:00
|
|
|
#ifdef HAVE_MENU
|
2020-05-19 16:20:43 +02:00
|
|
|
bool menu_is_alive = video_info->menu_is_alive;
|
2020-08-03 16:33:54 +02:00
|
|
|
#endif
|
2021-03-23 22:03:44 +01:00
|
|
|
#ifdef HAVE_GFX_WIDGETS
|
|
|
|
bool widgets_active = video_info->widgets_active;
|
|
|
|
#endif
|
2021-09-04 01:14:03 +09:00
|
|
|
bool lcd_bottom = false;
|
2015-04-13 11:26:02 +02:00
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
if (!width || !height || !settings)
|
2015-04-01 22:14:13 +01:00
|
|
|
{
|
2015-11-19 23:15:48 +01:00
|
|
|
gspWaitForEvent(GSPGPU_EVENT_VBlank0, true);
|
2015-04-17 19:45:07 +01:00
|
|
|
return true;
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
lcd_bottom = settings->bools.video_3ds_lcd_bottom;
|
|
|
|
if (lcd_bottom != ctr_bottom_screen_enabled)
|
2021-09-06 01:16:16 +02:00
|
|
|
{
|
2021-09-28 12:56:10 +02:00
|
|
|
if (retroarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
2021-09-06 01:16:16 +02:00
|
|
|
{
|
|
|
|
ctr_set_bottom_screen_enable(lcd_bottom, false);
|
|
|
|
if (lcd_bottom)
|
|
|
|
ctr->refresh_bottom_menu = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ctr_bottom_screen_enabled = lcd_bottom;
|
|
|
|
}
|
2021-09-04 01:14:03 +09:00
|
|
|
bottom_menu_control(data, lcd_bottom);
|
2015-09-28 14:54:48 +01:00
|
|
|
|
2016-09-30 16:16:18 +01:00
|
|
|
if (ctr->p3d_event_pending)
|
|
|
|
{
|
|
|
|
gspWaitForEvent(GSPGPU_EVENT_P3D, false);
|
|
|
|
ctr->p3d_event_pending = false;
|
|
|
|
}
|
|
|
|
if (ctr->ppf_event_pending)
|
|
|
|
{
|
|
|
|
gspWaitForEvent(GSPGPU_EVENT_PPF, false);
|
|
|
|
ctr->ppf_event_pending = false;
|
|
|
|
}
|
2016-10-10 22:25:25 +01:00
|
|
|
#ifndef HAVE_THREADS
|
2020-02-21 20:45:06 +01:00
|
|
|
if (task_queue_find(&ctr_tasks_finder_data))
|
2016-10-10 22:25:25 +01:00
|
|
|
{
|
2017-01-19 16:30:40 +01:00
|
|
|
#if 0
|
|
|
|
ctr->vsync_event_pending = true;
|
|
|
|
#endif
|
2020-06-26 20:00:19 +02:00
|
|
|
while (ctr->vsync_event_pending)
|
2016-10-10 22:25:25 +01:00
|
|
|
{
|
2017-05-14 20:43:39 +02:00
|
|
|
task_queue_check();
|
2016-10-10 22:25:25 +01:00
|
|
|
svcSleepThread(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2015-04-17 19:45:07 +01:00
|
|
|
if (ctr->vsync)
|
2019-04-16 15:41:55 +01:00
|
|
|
{
|
|
|
|
/* If we are running at the display refresh rate,
|
|
|
|
* then all is well - just wait on the *current* VBlank0
|
|
|
|
* event and carry on.
|
|
|
|
*
|
|
|
|
* If we are running at below the display refresh rate,
|
|
|
|
* then we have problems: frame updates will happen
|
|
|
|
* entirely out of sync with VBlank0 events. To elaborate,
|
|
|
|
* we'll wait for a VBlank0 here, but it will already have
|
|
|
|
* happened partway through the previous frame. So it's:
|
|
|
|
* 'oh good - let's render the current frame', but the next
|
|
|
|
* VBlank0 will occur in less time than it takes to draw the
|
|
|
|
* current frame, resulting in 'overlap' and screen tearing.
|
|
|
|
*
|
|
|
|
* This seems to be a consequence of using the GPU directly.
|
|
|
|
* Other 3DS homebrew typically uses the ctrulib function
|
|
|
|
* gfxSwapBuffers(), which ensures an immediate buffer
|
|
|
|
* swap every time, and no tearing. We can't do this:
|
|
|
|
* instead, we use a variant of the ctrulib function
|
|
|
|
* gfxSwapBuffersGpu(), which seems to send a notification,
|
|
|
|
* and the swap happens when it happens...
|
|
|
|
*
|
|
|
|
* I don't know how to fix this 'properly' (probably needs
|
|
|
|
* some low level rewriting, maybe switching to an implementation
|
|
|
|
* based on citro3d), but I can at least implement a hack/workaround
|
|
|
|
* that allows 50Hz content to be run without tearing. This involves
|
|
|
|
* the following:
|
|
|
|
*
|
|
|
|
* If content frame rate is more than 10% lower than the 3DS
|
|
|
|
* display refresh rate, don't wait on the *current* VBlank0
|
|
|
|
* event (because it is 'tainted'), but instead wait on the
|
|
|
|
* *next* VBlank0 event (which will ensure we have enough time
|
|
|
|
* to write/flush the display buffers).
|
|
|
|
*
|
|
|
|
* This fixes screen tearing, but it has a significant impact on
|
|
|
|
* performance...
|
|
|
|
* */
|
|
|
|
bool next_event = false;
|
|
|
|
struct retro_system_av_info *av_info = video_viewport_get_system_av_info();
|
|
|
|
if (av_info)
|
2020-03-09 05:18:02 +01:00
|
|
|
next_event = av_info->timing.fps < video_refresh_rate * 0.9f;
|
2019-04-16 15:41:55 +01:00
|
|
|
gspWaitForEvent(GSPGPU_EVENT_VBlank0, next_event);
|
|
|
|
}
|
2015-04-17 19:45:07 +01:00
|
|
|
|
2016-10-10 22:25:25 +01:00
|
|
|
ctr->vsync_event_pending = true;
|
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
/* Internal counters/statistics
|
|
|
|
* > This is only required if the bottom screen is enabled */
|
|
|
|
if (ctr_bottom_screen_enabled)
|
2015-04-02 04:00:26 +01:00
|
|
|
{
|
2019-04-15 17:05:55 +01:00
|
|
|
frames++;
|
|
|
|
currentTick = svcGetSystemTick();
|
|
|
|
diff = currentTick - lastTick;
|
|
|
|
if(diff > CTR_CPU_TICKS_PER_SECOND)
|
|
|
|
{
|
|
|
|
fps = (float)frames * ((float) CTR_CPU_TICKS_PER_SECOND / (float) diff);
|
|
|
|
lastTick = currentTick;
|
|
|
|
frames = 0;
|
|
|
|
}
|
2015-04-02 04:00:26 +01:00
|
|
|
|
2015-11-02 01:24:11 +01:00
|
|
|
#ifdef CTR_INSPECT_MEMORY_USAGE
|
2019-04-15 17:05:55 +01:00
|
|
|
uint32_t ctr_get_stack_usage(void);
|
|
|
|
void ctr_linear_get_stats(void);
|
|
|
|
extern u32 __linear_heap_size;
|
|
|
|
extern u32 __heap_size;
|
|
|
|
|
|
|
|
MemInfo mem_info;
|
|
|
|
PageInfo page_info;
|
|
|
|
u32 query_addr = 0x08000000;
|
|
|
|
printf(PRINTFPOS(0,0));
|
|
|
|
while (query_addr < 0x40000000)
|
|
|
|
{
|
|
|
|
svcQueryMemory(&mem_info, &page_info, query_addr);
|
|
|
|
printf("0x%08X --> 0x%08X (0x%08X) \n", mem_info.base_addr, mem_info.base_addr + mem_info.size, mem_info.size);
|
|
|
|
query_addr = mem_info.base_addr + mem_info.size;
|
|
|
|
if(query_addr == 0x1F000000)
|
|
|
|
query_addr = 0x30000000;
|
|
|
|
}
|
2015-11-02 01:24:11 +01:00
|
|
|
|
2017-01-19 16:30:40 +01:00
|
|
|
#if 0
|
2019-04-15 17:05:55 +01:00
|
|
|
static u32* dummy_pointer;
|
|
|
|
if(total_frames == 500)
|
|
|
|
dummy_pointer = malloc(0x2000000);
|
|
|
|
if(total_frames == 1000)
|
|
|
|
free(dummy_pointer);
|
2017-01-19 16:30:40 +01:00
|
|
|
#endif
|
2015-11-02 01:24:11 +01:00
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
printf("========================================");
|
|
|
|
printf("0x%08X 0x%08X 0x%08X\n", __heap_size, gpuCmdBufOffset, (__linear_heap_size - linearSpaceFree()));
|
|
|
|
printf("fps: %8.4f frames: %i (%X)\n", fps, total_frames++, (__linear_heap_size - linearSpaceFree()));
|
|
|
|
printf("========================================");
|
|
|
|
u32 app_memory = *((u32*)0x1FF80040);
|
|
|
|
u64 mem_used;
|
|
|
|
svcGetSystemInfo(&mem_used, 0, 1);
|
|
|
|
printf("total mem : 0x%08X \n", app_memory);
|
|
|
|
printf("used: 0x%08X free: 0x%08X \n", (u32)mem_used, app_memory - (u32)mem_used);
|
|
|
|
static u32 stack_usage = 0;
|
|
|
|
extern u32 __stack_bottom;
|
|
|
|
if(!(total_frames & 0x3F))
|
|
|
|
stack_usage = ctr_get_stack_usage();
|
|
|
|
printf("stack total:0x%08X used: 0x%08X\n", 0x10000000 - __stack_bottom, stack_usage);
|
|
|
|
|
|
|
|
printf("========================================");
|
|
|
|
ctr_linear_get_stats();
|
|
|
|
printf("========================================");
|
2015-11-02 01:24:11 +01:00
|
|
|
|
|
|
|
#else
|
2019-04-15 17:05:55 +01:00
|
|
|
printf(PRINTFPOS(29,0)"fps: %8.4f frames: %i\r", fps, total_frames++);
|
2015-11-02 01:24:11 +01:00
|
|
|
#endif
|
2019-04-15 17:05:55 +01:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
2015-04-02 04:00:26 +01:00
|
|
|
|
2015-09-14 00:19:38 +01:00
|
|
|
if (ctr->should_resize)
|
2020-03-10 19:52:05 +01:00
|
|
|
ctr_update_viewport(ctr, settings,
|
|
|
|
custom_vp_x,
|
|
|
|
custom_vp_y,
|
|
|
|
custom_vp_width,
|
|
|
|
custom_vp_height
|
|
|
|
);
|
2015-09-14 00:19:38 +01:00
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
if (ctr->refresh_bottom_menu)
|
|
|
|
{
|
|
|
|
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
|
|
|
|
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
0x201,
|
|
|
|
(u32*)ctr->drawbuffers.bottom, 0x00000000,
|
|
|
|
(u32*)ctr->drawbuffers.bottom + 2 * CTR_BOTTOM_FRAMEBUFFER_WIDTH * CTR_BOTTOM_FRAMEBUFFER_HEIGHT,
|
|
|
|
0x201);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctrGuSetMemoryFill(true, (u32*)ctr->drawbuffers.top.left, 0x00000000,
|
|
|
|
(u32*)ctr->drawbuffers.top.left + 2 * CTR_TOP_FRAMEBUFFER_WIDTH * CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
0x201, NULL, 0x00000000,
|
|
|
|
0,
|
|
|
|
0x201);
|
|
|
|
}
|
2015-04-13 01:50:00 +01:00
|
|
|
|
2015-04-08 18:59:41 +01:00
|
|
|
GPUCMD_SetBufferOffset(0);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-13 01:50:00 +01:00
|
|
|
if (width > ctr->texture_width)
|
|
|
|
width = ctr->texture_width;
|
|
|
|
if (height > ctr->texture_height)
|
|
|
|
height = ctr->texture_height;
|
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
if(frame)
|
2015-04-02 04:00:26 +01:00
|
|
|
{
|
2015-10-02 04:59:16 +01:00
|
|
|
if(((((u32)(frame)) >= 0x14000000 && ((u32)(frame)) < 0x40000000)) /* frame in linear memory */
|
2015-04-13 01:50:00 +01:00
|
|
|
&& !((u32)frame & 0x7F) /* 128-byte aligned */
|
2015-11-12 15:00:53 +01:00
|
|
|
&& !(pitch & 0xF) /* 16-byte aligned */
|
|
|
|
&& (pitch > 0x40))
|
2015-04-02 04:00:26 +01:00
|
|
|
{
|
2015-04-13 01:50:00 +01:00
|
|
|
/* can copy the buffer directly with the GPU */
|
2017-01-19 16:30:40 +01:00
|
|
|
#if 0
|
|
|
|
GSPGPU_FlushDataCache(frame, pitch * height);
|
|
|
|
#endif
|
2015-11-24 12:02:02 +01:00
|
|
|
ctrGuSetCommandList_First(true,(void*)frame, pitch * height,0,0,0,0);
|
2015-11-24 11:25:28 +01:00
|
|
|
ctrGuCopyImage(true, frame, pitch / (ctr->rgb32? 4: 2), height, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, false,
|
2017-01-19 16:30:40 +01:00
|
|
|
ctr->texture_swizzled, ctr->texture_width, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, true);
|
2015-04-02 04:00:26 +01:00
|
|
|
}
|
2015-04-13 01:50:00 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
2019-04-15 17:05:55 +01:00
|
|
|
uint8_t *dst = (uint8_t*)ctr->texture_linear;
|
2015-09-20 10:02:47 +02:00
|
|
|
const uint8_t *src = frame;
|
|
|
|
|
2015-04-13 01:50:00 +01:00
|
|
|
for (i = 0; i < height; i++)
|
|
|
|
{
|
2015-10-20 16:03:39 +01:00
|
|
|
memcpy(dst, src, width * (ctr->rgb32? 4: 2));
|
|
|
|
dst += ctr->texture_width * (ctr->rgb32? 4: 2);
|
2015-04-13 01:50:00 +01:00
|
|
|
src += pitch;
|
|
|
|
}
|
2015-10-21 15:41:06 +01:00
|
|
|
GSPGPU_FlushDataCache(ctr->texture_linear,
|
2015-10-20 16:03:39 +01:00
|
|
|
ctr->texture_width * ctr->texture_height * (ctr->rgb32? 4: 2));
|
2015-04-13 01:50:00 +01:00
|
|
|
|
2015-10-20 16:03:39 +01:00
|
|
|
ctrGuCopyImage(false, ctr->texture_linear, ctr->texture_width, ctr->texture_height, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, false,
|
|
|
|
ctr->texture_swizzled, ctr->texture_width, ctr->rgb32 ? CTRGU_RGBA8: CTRGU_RGB565, true);
|
2015-04-05 20:40:35 +01:00
|
|
|
|
2015-04-13 01:50:00 +01:00
|
|
|
}
|
2015-04-05 20:40:35 +01:00
|
|
|
|
2016-04-17 15:30:44 +01:00
|
|
|
ctr->frame_coords->u0 = 0;
|
|
|
|
ctr->frame_coords->v0 = 0;
|
|
|
|
ctr->frame_coords->u1 = width;
|
|
|
|
ctr->frame_coords->v1 = height;
|
2015-11-12 15:00:53 +01:00
|
|
|
GSPGPU_FlushDataCache(ctr->frame_coords, sizeof(ctr_vertex_t));
|
2015-04-13 01:50:00 +01:00
|
|
|
}
|
2015-04-05 20:40:35 +01:00
|
|
|
|
2020-10-27 21:13:19 -07:00
|
|
|
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, ctr->rotation & 1);
|
Fix 3DS screen flickering when OSD is enabled
On the 3DS, for some cores, the screen will flicker if OSD is enabled,
and sometimes when going in and out of the menu.
As far as I can tell, this happens when a frame is dup'd, and we send
0x0 as the frame to the gfx driver. When that happens, we still draw
the OSD, using a vertex shader to transform and render it at the right
size.
When the frame is 0x0, though, the vertex shader uniforms are never
_reset_ to redraw the previous frame, so it's drawn with different
params, and gets drawn the wrong size. It will draw as the correct
size when the correct vertex shader uniforms are set, and the
incorrect size when the incorrect uniforms are set, causing
flickering.
At least, that's what I think is happening. Forcing the vertex shader
to be set regardless of whether the frame data is set fixes it, at
least during some light testing with PCSX.
2019-10-05 14:21:42 -07:00
|
|
|
ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->scale_vector, 1);
|
2015-04-13 01:50:00 +01:00
|
|
|
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->texture_swizzled), ctr->texture_width, ctr->texture_height,
|
2015-09-14 00:19:38 +01:00
|
|
|
(ctr->smooth? GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR)
|
|
|
|
: GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST)) |
|
2015-04-13 01:50:00 +01:00
|
|
|
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
2015-10-20 16:03:39 +01:00
|
|
|
ctr->rgb32 ? GPU_RGBA8: GPU_RGB565);
|
2015-04-05 20:40:35 +01:00
|
|
|
|
2020-02-19 00:23:33 +01:00
|
|
|
ctr_check_3D_slider(ctr, (ctr_video_mode_enum)disp_mode);
|
2016-04-18 15:55:34 +01:00
|
|
|
|
2017-01-19 16:30:40 +01:00
|
|
|
/* ARGB --> RGBA */
|
2015-10-20 16:03:39 +01:00
|
|
|
if (ctr->rgb32)
|
|
|
|
{
|
|
|
|
GPU_SetTexEnv(0,
|
|
|
|
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, 0),
|
2016-10-04 20:38:00 +01:00
|
|
|
GPU_CONSTANT,
|
2015-10-20 16:03:39 +01:00
|
|
|
GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_G, 0, 0),
|
2016-10-04 20:38:00 +01:00
|
|
|
0,
|
|
|
|
GPU_MODULATE, GPU_REPLACE,
|
|
|
|
0xFF0000FF);
|
2015-10-20 16:03:39 +01:00
|
|
|
GPU_SetTexEnv(1,
|
|
|
|
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_PREVIOUS),
|
2016-10-04 20:38:00 +01:00
|
|
|
GPU_PREVIOUS,
|
2015-10-20 16:03:39 +01:00
|
|
|
GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_B, 0, 0),
|
2016-10-04 20:38:00 +01:00
|
|
|
0,
|
|
|
|
GPU_MULTIPLY_ADD, GPU_REPLACE,
|
2015-10-20 16:03:39 +01:00
|
|
|
0x00FF00);
|
|
|
|
GPU_SetTexEnv(2,
|
|
|
|
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_PREVIOUS),
|
2016-10-04 20:38:00 +01:00
|
|
|
GPU_PREVIOUS,
|
2015-10-20 16:03:39 +01:00
|
|
|
GPU_TEVOPERANDS(GPU_TEVOP_RGB_SRC_ALPHA, 0, 0),
|
2016-10-04 20:38:00 +01:00
|
|
|
0,
|
|
|
|
GPU_MULTIPLY_ADD, GPU_REPLACE,
|
2015-10-20 16:03:39 +01:00
|
|
|
0xFF0000);
|
|
|
|
}
|
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
2016-04-17 20:10:21 +01:00
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
2020-06-02 10:28:00 +03:00
|
|
|
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240 ? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2016-04-18 15:55:34 +01:00
|
|
|
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
|
2016-04-17 20:10:21 +01:00
|
|
|
{
|
2016-04-18 15:55:34 +01:00
|
|
|
if (ctr->menu_texture_enable)
|
|
|
|
{
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(&ctr->frame_coords[1]));
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(&ctr->frame_coords[2]));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords));
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
}
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
|
2016-04-17 20:10:21 +01:00
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
CTR_TOP_FRAMEBUFFER_WIDTH);
|
|
|
|
}
|
2016-04-18 15:55:34 +01:00
|
|
|
else
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->frame_coords));
|
|
|
|
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2015-10-20 16:03:39 +01:00
|
|
|
/* restore */
|
|
|
|
if (ctr->rgb32)
|
|
|
|
{
|
2016-04-16 22:38:13 +01:00
|
|
|
GPU_SetTexEnv(0, GPU_TEXTURE0, GPU_TEXTURE0, 0, 0, GPU_REPLACE, GPU_REPLACE, 0);
|
|
|
|
GPU_SetTexEnv(1, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
|
|
|
GPU_SetTexEnv(2, GPU_PREVIOUS, GPU_PREVIOUS, 0, 0, 0, 0, 0);
|
2015-10-20 16:03:39 +01:00
|
|
|
}
|
|
|
|
|
2018-03-23 17:43:49 +01:00
|
|
|
#ifdef HAVE_MENU
|
2015-04-05 20:40:35 +01:00
|
|
|
if (ctr->menu_texture_enable)
|
|
|
|
{
|
2016-10-13 12:16:07 +01:00
|
|
|
if(ctr->menu_texture_frame_enable)
|
|
|
|
{
|
|
|
|
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->menu.texture_swizzled), ctr->menu.texture_width, ctr->menu.texture_height,
|
|
|
|
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
|
|
|
|
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
|
|
|
GPU_RGBA4);
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2020-10-27 21:13:19 -07:00
|
|
|
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
2016-10-13 12:16:07 +01:00
|
|
|
ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->menu.scale_vector, 1);
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->menu.frame_coords));
|
2016-04-18 15:55:34 +01:00
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
GPU_SetViewport(NULL,
|
2016-10-13 12:16:07 +01:00
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
2016-04-17 20:10:21 +01:00
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
2020-06-02 10:28:00 +03:00
|
|
|
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240 ? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
|
2016-04-17 20:10:21 +01:00
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
2016-10-13 12:16:07 +01:00
|
|
|
|
|
|
|
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
|
|
|
|
{
|
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
|
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
CTR_TOP_FRAMEBUFFER_WIDTH);
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
}
|
2016-04-17 20:10:21 +01:00
|
|
|
}
|
2016-09-29 20:14:12 +01:00
|
|
|
|
|
|
|
ctr->msg_rendering_enabled = true;
|
2021-09-28 10:27:00 +02:00
|
|
|
#ifdef HAVE_MENU
|
2020-05-19 16:20:43 +02:00
|
|
|
menu_driver_frame(menu_is_alive, video_info);
|
2021-09-28 10:27:00 +02:00
|
|
|
#endif
|
2016-09-29 20:14:12 +01:00
|
|
|
ctr->msg_rendering_enabled = false;
|
2015-04-05 20:40:35 +01:00
|
|
|
}
|
2020-03-09 16:15:53 +01:00
|
|
|
else if (statistics_show)
|
2018-03-23 17:43:49 +01:00
|
|
|
{
|
|
|
|
if (osd_params)
|
|
|
|
{
|
2020-03-10 03:24:59 +01:00
|
|
|
font_driver_render_msg(ctr, stat_text,
|
2020-03-09 16:15:53 +01:00
|
|
|
(const struct font_params*)osd_params, NULL);
|
2018-03-23 17:43:49 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2015-04-05 20:40:35 +01:00
|
|
|
|
2021-04-04 22:50:59 +02:00
|
|
|
#ifdef HAVE_OVERLAY
|
|
|
|
if (ctr->overlay_enabled)
|
|
|
|
ctr_render_overlay(ctr);
|
|
|
|
#endif
|
|
|
|
|
2021-03-23 22:03:44 +01:00
|
|
|
#ifdef HAVE_GFX_WIDGETS
|
|
|
|
if (widgets_active)
|
|
|
|
gfx_widgets_frame(video_info);
|
|
|
|
#endif
|
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
#ifndef CONSOLE_LOG
|
|
|
|
if (ctr_bottom_screen_enabled &&
|
2021-09-28 12:56:10 +02:00
|
|
|
retroarch_ctl(RARCH_CTL_CORE_IS_RUNNING, NULL))
|
2021-09-06 01:16:16 +02:00
|
|
|
{
|
|
|
|
if ( !ctr->bottom_is_idle )
|
|
|
|
{
|
|
|
|
ctr_render_bottom_screen(ctr);
|
|
|
|
|
|
|
|
if ( ctr->bottom_check_idle )
|
|
|
|
ctr_set_bottom_screen_idle(ctr);
|
|
|
|
}
|
|
|
|
}
|
2021-09-04 01:14:03 +09:00
|
|
|
#endif
|
|
|
|
|
2016-11-20 17:51:16 +01:00
|
|
|
if (msg)
|
2020-03-10 03:24:59 +01:00
|
|
|
font_driver_render_msg(ctr, msg, NULL, NULL);
|
2016-09-29 20:14:12 +01:00
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
GPU_FinishDrawing();
|
2017-12-25 08:51:50 +01:00
|
|
|
GPU_Finalize();
|
2015-04-13 01:50:00 +01:00
|
|
|
ctrGuFlushAndRun(true);
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-09-28 20:59:54 +01:00
|
|
|
ctrGuDisplayTransfer(true, ctr->drawbuffers.top.left,
|
2016-04-17 20:10:21 +01:00
|
|
|
240,
|
2020-06-02 10:28:00 +03:00
|
|
|
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240 ? 800 : 400,
|
2016-04-17 20:10:21 +01:00
|
|
|
CTRGU_RGBA8,
|
2019-04-15 17:05:55 +01:00
|
|
|
gfxTopLeftFramebuffers[ctr->current_buffer_top], 240, CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE);
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2020-06-02 10:28:00 +03:00
|
|
|
if ((ctr->video_mode == CTR_VIDEO_MODE_2D_400X240) || (ctr->video_mode == CTR_VIDEO_MODE_3D))
|
2016-09-28 20:59:54 +01:00
|
|
|
ctrGuDisplayTransfer(true, ctr->drawbuffers.top.right,
|
2016-04-17 20:10:21 +01:00
|
|
|
240,
|
|
|
|
400,
|
|
|
|
CTRGU_RGBA8,
|
2019-04-15 17:05:55 +01:00
|
|
|
gfxTopRightFramebuffers[ctr->current_buffer_top], 240, CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE);
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2021-09-04 01:14:03 +09:00
|
|
|
#ifndef CONSOLE_LOG
|
2021-09-06 01:16:16 +02:00
|
|
|
if (ctr->refresh_bottom_menu)
|
|
|
|
ctrGuDisplayTransfer(true,
|
|
|
|
ctr->drawbuffers.bottom,
|
|
|
|
240,
|
|
|
|
320,
|
|
|
|
CTRGU_RGBA8,
|
|
|
|
gfxBottomFramebuffers[ctr->current_buffer_bottom], 240, CTRGU_RGB8, CTRGU_MULTISAMPLE_NONE);
|
2021-09-04 01:14:03 +09:00
|
|
|
#endif
|
2017-01-19 16:30:40 +01:00
|
|
|
/* Swap buffers : */
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2019-09-19 20:49:26 -07:00
|
|
|
#ifdef USE_CTRULIB_2
|
2021-09-04 01:14:03 +09:00
|
|
|
u32 *buf0, *buf1, *bottom;
|
2019-09-19 20:49:26 -07:00
|
|
|
u32 stride;
|
|
|
|
|
|
|
|
buf0 = (u32*)gfxTopLeftFramebuffers[ctr->current_buffer_top];
|
|
|
|
|
|
|
|
if(ctr->video_mode == CTR_VIDEO_MODE_2D_800X240)
|
|
|
|
{
|
|
|
|
buf1 = (u32*)(gfxTopLeftFramebuffers[ctr->current_buffer_top] + 240 * 3);
|
|
|
|
stride = 240 * 3 * 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ctr->enable_3d)
|
|
|
|
buf1 = (u32*)gfxTopRightFramebuffers[ctr->current_buffer_top];
|
|
|
|
else
|
|
|
|
buf1 = buf0;
|
|
|
|
|
|
|
|
stride = 240 * 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
u8 bit5 = (ctr->enable_3d != 0);
|
|
|
|
|
|
|
|
gspPresentBuffer(GFX_TOP, ctr->current_buffer_top, buf0, buf1,
|
|
|
|
stride, (1<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES);
|
2021-09-04 01:14:03 +09:00
|
|
|
|
|
|
|
#ifndef CONSOLE_LOG
|
|
|
|
if (ctr->refresh_bottom_menu)
|
|
|
|
{
|
|
|
|
bottom = (u32*)gfxBottomFramebuffers[ctr->current_buffer_bottom];
|
|
|
|
stride = 240 * 3;
|
|
|
|
gspPresentBuffer(GFX_BOTTOM, ctr->current_buffer_bottom, bottom, bottom,
|
|
|
|
stride, GSP_BGR8_OES);
|
|
|
|
}
|
2021-09-06 01:16:16 +02:00
|
|
|
else if (ctr->bottom_is_fading)
|
|
|
|
{
|
|
|
|
gfxScreenSwapBuffers(GFX_BOTTOM,false);
|
|
|
|
}
|
2021-09-04 01:14:03 +09:00
|
|
|
#endif
|
2019-09-19 20:49:26 -07:00
|
|
|
#else
|
2017-01-25 16:53:06 +01:00
|
|
|
topFramebufferInfo.
|
|
|
|
active_framebuf = ctr->current_buffer_top;
|
|
|
|
topFramebufferInfo.
|
|
|
|
framebuf0_vaddr = (u32*)gfxTopLeftFramebuffers[ctr->current_buffer_top];
|
|
|
|
|
2020-06-02 10:28:00 +03:00
|
|
|
if(ctr->video_mode == CTR_VIDEO_MODE_2D_800X240)
|
2016-04-17 20:10:21 +01:00
|
|
|
{
|
2017-01-25 16:53:06 +01:00
|
|
|
topFramebufferInfo.
|
|
|
|
framebuf1_vaddr = (u32*)(gfxTopLeftFramebuffers[ctr->current_buffer_top] + 240 * 3);
|
|
|
|
topFramebufferInfo.
|
|
|
|
framebuf_widthbytesize = 240 * 3 * 2;
|
2016-04-17 20:10:21 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-15 17:05:55 +01:00
|
|
|
if (ctr->enable_3d)
|
|
|
|
topFramebufferInfo.
|
|
|
|
framebuf1_vaddr = (u32*)gfxTopRightFramebuffers[ctr->current_buffer_top];
|
|
|
|
else
|
|
|
|
topFramebufferInfo.
|
2021-09-04 01:14:03 +09:00
|
|
|
framebuf1_vaddr = topFramebufferInfo.framebuf0_vaddr;
|
2019-04-15 17:05:55 +01:00
|
|
|
|
2017-01-25 16:53:06 +01:00
|
|
|
topFramebufferInfo.
|
|
|
|
framebuf_widthbytesize = 240 * 3;
|
2016-04-17 20:10:21 +01:00
|
|
|
}
|
|
|
|
|
2019-04-15 17:05:55 +01:00
|
|
|
u8 bit5 = (ctr->enable_3d != 0);
|
|
|
|
topFramebufferInfo.format = (1<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES;
|
2017-01-25 16:53:06 +01:00
|
|
|
topFramebufferInfo.
|
|
|
|
framebuf_dispselect = ctr->current_buffer_top;
|
|
|
|
topFramebufferInfo.unk = 0x00000000;
|
2016-04-17 20:10:21 +01:00
|
|
|
|
2017-01-25 16:53:06 +01:00
|
|
|
u8* framebufferInfoHeader = gfxSharedMemory+0x200+gfxThreadID*0x80;
|
2017-12-11 23:55:31 -08:00
|
|
|
GSPGPU_FramebufferInfo*
|
2017-01-25 16:53:06 +01:00
|
|
|
framebufferInfo = (GSPGPU_FramebufferInfo*)&framebufferInfoHeader[0x4];
|
|
|
|
framebufferInfoHeader[0x0] ^= 1;
|
2016-04-17 20:10:21 +01:00
|
|
|
framebufferInfo[framebufferInfoHeader[0x0]] = topFramebufferInfo;
|
2017-01-25 16:53:06 +01:00
|
|
|
framebufferInfoHeader[0x1] = 1;
|
2021-09-04 01:14:03 +09:00
|
|
|
|
|
|
|
#ifndef CONSOLE_LOG
|
|
|
|
if (ctr->refresh_bottom_menu)
|
|
|
|
{
|
|
|
|
bottomFramebufferInfo.
|
|
|
|
active_framebuf = ctr->current_buffer_bottom;
|
|
|
|
bottomFramebufferInfo.
|
|
|
|
framebuf0_vaddr = (u32*)gfxBottomFramebuffers[
|
|
|
|
ctr->current_buffer_bottom];
|
|
|
|
|
|
|
|
bottomFramebufferInfo.
|
|
|
|
framebuf1_vaddr = (u32*)(gfxBottomFramebuffers[
|
|
|
|
ctr->current_buffer_bottom] + 240 * 3);
|
|
|
|
bottomFramebufferInfo.
|
|
|
|
framebuf_widthbytesize = 240 * 3;
|
|
|
|
|
|
|
|
bottomFramebufferInfo.format = GSP_BGR8_OES;
|
|
|
|
bottomFramebufferInfo.
|
|
|
|
framebuf_dispselect = ctr->current_buffer_bottom;
|
|
|
|
bottomFramebufferInfo.unk = 0x00000000;
|
|
|
|
|
|
|
|
u8* framebufferInfoHeader2 = gfxSharedMemory+0x200+gfxThreadID*0x80+0x40;
|
|
|
|
GSPGPU_FramebufferInfo*
|
|
|
|
framebufferInfo2 =
|
|
|
|
(GSPGPU_FramebufferInfo*)&framebufferInfoHeader2[0x4];
|
|
|
|
framebufferInfoHeader2[0x0] ^= 1;
|
|
|
|
framebufferInfo2[framebufferInfoHeader2[0x0]] = bottomFramebufferInfo;
|
|
|
|
framebufferInfoHeader2[0x1] = 1;
|
|
|
|
}
|
|
|
|
#endif
|
2019-09-19 20:49:26 -07:00
|
|
|
#endif
|
2017-01-25 16:53:06 +01:00
|
|
|
ctr->current_buffer_top ^= 1;
|
2021-09-06 01:16:16 +02:00
|
|
|
if (ctr->refresh_bottom_menu || ctr->bottom_is_fading)
|
|
|
|
ctr->current_buffer_bottom ^= 1;
|
|
|
|
|
2017-01-25 16:53:06 +01:00
|
|
|
ctr->p3d_event_pending = true;
|
|
|
|
ctr->ppf_event_pending = true;
|
2021-09-04 01:14:03 +09:00
|
|
|
ctr->refresh_bottom_menu = false;
|
2015-05-09 15:41:10 +02:00
|
|
|
|
2015-04-01 22:14:13 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-16 22:26:07 +01:00
|
|
|
static void ctr_set_nonblock_state(void* data, bool toggle,
|
|
|
|
bool a, unsigned b)
|
2015-04-01 22:14:13 +01:00
|
|
|
{
|
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
ctr->vsync = !toggle;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ctr_alive(void* data)
|
|
|
|
{
|
|
|
|
(void)data;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ctr_focus(void* data)
|
|
|
|
{
|
|
|
|
(void)data;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ctr_suppress_screensaver(void* data, bool enable)
|
|
|
|
{
|
|
|
|
(void)data;
|
|
|
|
(void)enable;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_free(void* data)
|
|
|
|
{
|
2021-09-04 01:14:03 +09:00
|
|
|
unsigned i;
|
2015-04-01 22:14:13 +01:00
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (!ctr)
|
|
|
|
return;
|
|
|
|
|
2015-10-06 19:56:11 +01:00
|
|
|
aptUnhook(&ctr->lcd_aptHook);
|
2016-10-10 22:25:25 +01:00
|
|
|
gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL, true);
|
2015-04-05 20:40:35 +01:00
|
|
|
shaderProgramFree(&ctr->shader);
|
|
|
|
DVLB_Free(ctr->dvlb);
|
2016-09-28 20:59:54 +01:00
|
|
|
vramFree(ctr->drawbuffers.top.left);
|
2021-09-04 01:14:03 +09:00
|
|
|
vramFree(ctr->drawbuffers.bottom);
|
|
|
|
for (i = 0; i < CTR_TEXTURE_LAST; i++)
|
|
|
|
{
|
|
|
|
struct ctr_bottom_texture_data *o = &ctr->bottom_textures[i];
|
|
|
|
ctr_texture_t *texture = (ctr_texture_t *) o->texture;
|
|
|
|
if (texture)
|
|
|
|
{
|
|
|
|
linearFree(texture->data);
|
|
|
|
linearFree(o->frame_coords);
|
|
|
|
o->texture = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(ctr->bottom_textures);
|
2015-04-05 20:40:35 +01:00
|
|
|
linearFree(ctr->display_list);
|
|
|
|
linearFree(ctr->texture_linear);
|
|
|
|
linearFree(ctr->texture_swizzled);
|
|
|
|
linearFree(ctr->frame_coords);
|
|
|
|
linearFree(ctr->menu.texture_linear);
|
|
|
|
linearFree(ctr->menu.texture_swizzled);
|
|
|
|
linearFree(ctr->menu.frame_coords);
|
2016-09-29 20:14:12 +01:00
|
|
|
linearFree(ctr->vertex_cache.buffer);
|
2015-04-05 20:40:35 +01:00
|
|
|
linearFree(ctr);
|
2017-01-23 01:37:19 +01:00
|
|
|
#if 0
|
|
|
|
gfxExit();
|
|
|
|
#endif
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
static void ctr_set_texture_frame(void* data, const void* frame, bool rgb32,
|
|
|
|
unsigned width, unsigned height, float alpha)
|
|
|
|
{
|
2015-04-05 20:40:35 +01:00
|
|
|
int i;
|
2015-04-01 22:14:13 +01:00
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
2015-04-05 20:40:35 +01:00
|
|
|
int line_width = width;
|
|
|
|
(void)rgb32;
|
|
|
|
(void)alpha;
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-10-04 15:49:55 +01:00
|
|
|
if(!ctr || !frame)
|
|
|
|
return;
|
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
if (line_width > ctr->menu.texture_width)
|
|
|
|
line_width = ctr->menu.texture_width;
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2015-04-05 20:40:35 +01:00
|
|
|
if (height > (unsigned)ctr->menu.texture_height)
|
|
|
|
height = (unsigned)ctr->menu.texture_height;
|
2015-04-01 22:14:13 +01:00
|
|
|
|
2016-10-04 15:49:55 +01:00
|
|
|
const uint16_t* src = frame;
|
|
|
|
uint16_t* dst = (uint16_t*)ctr->menu.texture_linear;
|
2015-04-05 20:40:35 +01:00
|
|
|
for (i = 0; i < height; i++)
|
|
|
|
{
|
|
|
|
memcpy(dst, src, line_width * sizeof(uint16_t));
|
|
|
|
dst += ctr->menu.texture_width;
|
|
|
|
src += width;
|
|
|
|
}
|
2015-04-08 18:59:41 +01:00
|
|
|
|
|
|
|
ctr->menu.frame_coords->x0 = (CTR_TOP_FRAMEBUFFER_WIDTH - width) / 2;
|
|
|
|
ctr->menu.frame_coords->y0 = (CTR_TOP_FRAMEBUFFER_HEIGHT - height) / 2;
|
|
|
|
ctr->menu.frame_coords->x1 = ctr->menu.frame_coords->x0 + width;
|
|
|
|
ctr->menu.frame_coords->y1 = ctr->menu.frame_coords->y0 + height;
|
2016-04-17 15:30:44 +01:00
|
|
|
ctr->menu.frame_coords->u0 = 0;
|
|
|
|
ctr->menu.frame_coords->v0 = 0;
|
|
|
|
ctr->menu.frame_coords->u1 = width;
|
|
|
|
ctr->menu.frame_coords->v1 = height;
|
2015-10-21 15:41:06 +01:00
|
|
|
GSPGPU_FlushDataCache(ctr->menu.frame_coords, sizeof(ctr_vertex_t));
|
2016-10-13 12:16:07 +01:00
|
|
|
ctr->menu_texture_frame_enable = true;
|
|
|
|
GSPGPU_FlushDataCache(ctr->menu.texture_linear,
|
|
|
|
ctr->menu.texture_width * ctr->menu.texture_height * sizeof(uint16_t));
|
|
|
|
|
|
|
|
ctrGuCopyImage(false, ctr->menu.texture_linear, ctr->menu.texture_width, ctr->menu.texture_height, CTRGU_RGBA4444,false,
|
|
|
|
ctr->menu.texture_swizzled, ctr->menu.texture_width, CTRGU_RGBA4444, true);
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_set_texture_enable(void* data, bool state, bool full_screen)
|
|
|
|
{
|
|
|
|
(void) full_screen;
|
|
|
|
|
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
ctr->menu_texture_enable = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_set_rotation(void* data, unsigned rotation)
|
|
|
|
{
|
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (!ctr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ctr->rotation = rotation;
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->should_resize = true;
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
2020-03-04 23:36:22 -05:00
|
|
|
static void ctr_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling)
|
2015-04-01 22:14:13 +01:00
|
|
|
{
|
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
ctr->smooth = smooth;
|
|
|
|
}
|
|
|
|
|
2015-11-21 13:13:55 +01:00
|
|
|
static void ctr_set_aspect_ratio(void* data, unsigned aspect_ratio_idx)
|
2015-04-01 22:14:13 +01:00
|
|
|
{
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
2016-10-04 15:55:30 +01:00
|
|
|
if(!ctr)
|
|
|
|
return;
|
|
|
|
|
2019-08-12 12:52:40 +02:00
|
|
|
ctr->keep_aspect = true;
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr->should_resize = true;
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_apply_state_changes(void* data)
|
|
|
|
{
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
ctr->should_resize = true;
|
|
|
|
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_viewport_info(void* data, struct video_viewport* vp)
|
|
|
|
{
|
2015-09-14 00:19:38 +01:00
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
*vp = ctr->vp;
|
2015-04-01 22:14:13 +01:00
|
|
|
}
|
|
|
|
|
2016-09-29 20:14:12 +01:00
|
|
|
static uintptr_t ctr_load_texture(void *video_data, void *data,
|
|
|
|
bool threaded, enum texture_filter_type filter_type)
|
|
|
|
{
|
2020-07-27 10:15:28 +02:00
|
|
|
void* tmpdata;
|
|
|
|
ctr_texture_t *texture = NULL;
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)video_data;
|
2016-09-29 20:14:12 +01:00
|
|
|
struct texture_image *image = (struct texture_image*)data;
|
2020-07-27 10:15:28 +02:00
|
|
|
int size = image->width
|
|
|
|
* image->height * sizeof(uint32_t);
|
2016-09-29 20:14:12 +01:00
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
if ((size * 3) > linearSpaceFree())
|
2016-10-10 22:25:25 +01:00
|
|
|
return 0;
|
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
if (!ctr || !image || image->width > 2048 || image->height > 2048)
|
2016-10-08 01:17:48 +01:00
|
|
|
return 0;
|
2016-10-04 15:49:55 +01:00
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
texture = (ctr_texture_t*)
|
|
|
|
calloc(1, sizeof(ctr_texture_t));
|
2016-10-10 22:25:25 +01:00
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
texture->width = next_pow2(image->width);
|
|
|
|
texture->height = next_pow2(image->height);
|
|
|
|
texture->active_width = image->width;
|
|
|
|
texture->active_height = image->height;
|
|
|
|
texture->data = linearAlloc(
|
|
|
|
texture->width * texture->height * sizeof(uint32_t));
|
|
|
|
texture->type = filter_type;
|
2016-09-29 20:14:12 +01:00
|
|
|
|
2016-10-04 15:49:55 +01:00
|
|
|
if (!texture->data)
|
2016-09-29 20:14:12 +01:00
|
|
|
{
|
|
|
|
free(texture);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-07-27 10:15:28 +02:00
|
|
|
|
2016-10-10 22:25:25 +01:00
|
|
|
if ((image->width <= 32) || (image->height <= 32))
|
2016-09-29 20:14:12 +01:00
|
|
|
{
|
2016-10-10 22:25:25 +01:00
|
|
|
int i, j;
|
|
|
|
uint32_t* src = (uint32_t*)image->pixels;
|
|
|
|
|
|
|
|
for (j = 0; j < image->height; j++)
|
|
|
|
for (i = 0; i < image->width; i++)
|
|
|
|
{
|
2020-07-27 10:15:28 +02:00
|
|
|
((uint32_t*)texture->data)[ctrgu_swizzle_coords(i, j,
|
|
|
|
texture->width)] =
|
2021-04-27 01:58:41 +09:00
|
|
|
((*src << 8) & 0xFF000000)
|
|
|
|
| ((*src << 8) & 0x00FF0000)
|
|
|
|
| ((*src << 8) & 0x0000FF00)
|
|
|
|
| ((*src >> 24) & 0x000000FF);
|
2016-10-10 22:25:25 +01:00
|
|
|
src++;
|
|
|
|
}
|
2020-07-27 10:15:28 +02:00
|
|
|
GSPGPU_FlushDataCache(texture->data, texture->width
|
|
|
|
* texture->height * sizeof(uint32_t));
|
2016-09-29 20:14:12 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-27 10:15:28 +02:00
|
|
|
int i;
|
|
|
|
uint32_t *src = NULL;
|
|
|
|
uint32_t *dst = NULL;
|
|
|
|
|
|
|
|
tmpdata = linearAlloc(image->width
|
|
|
|
* image->height * sizeof(uint32_t));
|
2016-10-10 22:25:25 +01:00
|
|
|
if (!tmpdata)
|
|
|
|
{
|
|
|
|
free(texture->data);
|
|
|
|
free(texture);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-07-27 10:15:28 +02:00
|
|
|
|
|
|
|
src = (uint32_t*)image->pixels;
|
|
|
|
dst = (uint32_t*)tmpdata;
|
|
|
|
|
2016-09-29 20:14:12 +01:00
|
|
|
for (i = 0; i < image->width * image->height; i++)
|
|
|
|
{
|
2020-07-27 10:15:28 +02:00
|
|
|
*dst =
|
2021-04-27 01:58:41 +09:00
|
|
|
((*src << 8) & 0xFF000000)
|
|
|
|
| ((*src << 8) & 0x00FF0000)
|
|
|
|
| ((*src << 8) & 0x0000FF00)
|
|
|
|
| ((*src >> 24) & 0x000000FF);
|
2016-09-29 20:14:12 +01:00
|
|
|
dst++;
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
GSPGPU_FlushDataCache(tmpdata,
|
|
|
|
image->width * image->height * sizeof(uint32_t));
|
|
|
|
ctrGuCopyImage(true, tmpdata,
|
|
|
|
image->width, image->height, CTRGU_RGBA8, false,
|
|
|
|
texture->data, texture->width, CTRGU_RGBA8, true);
|
2016-09-30 16:16:18 +01:00
|
|
|
#if 0
|
|
|
|
gspWaitForEvent(GSPGPU_EVENT_PPF, false);
|
|
|
|
ctr->ppf_event_pending = false;
|
|
|
|
#else
|
|
|
|
ctr->ppf_event_pending = true;
|
|
|
|
#endif
|
2016-09-29 20:14:12 +01:00
|
|
|
linearFree(tmpdata);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (uintptr_t)texture;
|
|
|
|
}
|
|
|
|
|
2020-07-27 10:15:28 +02:00
|
|
|
static void ctr_unload_texture(void *data, bool threaded,
|
|
|
|
uintptr_t handle)
|
2016-09-29 20:14:12 +01:00
|
|
|
{
|
|
|
|
struct ctr_texture *texture = (struct ctr_texture*)handle;
|
2016-10-04 15:49:55 +01:00
|
|
|
|
2016-09-29 20:14:12 +01:00
|
|
|
if (!texture)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (texture->data)
|
|
|
|
{
|
2020-07-27 10:15:28 +02:00
|
|
|
if (((u32)texture->data & 0xFF000000) == 0x1F000000)
|
2016-09-29 20:14:12 +01:00
|
|
|
vramFree(texture->data);
|
|
|
|
else
|
|
|
|
linearFree(texture->data);
|
|
|
|
}
|
|
|
|
free(texture);
|
|
|
|
}
|
|
|
|
|
2021-04-04 22:50:59 +02:00
|
|
|
#ifdef HAVE_OVERLAY
|
|
|
|
static void ctr_overlay_tex_geom(void *data,
|
|
|
|
unsigned image, float x, float y, float w, float h)
|
|
|
|
{
|
2021-04-24 15:36:03 +02:00
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
2021-04-04 22:50:59 +02:00
|
|
|
struct ctr_overlay_data *o = NULL;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
o = (struct ctr_overlay_data *)&ctr->overlay[image];
|
|
|
|
|
|
|
|
if (!o)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// printf("tex_geom[%i]: %i, %i, %.6f, %.6f\n%.6f, %.6f, ", image, o->texture.width, o->texture.height,x,y,w,h);
|
|
|
|
|
|
|
|
o->frame_coords->u0 = x*o->texture.width;
|
|
|
|
o->frame_coords->v0 = y*o->texture.height;
|
|
|
|
o->frame_coords->u1 = w*o->texture.width;
|
|
|
|
o->frame_coords->v1 = h*o->texture.height;
|
|
|
|
|
|
|
|
// printf("tex_geom[%i]: %i, %i, %i, %i\n", image, o->frame_coords->u0,o->frame_coords->v0,o->frame_coords->u1,o->frame_coords->v1);
|
|
|
|
|
|
|
|
GSPGPU_FlushDataCache(o->frame_coords, sizeof(ctr_vertex_t));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_overlay_vertex_geom(void *data,
|
|
|
|
unsigned image, float x, float y, float w, float h)
|
|
|
|
{
|
2021-04-24 15:36:03 +02:00
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
2021-04-04 22:50:59 +02:00
|
|
|
struct ctr_overlay_data *o = NULL;
|
|
|
|
|
|
|
|
if (ctr)
|
|
|
|
o = (struct ctr_overlay_data *)&ctr->overlay[image];
|
|
|
|
|
|
|
|
if (!o)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// printf("vertex_geom[%i]: %.6f, %.6f, %.6f, %.6f, ", image, x,y,w,h);
|
|
|
|
|
|
|
|
o->frame_coords->x0 = x * CTR_TOP_FRAMEBUFFER_WIDTH;
|
|
|
|
o->frame_coords->y0 = y * CTR_TOP_FRAMEBUFFER_HEIGHT;
|
|
|
|
o->frame_coords->x1 = w * (o->frame_coords->x0 + o->texture.width);
|
|
|
|
o->frame_coords->y1 = h * (o->frame_coords->y0 + o->texture.height);
|
|
|
|
|
|
|
|
// printf("vertex_geom[%i]: %i, %i, %i, %i\n", image, o->frame_coords->x0,o->frame_coords->y0,o->frame_coords->x1,o->frame_coords->y1);
|
|
|
|
|
|
|
|
GSPGPU_FlushDataCache(o->frame_coords, sizeof(ctr_vertex_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool ctr_overlay_load(void *data,
|
|
|
|
const void *image_data, unsigned num_images)
|
|
|
|
{
|
|
|
|
void* tmpdata;
|
|
|
|
unsigned i, j;
|
|
|
|
ctr_texture_t *texture = NULL;
|
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
|
|
|
struct texture_image *images = (struct texture_image *)image_data;
|
|
|
|
|
|
|
|
ctr_free_overlay(ctr);
|
|
|
|
|
|
|
|
ctr->overlay = (struct ctr_overlay_data *)calloc(num_images, sizeof(*ctr->overlay));
|
|
|
|
|
|
|
|
if (!ctr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ctr->overlays = num_images;
|
|
|
|
|
|
|
|
for (i = 0; i < num_images; i++)
|
|
|
|
{
|
|
|
|
struct ctr_overlay_data *o = (struct ctr_overlay_data *)&ctr->overlay[i];
|
|
|
|
|
|
|
|
o->frame_coords = linearAlloc(sizeof(ctr_vertex_t));
|
|
|
|
|
|
|
|
if (!ctr || !images || images[i].width > 1024 || images[i].height > 1024)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
memset(&o->texture, 0, sizeof(ctr_texture_t));
|
|
|
|
|
|
|
|
o->texture.width = next_pow2(images[i].width);
|
|
|
|
o->texture.height = next_pow2(images[i].height);
|
|
|
|
o->texture.data = linearAlloc(
|
|
|
|
o->texture.width * o->texture.height * sizeof(uint32_t));
|
|
|
|
|
|
|
|
if (!o->texture.data)
|
|
|
|
{
|
|
|
|
free(o);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t *src = NULL;
|
|
|
|
uint32_t *dst = NULL;
|
|
|
|
|
|
|
|
tmpdata = linearAlloc(images[i].width
|
|
|
|
* images[i].height * sizeof(uint32_t));
|
|
|
|
if (!tmpdata)
|
|
|
|
{
|
|
|
|
linearFree(o->texture.data);
|
|
|
|
free(o);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
src = (uint32_t*)images[i].pixels;
|
|
|
|
dst = (uint32_t*)tmpdata;
|
|
|
|
|
|
|
|
for (j = 0; j < images[i].width * images[i].height; j++)
|
|
|
|
{
|
2021-04-28 19:16:14 +09:00
|
|
|
*dst =
|
|
|
|
((*src << 8) & 0xFF000000)
|
|
|
|
| ((*src << 8) & 0x00FF0000)
|
|
|
|
| ((*src << 8) & 0x0000FF00)
|
|
|
|
| ((*src >> 24) & 0x000000FF);
|
2021-04-04 22:50:59 +02:00
|
|
|
dst++;
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
|
|
|
|
GSPGPU_FlushDataCache(tmpdata,
|
|
|
|
images[i].width * images[i].height * sizeof(uint32_t));
|
|
|
|
ctrGuCopyImage(true, tmpdata,
|
|
|
|
images[i].width, images[i].height, CTRGU_RGBA8, false,
|
|
|
|
o->texture.data, o->texture.width, CTRGU_RGBA8, true);
|
|
|
|
|
|
|
|
ctr->ppf_event_pending = true;
|
|
|
|
|
|
|
|
linearFree(tmpdata);
|
|
|
|
|
|
|
|
ctr_overlay_tex_geom(ctr, i, 0, 0, 1, 1);
|
|
|
|
ctr_overlay_vertex_geom(ctr, i, 0, 0, 1, 1);
|
|
|
|
|
|
|
|
ctr_set_scale_vector(&o->scale_vector,
|
|
|
|
CTR_TOP_FRAMEBUFFER_WIDTH, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
o->texture.width, o->texture.height);
|
|
|
|
|
|
|
|
ctr->overlay[i].alpha_mod = 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_overlay_enable(void *data, bool state)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
|
|
|
|
|
|
|
if (!ctr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ctr->overlay_enabled = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_overlay_full_screen(void *data, bool enable)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
|
|
|
ctr->overlay_full_screen = enable;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ctr_overlay_set_alpha(void *data, unsigned image, float mod){ }
|
|
|
|
|
|
|
|
static void ctr_render_overlay(void *data)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
ctr_video_t *ctr = (ctr_video_t*)data;
|
|
|
|
|
|
|
|
for (i = 0; i < ctr->overlays; i++)
|
|
|
|
{
|
|
|
|
ctrGuSetTexture(GPU_TEXUNIT0, VIRT_TO_PHYS(ctr->overlay[i].texture.data), ctr->overlay[i].texture.width, ctr->overlay[i].texture.height,
|
|
|
|
GPU_TEXTURE_MAG_FILTER(GPU_LINEAR) | GPU_TEXTURE_MIN_FILTER(GPU_LINEAR) |
|
|
|
|
GPU_TEXTURE_WRAP_S(GPU_CLAMP_TO_EDGE) | GPU_TEXTURE_WRAP_T(GPU_CLAMP_TO_EDGE),
|
|
|
|
GPU_RGBA8);
|
|
|
|
|
|
|
|
GPUCMD_AddWrite(GPUREG_GSH_BOOLUNIFORM, 0);
|
|
|
|
ctrGuSetVertexShaderFloatUniform(0, (float*)&ctr->overlay[i].scale_vector, 1);
|
|
|
|
ctrGuSetAttributeBuffersAddress(VIRT_TO_PHYS(ctr->overlay[i].frame_coords));
|
|
|
|
|
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.left),
|
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
ctr->video_mode == CTR_VIDEO_MODE_2D_800X240 ? CTR_TOP_FRAMEBUFFER_WIDTH * 2 : CTR_TOP_FRAMEBUFFER_WIDTH);
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
|
|
|
|
if (ctr->video_mode == CTR_VIDEO_MODE_3D)
|
|
|
|
{
|
|
|
|
GPU_SetViewport(NULL,
|
|
|
|
VIRT_TO_PHYS(ctr->drawbuffers.top.right),
|
|
|
|
0, 0, CTR_TOP_FRAMEBUFFER_HEIGHT,
|
|
|
|
CTR_TOP_FRAMEBUFFER_WIDTH);
|
|
|
|
GPU_DrawArray(GPU_GEOMETRY_PRIM, 0, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const video_overlay_interface_t ctr_overlay = {
|
|
|
|
ctr_overlay_enable,
|
|
|
|
ctr_overlay_load,
|
|
|
|
ctr_overlay_tex_geom,
|
|
|
|
ctr_overlay_vertex_geom,
|
|
|
|
ctr_overlay_full_screen,
|
|
|
|
ctr_overlay_set_alpha,
|
|
|
|
};
|
|
|
|
|
|
|
|
void ctr_overlay_interface(void *data, const video_overlay_interface_t **iface)
|
|
|
|
{
|
|
|
|
ctr_video_t *ctr = (ctr_video_t *)data;
|
|
|
|
|
|
|
|
if (!ctr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
*iface = &ctr_overlay;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-04-23 22:20:11 +02:00
|
|
|
static void ctr_set_osd_msg(void *data,
|
|
|
|
const char *msg,
|
2017-01-19 16:30:40 +01:00
|
|
|
const void *params, void *font)
|
2016-09-29 20:14:12 +01:00
|
|
|
{
|
|
|
|
ctr_video_t* ctr = (ctr_video_t*)data;
|
|
|
|
|
2016-10-04 15:49:55 +01:00
|
|
|
if (ctr && ctr->msg_rendering_enabled)
|
2020-03-10 03:24:59 +01:00
|
|
|
font_driver_render_msg(data, msg, params, font);
|
2016-09-29 20:14:12 +01:00
|
|
|
}
|
|
|
|
|
2019-05-05 13:46:26 +02:00
|
|
|
static uint32_t ctr_get_flags(void *data)
|
|
|
|
{
|
|
|
|
uint32_t flags = 0;
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2015-12-20 20:52:23 +01:00
|
|
|
static const video_poke_interface_t ctr_poke_interface = {
|
2019-05-05 13:46:26 +02:00
|
|
|
ctr_get_flags,
|
2016-09-29 20:14:12 +01:00
|
|
|
ctr_load_texture,
|
|
|
|
ctr_unload_texture,
|
2015-04-01 22:14:13 +01:00
|
|
|
NULL,
|
2018-04-15 11:12:56 -05:00
|
|
|
NULL,
|
2015-04-01 22:14:13 +01:00
|
|
|
ctr_set_filtering,
|
2017-11-14 21:34:03 +01:00
|
|
|
NULL, /* get_video_output_size */
|
|
|
|
NULL, /* get_video_output_prev */
|
|
|
|
NULL, /* get_video_output_next */
|
|
|
|
NULL, /* get_current_framebuffer */
|
2015-04-01 22:14:13 +01:00
|
|
|
NULL,
|
|
|
|
ctr_set_aspect_ratio,
|
|
|
|
ctr_apply_state_changes,
|
|
|
|
ctr_set_texture_frame,
|
|
|
|
ctr_set_texture_enable,
|
2021-03-23 22:03:44 +01:00
|
|
|
font_driver_render_msg, /* ctr_set_osd_msg*/
|
2018-01-30 22:29:57 +01:00
|
|
|
NULL, /* show_mouse */
|
|
|
|
NULL, /* grab_mouse_toggle */
|
|
|
|
NULL, /* get_current_shader */
|
|
|
|
NULL, /* get_current_software_framebuffer */
|
2021-09-03 06:15:25 +02:00
|
|
|
NULL, /* get_hw_render_interface */
|
|
|
|
NULL, /* set_hdr_max_nits */
|
|
|
|
NULL, /* set_hdr_paper_white_nits */
|
|
|
|
NULL, /* set_hdr_contrast */
|
|
|
|
NULL /* set_hdr_expand_gamut */
|
2015-04-01 22:14:13 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static void ctr_get_poke_interface(void* data,
|
|
|
|
const video_poke_interface_t** iface)
|
|
|
|
{
|
|
|
|
(void)data;
|
|
|
|
*iface = &ctr_poke_interface;
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:03:44 +01:00
|
|
|
#ifdef HAVE_GFX_WIDGETS
|
|
|
|
static bool ctr_gfx_widgets_enabled(void *data)
|
|
|
|
{
|
|
|
|
(void)data;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-04-01 22:14:13 +01:00
|
|
|
static bool ctr_set_shader(void* data,
|
|
|
|
enum rarch_shader_type type, const char* path)
|
|
|
|
{
|
|
|
|
(void)data;
|
|
|
|
(void)type;
|
|
|
|
(void)path;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
video_driver_t video_ctr =
|
|
|
|
{
|
|
|
|
ctr_init,
|
|
|
|
ctr_frame,
|
|
|
|
ctr_set_nonblock_state,
|
|
|
|
ctr_alive,
|
|
|
|
ctr_focus,
|
|
|
|
ctr_suppress_screensaver,
|
2017-05-13 19:11:32 +02:00
|
|
|
NULL, /* has_windowed */
|
2015-04-01 22:14:13 +01:00
|
|
|
ctr_set_shader,
|
|
|
|
ctr_free,
|
|
|
|
"ctr",
|
2015-04-26 19:46:59 +02:00
|
|
|
NULL, /* set_viewport */
|
2015-04-01 22:14:13 +01:00
|
|
|
ctr_set_rotation,
|
|
|
|
ctr_viewport_info,
|
2019-05-22 07:07:33 +02:00
|
|
|
NULL, /* read_viewport */
|
2015-04-01 22:14:13 +01:00
|
|
|
NULL, /* read_frame_raw */
|
|
|
|
#ifdef HAVE_OVERLAY
|
2021-04-04 22:50:59 +02:00
|
|
|
ctr_overlay_interface,
|
2019-04-01 04:00:58 +01:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_VIDEO_LAYOUT
|
2021-03-23 22:03:44 +01:00
|
|
|
NULL,
|
|
|
|
#endif
|
|
|
|
ctr_get_poke_interface,
|
|
|
|
NULL,
|
|
|
|
#ifdef HAVE_GFX_WIDGETS
|
|
|
|
ctr_gfx_widgets_enabled
|
2015-04-01 22:14:13 +01:00
|
|
|
#endif
|
|
|
|
};
|