RetroArch/gfx/drivers/psp1_gfx.c

921 lines
25 KiB
C
Raw Normal View History

/* RetroArch - A frontend for libretro.
2017-01-22 12:40:32 +00:00
* Copyright (C) 2014-2017 - Ali Bouhlel
* Copyright (C) 2011-2017 - Daniel De Matteis
*
* 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 <pspkernel.h>
#include <pspdisplay.h>
2014-02-18 17:42:15 +00:00
#include <malloc.h>
2012-11-23 06:19:21 +00:00
#include <pspgu.h>
#include <pspgum.h>
#include <psprtc.h>
2016-02-13 04:08:29 +00:00
#include <retro_assert.h>
#include <retro_inline.h>
2017-06-28 02:41:38 +00:00
#include <retro_math.h>
2015-11-22 12:32:46 +00:00
2016-09-11 12:46:53 +00:00
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
#ifdef HAVE_MENU
#include "../../menu/menu_driver.h"
#endif
2017-01-19 16:20:42 +00:00
#include "../font_driver.h"
#include "../../defines/psp_defines.h"
#ifndef SCEGU_SCR_WIDTH
#define SCEGU_SCR_WIDTH 480
#endif
#ifndef SCEGU_SCR_HEIGHT
#define SCEGU_SCR_HEIGHT 272
#endif
#ifndef SCEGU_VRAM_WIDTH
#define SCEGU_VRAM_WIDTH 512
#endif
/* Frame buffer */
#define SCEGU_VRAM_TOP (0x44000000)
/* 16bit mode */
#define SCEGU_VRAM_BUFSIZE (SCEGU_VRAM_WIDTH*SCEGU_SCR_HEIGHT*2)
#define SCEGU_VRAM_BP_0 ((void *)(SCEGU_VRAM_TOP))
#define SCEGU_VRAM_BP_1 ((void *)(SCEGU_VRAM_TOP+SCEGU_VRAM_BUFSIZE))
#define SCEGU_VRAM_BP_2 ((void *)(SCEGU_VRAM_TOP+(SCEGU_VRAM_BUFSIZE*2)))
/* 32bit mode */
#define SCEGU_VRAM_BUFSIZE32 (SCEGU_VRAM_WIDTH*SCEGU_SCR_HEIGHT*4)
#define SCEGU_VRAM_BP32_0 ((void *)(SCEGU_VRAM_TOP))
#define SCEGU_VRAM_BP32_1 ((void *)(SCEGU_VRAM_TOP+SCEGU_VRAM_BUFSIZE32))
#define SCEGU_VRAM_BP32_2 ((void *)(SCEGU_VRAM_TOP+(SCEGU_VRAM_BUFSIZE32*2)))
#define TO_UNCACHED_PTR(ptr) ((void *)((uint32_t)(ptr)|0x40000000))
#define TO_CACHED_PTR(ptr) ((void *)((uint32_t)(ptr)&~0x40000000))
2014-02-18 17:42:15 +00:00
#define FROM_GU_POINTER(ptr) ((void *)((uint32_t)(ptr)|0x44000000))
#define TO_GU_POINTER(ptr) ((void *)((uint32_t)(ptr)&~0x44000000))
2014-02-18 17:42:15 +00:00
typedef struct __attribute__((packed)) psp1_vertex
{
float u,v;
float x,y,z;
} psp1_vertex_t;
typedef struct __attribute__((packed)) psp1_sprite
{
psp1_vertex_t v0;
psp1_vertex_t v1;
} psp1_sprite_t;
typedef struct psp1_menu_frame
{
void* dList;
void* frame;
psp1_sprite_t* frame_coords;
bool active;
PspGeContext context_storage;
} psp1_menu_frame_t;
2014-02-18 17:42:15 +00:00
typedef struct psp1_video
{
bool vsync;
2014-02-18 17:42:15 +00:00
bool rgb32;
bool vblank_not_reached;
bool keep_aspect;
bool should_resize;
bool hw_render;
2020-03-07 18:54:58 +00:00
int tex_filter;
int bpp_log2;
unsigned rotation;
psp1_menu_frame_t menu;
video_viewport_t vp;
void* main_dList;
void* frame_dList;
void* draw_buffer;
void* texture;
psp1_sprite_t *frame_coords;
2014-02-18 17:42:15 +00:00
} psp1_video_t;
2020-03-07 18:54:58 +00:00
/* both row and column count need to be a power of 2 */
#define PSP_FRAME_ROWS_COUNT 4
#define PSP_FRAME_COLUMNS_COUNT 16
#define PSP_FRAME_SLICE_COUNT (PSP_FRAME_ROWS_COUNT * PSP_FRAME_COLUMNS_COUNT)
#define PSP_FRAME_VERTEX_COUNT (PSP_FRAME_SLICE_COUNT * 2)
static INLINE void psp_set_screen_coords (psp1_sprite_t* framecoords,
int x, int y, int width, int height, unsigned rotation)
{
int i;
float x0, y0, step_x, step_y;
2015-03-21 22:25:46 +00:00
int current_column = 0;
if (rotation == 0)
{
x0 = x;
y0 = y;
step_x = ((float) width) / PSP_FRAME_COLUMNS_COUNT;
step_y = ((float) height) / PSP_FRAME_ROWS_COUNT;
for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
{
framecoords[i].v0.x = x0;
framecoords[i].v0.y = y0;
framecoords[i].v1.x = (x0 += step_x);
framecoords[i].v1.y = y0 + step_y;
if (++current_column == PSP_FRAME_COLUMNS_COUNT)
{
x0 = x;
y0 += step_y;
current_column = 0;
}
}
}
else if (rotation == 1) /* 90° */
{
x0 = x + width;
y0 = y;
step_x = -((float) width) / PSP_FRAME_ROWS_COUNT;
step_y = ((float) height) / PSP_FRAME_COLUMNS_COUNT;
for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
{
framecoords[i].v0.x = x0;
framecoords[i].v0.y = y0;
framecoords[i].v1.x = x0 + step_x;
framecoords[i].v1.y = (y0 += step_y);
if (++current_column == PSP_FRAME_COLUMNS_COUNT)
{
y0 = y;
x0 += step_x;
current_column = 0;
}
}
}
else if (rotation == 2) /* 180° */
{
x0 = x + width;
y0 = y + height;
step_x = -((float) width) / PSP_FRAME_COLUMNS_COUNT;
step_y = -((float) height) / PSP_FRAME_ROWS_COUNT;
for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
{
framecoords[i].v0.x = x0;
framecoords[i].v0.y = y0;
framecoords[i].v1.x = (x0 += step_x);
framecoords[i].v1.y = y0 + step_y;
if (++current_column == PSP_FRAME_COLUMNS_COUNT)
{
x0 = x + width;
y0 += step_y;
current_column = 0;
}
}
}
else /* 270° */
{
x0 = x;
y0 = y + height;
step_x = ((float) width) / PSP_FRAME_ROWS_COUNT;
step_y = -((float) height) / PSP_FRAME_COLUMNS_COUNT;
for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
{
framecoords[i].v0.x = x0;
framecoords[i].v0.y = y0;
framecoords[i].v1.x = x0 + step_x;
framecoords[i].v1.y = (y0 += step_y);
if (++current_column == PSP_FRAME_COLUMNS_COUNT)
{
y0 = y + height;
x0 += step_x;
current_column = 0;
}
}
}
}
static INLINE void psp_set_tex_coords (psp1_sprite_t* framecoords,
2014-09-08 17:28:10 +00:00
int width, int height)
{
int i;
2015-03-21 22:25:46 +00:00
int current_column = 0;
float u0 = 0;
float v0 = 0;
float step_u = ((float) width) / PSP_FRAME_COLUMNS_COUNT;
float step_v = ((float) height) / PSP_FRAME_ROWS_COUNT;
for (i=0; i < PSP_FRAME_SLICE_COUNT; i++)
{
framecoords[i].v0.u = u0;
framecoords[i].v0.v = v0;
2015-03-21 22:25:46 +00:00
u0 += step_u;
framecoords[i].v1.u = u0;
framecoords[i].v1.v = v0 + step_v;
if (++current_column == PSP_FRAME_COLUMNS_COUNT)
{
2015-03-21 22:25:46 +00:00
u0 = 0;
v0 += step_v;
current_column = 0;
}
}
}
2017-01-24 13:04:12 +00:00
static void psp_update_viewport(psp1_video_t* psp,
2020-08-03 14:33:54 +00:00
video_frame_info_t *video_info)
{
int x = 0;
int y = 0;
float device_aspect = ((float)SCEGU_SCR_WIDTH) / SCEGU_SCR_HEIGHT;
float width = SCEGU_SCR_WIDTH;
float height = SCEGU_SCR_HEIGHT;
settings_t *settings = config_get_ptr();
bool video_scale_integer = settings->bools.video_scale_integer;
unsigned aspect_ratio_idx = settings->uints.video_aspect_ratio_idx;
if (video_scale_integer)
{
video_viewport_get_scaled_integer(&psp->vp, SCEGU_SCR_WIDTH,
SCEGU_SCR_HEIGHT, video_driver_get_aspect_ratio(), psp->keep_aspect);
width = psp->vp.width;
height = psp->vp.height;
}
else if (psp->keep_aspect)
{
#if defined(HAVE_MENU)
if (aspect_ratio_idx == ASPECT_RATIO_CUSTOM)
{
x = video_info->custom_vp_x;
y = video_info->custom_vp_y;
width = video_info->custom_vp_width;
height = video_info->custom_vp_height;
}
else
#endif
{
float delta;
float desired_aspect = video_driver_get_aspect_ratio();
if ((fabsf(device_aspect - desired_aspect) < 0.0001f)
|| (fabsf((16.0/9.0) - desired_aspect) < 0.02f))
{
/* 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);
}
}
psp->vp.x = x;
psp->vp.y = y;
psp->vp.width = width;
psp->vp.height = height;
}
else
{
psp->vp.x = 0;
psp->vp.y = 0;
psp->vp.width = width;
psp->vp.height = height;
}
psp->vp.width += psp->vp.width & 0x1;
psp->vp.height += psp->vp.height & 0x1;
psp_set_screen_coords(psp->frame_coords, psp->vp.x,
psp->vp.y, psp->vp.width, psp->vp.height, psp->rotation);
psp->should_resize = false;
}
static void psp_on_vblank(u32 sub, psp1_video_t *psp)
{
2015-03-21 22:25:46 +00:00
if (psp)
psp->vblank_not_reached = false;
}
static void *psp_init(const video_info_t *video,
input_driver_t **input, void **input_data)
{
/* TODO : add ASSERT() checks or use main RAM if
2014-09-08 17:28:10 +00:00
* VRAM is too low for desired video->input_scale. */
2017-01-24 13:04:12 +00:00
int pixel_format, lut_pixel_format, lut_block_count;
unsigned int red_shift, color_mask;
2017-01-24 13:04:12 +00:00
void *pspinput = NULL;
void *displayBuffer = NULL;
void *LUT_r = NULL;
void *LUT_b = NULL;
2015-03-21 22:25:46 +00:00
psp1_video_t *psp = (psp1_video_t*)calloc(1, sizeof(psp1_video_t));
2014-02-18 17:42:15 +00:00
if (!psp)
return NULL;
sceGuInit();
2015-03-21 22:25:46 +00:00
psp->vp.x = 0;
psp->vp.y = 0;
psp->vp.width = SCEGU_SCR_WIDTH;
psp->vp.height = SCEGU_SCR_HEIGHT;
psp->vp.full_width = SCEGU_SCR_WIDTH;
psp->vp.full_height = SCEGU_SCR_HEIGHT;
/* Make sure anything using uncached pointers reserves
2014-09-08 17:28:10 +00:00
* whole cachelines (memory address and size need to be a multiple of 64)
* so it isn't overwritten by an unlucky cache writeback.
*
* This includes display lists since the Gu library uses
2014-09-08 17:28:10 +00:00
* uncached pointers to write to them. */
/* Allocate more space if bigger display lists are needed. */
2015-03-21 22:25:46 +00:00
psp->main_dList = memalign(64, 256);
2015-03-21 22:25:46 +00:00
psp->frame_dList = memalign(64, 256);
psp->menu.dList = memalign(64, 256);
psp->menu.frame = memalign(16, 2 * 480 * 272);
psp->frame_coords = memalign(64,
2014-09-08 17:28:10 +00:00
(((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));
2015-03-21 22:25:46 +00:00
psp->menu.frame_coords = memalign(64,
2014-09-08 17:28:10 +00:00
(((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));
memset(psp->frame_coords, 0,
PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t));
memset(psp->menu.frame_coords, 0,
PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t));
sceKernelDcacheWritebackInvalidateAll();
2015-03-21 22:25:46 +00:00
psp->frame_coords = TO_UNCACHED_PTR(psp->frame_coords);
psp->menu.frame_coords = TO_UNCACHED_PTR(psp->menu.frame_coords);
2015-03-21 22:25:46 +00:00
psp->frame_coords->v0.x = 60;
psp->frame_coords->v0.y = 0;
psp->frame_coords->v0.u = 0;
psp->frame_coords->v0.v = 0;
2015-03-21 22:25:46 +00:00
psp->frame_coords->v1.x = 420;
psp->frame_coords->v1.y = SCEGU_SCR_HEIGHT;
psp->frame_coords->v1.u = 256;
psp->frame_coords->v1.v = 240;
2015-03-21 22:25:46 +00:00
psp->vsync = video->vsync;
psp->rgb32 = video->rgb32;
if(psp->rgb32)
{
2015-03-21 22:25:46 +00:00
u32 i;
uint32_t* LUT_r_local = (uint32_t*)(SCEGU_VRAM_BP32_2);
uint32_t* LUT_b_local = (uint32_t*)(SCEGU_VRAM_BP32_2) + (1 << 8);
2015-03-21 22:25:46 +00:00
red_shift = 8 + 8;
color_mask = 0xFF;
lut_block_count = (1 << 8) / 8;
2015-03-21 22:25:46 +00:00
psp->texture = (void*)(LUT_b_local + (1 << 8));
psp->draw_buffer = SCEGU_VRAM_BP32_0;
psp->bpp_log2 = 2;
2015-03-21 22:25:46 +00:00
pixel_format = GU_PSM_8888;
lut_pixel_format = GU_PSM_T32;
2015-03-21 22:25:46 +00:00
displayBuffer = SCEGU_VRAM_BP32_1;
2015-03-21 22:25:46 +00:00
for (i = 0; i < (1 << 8); i++)
{
LUT_r_local[i] = i;
LUT_b_local[i] = i << (8 + 8);
}
2015-03-21 22:25:46 +00:00
LUT_r = (void*)LUT_r_local;
LUT_b = (void*)LUT_b_local;
}
else
{
2015-03-21 22:25:46 +00:00
u16 i;
uint16_t* LUT_r_local = (uint16_t*)(SCEGU_VRAM_BP_2);
uint16_t* LUT_b_local = (uint16_t*)(SCEGU_VRAM_BP_2) + (1 << 5);
2015-03-21 22:25:46 +00:00
red_shift = 6 + 5;
color_mask = 0x1F;
lut_block_count = (1 << 5) / 8;
2015-03-21 22:25:46 +00:00
psp->texture = (void*)(LUT_b_local + (1 << 5));
psp->draw_buffer = SCEGU_VRAM_BP_0;
psp->bpp_log2 = 1;
pixel_format =
(video_driver_get_pixel_format() == RETRO_PIXEL_FORMAT_0RGB1555)
2014-09-08 17:28:10 +00:00
? GU_PSM_5551 : GU_PSM_5650 ;
2015-03-21 22:25:46 +00:00
lut_pixel_format = GU_PSM_T16;
2015-03-21 22:25:46 +00:00
displayBuffer = SCEGU_VRAM_BP_1;
2015-03-21 22:25:46 +00:00
for (i = 0; i < (1 << 5); i++)
2014-09-08 17:28:10 +00:00
{
2015-03-21 22:25:46 +00:00
LUT_r_local[i] = i;
LUT_b_local[i] = i << (5 + 6);
}
2015-03-21 22:25:46 +00:00
LUT_r = (void*)LUT_r_local;
LUT_b = (void*)LUT_b_local;
}
psp->tex_filter = video->smooth? GU_LINEAR : GU_NEAREST;
2014-09-08 17:28:10 +00:00
/* TODO: check if necessary. */
sceDisplayWaitVblankStart();
2014-02-18 17:42:15 +00:00
sceGuDisplay(GU_FALSE);
sceGuStart(GU_DIRECT, psp->main_dList);
2014-02-16 20:26:56 +00:00
2014-09-08 17:28:10 +00:00
sceGuDrawBuffer(pixel_format, TO_GU_POINTER(psp->draw_buffer),
SCEGU_VRAM_WIDTH);
sceGuDispBuffer(SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT,
TO_GU_POINTER(displayBuffer), SCEGU_VRAM_WIDTH);
sceGuClearColor(0);
2014-02-18 17:42:15 +00:00
sceGuScissor(0, 0, SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT);
sceGuEnable(GU_SCISSOR_TEST);
sceGuTexFilter(psp->tex_filter, psp->tex_filter);
2014-02-18 17:42:15 +00:00
sceGuTexWrap (GU_CLAMP, GU_CLAMP);
sceGuEnable(GU_TEXTURE_2D);
sceGuDisable(GU_DEPTH_TEST);
sceGuCallMode(GU_FALSE);
2014-02-18 17:42:15 +00:00
sceGuFinish();
sceGuSync(0, 0);
2014-09-08 17:28:10 +00:00
/* TODO : check if necessary */
sceDisplayWaitVblankStart();
2014-02-18 17:42:15 +00:00
sceGuDisplay(GU_TRUE);
pspDebugScreenSetColorMode(pixel_format);
pspDebugScreenSetBase(psp->draw_buffer);
2014-09-08 17:28:10 +00:00
/* fill frame_dList : */
sceGuStart(GU_CALL, psp->frame_dList);
sceGuTexMode(pixel_format, 0, 0, GU_FALSE);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuEnable(GU_BLEND);
2014-09-08 17:28:10 +00:00
/* green only */
sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0x0000FF00, 0xFFFFFFFF);
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
2014-09-08 17:28:10 +00:00
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
(void*)(psp->frame_coords));
2014-09-08 17:28:10 +00:00
/* restore */
sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0xFFFFFFFF, 0xFFFFFFFF);
sceGuTexMode(lut_pixel_format, 0, 0, GU_FALSE);
sceGuClutMode(pixel_format, red_shift, color_mask, 0);
sceGuClutLoad(lut_block_count, LUT_r);
2014-09-08 17:28:10 +00:00
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
(void*)(psp->frame_coords));
sceGuClutMode(pixel_format, 0, color_mask, 0);
sceGuClutLoad(lut_block_count, LUT_b);
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
2014-09-08 17:28:10 +00:00
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
(void*)(psp->frame_coords));
sceGuFinish();
if (input && input_data)
{
2017-01-10 20:15:52 +00:00
settings_t *settings = config_get_ptr();
2020-08-30 03:29:32 +00:00
pspinput = input_driver_init_wrap(&input_psp,
settings->arrays.input_joypad_driver);
2017-01-10 20:15:52 +00:00
*input = pspinput ? &input_psp : NULL;
*input_data = pspinput;
}
psp->vblank_not_reached = true;
sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT, 0, psp_on_vblank, psp);
sceKernelEnableSubIntr(PSP_VBLANK_INT, 0);
2015-03-21 22:25:46 +00:00
psp->keep_aspect = true;
psp->should_resize = true;
psp->hw_render = false;
2014-02-11 13:10:47 +00:00
return psp;
}
2012-11-26 23:50:29 +00:00
static bool psp_frame(void *data, const void *frame,
2015-08-03 21:01:07 +00:00
unsigned width, unsigned height, uint64_t frame_count,
2017-01-18 16:41:27 +00:00
unsigned pitch, const char *msg, video_frame_info_t *video_info)
{
2020-05-19 14:20:43 +00:00
psp1_video_t *psp = (psp1_video_t*)data;
2020-08-03 14:33:54 +00:00
#ifdef HAVE_MENU
2020-05-19 14:20:43 +00:00
bool menu_is_alive = video_info->menu_is_alive;
2020-08-03 14:33:54 +00:00
#endif
if (!width || !height)
return false;
if (((uint32_t)frame&0x04000000) || (frame == RETRO_HW_FRAME_BUFFER_VALID))
psp->hw_render = true;
else if (frame)
psp->hw_render = false;
if (!psp->hw_render)
2014-09-08 17:28:10 +00:00
sceGuSync(0, 0); /* let the core decide when to sync when HW_RENDER */
2019-10-15 22:46:29 +00:00
if (msg)
{
2019-10-15 22:46:29 +00:00
pspDebugScreenSetBase(psp->draw_buffer);
pspDebugScreenSetXY(0,0);
pspDebugScreenPuts(msg);
2019-10-15 22:46:29 +00:00
}
2020-08-03 14:33:54 +00:00
if ((psp->vsync) && (psp->vblank_not_reached))
2014-02-18 17:42:15 +00:00
sceDisplayWaitVblankStart();
psp->vblank_not_reached = true;
psp->draw_buffer = FROM_GU_POINTER(sceGuSwapBuffers());
if (psp->should_resize)
2017-01-24 13:04:12 +00:00
psp_update_viewport(psp, video_info);
psp_set_tex_coords(psp->frame_coords, width, height);
sceGuStart(GU_DIRECT, psp->main_dList);
sceGuTexFilter(psp->tex_filter, psp->tex_filter);
sceGuClear(GU_COLOR_BUFFER_BIT);
/* frame in VRAM ? texture/palette was
2014-09-08 17:28:10 +00:00
* set in core so draw directly */
if (psp->hw_render)
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
2014-09-08 17:28:10 +00:00
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
(void*)(psp->frame_coords));
else
{
2014-09-08 17:28:10 +00:00
if (frame)
{
sceKernelDcacheWritebackRange(frame,pitch * height);
sceGuCopyImage(psp->rgb32? GU_PSM_8888 : GU_PSM_5650,
((u32)frame & 0xF) >> psp->bpp_log2,
2014-09-08 17:28:10 +00:00
0, width, height, pitch >> psp->bpp_log2,
(void*)((u32)frame & ~0xF), 0, 0, width, psp->texture);
}
sceGuTexImage(0, next_pow2(width), next_pow2(height), width, psp->texture);
sceGuCallList(psp->frame_dList);
}
sceGuFinish();
#ifdef HAVE_MENU
2020-05-19 14:20:43 +00:00
menu_driver_frame(menu_is_alive, video_info);
#endif
2014-06-10 00:21:49 +00:00
if(psp->menu.active)
{
2014-06-10 00:21:49 +00:00
sceGuSendList(GU_TAIL, psp->menu.dList, &(psp->menu.context_storage));
sceGuSync(0, 0);
}
return true;
}
static void psp_set_nonblock_state(void *data, bool toggle,
bool adaptive_vsync_enabled, unsigned swap_interval)
{
2014-02-18 17:42:15 +00:00
psp1_video_t *psp = (psp1_video_t*)data;
2014-11-08 15:35:59 +00:00
if (psp)
psp->vsync = !toggle;
}
static bool psp_alive(void *data) { return true; }
static bool psp_focus(void *data) { return true; }
static bool psp_suppress_screensaver(void *data, bool enable) { return false; }
2015-01-18 21:32:14 +00:00
2012-11-26 23:50:29 +00:00
static void psp_free(void *data)
{
2014-02-18 17:42:15 +00:00
psp1_video_t *psp = (psp1_video_t*)data;
if(!(psp) || !(psp->main_dList))
return;
sceDisplayWaitVblankStart();
sceGuDisplay(GU_FALSE);
sceGuTerm();
if (psp->main_dList)
free(psp->main_dList);
if (psp->frame_dList)
free(psp->frame_dList);
if (psp->frame_coords)
free(TO_CACHED_PTR(psp->frame_coords));
2014-06-10 00:21:49 +00:00
if (psp->menu.frame_coords)
free(TO_CACHED_PTR(psp->menu.frame_coords));
if (psp->menu.dList)
free(psp->menu.dList);
if (psp->menu.frame)
free(psp->menu.frame);
free(data);
sceKernelDisableSubIntr(PSP_VBLANK_INT, 0);
sceKernelReleaseSubIntrHandler(PSP_VBLANK_INT,0);
}
static void psp_set_texture_frame(void *data, const void *frame, bool rgb32,
unsigned width, unsigned height, float alpha)
{
2015-01-26 18:55:19 +00:00
psp1_video_t *psp = (psp1_video_t*)data;
(void) rgb32;
(void) alpha;
#ifdef DEBUG
2014-09-08 17:28:10 +00:00
/* psp->menu.frame buffer size is (480 * 272)*2 Bytes */
retro_assert((width*height) < (480 * 272));
#endif
2014-09-08 17:28:10 +00:00
psp_set_screen_coords(psp->menu.frame_coords, 0, 0,
SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT, 0);
psp_set_tex_coords(psp->menu.frame_coords, width, height);
sceKernelDcacheWritebackRange(frame, width * height * 2);
sceGuStart(GU_DIRECT, psp->main_dList);
2014-09-08 17:28:10 +00:00
sceGuCopyImage(GU_PSM_4444, 0, 0, width, height, width,
(void*)frame, 0, 0, width, psp->menu.frame);
sceGuFinish();
2014-06-10 00:21:49 +00:00
sceGuStart(GU_SEND, psp->menu.dList);
sceGuTexMode(GU_PSM_4444, 0, 0, GU_FALSE);
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB);
sceGuTexFilter(GU_LINEAR, GU_LINEAR);
2014-06-10 00:21:49 +00:00
sceGuTexImage(0, next_pow2(width), next_pow2(height), width, psp->menu.frame);
sceGuEnable(GU_BLEND);
2014-09-08 17:28:10 +00:00
#if 0
/* default blending */
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
#endif
sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0xF0F0F0F0, 0x0F0F0F0F);
;
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
2014-09-08 17:28:10 +00:00
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
psp->menu.frame_coords);
sceGuFinish();
}
static void psp_set_texture_enable(void *data, bool state, bool full_screen)
{
2014-02-18 17:42:15 +00:00
(void) full_screen;
psp1_video_t *psp = (psp1_video_t*)data;
2014-02-18 17:42:15 +00:00
2014-11-08 15:35:59 +00:00
if (psp)
psp->menu.active = state;
}
static void psp_set_rotation(void *data, unsigned rotation)
{
psp1_video_t *psp = (psp1_video_t*)data;
2014-11-08 15:35:59 +00:00
if (!psp)
return;
psp->rotation = rotation;
psp->should_resize = true;
}
static void psp_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling)
{
psp1_video_t *psp = (psp1_video_t*)data;
2014-11-08 15:35:59 +00:00
if (psp)
psp->tex_filter = smooth? GU_LINEAR : GU_NEAREST;
}
2015-11-21 12:13:55 +00:00
static void psp_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
{
psp1_video_t *psp = (psp1_video_t*)data;
if (!psp)
return;
psp->keep_aspect = true;
psp->should_resize = true;
}
static void psp_apply_state_changes(void *data)
{
psp1_video_t *psp = (psp1_video_t*)data;
2014-11-08 15:35:59 +00:00
if (psp)
psp->should_resize = true;
}
2015-02-14 04:52:05 +00:00
static void psp_viewport_info(void *data, struct video_viewport *vp)
{
psp1_video_t *psp = (psp1_video_t*)data;
2014-11-08 15:35:59 +00:00
if (psp)
*vp = psp->vp;
}
static uint32_t psp_get_flags(void *data)
{
uint32_t flags = 0;
BIT32_SET(flags, GFX_CTX_FLAGS_SCREENSHOTS_SUPPORTED);
return flags;
}
static const video_poke_interface_t psp_poke_interface = {
psp_get_flags,
NULL,
NULL,
NULL,
NULL, /* get_refresh_rate */
psp_set_filtering,
NULL, /* get_video_output_size */
NULL, /* get_video_output_prev */
NULL, /* get_video_output_next */
2015-04-25 00:35:06 +00:00
NULL, /* get_current_framebuffer */
NULL, /* get_proc_address */
psp_set_aspect_ratio,
psp_apply_state_changes,
psp_set_texture_frame,
psp_set_texture_enable,
2018-01-30 21:29:57 +00:00
NULL, /* set_osd_msg */
NULL, /* show_mouse */
NULL, /* grab_mouse_toggle */
NULL, /* get_current_shader */
NULL, /* get_current_software_framebuffer */
NULL /* get_hw_render_interface */
};
2014-09-08 17:28:10 +00:00
static void psp_get_poke_interface(void *data,
const video_poke_interface_t **iface)
{
(void)data;
*iface = &psp_poke_interface;
2012-11-26 23:50:29 +00:00
}
static bool psp_read_viewport(void *data, uint8_t *buffer, bool is_idle)
{
2015-03-06 21:27:06 +00:00
void* src_buffer;
int i, j, src_bufferwidth, src_pixelformat, src_x, src_y, src_x_max, src_y_max;
uint8_t *dst = buffer;
2015-03-21 22:27:18 +00:00
psp1_video_t *psp = (psp1_video_t*)data;
2015-03-06 21:27:06 +00:00
sceDisplayGetFrameBuf(&src_buffer, &src_bufferwidth, &src_pixelformat, PSP_DISPLAY_SETBUF_NEXTFRAME);
2015-03-21 22:27:18 +00:00
src_x = (psp->vp.x > 0)? psp->vp.x : 0;
src_y = (psp->vp.y > 0)? psp->vp.y : 0;
2015-03-06 21:27:06 +00:00
src_x_max = ((psp->vp.x + psp->vp.width) < src_bufferwidth)? (psp->vp.x + psp->vp.width): src_bufferwidth;
src_y_max = ((psp->vp.y + psp->vp.height) < SCEGU_SCR_HEIGHT)? (psp->vp.y + psp->vp.height): SCEGU_SCR_HEIGHT;
switch(src_pixelformat)
{
case PSP_DISPLAY_PIXEL_FORMAT_565:
for (j = (src_y_max - 1); j >= src_y ; j--)
{
uint16_t* src = (uint16_t*)src_buffer + src_bufferwidth * j + src_x;
for (i = src_x; i < src_x_max; i++)
{
*(dst++) = ((*src) >> 11) << 3;
*(dst++) = (((*src) >> 5) << 2) &0xFF;
*(dst++) = ((*src) & 0x1F) << 3;
src++;
}
}
return true;
case PSP_DISPLAY_PIXEL_FORMAT_5551:
for (j = (src_y_max - 1); j >= src_y ; j--)
{
uint16_t* src = (uint16_t*)src_buffer + src_bufferwidth * j + src_x;
for (i = src_x; i < src_x_max; i++)
{
*(dst++) = (((*src) >> 10) << 3) &0xFF;
*(dst++) = (((*src) >> 5) << 3) &0xFF;
*(dst++) = ((*src) & 0x1F) << 3;
src++;
}
}
return true;
case PSP_DISPLAY_PIXEL_FORMAT_4444:
for (j = (src_y_max - 1); j >= src_y ; j--)
{
uint16_t* src = (uint16_t*)src_buffer + src_bufferwidth * j + src_x;
for (i = src_x; i < src_x_max; i++)
{
*(dst++) = ((*src) >> 4) & 0xF0;
*(dst++) = (*src) & 0xF0;
*(dst++) = ((*src) << 4) & 0xF0;
src++;
}
}
return true;
case PSP_DISPLAY_PIXEL_FORMAT_8888:
for (j = (src_y_max - 1); j >= src_y ; j--)
{
uint32_t* src = (uint32_t*)src_buffer + src_bufferwidth * j + src_x;
for (i = src_x; i < src_x_max; i++)
{
*(dst++) = ((*src) >> 16) & 0xFF;
*(dst++) = ((*src) >> 8 ) & 0xFF;
*(dst++) = (*src) & 0xFF;
src++;
}
}
return true;
}
return false;
}
static bool psp_set_shader(void *data, enum rarch_shader_type type, const char *path) { return false; }
2014-09-11 05:06:20 +00:00
video_driver_t video_psp1 = {
2012-11-26 23:50:29 +00:00
psp_init,
psp_frame,
psp_set_nonblock_state,
psp_alive,
psp_focus,
2015-01-18 21:32:14 +00:00
psp_suppress_screensaver,
NULL, /* has_windowed */
psp_set_shader,
2012-11-26 23:50:29 +00:00
psp_free,
"psp1",
NULL, /* set_viewport */
2012-11-26 23:50:29 +00:00
psp_set_rotation,
psp_viewport_info,
psp_read_viewport,
NULL, /* read_frame_raw */
#ifdef HAVE_OVERLAY
NULL,
2019-04-01 03:00:58 +00:00
#endif
#ifdef HAVE_VIDEO_LAYOUT
NULL,
#endif
psp_get_poke_interface
};