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);

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
}
else if (settings.input.JammaSetup == 1)
{
// 4 players
mcfg_Create(MDT_SegaController, 2, 5);
mcfg_Create(MDT_SegaController, 3, 5);
}
else if (settings.input.JammaSetup == 5)
{
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3 // Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
// Sports Shooting same // Sports Shooting same
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3 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,7 +245,7 @@ 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);
@ -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]; u32 keycode = ~kcode[first_player + player];
for (int i = 0; i < 16; i++)
{
if ((keycode & (1 << i)) != 0)
buttons[player] |= naomi_button_mapping[i];
} }
}
LOGJVS("btns ");
JVS_OUT((buttons[0] & NAOMI_TEST_KEY) ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
for (int player = 0; player < buffer_in[cmdi + 1]; player++) for (int player = 0; player < buffer_in[cmdi + 1]; player++)
{ {
u8 *cur_btns = &buttons[(first_player + player) * 2]; u16 cur_btns = first_player + player < ARRAY_SIZE(buttons) ? buttons[first_player + player] : 0;
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]); LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns >> 8);
JVS_OUT(cur_btns[0]); JVS_OUT(cur_btns >> 8);
if (buffer_in[cmdi + 2] == 2) if (buffer_in[cmdi + 2] == 2)
{ {
LOGJVS("%02x ", cur_btns[1]); LOGJVS("%02x ", cur_btns & 0xFF);
JVS_OUT(cur_btns[1]); 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;
} }
@ -2399,28 +2466,44 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
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:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_sega_controller(); 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

@ -87,6 +87,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,13 +128,15 @@ u32 emit_FreeSpace()
} }
bool DoCheck(u32 pc) SmcCheckEnum DoCheck(u32 pc)
{ {
switch (settings.dynarec.SmcCheckLevel) {
// Heuristic-elimintaed FastChecks
case NoCheck: {
if (IsOnRam(pc)) if (IsOnRam(pc))
{ {
if (!settings.dynarec.unstable_opt)
return true;
pc&=0xFFFFFF; pc&=0xFFFFFF;
switch(pc) switch(pc)
{ {
@ -140,13 +151,28 @@ bool DoCheck(u32 pc)
case 0x41860e: case 0x41860e:
return true; return FastCheck;
default: default:
return false; return NoCheck;
} }
} }
return false; 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;
}
} }
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);
if (settings.dynarec.SmcCheckLevel != FullCheck) {
//TODO: Add skip/check vectors for Shikigami No Shiro II (uses ICI frequently)
//which game is 0xAC13DBF8 from ?
if (curr_pc != 0xAC13DBF8)
{ {
//printf("Sh4: i-cache invalidation %08X\n",curr_pc); printf("Sh4: code cache clear (ICI) pc: %08X\n",curr_pc);
// Shikigami No Shiro II sets ICI frequently sh4_cpu.ResetCache();
// Any reason to flush the dynarec cache for this? }
//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

@ -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

@ -12,7 +12,7 @@
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>
@ -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>
@ -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>
@ -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,40 +76,13 @@ 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")
{ {
@ -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)) {
@ -178,22 +183,20 @@ void InitAudio()
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();
} }

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,8 +2114,25 @@ 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:
break;
case FastCheck: {
MOV32(r0,block->addr);
u32* ptr=(u32*)GetMemPtr(block->addr,4);
if (ptr != NULL)
{ {
MOV32(r2,(u32)ptr);
LDR(r2,r2,0);
MOV32(r1,*ptr);
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
}
}
break;
case FullCheck: {
s32 sz = block->sh4_code_size; s32 sz = block->sh4_code_size;
u32 addr = block->addr; u32 addr = block->addr;
MOV32(r0,addr); MOV32(r0,addr);
@ -2125,29 +2142,41 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
if (sz > 2) if (sz > 2)
{ {
u32* ptr=(u32*)GetMemPtr(addr,4); u32* ptr=(u32*)GetMemPtr(addr,4);
if (ptr != NULL)
{
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; addr += 4;
sz -= 4; sz -= 4;
} }
else else
{ {
u16* ptr = (u16 *)GetMemPtr(addr, 2); u16* ptr = (u16 *)GetMemPtr(addr, 2);
if (ptr != NULL)
{
MOV32(r2, (u32)ptr); MOV32(r2, (u32)ptr);
LDRH(r2, r2, 0, AL); LDRH(r2, r2, 0, AL);
MOVW(r1, *ptr, AL); MOVW(r1, *ptr, AL);
CMP(r1, r2); CMP(r1, r2);
JUMP((u32)ngen_blockcheckfail, CC_NE); JUMP((u32)ngen_blockcheckfail, CC_NE);
}
addr += 2; addr += 2;
sz -= 2; sz -= 2;
} }
} }
} }
break;
default: {
die("unhandled smc_checks");
}
}
u32 cyc=block->guest_cycles; u32 cyc=block->guest_cycles;
if (!is_i8r4(cyc)) if (!is_i8r4(cyc))

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,16 +1292,33 @@ 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;
switch (smc_checks) {
case NoCheck:
return;
case FastCheck: {
u8* ptr = GetMemPtr(block->addr, 4);
if (ptr == NULL)
return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
Ldr(w10, MemOperand(x9));
Ldr(w11, *(u32*)ptr);
Cmp(w10, w11);
B(eq, &blockcheck_success);
}
break;
case FullCheck: {
s32 sz = block->sh4_code_size;
u8* ptr = GetMemPtr(block->addr, sz); u8* ptr = GetMemPtr(block->addr, sz);
if (ptr == NULL) if (ptr == NULL)
// FIXME Can a block cross a RAM / non-RAM boundary??
return; return;
Ldr(x9, reinterpret_cast<uintptr_t>(ptr)); Ldr(x9, reinterpret_cast<uintptr_t>(ptr));
@ -1335,6 +1352,12 @@ private:
B(ne, &blockcheck_fail); B(ne, &blockcheck_fail);
} }
B(&blockcheck_success); B(&blockcheck_success);
}
break;
default:
die("unhandled smc_checks");
}
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,16 +1090,35 @@ 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);
switch (smc_checks) {
case NoCheck:
return;
case FastCheck: {
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
mov(call_regs[0], block->addr);
mov(rax, reinterpret_cast<uintptr_t>(ptr));
mov(edx, *(u32*)ptr);
cmp(dword[rax], edx);
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
}
}
break;
case FullCheck: {
s32 sz=block->sh4_code_size; s32 sz=block->sh4_code_size;
u32 sa=block->addr; u32 sa=block->addr;
while (sz > 0)
{
void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz); void* ptr = (void*)GetMemPtr(sa, sz > 8 ? 8 : sz);
if (ptr) if (ptr)
{
mov(call_regs[0], block->addr);
while (sz > 0)
{ {
mov(rax, reinterpret_cast<uintptr_t>(ptr)); mov(rax, reinterpret_cast<uintptr_t>(ptr));
@ -1123,9 +1141,15 @@ private:
sa += 2; sa += 2;
} }
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail)); 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,8 +229,24 @@ 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)
{ {
switch (smc_checks) {
case NoCheck:
break;
case FastCheck: {
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
x86e->Emit(op_cmp32, ptr, *(u32*)ptr);
x86e->Emit(op_jne, x86_ptr_imm(ngen_blockcheckfail));
}
}
break;
case FullCheck: {
s32 sz=block->sh4_code_size; s32 sz=block->sh4_code_size;
u32 sa=block->addr; u32 sa=block->addr;
while(sz>0) while(sz>0)
@ -242,16 +258,21 @@ void CheckBlock(RuntimeBlockInfo* block,x86_ptr_imm place)
x86e->Emit(op_cmp16,ptr,*(u16*)ptr); x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
else else
x86e->Emit(op_cmp32,ptr,*(u32*)ptr); x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
x86e->Emit(op_jne,place); x86e->Emit(op_jne,x86_ptr_imm(ngen_blockcheckfail));
} }
sz-=4; sz-=4;
sa+=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)
{
shader->cp_AlphaTest = cp_AlphaTest;
shader->pp_ClipTestMode = pp_ClipTestMode;
shader->pp_Texture = pp_Texture;
shader->pp_UseAlpha = pp_UseAlpha;
shader->pp_IgnoreTexA = pp_IgnoreTexA;
shader->pp_ShadInstr = pp_ShadInstr;
shader->pp_Offset = pp_Offset;
shader->pp_FogCtrl = pp_FogCtrl;
shader->pp_TwoVolumes = pp_TwoVolumes;
shader->pp_DepthFunc = pp_DepthFunc;
shader->pp_Gouraud = pp_Gouraud;
shader->pp_BumpMap = pp_BumpMap;
shader->fog_clamping = fog_clamping;
shader->pass = pass;
gl4CompilePipelineShader(shader, settings.rend.Rotate90);
} }
static void setCurrentShader(u32 cp_AlphaTest, u32 pp_ClipTestMode, return shader;
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
{
int shaderId = gl4GetProgramID(cp_AlphaTest,
pp_ClipTestMode + 1,
pp_Texture,
pp_UseAlpha,
pp_IgnoreTexA,
pp_ShadInstr,
pp_Offset,
pp_FogCtrl,
pp_TwoVolumes,
pp_DepthFunc,
pp_Gouraud,
pp_BumpMap,
fog_clamping,
pass);
CurrentShader = gl4.getShader(shaderId);
if (CurrentShader->program == -1) {
CurrentShader->cp_AlphaTest = cp_AlphaTest;
CurrentShader->pp_ClipTestMode = pp_ClipTestMode;
CurrentShader->pp_Texture = pp_Texture;
CurrentShader->pp_UseAlpha = pp_UseAlpha;
CurrentShader->pp_IgnoreTexA = pp_IgnoreTexA;
CurrentShader->pp_ShadInstr = pp_ShadInstr;
CurrentShader->pp_Offset = pp_Offset;
CurrentShader->pp_FogCtrl = pp_FogCtrl;
CurrentShader->pp_TwoVolumes = pp_TwoVolumes;
CurrentShader->pp_DepthFunc = pp_DepthFunc;
CurrentShader->pp_Gouraud = pp_Gouraud;
CurrentShader->pp_BumpMap = pp_BumpMap;
CurrentShader->fog_clamping = fog_clamping;
CurrentShader->pass = pass;
gl4CompilePipelineShader(CurrentShader);
}
} }
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);
float dc2s_scale_h;
float ds2s_offs_x;
if (is_rtt)
{
gl4ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
gl4ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
gl4ShaderUniforms.scale_coefs[2] = 1;
gl4ShaderUniforms.scale_coefs[3] = 1;
}
else
{
if (settings.rend.Rotate90)
{
dc2s_scale_h = screen_height / 640.0;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2;
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
gl4ShaderUniforms.scale_coefs[3] = 1;
}
else
{
dc2s_scale_h = screen_height / 480.0;
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2;
//-1 -> too much to left //-1 -> too much to left
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x); gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
gl4ShaderUniforms.scale_coefs[1] = (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512 gl4ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling); gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1); 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,8 +50,14 @@ void CustomTexture::LoaderThread()
if (texture != NULL) if (texture != NULL)
{ {
// FIXME texture may have been deleted. Need to detect this.
texture->ComputeHash(); texture->ComputeHash();
if (texture->custom_image_data != NULL)
{
delete [] texture->custom_image_data;
texture->custom_image_data = NULL;
}
if (!texture->dirty)
{
int width, height; int width, height;
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height); u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
if (image_data == NULL) if (image_data == NULL)
@ -60,13 +66,12 @@ void CustomTexture::LoaderThread()
} }
if (image_data != NULL) if (image_data != NULL)
{ {
if (texture->custom_image_data != NULL)
delete [] texture->custom_image_data;
texture->custom_width = width; texture->custom_width = width;
texture->custom_height = height; texture->custom_height = height;
texture->custom_image_data = image_data; 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 dc2s_scale_h;
float ds2s_offs_x;
float screen_stretching = settings.rend.ScreenStretching / 100.f;
if (settings.rend.Rotate90)
{
float t = cex;
cex = cey;
cey = 640 - csx;
csx = csy;
csy = 640 - t;
dc2s_scale_h = screen_height / 640.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0 * screen_stretching) / 2;
}
else
{
float t = cey; float t = cey;
cey = 480 - csy; cey = 480 - csy;
csy = 480 - t; csy = 480 - t;
float dc2s_scale_h = screen_height / 480.0f; dc2s_scale_h = screen_height / 480.0f;
float ds2s_offs_x = (screen_width - dc2s_scale_h * 640) / 2; ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2;
csx = csx * dc2s_scale_h + ds2s_offs_x; }
cex = cex * dc2s_scale_h + ds2s_offs_x; 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,
gp->tsp.FogCtrl, fog_ctrl,
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)
CompilePipelineShader(CurrentShader);
else
{
glcache.UseProgram(CurrentShader->program); glcache.UseProgram(CurrentShader->program);
ShaderUniforms.Set(CurrentShader); if (CurrentShader->trilinear_alpha != -1)
} glUniform1f(CurrentShader->trilinear_alpha, ShaderUniforms.trilinear_alpha);
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)
CompilePipelineShader(shader);
else
{
glcache.UseProgram(shader->program); 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);
float dc2s_scale_h;
float ds2s_offs_x;
if (is_rtt)
{
ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2] = 1;
ShaderUniforms.scale_coefs[3] = 1;
}
else
{
if (settings.rend.Rotate90)
{
dc2s_scale_h = screen_height / 640.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3] = 1;
}
else
{
dc2s_scale_h = screen_height / 480.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3] = -1;
}
//-1 -> too much to left //-1 -> too much to left
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x); }
ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1);
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,6 +1020,8 @@ 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);
if (gl.gl_major < 3)
{
// Create a texture for rendering to // Create a texture for rendering to
gl.ofbo.tex = glcache.GenTexture(); gl.ofbo.tex = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex); glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
@ -1046,6 +1031,14 @@ GLuint init_output_framebuffer(int width, int height)
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
if (gl.gl_major < 3)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0); 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;
if (gl.ofbo.tex != 0)
{
glcache.DeleteTextures(1, &gl.ofbo.tex); glcache.DeleteTextures(1, &gl.ofbo.tex);
gl.ofbo.tex = 0; 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,6 +301,8 @@ static void gui_display_commands()
if (!settings_opening) if (!settings_opening)
ImGui_ImplOpenGL3_DrawBackground(); ImGui_ImplOpenGL3_DrawBackground();
if (!settings.rend.FloatVMUs)
// If floating VMUs, they are already visible on the background
display_vmus(); 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));
@ -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,15 +1533,17 @@ 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;
if (!message.empty() || settings.rend.FloatVMUs)
{
ImGui_Impl_NewFrame(); ImGui_Impl_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
if (!message.empty())
{
ImGui::SetNextWindowBgAlpha(0); ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
@ -1469,10 +1552,14 @@ void gui_display_osd()
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

@ -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
{ {
@ -628,6 +633,10 @@ struct settings_t
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,6 +646,7 @@ 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
@ -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
{ {

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,6 +228,7 @@ 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 (event.getRepeatCount() == 0) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (!JNIdc.guiIsOpen()) { if (!JNIdc.guiIsOpen()) {
showMenu(); showMenu();
@ -246,6 +247,7 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
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,34 +403,56 @@ 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;
rend_init_renderer();
while (render_running) {
if (render_reinit)
{
render_reinit = false;
rend_init_renderer();
}
else
if (!egl_makecurrent()) if (!egl_makecurrent())
return false; break;;
jboolean ret = (jboolean)rend_single_frame();
bool ret = rend_single_frame();
if (ret) if (ret)
gl_swap(); gl_swap();
return ret;
} }
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height)
{
if (g_window != NULL)
{
egl_makecurrent(); egl_makecurrent();
rend_term_renderer(); rend_term_renderer();
ANativeWindow_release(g_window); ANativeWindow_release(g_window);
g_window = NULL; g_window = NULL;
render_running = false;
return NULL;
} }
if (surface != NULL)
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 (render_thread.hThread != NULL)
{
if (surface == NULL)
{
render_running = false;
render_thread.WaitToEnd();
}
else
render_reinit = true;
}
else if (surface != NULL)
{ {
g_window = ANativeWindow_fromSurface(env, surface); g_window = ANativeWindow_fromSurface(env, surface);
rend_init_renderer(); render_thread.Start();
screen_width = width;
screen_height = 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)

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>