mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-30 19:50:24 +00:00
976 lines
26 KiB
C
976 lines
26 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* 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>
|
|
#include <malloc.h>
|
|
#include <pspgu.h>
|
|
#include <pspgum.h>
|
|
#include <psprtc.h>
|
|
|
|
#include <retro_assert.h>
|
|
#include <retro_inline.h>
|
|
#include <retro_math.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "../../config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_MENU
|
|
#include "../../menu/menu_driver.h"
|
|
#endif
|
|
|
|
#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))
|
|
|
|
#define FROM_GU_POINTER(ptr) ((void *)((uint32_t)(ptr)|0x44000000))
|
|
#define TO_GU_POINTER(ptr) ((void *)((uint32_t)(ptr)&~0x44000000))
|
|
|
|
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;
|
|
|
|
typedef struct psp1_video
|
|
{
|
|
void* main_dList;
|
|
void* frame_dList;
|
|
void* draw_buffer;
|
|
void* texture;
|
|
psp1_sprite_t* frame_coords;
|
|
int tex_filter;
|
|
|
|
bool vsync;
|
|
bool rgb32;
|
|
int bpp_log2;
|
|
|
|
psp1_menu_frame_t menu;
|
|
|
|
video_viewport_t vp;
|
|
|
|
unsigned rotation;
|
|
bool vblank_not_reached;
|
|
bool keep_aspect;
|
|
bool should_resize;
|
|
bool hw_render;
|
|
} psp1_video_t;
|
|
|
|
// 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;
|
|
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,
|
|
int width, int height)
|
|
{
|
|
int i;
|
|
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;
|
|
u0 += step_u;
|
|
framecoords[i].v1.u = u0;
|
|
framecoords[i].v1.v = v0 + step_v;
|
|
|
|
if (++current_column == PSP_FRAME_COLUMNS_COUNT)
|
|
{
|
|
u0 = 0;
|
|
v0 += step_v;
|
|
current_column = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void psp_update_viewport(psp1_video_t* psp,
|
|
video_frame_info_t *video_info);
|
|
|
|
static void psp_on_vblank(u32 sub, psp1_video_t *psp)
|
|
{
|
|
if (psp)
|
|
psp->vblank_not_reached = false;
|
|
}
|
|
|
|
static void *psp_init(const video_info_t *video,
|
|
const input_driver_t **input, void **input_data)
|
|
{
|
|
/* TODO : add ASSERT() checks or use main RAM if
|
|
* VRAM is too low for desired video->input_scale. */
|
|
|
|
int pixel_format, lut_pixel_format, lut_block_count;
|
|
unsigned int red_shift, color_mask;
|
|
void *pspinput = NULL;
|
|
void *displayBuffer = NULL;
|
|
void *LUT_r = NULL;
|
|
void *LUT_b = NULL;
|
|
psp1_video_t *psp = (psp1_video_t*)calloc(1, sizeof(psp1_video_t));
|
|
|
|
if (!psp)
|
|
return NULL;
|
|
|
|
sceGuInit();
|
|
|
|
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
|
|
* 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
|
|
* uncached pointers to write to them. */
|
|
|
|
/* Allocate more space if bigger display lists are needed. */
|
|
psp->main_dList = memalign(64, 256);
|
|
|
|
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,
|
|
(((PSP_FRAME_SLICE_COUNT * sizeof(psp1_sprite_t)) + 63) & ~63));
|
|
psp->menu.frame_coords = memalign(64,
|
|
(((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();
|
|
psp->frame_coords = TO_UNCACHED_PTR(psp->frame_coords);
|
|
psp->menu.frame_coords = TO_UNCACHED_PTR(psp->menu.frame_coords);
|
|
|
|
psp->frame_coords->v0.x = 60;
|
|
psp->frame_coords->v0.y = 0;
|
|
psp->frame_coords->v0.u = 0;
|
|
psp->frame_coords->v0.v = 0;
|
|
|
|
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;
|
|
|
|
psp->vsync = video->vsync;
|
|
psp->rgb32 = video->rgb32;
|
|
|
|
if(psp->rgb32)
|
|
{
|
|
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);
|
|
|
|
red_shift = 8 + 8;
|
|
color_mask = 0xFF;
|
|
lut_block_count = (1 << 8) / 8;
|
|
|
|
psp->texture = (void*)(LUT_b_local + (1 << 8));
|
|
psp->draw_buffer = SCEGU_VRAM_BP32_0;
|
|
psp->bpp_log2 = 2;
|
|
|
|
pixel_format = GU_PSM_8888;
|
|
lut_pixel_format = GU_PSM_T32;
|
|
|
|
displayBuffer = SCEGU_VRAM_BP32_1;
|
|
|
|
for (i = 0; i < (1 << 8); i++)
|
|
{
|
|
LUT_r_local[i] = i;
|
|
LUT_b_local[i] = i << (8 + 8);
|
|
}
|
|
|
|
LUT_r = (void*)LUT_r_local;
|
|
LUT_b = (void*)LUT_b_local;
|
|
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
|
|
red_shift = 6 + 5;
|
|
color_mask = 0x1F;
|
|
lut_block_count = (1 << 5) / 8;
|
|
|
|
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)
|
|
? GU_PSM_5551 : GU_PSM_5650 ;
|
|
|
|
lut_pixel_format = GU_PSM_T16;
|
|
|
|
displayBuffer = SCEGU_VRAM_BP_1;
|
|
|
|
for (i = 0; i < (1 << 5); i++)
|
|
{
|
|
LUT_r_local[i] = i;
|
|
LUT_b_local[i] = i << (5 + 6);
|
|
}
|
|
|
|
LUT_r = (void*)LUT_r_local;
|
|
LUT_b = (void*)LUT_b_local;
|
|
|
|
}
|
|
|
|
psp->tex_filter = video->smooth? GU_LINEAR : GU_NEAREST;
|
|
|
|
/* TODO: check if necessary. */
|
|
sceDisplayWaitVblankStart();
|
|
|
|
sceGuDisplay(GU_FALSE);
|
|
|
|
sceGuStart(GU_DIRECT, psp->main_dList);
|
|
|
|
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);
|
|
sceGuScissor(0, 0, SCEGU_SCR_WIDTH, SCEGU_SCR_HEIGHT);
|
|
sceGuEnable(GU_SCISSOR_TEST);
|
|
sceGuTexFilter(psp->tex_filter, psp->tex_filter);
|
|
sceGuTexWrap (GU_CLAMP, GU_CLAMP);
|
|
sceGuEnable(GU_TEXTURE_2D);
|
|
sceGuDisable(GU_DEPTH_TEST);
|
|
sceGuCallMode(GU_FALSE);
|
|
|
|
sceGuFinish();
|
|
sceGuSync(0, 0);
|
|
|
|
/* TODO : check if necessary */
|
|
sceDisplayWaitVblankStart();
|
|
sceGuDisplay(GU_TRUE);
|
|
|
|
pspDebugScreenSetColorMode(pixel_format);
|
|
pspDebugScreenSetBase(psp->draw_buffer);
|
|
|
|
/* 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);
|
|
|
|
/* green only */
|
|
sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, 0x0000FF00, 0xFFFFFFFF);
|
|
|
|
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
|
|
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
|
|
(void*)(psp->frame_coords));
|
|
|
|
/* 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);
|
|
|
|
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 |
|
|
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
|
|
(void*)(psp->frame_coords));
|
|
|
|
sceGuFinish();
|
|
|
|
if (input && input_data)
|
|
{
|
|
settings_t *settings = config_get_ptr();
|
|
pspinput = input_psp.init(settings->arrays.input_joypad_driver);
|
|
*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);
|
|
|
|
psp->keep_aspect = true;
|
|
psp->should_resize = true;
|
|
psp->hw_render = false;
|
|
|
|
return psp;
|
|
}
|
|
|
|
#if 0
|
|
#define DISPLAY_FPS
|
|
#endif
|
|
|
|
static bool psp_frame(void *data, const void *frame,
|
|
unsigned width, unsigned height, uint64_t frame_count,
|
|
unsigned pitch, const char *msg, video_frame_info_t *video_info)
|
|
{
|
|
#ifdef DISPLAY_FPS
|
|
uint32_t diff;
|
|
static uint64_t currentTick,lastTick;
|
|
static int frames;
|
|
static float fps = 0.0;
|
|
#endif
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
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)
|
|
sceGuSync(0, 0); /* let the core decide when to sync when HW_RENDER */
|
|
|
|
pspDebugScreenSetBase(psp->draw_buffer);
|
|
|
|
pspDebugScreenSetXY(0,0);
|
|
|
|
if (video_info->fps_show)
|
|
{
|
|
pspDebugScreenSetXY(68 - strlen(video_info->fps_text) - 1,0);
|
|
pspDebugScreenPuts(video_info->fps_text);
|
|
pspDebugScreenSetXY(0,1);
|
|
}
|
|
|
|
if (msg)
|
|
pspDebugScreenPuts(msg);
|
|
|
|
if ((psp->vsync)&&(psp->vblank_not_reached))
|
|
sceDisplayWaitVblankStart();
|
|
|
|
psp->vblank_not_reached = true;
|
|
|
|
#ifdef DISPLAY_FPS
|
|
frames++;
|
|
sceRtcGetCurrentTick(¤tTick);
|
|
diff = currentTick - lastTick;
|
|
if(diff > 1000000)
|
|
{
|
|
fps = (float)frames * 1000000.0 / diff;
|
|
lastTick = currentTick;
|
|
frames = 0;
|
|
}
|
|
|
|
pspDebugScreenSetXY(0,0);
|
|
pspDebugScreenPrintf("%f", fps);
|
|
#endif
|
|
|
|
psp->draw_buffer = FROM_GU_POINTER(sceGuSwapBuffers());
|
|
|
|
if (psp->should_resize)
|
|
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
|
|
* set in core so draw directly */
|
|
if (psp->hw_render)
|
|
sceGuDrawArray(GU_SPRITES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF |
|
|
GU_TRANSFORM_2D, PSP_FRAME_VERTEX_COUNT, NULL,
|
|
(void*)(psp->frame_coords));
|
|
else
|
|
{
|
|
if (frame)
|
|
{
|
|
sceKernelDcacheWritebackRange(frame,pitch * height);
|
|
sceGuCopyImage(psp->rgb32? GU_PSM_8888 : GU_PSM_5650, ((u32)frame & 0xF) >> psp->bpp_log2,
|
|
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
|
|
menu_driver_frame(video_info);
|
|
#endif
|
|
|
|
if(psp->menu.active)
|
|
{
|
|
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)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
if (psp)
|
|
psp->vsync = !toggle;
|
|
}
|
|
|
|
static bool psp_alive(void *data)
|
|
{
|
|
(void)data;
|
|
return true;
|
|
}
|
|
|
|
static bool psp_focus(void *data)
|
|
{
|
|
(void)data;
|
|
return true;
|
|
}
|
|
|
|
static bool psp_suppress_screensaver(void *data, bool enable)
|
|
{
|
|
(void)data;
|
|
(void)enable;
|
|
return false;
|
|
}
|
|
|
|
static void psp_free(void *data)
|
|
{
|
|
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));
|
|
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)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
(void) rgb32;
|
|
(void) alpha;
|
|
|
|
#ifdef DEBUG
|
|
/* psp->menu.frame buffer size is (480 * 272)*2 Bytes */
|
|
retro_assert((width*height) < (480 * 272));
|
|
#endif
|
|
|
|
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);
|
|
sceGuCopyImage(GU_PSM_4444, 0, 0, width, height, width,
|
|
(void*)frame, 0, 0, width, psp->menu.frame);
|
|
sceGuFinish();
|
|
|
|
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);
|
|
sceGuTexImage(0, next_pow2(width), next_pow2(height), width, psp->menu.frame);
|
|
sceGuEnable(GU_BLEND);
|
|
|
|
#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 |
|
|
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)
|
|
{
|
|
(void) full_screen;
|
|
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
if (psp)
|
|
psp->menu.active = state;
|
|
}
|
|
|
|
static void psp_update_viewport(psp1_video_t* psp,
|
|
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();
|
|
|
|
if (settings->bools.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 (settings->uints.video_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 = 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_set_rotation(void *data, unsigned rotation)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
if (!psp)
|
|
return;
|
|
|
|
psp->rotation = rotation;
|
|
psp->should_resize = true;
|
|
}
|
|
static void psp_set_filtering(void *data, unsigned index, bool smooth)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
if (psp)
|
|
psp->tex_filter = smooth? GU_LINEAR : GU_NEAREST;
|
|
}
|
|
|
|
static void psp_set_aspect_ratio(void *data, unsigned aspect_ratio_idx)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
switch (aspect_ratio_idx)
|
|
{
|
|
case ASPECT_RATIO_SQUARE:
|
|
video_driver_set_viewport_square_pixel();
|
|
break;
|
|
|
|
case ASPECT_RATIO_CORE:
|
|
video_driver_set_viewport_core();
|
|
break;
|
|
|
|
case ASPECT_RATIO_CONFIG:
|
|
video_driver_set_viewport_config();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
video_driver_set_aspect_ratio_value(aspectratio_lut[aspect_ratio_idx].value);
|
|
|
|
psp->keep_aspect = true;
|
|
psp->should_resize = true;
|
|
}
|
|
|
|
static void psp_apply_state_changes(void *data)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
if (psp)
|
|
psp->should_resize = true;
|
|
}
|
|
|
|
static void psp_viewport_info(void *data, struct video_viewport *vp)
|
|
{
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
if (psp)
|
|
*vp = psp->vp;
|
|
}
|
|
|
|
static const video_poke_interface_t psp_poke_interface = {
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
psp_set_filtering,
|
|
NULL, /* get_video_output_size */
|
|
NULL, /* get_video_output_prev */
|
|
NULL, /* get_video_output_next */
|
|
NULL, /* get_current_framebuffer */
|
|
NULL, /* get_proc_address */
|
|
psp_set_aspect_ratio,
|
|
psp_apply_state_changes,
|
|
#ifdef HAVE_MENU
|
|
psp_set_texture_frame,
|
|
psp_set_texture_enable,
|
|
#endif
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
static void psp_get_poke_interface(void *data,
|
|
const video_poke_interface_t **iface)
|
|
{
|
|
(void)data;
|
|
*iface = &psp_poke_interface;
|
|
}
|
|
|
|
static bool psp_read_viewport(void *data, uint8_t *buffer, bool is_idle)
|
|
{
|
|
void* src_buffer;
|
|
int i, j, src_bufferwidth, src_pixelformat, src_x, src_y, src_x_max, src_y_max;
|
|
uint8_t* dst = buffer;
|
|
psp1_video_t *psp = (psp1_video_t*)data;
|
|
|
|
(void)data;
|
|
(void)buffer;
|
|
|
|
sceDisplayGetFrameBuf(&src_buffer, &src_bufferwidth, &src_pixelformat, PSP_DISPLAY_SETBUF_NEXTFRAME);
|
|
|
|
src_x = (psp->vp.x > 0)? psp->vp.x : 0;
|
|
src_y = (psp->vp.y > 0)? psp->vp.y : 0;
|
|
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)
|
|
{
|
|
(void)data;
|
|
(void)type;
|
|
(void)path;
|
|
|
|
return false;
|
|
}
|
|
|
|
video_driver_t video_psp1 = {
|
|
psp_init,
|
|
psp_frame,
|
|
psp_set_nonblock_state,
|
|
psp_alive,
|
|
psp_focus,
|
|
psp_suppress_screensaver,
|
|
NULL, /* has_windowed */
|
|
psp_set_shader,
|
|
psp_free,
|
|
"psp1",
|
|
NULL, /* set_viewport */
|
|
psp_set_rotation,
|
|
psp_viewport_info,
|
|
psp_read_viewport,
|
|
NULL, /* read_frame_raw */
|
|
#ifdef HAVE_OVERLAY
|
|
NULL,
|
|
#endif
|
|
psp_get_poke_interface
|
|
};
|