Merge branch 'master' into fh/win32-winresize
This commit is contained in:
commit
3d1b82854e
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "hw/naomi/naomi.h"
|
#include "hw/naomi/naomi.h"
|
||||||
#include "hw/naomi/naomi_cart.h"
|
#include "hw/naomi/naomi_cart.h"
|
||||||
#include "hw/pvr/spg.h"
|
#include "hw/pvr/spg.h"
|
||||||
|
#include "input/gamepad.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "deps/zlib/zlib.h"
|
#include "deps/zlib/zlib.h"
|
||||||
|
@ -198,6 +199,35 @@ struct maple_base: maple_device
|
||||||
*/
|
*/
|
||||||
struct maple_sega_controller: maple_base
|
struct maple_sega_controller: maple_base
|
||||||
{
|
{
|
||||||
|
virtual u32 get_capabilities() {
|
||||||
|
// byte 0: 0 0 0 0 0 0 0 0
|
||||||
|
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
|
||||||
|
// byte 2: R2 L2 D2 U2 D X Y Z
|
||||||
|
// byte 3: R L D U St A B C
|
||||||
|
|
||||||
|
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual u32 transform_kcode(u32 kcode) {
|
||||||
|
return kcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) {
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return pjs.trigger[PJTI_R]; // Right trigger
|
||||||
|
case 1:
|
||||||
|
return pjs.trigger[PJTI_L]; // Left trigger
|
||||||
|
case 2:
|
||||||
|
return pjs.joy[PJAI_X1]; // Stick X
|
||||||
|
case 3:
|
||||||
|
return pjs.joy[PJAI_Y1]; // Stick Y
|
||||||
|
default:
|
||||||
|
return 0x80; // unused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual MapleDeviceType get_device_type()
|
virtual MapleDeviceType get_device_type()
|
||||||
{
|
{
|
||||||
return MDT_SegaController;
|
return MDT_SegaController;
|
||||||
|
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
|
||||||
|
|
||||||
//struct data
|
//struct data
|
||||||
//3*4
|
//3*4
|
||||||
w32( 0xfe060f00);
|
w32(get_capabilities());
|
||||||
w32( 0);
|
w32(0);
|
||||||
w32( 0);
|
w32(0);
|
||||||
|
|
||||||
//1 area code
|
//1 area code
|
||||||
w8(0xFF);
|
w8(0xFF);
|
||||||
|
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
|
||||||
|
|
||||||
//state data
|
//state data
|
||||||
//2 key code
|
//2 key code
|
||||||
w16(pjs.kcode);
|
w16(transform_kcode(pjs.kcode));
|
||||||
|
|
||||||
//triggers
|
//triggers
|
||||||
//1 R
|
//1 R
|
||||||
w8(pjs.trigger[PJTI_R]);
|
w8(get_analog_axis(0, pjs));
|
||||||
//1 L
|
//1 L
|
||||||
w8(pjs.trigger[PJTI_L]);
|
w8(get_analog_axis(1, pjs));
|
||||||
|
|
||||||
//joyx
|
//joyx
|
||||||
//1
|
//1
|
||||||
w8(pjs.joy[PJAI_X1]);
|
w8(get_analog_axis(2, pjs));
|
||||||
//joyy
|
//joyy
|
||||||
//1
|
//1
|
||||||
w8(pjs.joy[PJAI_Y1]);
|
w8(get_analog_axis(3, pjs));
|
||||||
|
|
||||||
//not used
|
//not used
|
||||||
//1
|
//1
|
||||||
w8(0x80);
|
w8(get_analog_axis(4, pjs));
|
||||||
//1
|
//1
|
||||||
w8(0x80);
|
w8(get_analog_axis(5, pjs));
|
||||||
}
|
}
|
||||||
|
|
||||||
return MDRS_DataTransfer;
|
return MDRS_DataTransfer;
|
||||||
|
@ -281,6 +311,38 @@ struct maple_sega_controller: maple_base
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct maple_atomiswave_controller: maple_sega_controller
|
||||||
|
{
|
||||||
|
virtual u32 get_capabilities() override {
|
||||||
|
// byte 0: 0 0 0 0 0 0 0 0
|
||||||
|
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
|
||||||
|
// byte 2: R2 L2 D2 U2 D X Y Z
|
||||||
|
// byte 3: R L D U St A B C
|
||||||
|
|
||||||
|
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual u32 transform_kcode(u32 kcode) override {
|
||||||
|
return kcode | AWAVE_TRIGGER_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
return pjs.joy[PJAI_X1];
|
||||||
|
case 3:
|
||||||
|
return pjs.joy[PJAI_Y1];
|
||||||
|
case 4:
|
||||||
|
return pjs.joy[PJAI_X2];
|
||||||
|
case 5:
|
||||||
|
return pjs.joy[PJAI_Y2];
|
||||||
|
default:
|
||||||
|
return 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sega Dreamcast Visual Memory Unit
|
Sega Dreamcast Visual Memory Unit
|
||||||
This is pretty much done (?)
|
This is pretty much done (?)
|
||||||
|
@ -1267,6 +1329,10 @@ struct maple_mouse : maple_base
|
||||||
|
|
||||||
struct maple_lightgun : maple_base
|
struct maple_lightgun : maple_base
|
||||||
{
|
{
|
||||||
|
virtual u32 transform_kcode(u32 kcode) {
|
||||||
|
return kcode | 0xFF01;
|
||||||
|
}
|
||||||
|
|
||||||
virtual MapleDeviceType get_device_type()
|
virtual MapleDeviceType get_device_type()
|
||||||
{
|
{
|
||||||
return MDT_LightGun;
|
return MDT_LightGun;
|
||||||
|
@ -1315,21 +1381,13 @@ struct maple_lightgun : maple_base
|
||||||
PlainJoystickState pjs;
|
PlainJoystickState pjs;
|
||||||
config->GetInput(&pjs);
|
config->GetInput(&pjs);
|
||||||
|
|
||||||
// Also use the mouse buttons
|
|
||||||
if (!(mo_buttons & 4)) // Left button
|
|
||||||
pjs.kcode &= ~4; // A
|
|
||||||
if (!(mo_buttons & 2)) // Right button
|
|
||||||
pjs.kcode &= ~2; // B
|
|
||||||
if (!(mo_buttons & 8)) // Wheel button
|
|
||||||
pjs.kcode &= ~8; // Start
|
|
||||||
|
|
||||||
//caps
|
//caps
|
||||||
//4
|
//4
|
||||||
w32(MFID_0_Input);
|
w32(MFID_0_Input);
|
||||||
|
|
||||||
//state data
|
//state data
|
||||||
//2 key code
|
//2 key code
|
||||||
w16(pjs.kcode | 0xFF01);
|
w16(transform_kcode(pjs.kcode));
|
||||||
|
|
||||||
//not used
|
//not used
|
||||||
//2
|
//2
|
||||||
|
@ -1355,6 +1413,13 @@ struct maple_lightgun : maple_base
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct atomiswave_lightgun : maple_lightgun
|
||||||
|
{
|
||||||
|
virtual u32 transform_kcode(u32 kcode) override {
|
||||||
|
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
extern u16 kcode[4];
|
extern u16 kcode[4];
|
||||||
extern s8 joyx[4],joyy[4];
|
extern s8 joyx[4],joyy[4];
|
||||||
extern u8 rt[4], lt[4];
|
extern u8 rt[4], lt[4];
|
||||||
|
@ -1381,20 +1446,29 @@ static u16 getRightTriggerAxis()
|
||||||
return rt[0] << 8;
|
return rt[0] << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
NaomiInputMapping Naomi_Mapping = {
|
u32 naomi_button_mapping[] = {
|
||||||
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis },
|
NAOMI_SERVICE_KEY, // DC_BTN_C
|
||||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
|
NAOMI_BTN1_KEY, // DC_BTN_B
|
||||||
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 },
|
NAOMI_BTN0_KEY, // DC_BTN_A
|
||||||
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3
|
NAOMI_START_KEY, // DC_BTN_START
|
||||||
|
NAOMI_UP_KEY, // DC_DPAD_UP
|
||||||
|
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
|
||||||
|
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
|
||||||
|
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
|
||||||
|
NAOMI_TEST_KEY, // DC_BTN_Z
|
||||||
|
NAOMI_BTN3_KEY, // DC_BTN_Y
|
||||||
|
NAOMI_BTN2_KEY, // DC_BTN_X
|
||||||
|
NAOMI_COIN_KEY, // DC_BTN_D
|
||||||
|
// DC_DPAD2_UP
|
||||||
|
// DC_DPAD2_DOWN
|
||||||
|
// DC_DPAD2_LEFT
|
||||||
|
// DC_DPAD2_RIGHT
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sega JVS I/O board
|
* Sega JVS I/O board
|
||||||
*/
|
*/
|
||||||
bool coin_chute;
|
static bool old_coin_chute[4];
|
||||||
static bool old_coin_chute;
|
static int coin_count[4];
|
||||||
static int coin_count;
|
|
||||||
bool naomi_test_button = false;
|
|
||||||
|
|
||||||
struct maple_naomi_jamma;
|
struct maple_naomi_jamma;
|
||||||
|
|
||||||
|
@ -2313,63 +2387,56 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
||||||
{
|
{
|
||||||
JVS_STATUS1(); // report byte
|
JVS_STATUS1(); // report byte
|
||||||
|
|
||||||
LOGJVS("btns ");
|
u16 buttons[4] = { 0 };
|
||||||
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
|
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
|
||||||
// FIXME in-lst mapping
|
|
||||||
u8 buttons[8] = { 0 };
|
|
||||||
u32 keycode = ~kcode[0];
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
if ((keycode & (1 << i)) != 0)
|
|
||||||
{
|
{
|
||||||
buttons[Naomi_Mapping.button_mapping_byte[i]] |= Naomi_Mapping.button_mapping_mask[i];
|
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:
|
||||||
rv=new maple_sega_controller();
|
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||||
|
rv = new maple_sega_controller();
|
||||||
|
#else
|
||||||
|
rv = new maple_atomiswave_controller();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MDT_Microphone:
|
case MDT_Microphone:
|
||||||
|
@ -2566,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MDT_LightGun:
|
case MDT_LightGun:
|
||||||
|
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
|
||||||
rv = new maple_lightgun();
|
rv = new maple_lightgun();
|
||||||
|
#else
|
||||||
|
rv = new atomiswave_lightgun();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MDT_NaomiJamma:
|
case MDT_NaomiJamma:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_alsa;
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_android;
|
|
|
@ -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
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_coreaudio;
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "oslib/audiobackend_directsound.h"
|
#include "oslib/audiostream.h"
|
||||||
#if HOST_OS==OS_WINDOWS
|
#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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_directsound;
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "oslib/audiobackend_libao.h"
|
#include "oslib/audiostream.h"
|
||||||
#ifdef USE_LIBAO
|
#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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_libao;
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "oslib/audiobackend_omx.h"
|
#include "oslib/audiostream.h"
|
||||||
#if USE_OMX
|
#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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_omx;
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "oslib/audiobackend_oss.h"
|
#include "oslib/audiostream.h"
|
||||||
#ifdef USE_OSS
|
#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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_oss;
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "oslib/audiobackend_pulseaudio.h"
|
#include "oslib/audiostream.h"
|
||||||
#ifdef USE_PULSEAUDIO
|
#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
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "oslib/audiostream.h"
|
|
||||||
|
|
||||||
extern audiobackend_t audiobackend_pulseaudio;
|
|
|
@ -2,14 +2,6 @@
|
||||||
#include "cfg/cfg.h"
|
#include "cfg/cfg.h"
|
||||||
#include "oslib/oslib.h"
|
#include "oslib/oslib.h"
|
||||||
#include "audiostream.h"
|
#include "audiostream.h"
|
||||||
#include "oslib/audiobackend_directsound.h"
|
|
||||||
#include "oslib/audiobackend_android.h"
|
|
||||||
#include "oslib/audiobackend_alsa.h"
|
|
||||||
#include "oslib/audiobackend_oss.h"
|
|
||||||
#include "oslib/audiobackend_pulseaudio.h"
|
|
||||||
#include "oslib/audiobackend_coreaudio.h"
|
|
||||||
#include "oslib/audiobackend_omx.h"
|
|
||||||
#include "oslib/audiobackend_libao.h"
|
|
||||||
|
|
||||||
struct SoundFrame { s16 l;s16 r; };
|
struct SoundFrame { s16 l;s16 r; };
|
||||||
#define SAMPLE_COUNT 512
|
#define SAMPLE_COUNT 512
|
||||||
|
@ -25,16 +17,27 @@ u32 gen_samples=0;
|
||||||
|
|
||||||
double time_diff = 128/44100.0;
|
double time_diff = 128/44100.0;
|
||||||
double time_last;
|
double time_last;
|
||||||
|
|
||||||
#ifdef LOG_SOUND
|
#ifdef LOG_SOUND
|
||||||
|
// TODO Only works on Windows!
|
||||||
WaveWriter rawout("d:\\aica_out.wav");
|
WaveWriter rawout("d:\\aica_out.wav");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool audiobackends_registered = false;
|
|
||||||
static unsigned int audiobackends_num_max = 1;
|
static unsigned int audiobackends_num_max = 1;
|
||||||
static unsigned int audiobackends_num_registered = 0;
|
static unsigned int audiobackends_num_registered = 0;
|
||||||
static audiobackend_t **audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
|
static audiobackend_t **audiobackends = NULL;
|
||||||
static audiobackend_t *audiobackend_current = NULL;
|
static audiobackend_t *audiobackend_current = NULL;
|
||||||
|
|
||||||
|
u32 GetAudioBackendCount()
|
||||||
|
{
|
||||||
|
return audiobackends_num_registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
audiobackend_t* GetAudioBackend(int num)
|
||||||
|
{
|
||||||
|
return audiobackends[num];
|
||||||
|
}
|
||||||
|
|
||||||
bool RegisterAudioBackend(audiobackend_t *backend)
|
bool RegisterAudioBackend(audiobackend_t *backend)
|
||||||
{
|
{
|
||||||
/* This function announces the availability of an audio backend to reicast. */
|
/* This function announces the availability of an audio backend to reicast. */
|
||||||
|
@ -44,10 +47,16 @@ bool RegisterAudioBackend(audiobackend_t *backend)
|
||||||
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
|
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backend->slug == "auto" || backend->slug == "none") {
|
if (backend->slug == "auto" || backend->slug == "none") {
|
||||||
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
|
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First call to RegisterAudioBackend(), create the backend structure;
|
||||||
|
if (audiobackends == NULL)
|
||||||
|
audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
|
||||||
|
|
||||||
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
|
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
|
||||||
if (audiobackends_num_registered == audiobackends_num_max)
|
if (audiobackends_num_registered == audiobackends_num_max)
|
||||||
{
|
{
|
||||||
|
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
|
||||||
}
|
}
|
||||||
audiobackends = new_ptr;
|
audiobackends = new_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
audiobackends[audiobackends_num_registered] = backend;
|
audiobackends[audiobackends_num_registered] = backend;
|
||||||
audiobackends_num_registered++;
|
audiobackends_num_registered++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterAllAudioBackends() {
|
audiobackend_t* GetAudioBackend(std::string slug)
|
||||||
#if HOST_OS==OS_WINDOWS
|
|
||||||
RegisterAudioBackend(&audiobackend_directsound);
|
|
||||||
#endif
|
|
||||||
#if ANDROID
|
|
||||||
RegisterAudioBackend(&audiobackend_android);
|
|
||||||
#endif
|
|
||||||
#if USE_OMX
|
|
||||||
RegisterAudioBackend(&audiobackend_omx);
|
|
||||||
#endif
|
|
||||||
#if USE_ALSA
|
|
||||||
RegisterAudioBackend(&audiobackend_alsa);
|
|
||||||
#endif
|
|
||||||
#if USE_OSS
|
|
||||||
RegisterAudioBackend(&audiobackend_oss);
|
|
||||||
#endif
|
|
||||||
#if USE_PULSEAUDIO
|
|
||||||
RegisterAudioBackend(&audiobackend_pulseaudio);
|
|
||||||
#endif
|
|
||||||
#if USE_LIBAO
|
|
||||||
RegisterAudioBackend(&audiobackend_libao);
|
|
||||||
#endif
|
|
||||||
#if HOST_OS == OS_DARWIN
|
|
||||||
RegisterAudioBackend(&audiobackend_coreaudio);
|
|
||||||
#endif
|
|
||||||
audiobackends_registered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static audiobackend_t* GetAudioBackend(std::string slug)
|
|
||||||
{
|
{
|
||||||
if (slug == "none")
|
if (slug == "none")
|
||||||
{
|
{
|
||||||
printf("WARNING: Audio backend set to \"none\"!\n");
|
printf("WARNING: Audio backend set to \"none\"!\n");
|
||||||
}
|
}
|
||||||
else if(audiobackends_num_registered > 0)
|
else if (audiobackends_num_registered > 0)
|
||||||
{
|
{
|
||||||
if (slug == "auto")
|
if (slug == "auto")
|
||||||
{
|
{
|
||||||
|
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PushAudio(void* frame, u32 amt, bool wait) {
|
u32 PushAudio(void* frame, u32 amt, bool wait)
|
||||||
|
{
|
||||||
if (audiobackend_current != NULL) {
|
if (audiobackend_current != NULL) {
|
||||||
return audiobackend_current->push(frame, amt, wait);
|
return audiobackend_current->push(frame, amt, wait);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +134,7 @@ u32 asRingUsedCount()
|
||||||
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
|
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
|
||||||
//return sz<0?sz+RingBufferSampleCount:sz;
|
//return sz<0?sz+RingBufferSampleCount:sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 asRingFreeCount()
|
u32 asRingFreeCount()
|
||||||
{
|
{
|
||||||
return RingBufferSampleCount-asRingUsedCount();
|
return RingBufferSampleCount-asRingUsedCount();
|
||||||
|
@ -169,6 +153,27 @@ void WriteSample(s16 r, s16 l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool backends_sorted = false;
|
||||||
|
void SortAudioBackends()
|
||||||
|
{
|
||||||
|
if (backends_sorted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Sort backends by slug
|
||||||
|
for (int n = audiobackends_num_registered; n > 0; n--)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n-1; i++)
|
||||||
|
{
|
||||||
|
if (audiobackends[i]->slug > audiobackends[i+1]->slug)
|
||||||
|
{
|
||||||
|
audiobackend_t* swap = audiobackends[i];
|
||||||
|
audiobackends[i] = audiobackends[i+1];
|
||||||
|
audiobackends[i+1] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InitAudio()
|
void InitAudio()
|
||||||
{
|
{
|
||||||
if (cfgLoadInt("audio", "disable", 0)) {
|
if (cfgLoadInt("audio", "disable", 0)) {
|
||||||
|
@ -176,24 +181,22 @@ void InitAudio()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfgSaveInt("audio","disable",0);
|
cfgSaveInt("audio", "disable", 0);
|
||||||
|
|
||||||
if (!audiobackends_registered) {
|
|
||||||
//FIXME: There might some nicer way to do this.
|
|
||||||
RegisterAllAudioBackends();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audiobackend_current != NULL) {
|
if (audiobackend_current != NULL) {
|
||||||
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string audiobackend_slug = cfgLoadStr("audio", "backend", "auto"); // FIXME: This could be made a parameter
|
SortAudioBackends();
|
||||||
|
|
||||||
|
string audiobackend_slug = settings.audio.backend;
|
||||||
audiobackend_current = GetAudioBackend(audiobackend_slug);
|
audiobackend_current = GetAudioBackend(audiobackend_slug);
|
||||||
if (audiobackend_current == NULL) {
|
if (audiobackend_current == NULL) {
|
||||||
printf("WARNING: Running without audio!\n");
|
printf("WARNING: Running without audio!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
|
||||||
audiobackend_current->init();
|
audiobackend_current->init();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -45,10 +45,15 @@ static GLuint texSamplers[2];
|
||||||
static GLuint depth_fbo;
|
static GLuint depth_fbo;
|
||||||
GLuint depthSaveTexId;
|
GLuint depthSaveTexId;
|
||||||
|
|
||||||
static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
static gl4PipelineShader *gl4GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
||||||
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
|
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
|
||||||
{
|
{
|
||||||
|
if (settings.rend.Rotate90 != gl4.rotate90)
|
||||||
|
{
|
||||||
|
gl4_delete_shaders();
|
||||||
|
gl4.rotate90 = settings.rend.Rotate90;
|
||||||
|
}
|
||||||
u32 rv=0;
|
u32 rv=0;
|
||||||
|
|
||||||
rv|=pp_ClipTestMode;
|
rv|=pp_ClipTestMode;
|
||||||
|
@ -66,45 +71,27 @@ static int gl4GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
||||||
rv <<= 1; rv |= fog_clamping;
|
rv <<= 1; rv |= fog_clamping;
|
||||||
rv <<= 2; rv |= pass;
|
rv <<= 2; rv |= pass;
|
||||||
|
|
||||||
return rv;
|
gl4PipelineShader *shader = &gl4.shaders[rv];
|
||||||
}
|
if (shader->program == 0)
|
||||||
|
{
|
||||||
static void setCurrentShader(u32 cp_AlphaTest, u32 pp_ClipTestMode,
|
shader->cp_AlphaTest = cp_AlphaTest;
|
||||||
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
|
shader->pp_ClipTestMode = pp_ClipTestMode;
|
||||||
u32 pp_FogCtrl, bool pp_TwoVolumes, u32 pp_DepthFunc, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, int pass)
|
shader->pp_Texture = pp_Texture;
|
||||||
{
|
shader->pp_UseAlpha = pp_UseAlpha;
|
||||||
int shaderId = gl4GetProgramID(cp_AlphaTest,
|
shader->pp_IgnoreTexA = pp_IgnoreTexA;
|
||||||
pp_ClipTestMode + 1,
|
shader->pp_ShadInstr = pp_ShadInstr;
|
||||||
pp_Texture,
|
shader->pp_Offset = pp_Offset;
|
||||||
pp_UseAlpha,
|
shader->pp_FogCtrl = pp_FogCtrl;
|
||||||
pp_IgnoreTexA,
|
shader->pp_TwoVolumes = pp_TwoVolumes;
|
||||||
pp_ShadInstr,
|
shader->pp_DepthFunc = pp_DepthFunc;
|
||||||
pp_Offset,
|
shader->pp_Gouraud = pp_Gouraud;
|
||||||
pp_FogCtrl,
|
shader->pp_BumpMap = pp_BumpMap;
|
||||||
pp_TwoVolumes,
|
shader->fog_clamping = fog_clamping;
|
||||||
pp_DepthFunc,
|
shader->pass = pass;
|
||||||
pp_Gouraud,
|
gl4CompilePipelineShader(shader, settings.rend.Rotate90);
|
||||||
pp_BumpMap,
|
|
||||||
fog_clamping,
|
|
||||||
pass);
|
|
||||||
CurrentShader = gl4.getShader(shaderId);
|
|
||||||
if (CurrentShader->program == -1) {
|
|
||||||
CurrentShader->cp_AlphaTest = cp_AlphaTest;
|
|
||||||
CurrentShader->pp_ClipTestMode = pp_ClipTestMode;
|
|
||||||
CurrentShader->pp_Texture = pp_Texture;
|
|
||||||
CurrentShader->pp_UseAlpha = pp_UseAlpha;
|
|
||||||
CurrentShader->pp_IgnoreTexA = pp_IgnoreTexA;
|
|
||||||
CurrentShader->pp_ShadInstr = pp_ShadInstr;
|
|
||||||
CurrentShader->pp_Offset = pp_Offset;
|
|
||||||
CurrentShader->pp_FogCtrl = pp_FogCtrl;
|
|
||||||
CurrentShader->pp_TwoVolumes = pp_TwoVolumes;
|
|
||||||
CurrentShader->pp_DepthFunc = pp_DepthFunc;
|
|
||||||
CurrentShader->pp_Gouraud = pp_Gouraud;
|
|
||||||
CurrentShader->pp_BumpMap = pp_BumpMap;
|
|
||||||
CurrentShader->fog_clamping = fog_clamping;
|
|
||||||
CurrentShader->pass = pass;
|
|
||||||
gl4CompilePipelineShader(CurrentShader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetTextureRepeatMode(int index, GLuint dir, u32 clamp, u32 mirror)
|
static void SetTextureRepeatMode(int index, GLuint dir, u32 clamp, u32 mirror)
|
||||||
|
@ -132,7 +119,7 @@ template <u32 Type, bool SortingEnabled>
|
||||||
|
|
||||||
if (pass == 0)
|
if (pass == 0)
|
||||||
{
|
{
|
||||||
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0,
|
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||||
clipping,
|
clipping,
|
||||||
Type == ListType_Punch_Through ? gp->pcw.Texture : 0,
|
Type == ListType_Punch_Through ? gp->pcw.Texture : 0,
|
||||||
1,
|
1,
|
||||||
|
@ -153,6 +140,8 @@ template <u32 Type, bool SortingEnabled>
|
||||||
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent;
|
bool two_volumes_mode = (gp->tsp1.full != -1) && Type != ListType_Translucent;
|
||||||
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min != 0 || pvrrc.fog_clamp_max != 0xffffffff);
|
||||||
|
|
||||||
|
int fog_ctrl = settings.rend.Fog ? gp->tsp.FogCtrl : 2;
|
||||||
|
|
||||||
int depth_func = 0;
|
int depth_func = 0;
|
||||||
if (Type == ListType_Translucent)
|
if (Type == ListType_Translucent)
|
||||||
{
|
{
|
||||||
|
@ -162,14 +151,14 @@ template <u32 Type, bool SortingEnabled>
|
||||||
depth_func = gp->isp.DepthMode;
|
depth_func = gp->isp.DepthMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentShader(Type == ListType_Punch_Through ? 1 : 0,
|
CurrentShader = gl4GetProgram(Type == ListType_Punch_Through ? 1 : 0,
|
||||||
clipping,
|
clipping,
|
||||||
gp->pcw.Texture,
|
gp->pcw.Texture,
|
||||||
gp->tsp.UseAlpha,
|
gp->tsp.UseAlpha,
|
||||||
gp->tsp.IgnoreTexA,
|
gp->tsp.IgnoreTexA,
|
||||||
gp->tsp.ShadInstr,
|
gp->tsp.ShadInstr,
|
||||||
gp->pcw.Offset,
|
gp->pcw.Offset,
|
||||||
gp->tsp.FogCtrl,
|
fog_ctrl,
|
||||||
two_volumes_mode,
|
two_volumes_mode,
|
||||||
depth_func,
|
depth_func,
|
||||||
gp->pcw.Gouraud,
|
gp->pcw.Gouraud,
|
||||||
|
@ -681,7 +670,7 @@ static void gl4_draw_quad_texture(GLuint texture, bool upsideDown, float x = 0.f
|
||||||
|
|
||||||
ShaderUniforms.trilinear_alpha = 1.0;
|
ShaderUniforms.trilinear_alpha = 1.0;
|
||||||
|
|
||||||
setCurrentShader(0,
|
CurrentShader = gl4GetProgram(0,
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
|
@ -713,11 +702,15 @@ void gl4DrawFramebuffer(float w, float h)
|
||||||
|
|
||||||
bool gl4_render_output_framebuffer()
|
bool gl4_render_output_framebuffer()
|
||||||
{
|
{
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
glViewport(0, 0, screen_width, screen_height);
|
glViewport(0, 0, screen_width, screen_height);
|
||||||
if (gl.ofbo.tex == 0)
|
glcache.Disable(GL_SCISSOR_TEST);
|
||||||
|
if (gl.ofbo.fbo == 0)
|
||||||
return false;
|
return false;
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
|
||||||
gl4_draw_quad_texture(gl.ofbo.tex, true);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
|
||||||
|
0, 0, screen_width, screen_height,
|
||||||
|
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,9 +1552,13 @@ 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()
|
||||||
|
|
14
core/types.h
14
core/types.h
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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>
|
|
@ -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"
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
if (surface != NULL)
|
else
|
||||||
|
render_reinit = true;
|
||||||
|
}
|
||||||
|
else if (surface != NULL)
|
||||||
{
|
{
|
||||||
g_window = ANativeWindow_fromSurface(env, surface);
|
g_window = ANativeWindow_fromSurface(env, surface);
|
||||||
rend_init_renderer();
|
render_thread.Start();
|
||||||
screen_width = width;
|
|
||||||
screen_height = height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue