Merge branch 'master' into fh/win32-winresize
This commit is contained in:
commit
3d1b82854e
|
@ -1,4 +1,5 @@
|
|||
#include "aica.h"
|
||||
#include "aica_if.h"
|
||||
#include "sgc_if.h"
|
||||
#include "aica_mem.h"
|
||||
#include <math.h>
|
||||
|
@ -180,6 +181,7 @@ template void WriteAicaReg<2>(u32 reg,u32 data);
|
|||
s32 libAICA_Init()
|
||||
{
|
||||
init_mem();
|
||||
aica_Init();
|
||||
|
||||
verify(sizeof(*CommonData)==0x508);
|
||||
verify(sizeof(*DSPData)==0x15C8);
|
||||
|
@ -203,9 +205,12 @@ s32 libAICA_Init()
|
|||
return rv_ok;
|
||||
}
|
||||
|
||||
void libAICA_Reset(bool m)
|
||||
void libAICA_Reset(bool manual)
|
||||
{
|
||||
if (!manual)
|
||||
init_mem();
|
||||
sgc_Init();
|
||||
aica_Reset(manual);
|
||||
}
|
||||
|
||||
void libAICA_Term()
|
||||
|
|
|
@ -18,6 +18,7 @@ u32 VREG;//video reg =P
|
|||
u32 ARMRST;//arm reset reg
|
||||
u32 rtc_EN=0;
|
||||
int dma_sched_id;
|
||||
u32 RealTimeClock;
|
||||
|
||||
u32 GetRTC_now()
|
||||
{
|
||||
|
@ -39,9 +40,9 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz)
|
|||
switch( addr & 0xFF )
|
||||
{
|
||||
case 0:
|
||||
return settings.dreamcast.RTC>>16;
|
||||
return RealTimeClock>>16;
|
||||
case 4:
|
||||
return settings.dreamcast.RTC &0xFFFF;
|
||||
return RealTimeClock &0xFFFF;
|
||||
case 8:
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,16 +58,16 @@ void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz)
|
|||
case 0:
|
||||
if (rtc_EN)
|
||||
{
|
||||
settings.dreamcast.RTC&=0xFFFF;
|
||||
settings.dreamcast.RTC|=(data&0xFFFF)<<16;
|
||||
RealTimeClock&=0xFFFF;
|
||||
RealTimeClock|=(data&0xFFFF)<<16;
|
||||
rtc_EN=0;
|
||||
}
|
||||
return;
|
||||
case 4:
|
||||
if (rtc_EN)
|
||||
{
|
||||
settings.dreamcast.RTC&=0xFFFF0000;
|
||||
settings.dreamcast.RTC|= data&0xFFFF;
|
||||
RealTimeClock&=0xFFFF0000;
|
||||
RealTimeClock|= data&0xFFFF;
|
||||
//TODO: Clean the internal timer ?
|
||||
}
|
||||
return;
|
||||
|
@ -153,15 +154,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
|
|||
//Init/res/term
|
||||
void aica_Init()
|
||||
{
|
||||
//mmnnn ? gotta fill it w/ something
|
||||
RealTimeClock = GetRTC_now();
|
||||
}
|
||||
|
||||
void aica_Reset(bool Manual)
|
||||
{
|
||||
if (!Manual)
|
||||
{
|
||||
aica_ram.Zero();
|
||||
}
|
||||
aica_Init();
|
||||
}
|
||||
|
||||
void aica_Term()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
extern u32 VREG;
|
||||
extern VArray2 aica_ram;
|
||||
extern u32 RealTimeClock;
|
||||
u32 ReadMem_aica_rtc(u32 addr,u32 sz);
|
||||
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);
|
||||
u32 ReadMem_aica_reg(u32 addr,u32 sz);
|
||||
|
@ -17,4 +18,4 @@ void aica_Term();
|
|||
|
||||
void aica_sb_Init();
|
||||
void aica_sb_Reset(bool Manual);
|
||||
void aica_sb_Term();
|
||||
void aica_sb_Term();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "maple_devs.h"
|
||||
#include "maple_cfg.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
|
||||
#define HAS_VMU
|
||||
/*
|
||||
|
@ -28,13 +29,31 @@ extern u16 kcode[4];
|
|||
extern u32 vks[4];
|
||||
extern s8 joyx[4],joyy[4];
|
||||
extern u8 rt[4],lt[4];
|
||||
extern bool naomi_test_button;
|
||||
|
||||
u8 GetBtFromSgn(s8 val)
|
||||
{
|
||||
return val+128;
|
||||
}
|
||||
|
||||
u32 awave_button_mapping[] = {
|
||||
AWAVE_SERVICE_KEY, // DC_BTN_C
|
||||
AWAVE_BTN1_KEY, // DC_BTN_B
|
||||
AWAVE_BTN0_KEY, // DC_BTN_A
|
||||
AWAVE_START_KEY, // DC_BTN_START
|
||||
AWAVE_UP_KEY, // DC_DPAD_UP
|
||||
AWAVE_DOWN_KEY, // DC_DPAD_DOWN
|
||||
AWAVE_LEFT_KEY, // DC_DPAD_LEFT
|
||||
AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
AWAVE_TEST_KEY, // DC_BTN_Z
|
||||
AWAVE_BTN3_KEY, // DC_BTN_Y
|
||||
AWAVE_BTN2_KEY, // DC_BTN_X
|
||||
AWAVE_COIN_KEY, // DC_BTN_D
|
||||
// DC_DPAD2_UP
|
||||
// DC_DPAD2_DOWN
|
||||
// DC_DPAD2_LEFT
|
||||
// DC_DPAD2_RIGHT
|
||||
};
|
||||
|
||||
struct MapleConfigMap : IMapleConfigMap
|
||||
{
|
||||
maple_device* dev;
|
||||
|
@ -59,17 +78,32 @@ struct MapleConfigMap : IMapleConfigMap
|
|||
|
||||
pjs->kcode=kcode[player_num];
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
pjs->kcode |= 0xF901;
|
||||
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
if (naomi_test_button)
|
||||
pjs->kcode &= ~(1 << 14);
|
||||
// if (!(pjs->kcode & (1 << 9))) // Hack (Y -> service btn)
|
||||
// pjs->kcode &= ~(1 << 13);
|
||||
#endif
|
||||
pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
|
||||
pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
|
||||
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
|
||||
pjs->trigger[PJTI_R]=rt[player_num];
|
||||
pjs->trigger[PJTI_L]=lt[player_num];
|
||||
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
pjs->kcode = 0xFFFF;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((kcode[player_num] & (1 << i)) == 0)
|
||||
pjs->kcode &= ~awave_button_mapping[i];
|
||||
}
|
||||
pjs->joy[PJAI_X1] = GetBtFromSgn(joyx[player_num]);
|
||||
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[1].name != NULL && NaomiGameInputs->axes[1].type == Half)
|
||||
{
|
||||
// Driving games: put axis 2 on RT (accel) and axis 3 on LT (brake)
|
||||
pjs->joy[PJAI_Y1] = rt[player_num];
|
||||
pjs->joy[PJAI_X2] = lt[player_num];
|
||||
}
|
||||
else
|
||||
{
|
||||
pjs->joy[PJAI_Y1] = GetBtFromSgn(joyy[player_num]);
|
||||
pjs->joy[PJAI_X2] = rt[player_num];
|
||||
pjs->joy[PJAI_Y2] = lt[player_num];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void SetImage(void* img)
|
||||
{
|
||||
|
@ -77,6 +111,16 @@ struct MapleConfigMap : IMapleConfigMap
|
|||
}
|
||||
};
|
||||
|
||||
bool maple_atomiswave_coin_chute(int slot)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((kcode[slot] & (1 << i)) == 0 && awave_button_mapping[i] == AWAVE_COIN_KEY)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1)
|
||||
{
|
||||
if (MapleDevices[bus][port] != NULL)
|
||||
|
@ -100,17 +144,32 @@ void mcfg_CreateAtomisWaveControllers()
|
|||
// Then other devices on port 2 and 3 for analog axes, light guns, ...
|
||||
mcfg_Create(MDT_SegaController, 0, 5);
|
||||
mcfg_Create(MDT_SegaController, 1, 5);
|
||||
// mcfg_Create(MDT_SegaController, 2, 5, 0);
|
||||
// mcfg_Create(MDT_SegaController, 3, 5, 1);
|
||||
// mcfg_Create(MDT_LightGun, 2, 5, 0);
|
||||
// mcfg_Create(MDT_LightGun, 3, 5, 1);
|
||||
// mcfg_Create(MDT_Mouse, 2, 5, 0);
|
||||
// Guilty Gear Isuka (4P) needs 4 std controllers
|
||||
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
|
||||
// Maximum Speed same
|
||||
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
|
||||
// Sports Shooting same
|
||||
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3
|
||||
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[0].name != NULL)
|
||||
{
|
||||
// Game needs analog axes
|
||||
mcfg_Create(MDT_SegaController, 2, 5, 0);
|
||||
mcfg_Create(MDT_SegaController, 3, 5, 1);
|
||||
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
|
||||
// Maximum Speed same
|
||||
}
|
||||
else if (settings.input.JammaSetup == 1)
|
||||
{
|
||||
// 4 players
|
||||
mcfg_Create(MDT_SegaController, 2, 5);
|
||||
mcfg_Create(MDT_SegaController, 3, 5);
|
||||
}
|
||||
else if (settings.input.JammaSetup == 5)
|
||||
{
|
||||
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
|
||||
// Sports Shooting same
|
||||
mcfg_Create(MDT_LightGun, 2, 5, 0);
|
||||
mcfg_Create(MDT_LightGun, 3, 5, 1);
|
||||
}
|
||||
else if (settings.input.JammaSetup == 3)
|
||||
{
|
||||
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 2
|
||||
mcfg_Create(MDT_Mouse, 2, 5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void mcfg_CreateDevices()
|
||||
|
|
|
@ -68,3 +68,5 @@ void mcfg_CreateAtomisWaveControllers();
|
|||
void mcfg_DestroyDevices();
|
||||
void mcfg_SerializeDevices(void **data, unsigned int *total_size);
|
||||
void mcfg_UnserializeDevices(void **data, unsigned int *total_size);
|
||||
|
||||
bool maple_atomiswave_coin_chute(int slot);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "hw/naomi/naomi.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
#include "hw/pvr/spg.h"
|
||||
#include "input/gamepad.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "deps/zlib/zlib.h"
|
||||
|
@ -198,6 +199,35 @@ struct maple_base: maple_device
|
|||
*/
|
||||
struct maple_sega_controller: maple_base
|
||||
{
|
||||
virtual u32 get_capabilities() {
|
||||
// byte 0: 0 0 0 0 0 0 0 0
|
||||
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
|
||||
// byte 2: R2 L2 D2 U2 D X Y Z
|
||||
// byte 3: R L D U St A B C
|
||||
|
||||
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
|
||||
}
|
||||
|
||||
virtual u32 transform_kcode(u32 kcode) {
|
||||
return kcode;
|
||||
}
|
||||
|
||||
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) {
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return pjs.trigger[PJTI_R]; // Right trigger
|
||||
case 1:
|
||||
return pjs.trigger[PJTI_L]; // Left trigger
|
||||
case 2:
|
||||
return pjs.joy[PJAI_X1]; // Stick X
|
||||
case 3:
|
||||
return pjs.joy[PJAI_Y1]; // Stick Y
|
||||
default:
|
||||
return 0x80; // unused
|
||||
}
|
||||
}
|
||||
|
||||
virtual MapleDeviceType get_device_type()
|
||||
{
|
||||
return MDT_SegaController;
|
||||
|
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
|
|||
|
||||
//struct data
|
||||
//3*4
|
||||
w32( 0xfe060f00);
|
||||
w32( 0);
|
||||
w32( 0);
|
||||
w32(get_capabilities());
|
||||
w32(0);
|
||||
w32(0);
|
||||
|
||||
//1 area code
|
||||
w8(0xFF);
|
||||
|
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
|
|||
|
||||
//state data
|
||||
//2 key code
|
||||
w16(pjs.kcode);
|
||||
w16(transform_kcode(pjs.kcode));
|
||||
|
||||
//triggers
|
||||
//1 R
|
||||
w8(pjs.trigger[PJTI_R]);
|
||||
w8(get_analog_axis(0, pjs));
|
||||
//1 L
|
||||
w8(pjs.trigger[PJTI_L]);
|
||||
w8(get_analog_axis(1, pjs));
|
||||
|
||||
//joyx
|
||||
//1
|
||||
w8(pjs.joy[PJAI_X1]);
|
||||
w8(get_analog_axis(2, pjs));
|
||||
//joyy
|
||||
//1
|
||||
w8(pjs.joy[PJAI_Y1]);
|
||||
w8(get_analog_axis(3, pjs));
|
||||
|
||||
//not used
|
||||
//1
|
||||
w8(0x80);
|
||||
w8(get_analog_axis(4, pjs));
|
||||
//1
|
||||
w8(0x80);
|
||||
w8(get_analog_axis(5, pjs));
|
||||
}
|
||||
|
||||
return MDRS_DataTransfer;
|
||||
|
@ -281,6 +311,38 @@ struct maple_sega_controller: maple_base
|
|||
}
|
||||
};
|
||||
|
||||
struct maple_atomiswave_controller: maple_sega_controller
|
||||
{
|
||||
virtual u32 get_capabilities() override {
|
||||
// byte 0: 0 0 0 0 0 0 0 0
|
||||
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
|
||||
// byte 2: R2 L2 D2 U2 D X Y Z
|
||||
// byte 3: R L D U St A B C
|
||||
|
||||
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
|
||||
}
|
||||
|
||||
virtual u32 transform_kcode(u32 kcode) override {
|
||||
return kcode | AWAVE_TRIGGER_KEY;
|
||||
}
|
||||
|
||||
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
|
||||
switch (index)
|
||||
{
|
||||
case 2:
|
||||
return pjs.joy[PJAI_X1];
|
||||
case 3:
|
||||
return pjs.joy[PJAI_Y1];
|
||||
case 4:
|
||||
return pjs.joy[PJAI_X2];
|
||||
case 5:
|
||||
return pjs.joy[PJAI_Y2];
|
||||
default:
|
||||
return 0x80;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Sega Dreamcast Visual Memory Unit
|
||||
This is pretty much done (?)
|
||||
|
@ -1267,6 +1329,10 @@ struct maple_mouse : maple_base
|
|||
|
||||
struct maple_lightgun : maple_base
|
||||
{
|
||||
virtual u32 transform_kcode(u32 kcode) {
|
||||
return kcode | 0xFF01;
|
||||
}
|
||||
|
||||
virtual MapleDeviceType get_device_type()
|
||||
{
|
||||
return MDT_LightGun;
|
||||
|
@ -1315,21 +1381,13 @@ struct maple_lightgun : maple_base
|
|||
PlainJoystickState pjs;
|
||||
config->GetInput(&pjs);
|
||||
|
||||
// Also use the mouse buttons
|
||||
if (!(mo_buttons & 4)) // Left button
|
||||
pjs.kcode &= ~4; // A
|
||||
if (!(mo_buttons & 2)) // Right button
|
||||
pjs.kcode &= ~2; // B
|
||||
if (!(mo_buttons & 8)) // Wheel button
|
||||
pjs.kcode &= ~8; // Start
|
||||
|
||||
//caps
|
||||
//4
|
||||
w32(MFID_0_Input);
|
||||
|
||||
//state data
|
||||
//2 key code
|
||||
w16(pjs.kcode | 0xFF01);
|
||||
w16(transform_kcode(pjs.kcode));
|
||||
|
||||
//not used
|
||||
//2
|
||||
|
@ -1355,6 +1413,13 @@ struct maple_lightgun : maple_base
|
|||
}
|
||||
};
|
||||
|
||||
struct atomiswave_lightgun : maple_lightgun
|
||||
{
|
||||
virtual u32 transform_kcode(u32 kcode) override {
|
||||
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
|
||||
}
|
||||
};
|
||||
|
||||
extern u16 kcode[4];
|
||||
extern s8 joyx[4],joyy[4];
|
||||
extern u8 rt[4], lt[4];
|
||||
|
@ -1381,20 +1446,29 @@ static u16 getRightTriggerAxis()
|
|||
return rt[0] << 8;
|
||||
}
|
||||
|
||||
NaomiInputMapping Naomi_Mapping = {
|
||||
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
|
||||
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 },
|
||||
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3
|
||||
u32 naomi_button_mapping[] = {
|
||||
NAOMI_SERVICE_KEY, // DC_BTN_C
|
||||
NAOMI_BTN1_KEY, // DC_BTN_B
|
||||
NAOMI_BTN0_KEY, // DC_BTN_A
|
||||
NAOMI_START_KEY, // DC_BTN_START
|
||||
NAOMI_UP_KEY, // DC_DPAD_UP
|
||||
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
|
||||
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
|
||||
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||
NAOMI_TEST_KEY, // DC_BTN_Z
|
||||
NAOMI_BTN3_KEY, // DC_BTN_Y
|
||||
NAOMI_BTN2_KEY, // DC_BTN_X
|
||||
NAOMI_COIN_KEY, // DC_BTN_D
|
||||
// DC_DPAD2_UP
|
||||
// DC_DPAD2_DOWN
|
||||
// DC_DPAD2_LEFT
|
||||
// DC_DPAD2_RIGHT
|
||||
};
|
||||
|
||||
/*
|
||||
* Sega JVS I/O board
|
||||
*/
|
||||
bool coin_chute;
|
||||
static bool old_coin_chute;
|
||||
static int coin_count;
|
||||
bool naomi_test_button = false;
|
||||
static bool old_coin_chute[4];
|
||||
static int coin_count[4];
|
||||
|
||||
struct maple_naomi_jamma;
|
||||
|
||||
|
@ -2313,63 +2387,56 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
{
|
||||
JVS_STATUS1(); // report byte
|
||||
|
||||
LOGJVS("btns ");
|
||||
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
|
||||
// FIXME in-lst mapping
|
||||
u8 buttons[8] = { 0 };
|
||||
u32 keycode = ~kcode[0];
|
||||
for (int i = 0; i < 16; i++)
|
||||
if ((keycode & (1 << i)) != 0)
|
||||
{
|
||||
buttons[Naomi_Mapping.button_mapping_byte[i]] |= Naomi_Mapping.button_mapping_mask[i];
|
||||
}
|
||||
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
|
||||
u16 buttons[4] = { 0 };
|
||||
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
|
||||
{
|
||||
u8 *cur_btns = &buttons[(first_player + player) * 2];
|
||||
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]);
|
||||
JVS_OUT(cur_btns[0]);
|
||||
if (buffer_in[cmdi + 2] == 2)
|
||||
u32 keycode = ~kcode[first_player + player];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
LOGJVS("%02x ", cur_btns[1]);
|
||||
JVS_OUT(cur_btns[1]);
|
||||
if ((keycode & (1 << i)) != 0)
|
||||
buttons[player] |= naomi_button_mapping[i];
|
||||
}
|
||||
}
|
||||
|
||||
LOGJVS("btns ");
|
||||
JVS_OUT((buttons[0] & NAOMI_TEST_KEY) ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
|
||||
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
|
||||
{
|
||||
u16 cur_btns = first_player + player < ARRAY_SIZE(buttons) ? buttons[first_player + player] : 0;
|
||||
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns >> 8);
|
||||
JVS_OUT(cur_btns >> 8);
|
||||
if (buffer_in[cmdi + 2] == 2)
|
||||
{
|
||||
LOGJVS("%02x ", cur_btns & 0xFF);
|
||||
JVS_OUT(cur_btns);
|
||||
}
|
||||
}
|
||||
// for (int player = 0; player < jvs_request[channel][cmdi + 1]; player++)
|
||||
// {
|
||||
// u32 keycode = ~kcode[player];
|
||||
// if (keycode & DC_BTN_C)
|
||||
// keycode |= 0xFFff;
|
||||
//
|
||||
// if (jvs_request[channel][cmdi + 2] == 1)
|
||||
// JVS_OUT(keycode);
|
||||
// else
|
||||
// w16(keycode);
|
||||
// }
|
||||
cmdi += 3;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21: // Read coins
|
||||
{
|
||||
if (coin_chute && !old_coin_chute)
|
||||
coin_count++;
|
||||
old_coin_chute = coin_chute;
|
||||
JVS_STATUS1(); // report byte
|
||||
LOGJVS("coins ");
|
||||
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++)
|
||||
{
|
||||
if (slot == 0)
|
||||
bool coin_chute = false;
|
||||
u32 keycode = ~kcode[first_player + slot];
|
||||
for (int i = 0; i < 16 && !coin_chute; i++)
|
||||
{
|
||||
LOGJVS("0:%d ", coin_count);
|
||||
JVS_OUT((coin_count >> 8) & 0x3F); // status (2 highest bits, 0: normal), coin count MSB
|
||||
JVS_OUT(coin_count); // coin count LSB
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGJVS("%d:0 ", slot);
|
||||
JVS_OUT(0);
|
||||
JVS_OUT(0);
|
||||
if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
|
||||
coin_chute = true;
|
||||
}
|
||||
if (coin_chute && !old_coin_chute[first_player + slot])
|
||||
coin_count[first_player + slot] += 1;
|
||||
old_coin_chute[first_player + slot] = coin_chute;
|
||||
|
||||
LOGJVS("%d:%d ", slot + 1 + first_player, coin_count[first_player + slot]);
|
||||
// status (2 highest bits, 0: normal), coin count MSB
|
||||
JVS_OUT((coin_count[first_player + slot] >> 8) & 0x3F);
|
||||
// coin count LSB
|
||||
JVS_OUT(coin_count[first_player + slot]);
|
||||
}
|
||||
cmdi += 2;
|
||||
}
|
||||
|
@ -2393,34 +2460,50 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
}
|
||||
LOGJVS("x,y:%4x,%4x ", x, y);
|
||||
JVS_OUT(x >> 8); // X, MSB
|
||||
JVS_OUT(x); // X, LSB
|
||||
JVS_OUT(x); // X, LSB
|
||||
JVS_OUT(y >> 8); // Y, MSB
|
||||
JVS_OUT(y); // Y, LSB
|
||||
JVS_OUT(y); // Y, LSB
|
||||
axis = 2;
|
||||
}
|
||||
|
||||
int full_axis_count = 0;
|
||||
int half_axis_count = 0;
|
||||
for (; axis < buffer_in[cmdi + 1]; axis++)
|
||||
{
|
||||
// FIXME Need to know how many axes per player for proper mapping
|
||||
u16 axis_value;
|
||||
if (axis + first_player * 4 < 8 && Naomi_Mapping.axis[axis + first_player * 4] != NULL)
|
||||
axis_value = Naomi_Mapping.axis[axis + first_player * 4]();
|
||||
if (NaomiGameInputs != NULL
|
||||
&& axis < ARRAY_SIZE(NaomiGameInputs->axes)
|
||||
&& NaomiGameInputs->axes[axis].name != NULL
|
||||
&& NaomiGameInputs->axes[axis].type == Half)
|
||||
{
|
||||
if (half_axis_count == 0)
|
||||
axis_value = rt[first_player] << 8;
|
||||
else if (half_axis_count == 1)
|
||||
axis_value = lt[first_player] << 8;
|
||||
else
|
||||
axis_value = 0;
|
||||
half_axis_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (axis) {
|
||||
switch (full_axis_count) {
|
||||
case 0:
|
||||
axis_value = (joyx[first_player + axis / 4] + 128) << 8;
|
||||
axis_value = (joyx[first_player] + 128) << 8;
|
||||
break;
|
||||
case 1:
|
||||
axis_value = (joyy[first_player + axis / 4] + 128) << 8;
|
||||
break;
|
||||
case 2:
|
||||
axis_value = rt[first_player + axis / 4] << 8;
|
||||
break;
|
||||
case 3:
|
||||
axis_value = lt[first_player + axis / 4] << 8;
|
||||
axis_value = (joyy[first_player] + 128) << 8;
|
||||
break;
|
||||
// TODO right analog stick
|
||||
// case 2:
|
||||
// axis_value = (joyrx[first_player] + 128) << 8;
|
||||
// break;
|
||||
// case 3:
|
||||
// axis_value = (joyry[first_player] + 128) << 8;
|
||||
// break;
|
||||
default:
|
||||
axis_value = 128;
|
||||
}
|
||||
full_axis_count++;
|
||||
}
|
||||
LOGJVS("%d:%4x ", axis, axis_value);
|
||||
JVS_OUT(axis_value >> 8);
|
||||
|
@ -2493,8 +2576,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
|||
break;
|
||||
|
||||
case 0x30: // substract coin
|
||||
if (buffer_in[cmdi + 1] == 1)
|
||||
coin_count -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
|
||||
if (buffer_in[cmdi + 1] > 0 && first_player + buffer_in[cmdi + 1] - 1 < ARRAY_SIZE(coin_count))
|
||||
coin_count[first_player + buffer_in[cmdi + 1] - 1] -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
|
||||
JVS_STATUS1(); // report byte
|
||||
cmdi += 4;
|
||||
break;
|
||||
|
@ -2542,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type)
|
|||
switch(type)
|
||||
{
|
||||
case MDT_SegaController:
|
||||
rv=new maple_sega_controller();
|
||||
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||
rv = new maple_sega_controller();
|
||||
#else
|
||||
rv = new maple_atomiswave_controller();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MDT_Microphone:
|
||||
|
@ -2566,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
|
|||
break;
|
||||
|
||||
case MDT_LightGun:
|
||||
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||
rv = new maple_lightgun();
|
||||
#else
|
||||
rv = new atomiswave_lightgun();
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MDT_NaomiJamma:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "hw/holly/sb.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/holly/holly_intc.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
|
||||
#include "naomi.h"
|
||||
#include "naomi_cart.h"
|
||||
|
@ -634,7 +635,6 @@ void Update_naomi()
|
|||
}
|
||||
|
||||
static u8 aw_maple_devs;
|
||||
extern bool coin_chute;
|
||||
|
||||
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
|
||||
addr &= 0x7ff;
|
||||
|
@ -653,12 +653,13 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
|
|||
aw_ram_test_skipped = true;
|
||||
return 0;
|
||||
}
|
||||
if (coin_chute)
|
||||
{
|
||||
// FIXME Coin Error if coin_chute is set for too long
|
||||
return 0xE;
|
||||
u8 coin_input = 0xF;
|
||||
for (int slot = 0; slot < 4; slot++)
|
||||
if (maple_atomiswave_coin_chute(slot))
|
||||
coin_input &= ~(1 << slot);
|
||||
return coin_input;
|
||||
}
|
||||
return 0xF;
|
||||
|
||||
case 0x284: // Atomiswave maple devices
|
||||
// ddcc0000 where cc/dd are the types of devices on maple bus 2 and 3:
|
||||
|
|
|
@ -32,7 +32,7 @@ fd_t* RomCacheMap = NULL;
|
|||
u32 RomCacheMapCount;
|
||||
|
||||
char naomi_game_id[33];
|
||||
InputDescriptors *naomi_game_inputs;
|
||||
InputDescriptors *NaomiGameInputs;
|
||||
u8 *naomi_default_eeprom;
|
||||
|
||||
extern RomChip sys_rom;
|
||||
|
@ -246,7 +246,7 @@ static bool naomi_cart_LoadZip(char *filename)
|
|||
break;
|
||||
}
|
||||
CurrentCartridge->SetKey(game->key);
|
||||
naomi_game_inputs = game->inputs;
|
||||
NaomiGameInputs = game->inputs;
|
||||
|
||||
for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
|
||||
{
|
||||
|
|
|
@ -110,6 +110,6 @@ struct InputDescriptors
|
|||
AxisDescriptor axes[8];
|
||||
};
|
||||
|
||||
extern InputDescriptors *naomi_game_inputs;
|
||||
extern InputDescriptors *NaomiGameInputs;
|
||||
|
||||
#endif //NAOMI_CART_H
|
||||
|
|
|
@ -304,6 +304,8 @@ void bm_Rebuild()
|
|||
{
|
||||
return;
|
||||
|
||||
die("this is broken in multiple levels, including compile options");
|
||||
|
||||
void RASDASD();
|
||||
RASDASD();
|
||||
|
||||
|
@ -321,7 +323,7 @@ void bm_Rebuild()
|
|||
//constprop(all_blocks[i]);
|
||||
//#endif
|
||||
}
|
||||
ngen_Compile(all_blocks[i],false,false,all_blocks[i]->staging_runs>0,do_opts);
|
||||
ngen_Compile(all_blocks[i],NoCheck,false,all_blocks[i]->staging_runs>0,do_opts);
|
||||
|
||||
blkmap.insert(all_blocks[i]);
|
||||
verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]);
|
||||
|
|
|
@ -86,6 +86,15 @@ void recSh4_Run()
|
|||
|
||||
sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx);
|
||||
printf("cntx // fpcb offset: %td // pc offset: %td // pc %08X\n",(u8*)&sh4rcb.fpcb - sh4_dyna_rcb, (u8*)&sh4rcb.cntx.pc - sh4_dyna_rcb,sh4rcb.cntx.pc);
|
||||
|
||||
if (!settings.dynarec.safemode)
|
||||
printf("Warning: Dynarec safe mode is off\n");
|
||||
|
||||
if (settings.dynarec.unstable_opt)
|
||||
printf("Warning: Unstable optimizations is on\n");
|
||||
|
||||
if (settings.dynarec.SmcCheckLevel != FullCheck)
|
||||
printf("Warning: SMC check mode is %d\n", settings.dynarec.SmcCheckLevel);
|
||||
|
||||
verify(rcb_noffs(&next_pc)==-184);
|
||||
ngen_mainloop(sh4_dyna_rcb);
|
||||
|
@ -119,34 +128,51 @@ u32 emit_FreeSpace()
|
|||
}
|
||||
|
||||
|
||||
bool DoCheck(u32 pc)
|
||||
SmcCheckEnum DoCheck(u32 pc)
|
||||
{
|
||||
if (IsOnRam(pc))
|
||||
{
|
||||
if (!settings.dynarec.unstable_opt)
|
||||
return true;
|
||||
|
||||
pc&=0xFFFFFF;
|
||||
switch(pc)
|
||||
{
|
||||
//DOA2LE
|
||||
case 0x3DAFC6:
|
||||
case 0x3C83F8:
|
||||
switch (settings.dynarec.SmcCheckLevel) {
|
||||
|
||||
//Shenmue 2
|
||||
case 0x348000:
|
||||
|
||||
//Shenmue
|
||||
case 0x41860e:
|
||||
|
||||
// Heuristic-elimintaed FastChecks
|
||||
case NoCheck: {
|
||||
if (IsOnRam(pc))
|
||||
{
|
||||
pc&=0xFFFFFF;
|
||||
switch(pc)
|
||||
{
|
||||
//DOA2LE
|
||||
case 0x3DAFC6:
|
||||
case 0x3C83F8:
|
||||
|
||||
return true;
|
||||
//Shenmue 2
|
||||
case 0x348000:
|
||||
|
||||
//Shenmue
|
||||
case 0x41860e:
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
return FastCheck;
|
||||
|
||||
default:
|
||||
return NoCheck;
|
||||
}
|
||||
}
|
||||
return NoCheck;
|
||||
}
|
||||
break;
|
||||
|
||||
// Fast Check everything
|
||||
case FastCheck:
|
||||
return FastCheck;
|
||||
|
||||
// Full Check everything
|
||||
case FullCheck:
|
||||
return FullCheck;
|
||||
|
||||
default:
|
||||
die("Unhandled settings.dynarec.SmcCheckLevel");
|
||||
return FullCheck;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnalyseBlock(RuntimeBlockInfo* blk);
|
||||
|
|
|
@ -85,7 +85,7 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc);
|
|||
void ngen_init();
|
||||
|
||||
//Called to compile a block
|
||||
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise);
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise);
|
||||
|
||||
//Called when blocks are reseted
|
||||
void ngen_ResetBlocks();
|
||||
|
|
|
@ -232,7 +232,7 @@ int AicaUpdate(int tag, int c, int j)
|
|||
|
||||
int DreamcastSecond(int tag, int c, int j)
|
||||
{
|
||||
settings.dreamcast.RTC++;
|
||||
RealTimeClock++;
|
||||
|
||||
#if 1 //HOST_OS==OS_WINDOWS
|
||||
prof_periodical();
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
//Types
|
||||
|
||||
#define printf_smc(...) // printf
|
||||
|
||||
|
||||
u32 CCN_QACR_TR[2];
|
||||
|
||||
|
@ -72,13 +74,18 @@ void CCN_CCR_write(u32 addr, u32 value)
|
|||
temp.reg_data=value;
|
||||
|
||||
|
||||
//what is 0xAC13DBF8 from ?
|
||||
if (temp.ICI && curr_pc!=0xAC13DBF8)
|
||||
{
|
||||
//printf("Sh4: i-cache invalidation %08X\n",curr_pc);
|
||||
// Shikigami No Shiro II sets ICI frequently
|
||||
// Any reason to flush the dynarec cache for this?
|
||||
//sh4_cpu.ResetCache();
|
||||
if (temp.ICI) {
|
||||
printf_smc("Sh4: i-cache invalidation %08X\n",curr_pc);
|
||||
|
||||
if (settings.dynarec.SmcCheckLevel != FullCheck) {
|
||||
//TODO: Add skip/check vectors for Shikigami No Shiro II (uses ICI frequently)
|
||||
//which game is 0xAC13DBF8 from ?
|
||||
if (curr_pc != 0xAC13DBF8)
|
||||
{
|
||||
printf("Sh4: code cache clear (ICI) pc: %08X\n",curr_pc);
|
||||
sh4_cpu.ResetCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
temp.ICI=0;
|
||||
|
|
|
@ -51,7 +51,39 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
|
|||
if (key < 0x10000)
|
||||
{
|
||||
if (pressed)
|
||||
{
|
||||
kcode[_maple_port] &= ~(u16)key;
|
||||
// Avoid two opposite dpad keys being pressed simultaneously
|
||||
switch (key)
|
||||
{
|
||||
case DC_DPAD_UP:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_DOWN;
|
||||
break;
|
||||
case DC_DPAD_DOWN:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_UP;
|
||||
break;
|
||||
case DC_DPAD_LEFT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_RIGHT;
|
||||
break;
|
||||
case DC_DPAD_RIGHT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD_LEFT;
|
||||
break;
|
||||
case DC_DPAD2_UP:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_DOWN;
|
||||
break;
|
||||
case DC_DPAD2_DOWN:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_UP;
|
||||
break;
|
||||
case DC_DPAD2_LEFT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_RIGHT;
|
||||
break;
|
||||
case DC_DPAD2_RIGHT:
|
||||
kcode[_maple_port] |= (u16)DC_DPAD2_LEFT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
kcode[_maple_port] |= (u16)key;
|
||||
}
|
||||
|
|
|
@ -84,8 +84,6 @@ Atom wmDeleteMessage;
|
|||
void* x11_vis;
|
||||
|
||||
extern bool dump_frame_switch;
|
||||
extern bool naomi_test_button;
|
||||
extern bool coin_chute;
|
||||
|
||||
void dc_exit(void);
|
||||
|
||||
|
@ -275,16 +273,6 @@ void input_x11_handle()
|
|||
x11_fullscreen = !x11_fullscreen;
|
||||
x11_window_set_fullscreen(x11_fullscreen);
|
||||
}
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
else if (e.xkey.keycode == KEY_F8)
|
||||
{
|
||||
coin_chute = e.type == KeyPress;
|
||||
}
|
||||
else if (e.xkey.keycode == KEY_F7)
|
||||
{
|
||||
naomi_test_button = e.type == KeyPress;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -134,7 +134,7 @@ void LoadSpecialSettings()
|
|||
safemode_game = false;
|
||||
tr_poly_depth_mask_game = false;
|
||||
extra_depth_game = false;
|
||||
|
||||
|
||||
if (reios_windows_ce)
|
||||
{
|
||||
printf("Enabling Extra depth scaling for Windows CE games\n");
|
||||
|
@ -190,7 +190,7 @@ void LoadSpecialSettings()
|
|||
}
|
||||
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
printf("Game ID is [%s]\n", naomi_game_id);
|
||||
|
||||
|
||||
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", naomi_game_id))
|
||||
{
|
||||
printf("Enabling Dynarec safe mode for game %s\n", naomi_game_id);
|
||||
|
@ -213,12 +213,14 @@ void LoadSpecialSettings()
|
|||
printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 2;
|
||||
}
|
||||
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id))
|
||||
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi
|
||||
|| !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW
|
||||
{
|
||||
printf("Enabling 4-player setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 1;
|
||||
}
|
||||
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id))
|
||||
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)
|
||||
|| !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW
|
||||
{
|
||||
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 3;
|
||||
|
@ -228,9 +230,11 @@ void LoadSpecialSettings()
|
|||
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 4;
|
||||
}
|
||||
else if (!strcmp("NINJA ASSAULT", naomi_game_id))
|
||||
else if (!strcmp("NINJA ASSAULT", naomi_game_id)
|
||||
|| !strcmp(naomi_game_id, "Sports Shooting USA") // AW
|
||||
|| !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE")) // AW
|
||||
{
|
||||
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
|
||||
printf("Enabling lightgun setup for game %s\n", naomi_game_id);
|
||||
settings.input.JammaSetup = 5;
|
||||
}
|
||||
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
|
||||
|
@ -309,11 +313,12 @@ int dc_start_game(const char *path)
|
|||
{
|
||||
InitSettings();
|
||||
LoadSettings(false);
|
||||
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
if (!settings.bios.UseReios)
|
||||
#endif
|
||||
LoadRomFiles(get_readonly_data_path(DATA_PATH));
|
||||
if (!LoadRomFiles(get_readonly_data_path(DATA_PATH)))
|
||||
return -5;
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
if (path == NULL)
|
||||
{
|
||||
|
@ -345,7 +350,6 @@ int dc_start_game(const char *path)
|
|||
return 0;
|
||||
}
|
||||
|
||||
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
|
||||
if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
|
||||
{
|
||||
#ifdef USE_REIOS
|
||||
|
@ -485,7 +489,6 @@ void dc_exit()
|
|||
|
||||
void InitSettings()
|
||||
{
|
||||
settings.dreamcast.RTC = GetRTC_now();
|
||||
settings.dynarec.Enable = true;
|
||||
settings.dynarec.idleskip = true;
|
||||
settings.dynarec.unstable_opt = false;
|
||||
|
@ -495,9 +498,11 @@ void InitSettings()
|
|||
settings.dreamcast.broadcast = 4; // default
|
||||
settings.dreamcast.language = 6; // default
|
||||
settings.dreamcast.FullMMU = false;
|
||||
settings.dynarec.SmcCheckLevel = FullCheck;
|
||||
settings.aica.LimitFPS = true;
|
||||
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
|
||||
settings.aica.NoSound = false;
|
||||
settings.audio.backend = "auto";
|
||||
settings.rend.UseMipmaps = true;
|
||||
settings.rend.WideScreen = false;
|
||||
settings.rend.ShowFPS = false;
|
||||
|
@ -512,6 +517,10 @@ void InitSettings()
|
|||
settings.rend.CustomTextures = false;
|
||||
settings.rend.DumpTextures = false;
|
||||
settings.rend.ScreenScaling = 100;
|
||||
settings.rend.ScreenStretching = 100;
|
||||
settings.rend.Fog = true;
|
||||
settings.rend.FloatVMUs = false;
|
||||
settings.rend.Rotate90 = false;
|
||||
|
||||
settings.pvr.ta_skip = 0;
|
||||
settings.pvr.rend = 0;
|
||||
|
@ -558,11 +567,13 @@ void LoadSettings(bool game_specific)
|
|||
{
|
||||
const char *config_section = game_specific ? cfgGetGameId() : "config";
|
||||
const char *input_section = game_specific ? cfgGetGameId() : "input";
|
||||
const char *audio_section = game_specific ? cfgGetGameId() : "audio";
|
||||
|
||||
settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
|
||||
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip);
|
||||
settings.dynarec.unstable_opt = cfgLoadBool(config_section, "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
|
||||
settings.dynarec.safemode = cfgLoadBool(config_section, "Dynarec.safe-mode", settings.dynarec.safemode);
|
||||
settings.dynarec.SmcCheckLevel = (SmcCheckEnum)cfgLoadInt(config_section, "Dynarec.SmcCheckLevel", settings.dynarec.SmcCheckLevel);
|
||||
//disable_nvmem can't be loaded, because nvmem init is before cfg load
|
||||
settings.dreamcast.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable);
|
||||
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region);
|
||||
|
@ -572,6 +583,7 @@ void LoadSettings(bool game_specific)
|
|||
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
|
||||
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
|
||||
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
|
||||
settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str());
|
||||
settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
|
||||
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
|
||||
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS);
|
||||
|
@ -593,6 +605,10 @@ void LoadSettings(bool game_specific)
|
|||
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
|
||||
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
|
||||
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100);
|
||||
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
|
||||
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
|
||||
settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs);
|
||||
settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90);
|
||||
|
||||
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
|
||||
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend);
|
||||
|
@ -698,10 +714,13 @@ void SaveSettings()
|
|||
cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
|
||||
if (!safemode_game || !settings.dynarec.safemode)
|
||||
cfgSaveBool("config", "Dynarec.safe-mode", settings.dynarec.safemode);
|
||||
cfgSaveInt("config", "Dynarec.SmcCheckLevel", (int)settings.dynarec.SmcCheckLevel);
|
||||
|
||||
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
|
||||
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
|
||||
cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch);
|
||||
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound);
|
||||
cfgSaveStr("audio", "backend", settings.audio.backend.c_str());
|
||||
cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen);
|
||||
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
|
||||
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
|
||||
|
@ -714,6 +733,10 @@ void SaveSettings()
|
|||
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
|
||||
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
|
||||
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
|
||||
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
|
||||
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
|
||||
cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs);
|
||||
cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90);
|
||||
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
|
||||
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_alsa.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#if USE_ALSA
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "cfg/cfg.h"
|
||||
|
@ -175,11 +175,13 @@ static void alsa_term()
|
|||
snd_pcm_close(handle);
|
||||
}
|
||||
|
||||
audiobackend_t audiobackend_alsa = {
|
||||
static audiobackend_t audiobackend_alsa = {
|
||||
"alsa", // Slug
|
||||
"Advanced Linux Sound Architecture", // Name
|
||||
&alsa_init,
|
||||
&alsa_push,
|
||||
&alsa_term
|
||||
};
|
||||
|
||||
static bool alsa = RegisterAudioBackend(&audiobackend_alsa);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_alsa;
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_android;
|
|
@ -1,18 +1,18 @@
|
|||
/*
|
||||
Simple Core Audio backend for osx (and maybe ios?)
|
||||
Based off various audio core samples and dolphin's code
|
||||
|
||||
|
||||
This is part of the Reicast project, please consult the
|
||||
LICENSE file for licensing & related information
|
||||
|
||||
|
||||
This could do with some locking logic to avoid
|
||||
race conditions, and some variable length buffer
|
||||
logic to support chunk sizes other than 512 bytes
|
||||
|
||||
|
||||
It does work on my macmini though
|
||||
*/
|
||||
|
||||
#include "oslib/audiobackend_coreaudio.h"
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
#if HOST_OS == OS_DARWIN
|
||||
#include <atomic>
|
||||
|
@ -49,9 +49,9 @@ static OSStatus coreaudio_callback(void* ctx, AudioUnitRenderActionFlags* flags,
|
|||
samples_rptr = (samples_rptr + buf_size) % BUFSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bufferEmpty.Set();
|
||||
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ static void coreaudio_init()
|
|||
AudioStreamBasicDescription format;
|
||||
AudioComponentDescription desc;
|
||||
AudioComponent component;
|
||||
|
||||
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
#if !defined(TARGET_IPHONE)
|
||||
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
|
||||
|
@ -75,12 +75,12 @@ static void coreaudio_init()
|
|||
desc.componentFlagsMask = 0;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
component = AudioComponentFindNext(nullptr, &desc);
|
||||
|
||||
|
||||
verify(component != nullptr);
|
||||
|
||||
|
||||
err = AudioComponentInstanceNew(component, &audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
FillOutASBDForLPCM(format, 44100,
|
||||
2, 16, 16, false, false, false);
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
|
@ -88,7 +88,7 @@ static void coreaudio_init()
|
|||
kAudioUnitScope_Input, 0, &format,
|
||||
sizeof(AudioStreamBasicDescription));
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
callback_struct.inputProc = coreaudio_callback;
|
||||
callback_struct.inputProcRefCon = 0;
|
||||
err = AudioUnitSetProperty(audioUnit,
|
||||
|
@ -96,24 +96,24 @@ static void coreaudio_init()
|
|||
kAudioUnitScope_Input, 0, &callback_struct,
|
||||
sizeof callback_struct);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
/*
|
||||
err = AudioUnitSetParameter(audioUnit,
|
||||
kHALOutputParam_Volume,
|
||||
kAudioUnitParameterFlag_Output, 0,
|
||||
1, 0);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
err = AudioUnitInitialize(audioUnit);
|
||||
|
||||
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
err = AudioOutputUnitStart(audioUnit);
|
||||
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
bufferEmpty.Set();
|
||||
}
|
||||
|
||||
|
@ -134,23 +134,23 @@ static u32 coreaudio_push(void* frame, u32 samples, bool wait)
|
|||
samples_wptr = (samples_wptr + byte_size) % BUFSIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void coreaudio_term()
|
||||
{
|
||||
OSStatus err;
|
||||
|
||||
|
||||
err = AudioOutputUnitStop(audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
err = AudioUnitUninitialize(audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
err = AudioComponentInstanceDispose(audioUnit);
|
||||
verify(err == noErr);
|
||||
|
||||
|
||||
bufferEmpty.Set();
|
||||
}
|
||||
|
||||
|
@ -161,4 +161,7 @@ audiobackend_t audiobackend_coreaudio = {
|
|||
&coreaudio_push,
|
||||
&coreaudio_term
|
||||
};
|
||||
|
||||
static bool core = RegisterAudioBackend(&audiobackend_coreaudio);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_coreaudio;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_directsound.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
#include "oslib.h"
|
||||
#include <initguid.h>
|
||||
|
@ -19,31 +19,31 @@ static void directsound_init()
|
|||
verifyc(dsound->SetCooperativeLevel((HWND)libPvr_GetRenderTarget(),DSSCL_PRIORITY));
|
||||
IDirectSoundBuffer* buffer_;
|
||||
|
||||
WAVEFORMATEX wfx;
|
||||
DSBUFFERDESC desc;
|
||||
WAVEFORMATEX wfx;
|
||||
DSBUFFERDESC desc;
|
||||
|
||||
// Set up WAV format structure.
|
||||
// Set up WAV format structure.
|
||||
|
||||
memset(&wfx, 0, sizeof(WAVEFORMATEX));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = 44100;
|
||||
wfx.nBlockAlign = 4;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 16;
|
||||
memset(&wfx, 0, sizeof(WAVEFORMATEX));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = 44100;
|
||||
wfx.nBlockAlign = 4;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 16;
|
||||
|
||||
// Set up DSBUFFERDESC structure.
|
||||
// Set up DSBUFFERDESC structure.
|
||||
|
||||
ds_ring_size=8192*wfx.nBlockAlign;
|
||||
|
||||
memset(&desc, 0, sizeof(DSBUFFERDESC));
|
||||
desc.dwSize = sizeof(DSBUFFERDESC);
|
||||
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
|
||||
|
||||
desc.dwBufferBytes = ds_ring_size;
|
||||
desc.lpwfxFormat = &wfx;
|
||||
memset(&desc, 0, sizeof(DSBUFFERDESC));
|
||||
desc.dwSize = sizeof(DSBUFFERDESC);
|
||||
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
|
||||
|
||||
desc.dwBufferBytes = ds_ring_size;
|
||||
desc.lpwfxFormat = &wfx;
|
||||
|
||||
|
||||
|
||||
|
||||
if (settings.aica.HW_mixing==0)
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ static void directsound_init()
|
|||
|
||||
//Play the buffer !
|
||||
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -159,7 +159,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
|
|||
wait &= w;
|
||||
*/
|
||||
int ffs=1;
|
||||
|
||||
|
||||
/*
|
||||
while (directsound_IsAudioBufferedLots() && wait)
|
||||
if (ffs == 0)
|
||||
|
@ -175,7 +175,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
|
|||
static void directsound_term()
|
||||
{
|
||||
buffer->Stop();
|
||||
|
||||
|
||||
buffer->Release();
|
||||
dsound->Release();
|
||||
}
|
||||
|
@ -187,4 +187,6 @@ audiobackend_t audiobackend_directsound = {
|
|||
&directsound_push,
|
||||
&directsound_term
|
||||
};
|
||||
|
||||
static bool ds = RegisterAudioBackend(&audiobackend_directsound);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_directsound;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_libao.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#ifdef USE_LIBAO
|
||||
|
||||
#include <ao/ao.h>
|
||||
|
@ -10,12 +10,12 @@ static void libao_init()
|
|||
{
|
||||
ao_initialize();
|
||||
memset(&aoformat, 0, sizeof(aoformat));
|
||||
|
||||
|
||||
aoformat.bits = 16;
|
||||
aoformat.channels = 2;
|
||||
aoformat.rate = 44100;
|
||||
aoformat.byte_format = AO_FMT_LITTLE;
|
||||
|
||||
|
||||
aodevice = ao_open_live(ao_default_driver_id(), &aoformat, NULL); // Live output
|
||||
if (!aodevice)
|
||||
aodevice = ao_open_live(ao_driver_id("null"), &aoformat, NULL);
|
||||
|
@ -23,13 +23,13 @@ static void libao_init()
|
|||
|
||||
static u32 libao_push(void* frame, u32 samples, bool wait)
|
||||
{
|
||||
if (aodevice)
|
||||
if (aodevice)
|
||||
ao_play(aodevice, (char*)frame, samples * 4);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void libao_term()
|
||||
static void libao_term()
|
||||
{
|
||||
if (aodevice)
|
||||
{
|
||||
|
@ -46,4 +46,5 @@ audiobackend_t audiobackend_libao = {
|
|||
&libao_term
|
||||
};
|
||||
|
||||
static bool ao = RegisterAudioBackend(&audiobackend_libao);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_libao;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_omx.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#if USE_OMX
|
||||
|
||||
#include <IL/OMX_Broadcom.h>
|
||||
|
@ -316,4 +316,5 @@ audiobackend_t audiobackend_omx = {
|
|||
&omx_term
|
||||
};
|
||||
|
||||
static bool omx = RegisterAudioBackend(&audiobackend_omx);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_omx;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_oss.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#ifdef USE_OSS
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
@ -51,4 +51,5 @@ audiobackend_t audiobackend_oss = {
|
|||
&oss_term
|
||||
};
|
||||
|
||||
static bool oss = RegisterAudioBackend(&audiobackend_oss);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_oss;
|
|
@ -1,4 +1,4 @@
|
|||
#include "oslib/audiobackend_pulseaudio.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#ifdef USE_PULSEAUDIO
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
@ -45,4 +45,6 @@ audiobackend_t audiobackend_pulseaudio = {
|
|||
&pulseaudio_push,
|
||||
&pulseaudio_term
|
||||
};
|
||||
|
||||
static bool pulse = RegisterAudioBackend(&audiobackend_pulseaudio);
|
||||
#endif
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
extern audiobackend_t audiobackend_pulseaudio;
|
|
@ -2,14 +2,6 @@
|
|||
#include "cfg/cfg.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "audiostream.h"
|
||||
#include "oslib/audiobackend_directsound.h"
|
||||
#include "oslib/audiobackend_android.h"
|
||||
#include "oslib/audiobackend_alsa.h"
|
||||
#include "oslib/audiobackend_oss.h"
|
||||
#include "oslib/audiobackend_pulseaudio.h"
|
||||
#include "oslib/audiobackend_coreaudio.h"
|
||||
#include "oslib/audiobackend_omx.h"
|
||||
#include "oslib/audiobackend_libao.h"
|
||||
|
||||
struct SoundFrame { s16 l;s16 r; };
|
||||
#define SAMPLE_COUNT 512
|
||||
|
@ -25,16 +17,27 @@ u32 gen_samples=0;
|
|||
|
||||
double time_diff = 128/44100.0;
|
||||
double time_last;
|
||||
|
||||
#ifdef LOG_SOUND
|
||||
// TODO Only works on Windows!
|
||||
WaveWriter rawout("d:\\aica_out.wav");
|
||||
#endif
|
||||
|
||||
static bool audiobackends_registered = false;
|
||||
static unsigned int audiobackends_num_max = 1;
|
||||
static unsigned int audiobackends_num_registered = 0;
|
||||
static audiobackend_t **audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
|
||||
static audiobackend_t **audiobackends = NULL;
|
||||
static audiobackend_t *audiobackend_current = NULL;
|
||||
|
||||
u32 GetAudioBackendCount()
|
||||
{
|
||||
return audiobackends_num_registered;
|
||||
}
|
||||
|
||||
audiobackend_t* GetAudioBackend(int num)
|
||||
{
|
||||
return audiobackends[num];
|
||||
}
|
||||
|
||||
bool RegisterAudioBackend(audiobackend_t *backend)
|
||||
{
|
||||
/* This function announces the availability of an audio backend to reicast. */
|
||||
|
@ -44,10 +47,16 @@ bool RegisterAudioBackend(audiobackend_t *backend)
|
|||
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (backend->slug == "auto" || backend->slug == "none") {
|
||||
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// First call to RegisterAudioBackend(), create the backend structure;
|
||||
if (audiobackends == NULL)
|
||||
audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
|
||||
|
||||
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
|
||||
if (audiobackends_num_registered == audiobackends_num_max)
|
||||
{
|
||||
|
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
|
|||
}
|
||||
audiobackends = new_ptr;
|
||||
}
|
||||
|
||||
audiobackends[audiobackends_num_registered] = backend;
|
||||
audiobackends_num_registered++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RegisterAllAudioBackends() {
|
||||
#if HOST_OS==OS_WINDOWS
|
||||
RegisterAudioBackend(&audiobackend_directsound);
|
||||
#endif
|
||||
#if ANDROID
|
||||
RegisterAudioBackend(&audiobackend_android);
|
||||
#endif
|
||||
#if USE_OMX
|
||||
RegisterAudioBackend(&audiobackend_omx);
|
||||
#endif
|
||||
#if USE_ALSA
|
||||
RegisterAudioBackend(&audiobackend_alsa);
|
||||
#endif
|
||||
#if USE_OSS
|
||||
RegisterAudioBackend(&audiobackend_oss);
|
||||
#endif
|
||||
#if USE_PULSEAUDIO
|
||||
RegisterAudioBackend(&audiobackend_pulseaudio);
|
||||
#endif
|
||||
#if USE_LIBAO
|
||||
RegisterAudioBackend(&audiobackend_libao);
|
||||
#endif
|
||||
#if HOST_OS == OS_DARWIN
|
||||
RegisterAudioBackend(&audiobackend_coreaudio);
|
||||
#endif
|
||||
audiobackends_registered = true;
|
||||
}
|
||||
|
||||
static audiobackend_t* GetAudioBackend(std::string slug)
|
||||
audiobackend_t* GetAudioBackend(std::string slug)
|
||||
{
|
||||
if (slug == "none")
|
||||
{
|
||||
printf("WARNING: Audio backend set to \"none\"!\n");
|
||||
}
|
||||
else if(audiobackends_num_registered > 0)
|
||||
else if (audiobackends_num_registered > 0)
|
||||
{
|
||||
if (slug == "auto")
|
||||
{
|
||||
|
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
u32 PushAudio(void* frame, u32 amt, bool wait) {
|
||||
u32 PushAudio(void* frame, u32 amt, bool wait)
|
||||
{
|
||||
if (audiobackend_current != NULL) {
|
||||
return audiobackend_current->push(frame, amt, wait);
|
||||
}
|
||||
|
@ -151,6 +134,7 @@ u32 asRingUsedCount()
|
|||
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
|
||||
//return sz<0?sz+RingBufferSampleCount:sz;
|
||||
}
|
||||
|
||||
u32 asRingFreeCount()
|
||||
{
|
||||
return RingBufferSampleCount-asRingUsedCount();
|
||||
|
@ -169,6 +153,27 @@ void WriteSample(s16 r, s16 l)
|
|||
}
|
||||
}
|
||||
|
||||
static bool backends_sorted = false;
|
||||
void SortAudioBackends()
|
||||
{
|
||||
if (backends_sorted)
|
||||
return;
|
||||
|
||||
// Sort backends by slug
|
||||
for (int n = audiobackends_num_registered; n > 0; n--)
|
||||
{
|
||||
for (int i = 0; i < n-1; i++)
|
||||
{
|
||||
if (audiobackends[i]->slug > audiobackends[i+1]->slug)
|
||||
{
|
||||
audiobackend_t* swap = audiobackends[i];
|
||||
audiobackends[i] = audiobackends[i+1];
|
||||
audiobackends[i+1] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitAudio()
|
||||
{
|
||||
if (cfgLoadInt("audio", "disable", 0)) {
|
||||
|
@ -176,26 +181,24 @@ void InitAudio()
|
|||
return;
|
||||
}
|
||||
|
||||
cfgSaveInt("audio","disable",0);
|
||||
|
||||
if (!audiobackends_registered) {
|
||||
//FIXME: There might some nicer way to do this.
|
||||
RegisterAllAudioBackends();
|
||||
}
|
||||
cfgSaveInt("audio", "disable", 0);
|
||||
|
||||
if (audiobackend_current != NULL) {
|
||||
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
string audiobackend_slug = cfgLoadStr("audio", "backend", "auto"); // FIXME: This could be made a parameter
|
||||
SortAudioBackends();
|
||||
|
||||
string audiobackend_slug = settings.audio.backend;
|
||||
audiobackend_current = GetAudioBackend(audiobackend_slug);
|
||||
if (audiobackend_current == NULL) {
|
||||
printf("WARNING: Running without audio!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||
audiobackend_current->init();
|
||||
audiobackend_current->init();
|
||||
}
|
||||
|
||||
void TermAudio()
|
||||
|
@ -204,5 +207,5 @@ void TermAudio()
|
|||
audiobackend_current->term();
|
||||
printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||
audiobackend_current = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include <tuple>
|
||||
|
||||
//Get used size in the ring buffer
|
||||
u32 asRingUsedCount();
|
||||
|
@ -24,3 +25,8 @@ extern bool RegisterAudioBackend(audiobackend_t* backend);
|
|||
extern void InitAudio();
|
||||
extern u32 PushAudio(void* frame, u32 amt, bool wait);
|
||||
extern void TermAudio();
|
||||
|
||||
u32 GetAudioBackendCount();
|
||||
void SortAudioBackends();
|
||||
audiobackend_t* GetAudioBackend(int num);
|
||||
audiobackend_t* GetAudioBackend(std::string slug);
|
||||
|
|
|
@ -2082,7 +2082,7 @@ __default:
|
|||
}
|
||||
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
|
||||
{
|
||||
//printf("Compile: %08X, %d, %d\n",block->addr,staging,optimise);
|
||||
block->code=(DynarecCodeEntryPtr)EMIT_GET_PTR();
|
||||
|
@ -2114,39 +2114,68 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
|
|||
reg.OpBegin(&block->oplist[0],0);
|
||||
|
||||
//scheduler
|
||||
if (force_checks)
|
||||
{
|
||||
s32 sz = block->sh4_code_size;
|
||||
u32 addr = block->addr;
|
||||
MOV32(r0,addr);
|
||||
switch (smc_checks) {
|
||||
case NoCheck:
|
||||
break;
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
if (sz > 2)
|
||||
case FastCheck: {
|
||||
MOV32(r0,block->addr);
|
||||
u32* ptr=(u32*)GetMemPtr(block->addr,4);
|
||||
if (ptr != NULL)
|
||||
{
|
||||
u32* ptr=(u32*)GetMemPtr(addr,4);
|
||||
MOV32(r2,(u32)ptr);
|
||||
LDR(r2,r2,0);
|
||||
MOV32(r1,*ptr);
|
||||
CMP(r1,r2);
|
||||
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
addr += 4;
|
||||
sz -= 4;
|
||||
}
|
||||
else
|
||||
}
|
||||
break;
|
||||
|
||||
case FullCheck: {
|
||||
s32 sz = block->sh4_code_size;
|
||||
u32 addr = block->addr;
|
||||
MOV32(r0,addr);
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
u16* ptr = (u16 *)GetMemPtr(addr, 2);
|
||||
MOV32(r2, (u32)ptr);
|
||||
LDRH(r2, r2, 0, AL);
|
||||
MOVW(r1, *ptr, AL);
|
||||
CMP(r1, r2);
|
||||
if (sz > 2)
|
||||
{
|
||||
u32* ptr=(u32*)GetMemPtr(addr,4);
|
||||
if (ptr != NULL)
|
||||
{
|
||||
MOV32(r2,(u32)ptr);
|
||||
LDR(r2,r2,0);
|
||||
MOV32(r1,*ptr);
|
||||
CMP(r1,r2);
|
||||
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
addr += 2;
|
||||
sz -= 2;
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
}
|
||||
addr += 4;
|
||||
sz -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16* ptr = (u16 *)GetMemPtr(addr, 2);
|
||||
if (ptr != NULL)
|
||||
{
|
||||
MOV32(r2, (u32)ptr);
|
||||
LDRH(r2, r2, 0, AL);
|
||||
MOVW(r1, *ptr, AL);
|
||||
CMP(r1, r2);
|
||||
|
||||
JUMP((u32)ngen_blockcheckfail, CC_NE);
|
||||
}
|
||||
addr += 2;
|
||||
sz -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
die("unhandled smc_checks");
|
||||
}
|
||||
}
|
||||
|
||||
u32 cyc=block->guest_cycles;
|
||||
|
|
|
@ -348,15 +348,15 @@ public:
|
|||
return *ret_reg;
|
||||
}
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
//printf("REC-ARM64 compiling %08x\n", block->addr);
|
||||
#ifdef PROFILING
|
||||
SaveFramePointer();
|
||||
#endif
|
||||
this->block = block;
|
||||
if (force_checks)
|
||||
CheckBlock(block);
|
||||
|
||||
CheckBlock(smc_checks, block);
|
||||
|
||||
// run register allocator
|
||||
regalloc.DoAlloc(block);
|
||||
|
@ -1292,49 +1292,72 @@ private:
|
|||
verify (GetCursorAddress<Instruction *>() - start_instruction == code_size * kInstructionSize);
|
||||
}
|
||||
|
||||
void CheckBlock(RuntimeBlockInfo* block)
|
||||
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
|
||||
{
|
||||
s32 sz = block->sh4_code_size;
|
||||
|
||||
Label blockcheck_fail;
|
||||
Label blockcheck_success;
|
||||
|
||||
u8* ptr = GetMemPtr(block->addr, sz);
|
||||
if (ptr == NULL)
|
||||
// FIXME Can a block cross a RAM / non-RAM boundary??
|
||||
return;
|
||||
switch (smc_checks) {
|
||||
case NoCheck:
|
||||
return;
|
||||
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
if (sz >= 8)
|
||||
{
|
||||
Ldr(x10, MemOperand(x9, 8, PostIndex));
|
||||
Ldr(x11, *(u64*)ptr);
|
||||
Cmp(x10, x11);
|
||||
sz -= 8;
|
||||
ptr += 8;
|
||||
}
|
||||
else if (sz >= 4)
|
||||
{
|
||||
Ldr(w10, MemOperand(x9, 4, PostIndex));
|
||||
case FastCheck: {
|
||||
u8* ptr = GetMemPtr(block->addr, 4);
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
|
||||
Ldr(w10, MemOperand(x9));
|
||||
Ldr(w11, *(u32*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 4;
|
||||
ptr += 4;
|
||||
B(eq, &blockcheck_success);
|
||||
}
|
||||
else
|
||||
{
|
||||
Ldrh(w10, MemOperand(x9, 2, PostIndex));
|
||||
Mov(w11, *(u16*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 2;
|
||||
ptr += 2;
|
||||
break;
|
||||
|
||||
case FullCheck: {
|
||||
s32 sz = block->sh4_code_size;
|
||||
|
||||
u8* ptr = GetMemPtr(block->addr, sz);
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
|
||||
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
if (sz >= 8)
|
||||
{
|
||||
Ldr(x10, MemOperand(x9, 8, PostIndex));
|
||||
Ldr(x11, *(u64*)ptr);
|
||||
Cmp(x10, x11);
|
||||
sz -= 8;
|
||||
ptr += 8;
|
||||
}
|
||||
else if (sz >= 4)
|
||||
{
|
||||
Ldr(w10, MemOperand(x9, 4, PostIndex));
|
||||
Ldr(w11, *(u32*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 4;
|
||||
ptr += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ldrh(w10, MemOperand(x9, 2, PostIndex));
|
||||
Mov(w11, *(u16*)ptr);
|
||||
Cmp(w10, w11);
|
||||
sz -= 2;
|
||||
ptr += 2;
|
||||
}
|
||||
B(ne, &blockcheck_fail);
|
||||
}
|
||||
B(&blockcheck_success);
|
||||
}
|
||||
B(ne, &blockcheck_fail);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("unhandled smc_checks");
|
||||
}
|
||||
B(&blockcheck_success);
|
||||
|
||||
Bind(&blockcheck_fail);
|
||||
Ldr(w0, block->addr);
|
||||
|
@ -1404,13 +1427,13 @@ private:
|
|||
|
||||
static Arm64Assembler* compiler;
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
verify(emit_FreeSpace() >= 16 * 1024);
|
||||
|
||||
compiler = new Arm64Assembler();
|
||||
|
||||
compiler->ngen_Compile(block, force_checks, reset, staging, optimise);
|
||||
compiler->ngen_Compile(block, smc_checks, reset, staging, optimise);
|
||||
|
||||
delete compiler;
|
||||
compiler = NULL;
|
||||
|
|
|
@ -1190,10 +1190,10 @@ public:
|
|||
|
||||
size_t opcode_index;
|
||||
opcodeExec** ptrsg;
|
||||
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) {
|
||||
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise) {
|
||||
|
||||
//we need an extra one for the end opcode and optionally one more for block check
|
||||
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (force_checks ? 1 : 0))(block->guest_cycles);
|
||||
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (smc_checks != NoCheck ? 1 : 0))(block->guest_cycles);
|
||||
|
||||
ptrsg = ptrs.ptrs;
|
||||
|
||||
|
@ -1207,9 +1207,16 @@ public:
|
|||
}
|
||||
|
||||
size_t i = 0;
|
||||
if (force_checks)
|
||||
if (smc_checks != NoCheck)
|
||||
{
|
||||
verify (smc_checks == FastCheck || smc_checks == FullCheck)
|
||||
opcodeExec* op;
|
||||
int check_size = block->sh4_code_size;
|
||||
|
||||
if (smc_checks == FastCheck) {
|
||||
check_size = 4;
|
||||
}
|
||||
|
||||
switch (block->sh4_code_size)
|
||||
{
|
||||
case 4:
|
||||
|
@ -1227,6 +1234,7 @@ public:
|
|||
}
|
||||
ptrs.ptrs[i++] = op;
|
||||
}
|
||||
|
||||
for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) {
|
||||
opcode_index = i;
|
||||
shil_opcode& op = block->oplist[opnum];
|
||||
|
@ -1551,14 +1559,14 @@ public:
|
|||
|
||||
BlockCompiler* compiler;
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
verify(emit_FreeSpace() >= 16 * 1024);
|
||||
|
||||
compiler = new BlockCompiler();
|
||||
|
||||
|
||||
compiler->compile(block, force_checks, reset, staging, optimise);
|
||||
compiler->compile(block, smc_checks, reset, staging, optimise);
|
||||
|
||||
delete compiler;
|
||||
}
|
||||
|
|
|
@ -244,12 +244,11 @@ public:
|
|||
call_regsxmm.push_back(xmm3);
|
||||
}
|
||||
|
||||
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
//printf("X86_64 compiling %08x to %p\n", block->addr, emit_GetCCPtr());
|
||||
if (force_checks) {
|
||||
CheckBlock(block);
|
||||
}
|
||||
CheckBlock(smc_checks, block);
|
||||
|
||||
regalloc.DoAlloc(block);
|
||||
|
||||
sub(dword[rip + &cycle_counter], block->guest_cycles);
|
||||
|
@ -1091,41 +1090,66 @@ private:
|
|||
typedef void (BlockCompiler::*X64BinaryOp)(const Xbyak::Operand&, const Xbyak::Operand&);
|
||||
typedef void (BlockCompiler::*X64BinaryFOp)(const Xbyak::Xmm&, const Xbyak::Operand&);
|
||||
|
||||
void CheckBlock(RuntimeBlockInfo* block) {
|
||||
mov(call_regs[0], block->addr);
|
||||
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block) {
|
||||
|
||||
s32 sz=block->sh4_code_size;
|
||||
u32 sa=block->addr;
|
||||
switch (smc_checks) {
|
||||
case NoCheck:
|
||||
return;
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
|
||||
if (ptr)
|
||||
{
|
||||
mov(rax, reinterpret_cast<uintptr_t>(ptr));
|
||||
|
||||
if (sz >= 8) {
|
||||
mov(rdx, *(u64*)ptr);
|
||||
cmp(qword[rax], rdx);
|
||||
sz -= 8;
|
||||
sa += 8;
|
||||
}
|
||||
else if (sz >= 4) {
|
||||
case FastCheck: {
|
||||
void* ptr = (void*)GetMemPtr(block->addr, 4);
|
||||
if (ptr)
|
||||
{
|
||||
mov(call_regs[0], block->addr);
|
||||
mov(rax, reinterpret_cast<uintptr_t>(ptr));
|
||||
mov(edx, *(u32*)ptr);
|
||||
cmp(dword[rax], edx);
|
||||
sz -= 4;
|
||||
sa += 4;
|
||||
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
|
||||
}
|
||||
else {
|
||||
mov(edx, *(u16*)ptr);
|
||||
cmp(word[rax],dx);
|
||||
sz -= 2;
|
||||
sa += 2;
|
||||
}
|
||||
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FullCheck: {
|
||||
s32 sz=block->sh4_code_size;
|
||||
u32 sa=block->addr;
|
||||
|
||||
void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
|
||||
if (ptr)
|
||||
{
|
||||
mov(call_regs[0], block->addr);
|
||||
|
||||
while (sz > 0)
|
||||
{
|
||||
mov(rax, reinterpret_cast<uintptr_t>(ptr));
|
||||
|
||||
if (sz >= 8) {
|
||||
mov(rdx, *(u64*)ptr);
|
||||
cmp(qword[rax], rdx);
|
||||
sz -= 8;
|
||||
sa += 8;
|
||||
}
|
||||
else if (sz >= 4) {
|
||||
mov(edx, *(u32*)ptr);
|
||||
cmp(dword[rax], edx);
|
||||
sz -= 4;
|
||||
sa += 4;
|
||||
}
|
||||
else {
|
||||
mov(edx, *(u16*)ptr);
|
||||
cmp(word[rax],dx);
|
||||
sz -= 2;
|
||||
sa += 2;
|
||||
}
|
||||
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
|
||||
ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
die("unhandled smc_checks");
|
||||
}
|
||||
}
|
||||
|
||||
void GenBinaryOp(const shil_opcode &op, X64BinaryOp natop)
|
||||
|
@ -1267,13 +1291,13 @@ void X64RegAlloc::Writeback_FPU(u32 reg, s8 nreg)
|
|||
|
||||
static BlockCompiler* compiler;
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
|
||||
{
|
||||
verify(emit_FreeSpace() >= 16 * 1024);
|
||||
|
||||
compiler = new BlockCompiler();
|
||||
|
||||
compiler->compile(block, force_checks, reset, staging, optimise);
|
||||
compiler->compile(block, smc_checks, reset, staging, optimise);
|
||||
|
||||
delete compiler;
|
||||
}
|
||||
|
|
|
@ -229,29 +229,50 @@ u32 rdmt[6];
|
|||
extern u32 memops_t,memops_l;
|
||||
extern int mips_counter;
|
||||
|
||||
void CheckBlock(RuntimeBlockInfo* block,x86_ptr_imm place)
|
||||
//TODO: Get back validating mode for this
|
||||
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
|
||||
{
|
||||
s32 sz=block->sh4_code_size;
|
||||
u32 sa=block->addr;
|
||||
while(sz>0)
|
||||
{
|
||||
void* ptr=(void*)GetMemPtr(sa,4);
|
||||
if (ptr)
|
||||
{
|
||||
if (sz==2)
|
||||
x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
|
||||
else
|
||||
x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
|
||||
x86e->Emit(op_jne,place);
|
||||
switch (smc_checks) {
|
||||
case NoCheck:
|
||||
break;
|
||||
|
||||
case FastCheck: {
|
||||
void* ptr = (void*)GetMemPtr(block->addr, 4);
|
||||
if (ptr)
|
||||
{
|
||||
x86e->Emit(op_cmp32, ptr, *(u32*)ptr);
|
||||
x86e->Emit(op_jne, x86_ptr_imm(ngen_blockcheckfail));
|
||||
}
|
||||
}
|
||||
sz-=4;
|
||||
sa+=4;
|
||||
break;
|
||||
|
||||
case FullCheck: {
|
||||
s32 sz=block->sh4_code_size;
|
||||
u32 sa=block->addr;
|
||||
while(sz>0)
|
||||
{
|
||||
void* ptr=(void*)GetMemPtr(sa,4);
|
||||
if (ptr)
|
||||
{
|
||||
if (sz==2)
|
||||
x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
|
||||
else
|
||||
x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
|
||||
x86e->Emit(op_jne,x86_ptr_imm(ngen_blockcheckfail));
|
||||
}
|
||||
sz-=4;
|
||||
sa+=4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
die("unhandled smc_checks");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
|
||||
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
|
||||
{
|
||||
//initialise stuff
|
||||
DetectCpuFeatures();
|
||||
|
@ -282,7 +303,7 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
|
|||
//block invl. checks
|
||||
x86e->Emit(op_mov32,ECX,block->addr);
|
||||
|
||||
CheckBlock(block,force_checks?x86_ptr_imm(ngen_blockcheckfail):x86_ptr_imm(ngen_blockcheckfail2));
|
||||
CheckBlock(smc_checks, block);
|
||||
|
||||
//Scheduler
|
||||
x86_Label* no_up=x86e->CreateLabel(false,8);
|
||||
|
|
|
@ -331,23 +331,23 @@ void initABuffer()
|
|||
{
|
||||
char source[16384];
|
||||
sprintf(source, final_shader_source, 1);
|
||||
gl4CompilePipelineShader(&g_abuffer_final_shader, source);
|
||||
gl4CompilePipelineShader(&g_abuffer_final_shader, false, source);
|
||||
}
|
||||
if (g_abuffer_final_nosort_shader.program == 0)
|
||||
{
|
||||
char source[16384];
|
||||
sprintf(source, final_shader_source, 0);
|
||||
gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, source);
|
||||
gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, false, source);
|
||||
}
|
||||
if (g_abuffer_clear_shader.program == 0)
|
||||
gl4CompilePipelineShader(&g_abuffer_clear_shader, clear_shader_source);
|
||||
gl4CompilePipelineShader(&g_abuffer_clear_shader, false, clear_shader_source);
|
||||
if (g_abuffer_tr_modvol_shaders[0].program == 0)
|
||||
{
|
||||
char source[16384];
|
||||
for (int mode = 0; mode < ModeCount; mode++)
|
||||
{
|
||||
sprintf(source, tr_modvol_shader_source, mode);
|
||||
gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], source);
|
||||
gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], false, source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,6 +417,17 @@ void termABuffer()
|
|||
glDeleteBuffers(1, &g_quadBuffer);
|
||||
g_quadBuffer = 0;
|
||||
}
|
||||
glcache.DeleteProgram(g_abuffer_final_shader.program);
|
||||
g_abuffer_final_shader.program = 0;
|
||||
glcache.DeleteProgram(g_abuffer_final_nosort_shader.program);
|
||||
g_abuffer_final_nosort_shader.program = 0;
|
||||
glcache.DeleteProgram(g_abuffer_clear_shader.program);
|
||||
g_abuffer_clear_shader.program = 0;
|
||||
for (int mode = 0; mode < ModeCount; mode++)
|
||||
{
|
||||
glcache.DeleteProgram(g_abuffer_tr_modvol_shaders[mode].program);
|
||||
g_abuffer_tr_modvol_shaders[mode].program = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reshapeABuffer(int w, int h)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include "rend/gles/gles.h"
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
void gl4DrawStrips(GLuint output_fbo);
|
||||
|
||||
|
@ -44,7 +44,8 @@ struct gl4_ctx
|
|||
GLuint extra_depth_scale;
|
||||
} modvol_shader;
|
||||
|
||||
std::map<int, gl4PipelineShader *> shaders;
|
||||
std::unordered_map<u32, gl4PipelineShader> shaders;
|
||||
bool rotate90;
|
||||
|
||||
struct
|
||||
{
|
||||
|
@ -53,16 +54,6 @@ struct gl4_ctx
|
|||
GLuint modvol_vao;
|
||||
GLuint tr_poly_params;
|
||||
} vbo;
|
||||
|
||||
gl4PipelineShader *getShader(int programId) {
|
||||
gl4PipelineShader *shader = shaders[programId];
|
||||
if (shader == NULL) {
|
||||
shader = new gl4PipelineShader();
|
||||
shaders[programId] = shader;
|
||||
shader->program = -1;
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
};
|
||||
|
||||
extern gl4_ctx gl4;
|
||||
|
@ -76,7 +67,8 @@ bool gl4_render_output_framebuffer();
|
|||
void abufferDrawQuad(bool upsideDown = false, float x = 0.f, float y = 0.f, float w = 0.f, float h = 0.f);
|
||||
|
||||
extern const char *gl4PixelPipelineShader;
|
||||
bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *source = gl4PixelPipelineShader);
|
||||
bool gl4CompilePipelineShader(gl4PipelineShader* s, bool rotate_90, const char *source = gl4PixelPipelineShader);
|
||||
void gl4_delete_shaders();
|
||||
|
||||
extern GLuint stencilTexId;
|
||||
extern GLuint depthTexId;
|
||||
|
|
|
@ -45,10 +45,15 @@ static GLuint texSamplers[2];
|
|||
static GLuint depth_fbo;
|
||||
GLuint depthSaveTexId;
|
||||
|
||||
static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
static gl4PipelineShader *gl4GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
|
||||
{
|
||||
if (settings.rend.Rotate90 != gl4.rotate90)
|
||||
{
|
||||
gl4_delete_shaders();
|
||||
gl4.rotate90 = settings.rend.Rotate90;
|
||||
}
|
||||
u32 rv=0;
|
||||
|
||||
rv|=pp_ClipTestMode;
|
||||
|
@ -66,45 +71,27 @@ static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
|||
rv <<= 1; rv |= fog_clamping;
|
||||
rv <<= 2; rv |= pass;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void setCurrentShader(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
|
||||
{
|
||||
int shaderId = gl4GetProgramID(cp_AlphaTest,
|
||||
pp_ClipTestMode + 1,
|
||||
pp_Texture,
|
||||
pp_UseAlpha,
|
||||
pp_IgnoreTexA,
|
||||
pp_ShadInstr,
|
||||
pp_Offset,
|
||||
pp_FogCtrl,
|
||||
pp_TwoVolumes,
|
||||
pp_DepthFunc,
|
||||
pp_Gouraud,
|
||||
pp_BumpMap,
|
||||
fog_clamping,
|
||||
pass);
|
||||
CurrentShader = gl4.getShader(shaderId);
|
||||
if (CurrentShader->program == -1) {
|
||||
CurrentShader->cp_AlphaTest = cp_AlphaTest;
|
||||
CurrentShader->pp_ClipTestMode = pp_ClipTestMode;
|
||||
CurrentShader->pp_Texture = pp_Texture;
|
||||
CurrentShader->pp_UseAlpha = pp_UseAlpha;
|
||||
CurrentShader->pp_IgnoreTexA = pp_IgnoreTexA;
|
||||
CurrentShader->pp_ShadInstr = pp_ShadInstr;
|
||||
CurrentShader->pp_Offset = pp_Offset;
|
||||
CurrentShader->pp_FogCtrl = pp_FogCtrl;
|
||||
CurrentShader->pp_TwoVolumes = pp_TwoVolumes;
|
||||
CurrentShader->pp_DepthFunc = pp_DepthFunc;
|
||||
CurrentShader->pp_Gouraud = pp_Gouraud;
|
||||
CurrentShader->pp_BumpMap = pp_BumpMap;
|
||||
CurrentShader->fog_clamping = fog_clamping;
|
||||
CurrentShader->pass = pass;
|
||||
gl4CompilePipelineShader(CurrentShader);
|
||||
gl4PipelineShader *shader = &gl4.shaders[rv];
|
||||
if (shader->program == 0)
|
||||
{
|
||||
shader->cp_AlphaTest = cp_AlphaTest;
|
||||
shader->pp_ClipTestMode = pp_ClipTestMode;
|
||||
shader->pp_Texture = pp_Texture;
|
||||
shader->pp_UseAlpha = pp_UseAlpha;
|
||||
shader->pp_IgnoreTexA = pp_IgnoreTexA;
|
||||
shader->pp_ShadInstr = pp_ShadInstr;
|
||||
shader->pp_Offset = pp_Offset;
|
||||
shader->pp_FogCtrl = pp_FogCtrl;
|
||||
shader->pp_TwoVolumes = pp_TwoVolumes;
|
||||
shader->pp_DepthFunc = pp_DepthFunc;
|
||||
shader->pp_Gouraud = pp_Gouraud;
|
||||
shader->pp_BumpMap = pp_BumpMap;
|
||||
shader->fog_clamping = fog_clamping;
|
||||
shader->pass = pass;
|
||||
gl4CompilePipelineShader(shader, settings.rend.Rotate90);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
static void SetTextureRepeatMode(int index, GLuint dir, u32 clamp, u32 mirror)
|
||||
|
@ -132,7 +119,7 @@ template <u32 Type, bool SortingEnabled>
|
|||
|
||||
if (pass == 0)
|
||||
{
|
||||
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0,
|
||||
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||
clipping,
|
||||
Type == ListType_Punch_Through ? gp->pcw.Texture : 0,
|
||||
1,
|
||||
|
@ -153,6 +140,8 @@ template <u32 Type, bool SortingEnabled>
|
|||
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent;
|
||||
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
||||
|
||||
int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2;
|
||||
|
||||
int depth_func = 0;
|
||||
if (Type == ListType_Translucent)
|
||||
{
|
||||
|
@ -162,14 +151,14 @@ template <u32 Type, bool SortingEnabled>
|
|||
depth_func = gp->isp.DepthMode;
|
||||
}
|
||||
|
||||
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0,
|
||||
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||
clipping,
|
||||
gp->pcw.Texture,
|
||||
gp->tsp.UseAlpha,
|
||||
gp->tsp.IgnoreTexA,
|
||||
gp->tsp.ShadInstr,
|
||||
gp->pcw.Offset,
|
||||
gp->tsp.FogCtrl,
|
||||
fog_ctrl,
|
||||
two_volumes_mode,
|
||||
depth_func,
|
||||
gp->pcw.Gouraud,
|
||||
|
@ -681,7 +670,7 @@ static void gl4_draw_quad_texture(GLuint texture, bool upsideDown, float x = 0.f
|
|||
|
||||
ShaderUniforms.trilinear_alpha = 1.0;
|
||||
|
||||
setCurrentShader(0,
|
||||
CurrentShader = gl4GetProgram(0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
|
@ -713,11 +702,15 @@ void gl4DrawFramebuffer(float w, float h)
|
|||
|
||||
bool gl4_render_output_framebuffer()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glViewport(0, 0, screen_width, screen_height);
|
||||
if (gl.ofbo.tex == 0)
|
||||
glcache.Disable(GL_SCISSOR_TEST);
|
||||
if (gl.ofbo.fbo == 0)
|
||||
return false;
|
||||
|
||||
gl4_draw_quad_texture(gl.ofbo.tex, true);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
|
||||
0, 0, screen_width, screen_height,
|
||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ static const char* VertexShaderSource =
|
|||
"\
|
||||
#version 140 \n\
|
||||
#define pp_Gouraud %d \n\
|
||||
#define ROTATE_90 %d \n\
|
||||
\n\
|
||||
#if pp_Gouraud == 0 \n\
|
||||
#define INTERPOLATION flat \n\
|
||||
|
@ -56,6 +57,9 @@ void main() \n\
|
|||
\n\
|
||||
vpos.w = extra_depth_scale / vpos.z; \n\
|
||||
vpos.z = vpos.w; \n\
|
||||
#if ROTATE_90 == 1 \n\
|
||||
vpos.xy = vec2(vpos.y, -vpos.x); \n\
|
||||
#endif \n\
|
||||
vpos.xy=vpos.xy*scale.xy-scale.zw; \n\
|
||||
vpos.xy*=vpos.w; \n\
|
||||
gl_Position = vpos; \n\
|
||||
|
@ -393,11 +397,11 @@ gl4_ctx gl4;
|
|||
|
||||
struct gl4ShaderUniforms_t gl4ShaderUniforms;
|
||||
|
||||
bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = PixelPipelineShader */)
|
||||
bool gl4CompilePipelineShader( gl4PipelineShader* s, bool rotate_90, const char *source /* = PixelPipelineShader */)
|
||||
{
|
||||
char vshader[16384];
|
||||
|
||||
sprintf(vshader, VertexShaderSource, s->pp_Gouraud);
|
||||
sprintf(vshader, VertexShaderSource, s->pp_Gouraud, rotate_90);
|
||||
|
||||
char pshader[16384];
|
||||
|
||||
|
@ -478,28 +482,45 @@ bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = Pix
|
|||
|
||||
void gl_term();
|
||||
|
||||
void gl4_delete_shaders()
|
||||
{
|
||||
for (auto it : gl4.shaders)
|
||||
{
|
||||
if (it.second.program != 0)
|
||||
glcache.DeleteProgram(it.second.program);
|
||||
}
|
||||
gl4.shaders.clear();
|
||||
glcache.DeleteProgram(gl4.modvol_shader.program);
|
||||
gl4.modvol_shader.program = 0;
|
||||
}
|
||||
|
||||
static void gles_term(void)
|
||||
{
|
||||
glDeleteProgram(gl4.modvol_shader.program);
|
||||
glDeleteBuffers(1, &gl4.vbo.geometry);
|
||||
gl4.vbo.geometry = 0;
|
||||
glDeleteBuffers(1, &gl4.vbo.modvols);
|
||||
glDeleteBuffers(1, &gl4.vbo.idxs);
|
||||
glDeleteBuffers(1, &gl4.vbo.idxs2);
|
||||
glDeleteBuffers(1, &gl4.vbo.tr_poly_params);
|
||||
for (auto it = gl4.shaders.begin(); it != gl4.shaders.end(); it++)
|
||||
{
|
||||
if (it->second->program != -1)
|
||||
glDeleteProgram(it->second->program);
|
||||
delete it->second;
|
||||
}
|
||||
gl4.shaders.clear();
|
||||
gl4_delete_shaders();
|
||||
glDeleteVertexArrays(1, &gl4.vbo.main_vao);
|
||||
glDeleteVertexArrays(1, &gl4.vbo.modvol_vao);
|
||||
|
||||
gl_term();
|
||||
}
|
||||
|
||||
static void create_modvol_shader()
|
||||
{
|
||||
if (gl4.modvol_shader.program != 0)
|
||||
return;
|
||||
char vshader[16384];
|
||||
sprintf(vshader, VertexShaderSource, 1, settings.rend.Rotate90);
|
||||
|
||||
gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader);
|
||||
gl4.modvol_shader.scale = glGetUniformLocation(gl4.modvol_shader.program, "scale");
|
||||
gl4.modvol_shader.extra_depth_scale = glGetUniformLocation(gl4.modvol_shader.program, "extra_depth_scale");
|
||||
}
|
||||
|
||||
static bool gl_create_resources()
|
||||
{
|
||||
if (gl4.vbo.geometry != 0)
|
||||
|
@ -521,12 +542,7 @@ static bool gl_create_resources()
|
|||
gl4SetupMainVBO();
|
||||
gl4SetupModvolVBO();
|
||||
|
||||
char vshader[16384];
|
||||
sprintf(vshader, VertexShaderSource, 1);
|
||||
|
||||
gl4.modvol_shader.program=gl_CompileAndLink(vshader, ModifierVolumeShader);
|
||||
gl4.modvol_shader.scale = glGetUniformLocation(gl4.modvol_shader.program, "scale");
|
||||
gl4.modvol_shader.extra_depth_scale = glGetUniformLocation(gl4.modvol_shader.program, "extra_depth_scale");
|
||||
create_modvol_shader();
|
||||
|
||||
gl_load_osd_resources();
|
||||
|
||||
|
@ -604,6 +620,7 @@ static bool RenderFrame()
|
|||
old_screen_scaling = settings.rend.ScreenScaling;
|
||||
}
|
||||
DoCleanup();
|
||||
create_modvol_shader();
|
||||
|
||||
bool is_rtt=pvrrc.isRTT;
|
||||
|
||||
|
@ -662,16 +679,41 @@ static bool RenderFrame()
|
|||
/*
|
||||
Handle Dc to screen scaling
|
||||
*/
|
||||
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
|
||||
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
|
||||
dc2s_scale_h *= screen_scaling;
|
||||
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
|
||||
float screen_scaling = settings.rend.ScreenScaling / 100.f;
|
||||
float screen_stretching = settings.rend.ScreenStretching / 100.f;
|
||||
|
||||
//-1 -> too much to left
|
||||
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
|
||||
gl4ShaderUniforms.scale_coefs[1] = (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
|
||||
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
|
||||
gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1);
|
||||
float dc2s_scale_h;
|
||||
float ds2s_offs_x;
|
||||
|
||||
if (is_rtt)
|
||||
{
|
||||
gl4ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
|
||||
gl4ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
|
||||
gl4ShaderUniforms.scale_coefs[2] = 1;
|
||||
gl4ShaderUniforms.scale_coefs[3] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (settings.rend.Rotate90)
|
||||
{
|
||||
dc2s_scale_h = screen_height / 640.0;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2;
|
||||
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
|
||||
gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
|
||||
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
|
||||
gl4ShaderUniforms.scale_coefs[3] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dc2s_scale_h = screen_height / 480.0;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2;
|
||||
//-1 -> too much to left
|
||||
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
|
||||
gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
|
||||
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
|
||||
gl4ShaderUniforms.scale_coefs[3] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale;
|
||||
|
||||
|
@ -704,7 +746,7 @@ static bool RenderFrame()
|
|||
gl4ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
|
||||
gl4ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f;
|
||||
|
||||
if (fog_needs_update)
|
||||
if (fog_needs_update && settings.rend.Fog)
|
||||
{
|
||||
fog_needs_update = false;
|
||||
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE5, GL_RED);
|
||||
|
@ -764,7 +806,7 @@ static bool RenderFrame()
|
|||
{
|
||||
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
|
||||
{
|
||||
output_fbo = init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
|
||||
output_fbo = init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -826,22 +868,31 @@ static bool RenderFrame()
|
|||
float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
|
||||
if (!is_rtt)
|
||||
{
|
||||
if (settings.rend.Rotate90)
|
||||
{
|
||||
float t = width;
|
||||
width = height;
|
||||
height = t;
|
||||
t = min_x;
|
||||
min_x = min_y;
|
||||
min_y = 640 - t - height;
|
||||
}
|
||||
// Add x offset for aspect ratio > 4/3
|
||||
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
|
||||
min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling;
|
||||
// Invert y coordinates when rendering to screen
|
||||
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
|
||||
width *= dc2s_scale_h;
|
||||
height *= dc2s_scale_h;
|
||||
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
|
||||
width *= dc2s_scale_h * screen_stretching * screen_scaling;
|
||||
height *= dc2s_scale_h * screen_scaling;
|
||||
|
||||
if (ds2s_offs_x > 0)
|
||||
{
|
||||
float rounded_offs_x = ds2s_offs_x + 0.5f;
|
||||
float scaled_offs_x = ds2s_offs_x * screen_scaling;
|
||||
|
||||
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glcache.Enable(GL_SCISSOR_TEST);
|
||||
glScissor(0, 0, rounded_offs_x, screen_height);
|
||||
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
|
||||
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,23 +50,28 @@ void CustomTexture::LoaderThread()
|
|||
|
||||
if (texture != NULL)
|
||||
{
|
||||
// FIXME texture may have been deleted. Need to detect this.
|
||||
texture->ComputeHash();
|
||||
int width, height;
|
||||
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
|
||||
if (image_data == NULL)
|
||||
if (texture->custom_image_data != NULL)
|
||||
{
|
||||
image_data = LoadCustomTexture(texture->old_texture_hash, width, height);
|
||||
delete [] texture->custom_image_data;
|
||||
texture->custom_image_data = NULL;
|
||||
}
|
||||
if (image_data != NULL)
|
||||
if (!texture->dirty)
|
||||
{
|
||||
if (texture->custom_image_data != NULL)
|
||||
delete [] texture->custom_image_data;
|
||||
texture->custom_width = width;
|
||||
texture->custom_height = height;
|
||||
texture->custom_image_data = image_data;
|
||||
int width, height;
|
||||
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
|
||||
if (image_data == NULL)
|
||||
{
|
||||
image_data = LoadCustomTexture(texture->old_texture_hash, width, height);
|
||||
}
|
||||
if (image_data != NULL)
|
||||
{
|
||||
texture->custom_width = width;
|
||||
texture->custom_height = height;
|
||||
texture->custom_image_data = image_data;
|
||||
}
|
||||
}
|
||||
texture->custom_load_in_progress = false;
|
||||
texture->custom_load_in_progress--;
|
||||
}
|
||||
|
||||
} while (texture != NULL);
|
||||
|
@ -144,10 +149,9 @@ u8* CustomTexture::LoadCustomTexture(u32 hash, int& width, int& height)
|
|||
void CustomTexture::LoadCustomTextureAsync(TextureCacheData *texture_data)
|
||||
{
|
||||
if (!Init())
|
||||
{
|
||||
texture_data->custom_load_in_progress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
texture_data->custom_load_in_progress++;
|
||||
work_queue_mutex.Lock();
|
||||
work_queue.insert(work_queue.begin(), texture_data);
|
||||
work_queue_mutex.Unlock();
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
cThread loader_thread;
|
||||
#endif
|
||||
cResetEvent wakeup_thread;
|
||||
std::vector<struct TextureCacheData *> work_queue;
|
||||
std::vector<TextureCacheData *> work_queue;
|
||||
cMutex work_queue_mutex;
|
||||
};
|
||||
|
||||
|
|
|
@ -149,6 +149,19 @@ public:
|
|||
return _texture_ids[--_texture_cache_size];
|
||||
}
|
||||
|
||||
void DeleteProgram(GLuint program)
|
||||
{
|
||||
GLsizei shader_count;
|
||||
GLuint shaders[2];
|
||||
glGetAttachedShaders(program, ARRAY_SIZE(shaders), &shader_count, shaders);
|
||||
for (int i = 0; i < shader_count; i++)
|
||||
glDeleteShader(shaders[i]);
|
||||
|
||||
glDeleteProgram(program);
|
||||
if (_program == program)
|
||||
_program = 0;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
_texture = 0xFFFFFFFFu;
|
||||
_src_blend_factor = 0xFFFFFFFFu;
|
||||
|
@ -179,7 +192,7 @@ public:
|
|||
void DisableCache() { _disable_cache = true; }
|
||||
void EnableCache()
|
||||
{
|
||||
_disable_cache = true;
|
||||
_disable_cache = false;
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
|
|
@ -114,13 +114,30 @@ s32 SetTileClip(u32 val, GLint uniform)
|
|||
csy /= scale_y;
|
||||
cex /= scale_x;
|
||||
cey /= scale_y;
|
||||
float t = cey;
|
||||
cey = 480 - csy;
|
||||
csy = 480 - t;
|
||||
float dc2s_scale_h = screen_height / 480.0f;
|
||||
float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2;
|
||||
csx = csx * dc2s_scale_h + ds2s_offs_x;
|
||||
cex = cex * dc2s_scale_h + ds2s_offs_x;
|
||||
float dc2s_scale_h;
|
||||
float ds2s_offs_x;
|
||||
float screen_stretching = settings.rend.ScreenStretching / 100.f;
|
||||
|
||||
if (settings.rend.Rotate90)
|
||||
{
|
||||
float t = cex;
|
||||
cex = cey;
|
||||
cey = 640 - csx;
|
||||
csx = csy;
|
||||
csy = 640 - t;
|
||||
dc2s_scale_h = screen_height / 640.0f;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
float t = cey;
|
||||
cey = 480 - csy;
|
||||
csy = 480 - t;
|
||||
dc2s_scale_h = screen_height / 480.0f;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2;
|
||||
}
|
||||
csx = csx * dc2s_scale_h * screen_stretching + ds2s_offs_x;
|
||||
cex = cex * dc2s_scale_h * screen_stretching + ds2s_offs_x;
|
||||
csy = csy * dc2s_scale_h;
|
||||
cey = cey * dc2s_scale_h;
|
||||
}
|
||||
|
@ -173,28 +190,25 @@ __forceinline
|
|||
ShaderUniforms.trilinear_alpha = 1.f;
|
||||
|
||||
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
||||
int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2;
|
||||
|
||||
CurrentShader = &gl.pogram_table[
|
||||
GetProgramID(Type == ListType_Punch_Through ? 1 : 0,
|
||||
SetTileClip(gp->tileclip, -1) + 1,
|
||||
gp->pcw.Texture,
|
||||
gp->tsp.UseAlpha,
|
||||
gp->tsp.IgnoreTexA,
|
||||
gp->tsp.ShadInstr,
|
||||
gp->pcw.Offset,
|
||||
gp->tsp.FogCtrl,
|
||||
gp->pcw.Gouraud,
|
||||
gp->tcw.PixelFmt == PixelBumpMap,
|
||||
color_clamp,
|
||||
ShaderUniforms.trilinear_alpha != 1.f)];
|
||||
CurrentShader = GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||
SetTileClip(gp->tileclip, -1) + 1,
|
||||
gp->pcw.Texture,
|
||||
gp->tsp.UseAlpha,
|
||||
gp->tsp.IgnoreTexA,
|
||||
gp->tsp.ShadInstr,
|
||||
gp->pcw.Offset,
|
||||
fog_ctrl,
|
||||
gp->pcw.Gouraud,
|
||||
gp->tcw.PixelFmt == PixelBumpMap,
|
||||
color_clamp,
|
||||
ShaderUniforms.trilinear_alpha != 1.f);
|
||||
|
||||
if (CurrentShader->program == -1)
|
||||
CompilePipelineShader(CurrentShader);
|
||||
else
|
||||
{
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
ShaderUniforms.Set(CurrentShader);
|
||||
}
|
||||
glcache.UseProgram(CurrentShader->program);
|
||||
if (CurrentShader->trilinear_alpha != -1)
|
||||
glUniform1f(CurrentShader->trilinear_alpha, ShaderUniforms.trilinear_alpha);
|
||||
|
||||
SetTileClip(gp->tileclip, CurrentShader->pp_ClipTest);
|
||||
|
||||
//This bit control which pixels are affected
|
||||
|
@ -1122,14 +1136,8 @@ static void DrawQuad(GLuint texId, float x, float y, float w, float h, float u0,
|
|||
|
||||
ShaderUniforms.trilinear_alpha = 1.0;
|
||||
|
||||
PipelineShader *shader = &gl.pogram_table[GetProgramID(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false)];
|
||||
if (shader->program == -1)
|
||||
CompilePipelineShader(shader);
|
||||
else
|
||||
{
|
||||
glcache.UseProgram(shader->program);
|
||||
ShaderUniforms.Set(shader);
|
||||
}
|
||||
PipelineShader *shader = GetProgram(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false);
|
||||
glcache.UseProgram(shader->program);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, texId);
|
||||
|
@ -1150,17 +1158,27 @@ void DrawFramebuffer(float w, float h)
|
|||
|
||||
bool render_output_framebuffer()
|
||||
{
|
||||
#if HOST_OS != OS_DARWIN
|
||||
//Fix this in a proper way
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
#endif
|
||||
glViewport(0, 0, screen_width, screen_height);
|
||||
if (gl.ofbo.tex == 0)
|
||||
return false;
|
||||
|
||||
float scl = 480.f / screen_height;
|
||||
float tx = (screen_width * scl - 640.f) / 2;
|
||||
DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
|
||||
|
||||
glcache.Disable(GL_SCISSOR_TEST);
|
||||
if (gl.gl_major < 3)
|
||||
{
|
||||
glViewport(0, 0, screen_width, screen_height);
|
||||
if (gl.ofbo.tex == 0)
|
||||
return false;
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
float scl = 480.f / screen_height;
|
||||
float tx = (screen_width * scl - 640.f) / 2;
|
||||
DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gl.ofbo.fbo == 0)
|
||||
return false;
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
|
||||
0, 0, screen_width, screen_height,
|
||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ const char* VertexShaderSource =
|
|||
%s \n\
|
||||
#define TARGET_GL %s \n\
|
||||
#define pp_Gouraud %d \n\
|
||||
#define ROTATE_90 %d \n\
|
||||
\n\
|
||||
#define GLES2 0 \n\
|
||||
#define GLES3 1 \n\
|
||||
|
@ -136,6 +137,9 @@ void main() \n\
|
|||
vpos.z = vpos.w; \n\
|
||||
#else \n\
|
||||
vpos.z=depth_scale.x+depth_scale.y*vpos.w; \n\
|
||||
#endif \n\
|
||||
#if ROTATE_90 == 1 \n\
|
||||
vpos.xy = vec2(vpos.y, -vpos.x); \n\
|
||||
#endif \n\
|
||||
vpos.xy=vpos.xy*scale.xy-scale.zw; \n\
|
||||
vpos.xy*=vpos.w; \n\
|
||||
|
@ -850,9 +854,20 @@ GLuint fogTextureId;
|
|||
extern void gl_term();
|
||||
#endif
|
||||
|
||||
static void gl_delete_shaders()
|
||||
{
|
||||
for (auto it : gl.shaders)
|
||||
{
|
||||
if (it.second.program != 0)
|
||||
glcache.DeleteProgram(it.second.program);
|
||||
}
|
||||
gl.shaders.clear();
|
||||
glcache.DeleteProgram(gl.modvol_shader.program);
|
||||
gl.modvol_shader.program = 0;
|
||||
}
|
||||
|
||||
static void gles_term()
|
||||
{
|
||||
glDeleteProgram(gl.modvol_shader.program);
|
||||
glDeleteBuffers(1, &gl.vbo.geometry);
|
||||
gl.vbo.geometry = 0;
|
||||
glDeleteBuffers(1, &gl.vbo.modvols);
|
||||
|
@ -865,7 +880,7 @@ static void gles_term()
|
|||
gl_free_osd_resources();
|
||||
free_output_framebuffer();
|
||||
|
||||
memset(gl.pogram_table, 0, sizeof(gl.pogram_table));
|
||||
gl_delete_shaders();
|
||||
gl_term();
|
||||
}
|
||||
|
||||
|
@ -1014,10 +1029,15 @@ GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader)
|
|||
return program;
|
||||
}
|
||||
|
||||
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear)
|
||||
{
|
||||
if (settings.rend.Rotate90 != gl.rotate90)
|
||||
{
|
||||
gl_delete_shaders();
|
||||
gl.rotate90 = settings.rend.Rotate90;
|
||||
}
|
||||
u32 rv=0;
|
||||
|
||||
rv|=pp_ClipTestMode;
|
||||
|
@ -1033,14 +1053,32 @@ int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
|||
rv<<=1; rv|=fog_clamping;
|
||||
rv<<=1; rv|=trilinear;
|
||||
|
||||
return rv;
|
||||
PipelineShader *shader = &gl.shaders[rv];
|
||||
if (shader->program == 0)
|
||||
{
|
||||
shader->cp_AlphaTest = cp_AlphaTest;
|
||||
shader->pp_ClipTestMode = pp_ClipTestMode-1;
|
||||
shader->pp_Texture = pp_Texture;
|
||||
shader->pp_UseAlpha = pp_UseAlpha;
|
||||
shader->pp_IgnoreTexA = pp_IgnoreTexA;
|
||||
shader->pp_ShadInstr = pp_ShadInstr;
|
||||
shader->pp_Offset = pp_Offset;
|
||||
shader->pp_FogCtrl = pp_FogCtrl;
|
||||
shader->pp_Gouraud = pp_Gouraud;
|
||||
shader->pp_BumpMap = pp_BumpMap;
|
||||
shader->fog_clamping = fog_clamping;
|
||||
shader->trilinear = trilinear;
|
||||
CompilePipelineShader(shader);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
bool CompilePipelineShader( PipelineShader* s)
|
||||
{
|
||||
char vshader[8192];
|
||||
|
||||
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud);
|
||||
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud, settings.rend.Rotate90);
|
||||
|
||||
char pshader[8192];
|
||||
|
||||
|
@ -1126,13 +1164,30 @@ void gl_load_osd_resources()
|
|||
|
||||
void gl_free_osd_resources()
|
||||
{
|
||||
glDeleteProgram(gl.OSD_SHADER.program);
|
||||
glcache.DeleteProgram(gl.OSD_SHADER.program);
|
||||
|
||||
if (osd_tex != 0) {
|
||||
glcache.DeleteTextures(1, &osd_tex);
|
||||
osd_tex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void create_modvol_shader()
|
||||
{
|
||||
if (gl.modvol_shader.program != 0)
|
||||
return;
|
||||
char vshader[8192];
|
||||
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1, settings.rend.Rotate90);
|
||||
char fshader[8192];
|
||||
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
|
||||
|
||||
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
|
||||
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
|
||||
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
|
||||
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
|
||||
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
|
||||
}
|
||||
|
||||
bool gl_create_resources()
|
||||
{
|
||||
if (gl.vbo.geometry != 0)
|
||||
|
@ -1156,84 +1211,7 @@ bool gl_create_resources()
|
|||
glGenBuffers(1, &gl.vbo.idxs);
|
||||
glGenBuffers(1, &gl.vbo.idxs2);
|
||||
|
||||
memset(gl.pogram_table,0,sizeof(gl.pogram_table));
|
||||
|
||||
PipelineShader* dshader=0;
|
||||
u32 compile=0;
|
||||
#define forl(name,max) for(u32 name=0;name<=max;name++)
|
||||
forl(cp_AlphaTest,1)
|
||||
{
|
||||
forl(pp_ClipTestMode,2)
|
||||
{
|
||||
forl(pp_UseAlpha,1)
|
||||
{
|
||||
forl(pp_Texture,1)
|
||||
{
|
||||
forl(pp_FogCtrl,3)
|
||||
{
|
||||
forl(pp_IgnoreTexA,1)
|
||||
{
|
||||
forl(pp_ShadInstr,3)
|
||||
{
|
||||
forl(pp_Offset,1)
|
||||
{
|
||||
forl(pp_Gouraud,1)
|
||||
{
|
||||
forl(pp_BumpMap,1)
|
||||
{
|
||||
forl(fog_clamping,1)
|
||||
{
|
||||
forl(trilinear,1)
|
||||
{
|
||||
dshader=&gl.pogram_table[GetProgramID(cp_AlphaTest,pp_ClipTestMode,pp_Texture,pp_UseAlpha,pp_IgnoreTexA,
|
||||
pp_ShadInstr,pp_Offset,pp_FogCtrl, (bool)pp_Gouraud, (bool)pp_BumpMap, (bool)fog_clamping,
|
||||
(bool)trilinear)];
|
||||
|
||||
dshader->cp_AlphaTest = cp_AlphaTest;
|
||||
dshader->pp_ClipTestMode = pp_ClipTestMode-1;
|
||||
dshader->pp_Texture = pp_Texture;
|
||||
dshader->pp_UseAlpha = pp_UseAlpha;
|
||||
dshader->pp_IgnoreTexA = pp_IgnoreTexA;
|
||||
dshader->pp_ShadInstr = pp_ShadInstr;
|
||||
dshader->pp_Offset = pp_Offset;
|
||||
dshader->pp_FogCtrl = pp_FogCtrl;
|
||||
dshader->pp_Gouraud = pp_Gouraud;
|
||||
dshader->pp_BumpMap = pp_BumpMap;
|
||||
dshader->fog_clamping = fog_clamping;
|
||||
dshader->trilinear = trilinear;
|
||||
dshader->program = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char vshader[8192];
|
||||
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1);
|
||||
char fshader[8192];
|
||||
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
|
||||
|
||||
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
|
||||
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
|
||||
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
|
||||
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
|
||||
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
|
||||
|
||||
//#define PRECOMPILE_SHADERS
|
||||
#ifdef PRECOMPILE_SHADERS
|
||||
for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
|
||||
{
|
||||
if (!CompilePipelineShader( &gl.pogram_table[i] ))
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
create_modvol_shader();
|
||||
|
||||
gl_load_osd_resources();
|
||||
|
||||
|
@ -1553,6 +1531,7 @@ static void upload_vertex_indices()
|
|||
bool RenderFrame()
|
||||
{
|
||||
DoCleanup();
|
||||
create_modvol_shader();
|
||||
|
||||
bool is_rtt=pvrrc.isRTT;
|
||||
|
||||
|
@ -1719,17 +1698,41 @@ bool RenderFrame()
|
|||
/*
|
||||
Handle Dc to screen scaling
|
||||
*/
|
||||
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
|
||||
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
|
||||
dc2s_scale_h *= screen_scaling;
|
||||
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
|
||||
float screen_stretching = settings.rend.ScreenStretching / 100.f;
|
||||
float screen_scaling = settings.rend.ScreenScaling / 100.f;
|
||||
|
||||
//-1 -> too much to left
|
||||
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
|
||||
ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
|
||||
ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
|
||||
ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1);
|
||||
float dc2s_scale_h;
|
||||
float ds2s_offs_x;
|
||||
|
||||
if (is_rtt)
|
||||
{
|
||||
ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
|
||||
ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
|
||||
ShaderUniforms.scale_coefs[2] = 1;
|
||||
ShaderUniforms.scale_coefs[3] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (settings.rend.Rotate90)
|
||||
{
|
||||
dc2s_scale_h = screen_height / 640.0f;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2;
|
||||
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
|
||||
ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
|
||||
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
|
||||
ShaderUniforms.scale_coefs[3] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dc2s_scale_h = screen_height / 480.0f;
|
||||
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2;
|
||||
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
|
||||
ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
|
||||
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
|
||||
ShaderUniforms.scale_coefs[3] = -1;
|
||||
}
|
||||
//-1 -> too much to left
|
||||
}
|
||||
|
||||
ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ);
|
||||
ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1;
|
||||
|
@ -1768,7 +1771,7 @@ bool RenderFrame()
|
|||
ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
|
||||
ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f;
|
||||
|
||||
if (fog_needs_update)
|
||||
if (fog_needs_update && settings.rend.Fog)
|
||||
{
|
||||
fog_needs_update = false;
|
||||
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.fog_image_format);
|
||||
|
@ -1782,16 +1785,12 @@ bool RenderFrame()
|
|||
|
||||
ShaderUniforms.PT_ALPHA=(PT_ALPHA_REF&0xFF)/255.0f;
|
||||
|
||||
// for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
|
||||
// {
|
||||
// PipelineShader* s=&gl.pogram_table[i];
|
||||
// if (s->program == -1)
|
||||
// continue;
|
||||
//
|
||||
// glcache.UseProgram(s->program);
|
||||
//
|
||||
// ShaderUniforms.Set(s);
|
||||
// }
|
||||
for (auto it : gl.shaders)
|
||||
{
|
||||
glcache.UseProgram(it.second.program);
|
||||
ShaderUniforms.Set(&it.second);
|
||||
}
|
||||
|
||||
//setup render target first
|
||||
if (is_rtt)
|
||||
{
|
||||
|
@ -1836,7 +1835,7 @@ bool RenderFrame()
|
|||
{
|
||||
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
|
||||
{
|
||||
init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
|
||||
init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1883,9 +1882,6 @@ bool RenderFrame()
|
|||
glBufferData(GL_ARRAY_BUFFER,pvrrc.modtrig.bytes(),pvrrc.modtrig.head(),GL_STREAM_DRAW); glCheck();
|
||||
}
|
||||
|
||||
int offs_x=ds2s_offs_x+0.5f;
|
||||
//this needs to be scaled
|
||||
|
||||
//not all scaling affects pixel operations, scale to adjust for that
|
||||
scale_x *= scissoring_scale_x;
|
||||
|
||||
|
@ -1904,22 +1900,31 @@ bool RenderFrame()
|
|||
float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
|
||||
if (!is_rtt)
|
||||
{
|
||||
if (settings.rend.Rotate90)
|
||||
{
|
||||
float t = width;
|
||||
width = height;
|
||||
height = t;
|
||||
t = min_x;
|
||||
min_x = min_y;
|
||||
min_y = 640 - t - height;
|
||||
}
|
||||
// Add x offset for aspect ratio > 4/3
|
||||
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
|
||||
min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling;
|
||||
// Invert y coordinates when rendering to screen
|
||||
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
|
||||
width *= dc2s_scale_h;
|
||||
height *= dc2s_scale_h;
|
||||
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
|
||||
width *= dc2s_scale_h * screen_stretching * screen_scaling;
|
||||
height *= dc2s_scale_h * screen_scaling;
|
||||
|
||||
if (ds2s_offs_x > 0)
|
||||
{
|
||||
float rounded_offs_x = ds2s_offs_x + 0.5f;
|
||||
float scaled_offs_x = ds2s_offs_x * screen_scaling;
|
||||
|
||||
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glcache.Enable(GL_SCISSOR_TEST);
|
||||
glScissor(0, 0, rounded_offs_x, screen_height);
|
||||
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
|
||||
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <atomic>
|
||||
#include "rend/rend.h"
|
||||
|
||||
#if (defined(GLES) && !defined(TARGET_NACL32) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(_ANDROID)
|
||||
|
@ -93,7 +95,9 @@ struct gl_ctx
|
|||
|
||||
} modvol_shader;
|
||||
|
||||
PipelineShader pogram_table[24576];
|
||||
std::unordered_map<u32, PipelineShader> shaders;
|
||||
bool rotate90;
|
||||
|
||||
struct
|
||||
{
|
||||
GLuint program;
|
||||
|
@ -117,6 +121,7 @@ struct gl_ctx
|
|||
struct
|
||||
{
|
||||
GLuint depthb;
|
||||
GLuint colorb;
|
||||
GLuint tex;
|
||||
GLuint fbo;
|
||||
int width;
|
||||
|
@ -176,7 +181,7 @@ void free_output_framebuffer();
|
|||
|
||||
void HideOSD();
|
||||
void OSD_DRAW(bool clear_screen);
|
||||
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear);
|
||||
|
||||
|
@ -223,9 +228,6 @@ extern struct ShaderUniforms_t
|
|||
if (s->sp_FOG_COL_VERT!=-1)
|
||||
glUniform3fv( s->sp_FOG_COL_VERT, 1, ps_FOG_COL_VERT);
|
||||
|
||||
if (s->trilinear_alpha != -1)
|
||||
glUniform1f(s->trilinear_alpha, trilinear_alpha);
|
||||
|
||||
if (s->fog_clamp_min != -1)
|
||||
glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min);
|
||||
if (s->fog_clamp_max != -1)
|
||||
|
@ -272,10 +274,10 @@ struct TextureCacheData
|
|||
//a texture can't be both VQ and PAL at the same time
|
||||
u32 texture_hash; // xxhash of texture data, used for custom textures
|
||||
u32 old_texture_hash; // legacy hash
|
||||
u8* custom_image_data; // loaded custom image data
|
||||
u32 custom_width;
|
||||
u32 custom_height;
|
||||
bool custom_load_in_progress;
|
||||
u8* volatile custom_image_data; // loaded custom image data
|
||||
volatile u32 custom_width;
|
||||
volatile u32 custom_height;
|
||||
std::atomic_int custom_load_in_progress;
|
||||
|
||||
void PrintTextureName();
|
||||
|
||||
|
|
|
@ -296,10 +296,7 @@ void TextureCacheData::Update()
|
|||
}
|
||||
}
|
||||
if (settings.rend.CustomTextures)
|
||||
{
|
||||
custom_load_in_progress = true;
|
||||
custom_texture.LoadCustomTextureAsync(this);
|
||||
}
|
||||
|
||||
void *temp_tex_buffer = NULL;
|
||||
u32 upscaled_w = w;
|
||||
|
@ -428,7 +425,7 @@ void TextureCacheData::UploadToGPU(GLuint textype, int width, int height, u8 *te
|
|||
|
||||
void TextureCacheData::CheckCustomTexture()
|
||||
{
|
||||
if (custom_image_data != NULL)
|
||||
if (custom_load_in_progress == 0 && custom_image_data != NULL)
|
||||
{
|
||||
UploadToGPU(GL_UNSIGNED_BYTE, custom_width, custom_height, custom_image_data);
|
||||
delete [] custom_image_data;
|
||||
|
@ -446,7 +443,7 @@ bool TextureCacheData::NeedsUpdate() {
|
|||
|
||||
bool TextureCacheData::Delete()
|
||||
{
|
||||
if (custom_load_in_progress)
|
||||
if (custom_load_in_progress > 0)
|
||||
return false;
|
||||
|
||||
if (pData) {
|
||||
|
@ -736,11 +733,7 @@ TextureCacheData *getTextureCacheData(TSP tsp, TCW tcw) {
|
|||
}
|
||||
else //create if not existing
|
||||
{
|
||||
TextureCacheData tfc={0};
|
||||
TexCache[key] = tfc;
|
||||
|
||||
tx=TexCache.find(key);
|
||||
tf=&tx->second;
|
||||
tf=&TexCache[key];
|
||||
|
||||
tf->tsp = tsp;
|
||||
tf->tcw = tcw;
|
||||
|
@ -800,11 +793,7 @@ text_info raw_GetTexture(TSP tsp, TCW tcw)
|
|||
}
|
||||
else //create if not existing
|
||||
{
|
||||
TextureCacheData tfc = { 0 };
|
||||
TexCache[key] = tfc;
|
||||
|
||||
tx = TexCache.find(key);
|
||||
tf = &tx->second;
|
||||
tf = &TexCache[key];
|
||||
|
||||
tf->tsp = tsp;
|
||||
tf->tcw = tcw;
|
||||
|
@ -1007,13 +996,7 @@ GLuint init_output_framebuffer(int width, int height)
|
|||
{
|
||||
if (width != gl.ofbo.width || height != gl.ofbo.height)
|
||||
{
|
||||
if (gl.ofbo.fbo != 0)
|
||||
{
|
||||
glDeleteFramebuffers(1, &gl.ofbo.fbo);
|
||||
gl.ofbo.fbo = 0;
|
||||
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
|
||||
glcache.DeleteTextures(1, &gl.ofbo.tex);
|
||||
}
|
||||
free_output_framebuffer();
|
||||
gl.ofbo.width = width;
|
||||
gl.ofbo.height = height;
|
||||
}
|
||||
|
@ -1037,15 +1020,25 @@ GLuint init_output_framebuffer(int width, int height)
|
|||
else
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
|
||||
// Create a texture for rendering to
|
||||
gl.ofbo.tex = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
|
||||
if (gl.gl_major < 3)
|
||||
{
|
||||
// Create a texture for rendering to
|
||||
gl.ofbo.tex = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use a renderbuffer and glBlitFramebuffer
|
||||
glGenRenderbuffers(1, &gl.ofbo.colorb);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, gl.ofbo.colorb);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
|
||||
}
|
||||
|
||||
// Create the framebuffer
|
||||
glGenFramebuffers(1, &gl.ofbo.fbo);
|
||||
|
@ -1057,13 +1050,20 @@ GLuint init_output_framebuffer(int width, int height)
|
|||
if (!gl.is_gles || gl.GL_OES_packed_depth_stencil_supported)
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl.ofbo.depthb);
|
||||
|
||||
// Attach the texture to the FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0);
|
||||
// Attach the texture/renderbuffer to the FBO
|
||||
if (gl.gl_major < 3)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0);
|
||||
else
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gl.ofbo.colorb);
|
||||
|
||||
// Check that our FBO creation was successful
|
||||
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
|
||||
verify(uStatus == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
glcache.Disable(GL_SCISSOR_TEST);
|
||||
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
else
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.fbo);
|
||||
|
@ -1082,7 +1082,15 @@ void free_output_framebuffer()
|
|||
gl.ofbo.fbo = 0;
|
||||
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
|
||||
gl.ofbo.depthb = 0;
|
||||
glcache.DeleteTextures(1, &gl.ofbo.tex);
|
||||
gl.ofbo.tex = 0;
|
||||
if (gl.ofbo.tex != 0)
|
||||
{
|
||||
glcache.DeleteTextures(1, &gl.ofbo.tex);
|
||||
gl.ofbo.tex = 0;
|
||||
}
|
||||
if (gl.ofbo.colorb != 0)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &gl.ofbo.colorb);
|
||||
gl.ofbo.colorb = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#endif
|
||||
|
||||
#include "gles.h"
|
||||
#include "glcache.h"
|
||||
|
||||
// OpenGL Data
|
||||
static char g_GlslVersionString[32] = "";
|
||||
|
@ -127,28 +128,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
|
|||
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
|
||||
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
#ifdef GL_POLYGON_MODE
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
#endif
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
bool clip_origin_lower_left = true;
|
||||
#ifdef GL_CLIP_ORIGIN
|
||||
if (gl.gl_major >= 4 && glClipControl != NULL)
|
||||
|
@ -166,13 +146,13 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
|
|||
|
||||
// (Re-)create the background texture and reserve space for it
|
||||
if (g_BackgroundTexture != 0)
|
||||
glDeleteTextures(1, &g_BackgroundTexture);
|
||||
glGenTextures(1, &g_BackgroundTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glcache.DeleteTextures(1, &g_BackgroundTexture);
|
||||
g_BackgroundTexture = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_width, fb_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)NULL);
|
||||
|
||||
// Copy the current framebuffer into it
|
||||
|
@ -180,12 +160,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
|
|||
}
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glcache.Enable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glcache.Disable(GL_CULL_FACE);
|
||||
glcache.Disable(GL_DEPTH_TEST);
|
||||
glcache.Enable(GL_SCISSOR_TEST);
|
||||
#ifdef GL_POLYGON_MODE
|
||||
if (glPolygonMode != NULL)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
@ -205,7 +185,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
|
|||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||
};
|
||||
glUseProgram(g_ShaderHandle);
|
||||
glcache.UseProgram(g_ShaderHandle);
|
||||
glUniform1i(g_AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
if (gl.gl_major >= 3 && glBindSampler != NULL)
|
||||
|
@ -260,7 +240,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
|
|||
glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
|
||||
}
|
||||
}
|
||||
|
@ -269,28 +249,6 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
|
|||
}
|
||||
if (vao_handle != 0)
|
||||
glDeleteVertexArrays(1, &vao_handle);
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
if (gl.gl_major >= 3 && glBindSampler != NULL)
|
||||
glBindSampler(0, last_sampler);
|
||||
glActiveTexture(last_active_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
if (gl.gl_major >= 3)
|
||||
glBindVertexArray(last_vertex_array);
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
#ifdef GL_POLYGON_MODE
|
||||
if (glPolygonMode != NULL)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
#endif
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
|
@ -302,21 +260,16 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
|||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &g_FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
g_FontTexture = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
|
||||
|
||||
// Restore state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -325,7 +278,7 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
|||
if (g_FontTexture)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
glDeleteTextures(1, &g_FontTexture);
|
||||
glcache.DeleteTextures(1, &g_FontTexture);
|
||||
io.Fonts->TexID = 0;
|
||||
g_FontTexture = 0;
|
||||
}
|
||||
|
@ -369,12 +322,6 @@ static bool CheckProgram(GLuint handle, const char* desc)
|
|||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer, last_vertex_array;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
|
||||
// Parse GLSL version string
|
||||
int glsl_version = 130;
|
||||
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
|
||||
|
@ -534,12 +481,6 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
|||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
if (gl.gl_major >= 3)
|
||||
glBindVertexArray(last_vertex_array);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -549,26 +490,23 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
|||
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle);
|
||||
g_VboHandle = g_ElementsHandle = 0;
|
||||
|
||||
if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle);
|
||||
if (g_VertHandle) glDeleteShader(g_VertHandle);
|
||||
glcache.DeleteProgram(g_ShaderHandle);
|
||||
g_VertHandle = 0;
|
||||
|
||||
if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle);
|
||||
if (g_FragHandle) glDeleteShader(g_FragHandle);
|
||||
g_FragHandle = 0;
|
||||
|
||||
if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle);
|
||||
g_ShaderHandle = 0;
|
||||
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
|
||||
if (g_BackgroundTexture != 0)
|
||||
glDeleteTextures(1, &g_BackgroundTexture);
|
||||
glcache.DeleteTextures(1, &g_BackgroundTexture);
|
||||
g_BackgroundTexture = 0;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DrawBackground()
|
||||
{
|
||||
glcache.Disable(GL_SCISSOR_TEST);
|
||||
glcache.ClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (g_BackgroundTexture != 0)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
@ -579,20 +517,14 @@ void ImGui_ImplOpenGL3_DrawBackground()
|
|||
ImGui::GetWindowDrawList()->AddImage((ImTextureID)(uintptr_t)g_BackgroundTexture, ImVec2(0, 0), io.DisplaySize, ImVec2(0, 1), ImVec2(1, 0), 0xffffffff);
|
||||
ImGui::End();
|
||||
}
|
||||
else
|
||||
{
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
|
||||
{
|
||||
GLuint tex_id;
|
||||
glGenTextures(1, &tex_id);
|
||||
glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
GLuint tex_id = glcache.GenTexture();
|
||||
glcache.BindTexture(GL_TEXTURE_2D, tex_id);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 48, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
return reinterpret_cast<ImTextureID>(tex_id);
|
||||
|
@ -600,5 +532,5 @@ ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
|
|||
|
||||
void ImGui_ImplOpenGL3_DeleteVmuTexture(ImTextureID tex_id)
|
||||
{
|
||||
glDeleteTextures(1, &(GLuint &)tex_id);
|
||||
glcache.DeleteTextures(1, &(GLuint &)tex_id);
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@
|
|||
#include "linux-dist/main.h" // FIXME for kcode[]
|
||||
#include "gui_util.h"
|
||||
#include "gui_android.h"
|
||||
#include "version.h"
|
||||
#include "version/version.h"
|
||||
#include "oslib/audiostream.h"
|
||||
|
||||
|
||||
extern void dc_loadstate();
|
||||
extern void dc_savestate();
|
||||
|
@ -299,7 +301,9 @@ static void gui_display_commands()
|
|||
if (!settings_opening)
|
||||
ImGui_ImplOpenGL3_DrawBackground();
|
||||
|
||||
display_vmus();
|
||||
if (!settings.rend.FloatVMUs)
|
||||
// If floating VMUs, they are already visible on the background
|
||||
display_vmus();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(screen_width / 2.f, screen_height / 2.f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
ImGui::SetNextWindowSize(ImVec2(330 * scaling, 0));
|
||||
|
@ -622,6 +626,8 @@ void directory_selected_callback(bool cancelled, std::string selection)
|
|||
|
||||
static void gui_display_settings()
|
||||
{
|
||||
static bool maple_devices_changed;
|
||||
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
|
@ -644,10 +650,14 @@ static void gui_display_settings()
|
|||
gui_state = Commands;
|
||||
else
|
||||
gui_state = Main;
|
||||
if (maple_devices_changed)
|
||||
{
|
||||
maple_devices_changed = false;
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
maple_ReconnectDevices();
|
||||
reset_vmus();
|
||||
maple_ReconnectDevices();
|
||||
reset_vmus();
|
||||
#endif
|
||||
}
|
||||
SaveSettings();
|
||||
}
|
||||
if (game_started)
|
||||
|
@ -801,13 +811,14 @@ static void gui_display_settings()
|
|||
if (ImGui::BeginTabItem("Controls"))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
if (ImGui::CollapsingHeader("Dreamcast Devices", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
for (int bus = 0; bus < MAPLE_PORTS; bus++)
|
||||
{
|
||||
ImGui::Text("Device %c", bus + 'A');
|
||||
ImGui::SameLine();
|
||||
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
|
||||
char device_name[32];
|
||||
sprintf(device_name, "##device%d", bus);
|
||||
float w = ImGui::CalcItemWidth() / 3;
|
||||
|
@ -818,7 +829,10 @@ static void gui_display_settings()
|
|||
{
|
||||
bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i);
|
||||
if (ImGui::Selectable(maple_device_types[i], &is_selected))
|
||||
{
|
||||
settings.input.maple_devices[bus] = maple_device_type_from_index(i);
|
||||
maple_devices_changed = true;
|
||||
}
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
@ -836,7 +850,10 @@ static void gui_display_settings()
|
|||
{
|
||||
bool is_selected = settings.input.maple_expansion_devices[bus][port] == maple_expansion_device_type_from_index(i);
|
||||
if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected))
|
||||
{
|
||||
settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i);
|
||||
maple_devices_changed = true;
|
||||
}
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
@ -845,6 +862,10 @@ static void gui_display_settings()
|
|||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
if (MapleDevices[bus][5] != NULL)
|
||||
ImGui::Text("%s", maple_device_name(MapleDevices[bus][5]->get_device_type()));
|
||||
#endif
|
||||
}
|
||||
ImGui::Spacing();
|
||||
}
|
||||
|
@ -945,15 +966,27 @@ static void gui_display_settings()
|
|||
ImGui::Checkbox("Shadows", &settings.rend.ModifierVolumes);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Enable modifier volumes, usually used for shadows");
|
||||
ImGui::Checkbox("Fog", &settings.rend.Fog);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Enable fog effects");
|
||||
ImGui::Checkbox("Widescreen", &settings.rend.WideScreen);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas");
|
||||
ImGui::Checkbox("Show FPS Counter", &settings.rend.ShowFPS);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Show on-screen frame/sec counter");
|
||||
ImGui::Checkbox("Show VMU in game", &settings.rend.FloatVMUs);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Show the VMU LCD screens while in game");
|
||||
ImGui::Checkbox("Rotate screen 90°", &settings.rend.Rotate90);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Rotate the screen 90° counterclockwise");
|
||||
ImGui::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better");
|
||||
ImGui::SliderInt("Horizontal Stretching", (int *)&settings.rend.ScreenStretching, 100, 150);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Stretch the screen horizontally");
|
||||
ImGui::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Number of frames to skip between two actually rendered frames");
|
||||
|
@ -991,6 +1024,48 @@ static void gui_display_settings()
|
|||
ImGui::Checkbox("Disable Sound", &settings.aica.NoSound);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Disable the emulator sound output");
|
||||
|
||||
audiobackend_t* backend = NULL;;
|
||||
std::string backend_name = settings.audio.backend;
|
||||
if (backend_name != "auto" && backend_name != "none")
|
||||
{
|
||||
backend = GetAudioBackend(settings.audio.backend);
|
||||
if (backend != NULL)
|
||||
backend_name = backend->slug;
|
||||
}
|
||||
|
||||
SortAudioBackends();
|
||||
if (ImGui::BeginCombo("Audio Backend", backend_name.c_str(), ImGuiComboFlags_None))
|
||||
{
|
||||
bool is_selected = (settings.audio.backend == "auto");
|
||||
if (ImGui::Selectable("auto", &is_selected))
|
||||
settings.audio.backend = "auto";
|
||||
ImGui::SameLine(); ImGui::Text("-");
|
||||
ImGui::SameLine(); ImGui::Text("Autoselect audio backend");
|
||||
|
||||
is_selected = (settings.audio.backend == "none");
|
||||
if (ImGui::Selectable("none", &is_selected))
|
||||
settings.audio.backend = "none";
|
||||
ImGui::SameLine(); ImGui::Text("-");
|
||||
ImGui::SameLine(); ImGui::Text("No audio backend");
|
||||
|
||||
for (int i = 0; i < GetAudioBackendCount(); i++)
|
||||
{
|
||||
audiobackend_t* backend = GetAudioBackend(i);
|
||||
is_selected = (settings.audio.backend == backend->slug);
|
||||
|
||||
if (ImGui::Selectable(backend->slug.c_str(), &is_selected))
|
||||
settings.audio.backend = backend->slug;
|
||||
ImGui::SameLine(); ImGui::Text("-");
|
||||
ImGui::SameLine(); ImGui::Text(backend->name.c_str());
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("The audio backend to use");
|
||||
|
||||
ImGui::Checkbox("Enable DSP", &settings.aica.NoBatch);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Enable the Dreamcast Digital Sound Processor. Only recommended on fast and arm64 platforms");
|
||||
|
@ -1022,10 +1097,33 @@ static void gui_display_settings()
|
|||
ShowHelpMarker("Do not optimize integer division. Recommended");
|
||||
ImGui::Checkbox("Unstable Optimizations", &settings.dynarec.unstable_opt);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Enable unsafe optimizations. May cause crash or environmental disaster");
|
||||
ShowHelpMarker("Enable unsafe optimizations. Will cause crash or environmental disaster");
|
||||
ImGui::Checkbox("Idle Skip", &settings.dynarec.idleskip);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Skip wait loops. Recommended");
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize("Largeenough").x);
|
||||
const char *preview = settings.dynarec.SmcCheckLevel == NoCheck ? "Faster" : settings.dynarec.SmcCheckLevel == FastCheck ? "Fast" : "Full";
|
||||
if (ImGui::BeginCombo("SMC Checks", preview , ImGuiComboFlags_None))
|
||||
{
|
||||
bool is_selected = settings.dynarec.SmcCheckLevel == NoCheck;
|
||||
if (ImGui::Selectable("Faster", &is_selected))
|
||||
settings.dynarec.SmcCheckLevel = NoCheck;
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
is_selected = settings.dynarec.SmcCheckLevel == FastCheck;
|
||||
if (ImGui::Selectable("Fast", &is_selected))
|
||||
settings.dynarec.SmcCheckLevel = FastCheck;
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
is_selected = settings.dynarec.SmcCheckLevel == FullCheck;
|
||||
if (ImGui::Selectable("Full", &is_selected))
|
||||
settings.dynarec.SmcCheckLevel = FullCheck;
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("How to detect self-modifying code. Full check recommended");
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Other", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
|
@ -1230,6 +1328,7 @@ static void gui_start_game(const std::string& path)
|
|||
{
|
||||
gui_state = Main;
|
||||
game_started = false;
|
||||
cfgSetVirtual("config", "image", "");
|
||||
switch (rc) {
|
||||
case -3:
|
||||
error_msg = "Audio/video initialization failed";
|
||||
|
@ -1387,24 +1486,6 @@ void gui_display_ui()
|
|||
gui_state = Closed;
|
||||
}
|
||||
|
||||
void gui_display_fps(const char *string)
|
||||
{
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowBgAlpha(0);
|
||||
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
|
||||
|
||||
ImGui::Begin("##fps", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
|
||||
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
|
||||
ImGui::SetWindowFontScale(2);
|
||||
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", string);
|
||||
ImGui::End();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
static float LastFPSTime;
|
||||
static int lastFrameCount = 0;
|
||||
static float fps = -1;
|
||||
|
@ -1452,26 +1533,32 @@ void gui_display_osd()
|
|||
if (osd_message.empty())
|
||||
{
|
||||
message = getFPSNotification();
|
||||
if (message.empty())
|
||||
return;
|
||||
}
|
||||
else
|
||||
message = osd_message;
|
||||
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
if (!message.empty() || settings.rend.FloatVMUs)
|
||||
{
|
||||
ImGui_Impl_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
ImGui::SetNextWindowBgAlpha(0);
|
||||
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
|
||||
if (!message.empty())
|
||||
{
|
||||
ImGui::SetNextWindowBgAlpha(0);
|
||||
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
|
||||
|
||||
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
|
||||
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
|
||||
ImGui::SetWindowFontScale(1.5);
|
||||
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
|
||||
ImGui::End();
|
||||
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
|
||||
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
|
||||
ImGui::SetWindowFontScale(1.5);
|
||||
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
|
||||
ImGui::End();
|
||||
}
|
||||
if (settings.rend.FloatVMUs)
|
||||
display_vmus();
|
||||
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
}
|
||||
|
||||
void gui_open_onboarding()
|
||||
|
|
54
core/types.h
54
core/types.h
|
@ -39,7 +39,7 @@
|
|||
#undef _CRT_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
//unnamed struncts/unions
|
||||
#pragma warning( disable : 4201)
|
||||
|
||||
|
@ -123,7 +123,7 @@ enum HollyInterruptType
|
|||
};
|
||||
|
||||
enum HollyInterruptID
|
||||
{
|
||||
{
|
||||
// asic9a /sh4 external holly normal [internal]
|
||||
holly_RENDER_DONE_vd = holly_nrm | 0, //bit 0 = End of Render interrupt : Video
|
||||
holly_RENDER_DONE_isp = holly_nrm | 1, //bit 1 = End of Render interrupt : ISP
|
||||
|
@ -132,11 +132,11 @@ enum HollyInterruptID
|
|||
holly_SCANINT1 = holly_nrm | 3, //bit 3 = V Blank-in interrupt
|
||||
holly_SCANINT2 = holly_nrm | 4, //bit 4 = V Blank-out interrupt
|
||||
holly_HBLank = holly_nrm | 5, //bit 5 = H Blank-in interrupt
|
||||
|
||||
|
||||
holly_YUV_DMA = holly_nrm | 6, //bit 6 = End of Transferring interrupt : YUV
|
||||
holly_OPAQUE = holly_nrm | 7, //bit 7 = End of Transferring interrupt : Opaque List
|
||||
holly_OPAQUEMOD = holly_nrm | 8, //bit 8 = End of Transferring interrupt : Opaque Modifier Volume List
|
||||
|
||||
|
||||
holly_TRANS = holly_nrm | 9, //bit 9 = End of Transferring interrupt : Translucent List
|
||||
holly_TRANSMOD = holly_nrm | 10, //bit 10 = End of Transferring interrupt : Translucent Modifier Volume List
|
||||
holly_PVR_DMA = holly_nrm | 11, //bit 11 = End of DMA interrupt : PVR-DMA
|
||||
|
@ -145,12 +145,12 @@ enum HollyInterruptID
|
|||
holly_MAPLE_VBOI = holly_nrm | 13, //bit 13 = Maple V blank over interrupt
|
||||
holly_GDROM_DMA = holly_nrm | 14, //bit 14 = End of DMA interrupt : GD-DMA
|
||||
holly_SPU_DMA = holly_nrm | 15, //bit 15 = End of DMA interrupt : AICA-DMA
|
||||
|
||||
|
||||
holly_EXT_DMA1 = holly_nrm | 16, //bit 16 = End of DMA interrupt : Ext-DMA1(External 1)
|
||||
holly_EXT_DMA2 = holly_nrm | 17, //bit 17 = End of DMA interrupt : Ext-DMA2(External 2)
|
||||
holly_DEV_DMA = holly_nrm | 18, //bit 18 = End of DMA interrupt : Dev-DMA(Development tool DMA)
|
||||
|
||||
holly_CH2_DMA = holly_nrm | 19, //bit 19 = End of DMA interrupt : ch2-DMA
|
||||
|
||||
holly_CH2_DMA = holly_nrm | 19, //bit 19 = End of DMA interrupt : ch2-DMA
|
||||
holly_PVR_SortDMA = holly_nrm | 20, //bit 20 = End of DMA interrupt : Sort-DMA (Transferring for alpha sorting)
|
||||
holly_PUNCHTHRU = holly_nrm | 21, //bit 21 = End of Transferring interrupt : Punch Through List
|
||||
|
||||
|
@ -188,8 +188,8 @@ enum HollyInterruptID
|
|||
//bit 23 = G2 : AICA-DMA Time out
|
||||
//bit 24 = G2 : Ext-DMA1 Time out
|
||||
//bit 25 = G2 : Ext-DMA2 Time out
|
||||
//bit 26 = G2 : Dev-DMA Time out
|
||||
//bit 27 = G2 : Time out in CPU accessing
|
||||
//bit 26 = G2 : Dev-DMA Time out
|
||||
//bit 27 = G2 : Time out in CPU accessing
|
||||
};
|
||||
|
||||
|
||||
|
@ -200,7 +200,7 @@ struct vram_block
|
|||
u32 end;
|
||||
u32 len;
|
||||
u32 type;
|
||||
|
||||
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
|
@ -229,7 +229,7 @@ struct NDC_WINDOW_RECT
|
|||
//******************************************************
|
||||
//*********************** PowerVR **********************
|
||||
//******************************************************
|
||||
|
||||
|
||||
void libCore_vramlock_Unlock_block (vram_block* block);
|
||||
void libCore_vramlock_Unlock_block_wb (vram_block* block);
|
||||
vram_block* libCore_vramlock_Lock(u32 start_offset,u32 end_offset,void* userdata);
|
||||
|
@ -246,7 +246,7 @@ enum DiscType
|
|||
CdRom_XA=0x20,
|
||||
CdRom_Extra=0x30,
|
||||
CdRom_CDI=0x40,
|
||||
GdRom=0x80,
|
||||
GdRom=0x80,
|
||||
|
||||
NoDisk=0x1, //These are a bit hacky .. but work for now ...
|
||||
Open=0x2, //tray is open :)
|
||||
|
@ -576,7 +576,7 @@ enum RegIO
|
|||
RIO_RO = REG_RO | REG_WF,
|
||||
RIO_RO_FUNC = REG_RO | REG_RF | REG_WF,
|
||||
RIO_CONST = REG_RO | REG_WF,
|
||||
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
|
||||
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
|
||||
RIO_NO_ACCESS = REG_WF | REG_RF | REG_NO_ACCESS
|
||||
};
|
||||
|
||||
|
@ -601,6 +601,11 @@ struct RegisterStruct
|
|||
u32 flags; //Access flags !
|
||||
};
|
||||
|
||||
enum SmcCheckEnum {
|
||||
FullCheck = 0,
|
||||
FastCheck = 1,
|
||||
NoCheck = 2
|
||||
};
|
||||
|
||||
struct settings_t
|
||||
{
|
||||
|
@ -627,7 +632,11 @@ struct settings_t
|
|||
f32 ExtraDepthScale;
|
||||
bool CustomTextures;
|
||||
bool DumpTextures;
|
||||
int ScreenScaling; // in percent. 50 means half the native resolution
|
||||
int ScreenScaling; // in percent. 50 means half the native resolution
|
||||
int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3
|
||||
bool Fog;
|
||||
bool FloatVMUs;
|
||||
bool Rotate90; // Rotate the screen 90 deg CC
|
||||
} rend;
|
||||
|
||||
struct
|
||||
|
@ -637,8 +646,9 @@ struct settings_t
|
|||
bool unstable_opt;
|
||||
bool safemode;
|
||||
bool disable_nvmem;
|
||||
SmcCheckEnum SmcCheckLevel;
|
||||
} dynarec;
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
u32 run_counts;
|
||||
|
@ -647,7 +657,6 @@ struct settings_t
|
|||
struct
|
||||
{
|
||||
u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV
|
||||
u32 RTC;
|
||||
u32 region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default
|
||||
u32 broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default
|
||||
u32 language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default
|
||||
|
@ -670,6 +679,9 @@ struct settings_t
|
|||
bool NoSound;
|
||||
} aica;
|
||||
|
||||
struct{
|
||||
std::string backend;
|
||||
} audio;
|
||||
#if USE_OMX
|
||||
struct
|
||||
{
|
||||
|
@ -699,7 +711,7 @@ struct settings_t
|
|||
{
|
||||
u32 ta_skip;
|
||||
u32 rend;
|
||||
|
||||
|
||||
u32 MaxThreads;
|
||||
bool SynchronousRender;
|
||||
} pvr;
|
||||
|
@ -742,7 +754,7 @@ static inline void do_nada(...) { }
|
|||
#ifdef _ANDROID
|
||||
#include <android/log.h>
|
||||
|
||||
#ifdef printf
|
||||
#ifdef printf
|
||||
#undef printf
|
||||
#endif
|
||||
|
||||
|
@ -849,7 +861,7 @@ void libARM_Update(u32 cycles);
|
|||
else if (sz==2) \
|
||||
return *(u16*)&arr[addr]; \
|
||||
else if (sz==4) \
|
||||
return *(u32*)&arr[addr];}
|
||||
return *(u32*)&arr[addr];}
|
||||
|
||||
#define WriteMemArr(arr,addr,data,sz) \
|
||||
{if(sz==1) \
|
||||
|
@ -857,7 +869,7 @@ void libARM_Update(u32 cycles);
|
|||
else if (sz==2) \
|
||||
{*(u16*)&arr[addr]=(u16)data;} \
|
||||
else if (sz==4) \
|
||||
{*(u32*)&arr[addr]=data;}}
|
||||
{*(u32*)&arr[addr]=data;}}
|
||||
|
||||
#define WriteMemArrRet(arr,addr,data,sz) \
|
||||
{if(sz==1) \
|
||||
|
@ -865,7 +877,7 @@ void libARM_Update(u32 cycles);
|
|||
else if (sz==2) \
|
||||
{*(u16*)&arr[addr]=(u16)data;return;} \
|
||||
else if (sz==4) \
|
||||
{*(u32*)&arr[addr]=data;return;}}
|
||||
{*(u32*)&arr[addr]=data;return;}}
|
||||
|
||||
struct OnLoad
|
||||
{
|
||||
|
|
|
@ -188,8 +188,6 @@ u16 kcode[4] = { 0xffff, 0xffff, 0xffff, 0xffff };
|
|||
u32 vks[4];
|
||||
s8 joyx[4],joyy[4];
|
||||
u8 rt[4],lt[4];
|
||||
extern bool coin_chute;
|
||||
extern bool naomi_test_button;
|
||||
// Mouse
|
||||
extern s32 mo_x_abs;
|
||||
extern s32 mo_y_abs;
|
||||
|
@ -220,12 +218,6 @@ void UpdateInputState(u32 port)
|
|||
std::shared_ptr<XInputGamepadDevice> gamepad = XInputGamepadDevice::GetXInputDevice(port);
|
||||
if (gamepad != NULL)
|
||||
gamepad->ReadInput();
|
||||
|
||||
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
|
||||
// FIXME
|
||||
coin_chute = GetAsyncKeyState(VK_F8);
|
||||
naomi_test_button = GetAsyncKeyState(VK_F7);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Windows class name to register
|
||||
|
@ -772,6 +764,7 @@ cThread::cThread(ThreadEntryFP* function,void* prm)
|
|||
|
||||
void cThread::Start()
|
||||
{
|
||||
verify(hThread == NULL);
|
||||
hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Entry,param,0,NULL);
|
||||
ResumeThread(hThread);
|
||||
}
|
||||
|
@ -779,6 +772,8 @@ void cThread::Start()
|
|||
void cThread::WaitToEnd()
|
||||
{
|
||||
WaitForSingleObject(hThread,INFINITE);
|
||||
CloseHandle(hThread);
|
||||
hThread = NULL;
|
||||
}
|
||||
//End thread class
|
||||
|
||||
|
|
|
@ -52,5 +52,56 @@
|
|||
android:scheme="file" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity-alias
|
||||
android:name="com.reicast.emulator.MainActivity"
|
||||
android:targetActivity="com.reicast.emulator.NativeGLActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.GDI"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.gdi"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.CHD"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.chd"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.CDI"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.cdi"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.CUE"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.cue"
|
||||
android:scheme="file" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
</application>
|
||||
</manifest>
|
|
@ -61,6 +61,16 @@
|
|||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity-alias
|
||||
android:name="com.reicast.emulator.MainActivity"
|
||||
android:targetActivity="com.reicast.emulator.NativeGLActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="tv.ouya.intent.category.GAME" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
|
|
|
@ -228,22 +228,24 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
|
|||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (!JNIdc.guiIsOpen()) {
|
||||
showMenu();
|
||||
return true;
|
||||
if (event.getRepeatCount() == 0) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (!JNIdc.guiIsOpen()) {
|
||||
showMenu();
|
||||
return true;
|
||||
}
|
||||
else if (JNIdc.guiIsContentBrowser()) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (JNIdc.guiIsContentBrowser()) {
|
||||
finish();
|
||||
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
|
||||
return true;
|
||||
|
||||
if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
return showMenu();
|
||||
if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
return showMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
|
@ -296,7 +298,7 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
|
|||
}
|
||||
|
||||
// Called from native code
|
||||
private void generateErrorLog() {
|
||||
protected void generateErrorLog() {
|
||||
try {
|
||||
new GenerateLogs(this).execute(getFilesDir().getAbsolutePath());
|
||||
} catch (RuntimeException e) {
|
||||
|
|
|
@ -21,8 +21,7 @@ public final class JNIdc
|
|||
public static native int send(int cmd, int opt);
|
||||
public static native int data(int cmd, byte[] data);
|
||||
|
||||
public static native void rendinitNative(Surface surface, int w, int h);
|
||||
public static native boolean rendframeNative();
|
||||
public static native void rendinitNative(Surface surface);
|
||||
public static native void rendinitJava(int w, int h);
|
||||
public static native boolean rendframeJava();
|
||||
public static native void rendtermJava();
|
||||
|
|
|
@ -19,8 +19,6 @@ import com.reicast.emulator.NativeGLActivity;
|
|||
import com.reicast.emulator.config.Config;
|
||||
|
||||
public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback {
|
||||
private Handler handler = new Handler();
|
||||
|
||||
private boolean surfaceReady = false;
|
||||
private boolean paused = false;
|
||||
VirtualJoystickDelegate vjoyDelegate;
|
||||
|
@ -66,23 +64,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
|
|||
|
||||
if (NativeGLActivity.syms != null)
|
||||
JNIdc.data(1, NativeGLActivity.syms);
|
||||
|
||||
startRendering();
|
||||
}
|
||||
|
||||
private void startRendering() {
|
||||
// Continuously render frames
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
handler.postAtTime(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!paused)
|
||||
{
|
||||
JNIdc.rendframeNative();
|
||||
handler.post(this);
|
||||
}
|
||||
}
|
||||
}, SystemClock.uptimeMillis() + 500);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +92,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
|
|||
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
|
||||
//Log.i("reicast", "NativeGLView.surfaceChanged: " + w + "x" + h);
|
||||
surfaceReady = true;
|
||||
JNIdc.rendinitNative(surfaceHolder.getSurface(), w, h);
|
||||
JNIdc.rendinitNative(surfaceHolder.getSurface());
|
||||
Emulator.getCurrentActivity().handleStateChange(false);
|
||||
}
|
||||
|
||||
|
@ -119,7 +100,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
|
|||
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
|
||||
//Log.i("reicast", "NativeGLView.surfaceDestroyed");
|
||||
surfaceReady = false;
|
||||
JNIdc.rendinitNative(null, 0, 0);
|
||||
JNIdc.rendinitNative(null);
|
||||
Emulator.getCurrentActivity().handleStateChange(true);
|
||||
}
|
||||
|
||||
|
@ -142,7 +123,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
|
|||
requestFocus();
|
||||
JNIdc.resume();
|
||||
}
|
||||
startRendering();
|
||||
}
|
||||
|
||||
@TargetApi(19)
|
||||
|
|
|
@ -15,7 +15,7 @@ import com.reicast.emulator.periph.InputDeviceManager;
|
|||
import com.reicast.emulator.periph.VJoy;
|
||||
|
||||
public class VirtualJoystickDelegate {
|
||||
private Vibrator vib;
|
||||
private VibratorThread vibratorThread;
|
||||
|
||||
private boolean editVjoyMode = false;
|
||||
private int selectedVjoyElement = -1;
|
||||
|
@ -39,7 +39,10 @@ public class VirtualJoystickDelegate {
|
|||
public VirtualJoystickDelegate(View view) {
|
||||
this.view = view;
|
||||
this.context = view.getContext();
|
||||
vib = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
|
||||
vibratorThread = new VibratorThread(context);
|
||||
vibratorThread.start();
|
||||
|
||||
readCustomVjoyValues();
|
||||
scaleGestureDetector = new ScaleGestureDetector(context, new OscOnScaleGestureListener());
|
||||
}
|
||||
|
@ -224,8 +227,9 @@ public class VirtualJoystickDelegate {
|
|||
if (y > vjoy[j][1] && y <= (vjoy[j][1] + vjoy[j][3])) {
|
||||
if (vjoy[j][4] >= -2) {
|
||||
if (vjoy[j][5] == 0)
|
||||
if (!editVjoyMode && Emulator.vibrationDuration > 0)
|
||||
vib.vibrate(Emulator.vibrationDuration);
|
||||
if (!editVjoyMode) {
|
||||
vibratorThread.vibrate();
|
||||
}
|
||||
vjoy[j][5] = 2;
|
||||
}
|
||||
|
||||
|
@ -397,4 +401,51 @@ public class VirtualJoystickDelegate {
|
|||
selectedVjoyElement = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class VibratorThread extends Thread
|
||||
{
|
||||
private Vibrator vibrator;
|
||||
private boolean vibrate = false;
|
||||
private boolean stopping = false;
|
||||
|
||||
VibratorThread(Context context) {
|
||||
vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stopping) {
|
||||
boolean doVibrate;
|
||||
synchronized (this) {
|
||||
doVibrate = false;
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
if (vibrate) {
|
||||
doVibrate = true;
|
||||
vibrate = false;
|
||||
}
|
||||
}
|
||||
if (doVibrate)
|
||||
vibrator.vibrate(Emulator.vibrationDuration);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopVibrator() {
|
||||
synchronized (this) {
|
||||
stopping = true;
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void vibrate() {
|
||||
if (Emulator.vibrationDuration > 0) {
|
||||
synchronized (this) {
|
||||
vibrate = true;
|
||||
notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "hw/maple/maple_devs.h"
|
||||
#include "hw/maple/maple_if.h"
|
||||
#include "hw/naomi/naomi_cart.h"
|
||||
#include "oslib/audiobackend_android.h"
|
||||
#include "oslib/audiostream.h"
|
||||
#include "imgread/common.h"
|
||||
#include "rend/gui.h"
|
||||
#include "cfg/cfg.h"
|
||||
|
@ -91,8 +91,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,j
|
|||
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobject obj,jint id, jint v) __attribute__((visibility("default")));
|
||||
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env,jobject obj,jint id, jbyteArray d) __attribute__((visibility("default")));
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface, jint w, jint h) __attribute__((visibility("default")));
|
||||
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface) __attribute__((visibility("default")));
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv *env, jobject obj, jint w, jint h) __attribute__((visibility("default")));
|
||||
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendtermJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
|
||||
|
@ -404,35 +403,57 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env, job
|
|||
|
||||
extern void gl_swap();
|
||||
extern void egl_stealcntx();
|
||||
volatile static bool render_running;
|
||||
volatile static bool render_reinit;
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj)
|
||||
void *render_thread_func(void *)
|
||||
{
|
||||
if (g_window == NULL)
|
||||
return false;
|
||||
if (!egl_makecurrent())
|
||||
return false;
|
||||
jboolean ret = (jboolean)rend_single_frame();
|
||||
if (ret)
|
||||
gl_swap();
|
||||
return ret;
|
||||
render_running = true;
|
||||
|
||||
rend_init_renderer();
|
||||
|
||||
while (render_running) {
|
||||
if (render_reinit)
|
||||
{
|
||||
render_reinit = false;
|
||||
rend_init_renderer();
|
||||
}
|
||||
else
|
||||
if (!egl_makecurrent())
|
||||
break;;
|
||||
|
||||
bool ret = rend_single_frame();
|
||||
if (ret)
|
||||
gl_swap();
|
||||
}
|
||||
egl_makecurrent();
|
||||
rend_term_renderer();
|
||||
ANativeWindow_release(g_window);
|
||||
g_window = NULL;
|
||||
render_running = false;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height)
|
||||
static cThread render_thread(render_thread_func, NULL);
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface)
|
||||
{
|
||||
if (g_window != NULL)
|
||||
{
|
||||
egl_makecurrent();
|
||||
rend_term_renderer();
|
||||
ANativeWindow_release(g_window);
|
||||
g_window = NULL;
|
||||
}
|
||||
if (surface != NULL)
|
||||
{
|
||||
if (render_thread.hThread != NULL)
|
||||
{
|
||||
if (surface == NULL)
|
||||
{
|
||||
render_running = false;
|
||||
render_thread.WaitToEnd();
|
||||
}
|
||||
else
|
||||
render_reinit = true;
|
||||
}
|
||||
else if (surface != NULL)
|
||||
{
|
||||
g_window = ANativeWindow_fromSurface(env, surface);
|
||||
rend_init_renderer();
|
||||
screen_width = width;
|
||||
screen_height = height;
|
||||
}
|
||||
render_thread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv * env, jobject obj, jint width, jint height)
|
||||
|
@ -529,6 +550,9 @@ audiobackend_t audiobackend_android = {
|
|||
&androidaudio_term
|
||||
};
|
||||
|
||||
static bool android = RegisterAudioBackend(&audiobackend_android);
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance)
|
||||
{
|
||||
if (g_audioBackend != NULL)
|
||||
|
@ -568,7 +592,7 @@ void os_DebugBreak()
|
|||
|
||||
raise(SIGABRT);
|
||||
//pthread_exit(NULL);
|
||||
|
||||
|
||||
// Attach debugger here to figure out what went wrong
|
||||
for(;;) ;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
android:name="com.reicast.emulator.Emulator">
|
||||
|
||||
<activity
|
||||
android:name="com.reicast.emulator.MainActivity">
|
||||
android:name="com.reicast.emulator.NativeGLActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
|
@ -62,5 +62,66 @@
|
|||
android:scheme="file" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity-alias
|
||||
android:name="com.reicast.emulator.MainActivity"
|
||||
android:targetActivity="com.reicast.emulator.NativeGLActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.LST"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.lst"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.BIN"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.bin"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.DAT"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.dat"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.ZIP"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.zip"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.7Z"
|
||||
android:scheme="file" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.7z"
|
||||
android:scheme="file" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
Loading…
Reference in New Issue