Merge branch 'master' into fh/win32-winresize

This commit is contained in:
David Miller 2019-04-12 13:03:30 -04:00 committed by GitHub
commit 3d1b82854e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1618 additions and 989 deletions

View File

@ -1,4 +1,5 @@
#include "aica.h" #include "aica.h"
#include "aica_if.h"
#include "sgc_if.h" #include "sgc_if.h"
#include "aica_mem.h" #include "aica_mem.h"
#include <math.h> #include <math.h>
@ -180,6 +181,7 @@ template void WriteAicaReg<2>(u32 reg,u32 data);
s32 libAICA_Init() s32 libAICA_Init()
{ {
init_mem(); init_mem();
aica_Init();
verify(sizeof(*CommonData)==0x508); verify(sizeof(*CommonData)==0x508);
verify(sizeof(*DSPData)==0x15C8); verify(sizeof(*DSPData)==0x15C8);
@ -203,9 +205,12 @@ s32 libAICA_Init()
return rv_ok; return rv_ok;
} }
void libAICA_Reset(bool m) void libAICA_Reset(bool manual)
{ {
if (!manual)
init_mem();
sgc_Init(); sgc_Init();
aica_Reset(manual);
} }
void libAICA_Term() void libAICA_Term()

View File

@ -18,6 +18,7 @@ u32 VREG;//video reg =P
u32 ARMRST;//arm reset reg u32 ARMRST;//arm reset reg
u32 rtc_EN=0; u32 rtc_EN=0;
int dma_sched_id; int dma_sched_id;
u32 RealTimeClock;
u32 GetRTC_now() u32 GetRTC_now()
{ {
@ -39,9 +40,9 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz)
switch( addr & 0xFF ) switch( addr & 0xFF )
{ {
case 0: case 0:
return settings.dreamcast.RTC>>16; return RealTimeClock>>16;
case 4: case 4:
return settings.dreamcast.RTC &0xFFFF; return RealTimeClock &0xFFFF;
case 8: case 8:
return 0; return 0;
} }
@ -57,16 +58,16 @@ void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz)
case 0: case 0:
if (rtc_EN) if (rtc_EN)
{ {
settings.dreamcast.RTC&=0xFFFF; RealTimeClock&=0xFFFF;
settings.dreamcast.RTC|=(data&0xFFFF)<<16; RealTimeClock|=(data&0xFFFF)<<16;
rtc_EN=0; rtc_EN=0;
} }
return; return;
case 4: case 4:
if (rtc_EN) if (rtc_EN)
{ {
settings.dreamcast.RTC&=0xFFFF0000; RealTimeClock&=0xFFFF0000;
settings.dreamcast.RTC|= data&0xFFFF; RealTimeClock|= data&0xFFFF;
//TODO: Clean the internal timer ? //TODO: Clean the internal timer ?
} }
return; return;
@ -153,15 +154,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
//Init/res/term //Init/res/term
void aica_Init() void aica_Init()
{ {
//mmnnn ? gotta fill it w/ something RealTimeClock = GetRTC_now();
} }
void aica_Reset(bool Manual) void aica_Reset(bool Manual)
{ {
if (!Manual) aica_Init();
{
aica_ram.Zero();
}
} }
void aica_Term() void aica_Term()

View File

@ -3,6 +3,7 @@
extern u32 VREG; extern u32 VREG;
extern VArray2 aica_ram; extern VArray2 aica_ram;
extern u32 RealTimeClock;
u32 ReadMem_aica_rtc(u32 addr,u32 sz); u32 ReadMem_aica_rtc(u32 addr,u32 sz);
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz); void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);
u32 ReadMem_aica_reg(u32 addr,u32 sz); u32 ReadMem_aica_reg(u32 addr,u32 sz);
@ -17,4 +18,4 @@ void aica_Term();
void aica_sb_Init(); void aica_sb_Init();
void aica_sb_Reset(bool Manual); void aica_sb_Reset(bool Manual);
void aica_sb_Term(); void aica_sb_Term();

View File

@ -4,6 +4,7 @@
#include "maple_devs.h" #include "maple_devs.h"
#include "maple_cfg.h" #include "maple_cfg.h"
#include "cfg/cfg.h" #include "cfg/cfg.h"
#include "hw/naomi/naomi_cart.h"
#define HAS_VMU #define HAS_VMU
/* /*
@ -28,13 +29,31 @@ extern u16 kcode[4];
extern u32 vks[4]; extern u32 vks[4];
extern s8 joyx[4],joyy[4]; extern s8 joyx[4],joyy[4];
extern u8 rt[4],lt[4]; extern u8 rt[4],lt[4];
extern bool naomi_test_button;
u8 GetBtFromSgn(s8 val) u8 GetBtFromSgn(s8 val)
{ {
return val+128; 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 struct MapleConfigMap : IMapleConfigMap
{ {
maple_device* dev; maple_device* dev;
@ -59,17 +78,32 @@ struct MapleConfigMap : IMapleConfigMap
pjs->kcode=kcode[player_num]; pjs->kcode=kcode[player_num];
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST #if DC_PLATFORM == DC_PLATFORM_DREAMCAST
pjs->kcode |= 0xF901; pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
#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->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]); pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]); pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
pjs->trigger[PJTI_R]=rt[player_num]; pjs->trigger[PJTI_R]=rt[player_num];
pjs->trigger[PJTI_L]=lt[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) 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) void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1)
{ {
if (MapleDevices[bus][port] != NULL) 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, ... // Then other devices on port 2 and 3 for analog axes, light guns, ...
mcfg_Create(MDT_SegaController, 0, 5); mcfg_Create(MDT_SegaController, 0, 5);
mcfg_Create(MDT_SegaController, 1, 5); mcfg_Create(MDT_SegaController, 1, 5);
// mcfg_Create(MDT_SegaController, 2, 5, 0); if (NaomiGameInputs != NULL && NaomiGameInputs->axes[0].name != NULL)
// mcfg_Create(MDT_SegaController, 3, 5, 1); {
// mcfg_Create(MDT_LightGun, 2, 5, 0); // Game needs analog axes
// mcfg_Create(MDT_LightGun, 3, 5, 1); mcfg_Create(MDT_SegaController, 2, 5, 0);
// mcfg_Create(MDT_Mouse, 2, 5, 0); mcfg_Create(MDT_SegaController, 3, 5, 1);
// 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)
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes) // Maximum Speed same
// Maximum Speed same }
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3 else if (settings.input.JammaSetup == 1)
// Sports Shooting same {
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3 // 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() void mcfg_CreateDevices()

View File

@ -68,3 +68,5 @@ void mcfg_CreateAtomisWaveControllers();
void mcfg_DestroyDevices(); void mcfg_DestroyDevices();
void mcfg_SerializeDevices(void **data, unsigned int *total_size); void mcfg_SerializeDevices(void **data, unsigned int *total_size);
void mcfg_UnserializeDevices(void **data, unsigned int *total_size); void mcfg_UnserializeDevices(void **data, unsigned int *total_size);
bool maple_atomiswave_coin_chute(int slot);

View File

@ -7,6 +7,7 @@
#include "hw/naomi/naomi.h" #include "hw/naomi/naomi.h"
#include "hw/naomi/naomi_cart.h" #include "hw/naomi/naomi_cart.h"
#include "hw/pvr/spg.h" #include "hw/pvr/spg.h"
#include "input/gamepad.h"
#include <time.h> #include <time.h>
#include "deps/zlib/zlib.h" #include "deps/zlib/zlib.h"
@ -198,6 +199,35 @@ struct maple_base: maple_device
*/ */
struct maple_sega_controller: maple_base 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() virtual MapleDeviceType get_device_type()
{ {
return MDT_SegaController; return MDT_SegaController;
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
//struct data //struct data
//3*4 //3*4
w32( 0xfe060f00); w32(get_capabilities());
w32( 0); w32(0);
w32( 0); w32(0);
//1 area code //1 area code
w8(0xFF); w8(0xFF);
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
//state data //state data
//2 key code //2 key code
w16(pjs.kcode); w16(transform_kcode(pjs.kcode));
//triggers //triggers
//1 R //1 R
w8(pjs.trigger[PJTI_R]); w8(get_analog_axis(0, pjs));
//1 L //1 L
w8(pjs.trigger[PJTI_L]); w8(get_analog_axis(1, pjs));
//joyx //joyx
//1 //1
w8(pjs.joy[PJAI_X1]); w8(get_analog_axis(2, pjs));
//joyy //joyy
//1 //1
w8(pjs.joy[PJAI_Y1]); w8(get_analog_axis(3, pjs));
//not used //not used
//1 //1
w8(0x80); w8(get_analog_axis(4, pjs));
//1 //1
w8(0x80); w8(get_analog_axis(5, pjs));
} }
return MDRS_DataTransfer; 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 Sega Dreamcast Visual Memory Unit
This is pretty much done (?) This is pretty much done (?)
@ -1267,6 +1329,10 @@ struct maple_mouse : maple_base
struct maple_lightgun : maple_base struct maple_lightgun : maple_base
{ {
virtual u32 transform_kcode(u32 kcode) {
return kcode | 0xFF01;
}
virtual MapleDeviceType get_device_type() virtual MapleDeviceType get_device_type()
{ {
return MDT_LightGun; return MDT_LightGun;
@ -1315,21 +1381,13 @@ struct maple_lightgun : maple_base
PlainJoystickState pjs; PlainJoystickState pjs;
config->GetInput(&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 //caps
//4 //4
w32(MFID_0_Input); w32(MFID_0_Input);
//state data //state data
//2 key code //2 key code
w16(pjs.kcode | 0xFF01); w16(transform_kcode(pjs.kcode));
//not used //not used
//2 //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 u16 kcode[4];
extern s8 joyx[4],joyy[4]; extern s8 joyx[4],joyy[4];
extern u8 rt[4], lt[4]; extern u8 rt[4], lt[4];
@ -1381,20 +1446,29 @@ static u16 getRightTriggerAxis()
return rt[0] << 8; return rt[0] << 8;
} }
NaomiInputMapping Naomi_Mapping = { u32 naomi_button_mapping[] = {
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis }, NAOMI_SERVICE_KEY, // DC_BTN_C
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 }, NAOMI_BTN1_KEY, // DC_BTN_B
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 }, NAOMI_BTN0_KEY, // DC_BTN_A
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3 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 * Sega JVS I/O board
*/ */
bool coin_chute; static bool old_coin_chute[4];
static bool old_coin_chute; static int coin_count[4];
static int coin_count;
bool naomi_test_button = false;
struct maple_naomi_jamma; 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 JVS_STATUS1(); // report byte
LOGJVS("btns "); u16 buttons[4] = { 0 };
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
// 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++)
{ {
u8 *cur_btns = &buttons[(first_player + player) * 2]; u32 keycode = ~kcode[first_player + player];
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]); for (int i = 0; i < 16; i++)
JVS_OUT(cur_btns[0]);
if (buffer_in[cmdi + 2] == 2)
{ {
LOGJVS("%02x ", cur_btns[1]); if ((keycode & (1 << i)) != 0)
JVS_OUT(cur_btns[1]); 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; cmdi += 3;
} }
break; break;
case 0x21: // Read coins case 0x21: // Read coins
{ {
if (coin_chute && !old_coin_chute)
coin_count++;
old_coin_chute = coin_chute;
JVS_STATUS1(); // report byte JVS_STATUS1(); // report byte
LOGJVS("coins "); LOGJVS("coins ");
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++) 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); if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
JVS_OUT((coin_count >> 8) & 0x3F); // status (2 highest bits, 0: normal), coin count MSB coin_chute = true;
JVS_OUT(coin_count); // coin count LSB
}
else
{
LOGJVS("%d:0 ", slot);
JVS_OUT(0);
JVS_OUT(0);
} }
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; 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); LOGJVS("x,y:%4x,%4x ", x, y);
JVS_OUT(x >> 8); // X, MSB 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 >> 8); // Y, MSB
JVS_OUT(y); // Y, LSB JVS_OUT(y); // Y, LSB
axis = 2; axis = 2;
} }
int full_axis_count = 0;
int half_axis_count = 0;
for (; axis < buffer_in[cmdi + 1]; axis++) for (; axis < buffer_in[cmdi + 1]; axis++)
{ {
// FIXME Need to know how many axes per player for proper mapping
u16 axis_value; u16 axis_value;
if (axis + first_player * 4 < 8 && Naomi_Mapping.axis[axis + first_player * 4] != NULL) if (NaomiGameInputs != NULL
axis_value = Naomi_Mapping.axis[axis + first_player * 4](); && 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 else
{ {
switch (axis) { switch (full_axis_count) {
case 0: case 0:
axis_value = (joyx[first_player + axis / 4] + 128) << 8; axis_value = (joyx[first_player] + 128) << 8;
break; break;
case 1: case 1:
axis_value = (joyy[first_player + axis / 4] + 128) << 8; axis_value = (joyy[first_player] + 128) << 8;
break;
case 2:
axis_value = rt[first_player + axis / 4] << 8;
break;
case 3:
axis_value = lt[first_player + axis / 4] << 8;
break; 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); LOGJVS("%d:%4x ", axis, axis_value);
JVS_OUT(axis_value >> 8); 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; break;
case 0x30: // substract coin case 0x30: // substract coin
if (buffer_in[cmdi + 1] == 1) if (buffer_in[cmdi + 1] > 0 && first_player + buffer_in[cmdi + 1] - 1 < ARRAY_SIZE(coin_count))
coin_count -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3]; coin_count[first_player + buffer_in[cmdi + 1] - 1] -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
JVS_STATUS1(); // report byte JVS_STATUS1(); // report byte
cmdi += 4; cmdi += 4;
break; break;
@ -2542,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type)
switch(type) switch(type)
{ {
case MDT_SegaController: 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; break;
case MDT_Microphone: case MDT_Microphone:
@ -2566,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
break; break;
case MDT_LightGun: case MDT_LightGun:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_lightgun(); rv = new maple_lightgun();
#else
rv = new atomiswave_lightgun();
#endif
break; break;
case MDT_NaomiJamma: case MDT_NaomiJamma:

View File

@ -6,6 +6,7 @@
#include "hw/holly/sb.h" #include "hw/holly/sb.h"
#include "hw/sh4/sh4_mem.h" #include "hw/sh4/sh4_mem.h"
#include "hw/holly/holly_intc.h" #include "hw/holly/holly_intc.h"
#include "hw/maple/maple_cfg.h"
#include "naomi.h" #include "naomi.h"
#include "naomi_cart.h" #include "naomi_cart.h"
@ -634,7 +635,6 @@ void Update_naomi()
} }
static u8 aw_maple_devs; static u8 aw_maple_devs;
extern bool coin_chute;
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) { u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
addr &= 0x7ff; addr &= 0x7ff;
@ -653,12 +653,13 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
aw_ram_test_skipped = true; aw_ram_test_skipped = true;
return 0; return 0;
} }
if (coin_chute)
{ {
// FIXME Coin Error if coin_chute is set for too long u8 coin_input = 0xF;
return 0xE; 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 case 0x284: // Atomiswave maple devices
// ddcc0000 where cc/dd are the types of devices on maple bus 2 and 3: // ddcc0000 where cc/dd are the types of devices on maple bus 2 and 3:

View File

@ -32,7 +32,7 @@ fd_t* RomCacheMap = NULL;
u32 RomCacheMapCount; u32 RomCacheMapCount;
char naomi_game_id[33]; char naomi_game_id[33];
InputDescriptors *naomi_game_inputs; InputDescriptors *NaomiGameInputs;
u8 *naomi_default_eeprom; u8 *naomi_default_eeprom;
extern RomChip sys_rom; extern RomChip sys_rom;
@ -246,7 +246,7 @@ static bool naomi_cart_LoadZip(char *filename)
break; break;
} }
CurrentCartridge->SetKey(game->key); CurrentCartridge->SetKey(game->key);
naomi_game_inputs = game->inputs; NaomiGameInputs = game->inputs;
for (int romid = 0; game->blobs[romid].filename != NULL; romid++) for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
{ {

View File

@ -110,6 +110,6 @@ struct InputDescriptors
AxisDescriptor axes[8]; AxisDescriptor axes[8];
}; };
extern InputDescriptors *naomi_game_inputs; extern InputDescriptors *NaomiGameInputs;
#endif //NAOMI_CART_H #endif //NAOMI_CART_H

View File

@ -304,6 +304,8 @@ void bm_Rebuild()
{ {
return; return;
die("this is broken in multiple levels, including compile options");
void RASDASD(); void RASDASD();
RASDASD(); RASDASD();
@ -321,7 +323,7 @@ void bm_Rebuild()
//constprop(all_blocks[i]); //constprop(all_blocks[i]);
//#endif //#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]); blkmap.insert(all_blocks[i]);
verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]); verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]);

View File

@ -86,6 +86,15 @@ void recSh4_Run()
sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx); 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); 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); verify(rcb_noffs(&next_pc)==-184);
ngen_mainloop(sh4_dyna_rcb); 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 (settings.dynarec.SmcCheckLevel) {
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
//Shenmue 2 // Heuristic-elimintaed FastChecks
case 0x348000: case NoCheck: {
if (IsOnRam(pc))
//Shenmue {
case 0x41860e: pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
return true; //Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
default: return FastCheck;
return false;
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); void AnalyseBlock(RuntimeBlockInfo* blk);

View File

@ -85,7 +85,7 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc);
void ngen_init(); void ngen_init();
//Called to compile a block //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 //Called when blocks are reseted
void ngen_ResetBlocks(); void ngen_ResetBlocks();

View File

@ -232,7 +232,7 @@ int AicaUpdate(int tag, int c, int j)
int DreamcastSecond(int tag, int c, int j) int DreamcastSecond(int tag, int c, int j)
{ {
settings.dreamcast.RTC++; RealTimeClock++;
#if 1 //HOST_OS==OS_WINDOWS #if 1 //HOST_OS==OS_WINDOWS
prof_periodical(); prof_periodical();

View File

@ -12,6 +12,8 @@
//Types //Types
#define printf_smc(...) // printf
u32 CCN_QACR_TR[2]; u32 CCN_QACR_TR[2];
@ -72,13 +74,18 @@ void CCN_CCR_write(u32 addr, u32 value)
temp.reg_data=value; temp.reg_data=value;
//what is 0xAC13DBF8 from ? if (temp.ICI) {
if (temp.ICI && curr_pc!=0xAC13DBF8) printf_smc("Sh4: i-cache invalidation %08X\n",curr_pc);
{
//printf("Sh4: i-cache invalidation %08X\n",curr_pc); if (settings.dynarec.SmcCheckLevel != FullCheck) {
// Shikigami No Shiro II sets ICI frequently //TODO: Add skip/check vectors for Shikigami No Shiro II (uses ICI frequently)
// Any reason to flush the dynarec cache for this? //which game is 0xAC13DBF8 from ?
//sh4_cpu.ResetCache(); if (curr_pc != 0xAC13DBF8)
{
printf("Sh4: code cache clear (ICI) pc: %08X\n",curr_pc);
sh4_cpu.ResetCache();
}
}
} }
temp.ICI=0; temp.ICI=0;

View File

@ -51,7 +51,39 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
if (key < 0x10000) if (key < 0x10000)
{ {
if (pressed) if (pressed)
{
kcode[_maple_port] &= ~(u16)key; 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 else
kcode[_maple_port] |= (u16)key; kcode[_maple_port] |= (u16)key;
} }

View File

@ -84,8 +84,6 @@ Atom wmDeleteMessage;
void* x11_vis; void* x11_vis;
extern bool dump_frame_switch; extern bool dump_frame_switch;
extern bool naomi_test_button;
extern bool coin_chute;
void dc_exit(void); void dc_exit(void);
@ -275,16 +273,6 @@ void input_x11_handle()
x11_fullscreen = !x11_fullscreen; x11_fullscreen = !x11_fullscreen;
x11_window_set_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; break;

View File

@ -134,7 +134,7 @@ void LoadSpecialSettings()
safemode_game = false; safemode_game = false;
tr_poly_depth_mask_game = false; tr_poly_depth_mask_game = false;
extra_depth_game = false; extra_depth_game = false;
if (reios_windows_ce) if (reios_windows_ce)
{ {
printf("Enabling Extra depth scaling for Windows CE games\n"); 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 #elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
printf("Game ID is [%s]\n", naomi_game_id); printf("Game ID is [%s]\n", naomi_game_id);
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", 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); 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); printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
settings.input.JammaSetup = 2; 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); printf("Enabling 4-player setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 1; 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); printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 3; settings.input.JammaSetup = 3;
@ -228,9 +230,11 @@ void LoadSpecialSettings()
printf("Enabling specific JVS setup for game %s\n", naomi_game_id); printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 4; 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; settings.input.JammaSetup = 5;
} }
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id)) else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
@ -309,11 +313,12 @@ int dc_start_game(const char *path)
{ {
InitSettings(); InitSettings();
LoadSettings(false); LoadSettings(false);
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST #if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (!settings.bios.UseReios) if (!settings.bios.UseReios)
#endif #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 DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (path == NULL) if (path == NULL)
{ {
@ -345,7 +350,6 @@ int dc_start_game(const char *path)
return 0; 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))) if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
{ {
#ifdef USE_REIOS #ifdef USE_REIOS
@ -485,7 +489,6 @@ void dc_exit()
void InitSettings() void InitSettings()
{ {
settings.dreamcast.RTC = GetRTC_now();
settings.dynarec.Enable = true; settings.dynarec.Enable = true;
settings.dynarec.idleskip = true; settings.dynarec.idleskip = true;
settings.dynarec.unstable_opt = false; settings.dynarec.unstable_opt = false;
@ -495,9 +498,11 @@ void InitSettings()
settings.dreamcast.broadcast = 4; // default settings.dreamcast.broadcast = 4; // default
settings.dreamcast.language = 6; // default settings.dreamcast.language = 6; // default
settings.dreamcast.FullMMU = false; settings.dreamcast.FullMMU = false;
settings.dynarec.SmcCheckLevel = FullCheck;
settings.aica.LimitFPS = true; settings.aica.LimitFPS = true;
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
settings.aica.NoSound = false; settings.aica.NoSound = false;
settings.audio.backend = "auto";
settings.rend.UseMipmaps = true; settings.rend.UseMipmaps = true;
settings.rend.WideScreen = false; settings.rend.WideScreen = false;
settings.rend.ShowFPS = false; settings.rend.ShowFPS = false;
@ -512,6 +517,10 @@ void InitSettings()
settings.rend.CustomTextures = false; settings.rend.CustomTextures = false;
settings.rend.DumpTextures = false; settings.rend.DumpTextures = false;
settings.rend.ScreenScaling = 100; 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.ta_skip = 0;
settings.pvr.rend = 0; settings.pvr.rend = 0;
@ -558,11 +567,13 @@ void LoadSettings(bool game_specific)
{ {
const char *config_section = game_specific ? cfgGetGameId() : "config"; const char *config_section = game_specific ? cfgGetGameId() : "config";
const char *input_section = game_specific ? cfgGetGameId() : "input"; 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.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip); 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.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.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 //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.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable);
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region); 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.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch); settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound); 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.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen); settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS); 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.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling); settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100); 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.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend); 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); cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
if (!safemode_game || !settings.dynarec.safemode) if (!safemode_game || !settings.dynarec.safemode)
cfgSaveBool("config", "Dynarec.safe-mode", 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); cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS); cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch); cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch);
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound); 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.WideScreen", settings.rend.WideScreen);
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS); cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer) if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
@ -714,6 +733,10 @@ void SaveSettings()
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures); cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures); cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling); 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", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", settings.pvr.rend); cfgSaveInt("config", "pvr.rend", settings.pvr.rend);

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_alsa.h" #include "oslib/audiostream.h"
#if USE_ALSA #if USE_ALSA
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include "cfg/cfg.h" #include "cfg/cfg.h"
@ -175,11 +175,13 @@ static void alsa_term()
snd_pcm_close(handle); snd_pcm_close(handle);
} }
audiobackend_t audiobackend_alsa = { static audiobackend_t audiobackend_alsa = {
"alsa", // Slug "alsa", // Slug
"Advanced Linux Sound Architecture", // Name "Advanced Linux Sound Architecture", // Name
&alsa_init, &alsa_init,
&alsa_push, &alsa_push,
&alsa_term &alsa_term
}; };
static bool alsa = RegisterAudioBackend(&audiobackend_alsa);
#endif #endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_alsa;

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_android;

View File

@ -1,18 +1,18 @@
/* /*
Simple Core Audio backend for osx (and maybe ios?) Simple Core Audio backend for osx (and maybe ios?)
Based off various audio core samples and dolphin's code Based off various audio core samples and dolphin's code
This is part of the Reicast project, please consult the This is part of the Reicast project, please consult the
LICENSE file for licensing & related information LICENSE file for licensing & related information
This could do with some locking logic to avoid This could do with some locking logic to avoid
race conditions, and some variable length buffer race conditions, and some variable length buffer
logic to support chunk sizes other than 512 bytes logic to support chunk sizes other than 512 bytes
It does work on my macmini though It does work on my macmini though
*/ */
#include "oslib/audiobackend_coreaudio.h" #include "oslib/audiostream.h"
#if HOST_OS == OS_DARWIN #if HOST_OS == OS_DARWIN
#include <atomic> #include <atomic>
@ -49,9 +49,9 @@ static OSStatus coreaudio_callback(void* ctx, AudioUnitRenderActionFlags* flags,
samples_rptr = (samples_rptr + buf_size) % BUFSIZE; samples_rptr = (samples_rptr + buf_size) % BUFSIZE;
} }
} }
bufferEmpty.Set(); bufferEmpty.Set();
return noErr; return noErr;
} }
@ -63,7 +63,7 @@ static void coreaudio_init()
AudioStreamBasicDescription format; AudioStreamBasicDescription format;
AudioComponentDescription desc; AudioComponentDescription desc;
AudioComponent component; AudioComponent component;
desc.componentType = kAudioUnitType_Output; desc.componentType = kAudioUnitType_Output;
#if !defined(TARGET_IPHONE) #if !defined(TARGET_IPHONE)
desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentSubType = kAudioUnitSubType_DefaultOutput;
@ -75,12 +75,12 @@ static void coreaudio_init()
desc.componentFlagsMask = 0; desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentManufacturer = kAudioUnitManufacturer_Apple;
component = AudioComponentFindNext(nullptr, &desc); component = AudioComponentFindNext(nullptr, &desc);
verify(component != nullptr); verify(component != nullptr);
err = AudioComponentInstanceNew(component, &audioUnit); err = AudioComponentInstanceNew(component, &audioUnit);
verify(err == noErr); verify(err == noErr);
FillOutASBDForLPCM(format, 44100, FillOutASBDForLPCM(format, 44100,
2, 16, 16, false, false, false); 2, 16, 16, false, false, false);
err = AudioUnitSetProperty(audioUnit, err = AudioUnitSetProperty(audioUnit,
@ -88,7 +88,7 @@ static void coreaudio_init()
kAudioUnitScope_Input, 0, &format, kAudioUnitScope_Input, 0, &format,
sizeof(AudioStreamBasicDescription)); sizeof(AudioStreamBasicDescription));
verify(err == noErr); verify(err == noErr);
callback_struct.inputProc = coreaudio_callback; callback_struct.inputProc = coreaudio_callback;
callback_struct.inputProcRefCon = 0; callback_struct.inputProcRefCon = 0;
err = AudioUnitSetProperty(audioUnit, err = AudioUnitSetProperty(audioUnit,
@ -96,24 +96,24 @@ static void coreaudio_init()
kAudioUnitScope_Input, 0, &callback_struct, kAudioUnitScope_Input, 0, &callback_struct,
sizeof callback_struct); sizeof callback_struct);
verify(err == noErr); verify(err == noErr);
/* /*
err = AudioUnitSetParameter(audioUnit, err = AudioUnitSetParameter(audioUnit,
kHALOutputParam_Volume, kHALOutputParam_Volume,
kAudioUnitParameterFlag_Output, 0, kAudioUnitParameterFlag_Output, 0,
1, 0); 1, 0);
verify(err == noErr); verify(err == noErr);
*/ */
err = AudioUnitInitialize(audioUnit); err = AudioUnitInitialize(audioUnit);
verify(err == noErr); verify(err == noErr);
err = AudioOutputUnitStart(audioUnit); err = AudioOutputUnitStart(audioUnit);
verify(err == noErr); verify(err == noErr);
bufferEmpty.Set(); bufferEmpty.Set();
} }
@ -134,23 +134,23 @@ static u32 coreaudio_push(void* frame, u32 samples, bool wait)
samples_wptr = (samples_wptr + byte_size) % BUFSIZE; samples_wptr = (samples_wptr + byte_size) % BUFSIZE;
break; break;
} }
return 1; return 1;
} }
static void coreaudio_term() static void coreaudio_term()
{ {
OSStatus err; OSStatus err;
err = AudioOutputUnitStop(audioUnit); err = AudioOutputUnitStop(audioUnit);
verify(err == noErr); verify(err == noErr);
err = AudioUnitUninitialize(audioUnit); err = AudioUnitUninitialize(audioUnit);
verify(err == noErr); verify(err == noErr);
err = AudioComponentInstanceDispose(audioUnit); err = AudioComponentInstanceDispose(audioUnit);
verify(err == noErr); verify(err == noErr);
bufferEmpty.Set(); bufferEmpty.Set();
} }
@ -161,4 +161,7 @@ audiobackend_t audiobackend_coreaudio = {
&coreaudio_push, &coreaudio_push,
&coreaudio_term &coreaudio_term
}; };
static bool core = RegisterAudioBackend(&audiobackend_coreaudio);
#endif #endif

View File

@ -1,5 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_coreaudio;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_directsound.h" #include "oslib/audiostream.h"
#if HOST_OS==OS_WINDOWS #if HOST_OS==OS_WINDOWS
#include "oslib.h" #include "oslib.h"
#include <initguid.h> #include <initguid.h>
@ -19,31 +19,31 @@ static void directsound_init()
verifyc(dsound->SetCooperativeLevel((HWND)libPvr_GetRenderTarget(),DSSCL_PRIORITY)); verifyc(dsound->SetCooperativeLevel((HWND)libPvr_GetRenderTarget(),DSSCL_PRIORITY));
IDirectSoundBuffer* buffer_; IDirectSoundBuffer* buffer_;
WAVEFORMATEX wfx; WAVEFORMATEX wfx;
DSBUFFERDESC desc; DSBUFFERDESC desc;
// Set up WAV format structure. // Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX)); memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2; wfx.nChannels = 2;
wfx.nSamplesPerSec = 44100; wfx.nSamplesPerSec = 44100;
wfx.nBlockAlign = 4; wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.wBitsPerSample = 16; wfx.wBitsPerSample = 16;
// Set up DSBUFFERDESC structure. // Set up DSBUFFERDESC structure.
ds_ring_size=8192*wfx.nBlockAlign; ds_ring_size=8192*wfx.nBlockAlign;
memset(&desc, 0, sizeof(DSBUFFERDESC)); memset(&desc, 0, sizeof(DSBUFFERDESC));
desc.dwSize = sizeof(DSBUFFERDESC); desc.dwSize = sizeof(DSBUFFERDESC);
desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY;// _CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
desc.dwBufferBytes = ds_ring_size; desc.dwBufferBytes = ds_ring_size;
desc.lpwfxFormat = &wfx; desc.lpwfxFormat = &wfx;
if (settings.aica.HW_mixing==0) if (settings.aica.HW_mixing==0)
{ {
@ -71,7 +71,7 @@ static void directsound_init()
//Play the buffer ! //Play the buffer !
verifyc(buffer->Play(0,0,DSBPLAY_LOOPING)); verifyc(buffer->Play(0,0,DSBPLAY_LOOPING));
} }
@ -159,7 +159,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
wait &= w; wait &= w;
*/ */
int ffs=1; int ffs=1;
/* /*
while (directsound_IsAudioBufferedLots() && wait) while (directsound_IsAudioBufferedLots() && wait)
if (ffs == 0) if (ffs == 0)
@ -175,7 +175,7 @@ static u32 directsound_push(void* frame, u32 samples, bool wait)
static void directsound_term() static void directsound_term()
{ {
buffer->Stop(); buffer->Stop();
buffer->Release(); buffer->Release();
dsound->Release(); dsound->Release();
} }
@ -187,4 +187,6 @@ audiobackend_t audiobackend_directsound = {
&directsound_push, &directsound_push,
&directsound_term &directsound_term
}; };
static bool ds = RegisterAudioBackend(&audiobackend_directsound);
#endif #endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_directsound;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_libao.h" #include "oslib/audiostream.h"
#ifdef USE_LIBAO #ifdef USE_LIBAO
#include <ao/ao.h> #include <ao/ao.h>
@ -10,12 +10,12 @@ static void libao_init()
{ {
ao_initialize(); ao_initialize();
memset(&aoformat, 0, sizeof(aoformat)); memset(&aoformat, 0, sizeof(aoformat));
aoformat.bits = 16; aoformat.bits = 16;
aoformat.channels = 2; aoformat.channels = 2;
aoformat.rate = 44100; aoformat.rate = 44100;
aoformat.byte_format = AO_FMT_LITTLE; aoformat.byte_format = AO_FMT_LITTLE;
aodevice = ao_open_live(ao_default_driver_id(), &aoformat, NULL); // Live output aodevice = ao_open_live(ao_default_driver_id(), &aoformat, NULL); // Live output
if (!aodevice) if (!aodevice)
aodevice = ao_open_live(ao_driver_id("null"), &aoformat, NULL); 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) static u32 libao_push(void* frame, u32 samples, bool wait)
{ {
if (aodevice) if (aodevice)
ao_play(aodevice, (char*)frame, samples * 4); ao_play(aodevice, (char*)frame, samples * 4);
return 1; return 1;
} }
static void libao_term() static void libao_term()
{ {
if (aodevice) if (aodevice)
{ {
@ -46,4 +46,5 @@ audiobackend_t audiobackend_libao = {
&libao_term &libao_term
}; };
static bool ao = RegisterAudioBackend(&audiobackend_libao);
#endif #endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_libao;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_omx.h" #include "oslib/audiostream.h"
#if USE_OMX #if USE_OMX
#include <IL/OMX_Broadcom.h> #include <IL/OMX_Broadcom.h>
@ -316,4 +316,5 @@ audiobackend_t audiobackend_omx = {
&omx_term &omx_term
}; };
static bool omx = RegisterAudioBackend(&audiobackend_omx);
#endif #endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_omx;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_oss.h" #include "oslib/audiostream.h"
#ifdef USE_OSS #ifdef USE_OSS
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
@ -51,4 +51,5 @@ audiobackend_t audiobackend_oss = {
&oss_term &oss_term
}; };
static bool oss = RegisterAudioBackend(&audiobackend_oss);
#endif #endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_oss;

View File

@ -1,4 +1,4 @@
#include "oslib/audiobackend_pulseaudio.h" #include "oslib/audiostream.h"
#ifdef USE_PULSEAUDIO #ifdef USE_PULSEAUDIO
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/fcntl.h> #include <sys/fcntl.h>
@ -45,4 +45,6 @@ audiobackend_t audiobackend_pulseaudio = {
&pulseaudio_push, &pulseaudio_push,
&pulseaudio_term &pulseaudio_term
}; };
static bool pulse = RegisterAudioBackend(&audiobackend_pulseaudio);
#endif #endif

View File

@ -1,4 +0,0 @@
#pragma once
#include "oslib/audiostream.h"
extern audiobackend_t audiobackend_pulseaudio;

View File

@ -2,14 +2,6 @@
#include "cfg/cfg.h" #include "cfg/cfg.h"
#include "oslib/oslib.h" #include "oslib/oslib.h"
#include "audiostream.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; }; struct SoundFrame { s16 l;s16 r; };
#define SAMPLE_COUNT 512 #define SAMPLE_COUNT 512
@ -25,16 +17,27 @@ u32 gen_samples=0;
double time_diff = 128/44100.0; double time_diff = 128/44100.0;
double time_last; double time_last;
#ifdef LOG_SOUND #ifdef LOG_SOUND
// TODO Only works on Windows!
WaveWriter rawout("d:\\aica_out.wav"); WaveWriter rawout("d:\\aica_out.wav");
#endif #endif
static bool audiobackends_registered = false;
static unsigned int audiobackends_num_max = 1; static unsigned int audiobackends_num_max = 1;
static unsigned int audiobackends_num_registered = 0; 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; 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) bool RegisterAudioBackend(audiobackend_t *backend)
{ {
/* This function announces the availability of an audio backend to reicast. */ /* 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"); printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
return false; return false;
} }
if (backend->slug == "auto" || backend->slug == "none") { 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()); printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
return false; 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 // Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
if (audiobackends_num_registered == audiobackends_num_max) if (audiobackends_num_registered == audiobackends_num_max)
{ {
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
} }
audiobackends = new_ptr; audiobackends = new_ptr;
} }
audiobackends[audiobackends_num_registered] = backend; audiobackends[audiobackends_num_registered] = backend;
audiobackends_num_registered++; audiobackends_num_registered++;
return true; return true;
} }
void RegisterAllAudioBackends() { audiobackend_t* GetAudioBackend(std::string slug)
#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)
{ {
if (slug == "none") if (slug == "none")
{ {
printf("WARNING: Audio backend set to \"none\"!\n"); printf("WARNING: Audio backend set to \"none\"!\n");
} }
else if(audiobackends_num_registered > 0) else if (audiobackends_num_registered > 0)
{ {
if (slug == "auto") if (slug == "auto")
{ {
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
return NULL; return NULL;
} }
u32 PushAudio(void* frame, u32 amt, bool wait) { u32 PushAudio(void* frame, u32 amt, bool wait)
{
if (audiobackend_current != NULL) { if (audiobackend_current != NULL) {
return audiobackend_current->push(frame, amt, wait); return audiobackend_current->push(frame, amt, wait);
} }
@ -151,6 +134,7 @@ u32 asRingUsedCount()
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr; //s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
//return sz<0?sz+RingBufferSampleCount:sz; //return sz<0?sz+RingBufferSampleCount:sz;
} }
u32 asRingFreeCount() u32 asRingFreeCount()
{ {
return RingBufferSampleCount-asRingUsedCount(); 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() void InitAudio()
{ {
if (cfgLoadInt("audio", "disable", 0)) { if (cfgLoadInt("audio", "disable", 0)) {
@ -176,26 +181,24 @@ void InitAudio()
return; return;
} }
cfgSaveInt("audio","disable",0); cfgSaveInt("audio", "disable", 0);
if (!audiobackends_registered) {
//FIXME: There might some nicer way to do this.
RegisterAllAudioBackends();
}
if (audiobackend_current != NULL) { 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()); 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; 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); audiobackend_current = GetAudioBackend(audiobackend_slug);
if (audiobackend_current == NULL) { if (audiobackend_current == NULL) {
printf("WARNING: Running without audio!\n"); printf("WARNING: Running without audio!\n");
return; return;
} }
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str()); 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() void TermAudio()
@ -204,5 +207,5 @@ void TermAudio()
audiobackend_current->term(); audiobackend_current->term();
printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str()); printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current = NULL; audiobackend_current = NULL;
} }
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include <tuple>
//Get used size in the ring buffer //Get used size in the ring buffer
u32 asRingUsedCount(); u32 asRingUsedCount();
@ -24,3 +25,8 @@ extern bool RegisterAudioBackend(audiobackend_t* backend);
extern void InitAudio(); extern void InitAudio();
extern u32 PushAudio(void* frame, u32 amt, bool wait); extern u32 PushAudio(void* frame, u32 amt, bool wait);
extern void TermAudio(); extern void TermAudio();
u32 GetAudioBackendCount();
void SortAudioBackends();
audiobackend_t* GetAudioBackend(int num);
audiobackend_t* GetAudioBackend(std::string slug);

View File

@ -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); //printf("Compile: %08X, %d, %d\n",block->addr,staging,optimise);
block->code=(DynarecCodeEntryPtr)EMIT_GET_PTR(); 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); reg.OpBegin(&block->oplist[0],0);
//scheduler //scheduler
if (force_checks) switch (smc_checks) {
{ case NoCheck:
s32 sz = block->sh4_code_size; break;
u32 addr = block->addr;
MOV32(r0,addr);
while (sz > 0) case FastCheck: {
{ MOV32(r0,block->addr);
if (sz > 2) u32* ptr=(u32*)GetMemPtr(block->addr,4);
if (ptr != NULL)
{ {
u32* ptr=(u32*)GetMemPtr(addr,4);
MOV32(r2,(u32)ptr); MOV32(r2,(u32)ptr);
LDR(r2,r2,0); LDR(r2,r2,0);
MOV32(r1,*ptr); MOV32(r1,*ptr);
CMP(r1,r2); CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE); 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); if (sz > 2)
MOV32(r2, (u32)ptr); {
LDRH(r2, r2, 0, AL); u32* ptr=(u32*)GetMemPtr(addr,4);
MOVW(r1, *ptr, AL); if (ptr != NULL)
CMP(r1, r2); {
MOV32(r2,(u32)ptr);
LDR(r2,r2,0);
MOV32(r1,*ptr);
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE); JUMP((u32)ngen_blockcheckfail, CC_NE);
addr += 2; }
sz -= 2; 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; u32 cyc=block->guest_cycles;

View File

@ -348,15 +348,15 @@ public:
return *ret_reg; 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); //printf("REC-ARM64 compiling %08x\n", block->addr);
#ifdef PROFILING #ifdef PROFILING
SaveFramePointer(); SaveFramePointer();
#endif #endif
this->block = block; this->block = block;
if (force_checks)
CheckBlock(block); CheckBlock(smc_checks, block);
// run register allocator // run register allocator
regalloc.DoAlloc(block); regalloc.DoAlloc(block);
@ -1292,49 +1292,72 @@ private:
verify (GetCursorAddress<Instruction *>() - start_instruction == code_size * kInstructionSize); 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_fail;
Label blockcheck_success; Label blockcheck_success;
u8* ptr = GetMemPtr(block->addr, sz); switch (smc_checks) {
if (ptr == NULL) case NoCheck:
// FIXME Can a block cross a RAM / non-RAM boundary?? return;
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr)); case FastCheck: {
u8* ptr = GetMemPtr(block->addr, 4);
while (sz > 0) if (ptr == NULL)
{ return;
if (sz >= 8) Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
{ Ldr(w10, MemOperand(x9));
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); Ldr(w11, *(u32*)ptr);
Cmp(w10, w11); Cmp(w10, w11);
sz -= 4; B(eq, &blockcheck_success);
ptr += 4;
} }
else break;
{
Ldrh(w10, MemOperand(x9, 2, PostIndex)); case FullCheck: {
Mov(w11, *(u16*)ptr); s32 sz = block->sh4_code_size;
Cmp(w10, w11);
sz -= 2; u8* ptr = GetMemPtr(block->addr, sz);
ptr += 2; 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); Bind(&blockcheck_fail);
Ldr(w0, block->addr); Ldr(w0, block->addr);
@ -1404,13 +1427,13 @@ private:
static Arm64Assembler* compiler; 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); verify(emit_FreeSpace() >= 16 * 1024);
compiler = new Arm64Assembler(); compiler = new Arm64Assembler();
compiler->ngen_Compile(block, force_checks, reset, staging, optimise); compiler->ngen_Compile(block, smc_checks, reset, staging, optimise);
delete compiler; delete compiler;
compiler = NULL; compiler = NULL;

View File

@ -1190,10 +1190,10 @@ public:
size_t opcode_index; size_t opcode_index;
opcodeExec** ptrsg; 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 //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; ptrsg = ptrs.ptrs;
@ -1207,9 +1207,16 @@ public:
} }
size_t i = 0; size_t i = 0;
if (force_checks) if (smc_checks != NoCheck)
{ {
verify (smc_checks == FastCheck || smc_checks == FullCheck)
opcodeExec* op; opcodeExec* op;
int check_size = block->sh4_code_size;
if (smc_checks == FastCheck) {
check_size = 4;
}
switch (block->sh4_code_size) switch (block->sh4_code_size)
{ {
case 4: case 4:
@ -1227,6 +1234,7 @@ public:
} }
ptrs.ptrs[i++] = op; ptrs.ptrs[i++] = op;
} }
for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) { for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) {
opcode_index = i; opcode_index = i;
shil_opcode& op = block->oplist[opnum]; shil_opcode& op = block->oplist[opnum];
@ -1551,14 +1559,14 @@ public:
BlockCompiler* compiler; 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); verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler(); compiler = new BlockCompiler();
compiler->compile(block, force_checks, reset, staging, optimise); compiler->compile(block, smc_checks, reset, staging, optimise);
delete compiler; delete compiler;
} }

View File

@ -244,12 +244,11 @@ public:
call_regsxmm.push_back(xmm3); 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()); //printf("X86_64 compiling %08x to %p\n", block->addr, emit_GetCCPtr());
if (force_checks) { CheckBlock(smc_checks, block);
CheckBlock(block);
}
regalloc.DoAlloc(block); regalloc.DoAlloc(block);
sub(dword[rip + &cycle_counter], block->guest_cycles); 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::*X64BinaryOp)(const Xbyak::Operand&, const Xbyak::Operand&);
typedef void (BlockCompiler::*X64BinaryFOp)(const Xbyak::Xmm&, const Xbyak::Operand&); typedef void (BlockCompiler::*X64BinaryFOp)(const Xbyak::Xmm&, const Xbyak::Operand&);
void CheckBlock(RuntimeBlockInfo* block) { void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block) {
mov(call_regs[0], block->addr);
s32 sz=block->sh4_code_size; switch (smc_checks) {
u32 sa=block->addr; case NoCheck:
return;
while (sz > 0) case FastCheck: {
{ void* ptr = (void*)GetMemPtr(block->addr, 4);
void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz); if (ptr)
if (ptr) {
{ mov(call_regs[0], block->addr);
mov(rax, reinterpret_cast<uintptr_t>(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) {
mov(edx, *(u32*)ptr); mov(edx, *(u32*)ptr);
cmp(dword[rax], edx); cmp(dword[rax], edx);
sz -= 4; jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
sa += 4;
} }
else { }
mov(edx, *(u16*)ptr); break;
cmp(word[rax],dx);
sz -= 2;
sa += 2;
}
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
}
}
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) void GenBinaryOp(const shil_opcode &op, X64BinaryOp natop)
@ -1267,13 +1291,13 @@ void X64RegAlloc::Writeback_FPU(u32 reg, s8 nreg)
static BlockCompiler* compiler; 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); verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler(); compiler = new BlockCompiler();
compiler->compile(block, force_checks, reset, staging, optimise); compiler->compile(block, smc_checks, reset, staging, optimise);
delete compiler; delete compiler;
} }

View File

@ -229,29 +229,50 @@ u32 rdmt[6];
extern u32 memops_t,memops_l; extern u32 memops_t,memops_l;
extern int mips_counter; 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; switch (smc_checks) {
u32 sa=block->addr; case NoCheck:
while(sz>0) break;
{
void* ptr=(void*)GetMemPtr(sa,4); case FastCheck: {
if (ptr) void* ptr = (void*)GetMemPtr(block->addr, 4);
{ if (ptr)
if (sz==2) {
x86e->Emit(op_cmp16,ptr,*(u16*)ptr); x86e->Emit(op_cmp32, ptr, *(u32*)ptr);
else x86e->Emit(op_jne, x86_ptr_imm(ngen_blockcheckfail));
x86e->Emit(op_cmp32,ptr,*(u32*)ptr); }
x86e->Emit(op_jne,place);
} }
sz-=4; break;
sa+=4;
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 //initialise stuff
DetectCpuFeatures(); DetectCpuFeatures();
@ -282,7 +303,7 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
//block invl. checks //block invl. checks
x86e->Emit(op_mov32,ECX,block->addr); 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 //Scheduler
x86_Label* no_up=x86e->CreateLabel(false,8); x86_Label* no_up=x86e->CreateLabel(false,8);

View File

@ -331,23 +331,23 @@ void initABuffer()
{ {
char source[16384]; char source[16384];
sprintf(source, final_shader_source, 1); 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) if (g_abuffer_final_nosort_shader.program == 0)
{ {
char source[16384]; char source[16384];
sprintf(source, final_shader_source, 0); 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) 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) if (g_abuffer_tr_modvol_shaders[0].program == 0)
{ {
char source[16384]; char source[16384];
for (int mode = 0; mode < ModeCount; mode++) for (int mode = 0; mode < ModeCount; mode++)
{ {
sprintf(source, tr_modvol_shader_source, 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); glDeleteBuffers(1, &g_quadBuffer);
g_quadBuffer = 0; 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) void reshapeABuffer(int w, int h)

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "rend/gles/gles.h" #include "rend/gles/gles.h"
#include <map> #include <unordered_map>
void gl4DrawStrips(GLuint output_fbo); void gl4DrawStrips(GLuint output_fbo);
@ -44,7 +44,8 @@ struct gl4_ctx
GLuint extra_depth_scale; GLuint extra_depth_scale;
} modvol_shader; } modvol_shader;
std::map<int, gl4PipelineShader *> shaders; std::unordered_map<u32, gl4PipelineShader> shaders;
bool rotate90;
struct struct
{ {
@ -53,16 +54,6 @@ struct gl4_ctx
GLuint modvol_vao; GLuint modvol_vao;
GLuint tr_poly_params; GLuint tr_poly_params;
} vbo; } 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; 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); 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; 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 stencilTexId;
extern GLuint depthTexId; extern GLuint depthTexId;

View File

@ -45,10 +45,15 @@ static GLuint texSamplers[2];
static GLuint depth_fbo; static GLuint depth_fbo;
GLuint depthSaveTexId; 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_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) 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; u32 rv=0;
rv|=pp_ClipTestMode; rv|=pp_ClipTestMode;
@ -66,45 +71,27 @@ static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
rv <<= 1; rv |= fog_clamping; rv <<= 1; rv |= fog_clamping;
rv <<= 2; rv |= pass; rv <<= 2; rv |= pass;
return rv; gl4PipelineShader *shader = &gl4.shaders[rv];
} if (shader->program == 0)
{
static void setCurrentShader(u32 cp_AlphaTest, u32 pp_ClipTestMode, shader->cp_AlphaTest = cp_AlphaTest;
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset, shader->pp_ClipTestMode = pp_ClipTestMode;
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass) shader->pp_Texture = pp_Texture;
{ shader->pp_UseAlpha = pp_UseAlpha;
int shaderId = gl4GetProgramID(cp_AlphaTest, shader->pp_IgnoreTexA = pp_IgnoreTexA;
pp_ClipTestMode + 1, shader->pp_ShadInstr = pp_ShadInstr;
pp_Texture, shader->pp_Offset = pp_Offset;
pp_UseAlpha, shader->pp_FogCtrl = pp_FogCtrl;
pp_IgnoreTexA, shader->pp_TwoVolumes = pp_TwoVolumes;
pp_ShadInstr, shader->pp_DepthFunc = pp_DepthFunc;
pp_Offset, shader->pp_Gouraud = pp_Gouraud;
pp_FogCtrl, shader->pp_BumpMap = pp_BumpMap;
pp_TwoVolumes, shader->fog_clamping = fog_clamping;
pp_DepthFunc, shader->pass = pass;
pp_Gouraud, gl4CompilePipelineShader(shader, settings.rend.Rotate90);
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);
} }
return shader;
} }
static void SetTextureRepeatMode(int index, GLuint dir, u32 clamp, u32 mirror) static void SetTextureRepeatMode(int index, GLuint dir, u32 clamp, u32 mirror)
@ -132,7 +119,7 @@ template <u32 Type, bool SortingEnabled>
if (pass == 0) if (pass == 0)
{ {
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0, CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
clipping, clipping,
Type == ListType_Punch_Through ? gp->pcw.Texture : 0, Type == ListType_Punch_Through ? gp->pcw.Texture : 0,
1, 1,
@ -153,6 +140,8 @@ template <u32 Type, bool SortingEnabled>
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent; 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); 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; int depth_func = 0;
if (Type == ListType_Translucent) if (Type == ListType_Translucent)
{ {
@ -162,14 +151,14 @@ template <u32 Type, bool SortingEnabled>
depth_func = gp->isp.DepthMode; depth_func = gp->isp.DepthMode;
} }
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0, CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
clipping, clipping,
gp->pcw.Texture, gp->pcw.Texture,
gp->tsp.UseAlpha, gp->tsp.UseAlpha,
gp->tsp.IgnoreTexA, gp->tsp.IgnoreTexA,
gp->tsp.ShadInstr, gp->tsp.ShadInstr,
gp->pcw.Offset, gp->pcw.Offset,
gp->tsp.FogCtrl, fog_ctrl,
two_volumes_mode, two_volumes_mode,
depth_func, depth_func,
gp->pcw.Gouraud, 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; ShaderUniforms.trilinear_alpha = 1.0;
setCurrentShader(0, CurrentShader = gl4GetProgram(0,
0, 0,
1, 1,
0, 0,
@ -713,11 +702,15 @@ void gl4DrawFramebuffer(float w, float h)
bool gl4_render_output_framebuffer() bool gl4_render_output_framebuffer()
{ {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screen_width, screen_height); glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0) glcache.Disable(GL_SCISSOR_TEST);
if (gl.ofbo.fbo == 0)
return false; return false;
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
gl4_draw_quad_texture(gl.ofbo.tex, true); 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; return true;
} }

View File

@ -14,6 +14,7 @@ static const char* VertexShaderSource =
"\ "\
#version 140 \n\ #version 140 \n\
#define pp_Gouraud %d \n\ #define pp_Gouraud %d \n\
#define ROTATE_90 %d \n\
\n\ \n\
#if pp_Gouraud == 0 \n\ #if pp_Gouraud == 0 \n\
#define INTERPOLATION flat \n\ #define INTERPOLATION flat \n\
@ -56,6 +57,9 @@ void main() \n\
\n\ \n\
vpos.w = extra_depth_scale / vpos.z; \n\ vpos.w = extra_depth_scale / vpos.z; \n\
vpos.z = vpos.w; \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.xy*scale.xy-scale.zw; \n\
vpos.xy*=vpos.w; \n\ vpos.xy*=vpos.w; \n\
gl_Position = vpos; \n\ gl_Position = vpos; \n\
@ -393,11 +397,11 @@ gl4_ctx gl4;
struct gl4ShaderUniforms_t gl4ShaderUniforms; 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]; char vshader[16384];
sprintf(vshader, VertexShaderSource, s->pp_Gouraud); sprintf(vshader, VertexShaderSource, s->pp_Gouraud, rotate_90);
char pshader[16384]; char pshader[16384];
@ -478,28 +482,45 @@ bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *source /* = Pix
void gl_term(); 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) static void gles_term(void)
{ {
glDeleteProgram(gl4.modvol_shader.program);
glDeleteBuffers(1, &gl4.vbo.geometry); glDeleteBuffers(1, &gl4.vbo.geometry);
gl4.vbo.geometry = 0; gl4.vbo.geometry = 0;
glDeleteBuffers(1, &gl4.vbo.modvols); glDeleteBuffers(1, &gl4.vbo.modvols);
glDeleteBuffers(1, &gl4.vbo.idxs); glDeleteBuffers(1, &gl4.vbo.idxs);
glDeleteBuffers(1, &gl4.vbo.idxs2); glDeleteBuffers(1, &gl4.vbo.idxs2);
glDeleteBuffers(1, &gl4.vbo.tr_poly_params); glDeleteBuffers(1, &gl4.vbo.tr_poly_params);
for (auto it = gl4.shaders.begin(); it != gl4.shaders.end(); it++) gl4_delete_shaders();
{
if (it->second->program != -1)
glDeleteProgram(it->second->program);
delete it->second;
}
gl4.shaders.clear();
glDeleteVertexArrays(1, &gl4.vbo.main_vao); glDeleteVertexArrays(1, &gl4.vbo.main_vao);
glDeleteVertexArrays(1, &gl4.vbo.modvol_vao); glDeleteVertexArrays(1, &gl4.vbo.modvol_vao);
gl_term(); 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() static bool gl_create_resources()
{ {
if (gl4.vbo.geometry != 0) if (gl4.vbo.geometry != 0)
@ -521,12 +542,7 @@ static bool gl_create_resources()
gl4SetupMainVBO(); gl4SetupMainVBO();
gl4SetupModvolVBO(); gl4SetupModvolVBO();
char vshader[16384]; create_modvol_shader();
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");
gl_load_osd_resources(); gl_load_osd_resources();
@ -604,6 +620,7 @@ static bool RenderFrame()
old_screen_scaling = settings.rend.ScreenScaling; old_screen_scaling = settings.rend.ScreenScaling;
} }
DoCleanup(); DoCleanup();
create_modvol_shader();
bool is_rtt=pvrrc.isRTT; bool is_rtt=pvrrc.isRTT;
@ -662,16 +679,41 @@ static bool RenderFrame()
/* /*
Handle Dc to screen scaling Handle Dc to screen scaling
*/ */
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f; float screen_scaling = settings.rend.ScreenScaling / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0); float screen_stretching = settings.rend.ScreenStretching / 100.f;
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
//-1 -> too much to left float dc2s_scale_h;
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x); float ds2s_offs_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); if (is_rtt)
gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1); {
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; 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[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
gl4ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 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; fog_needs_update = false;
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE5, GL_RED); 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) 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 else
{ {
@ -826,22 +868,31 @@ static bool RenderFrame()
float min_y = pvrrc.fb_Y_CLIP.min / scale_y; float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
if (!is_rtt) 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 // 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 // Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h; min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h; width *= dc2s_scale_h * screen_stretching * screen_scaling;
height *= dc2s_scale_h; height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0) 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.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST); 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); 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); glClear(GL_COLOR_BUFFER_BIT);
} }
} }

View File

@ -50,23 +50,28 @@ void CustomTexture::LoaderThread()
if (texture != NULL) if (texture != NULL)
{ {
// FIXME texture may have been deleted. Need to detect this.
texture->ComputeHash(); texture->ComputeHash();
int width, height; if (texture->custom_image_data != NULL)
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
if (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) int width, height;
delete [] texture->custom_image_data; u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
texture->custom_width = width; if (image_data == NULL)
texture->custom_height = height; {
texture->custom_image_data = image_data; 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); } while (texture != NULL);
@ -144,10 +149,9 @@ u8* CustomTexture::LoadCustomTexture(u32 hash, int& width, int& height)
void CustomTexture::LoadCustomTextureAsync(TextureCacheData *texture_data) void CustomTexture::LoadCustomTextureAsync(TextureCacheData *texture_data)
{ {
if (!Init()) if (!Init())
{
texture_data->custom_load_in_progress = false;
return; return;
}
texture_data->custom_load_in_progress++;
work_queue_mutex.Lock(); work_queue_mutex.Lock();
work_queue.insert(work_queue.begin(), texture_data); work_queue.insert(work_queue.begin(), texture_data);
work_queue_mutex.Unlock(); work_queue_mutex.Unlock();

View File

@ -53,7 +53,7 @@ private:
cThread loader_thread; cThread loader_thread;
#endif #endif
cResetEvent wakeup_thread; cResetEvent wakeup_thread;
std::vector<struct TextureCacheData *> work_queue; std::vector<TextureCacheData *> work_queue;
cMutex work_queue_mutex; cMutex work_queue_mutex;
}; };

View File

@ -149,6 +149,19 @@ public:
return _texture_ids[--_texture_cache_size]; 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() { void Reset() {
_texture = 0xFFFFFFFFu; _texture = 0xFFFFFFFFu;
_src_blend_factor = 0xFFFFFFFFu; _src_blend_factor = 0xFFFFFFFFu;
@ -179,7 +192,7 @@ public:
void DisableCache() { _disable_cache = true; } void DisableCache() { _disable_cache = true; }
void EnableCache() void EnableCache()
{ {
_disable_cache = true; _disable_cache = false;
Reset(); Reset();
} }

View File

@ -114,13 +114,30 @@ s32 SetTileClip(u32 val, GLint uniform)
csy /= scale_y; csy /= scale_y;
cex /= scale_x; cex /= scale_x;
cey /= scale_y; cey /= scale_y;
float t = cey; float dc2s_scale_h;
cey = 480 - csy; float ds2s_offs_x;
csy = 480 - t; float screen_stretching = settings.rend.ScreenStretching / 100.f;
float dc2s_scale_h = screen_height / 480.0f;
float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; if (settings.rend.Rotate90)
csx = csx * dc2s_scale_h + ds2s_offs_x; {
cex = cex * dc2s_scale_h + ds2s_offs_x; 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; csy = csy * dc2s_scale_h;
cey = cey * dc2s_scale_h; cey = cey * dc2s_scale_h;
} }
@ -173,28 +190,25 @@ __forceinline
ShaderUniforms.trilinear_alpha = 1.f; ShaderUniforms.trilinear_alpha = 1.f;
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff); 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[ CurrentShader = GetProgram(Type == ListType_Punch_Through ? 1 : 0,
GetProgramID(Type == ListType_Punch_Through ? 1 : 0, SetTileClip(gp->tileclip, -1) + 1,
SetTileClip(gp->tileclip, -1) + 1, gp->pcw.Texture,
gp->pcw.Texture, gp->tsp.UseAlpha,
gp->tsp.UseAlpha, gp->tsp.IgnoreTexA,
gp->tsp.IgnoreTexA, gp->tsp.ShadInstr,
gp->tsp.ShadInstr, gp->pcw.Offset,
gp->pcw.Offset, fog_ctrl,
gp->tsp.FogCtrl, gp->pcw.Gouraud,
gp->pcw.Gouraud, gp->tcw.PixelFmt == PixelBumpMap,
gp->tcw.PixelFmt == PixelBumpMap, color_clamp,
color_clamp, ShaderUniforms.trilinear_alpha != 1.f);
ShaderUniforms.trilinear_alpha != 1.f)];
if (CurrentShader->program == -1) glcache.UseProgram(CurrentShader->program);
CompilePipelineShader(CurrentShader); if (CurrentShader->trilinear_alpha != -1)
else glUniform1f(CurrentShader->trilinear_alpha, ShaderUniforms.trilinear_alpha);
{
glcache.UseProgram(CurrentShader->program);
ShaderUniforms.Set(CurrentShader);
}
SetTileClip(gp->tileclip, CurrentShader->pp_ClipTest); SetTileClip(gp->tileclip, CurrentShader->pp_ClipTest);
//This bit control which pixels are affected //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; ShaderUniforms.trilinear_alpha = 1.0;
PipelineShader *shader = &gl.pogram_table[GetProgramID(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false)]; PipelineShader *shader = GetProgram(0, 1, 1, 0, 1, 0, 0, 2, false, false, false, false);
if (shader->program == -1) glcache.UseProgram(shader->program);
CompilePipelineShader(shader);
else
{
glcache.UseProgram(shader->program);
ShaderUniforms.Set(shader);
}
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glcache.BindTexture(GL_TEXTURE_2D, texId); glcache.BindTexture(GL_TEXTURE_2D, texId);
@ -1150,17 +1158,27 @@ void DrawFramebuffer(float w, float h)
bool render_output_framebuffer() bool render_output_framebuffer()
{ {
#if HOST_OS != OS_DARWIN glcache.Disable(GL_SCISSOR_TEST);
//Fix this in a proper way if (gl.gl_major < 3)
glBindFramebuffer(GL_FRAMEBUFFER, 0); {
#endif glViewport(0, 0, screen_width, screen_height);
glViewport(0, 0, screen_width, screen_height); if (gl.ofbo.tex == 0)
if (gl.ofbo.tex == 0) return false;
return false; glBindFramebuffer(GL_FRAMEBUFFER, 0);
float scl = 480.f / screen_height;
float scl = 480.f / screen_height; float tx = (screen_width * scl - 640.f) / 2;
float tx = (screen_width * scl - 640.f) / 2; DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
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; return true;
} }

View File

@ -79,6 +79,7 @@ const char* VertexShaderSource =
%s \n\ %s \n\
#define TARGET_GL %s \n\ #define TARGET_GL %s \n\
#define pp_Gouraud %d \n\ #define pp_Gouraud %d \n\
#define ROTATE_90 %d \n\
\n\ \n\
#define GLES2 0 \n\ #define GLES2 0 \n\
#define GLES3 1 \n\ #define GLES3 1 \n\
@ -136,6 +137,9 @@ void main() \n\
vpos.z = vpos.w; \n\ vpos.z = vpos.w; \n\
#else \n\ #else \n\
vpos.z=depth_scale.x+depth_scale.y*vpos.w; \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\ #endif \n\
vpos.xy=vpos.xy*scale.xy-scale.zw; \n\ vpos.xy=vpos.xy*scale.xy-scale.zw; \n\
vpos.xy*=vpos.w; \n\ vpos.xy*=vpos.w; \n\
@ -850,9 +854,20 @@ GLuint fogTextureId;
extern void gl_term(); extern void gl_term();
#endif #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() static void gles_term()
{ {
glDeleteProgram(gl.modvol_shader.program);
glDeleteBuffers(1, &gl.vbo.geometry); glDeleteBuffers(1, &gl.vbo.geometry);
gl.vbo.geometry = 0; gl.vbo.geometry = 0;
glDeleteBuffers(1, &gl.vbo.modvols); glDeleteBuffers(1, &gl.vbo.modvols);
@ -865,7 +880,7 @@ static void gles_term()
gl_free_osd_resources(); gl_free_osd_resources();
free_output_framebuffer(); free_output_framebuffer();
memset(gl.pogram_table, 0, sizeof(gl.pogram_table)); gl_delete_shaders();
gl_term(); gl_term();
} }
@ -1014,10 +1029,15 @@ GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader)
return program; 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_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) 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; u32 rv=0;
rv|=pp_ClipTestMode; rv|=pp_ClipTestMode;
@ -1033,14 +1053,32 @@ int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
rv<<=1; rv|=fog_clamping; rv<<=1; rv|=fog_clamping;
rv<<=1; rv|=trilinear; 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) bool CompilePipelineShader( PipelineShader* s)
{ {
char vshader[8192]; 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]; char pshader[8192];
@ -1126,13 +1164,30 @@ void gl_load_osd_resources()
void gl_free_osd_resources() void gl_free_osd_resources()
{ {
glDeleteProgram(gl.OSD_SHADER.program); glcache.DeleteProgram(gl.OSD_SHADER.program);
if (osd_tex != 0) { if (osd_tex != 0) {
glcache.DeleteTextures(1, &osd_tex); glcache.DeleteTextures(1, &osd_tex);
osd_tex = 0; 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() bool gl_create_resources()
{ {
if (gl.vbo.geometry != 0) if (gl.vbo.geometry != 0)
@ -1156,84 +1211,7 @@ bool gl_create_resources()
glGenBuffers(1, &gl.vbo.idxs); glGenBuffers(1, &gl.vbo.idxs);
glGenBuffers(1, &gl.vbo.idxs2); glGenBuffers(1, &gl.vbo.idxs2);
memset(gl.pogram_table,0,sizeof(gl.pogram_table)); create_modvol_shader();
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
gl_load_osd_resources(); gl_load_osd_resources();
@ -1553,6 +1531,7 @@ static void upload_vertex_indices()
bool RenderFrame() bool RenderFrame()
{ {
DoCleanup(); DoCleanup();
create_modvol_shader();
bool is_rtt=pvrrc.isRTT; bool is_rtt=pvrrc.isRTT;
@ -1719,17 +1698,41 @@ bool RenderFrame()
/* /*
Handle Dc to screen scaling Handle Dc to screen scaling
*/ */
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f; float screen_stretching = settings.rend.ScreenStretching / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0); float screen_scaling = settings.rend.ScreenScaling / 100.f;
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
//-1 -> too much to left float dc2s_scale_h;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x); float ds2s_offs_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);
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[0]=2/(vtx_max_fZ-vtx_min_fZ);
ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1; 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[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 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; fog_needs_update = false;
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.fog_image_format); 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; ShaderUniforms.PT_ALPHA=(PT_ALPHA_REF&0xFF)/255.0f;
// for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++) for (auto it : gl.shaders)
// { {
// PipelineShader* s=&gl.pogram_table[i]; glcache.UseProgram(it.second.program);
// if (s->program == -1) ShaderUniforms.Set(&it.second);
// continue; }
//
// glcache.UseProgram(s->program);
//
// ShaderUniforms.Set(s);
// }
//setup render target first //setup render target first
if (is_rtt) if (is_rtt)
{ {
@ -1836,7 +1835,7 @@ bool RenderFrame()
{ {
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) 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 else
{ {
@ -1883,9 +1882,6 @@ bool RenderFrame()
glBufferData(GL_ARRAY_BUFFER,pvrrc.modtrig.bytes(),pvrrc.modtrig.head(),GL_STREAM_DRAW); glCheck(); 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 //not all scaling affects pixel operations, scale to adjust for that
scale_x *= scissoring_scale_x; scale_x *= scissoring_scale_x;
@ -1904,22 +1900,31 @@ bool RenderFrame()
float min_y = pvrrc.fb_Y_CLIP.min / scale_y; float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
if (!is_rtt) 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 // 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 // Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h; min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h; width *= dc2s_scale_h * screen_stretching * screen_scaling;
height *= dc2s_scale_h; height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0) 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.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST); 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); 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); glClear(GL_COLOR_BUFFER_BIT);
} }
} }

View File

@ -1,4 +1,6 @@
#pragma once #pragma once
#include <unordered_map>
#include <atomic>
#include "rend/rend.h" #include "rend/rend.h"
#if (defined(GLES) && !defined(TARGET_NACL32) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(_ANDROID) #if (defined(GLES) && !defined(TARGET_NACL32) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(_ANDROID)
@ -93,7 +95,9 @@ struct gl_ctx
} modvol_shader; } modvol_shader;
PipelineShader pogram_table[24576]; std::unordered_map<u32, PipelineShader> shaders;
bool rotate90;
struct struct
{ {
GLuint program; GLuint program;
@ -117,6 +121,7 @@ struct gl_ctx
struct struct
{ {
GLuint depthb; GLuint depthb;
GLuint colorb;
GLuint tex; GLuint tex;
GLuint fbo; GLuint fbo;
int width; int width;
@ -176,7 +181,7 @@ void free_output_framebuffer();
void HideOSD(); void HideOSD();
void OSD_DRAW(bool clear_screen); 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_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); 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) if (s->sp_FOG_COL_VERT!=-1)
glUniform3fv( s->sp_FOG_COL_VERT, 1, ps_FOG_COL_VERT); 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) if (s->fog_clamp_min != -1)
glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min); glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min);
if (s->fog_clamp_max != -1) 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 //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 texture_hash; // xxhash of texture data, used for custom textures
u32 old_texture_hash; // legacy hash u32 old_texture_hash; // legacy hash
u8* custom_image_data; // loaded custom image data u8* volatile custom_image_data; // loaded custom image data
u32 custom_width; volatile u32 custom_width;
u32 custom_height; volatile u32 custom_height;
bool custom_load_in_progress; std::atomic_int custom_load_in_progress;
void PrintTextureName(); void PrintTextureName();

View File

@ -296,10 +296,7 @@ void TextureCacheData::Update()
} }
} }
if (settings.rend.CustomTextures) if (settings.rend.CustomTextures)
{
custom_load_in_progress = true;
custom_texture.LoadCustomTextureAsync(this); custom_texture.LoadCustomTextureAsync(this);
}
void *temp_tex_buffer = NULL; void *temp_tex_buffer = NULL;
u32 upscaled_w = w; u32 upscaled_w = w;
@ -428,7 +425,7 @@ void TextureCacheData::UploadToGPU(GLuint textype, int width, int height, u8 *te
void TextureCacheData::CheckCustomTexture() 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); UploadToGPU(GL_UNSIGNED_BYTE, custom_width, custom_height, custom_image_data);
delete [] custom_image_data; delete [] custom_image_data;
@ -446,7 +443,7 @@ bool TextureCacheData::NeedsUpdate() {
bool TextureCacheData::Delete() bool TextureCacheData::Delete()
{ {
if (custom_load_in_progress) if (custom_load_in_progress > 0)
return false; return false;
if (pData) { if (pData) {
@ -736,11 +733,7 @@ TextureCacheData *getTextureCacheData(TSP tsp, TCW tcw) {
} }
else //create if not existing else //create if not existing
{ {
TextureCacheData tfc={0}; tf=&TexCache[key];
TexCache[key] = tfc;
tx=TexCache.find(key);
tf=&tx->second;
tf->tsp = tsp; tf->tsp = tsp;
tf->tcw = tcw; tf->tcw = tcw;
@ -800,11 +793,7 @@ text_info raw_GetTexture(TSP tsp, TCW tcw)
} }
else //create if not existing else //create if not existing
{ {
TextureCacheData tfc = { 0 }; tf = &TexCache[key];
TexCache[key] = tfc;
tx = TexCache.find(key);
tf = &tx->second;
tf->tsp = tsp; tf->tsp = tsp;
tf->tcw = tcw; 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 (width != gl.ofbo.width || height != gl.ofbo.height)
{ {
if (gl.ofbo.fbo != 0) free_output_framebuffer();
{
glDeleteFramebuffers(1, &gl.ofbo.fbo);
gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
glcache.DeleteTextures(1, &gl.ofbo.tex);
}
gl.ofbo.width = width; gl.ofbo.width = width;
gl.ofbo.height = height; gl.ofbo.height = height;
} }
@ -1037,15 +1020,25 @@ GLuint init_output_framebuffer(int width, int height)
else else
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// Create a texture for rendering to if (gl.gl_major < 3)
gl.ofbo.tex = glcache.GenTexture(); {
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex); // 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); 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_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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 // Create the framebuffer
glGenFramebuffers(1, &gl.ofbo.fbo); 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) if (!gl.is_gles || gl.GL_OES_packed_depth_stencil_supported)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl.ofbo.depthb); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl.ofbo.depthb);
// Attach the texture to the FBO // Attach the texture/renderbuffer to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0); 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 // Check that our FBO creation was successful
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
verify(uStatus == GL_FRAMEBUFFER_COMPLETE); 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 else
glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.fbo); glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.fbo);
@ -1082,7 +1082,15 @@ void free_output_framebuffer()
gl.ofbo.fbo = 0; gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb); glDeleteRenderbuffers(1, &gl.ofbo.depthb);
gl.ofbo.depthb = 0; gl.ofbo.depthb = 0;
glcache.DeleteTextures(1, &gl.ofbo.tex); if (gl.ofbo.tex != 0)
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;
}
} }
} }

View File

@ -67,6 +67,7 @@
#endif #endif
#include "gles.h" #include "gles.h"
#include "glcache.h"
// OpenGL Data // OpenGL Data
static char g_GlslVersionString[32] = ""; static char g_GlslVersionString[32] = "";
@ -127,28 +128,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
draw_data->ScaleClipRects(io.DisplayFramebufferScale); draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// Backup GL state // Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0); 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; bool clip_origin_lower_left = true;
#ifdef GL_CLIP_ORIGIN #ifdef GL_CLIP_ORIGIN
if (gl.gl_major >= 4 && glClipControl != NULL) 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 // (Re-)create the background texture and reserve space for it
if (g_BackgroundTexture != 0) if (g_BackgroundTexture != 0)
glDeleteTextures(1, &g_BackgroundTexture); glcache.DeleteTextures(1, &g_BackgroundTexture);
glGenTextures(1, &g_BackgroundTexture); g_BackgroundTexture = glcache.GenTexture();
glBindTexture(GL_TEXTURE_2D, g_BackgroundTexture); glcache.BindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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); 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 // 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 // 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); glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE); glcache.Disable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glcache.Disable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST); glcache.Enable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE #ifdef GL_POLYGON_MODE
if (glPolygonMode != NULL) if (glPolygonMode != NULL)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 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 }, { 0.0f, 0.0f, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
}; };
glUseProgram(g_ShaderHandle); glcache.UseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0); glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
if (gl.gl_major >= 3 && glBindSampler != NULL) 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) 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 // 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); 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) if (vao_handle != 0)
glDeleteVertexArrays(1, &vao_handle); 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() 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. 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 // Upload texture to graphics system
GLint last_texture; g_FontTexture = glcache.GenTexture();
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); glcache.BindTexture(GL_TEXTURE_2D, g_FontTexture);
glGenTextures(1, &g_FontTexture); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, g_FontTexture); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier // Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true; return true;
} }
@ -325,7 +278,7 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
if (g_FontTexture) if (g_FontTexture)
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture); glcache.DeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0; io.Fonts->TexID = 0;
g_FontTexture = 0; g_FontTexture = 0;
} }
@ -369,12 +322,6 @@ static bool CheckProgram(GLuint handle, const char* desc)
bool ImGui_ImplOpenGL3_CreateDeviceObjects() 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 // Parse GLSL version string
int glsl_version = 130; int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version); sscanf(g_GlslVersionString, "#version %d", &glsl_version);
@ -534,12 +481,6 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
ImGui_ImplOpenGL3_CreateFontsTexture(); 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; return true;
} }
@ -549,26 +490,23 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle); if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle);
g_VboHandle = g_ElementsHandle = 0; g_VboHandle = g_ElementsHandle = 0;
if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle); glcache.DeleteProgram(g_ShaderHandle);
if (g_VertHandle) glDeleteShader(g_VertHandle);
g_VertHandle = 0; g_VertHandle = 0;
if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle);
if (g_FragHandle) glDeleteShader(g_FragHandle);
g_FragHandle = 0; g_FragHandle = 0;
if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle);
g_ShaderHandle = 0; g_ShaderHandle = 0;
ImGui_ImplOpenGL3_DestroyFontsTexture(); ImGui_ImplOpenGL3_DestroyFontsTexture();
if (g_BackgroundTexture != 0) if (g_BackgroundTexture != 0)
glDeleteTextures(1, &g_BackgroundTexture); glcache.DeleteTextures(1, &g_BackgroundTexture);
g_BackgroundTexture = 0; g_BackgroundTexture = 0;
} }
void ImGui_ImplOpenGL3_DrawBackground() void ImGui_ImplOpenGL3_DrawBackground()
{ {
glcache.Disable(GL_SCISSOR_TEST);
glcache.ClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
if (g_BackgroundTexture != 0) if (g_BackgroundTexture != 0)
{ {
ImGuiIO& io = ImGui::GetIO(); 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::GetWindowDrawList()->AddImage((ImTextureID)(uintptr_t)g_BackgroundTexture, ImVec2(0, 0), io.DisplaySize, ImVec2(0, 1), ImVec2(1, 0), 0xffffffff);
ImGui::End(); ImGui::End();
} }
else
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
}
} }
ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data) ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
{ {
GLuint tex_id; GLuint tex_id = glcache.GenTexture();
glGenTextures(1, &tex_id); glcache.BindTexture(GL_TEXTURE_2D, tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(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); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 48, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
return reinterpret_cast<ImTextureID>(tex_id); 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) void ImGui_ImplOpenGL3_DeleteVmuTexture(ImTextureID tex_id)
{ {
glDeleteTextures(1, &(GLuint &)tex_id); glcache.DeleteTextures(1, &(GLuint &)tex_id);
} }

View File

@ -39,7 +39,9 @@
#include "linux-dist/main.h" // FIXME for kcode[] #include "linux-dist/main.h" // FIXME for kcode[]
#include "gui_util.h" #include "gui_util.h"
#include "gui_android.h" #include "gui_android.h"
#include "version.h" #include "version/version.h"
#include "oslib/audiostream.h"
extern void dc_loadstate(); extern void dc_loadstate();
extern void dc_savestate(); extern void dc_savestate();
@ -299,7 +301,9 @@ static void gui_display_commands()
if (!settings_opening) if (!settings_opening)
ImGui_ImplOpenGL3_DrawBackground(); 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::SetNextWindowPos(ImVec2(screen_width / 2.f, screen_height / 2.f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(330 * scaling, 0)); 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 void gui_display_settings()
{ {
static bool maple_devices_changed;
ImGui_Impl_NewFrame(); ImGui_Impl_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
@ -644,10 +650,14 @@ static void gui_display_settings()
gui_state = Commands; gui_state = Commands;
else else
gui_state = Main; gui_state = Main;
if (maple_devices_changed)
{
maple_devices_changed = false;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST #if DC_PLATFORM == DC_PLATFORM_DREAMCAST
maple_ReconnectDevices(); maple_ReconnectDevices();
reset_vmus(); reset_vmus();
#endif #endif
}
SaveSettings(); SaveSettings();
} }
if (game_started) if (game_started)
@ -801,13 +811,14 @@ static void gui_display_settings()
if (ImGui::BeginTabItem("Controls")) if (ImGui::BeginTabItem("Controls"))
{ {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding); 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)) if (ImGui::CollapsingHeader("Dreamcast Devices", ImGuiTreeNodeFlags_DefaultOpen))
{ {
for (int bus = 0; bus < MAPLE_PORTS; bus++) for (int bus = 0; bus < MAPLE_PORTS; bus++)
{ {
ImGui::Text("Device %c", bus + 'A'); ImGui::Text("Device %c", bus + 'A');
ImGui::SameLine(); ImGui::SameLine();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
char device_name[32]; char device_name[32];
sprintf(device_name, "##device%d", bus); sprintf(device_name, "##device%d", bus);
float w = ImGui::CalcItemWidth() / 3; 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); bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i);
if (ImGui::Selectable(maple_device_types[i], &is_selected)) if (ImGui::Selectable(maple_device_types[i], &is_selected))
{
settings.input.maple_devices[bus] = maple_device_type_from_index(i); settings.input.maple_devices[bus] = maple_device_type_from_index(i);
maple_devices_changed = true;
}
if (is_selected) if (is_selected)
ImGui::SetItemDefaultFocus(); 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); 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)) if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected))
{
settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i); settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i);
maple_devices_changed = true;
}
if (is_selected) if (is_selected)
ImGui::SetItemDefaultFocus(); ImGui::SetItemDefaultFocus();
} }
@ -845,6 +862,10 @@ static void gui_display_settings()
ImGui::PopID(); ImGui::PopID();
} }
ImGui::PopItemWidth(); 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(); ImGui::Spacing();
} }
@ -945,15 +966,27 @@ static void gui_display_settings()
ImGui::Checkbox("Shadows", &settings.rend.ModifierVolumes); ImGui::Checkbox("Shadows", &settings.rend.ModifierVolumes);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Enable modifier volumes, usually used for shadows"); 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::Checkbox("Widescreen", &settings.rend.WideScreen);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas"); 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::Checkbox("Show FPS Counter", &settings.rend.ShowFPS);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Show on-screen frame/sec counter"); 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::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better"); 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::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Number of frames to skip between two actually rendered frames"); 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::Checkbox("Disable Sound", &settings.aica.NoSound);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Disable the emulator sound output"); 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::Checkbox("Enable DSP", &settings.aica.NoBatch);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Enable the Dreamcast Digital Sound Processor. Only recommended on fast and arm64 platforms"); 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"); ShowHelpMarker("Do not optimize integer division. Recommended");
ImGui::Checkbox("Unstable Optimizations", &settings.dynarec.unstable_opt); ImGui::Checkbox("Unstable Optimizations", &settings.dynarec.unstable_opt);
ImGui::SameLine(); 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::Checkbox("Idle Skip", &settings.dynarec.idleskip);
ImGui::SameLine(); ImGui::SameLine();
ShowHelpMarker("Skip wait loops. Recommended"); 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)) if (ImGui::CollapsingHeader("Other", ImGuiTreeNodeFlags_DefaultOpen))
{ {
@ -1230,6 +1328,7 @@ static void gui_start_game(const std::string& path)
{ {
gui_state = Main; gui_state = Main;
game_started = false; game_started = false;
cfgSetVirtual("config", "image", "");
switch (rc) { switch (rc) {
case -3: case -3:
error_msg = "Audio/video initialization failed"; error_msg = "Audio/video initialization failed";
@ -1387,24 +1486,6 @@ void gui_display_ui()
gui_state = Closed; 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 float LastFPSTime;
static int lastFrameCount = 0; static int lastFrameCount = 0;
static float fps = -1; static float fps = -1;
@ -1452,26 +1533,32 @@ void gui_display_osd()
if (osd_message.empty()) if (osd_message.empty())
{ {
message = getFPSNotification(); message = getFPSNotification();
if (message.empty())
return;
} }
else else
message = osd_message; message = osd_message;
ImGui_Impl_NewFrame(); if (!message.empty() || settings.rend.FloatVMUs)
ImGui::NewFrame(); {
ImGui_Impl_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0); if (!message.empty())
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner {
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 ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground); | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(1.5); ImGui::SetWindowFontScale(1.5);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str()); ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
ImGui::End(); ImGui::End();
}
if (settings.rend.FloatVMUs)
display_vmus();
ImGui::Render(); ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
} }
void gui_open_onboarding() void gui_open_onboarding()

View File

@ -39,7 +39,7 @@
#undef _CRT_SECURE_NO_DEPRECATE #undef _CRT_SECURE_NO_DEPRECATE
#endif #endif
#define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE
//unnamed struncts/unions //unnamed struncts/unions
#pragma warning( disable : 4201) #pragma warning( disable : 4201)
@ -123,7 +123,7 @@ enum HollyInterruptType
}; };
enum HollyInterruptID enum HollyInterruptID
{ {
// asic9a /sh4 external holly normal [internal] // asic9a /sh4 external holly normal [internal]
holly_RENDER_DONE_vd = holly_nrm | 0, //bit 0 = End of Render interrupt : Video 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 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_SCANINT1 = holly_nrm | 3, //bit 3 = V Blank-in interrupt
holly_SCANINT2 = holly_nrm | 4, //bit 4 = V Blank-out interrupt holly_SCANINT2 = holly_nrm | 4, //bit 4 = V Blank-out interrupt
holly_HBLank = holly_nrm | 5, //bit 5 = H Blank-in 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_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_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_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_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_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 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_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_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_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_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_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_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_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 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 23 = G2 : AICA-DMA Time out
//bit 24 = G2 : Ext-DMA1 Time out //bit 24 = G2 : Ext-DMA1 Time out
//bit 25 = G2 : Ext-DMA2 Time out //bit 25 = G2 : Ext-DMA2 Time out
//bit 26 = G2 : Dev-DMA Time out //bit 26 = G2 : Dev-DMA Time out
//bit 27 = G2 : Time out in CPU accessing //bit 27 = G2 : Time out in CPU accessing
}; };
@ -200,7 +200,7 @@ struct vram_block
u32 end; u32 end;
u32 len; u32 len;
u32 type; u32 type;
void* userdata; void* userdata;
}; };
@ -229,7 +229,7 @@ struct NDC_WINDOW_RECT
//****************************************************** //******************************************************
//*********************** PowerVR ********************** //*********************** PowerVR **********************
//****************************************************** //******************************************************
void libCore_vramlock_Unlock_block (vram_block* block); void libCore_vramlock_Unlock_block (vram_block* block);
void libCore_vramlock_Unlock_block_wb (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); vram_block* libCore_vramlock_Lock(u32 start_offset,u32 end_offset,void* userdata);
@ -246,7 +246,7 @@ enum DiscType
CdRom_XA=0x20, CdRom_XA=0x20,
CdRom_Extra=0x30, CdRom_Extra=0x30,
CdRom_CDI=0x40, CdRom_CDI=0x40,
GdRom=0x80, GdRom=0x80,
NoDisk=0x1, //These are a bit hacky .. but work for now ... NoDisk=0x1, //These are a bit hacky .. but work for now ...
Open=0x2, //tray is open :) Open=0x2, //tray is open :)
@ -576,7 +576,7 @@ enum RegIO
RIO_RO = REG_RO | REG_WF, RIO_RO = REG_RO | REG_WF,
RIO_RO_FUNC = REG_RO | REG_RF | REG_WF, RIO_RO_FUNC = REG_RO | REG_RF | REG_WF,
RIO_CONST = REG_RO | 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 RIO_NO_ACCESS = REG_WF | REG_RF | REG_NO_ACCESS
}; };
@ -601,6 +601,11 @@ struct RegisterStruct
u32 flags; //Access flags ! u32 flags; //Access flags !
}; };
enum SmcCheckEnum {
FullCheck = 0,
FastCheck = 1,
NoCheck = 2
};
struct settings_t struct settings_t
{ {
@ -627,7 +632,11 @@ struct settings_t
f32 ExtraDepthScale; f32 ExtraDepthScale;
bool CustomTextures; bool CustomTextures;
bool DumpTextures; 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; } rend;
struct struct
@ -637,8 +646,9 @@ struct settings_t
bool unstable_opt; bool unstable_opt;
bool safemode; bool safemode;
bool disable_nvmem; bool disable_nvmem;
SmcCheckEnum SmcCheckLevel;
} dynarec; } dynarec;
struct struct
{ {
u32 run_counts; u32 run_counts;
@ -647,7 +657,6 @@ struct settings_t
struct struct
{ {
u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV
u32 RTC;
u32 region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default 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 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 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; bool NoSound;
} aica; } aica;
struct{
std::string backend;
} audio;
#if USE_OMX #if USE_OMX
struct struct
{ {
@ -699,7 +711,7 @@ struct settings_t
{ {
u32 ta_skip; u32 ta_skip;
u32 rend; u32 rend;
u32 MaxThreads; u32 MaxThreads;
bool SynchronousRender; bool SynchronousRender;
} pvr; } pvr;
@ -742,7 +754,7 @@ static inline void do_nada(...) { }
#ifdef _ANDROID #ifdef _ANDROID
#include <android/log.h> #include <android/log.h>
#ifdef printf #ifdef printf
#undef printf #undef printf
#endif #endif
@ -849,7 +861,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \ else if (sz==2) \
return *(u16*)&arr[addr]; \ return *(u16*)&arr[addr]; \
else if (sz==4) \ else if (sz==4) \
return *(u32*)&arr[addr];} return *(u32*)&arr[addr];}
#define WriteMemArr(arr,addr,data,sz) \ #define WriteMemArr(arr,addr,data,sz) \
{if(sz==1) \ {if(sz==1) \
@ -857,7 +869,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \ else if (sz==2) \
{*(u16*)&arr[addr]=(u16)data;} \ {*(u16*)&arr[addr]=(u16)data;} \
else if (sz==4) \ else if (sz==4) \
{*(u32*)&arr[addr]=data;}} {*(u32*)&arr[addr]=data;}}
#define WriteMemArrRet(arr,addr,data,sz) \ #define WriteMemArrRet(arr,addr,data,sz) \
{if(sz==1) \ {if(sz==1) \
@ -865,7 +877,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \ else if (sz==2) \
{*(u16*)&arr[addr]=(u16)data;return;} \ {*(u16*)&arr[addr]=(u16)data;return;} \
else if (sz==4) \ else if (sz==4) \
{*(u32*)&arr[addr]=data;return;}} {*(u32*)&arr[addr]=data;return;}}
struct OnLoad struct OnLoad
{ {

View File

@ -188,8 +188,6 @@ u16 kcode[4] = { 0xffff, 0xffff, 0xffff, 0xffff };
u32 vks[4]; u32 vks[4];
s8 joyx[4],joyy[4]; s8 joyx[4],joyy[4];
u8 rt[4],lt[4]; u8 rt[4],lt[4];
extern bool coin_chute;
extern bool naomi_test_button;
// Mouse // Mouse
extern s32 mo_x_abs; extern s32 mo_x_abs;
extern s32 mo_y_abs; extern s32 mo_y_abs;
@ -220,12 +218,6 @@ void UpdateInputState(u32 port)
std::shared_ptr<XInputGamepadDevice> gamepad = XInputGamepadDevice::GetXInputDevice(port); std::shared_ptr<XInputGamepadDevice> gamepad = XInputGamepadDevice::GetXInputDevice(port);
if (gamepad != NULL) if (gamepad != NULL)
gamepad->ReadInput(); 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 // Windows class name to register
@ -772,6 +764,7 @@ cThread::cThread(ThreadEntryFP* function,void* prm)
void cThread::Start() void cThread::Start()
{ {
verify(hThread == NULL);
hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Entry,param,0,NULL); hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Entry,param,0,NULL);
ResumeThread(hThread); ResumeThread(hThread);
} }
@ -779,6 +772,8 @@ void cThread::Start()
void cThread::WaitToEnd() void cThread::WaitToEnd()
{ {
WaitForSingleObject(hThread,INFINITE); WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
hThread = NULL;
} }
//End thread class //End thread class

View File

@ -52,5 +52,56 @@
android:scheme="file" /> android:scheme="file" />
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>

View File

@ -61,6 +61,16 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </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 <provider
android:name="android.support.v4.content.FileProvider" android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider" android:authorities="${applicationId}.provider"

View File

@ -228,22 +228,24 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (event.getRepeatCount() == 0) {
if (!JNIdc.guiIsOpen()) { if (keyCode == KeyEvent.KEYCODE_BACK) {
showMenu(); if (!JNIdc.guiIsOpen()) {
return true; showMenu();
return true;
}
else if (JNIdc.guiIsContentBrowser()) {
finish();
return true;
}
} }
else if (JNIdc.guiIsContentBrowser()) { if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
finish();
return true; return true;
}
}
if (InputDeviceManager.getInstance().joystickButtonEvent(event.getDeviceId(), keyCode, true))
return true;
if (ViewConfiguration.get(this).hasPermanentMenuKey()) { if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
if (keyCode == KeyEvent.KEYCODE_MENU) { if (keyCode == KeyEvent.KEYCODE_MENU) {
return showMenu(); return showMenu();
}
} }
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
@ -296,7 +298,7 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
} }
// Called from native code // Called from native code
private void generateErrorLog() { protected void generateErrorLog() {
try { try {
new GenerateLogs(this).execute(getFilesDir().getAbsolutePath()); new GenerateLogs(this).execute(getFilesDir().getAbsolutePath());
} catch (RuntimeException e) { } catch (RuntimeException e) {

View File

@ -21,8 +21,7 @@ public final class JNIdc
public static native int send(int cmd, int opt); public static native int send(int cmd, int opt);
public static native int data(int cmd, byte[] data); public static native int data(int cmd, byte[] data);
public static native void rendinitNative(Surface surface, int w, int h); public static native void rendinitNative(Surface surface);
public static native boolean rendframeNative();
public static native void rendinitJava(int w, int h); public static native void rendinitJava(int w, int h);
public static native boolean rendframeJava(); public static native boolean rendframeJava();
public static native void rendtermJava(); public static native void rendtermJava();

View File

@ -19,8 +19,6 @@ import com.reicast.emulator.NativeGLActivity;
import com.reicast.emulator.config.Config; import com.reicast.emulator.config.Config;
public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback { public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback {
private Handler handler = new Handler();
private boolean surfaceReady = false; private boolean surfaceReady = false;
private boolean paused = false; private boolean paused = false;
VirtualJoystickDelegate vjoyDelegate; VirtualJoystickDelegate vjoyDelegate;
@ -66,23 +64,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
if (NativeGLActivity.syms != null) if (NativeGLActivity.syms != null)
JNIdc.data(1, NativeGLActivity.syms); 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 @Override
@ -111,7 +92,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) { public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int w, int h) {
//Log.i("reicast", "NativeGLView.surfaceChanged: " + w + "x" + h); //Log.i("reicast", "NativeGLView.surfaceChanged: " + w + "x" + h);
surfaceReady = true; surfaceReady = true;
JNIdc.rendinitNative(surfaceHolder.getSurface(), w, h); JNIdc.rendinitNative(surfaceHolder.getSurface());
Emulator.getCurrentActivity().handleStateChange(false); Emulator.getCurrentActivity().handleStateChange(false);
} }
@ -119,7 +100,7 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
public void surfaceDestroyed(SurfaceHolder surfaceHolder) { public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//Log.i("reicast", "NativeGLView.surfaceDestroyed"); //Log.i("reicast", "NativeGLView.surfaceDestroyed");
surfaceReady = false; surfaceReady = false;
JNIdc.rendinitNative(null, 0, 0); JNIdc.rendinitNative(null);
Emulator.getCurrentActivity().handleStateChange(true); Emulator.getCurrentActivity().handleStateChange(true);
} }
@ -142,7 +123,6 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
requestFocus(); requestFocus();
JNIdc.resume(); JNIdc.resume();
} }
startRendering();
} }
@TargetApi(19) @TargetApi(19)

View File

@ -15,7 +15,7 @@ import com.reicast.emulator.periph.InputDeviceManager;
import com.reicast.emulator.periph.VJoy; import com.reicast.emulator.periph.VJoy;
public class VirtualJoystickDelegate { public class VirtualJoystickDelegate {
private Vibrator vib; private VibratorThread vibratorThread;
private boolean editVjoyMode = false; private boolean editVjoyMode = false;
private int selectedVjoyElement = -1; private int selectedVjoyElement = -1;
@ -39,7 +39,10 @@ public class VirtualJoystickDelegate {
public VirtualJoystickDelegate(View view) { public VirtualJoystickDelegate(View view) {
this.view = view; this.view = view;
this.context = view.getContext(); this.context = view.getContext();
vib = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
vibratorThread = new VibratorThread(context);
vibratorThread.start();
readCustomVjoyValues(); readCustomVjoyValues();
scaleGestureDetector = new ScaleGestureDetector(context, new OscOnScaleGestureListener()); 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 (y > vjoy[j][1] && y <= (vjoy[j][1] + vjoy[j][3])) {
if (vjoy[j][4] >= -2) { if (vjoy[j][4] >= -2) {
if (vjoy[j][5] == 0) if (vjoy[j][5] == 0)
if (!editVjoyMode && Emulator.vibrationDuration > 0) if (!editVjoyMode) {
vib.vibrate(Emulator.vibrationDuration); vibratorThread.vibrate();
}
vjoy[j][5] = 2; vjoy[j][5] = 2;
} }
@ -397,4 +401,51 @@ public class VirtualJoystickDelegate {
selectedVjoyElement = -1; 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();
}
}
}
}
} }

View File

@ -20,7 +20,7 @@
#include "hw/maple/maple_devs.h" #include "hw/maple/maple_devs.h"
#include "hw/maple/maple_if.h" #include "hw/maple/maple_if.h"
#include "hw/naomi/naomi_cart.h" #include "hw/naomi/naomi_cart.h"
#include "oslib/audiobackend_android.h" #include "oslib/audiostream.h"
#include "imgread/common.h" #include "imgread/common.h"
#include "rend/gui.h" #include "rend/gui.h"
#include "cfg/cfg.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_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 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 void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface) __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_rendinitJava(JNIEnv *env, jobject obj, jint w, jint h) __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 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"))); 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 gl_swap();
extern void egl_stealcntx(); 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) render_running = true;
return false;
if (!egl_makecurrent()) rend_init_renderer();
return false;
jboolean ret = (jboolean)rend_single_frame(); while (render_running) {
if (ret) if (render_reinit)
gl_swap(); {
return ret; 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) if (render_thread.hThread != NULL)
{ {
egl_makecurrent(); if (surface == NULL)
rend_term_renderer(); {
ANativeWindow_release(g_window); render_running = false;
g_window = NULL; render_thread.WaitToEnd();
} }
if (surface != NULL) else
{ render_reinit = true;
}
else if (surface != NULL)
{
g_window = ANativeWindow_fromSurface(env, surface); g_window = ANativeWindow_fromSurface(env, surface);
rend_init_renderer(); render_thread.Start();
screen_width = width; }
screen_height = height;
}
} }
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv * env, jobject obj, jint width, jint height) 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 &androidaudio_term
}; };
static bool android = RegisterAudioBackend(&audiobackend_android);
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance) JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance)
{ {
if (g_audioBackend != NULL) if (g_audioBackend != NULL)
@ -568,7 +592,7 @@ void os_DebugBreak()
raise(SIGABRT); raise(SIGABRT);
//pthread_exit(NULL); //pthread_exit(NULL);
// Attach debugger here to figure out what went wrong // Attach debugger here to figure out what went wrong
for(;;) ; for(;;) ;
} }

View File

@ -3,7 +3,7 @@
android:name="com.reicast.emulator.Emulator"> android:name="com.reicast.emulator.Emulator">
<activity <activity
android:name="com.reicast.emulator.MainActivity"> android:name="com.reicast.emulator.NativeGLActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -62,5 +62,66 @@
android:scheme="file" /> android:scheme="file" />
</intent-filter> </intent-filter>
</activity> </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> </application>
</manifest> </manifest>