Merge branch 'master' into fh/win32-winresize

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include "maple_devs.h"
#include "maple_cfg.h"
#include "cfg/cfg.h"
#include "hw/naomi/naomi_cart.h"
#define HAS_VMU
/*
@ -28,13 +29,31 @@ extern u16 kcode[4];
extern u32 vks[4];
extern s8 joyx[4],joyy[4];
extern u8 rt[4],lt[4];
extern bool naomi_test_button;
u8 GetBtFromSgn(s8 val)
{
return val+128;
}
u32 awave_button_mapping[] = {
AWAVE_SERVICE_KEY, // DC_BTN_C
AWAVE_BTN1_KEY, // DC_BTN_B
AWAVE_BTN0_KEY, // DC_BTN_A
AWAVE_START_KEY, // DC_BTN_START
AWAVE_UP_KEY, // DC_DPAD_UP
AWAVE_DOWN_KEY, // DC_DPAD_DOWN
AWAVE_LEFT_KEY, // DC_DPAD_LEFT
AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT
AWAVE_TEST_KEY, // DC_BTN_Z
AWAVE_BTN3_KEY, // DC_BTN_Y
AWAVE_BTN2_KEY, // DC_BTN_X
AWAVE_COIN_KEY, // DC_BTN_D
// DC_DPAD2_UP
// DC_DPAD2_DOWN
// DC_DPAD2_LEFT
// DC_DPAD2_RIGHT
};
struct MapleConfigMap : IMapleConfigMap
{
maple_device* dev;
@ -59,17 +78,32 @@ struct MapleConfigMap : IMapleConfigMap
pjs->kcode=kcode[player_num];
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
pjs->kcode |= 0xF901;
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (naomi_test_button)
pjs->kcode &= ~(1 << 14);
// if (!(pjs->kcode & (1 << 9))) // Hack (Y -> service btn)
// pjs->kcode &= ~(1 << 13);
#endif
pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
pjs->trigger[PJTI_R]=rt[player_num];
pjs->trigger[PJTI_L]=lt[player_num];
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
pjs->kcode = 0xFFFF;
for (int i = 0; i < 16; i++)
{
if ((kcode[player_num] & (1 << i)) == 0)
pjs->kcode &= ~awave_button_mapping[i];
}
pjs->joy[PJAI_X1] = GetBtFromSgn(joyx[player_num]);
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[1].name != NULL && NaomiGameInputs->axes[1].type == Half)
{
// Driving games: put axis 2 on RT (accel) and axis 3 on LT (brake)
pjs->joy[PJAI_Y1] = rt[player_num];
pjs->joy[PJAI_X2] = lt[player_num];
}
else
{
pjs->joy[PJAI_Y1] = GetBtFromSgn(joyy[player_num]);
pjs->joy[PJAI_X2] = rt[player_num];
pjs->joy[PJAI_Y2] = lt[player_num];
}
#endif
}
void SetImage(void* img)
{
@ -77,6 +111,16 @@ struct MapleConfigMap : IMapleConfigMap
}
};
bool maple_atomiswave_coin_chute(int slot)
{
for (int i = 0; i < 16; i++)
{
if ((kcode[slot] & (1 << i)) == 0 && awave_button_mapping[i] == AWAVE_COIN_KEY)
return true;
}
return false;
}
void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1)
{
if (MapleDevices[bus][port] != NULL)
@ -100,17 +144,32 @@ void mcfg_CreateAtomisWaveControllers()
// Then other devices on port 2 and 3 for analog axes, light guns, ...
mcfg_Create(MDT_SegaController, 0, 5);
mcfg_Create(MDT_SegaController, 1, 5);
// mcfg_Create(MDT_SegaController, 2, 5, 0);
// mcfg_Create(MDT_SegaController, 3, 5, 1);
// mcfg_Create(MDT_LightGun, 2, 5, 0);
// mcfg_Create(MDT_LightGun, 3, 5, 1);
// mcfg_Create(MDT_Mouse, 2, 5, 0);
// Guilty Gear Isuka (4P) needs 4 std controllers
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
// Maximum Speed same
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
// Sports Shooting same
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 3
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[0].name != NULL)
{
// Game needs analog axes
mcfg_Create(MDT_SegaController, 2, 5, 0);
mcfg_Create(MDT_SegaController, 3, 5, 1);
// Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes)
// Maximum Speed same
}
else if (settings.input.JammaSetup == 1)
{
// 4 players
mcfg_Create(MDT_SegaController, 2, 5);
mcfg_Create(MDT_SegaController, 3, 5);
}
else if (settings.input.JammaSetup == 5)
{
// Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3
// Sports Shooting same
mcfg_Create(MDT_LightGun, 2, 5, 0);
mcfg_Create(MDT_LightGun, 3, 5, 1);
}
else if (settings.input.JammaSetup == 3)
{
// Sega Bass Fishing Challenge needs a mouse (track-ball) on port 2
mcfg_Create(MDT_Mouse, 2, 5, 0);
}
}
void mcfg_CreateDevices()

View File

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

View File

@ -7,6 +7,7 @@
#include "hw/naomi/naomi.h"
#include "hw/naomi/naomi_cart.h"
#include "hw/pvr/spg.h"
#include "input/gamepad.h"
#include <time.h>
#include "deps/zlib/zlib.h"
@ -198,6 +199,35 @@ struct maple_base: maple_device
*/
struct maple_sega_controller: maple_base
{
virtual u32 get_capabilities() {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xfe060f00; // 4 analog axes (0-3) X Y A B Start U D L R
}
virtual u32 transform_kcode(u32 kcode) {
return kcode;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) {
switch (index)
{
case 0:
return pjs.trigger[PJTI_R]; // Right trigger
case 1:
return pjs.trigger[PJTI_L]; // Left trigger
case 2:
return pjs.joy[PJAI_X1]; // Stick X
case 3:
return pjs.joy[PJAI_Y1]; // Stick Y
default:
return 0x80; // unused
}
}
virtual MapleDeviceType get_device_type()
{
return MDT_SegaController;
@ -215,9 +245,9 @@ struct maple_sega_controller: maple_base
//struct data
//3*4
w32( 0xfe060f00);
w32( 0);
w32( 0);
w32(get_capabilities());
w32(0);
w32(0);
//1 area code
w8(0xFF);
@ -250,26 +280,26 @@ struct maple_sega_controller: maple_base
//state data
//2 key code
w16(pjs.kcode);
w16(transform_kcode(pjs.kcode));
//triggers
//1 R
w8(pjs.trigger[PJTI_R]);
w8(get_analog_axis(0, pjs));
//1 L
w8(pjs.trigger[PJTI_L]);
w8(get_analog_axis(1, pjs));
//joyx
//1
w8(pjs.joy[PJAI_X1]);
w8(get_analog_axis(2, pjs));
//joyy
//1
w8(pjs.joy[PJAI_Y1]);
w8(get_analog_axis(3, pjs));
//not used
//1
w8(0x80);
w8(get_analog_axis(4, pjs));
//1
w8(0x80);
w8(get_analog_axis(5, pjs));
}
return MDRS_DataTransfer;
@ -281,6 +311,38 @@ struct maple_sega_controller: maple_base
}
};
struct maple_atomiswave_controller: maple_sega_controller
{
virtual u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xff663f00; // 6 analog axes, X Y L2/D2(?) A B C Start U D L R
}
virtual u32 transform_kcode(u32 kcode) override {
return kcode | AWAVE_TRIGGER_KEY;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
switch (index)
{
case 2:
return pjs.joy[PJAI_X1];
case 3:
return pjs.joy[PJAI_Y1];
case 4:
return pjs.joy[PJAI_X2];
case 5:
return pjs.joy[PJAI_Y2];
default:
return 0x80;
}
}
};
/*
Sega Dreamcast Visual Memory Unit
This is pretty much done (?)
@ -1267,6 +1329,10 @@ struct maple_mouse : maple_base
struct maple_lightgun : maple_base
{
virtual u32 transform_kcode(u32 kcode) {
return kcode | 0xFF01;
}
virtual MapleDeviceType get_device_type()
{
return MDT_LightGun;
@ -1315,21 +1381,13 @@ struct maple_lightgun : maple_base
PlainJoystickState pjs;
config->GetInput(&pjs);
// Also use the mouse buttons
if (!(mo_buttons & 4)) // Left button
pjs.kcode &= ~4; // A
if (!(mo_buttons & 2)) // Right button
pjs.kcode &= ~2; // B
if (!(mo_buttons & 8)) // Wheel button
pjs.kcode &= ~8; // Start
//caps
//4
w32(MFID_0_Input);
//state data
//2 key code
w16(pjs.kcode | 0xFF01);
w16(transform_kcode(pjs.kcode));
//not used
//2
@ -1355,6 +1413,13 @@ struct maple_lightgun : maple_base
}
};
struct atomiswave_lightgun : maple_lightgun
{
virtual u32 transform_kcode(u32 kcode) override {
return (kcode & AWAVE_TRIGGER_KEY) == 0 ? ~AWAVE_BTN0_KEY : ~0;
}
};
extern u16 kcode[4];
extern s8 joyx[4],joyy[4];
extern u8 rt[4], lt[4];
@ -1381,20 +1446,29 @@ static u16 getRightTriggerAxis()
return rt[0] << 8;
}
NaomiInputMapping Naomi_Mapping = {
{ getJoystickXAxis, getJoystickYAxis, getRightTriggerAxis, getLeftTriggerAxis },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
{ 0x40, 0x01, 0x02, 0x80, 0x20, 0x10, 0x08, 0x04, 0, 0x80, 0x40, 0, 0 },
// SERVICE BTN1 BTN0 START UP DOWN LEFT RIGHT BTN2 BTN3
u32 naomi_button_mapping[] = {
NAOMI_SERVICE_KEY, // DC_BTN_C
NAOMI_BTN1_KEY, // DC_BTN_B
NAOMI_BTN0_KEY, // DC_BTN_A
NAOMI_START_KEY, // DC_BTN_START
NAOMI_UP_KEY, // DC_DPAD_UP
NAOMI_DOWN_KEY, // DC_DPAD_DOWN
NAOMI_LEFT_KEY, // DC_DPAD_LEFT
NAOMI_RIGHT_KEY, // DC_DPAD_RIGHT
NAOMI_TEST_KEY, // DC_BTN_Z
NAOMI_BTN3_KEY, // DC_BTN_Y
NAOMI_BTN2_KEY, // DC_BTN_X
NAOMI_COIN_KEY, // DC_BTN_D
// DC_DPAD2_UP
// DC_DPAD2_DOWN
// DC_DPAD2_LEFT
// DC_DPAD2_RIGHT
};
/*
* Sega JVS I/O board
*/
bool coin_chute;
static bool old_coin_chute;
static int coin_count;
bool naomi_test_button = false;
static bool old_coin_chute[4];
static int coin_count[4];
struct maple_naomi_jamma;
@ -2313,63 +2387,56 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
{
JVS_STATUS1(); // report byte
LOGJVS("btns ");
JVS_OUT(naomi_test_button ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
// FIXME in-lst mapping
u8 buttons[8] = { 0 };
u32 keycode = ~kcode[0];
for (int i = 0; i < 16; i++)
if ((keycode & (1 << i)) != 0)
{
buttons[Naomi_Mapping.button_mapping_byte[i]] |= Naomi_Mapping.button_mapping_mask[i];
}
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
u16 buttons[4] = { 0 };
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
{
u8 *cur_btns = &buttons[(first_player + player) * 2];
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns[0]);
JVS_OUT(cur_btns[0]);
if (buffer_in[cmdi + 2] == 2)
u32 keycode = ~kcode[first_player + player];
for (int i = 0; i < 16; i++)
{
LOGJVS("%02x ", cur_btns[1]);
JVS_OUT(cur_btns[1]);
if ((keycode & (1 << i)) != 0)
buttons[player] |= naomi_button_mapping[i];
}
}
LOGJVS("btns ");
JVS_OUT((buttons[0] & NAOMI_TEST_KEY) ? 0x80 : 0x00); // test, tilt1, tilt2, tilt3, unused, unused, unused, unused
for (int player = 0; player < buffer_in[cmdi + 1]; player++)
{
u16 cur_btns = first_player + player < ARRAY_SIZE(buttons) ? buttons[first_player + player] : 0;
LOGJVS("P%d %02x ", player + 1 + first_player, cur_btns >> 8);
JVS_OUT(cur_btns >> 8);
if (buffer_in[cmdi + 2] == 2)
{
LOGJVS("%02x ", cur_btns & 0xFF);
JVS_OUT(cur_btns);
}
}
// for (int player = 0; player < jvs_request[channel][cmdi + 1]; player++)
// {
// u32 keycode = ~kcode[player];
// if (keycode & DC_BTN_C)
// keycode |= 0xFFff;
//
// if (jvs_request[channel][cmdi + 2] == 1)
// JVS_OUT(keycode);
// else
// w16(keycode);
// }
cmdi += 3;
}
break;
case 0x21: // Read coins
{
if (coin_chute && !old_coin_chute)
coin_count++;
old_coin_chute = coin_chute;
JVS_STATUS1(); // report byte
LOGJVS("coins ");
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++)
{
if (slot == 0)
bool coin_chute = false;
u32 keycode = ~kcode[first_player + slot];
for (int i = 0; i < 16 && !coin_chute; i++)
{
LOGJVS("0:%d ", coin_count);
JVS_OUT((coin_count >> 8) & 0x3F); // status (2 highest bits, 0: normal), coin count MSB
JVS_OUT(coin_count); // coin count LSB
}
else
{
LOGJVS("%d:0 ", slot);
JVS_OUT(0);
JVS_OUT(0);
if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
coin_chute = true;
}
if (coin_chute && !old_coin_chute[first_player + slot])
coin_count[first_player + slot] += 1;
old_coin_chute[first_player + slot] = coin_chute;
LOGJVS("%d:%d ", slot + 1 + first_player, coin_count[first_player + slot]);
// status (2 highest bits, 0: normal), coin count MSB
JVS_OUT((coin_count[first_player + slot] >> 8) & 0x3F);
// coin count LSB
JVS_OUT(coin_count[first_player + slot]);
}
cmdi += 2;
}
@ -2393,34 +2460,50 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
}
LOGJVS("x,y:%4x,%4x ", x, y);
JVS_OUT(x >> 8); // X, MSB
JVS_OUT(x); // X, LSB
JVS_OUT(x); // X, LSB
JVS_OUT(y >> 8); // Y, MSB
JVS_OUT(y); // Y, LSB
JVS_OUT(y); // Y, LSB
axis = 2;
}
int full_axis_count = 0;
int half_axis_count = 0;
for (; axis < buffer_in[cmdi + 1]; axis++)
{
// FIXME Need to know how many axes per player for proper mapping
u16 axis_value;
if (axis + first_player * 4 < 8 && Naomi_Mapping.axis[axis + first_player * 4] != NULL)
axis_value = Naomi_Mapping.axis[axis + first_player * 4]();
if (NaomiGameInputs != NULL
&& axis < ARRAY_SIZE(NaomiGameInputs->axes)
&& NaomiGameInputs->axes[axis].name != NULL
&& NaomiGameInputs->axes[axis].type == Half)
{
if (half_axis_count == 0)
axis_value = rt[first_player] << 8;
else if (half_axis_count == 1)
axis_value = lt[first_player] << 8;
else
axis_value = 0;
half_axis_count++;
}
else
{
switch (axis) {
switch (full_axis_count) {
case 0:
axis_value = (joyx[first_player + axis / 4] + 128) << 8;
axis_value = (joyx[first_player] + 128) << 8;
break;
case 1:
axis_value = (joyy[first_player + axis / 4] + 128) << 8;
break;
case 2:
axis_value = rt[first_player + axis / 4] << 8;
break;
case 3:
axis_value = lt[first_player + axis / 4] << 8;
axis_value = (joyy[first_player] + 128) << 8;
break;
// TODO right analog stick
// case 2:
// axis_value = (joyrx[first_player] + 128) << 8;
// break;
// case 3:
// axis_value = (joyry[first_player] + 128) << 8;
// break;
default:
axis_value = 128;
}
full_axis_count++;
}
LOGJVS("%d:%4x ", axis, axis_value);
JVS_OUT(axis_value >> 8);
@ -2493,8 +2576,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
break;
case 0x30: // substract coin
if (buffer_in[cmdi + 1] == 1)
coin_count -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
if (buffer_in[cmdi + 1] > 0 && first_player + buffer_in[cmdi + 1] - 1 < ARRAY_SIZE(coin_count))
coin_count[first_player + buffer_in[cmdi + 1] - 1] -= (buffer_in[cmdi + 2] << 8) + buffer_in[cmdi + 3];
JVS_STATUS1(); // report byte
cmdi += 4;
break;
@ -2542,7 +2625,11 @@ maple_device* maple_Create(MapleDeviceType type)
switch(type)
{
case MDT_SegaController:
rv=new maple_sega_controller();
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_sega_controller();
#else
rv = new maple_atomiswave_controller();
#endif
break;
case MDT_Microphone:
@ -2566,7 +2653,11 @@ maple_device* maple_Create(MapleDeviceType type)
break;
case MDT_LightGun:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_lightgun();
#else
rv = new atomiswave_lightgun();
#endif
break;
case MDT_NaomiJamma:

View File

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

View File

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

View File

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

View File

@ -304,6 +304,8 @@ void bm_Rebuild()
{
return;
die("this is broken in multiple levels, including compile options");
void RASDASD();
RASDASD();
@ -321,7 +323,7 @@ void bm_Rebuild()
//constprop(all_blocks[i]);
//#endif
}
ngen_Compile(all_blocks[i],false,false,all_blocks[i]->staging_runs>0,do_opts);
ngen_Compile(all_blocks[i],NoCheck,false,all_blocks[i]->staging_runs>0,do_opts);
blkmap.insert(all_blocks[i]);
verify(bm_GetBlock((RuntimeBlockInfo*)all_blocks[i]->code)==all_blocks[i]);

View File

@ -86,6 +86,15 @@ void recSh4_Run()
sh4_dyna_rcb=(u8*)&Sh4cntx + sizeof(Sh4cntx);
printf("cntx // fpcb offset: %td // pc offset: %td // pc %08X\n",(u8*)&sh4rcb.fpcb - sh4_dyna_rcb, (u8*)&sh4rcb.cntx.pc - sh4_dyna_rcb,sh4rcb.cntx.pc);
if (!settings.dynarec.safemode)
printf("Warning: Dynarec safe mode is off\n");
if (settings.dynarec.unstable_opt)
printf("Warning: Unstable optimizations is on\n");
if (settings.dynarec.SmcCheckLevel != FullCheck)
printf("Warning: SMC check mode is %d\n", settings.dynarec.SmcCheckLevel);
verify(rcb_noffs(&next_pc)==-184);
ngen_mainloop(sh4_dyna_rcb);
@ -119,34 +128,51 @@ u32 emit_FreeSpace()
}
bool DoCheck(u32 pc)
SmcCheckEnum DoCheck(u32 pc)
{
if (IsOnRam(pc))
{
if (!settings.dynarec.unstable_opt)
return true;
pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
switch (settings.dynarec.SmcCheckLevel) {
//Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
// Heuristic-elimintaed FastChecks
case NoCheck: {
if (IsOnRam(pc))
{
pc&=0xFFFFFF;
switch(pc)
{
//DOA2LE
case 0x3DAFC6:
case 0x3C83F8:
return true;
//Shenmue 2
case 0x348000:
//Shenmue
case 0x41860e:
default:
return false;
return FastCheck;
default:
return NoCheck;
}
}
return NoCheck;
}
break;
// Fast Check everything
case FastCheck:
return FastCheck;
// Full Check everything
case FullCheck:
return FullCheck;
default:
die("Unhandled settings.dynarec.SmcCheckLevel");
return FullCheck;
}
return false;
}
void AnalyseBlock(RuntimeBlockInfo* blk);

View File

@ -85,7 +85,7 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc);
void ngen_init();
//Called to compile a block
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise);
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise);
//Called when blocks are reseted
void ngen_ResetBlocks();

View File

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

View File

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

View File

@ -51,7 +51,39 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed)
if (key < 0x10000)
{
if (pressed)
{
kcode[_maple_port] &= ~(u16)key;
// Avoid two opposite dpad keys being pressed simultaneously
switch (key)
{
case DC_DPAD_UP:
kcode[_maple_port] |= (u16)DC_DPAD_DOWN;
break;
case DC_DPAD_DOWN:
kcode[_maple_port] |= (u16)DC_DPAD_UP;
break;
case DC_DPAD_LEFT:
kcode[_maple_port] |= (u16)DC_DPAD_RIGHT;
break;
case DC_DPAD_RIGHT:
kcode[_maple_port] |= (u16)DC_DPAD_LEFT;
break;
case DC_DPAD2_UP:
kcode[_maple_port] |= (u16)DC_DPAD2_DOWN;
break;
case DC_DPAD2_DOWN:
kcode[_maple_port] |= (u16)DC_DPAD2_UP;
break;
case DC_DPAD2_LEFT:
kcode[_maple_port] |= (u16)DC_DPAD2_RIGHT;
break;
case DC_DPAD2_RIGHT:
kcode[_maple_port] |= (u16)DC_DPAD2_LEFT;
break;
default:
break;
}
}
else
kcode[_maple_port] |= (u16)key;
}

View File

@ -84,8 +84,6 @@ Atom wmDeleteMessage;
void* x11_vis;
extern bool dump_frame_switch;
extern bool naomi_test_button;
extern bool coin_chute;
void dc_exit(void);
@ -275,16 +273,6 @@ void input_x11_handle()
x11_fullscreen = !x11_fullscreen;
x11_window_set_fullscreen(x11_fullscreen);
}
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
else if (e.xkey.keycode == KEY_F8)
{
coin_chute = e.type == KeyPress;
}
else if (e.xkey.keycode == KEY_F7)
{
naomi_test_button = e.type == KeyPress;
}
#endif
}
}
break;

View File

@ -134,7 +134,7 @@ void LoadSpecialSettings()
safemode_game = false;
tr_poly_depth_mask_game = false;
extra_depth_game = false;
if (reios_windows_ce)
{
printf("Enabling Extra depth scaling for Windows CE games\n");
@ -190,7 +190,7 @@ void LoadSpecialSettings()
}
#elif DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
printf("Game ID is [%s]\n", naomi_game_id);
if (!strcmp("METAL SLUG 6", naomi_game_id) || !strcmp("WAVE RUNNER GP", naomi_game_id))
{
printf("Enabling Dynarec safe mode for game %s\n", naomi_game_id);
@ -213,12 +213,14 @@ void LoadSpecialSettings()
printf("Enabling JVS rotary encoders for game %s\n", naomi_game_id);
settings.input.JammaSetup = 2;
}
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id))
else if (!strcmp("POWER STONE 2 JAPAN", naomi_game_id) // Naomi
|| !strcmp("GUILTY GEAR isuka", naomi_game_id)) // AW
{
printf("Enabling 4-player setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 1;
}
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id))
else if (!strcmp("SEGA MARINE FISHING JAPAN", naomi_game_id)
|| !strcmp(naomi_game_id, "BASS FISHING SIMULATOR VER.A")) // AW
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 3;
@ -228,9 +230,11 @@ void LoadSpecialSettings()
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 4;
}
else if (!strcmp("NINJA ASSAULT", naomi_game_id))
else if (!strcmp("NINJA ASSAULT", naomi_game_id)
|| !strcmp(naomi_game_id, "Sports Shooting USA") // AW
|| !strcmp(naomi_game_id, "SEGA CLAY CHALLENGE")) // AW
{
printf("Enabling specific JVS setup for game %s\n", naomi_game_id);
printf("Enabling lightgun setup for game %s\n", naomi_game_id);
settings.input.JammaSetup = 5;
}
else if (!strcmp(" BIOHAZARD GUN SURVIVOR2", naomi_game_id))
@ -309,11 +313,12 @@ int dc_start_game(const char *path)
{
InitSettings();
LoadSettings(false);
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (!settings.bios.UseReios)
#endif
LoadRomFiles(get_readonly_data_path(DATA_PATH));
if (!LoadRomFiles(get_readonly_data_path(DATA_PATH)))
return -5;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (path == NULL)
{
@ -345,7 +350,6 @@ int dc_start_game(const char *path)
return 0;
}
settings.dreamcast.RTC = GetRTC_now(); // FIXME This shouldn't be in settings anymore
if (settings.bios.UseReios || !LoadRomFiles(get_readonly_data_path(DATA_PATH)))
{
#ifdef USE_REIOS
@ -485,7 +489,6 @@ void dc_exit()
void InitSettings()
{
settings.dreamcast.RTC = GetRTC_now();
settings.dynarec.Enable = true;
settings.dynarec.idleskip = true;
settings.dynarec.unstable_opt = false;
@ -495,9 +498,11 @@ void InitSettings()
settings.dreamcast.broadcast = 4; // default
settings.dreamcast.language = 6; // default
settings.dreamcast.FullMMU = false;
settings.dynarec.SmcCheckLevel = FullCheck;
settings.aica.LimitFPS = true;
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
settings.aica.NoSound = false;
settings.audio.backend = "auto";
settings.rend.UseMipmaps = true;
settings.rend.WideScreen = false;
settings.rend.ShowFPS = false;
@ -512,6 +517,10 @@ void InitSettings()
settings.rend.CustomTextures = false;
settings.rend.DumpTextures = false;
settings.rend.ScreenScaling = 100;
settings.rend.ScreenStretching = 100;
settings.rend.Fog = true;
settings.rend.FloatVMUs = false;
settings.rend.Rotate90 = false;
settings.pvr.ta_skip = 0;
settings.pvr.rend = 0;
@ -558,11 +567,13 @@ void LoadSettings(bool game_specific)
{
const char *config_section = game_specific ? cfgGetGameId() : "config";
const char *input_section = game_specific ? cfgGetGameId() : "input";
const char *audio_section = game_specific ? cfgGetGameId() : "audio";
settings.dynarec.Enable = cfgLoadBool(config_section, "Dynarec.Enabled", settings.dynarec.Enable);
settings.dynarec.idleskip = cfgLoadBool(config_section, "Dynarec.idleskip", settings.dynarec.idleskip);
settings.dynarec.unstable_opt = cfgLoadBool(config_section, "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
settings.dynarec.safemode = cfgLoadBool(config_section, "Dynarec.safe-mode", settings.dynarec.safemode);
settings.dynarec.SmcCheckLevel = (SmcCheckEnum)cfgLoadInt(config_section, "Dynarec.SmcCheckLevel", settings.dynarec.SmcCheckLevel);
//disable_nvmem can't be loaded, because nvmem init is before cfg load
settings.dreamcast.cable = cfgLoadInt(config_section, "Dreamcast.Cable", settings.dreamcast.cable);
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region);
@ -572,6 +583,7 @@ void LoadSettings(bool game_specific)
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
settings.audio.backend = cfgLoadStr(audio_section, "backend", settings.audio.backend.c_str());
settings.rend.UseMipmaps = cfgLoadBool(config_section, "rend.UseMipmaps", settings.rend.UseMipmaps);
settings.rend.WideScreen = cfgLoadBool(config_section, "rend.WideScreen", settings.rend.WideScreen);
settings.rend.ShowFPS = cfgLoadBool(config_section, "rend.ShowFPS", settings.rend.ShowFPS);
@ -593,6 +605,10 @@ void LoadSettings(bool game_specific)
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100);
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
settings.rend.FloatVMUs = cfgLoadBool(config_section, "rend.FloatVMUs", settings.rend.FloatVMUs);
settings.rend.Rotate90 = cfgLoadBool(config_section, "rend.Rotate90", settings.rend.Rotate90);
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
settings.pvr.rend = cfgLoadInt(config_section, "pvr.rend", settings.pvr.rend);
@ -698,10 +714,13 @@ void SaveSettings()
cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
if (!safemode_game || !settings.dynarec.safemode)
cfgSaveBool("config", "Dynarec.safe-mode", settings.dynarec.safemode);
cfgSaveInt("config", "Dynarec.SmcCheckLevel", (int)settings.dynarec.SmcCheckLevel);
cfgSaveInt("config", "Dreamcast.Language", settings.dreamcast.language);
cfgSaveBool("config", "aica.LimitFPS", settings.aica.LimitFPS);
cfgSaveBool("config", "aica.NoBatch", settings.aica.NoBatch);
cfgSaveBool("config", "aica.NoSound", settings.aica.NoSound);
cfgSaveStr("audio", "backend", settings.audio.backend.c_str());
cfgSaveBool("config", "rend.WideScreen", settings.rend.WideScreen);
cfgSaveBool("config", "rend.ShowFPS", settings.rend.ShowFPS);
if (!rtt_to_buffer_game || !settings.rend.RenderToTextureBuffer)
@ -714,6 +733,10 @@ void SaveSettings()
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
cfgSaveBool("config", "rend.FloatVMUs", settings.rend.FloatVMUs);
cfgSaveBool("config", "rend.Rotate90", settings.rend.Rotate90);
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,14 +2,6 @@
#include "cfg/cfg.h"
#include "oslib/oslib.h"
#include "audiostream.h"
#include "oslib/audiobackend_directsound.h"
#include "oslib/audiobackend_android.h"
#include "oslib/audiobackend_alsa.h"
#include "oslib/audiobackend_oss.h"
#include "oslib/audiobackend_pulseaudio.h"
#include "oslib/audiobackend_coreaudio.h"
#include "oslib/audiobackend_omx.h"
#include "oslib/audiobackend_libao.h"
struct SoundFrame { s16 l;s16 r; };
#define SAMPLE_COUNT 512
@ -25,16 +17,27 @@ u32 gen_samples=0;
double time_diff = 128/44100.0;
double time_last;
#ifdef LOG_SOUND
// TODO Only works on Windows!
WaveWriter rawout("d:\\aica_out.wav");
#endif
static bool audiobackends_registered = false;
static unsigned int audiobackends_num_max = 1;
static unsigned int audiobackends_num_registered = 0;
static audiobackend_t **audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
static audiobackend_t **audiobackends = NULL;
static audiobackend_t *audiobackend_current = NULL;
u32 GetAudioBackendCount()
{
return audiobackends_num_registered;
}
audiobackend_t* GetAudioBackend(int num)
{
return audiobackends[num];
}
bool RegisterAudioBackend(audiobackend_t *backend)
{
/* This function announces the availability of an audio backend to reicast. */
@ -44,10 +47,16 @@ bool RegisterAudioBackend(audiobackend_t *backend)
printf("ERROR: Tried to register invalid audio backend (NULL pointer).\n");
return false;
}
if (backend->slug == "auto" || backend->slug == "none") {
printf("ERROR: Tried to register invalid audio backend (slug \"%s\" is a reserved keyword).\n", backend->slug.c_str());
return false;
}
// First call to RegisterAudioBackend(), create the backend structure;
if (audiobackends == NULL)
audiobackends = static_cast<audiobackend_t**>(calloc(audiobackends_num_max, sizeof(audiobackend_t*)));
// Check if we need to allocate addition memory for storing the pointers and allocate if neccessary
if (audiobackends_num_registered == audiobackends_num_max)
{
@ -67,46 +76,19 @@ bool RegisterAudioBackend(audiobackend_t *backend)
}
audiobackends = new_ptr;
}
audiobackends[audiobackends_num_registered] = backend;
audiobackends_num_registered++;
return true;
}
void RegisterAllAudioBackends() {
#if HOST_OS==OS_WINDOWS
RegisterAudioBackend(&audiobackend_directsound);
#endif
#if ANDROID
RegisterAudioBackend(&audiobackend_android);
#endif
#if USE_OMX
RegisterAudioBackend(&audiobackend_omx);
#endif
#if USE_ALSA
RegisterAudioBackend(&audiobackend_alsa);
#endif
#if USE_OSS
RegisterAudioBackend(&audiobackend_oss);
#endif
#if USE_PULSEAUDIO
RegisterAudioBackend(&audiobackend_pulseaudio);
#endif
#if USE_LIBAO
RegisterAudioBackend(&audiobackend_libao);
#endif
#if HOST_OS == OS_DARWIN
RegisterAudioBackend(&audiobackend_coreaudio);
#endif
audiobackends_registered = true;
}
static audiobackend_t* GetAudioBackend(std::string slug)
audiobackend_t* GetAudioBackend(std::string slug)
{
if (slug == "none")
{
printf("WARNING: Audio backend set to \"none\"!\n");
}
else if(audiobackends_num_registered > 0)
else if (audiobackends_num_registered > 0)
{
if (slug == "auto")
{
@ -135,7 +117,8 @@ static audiobackend_t* GetAudioBackend(std::string slug)
return NULL;
}
u32 PushAudio(void* frame, u32 amt, bool wait) {
u32 PushAudio(void* frame, u32 amt, bool wait)
{
if (audiobackend_current != NULL) {
return audiobackend_current->push(frame, amt, wait);
}
@ -151,6 +134,7 @@ u32 asRingUsedCount()
//s32 sz=(WritePtr+1)%RingBufferSampleCount-ReadPtr;
//return sz<0?sz+RingBufferSampleCount:sz;
}
u32 asRingFreeCount()
{
return RingBufferSampleCount-asRingUsedCount();
@ -169,6 +153,27 @@ void WriteSample(s16 r, s16 l)
}
}
static bool backends_sorted = false;
void SortAudioBackends()
{
if (backends_sorted)
return;
// Sort backends by slug
for (int n = audiobackends_num_registered; n > 0; n--)
{
for (int i = 0; i < n-1; i++)
{
if (audiobackends[i]->slug > audiobackends[i+1]->slug)
{
audiobackend_t* swap = audiobackends[i];
audiobackends[i] = audiobackends[i+1];
audiobackends[i+1] = swap;
}
}
}
}
void InitAudio()
{
if (cfgLoadInt("audio", "disable", 0)) {
@ -176,26 +181,24 @@ void InitAudio()
return;
}
cfgSaveInt("audio","disable",0);
if (!audiobackends_registered) {
//FIXME: There might some nicer way to do this.
RegisterAllAudioBackends();
}
cfgSaveInt("audio", "disable", 0);
if (audiobackend_current != NULL) {
printf("ERROR: The audio backend \"%s\" (%s) has already been initialized, you need to terminate it before you can call audio_init() again!\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
return;
}
string audiobackend_slug = cfgLoadStr("audio", "backend", "auto"); // FIXME: This could be made a parameter
SortAudioBackends();
string audiobackend_slug = settings.audio.backend;
audiobackend_current = GetAudioBackend(audiobackend_slug);
if (audiobackend_current == NULL) {
printf("WARNING: Running without audio!\n");
return;
}
printf("Initializing audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current->init();
audiobackend_current->init();
}
void TermAudio()
@ -204,5 +207,5 @@ void TermAudio()
audiobackend_current->term();
printf("Terminating audio backend \"%s\" (%s)...\n", audiobackend_current->slug.c_str(), audiobackend_current->name.c_str());
audiobackend_current = NULL;
}
}
}

View File

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

View File

@ -2082,7 +2082,7 @@ __default:
}
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
{
//printf("Compile: %08X, %d, %d\n",block->addr,staging,optimise);
block->code=(DynarecCodeEntryPtr)EMIT_GET_PTR();
@ -2114,39 +2114,68 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
reg.OpBegin(&block->oplist[0],0);
//scheduler
if (force_checks)
{
s32 sz = block->sh4_code_size;
u32 addr = block->addr;
MOV32(r0,addr);
switch (smc_checks) {
case NoCheck:
break;
while (sz > 0)
{
if (sz > 2)
case FastCheck: {
MOV32(r0,block->addr);
u32* ptr=(u32*)GetMemPtr(block->addr,4);
if (ptr != NULL)
{
u32* ptr=(u32*)GetMemPtr(addr,4);
MOV32(r2,(u32)ptr);
LDR(r2,r2,0);
MOV32(r1,*ptr);
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
addr += 4;
sz -= 4;
}
else
}
break;
case FullCheck: {
s32 sz = block->sh4_code_size;
u32 addr = block->addr;
MOV32(r0,addr);
while (sz > 0)
{
u16* ptr = (u16 *)GetMemPtr(addr, 2);
MOV32(r2, (u32)ptr);
LDRH(r2, r2, 0, AL);
MOVW(r1, *ptr, AL);
CMP(r1, r2);
if (sz > 2)
{
u32* ptr=(u32*)GetMemPtr(addr,4);
if (ptr != NULL)
{
MOV32(r2,(u32)ptr);
LDR(r2,r2,0);
MOV32(r1,*ptr);
CMP(r1,r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
addr += 2;
sz -= 2;
JUMP((u32)ngen_blockcheckfail, CC_NE);
}
addr += 4;
sz -= 4;
}
else
{
u16* ptr = (u16 *)GetMemPtr(addr, 2);
if (ptr != NULL)
{
MOV32(r2, (u32)ptr);
LDRH(r2, r2, 0, AL);
MOVW(r1, *ptr, AL);
CMP(r1, r2);
JUMP((u32)ngen_blockcheckfail, CC_NE);
}
addr += 2;
sz -= 2;
}
}
}
break;
default: {
die("unhandled smc_checks");
}
}
u32 cyc=block->guest_cycles;

View File

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

View File

@ -1190,10 +1190,10 @@ public:
size_t opcode_index;
opcodeExec** ptrsg;
void compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise) {
void compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise) {
//we need an extra one for the end opcode and optionally one more for block check
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (force_checks ? 1 : 0))(block->guest_cycles);
auto ptrs = fnnCtor_forreal(block->oplist.size() + 1 + (smc_checks != NoCheck ? 1 : 0))(block->guest_cycles);
ptrsg = ptrs.ptrs;
@ -1207,9 +1207,16 @@ public:
}
size_t i = 0;
if (force_checks)
if (smc_checks != NoCheck)
{
verify (smc_checks == FastCheck || smc_checks == FullCheck)
opcodeExec* op;
int check_size = block->sh4_code_size;
if (smc_checks == FastCheck) {
check_size = 4;
}
switch (block->sh4_code_size)
{
case 4:
@ -1227,6 +1234,7 @@ public:
}
ptrs.ptrs[i++] = op;
}
for (size_t opnum = 0; opnum < block->oplist.size(); opnum++, i++) {
opcode_index = i;
shil_opcode& op = block->oplist[opnum];
@ -1551,14 +1559,14 @@ public:
BlockCompiler* compiler;
void ngen_Compile(RuntimeBlockInfo* block, bool force_checks, bool reset, bool staging, bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging, bool optimise)
{
verify(emit_FreeSpace() >= 16 * 1024);
compiler = new BlockCompiler();
compiler->compile(block, force_checks, reset, staging, optimise);
compiler->compile(block, smc_checks, reset, staging, optimise);
delete compiler;
}

View File

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

View File

@ -229,29 +229,50 @@ u32 rdmt[6];
extern u32 memops_t,memops_l;
extern int mips_counter;
void CheckBlock(RuntimeBlockInfo* block,x86_ptr_imm place)
//TODO: Get back validating mode for this
void CheckBlock(SmcCheckEnum smc_checks, RuntimeBlockInfo* block)
{
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
while(sz>0)
{
void* ptr=(void*)GetMemPtr(sa,4);
if (ptr)
{
if (sz==2)
x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
else
x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
x86e->Emit(op_jne,place);
switch (smc_checks) {
case NoCheck:
break;
case FastCheck: {
void* ptr = (void*)GetMemPtr(block->addr, 4);
if (ptr)
{
x86e->Emit(op_cmp32, ptr, *(u32*)ptr);
x86e->Emit(op_jne, x86_ptr_imm(ngen_blockcheckfail));
}
}
sz-=4;
sa+=4;
break;
case FullCheck: {
s32 sz=block->sh4_code_size;
u32 sa=block->addr;
while(sz>0)
{
void* ptr=(void*)GetMemPtr(sa,4);
if (ptr)
{
if (sz==2)
x86e->Emit(op_cmp16,ptr,*(u16*)ptr);
else
x86e->Emit(op_cmp32,ptr,*(u32*)ptr);
x86e->Emit(op_jne,x86_ptr_imm(ngen_blockcheckfail));
}
sz-=4;
sa+=4;
}
}
break;
default:
die("unhandled smc_checks");
}
}
void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise)
void ngen_Compile(RuntimeBlockInfo* block, SmcCheckEnum smc_checks, bool reset, bool staging,bool optimise)
{
//initialise stuff
DetectCpuFeatures();
@ -282,7 +303,7 @@ void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool st
//block invl. checks
x86e->Emit(op_mov32,ECX,block->addr);
CheckBlock(block,force_checks?x86_ptr_imm(ngen_blockcheckfail):x86_ptr_imm(ngen_blockcheckfail2));
CheckBlock(smc_checks, block);
//Scheduler
x86_Label* no_up=x86e->CreateLabel(false,8);

View File

@ -331,23 +331,23 @@ void initABuffer()
{
char source[16384];
sprintf(source, final_shader_source, 1);
gl4CompilePipelineShader(&g_abuffer_final_shader, source);
gl4CompilePipelineShader(&g_abuffer_final_shader, false, source);
}
if (g_abuffer_final_nosort_shader.program == 0)
{
char source[16384];
sprintf(source, final_shader_source, 0);
gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, source);
gl4CompilePipelineShader(&g_abuffer_final_nosort_shader, false, source);
}
if (g_abuffer_clear_shader.program == 0)
gl4CompilePipelineShader(&g_abuffer_clear_shader, clear_shader_source);
gl4CompilePipelineShader(&g_abuffer_clear_shader, false, clear_shader_source);
if (g_abuffer_tr_modvol_shaders[0].program == 0)
{
char source[16384];
for (int mode = 0; mode < ModeCount; mode++)
{
sprintf(source, tr_modvol_shader_source, mode);
gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], source);
gl4CompilePipelineShader(&g_abuffer_tr_modvol_shaders[mode], false, source);
}
}
@ -417,6 +417,17 @@ void termABuffer()
glDeleteBuffers(1, &g_quadBuffer);
g_quadBuffer = 0;
}
glcache.DeleteProgram(g_abuffer_final_shader.program);
g_abuffer_final_shader.program = 0;
glcache.DeleteProgram(g_abuffer_final_nosort_shader.program);
g_abuffer_final_nosort_shader.program = 0;
glcache.DeleteProgram(g_abuffer_clear_shader.program);
g_abuffer_clear_shader.program = 0;
for (int mode = 0; mode < ModeCount; mode++)
{
glcache.DeleteProgram(g_abuffer_tr_modvol_shaders[mode].program);
g_abuffer_tr_modvol_shaders[mode].program = 0;
}
}
void reshapeABuffer(int w, int h)

View File

@ -1,6 +1,6 @@
#pragma once
#include "rend/gles/gles.h"
#include <map>
#include <unordered_map>
void gl4DrawStrips(GLuint output_fbo);
@ -44,7 +44,8 @@ struct gl4_ctx
GLuint extra_depth_scale;
} modvol_shader;
std::map<int, gl4PipelineShader *> shaders;
std::unordered_map<u32, gl4PipelineShader> shaders;
bool rotate90;
struct
{
@ -53,16 +54,6 @@ struct gl4_ctx
GLuint modvol_vao;
GLuint tr_poly_params;
} vbo;
gl4PipelineShader *getShader(int programId) {
gl4PipelineShader *shader = shaders[programId];
if (shader == NULL) {
shader = new gl4PipelineShader();
shaders[programId] = shader;
shader->program = -1;
}
return shader;
}
};
extern gl4_ctx gl4;
@ -76,7 +67,8 @@ bool gl4_render_output_framebuffer();
void abufferDrawQuad(bool upsideDown = false, float x = 0.f, float y = 0.f, float w = 0.f, float h = 0.f);
extern const char *gl4PixelPipelineShader;
bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *source = gl4PixelPipelineShader);
bool gl4CompilePipelineShader(gl4PipelineShader* s, bool rotate_90, const char *source = gl4PixelPipelineShader);
void gl4_delete_shaders();
extern GLuint stencilTexId;
extern GLuint depthTexId;

View File

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

View File

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

View File

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

View File

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

View File

@ -149,6 +149,19 @@ public:
return _texture_ids[--_texture_cache_size];
}
void DeleteProgram(GLuint program)
{
GLsizei shader_count;
GLuint shaders[2];
glGetAttachedShaders(program, ARRAY_SIZE(shaders), &shader_count, shaders);
for (int i = 0; i < shader_count; i++)
glDeleteShader(shaders[i]);
glDeleteProgram(program);
if (_program == program)
_program = 0;
}
void Reset() {
_texture = 0xFFFFFFFFu;
_src_blend_factor = 0xFFFFFFFFu;
@ -179,7 +192,7 @@ public:
void DisableCache() { _disable_cache = true; }
void EnableCache()
{
_disable_cache = true;
_disable_cache = false;
Reset();
}

View File

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

View File

@ -79,6 +79,7 @@ const char* VertexShaderSource =
%s \n\
#define TARGET_GL %s \n\
#define pp_Gouraud %d \n\
#define ROTATE_90 %d \n\
\n\
#define GLES2 0 \n\
#define GLES3 1 \n\
@ -136,6 +137,9 @@ void main() \n\
vpos.z = vpos.w; \n\
#else \n\
vpos.z=depth_scale.x+depth_scale.y*vpos.w; \n\
#endif \n\
#if ROTATE_90 == 1 \n\
vpos.xy = vec2(vpos.y, -vpos.x); \n\
#endif \n\
vpos.xy=vpos.xy*scale.xy-scale.zw; \n\
vpos.xy*=vpos.w; \n\
@ -850,9 +854,20 @@ GLuint fogTextureId;
extern void gl_term();
#endif
static void gl_delete_shaders()
{
for (auto it : gl.shaders)
{
if (it.second.program != 0)
glcache.DeleteProgram(it.second.program);
}
gl.shaders.clear();
glcache.DeleteProgram(gl.modvol_shader.program);
gl.modvol_shader.program = 0;
}
static void gles_term()
{
glDeleteProgram(gl.modvol_shader.program);
glDeleteBuffers(1, &gl.vbo.geometry);
gl.vbo.geometry = 0;
glDeleteBuffers(1, &gl.vbo.modvols);
@ -865,7 +880,7 @@ static void gles_term()
gl_free_osd_resources();
free_output_framebuffer();
memset(gl.pogram_table, 0, sizeof(gl.pogram_table));
gl_delete_shaders();
gl_term();
}
@ -1014,10 +1029,15 @@ GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader)
return program;
}
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear)
{
if (settings.rend.Rotate90 != gl.rotate90)
{
gl_delete_shaders();
gl.rotate90 = settings.rend.Rotate90;
}
u32 rv=0;
rv|=pp_ClipTestMode;
@ -1033,14 +1053,32 @@ int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
rv<<=1; rv|=fog_clamping;
rv<<=1; rv|=trilinear;
return rv;
PipelineShader *shader = &gl.shaders[rv];
if (shader->program == 0)
{
shader->cp_AlphaTest = cp_AlphaTest;
shader->pp_ClipTestMode = pp_ClipTestMode-1;
shader->pp_Texture = pp_Texture;
shader->pp_UseAlpha = pp_UseAlpha;
shader->pp_IgnoreTexA = pp_IgnoreTexA;
shader->pp_ShadInstr = pp_ShadInstr;
shader->pp_Offset = pp_Offset;
shader->pp_FogCtrl = pp_FogCtrl;
shader->pp_Gouraud = pp_Gouraud;
shader->pp_BumpMap = pp_BumpMap;
shader->fog_clamping = fog_clamping;
shader->trilinear = trilinear;
CompilePipelineShader(shader);
}
return shader;
}
bool CompilePipelineShader( PipelineShader* s)
{
char vshader[8192];
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud);
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud, settings.rend.Rotate90);
char pshader[8192];
@ -1126,13 +1164,30 @@ void gl_load_osd_resources()
void gl_free_osd_resources()
{
glDeleteProgram(gl.OSD_SHADER.program);
glcache.DeleteProgram(gl.OSD_SHADER.program);
if (osd_tex != 0) {
glcache.DeleteTextures(1, &osd_tex);
osd_tex = 0;
}
}
static void create_modvol_shader()
{
if (gl.modvol_shader.program != 0)
return;
char vshader[8192];
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1, settings.rend.Rotate90);
char fshader[8192];
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
}
bool gl_create_resources()
{
if (gl.vbo.geometry != 0)
@ -1156,84 +1211,7 @@ bool gl_create_resources()
glGenBuffers(1, &gl.vbo.idxs);
glGenBuffers(1, &gl.vbo.idxs2);
memset(gl.pogram_table,0,sizeof(gl.pogram_table));
PipelineShader* dshader=0;
u32 compile=0;
#define forl(name,max) for(u32 name=0;name<=max;name++)
forl(cp_AlphaTest,1)
{
forl(pp_ClipTestMode,2)
{
forl(pp_UseAlpha,1)
{
forl(pp_Texture,1)
{
forl(pp_FogCtrl,3)
{
forl(pp_IgnoreTexA,1)
{
forl(pp_ShadInstr,3)
{
forl(pp_Offset,1)
{
forl(pp_Gouraud,1)
{
forl(pp_BumpMap,1)
{
forl(fog_clamping,1)
{
forl(trilinear,1)
{
dshader=&gl.pogram_table[GetProgramID(cp_AlphaTest,pp_ClipTestMode,pp_Texture,pp_UseAlpha,pp_IgnoreTexA,
pp_ShadInstr,pp_Offset,pp_FogCtrl, (bool)pp_Gouraud, (bool)pp_BumpMap, (bool)fog_clamping,
(bool)trilinear)];
dshader->cp_AlphaTest = cp_AlphaTest;
dshader->pp_ClipTestMode = pp_ClipTestMode-1;
dshader->pp_Texture = pp_Texture;
dshader->pp_UseAlpha = pp_UseAlpha;
dshader->pp_IgnoreTexA = pp_IgnoreTexA;
dshader->pp_ShadInstr = pp_ShadInstr;
dshader->pp_Offset = pp_Offset;
dshader->pp_FogCtrl = pp_FogCtrl;
dshader->pp_Gouraud = pp_Gouraud;
dshader->pp_BumpMap = pp_BumpMap;
dshader->fog_clamping = fog_clamping;
dshader->trilinear = trilinear;
dshader->program = -1;
}
}
}
}
}
}
}
}
}
}
}
}
char vshader[8192];
sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, 1);
char fshader[8192];
sprintf(fshader, ModifierVolumeShader, gl.glsl_version_header, gl.gl_version);
gl.modvol_shader.program=gl_CompileAndLink(vshader, fshader);
gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale");
gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor");
gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale");
gl.modvol_shader.extra_depth_scale = glGetUniformLocation(gl.modvol_shader.program, "extra_depth_scale");
//#define PRECOMPILE_SHADERS
#ifdef PRECOMPILE_SHADERS
for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
{
if (!CompilePipelineShader( &gl.pogram_table[i] ))
return false;
}
#endif
create_modvol_shader();
gl_load_osd_resources();
@ -1553,6 +1531,7 @@ static void upload_vertex_indices()
bool RenderFrame()
{
DoCleanup();
create_modvol_shader();
bool is_rtt=pvrrc.isRTT;
@ -1719,17 +1698,41 @@ bool RenderFrame()
/*
Handle Dc to screen scaling
*/
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
float screen_stretching = settings.rend.ScreenStretching / 100.f;
float screen_scaling = settings.rend.ScreenScaling / 100.f;
//-1 -> too much to left
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1);
float dc2s_scale_h;
float ds2s_offs_x;
if (is_rtt)
{
ShaderUniforms.scale_coefs[0] = 2.0f / dc_width;
ShaderUniforms.scale_coefs[1] = 2.0f / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2] = 1;
ShaderUniforms.scale_coefs[3] = 1;
}
else
{
if (settings.rend.Rotate90)
{
dc2s_scale_h = screen_height / 640.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 480.0f * screen_stretching) / 2;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1] = -2.0f / dc_width;
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3] = 1;
}
else
{
dc2s_scale_h = screen_height / 480.0f;
ds2s_offs_x = (screen_width - dc2s_scale_h * 640.0f * screen_stretching) / 2;
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1] = -2.0f / dc_height;
ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3] = -1;
}
//-1 -> too much to left
}
ShaderUniforms.depth_coefs[0]=2/(vtx_max_fZ-vtx_min_fZ);
ShaderUniforms.depth_coefs[1]=-vtx_min_fZ-1;
@ -1768,7 +1771,7 @@ bool RenderFrame()
ShaderUniforms.fog_clamp_max[2] = ((pvrrc.fog_clamp_max >> 0) & 0xFF) / 255.0f;
ShaderUniforms.fog_clamp_max[3] = ((pvrrc.fog_clamp_max >> 24) & 0xFF) / 255.0f;
if (fog_needs_update)
if (fog_needs_update && settings.rend.Fog)
{
fog_needs_update = false;
UpdateFogTexture((u8 *)FOG_TABLE, GL_TEXTURE1, gl.fog_image_format);
@ -1782,16 +1785,12 @@ bool RenderFrame()
ShaderUniforms.PT_ALPHA=(PT_ALPHA_REF&0xFF)/255.0f;
// for (u32 i=0;i<sizeof(gl.pogram_table)/sizeof(gl.pogram_table[0]);i++)
// {
// PipelineShader* s=&gl.pogram_table[i];
// if (s->program == -1)
// continue;
//
// glcache.UseProgram(s->program);
//
// ShaderUniforms.Set(s);
// }
for (auto it : gl.shaders)
{
glcache.UseProgram(it.second.program);
ShaderUniforms.Set(&it.second);
}
//setup render target first
if (is_rtt)
{
@ -1836,7 +1835,7 @@ bool RenderFrame()
{
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
}
else
{
@ -1883,9 +1882,6 @@ bool RenderFrame()
glBufferData(GL_ARRAY_BUFFER,pvrrc.modtrig.bytes(),pvrrc.modtrig.head(),GL_STREAM_DRAW); glCheck();
}
int offs_x=ds2s_offs_x+0.5f;
//this needs to be scaled
//not all scaling affects pixel operations, scale to adjust for that
scale_x *= scissoring_scale_x;
@ -1904,22 +1900,31 @@ bool RenderFrame()
float min_y = pvrrc.fb_Y_CLIP.min / scale_y;
if (!is_rtt)
{
if (settings.rend.Rotate90)
{
float t = width;
width = height;
height = t;
t = min_x;
min_x = min_y;
min_y = 640 - t - height;
}
// Add x offset for aspect ratio > 4/3
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
min_x = (min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x) * screen_scaling;
// Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
width *= dc2s_scale_h;
height *= dc2s_scale_h;
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h * screen_stretching * screen_scaling;
height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0)
{
float rounded_offs_x = ds2s_offs_x + 0.5f;
float scaled_offs_x = ds2s_offs_x * screen_scaling;
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST);
glScissor(0, 0, rounded_offs_x, screen_height);
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
}
}

View File

@ -1,4 +1,6 @@
#pragma once
#include <unordered_map>
#include <atomic>
#include "rend/rend.h"
#if (defined(GLES) && !defined(TARGET_NACL32) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(_ANDROID)
@ -93,7 +95,9 @@ struct gl_ctx
} modvol_shader;
PipelineShader pogram_table[24576];
std::unordered_map<u32, PipelineShader> shaders;
bool rotate90;
struct
{
GLuint program;
@ -117,6 +121,7 @@ struct gl_ctx
struct
{
GLuint depthb;
GLuint colorb;
GLuint tex;
GLuint fbo;
int width;
@ -176,7 +181,7 @@ void free_output_framebuffer();
void HideOSD();
void OSD_DRAW(bool clear_screen);
int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode,
PipelineShader *GetProgram(u32 cp_AlphaTest, u32 pp_ClipTestMode,
u32 pp_Texture, u32 pp_UseAlpha, u32 pp_IgnoreTexA, u32 pp_ShadInstr, u32 pp_Offset,
u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear);
@ -223,9 +228,6 @@ extern struct ShaderUniforms_t
if (s->sp_FOG_COL_VERT!=-1)
glUniform3fv( s->sp_FOG_COL_VERT, 1, ps_FOG_COL_VERT);
if (s->trilinear_alpha != -1)
glUniform1f(s->trilinear_alpha, trilinear_alpha);
if (s->fog_clamp_min != -1)
glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min);
if (s->fog_clamp_max != -1)
@ -272,10 +274,10 @@ struct TextureCacheData
//a texture can't be both VQ and PAL at the same time
u32 texture_hash; // xxhash of texture data, used for custom textures
u32 old_texture_hash; // legacy hash
u8* custom_image_data; // loaded custom image data
u32 custom_width;
u32 custom_height;
bool custom_load_in_progress;
u8* volatile custom_image_data; // loaded custom image data
volatile u32 custom_width;
volatile u32 custom_height;
std::atomic_int custom_load_in_progress;
void PrintTextureName();

View File

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

View File

@ -67,6 +67,7 @@
#endif
#include "gles.h"
#include "glcache.h"
// OpenGL Data
static char g_GlslVersionString[32] = "";
@ -127,28 +128,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
// Backup GL state
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
glActiveTexture(GL_TEXTURE0);
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
#ifdef GL_POLYGON_MODE
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
#endif
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
bool clip_origin_lower_left = true;
#ifdef GL_CLIP_ORIGIN
if (gl.gl_major >= 4 && glClipControl != NULL)
@ -166,13 +146,13 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
// (Re-)create the background texture and reserve space for it
if (g_BackgroundTexture != 0)
glDeleteTextures(1, &g_BackgroundTexture);
glGenTextures(1, &g_BackgroundTexture);
glBindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glcache.DeleteTextures(1, &g_BackgroundTexture);
g_BackgroundTexture = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, g_BackgroundTexture);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_width, fb_height, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)NULL);
// Copy the current framebuffer into it
@ -180,12 +160,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
}
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND);
glcache.Enable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glcache.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glcache.Disable(GL_CULL_FACE);
glcache.Disable(GL_DEPTH_TEST);
glcache.Enable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
if (glPolygonMode != NULL)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
@ -205,7 +185,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
};
glUseProgram(g_ShaderHandle);
glcache.UseProgram(g_ShaderHandle);
glUniform1i(g_AttribLocationTex, 0);
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
if (gl.gl_major >= 3 && glBindSampler != NULL)
@ -260,7 +240,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
}
}
@ -269,28 +249,6 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data, bool save_backgr
}
if (vao_handle != 0)
glDeleteVertexArrays(1, &vao_handle);
// Restore modified GL state
glUseProgram(last_program);
glBindTexture(GL_TEXTURE_2D, last_texture);
if (gl.gl_major >= 3 && glBindSampler != NULL)
glBindSampler(0, last_sampler);
glActiveTexture(last_active_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
if (gl.gl_major >= 3)
glBindVertexArray(last_vertex_array);
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef GL_POLYGON_MODE
if (glPolygonMode != NULL)
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
}
bool ImGui_ImplOpenGL3_CreateFontsTexture()
@ -302,21 +260,16 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
GLint last_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGenTextures(1, &g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
g_FontTexture = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, g_FontTexture);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
return true;
}
@ -325,7 +278,7 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
if (g_FontTexture)
{
ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture);
glcache.DeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0;
g_FontTexture = 0;
}
@ -369,12 +322,6 @@ static bool CheckProgram(GLuint handle, const char* desc)
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
{
// Backup GL state
GLint last_texture, last_array_buffer, last_vertex_array;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
// Parse GLSL version string
int glsl_version = 130;
sscanf(g_GlslVersionString, "#version %d", &glsl_version);
@ -534,12 +481,6 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
ImGui_ImplOpenGL3_CreateFontsTexture();
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
if (gl.gl_major >= 3)
glBindVertexArray(last_vertex_array);
return true;
}
@ -549,26 +490,23 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle);
g_VboHandle = g_ElementsHandle = 0;
if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle);
if (g_VertHandle) glDeleteShader(g_VertHandle);
glcache.DeleteProgram(g_ShaderHandle);
g_VertHandle = 0;
if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle);
if (g_FragHandle) glDeleteShader(g_FragHandle);
g_FragHandle = 0;
if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle);
g_ShaderHandle = 0;
ImGui_ImplOpenGL3_DestroyFontsTexture();
if (g_BackgroundTexture != 0)
glDeleteTextures(1, &g_BackgroundTexture);
glcache.DeleteTextures(1, &g_BackgroundTexture);
g_BackgroundTexture = 0;
}
void ImGui_ImplOpenGL3_DrawBackground()
{
glcache.Disable(GL_SCISSOR_TEST);
glcache.ClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
if (g_BackgroundTexture != 0)
{
ImGuiIO& io = ImGui::GetIO();
@ -579,20 +517,14 @@ void ImGui_ImplOpenGL3_DrawBackground()
ImGui::GetWindowDrawList()->AddImage((ImTextureID)(uintptr_t)g_BackgroundTexture, ImVec2(0, 0), io.DisplaySize, ImVec2(0, 1), ImVec2(1, 0), 0xffffffff);
ImGui::End();
}
else
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
}
}
ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
{
GLuint tex_id;
glGenTextures(1, &tex_id);
glBindTexture(GL_TEXTURE_2D, tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLuint tex_id = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, tex_id);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 48, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
return reinterpret_cast<ImTextureID>(tex_id);
@ -600,5 +532,5 @@ ImTextureID ImGui_ImplOpenGL3_CreateVmuTexture(const unsigned int *data)
void ImGui_ImplOpenGL3_DeleteVmuTexture(ImTextureID tex_id)
{
glDeleteTextures(1, &(GLuint &)tex_id);
glcache.DeleteTextures(1, &(GLuint &)tex_id);
}

View File

@ -39,7 +39,9 @@
#include "linux-dist/main.h" // FIXME for kcode[]
#include "gui_util.h"
#include "gui_android.h"
#include "version.h"
#include "version/version.h"
#include "oslib/audiostream.h"
extern void dc_loadstate();
extern void dc_savestate();
@ -299,7 +301,9 @@ static void gui_display_commands()
if (!settings_opening)
ImGui_ImplOpenGL3_DrawBackground();
display_vmus();
if (!settings.rend.FloatVMUs)
// If floating VMUs, they are already visible on the background
display_vmus();
ImGui::SetNextWindowPos(ImVec2(screen_width / 2.f, screen_height / 2.f), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowSize(ImVec2(330 * scaling, 0));
@ -622,6 +626,8 @@ void directory_selected_callback(bool cancelled, std::string selection)
static void gui_display_settings()
{
static bool maple_devices_changed;
ImGui_Impl_NewFrame();
ImGui::NewFrame();
@ -644,10 +650,14 @@ static void gui_display_settings()
gui_state = Commands;
else
gui_state = Main;
if (maple_devices_changed)
{
maple_devices_changed = false;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
maple_ReconnectDevices();
reset_vmus();
maple_ReconnectDevices();
reset_vmus();
#endif
}
SaveSettings();
}
if (game_started)
@ -801,13 +811,14 @@ static void gui_display_settings()
if (ImGui::BeginTabItem("Controls"))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding);
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (ImGui::CollapsingHeader("Dreamcast Devices", ImGuiTreeNodeFlags_DefaultOpen))
{
for (int bus = 0; bus < MAPLE_PORTS; bus++)
{
ImGui::Text("Device %c", bus + 'A');
ImGui::SameLine();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
char device_name[32];
sprintf(device_name, "##device%d", bus);
float w = ImGui::CalcItemWidth() / 3;
@ -818,7 +829,10 @@ static void gui_display_settings()
{
bool is_selected = settings.input.maple_devices[bus] == maple_device_type_from_index(i);
if (ImGui::Selectable(maple_device_types[i], &is_selected))
{
settings.input.maple_devices[bus] = maple_device_type_from_index(i);
maple_devices_changed = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
@ -836,7 +850,10 @@ static void gui_display_settings()
{
bool is_selected = settings.input.maple_expansion_devices[bus][port] == maple_expansion_device_type_from_index(i);
if (ImGui::Selectable(maple_expansion_device_types[i], &is_selected))
{
settings.input.maple_expansion_devices[bus][port] = maple_expansion_device_type_from_index(i);
maple_devices_changed = true;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
@ -845,6 +862,10 @@ static void gui_display_settings()
ImGui::PopID();
}
ImGui::PopItemWidth();
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
if (MapleDevices[bus][5] != NULL)
ImGui::Text("%s", maple_device_name(MapleDevices[bus][5]->get_device_type()));
#endif
}
ImGui::Spacing();
}
@ -945,15 +966,27 @@ static void gui_display_settings()
ImGui::Checkbox("Shadows", &settings.rend.ModifierVolumes);
ImGui::SameLine();
ShowHelpMarker("Enable modifier volumes, usually used for shadows");
ImGui::Checkbox("Fog", &settings.rend.Fog);
ImGui::SameLine();
ShowHelpMarker("Enable fog effects");
ImGui::Checkbox("Widescreen", &settings.rend.WideScreen);
ImGui::SameLine();
ShowHelpMarker("Draw geometry outside of the normal 4:3 aspect ratio. May produce graphical glitches in the revealed areas");
ImGui::Checkbox("Show FPS Counter", &settings.rend.ShowFPS);
ImGui::SameLine();
ShowHelpMarker("Show on-screen frame/sec counter");
ImGui::Checkbox("Show VMU in game", &settings.rend.FloatVMUs);
ImGui::SameLine();
ShowHelpMarker("Show the VMU LCD screens while in game");
ImGui::Checkbox("Rotate screen 90°", &settings.rend.Rotate90);
ImGui::SameLine();
ShowHelpMarker("Rotate the screen 90° counterclockwise");
ImGui::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100);
ImGui::SameLine();
ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better");
ImGui::SliderInt("Horizontal Stretching", (int *)&settings.rend.ScreenStretching, 100, 150);
ImGui::SameLine();
ShowHelpMarker("Stretch the screen horizontally");
ImGui::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6);
ImGui::SameLine();
ShowHelpMarker("Number of frames to skip between two actually rendered frames");
@ -991,6 +1024,48 @@ static void gui_display_settings()
ImGui::Checkbox("Disable Sound", &settings.aica.NoSound);
ImGui::SameLine();
ShowHelpMarker("Disable the emulator sound output");
audiobackend_t* backend = NULL;;
std::string backend_name = settings.audio.backend;
if (backend_name != "auto" && backend_name != "none")
{
backend = GetAudioBackend(settings.audio.backend);
if (backend != NULL)
backend_name = backend->slug;
}
SortAudioBackends();
if (ImGui::BeginCombo("Audio Backend", backend_name.c_str(), ImGuiComboFlags_None))
{
bool is_selected = (settings.audio.backend == "auto");
if (ImGui::Selectable("auto", &is_selected))
settings.audio.backend = "auto";
ImGui::SameLine(); ImGui::Text("-");
ImGui::SameLine(); ImGui::Text("Autoselect audio backend");
is_selected = (settings.audio.backend == "none");
if (ImGui::Selectable("none", &is_selected))
settings.audio.backend = "none";
ImGui::SameLine(); ImGui::Text("-");
ImGui::SameLine(); ImGui::Text("No audio backend");
for (int i = 0; i < GetAudioBackendCount(); i++)
{
audiobackend_t* backend = GetAudioBackend(i);
is_selected = (settings.audio.backend == backend->slug);
if (ImGui::Selectable(backend->slug.c_str(), &is_selected))
settings.audio.backend = backend->slug;
ImGui::SameLine(); ImGui::Text("-");
ImGui::SameLine(); ImGui::Text(backend->name.c_str());
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::SameLine();
ShowHelpMarker("The audio backend to use");
ImGui::Checkbox("Enable DSP", &settings.aica.NoBatch);
ImGui::SameLine();
ShowHelpMarker("Enable the Dreamcast Digital Sound Processor. Only recommended on fast and arm64 platforms");
@ -1022,10 +1097,33 @@ static void gui_display_settings()
ShowHelpMarker("Do not optimize integer division. Recommended");
ImGui::Checkbox("Unstable Optimizations", &settings.dynarec.unstable_opt);
ImGui::SameLine();
ShowHelpMarker("Enable unsafe optimizations. May cause crash or environmental disaster");
ShowHelpMarker("Enable unsafe optimizations. Will cause crash or environmental disaster");
ImGui::Checkbox("Idle Skip", &settings.dynarec.idleskip);
ImGui::SameLine();
ShowHelpMarker("Skip wait loops. Recommended");
ImGui::PushItemWidth(ImGui::CalcTextSize("Largeenough").x);
const char *preview = settings.dynarec.SmcCheckLevel == NoCheck ? "Faster" : settings.dynarec.SmcCheckLevel == FastCheck ? "Fast" : "Full";
if (ImGui::BeginCombo("SMC Checks", preview , ImGuiComboFlags_None))
{
bool is_selected = settings.dynarec.SmcCheckLevel == NoCheck;
if (ImGui::Selectable("Faster", &is_selected))
settings.dynarec.SmcCheckLevel = NoCheck;
if (is_selected)
ImGui::SetItemDefaultFocus();
is_selected = settings.dynarec.SmcCheckLevel == FastCheck;
if (ImGui::Selectable("Fast", &is_selected))
settings.dynarec.SmcCheckLevel = FastCheck;
if (is_selected)
ImGui::SetItemDefaultFocus();
is_selected = settings.dynarec.SmcCheckLevel == FullCheck;
if (ImGui::Selectable("Full", &is_selected))
settings.dynarec.SmcCheckLevel = FullCheck;
if (is_selected)
ImGui::SetItemDefaultFocus();
ImGui::EndCombo();
}
ImGui::SameLine();
ShowHelpMarker("How to detect self-modifying code. Full check recommended");
}
if (ImGui::CollapsingHeader("Other", ImGuiTreeNodeFlags_DefaultOpen))
{
@ -1230,6 +1328,7 @@ static void gui_start_game(const std::string& path)
{
gui_state = Main;
game_started = false;
cfgSetVirtual("config", "image", "");
switch (rc) {
case -3:
error_msg = "Audio/video initialization failed";
@ -1387,24 +1486,6 @@ void gui_display_ui()
gui_state = Closed;
}
void gui_display_fps(const char *string)
{
ImGui_Impl_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::Begin("##fps", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(2);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", string);
ImGui::End();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
static float LastFPSTime;
static int lastFrameCount = 0;
static float fps = -1;
@ -1452,26 +1533,32 @@ void gui_display_osd()
if (osd_message.empty())
{
message = getFPSNotification();
if (message.empty())
return;
}
else
message = osd_message;
ImGui_Impl_NewFrame();
ImGui::NewFrame();
if (!message.empty() || settings.rend.FloatVMUs)
{
ImGui_Impl_NewFrame();
ImGui::NewFrame();
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
if (!message.empty())
{
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(1.5);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
ImGui::End();
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
ImGui::SetWindowFontScale(1.5);
ImGui::TextColored(ImVec4(1, 1, 0, 0.7), "%s", message.c_str());
ImGui::End();
}
if (settings.rend.FloatVMUs)
display_vmus();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
}
void gui_open_onboarding()

View File

@ -39,7 +39,7 @@
#undef _CRT_SECURE_NO_DEPRECATE
#endif
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE
//unnamed struncts/unions
#pragma warning( disable : 4201)
@ -123,7 +123,7 @@ enum HollyInterruptType
};
enum HollyInterruptID
{
{
// asic9a /sh4 external holly normal [internal]
holly_RENDER_DONE_vd = holly_nrm | 0, //bit 0 = End of Render interrupt : Video
holly_RENDER_DONE_isp = holly_nrm | 1, //bit 1 = End of Render interrupt : ISP
@ -132,11 +132,11 @@ enum HollyInterruptID
holly_SCANINT1 = holly_nrm | 3, //bit 3 = V Blank-in interrupt
holly_SCANINT2 = holly_nrm | 4, //bit 4 = V Blank-out interrupt
holly_HBLank = holly_nrm | 5, //bit 5 = H Blank-in interrupt
holly_YUV_DMA = holly_nrm | 6, //bit 6 = End of Transferring interrupt : YUV
holly_OPAQUE = holly_nrm | 7, //bit 7 = End of Transferring interrupt : Opaque List
holly_OPAQUEMOD = holly_nrm | 8, //bit 8 = End of Transferring interrupt : Opaque Modifier Volume List
holly_TRANS = holly_nrm | 9, //bit 9 = End of Transferring interrupt : Translucent List
holly_TRANSMOD = holly_nrm | 10, //bit 10 = End of Transferring interrupt : Translucent Modifier Volume List
holly_PVR_DMA = holly_nrm | 11, //bit 11 = End of DMA interrupt : PVR-DMA
@ -145,12 +145,12 @@ enum HollyInterruptID
holly_MAPLE_VBOI = holly_nrm | 13, //bit 13 = Maple V blank over interrupt
holly_GDROM_DMA = holly_nrm | 14, //bit 14 = End of DMA interrupt : GD-DMA
holly_SPU_DMA = holly_nrm | 15, //bit 15 = End of DMA interrupt : AICA-DMA
holly_EXT_DMA1 = holly_nrm | 16, //bit 16 = End of DMA interrupt : Ext-DMA1(External 1)
holly_EXT_DMA2 = holly_nrm | 17, //bit 17 = End of DMA interrupt : Ext-DMA2(External 2)
holly_DEV_DMA = holly_nrm | 18, //bit 18 = End of DMA interrupt : Dev-DMA(Development tool DMA)
holly_CH2_DMA = holly_nrm | 19, //bit 19 = End of DMA interrupt : ch2-DMA
holly_CH2_DMA = holly_nrm | 19, //bit 19 = End of DMA interrupt : ch2-DMA
holly_PVR_SortDMA = holly_nrm | 20, //bit 20 = End of DMA interrupt : Sort-DMA (Transferring for alpha sorting)
holly_PUNCHTHRU = holly_nrm | 21, //bit 21 = End of Transferring interrupt : Punch Through List
@ -188,8 +188,8 @@ enum HollyInterruptID
//bit 23 = G2 : AICA-DMA Time out
//bit 24 = G2 : Ext-DMA1 Time out
//bit 25 = G2 : Ext-DMA2 Time out
//bit 26 = G2 : Dev-DMA Time out
//bit 27 = G2 : Time out in CPU accessing
//bit 26 = G2 : Dev-DMA Time out
//bit 27 = G2 : Time out in CPU accessing
};
@ -200,7 +200,7 @@ struct vram_block
u32 end;
u32 len;
u32 type;
void* userdata;
};
@ -229,7 +229,7 @@ struct NDC_WINDOW_RECT
//******************************************************
//*********************** PowerVR **********************
//******************************************************
void libCore_vramlock_Unlock_block (vram_block* block);
void libCore_vramlock_Unlock_block_wb (vram_block* block);
vram_block* libCore_vramlock_Lock(u32 start_offset,u32 end_offset,void* userdata);
@ -246,7 +246,7 @@ enum DiscType
CdRom_XA=0x20,
CdRom_Extra=0x30,
CdRom_CDI=0x40,
GdRom=0x80,
GdRom=0x80,
NoDisk=0x1, //These are a bit hacky .. but work for now ...
Open=0x2, //tray is open :)
@ -576,7 +576,7 @@ enum RegIO
RIO_RO = REG_RO | REG_WF,
RIO_RO_FUNC = REG_RO | REG_RF | REG_WF,
RIO_CONST = REG_RO | REG_WF,
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
RIO_NO_ACCESS = REG_WF | REG_RF | REG_NO_ACCESS
};
@ -601,6 +601,11 @@ struct RegisterStruct
u32 flags; //Access flags !
};
enum SmcCheckEnum {
FullCheck = 0,
FastCheck = 1,
NoCheck = 2
};
struct settings_t
{
@ -627,7 +632,11 @@ struct settings_t
f32 ExtraDepthScale;
bool CustomTextures;
bool DumpTextures;
int ScreenScaling; // in percent. 50 means half the native resolution
int ScreenScaling; // in percent. 50 means half the native resolution
int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3
bool Fog;
bool FloatVMUs;
bool Rotate90; // Rotate the screen 90 deg CC
} rend;
struct
@ -637,8 +646,9 @@ struct settings_t
bool unstable_opt;
bool safemode;
bool disable_nvmem;
SmcCheckEnum SmcCheckLevel;
} dynarec;
struct
{
u32 run_counts;
@ -647,7 +657,6 @@ struct settings_t
struct
{
u32 cable; // 0 -> VGA, 1 -> VGA, 2 -> RGB, 3 -> TV
u32 RTC;
u32 region; // 0 -> JP, 1 -> USA, 2 -> EU, 3 -> default
u32 broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default
u32 language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default
@ -670,6 +679,9 @@ struct settings_t
bool NoSound;
} aica;
struct{
std::string backend;
} audio;
#if USE_OMX
struct
{
@ -699,7 +711,7 @@ struct settings_t
{
u32 ta_skip;
u32 rend;
u32 MaxThreads;
bool SynchronousRender;
} pvr;
@ -742,7 +754,7 @@ static inline void do_nada(...) { }
#ifdef _ANDROID
#include <android/log.h>
#ifdef printf
#ifdef printf
#undef printf
#endif
@ -849,7 +861,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \
return *(u16*)&arr[addr]; \
else if (sz==4) \
return *(u32*)&arr[addr];}
return *(u32*)&arr[addr];}
#define WriteMemArr(arr,addr,data,sz) \
{if(sz==1) \
@ -857,7 +869,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \
{*(u16*)&arr[addr]=(u16)data;} \
else if (sz==4) \
{*(u32*)&arr[addr]=data;}}
{*(u32*)&arr[addr]=data;}}
#define WriteMemArrRet(arr,addr,data,sz) \
{if(sz==1) \
@ -865,7 +877,7 @@ void libARM_Update(u32 cycles);
else if (sz==2) \
{*(u16*)&arr[addr]=(u16)data;return;} \
else if (sz==4) \
{*(u32*)&arr[addr]=data;return;}}
{*(u32*)&arr[addr]=data;return;}}
struct OnLoad
{

View File

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

View File

@ -52,5 +52,56 @@
android:scheme="file" />
</intent-filter>
</activity>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.GDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.gdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CHD"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.chd"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CDI"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cdi"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.CUE"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.cue"
android:scheme="file" />
</intent-filter>
</activity-alias>
</application>
</manifest>

View File

@ -61,6 +61,16 @@
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="tv.ouya.intent.category.GAME" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity-alias>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ import com.reicast.emulator.periph.InputDeviceManager;
import com.reicast.emulator.periph.VJoy;
public class VirtualJoystickDelegate {
private Vibrator vib;
private VibratorThread vibratorThread;
private boolean editVjoyMode = false;
private int selectedVjoyElement = -1;
@ -39,7 +39,10 @@ public class VirtualJoystickDelegate {
public VirtualJoystickDelegate(View view) {
this.view = view;
this.context = view.getContext();
vib = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
vibratorThread = new VibratorThread(context);
vibratorThread.start();
readCustomVjoyValues();
scaleGestureDetector = new ScaleGestureDetector(context, new OscOnScaleGestureListener());
}
@ -224,8 +227,9 @@ public class VirtualJoystickDelegate {
if (y > vjoy[j][1] && y <= (vjoy[j][1] + vjoy[j][3])) {
if (vjoy[j][4] >= -2) {
if (vjoy[j][5] == 0)
if (!editVjoyMode && Emulator.vibrationDuration > 0)
vib.vibrate(Emulator.vibrationDuration);
if (!editVjoyMode) {
vibratorThread.vibrate();
}
vjoy[j][5] = 2;
}
@ -397,4 +401,51 @@ public class VirtualJoystickDelegate {
selectedVjoyElement = -1;
}
}
private class VibratorThread extends Thread
{
private Vibrator vibrator;
private boolean vibrate = false;
private boolean stopping = false;
VibratorThread(Context context) {
vibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
}
@Override
public void run() {
while (!stopping) {
boolean doVibrate;
synchronized (this) {
doVibrate = false;
try {
this.wait();
} catch (InterruptedException e) {
}
if (vibrate) {
doVibrate = true;
vibrate = false;
}
}
if (doVibrate)
vibrator.vibrate(Emulator.vibrationDuration);
}
}
public void stopVibrator() {
synchronized (this) {
stopping = true;
notify();
}
}
public void vibrate() {
if (Emulator.vibrationDuration > 0) {
synchronized (this) {
vibrate = true;
notify();
}
}
}
}
}

View File

@ -20,7 +20,7 @@
#include "hw/maple/maple_devs.h"
#include "hw/maple/maple_if.h"
#include "hw/naomi/naomi_cart.h"
#include "oslib/audiobackend_android.h"
#include "oslib/audiostream.h"
#include "imgread/common.h"
#include "rend/gui.h"
#include "cfg/cfg.h"
@ -91,8 +91,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_destroy(JNIEnv *env,j
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_send(JNIEnv *env,jobject obj,jint id, jint v) __attribute__((visibility("default")));
JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env,jobject obj,jint id, jbyteArray d) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv *env, jobject obj, jobject surface) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv *env, jobject obj, jint w, jint h) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendtermJava(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
@ -404,35 +403,57 @@ JNIEXPORT jint JNICALL Java_com_reicast_emulator_emu_JNIdc_data(JNIEnv *env, job
extern void gl_swap();
extern void egl_stealcntx();
volatile static bool render_running;
volatile static bool render_reinit;
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeNative(JNIEnv *env,jobject obj)
void *render_thread_func(void *)
{
if (g_window == NULL)
return false;
if (!egl_makecurrent())
return false;
jboolean ret = (jboolean)rend_single_frame();
if (ret)
gl_swap();
return ret;
render_running = true;
rend_init_renderer();
while (render_running) {
if (render_reinit)
{
render_reinit = false;
rend_init_renderer();
}
else
if (!egl_makecurrent())
break;;
bool ret = rend_single_frame();
if (ret)
gl_swap();
}
egl_makecurrent();
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
render_running = false;
return NULL;
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface, jint width, jint height)
static cThread render_thread(render_thread_func, NULL);
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitNative(JNIEnv * env, jobject obj, jobject surface)
{
if (g_window != NULL)
{
egl_makecurrent();
rend_term_renderer();
ANativeWindow_release(g_window);
g_window = NULL;
}
if (surface != NULL)
{
if (render_thread.hThread != NULL)
{
if (surface == NULL)
{
render_running = false;
render_thread.WaitToEnd();
}
else
render_reinit = true;
}
else if (surface != NULL)
{
g_window = ANativeWindow_fromSurface(env, surface);
rend_init_renderer();
screen_width = width;
screen_height = height;
}
render_thread.Start();
}
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv * env, jobject obj, jint width, jint height)
@ -529,6 +550,9 @@ audiobackend_t audiobackend_android = {
&androidaudio_term
};
static bool android = RegisterAudioBackend(&audiobackend_android);
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_AudioBackend_setInstance(JNIEnv *env, jobject obj, jobject instance)
{
if (g_audioBackend != NULL)
@ -568,7 +592,7 @@ void os_DebugBreak()
raise(SIGABRT);
//pthread_exit(NULL);
// Attach debugger here to figure out what went wrong
for(;;) ;
}

View File

@ -3,7 +3,7 @@
android:name="com.reicast.emulator.Emulator">
<activity
android:name="com.reicast.emulator.MainActivity">
android:name="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -62,5 +62,66 @@
android:scheme="file" />
</intent-filter>
</activity>
<activity-alias
android:name="com.reicast.emulator.MainActivity"
android:targetActivity="com.reicast.emulator.NativeGLActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.LST"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.lst"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.BIN"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.bin"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.DAT"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.dat"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.ZIP"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.zip"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.7Z"
android:scheme="file" />
<data
android:host="*"
android:mimeType="*/*"
android:pathPattern=".*\\.7z"
android:scheme="file" />
</intent-filter>
</activity-alias>
</application>
</manifest>