Merge branch 'master' into framebuffer-texture

Conflicts:
	GPU/GLES/TextureCache.cpp
This commit is contained in:
Henrik Rydgard committed 2013-02-09 21:18:46 +01:00
commit aef2376b34
75 files changed
+2801 -579

No files matched your search

+3
View File
@@ -26,6 +26,9 @@ Windows/ipch
# For ppsspp.ini, etc.
*.ini
# Qt Linguist files
*.qm
Logs
Memstick
+5 -1
View File
@@ -918,7 +918,11 @@ if(WIN32)
endif()
if(HEADLESS)
add_executable(PPSSPPHeadless headless/Headless.cpp headless/StubHost.h)
add_executable(PPSSPPHeadless
headless/Headless.cpp
headless/StubHost.h
headless/Compare.cpp
headless/Compare.h)
target_link_libraries(PPSSPPHeadless ${CoreLibName}
${COCOA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
setup_target_project(PPSSPPHeadless headless)
+289 -21
View File
@@ -78,11 +78,25 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated)
}
}
void ARMXEmitter::MOVI2R(ARMReg reg, u32 val)
void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize)
{
Operand2 op2;
bool inverse;
if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) {
if (!optimize)
{
// Only used in backpatch atm
// Only support ARMv7 right now
if (cpu_info.bArmV7) {
MOVW(reg, val & 0xFFFF);
MOVT(reg, val, true);
}
else
{
// ARMv6 version won't use backpatch for now
// Run again with optimizations
MOVI2R(reg, val);
}
} else if (TryMakeOperand2_AllowInverse(val, op2, &inverse)) {
if (!inverse)
MOV(reg, op2);
else
@@ -115,7 +129,14 @@ void ARMXEmitter::MOVI2R(ARMReg reg, u32 val)
}
}
}
// Moves IMM to memory location
void ARMXEmitter::ARMABI_MOVI2M(Operand2 op, Operand2 val)
{
// This moves imm to a memory location
MOVW(R14, val); MOVT(R14, val, true);
MOVW(R12, op); MOVT(R12, op, true);
STR(R12, R14); // R10 is what we want to store
}
void ARMXEmitter::QuickCallFunction(ARMReg reg, void *func) {
MOVI2R(reg, (u32)(func));
BL(reg);
@@ -404,7 +425,7 @@ void ARMXEmitter::MOVT(ARMReg Rd, Operand2 Rm, bool TopBits) { WriteInstruction(
void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags) // This can get renamed later
{
u32 op = InstOps[Op][Rm.GetType()]; // Type always decided by last operand
s32 op = InstOps[Op][Rm.GetType()]; // Type always decided by last operand
u32 Data = Rm.GetData();
if (Rm.GetType() == TYPE_IMM)
{
@@ -419,7 +440,7 @@ void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, b
break;
}
}
if (op == (u32)-1)
if (op == -1)
_assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType());
Write32(condition | (op << 21) | (SetFlags ? (1 << 20) : 0) | Rn << 16 | Rd << 12 | Data);
}
@@ -486,6 +507,10 @@ void ARMXEmitter::REV (ARMReg dest, ARMReg src )
{
Write32(condition | (107 << 20) | (15 << 16) | (dest << 12) | (243 << 4) | src);
}
void ARMXEmitter::REV16(ARMReg dest, ARMReg src)
{
Write32(condition | (0x3DF << 16) | (dest << 12) | (0xFD << 4) | src);
}
void ARMXEmitter::_MSR (bool write_nzcvq, bool write_g, Operand2 op2)
{
@@ -526,8 +551,17 @@ void ARMXEmitter::DMB ()
{
Write32(0xF57FF05E);
}
void ARMXEmitter::SVC(Operand2 op)
{
Write32(condition | (0x0F << 24) | op.Imm24());
}
void ARMXEmitter::LDR (ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x41, src, dest, op);}
void ARMXEmitter::LDRH(ARMReg dest, ARMReg src, Operand2 op)
{
u8 Imm = op.Imm8();
Write32(condition | (0x05 << 20) | (src << 16) | (dest << 12) | ((Imm >> 4) << 8) | (0xB << 4) | (Imm & 0x0F));
}
void ARMXEmitter::LDRB(ARMReg dest, ARMReg src, Operand2 op) { WriteStoreOp(0x45, src, dest, op);}
void ARMXEmitter::LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add)
@@ -569,19 +603,249 @@ void ARMXEmitter::LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...)
WriteRegStoreOp(0x89, dest, WriteBack, RegList);
}
// NEON and ASIMD
ARMReg ARMXEmitter::SubBase(ARMReg Reg)
{
if (Reg >= S0)
{
if (Reg >= D0)
{
if (Reg >= Q0)
return (ARMReg)((Reg - Q0) * 2); // Always gets encoded as a double register
return (ARMReg)(Reg - D0);
}
return (ARMReg)(Reg - S0);
}
return Reg;
}
// NEON Specific
void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VADD(integer)");
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it");
// Gets encoded as a double register
Vd = SubBase(Vd);
Vn = SubBase(Vn);
Vm = SubBase(Vm);
Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
| ((Vm & 0x10) << 2) | (Vm & 0xF));
}
void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)");
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it");
// Gets encoded as a double register
Vd = SubBase(Vd);
Vn = SubBase(Vn);
Vm = SubBase(Vm);
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
| ((Vm & 0x10) << 2) | (Vm & 0xF));
}
// VFP Specific
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, Operand2 op)
{
_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR");
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR");
_assert_msg_(DYNA_REC, !(op.Imm12() & 4), "Offset needs to be word aligned");
bool single_reg = Dest < D0;
Dest = SubBase(Dest);
if (single_reg)
Dest = (ARMReg)(Dest - S0);
{
Write32(NO_COND | (0x1B << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \
| ((Dest & 0x1E) << 11) | (10 << 8) | (op.Imm12() >> 2));
}
else
Dest = (ARMReg)(Dest - D0);
Write32(NO_COND | (13 << 24) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \
| (5 << 9) | (!single_reg << 8) | op.Imm8());
{
Write32(NO_COND | (0x1B << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \
| ((Dest & 0xF) << 12) | (11 << 8) | (op.Imm12() >> 2));
}
}
void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, Operand2 op)
{
_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR");
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR");
_assert_msg_(DYNA_REC, !(op.Imm12() & 4), "Offset needs to be word aligned");
bool single_reg = Src < D0;
Src = SubBase(Src);
if (single_reg)
{
Write32(NO_COND | (0x1B << 23) | ((Src & 0x1) << 22) | (Base << 16) \
| ((Src & 0x1E) << 11) | (10 << 8) | (op.Imm12() >> 2));
}
else
{
Write32(NO_COND | (0x1B << 23) | ((Src & 0x10) << 18) | (Base << 16) \
| ((Src & 0xF) << 12) | (11 << 8) | (op.Imm12() >> 2));
}
}
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd < Q0, "Passed invalid Vd to VCMP");
bool single_reg = Vd < D0;
Vd = SubBase(Vd);
Vm = SubBase(Vm);
if (single_reg)
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x34 << 16) | ((Vd & 0x1E) << 11) \
| (0x2B << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
}
else
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x34 << 16) | ((Vd & 0xF) << 12) \
| (0x2F << 6) | ((Vm & 0x10) << 1) | (Vm & 0xF));
}
}
void ARMXEmitter::VCMP(ARMReg Vd)
{
_assert_msg_(DYNA_REC, Vd < Q0, "Passed invalid Vd to VCMP");
bool single_reg = Vd < D0;
Vd = SubBase(Vd);
if (single_reg)
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x35 << 16) | ((Vd & 0x1E) << 11) \
| (0x2B << 6));
}
else
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x35 << 16) | ((Vd & 0xF) << 12) \
| (0x2F << 6));
}
}
void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd < Q0, "Pased invalid dest register to VSQRT");
_assert_msg_(DYNA_REC, Vn < Q0, "Passed invalid Vn to VSQRT");
_assert_msg_(DYNA_REC, Vm < Q0, "Passed invalid Vm to VSQRT");
bool single_reg = Vd < D0;
Vd = SubBase(Vd);
Vn = SubBase(Vn);
Vm = SubBase(Vm);
if (single_reg)
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | ((Vn & 0x1E) << 16) \
| ((Vd & 0x1E) << 11) | (0xA << 8) | ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) \
| (Vm >> 1));
}
else
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0xB << 8) | ((Vn & 0x10) << 3) | ((Vm & 0x10) << 2) \
| (Vm & 0xF));
}
}
void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd < Q0, "Pased invalid dest register to VSQRT");
_assert_msg_(DYNA_REC, Vm < Q0, "Passed invalid Vm to VSQRT");
bool single_reg = Vd < D0;
Vd = SubBase(Vd);
Vm = SubBase(Vm);
if (single_reg)
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \
| ((Vd & 0x1E) << 11) | (0x2B << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
}
else
{
Write32(NO_COND | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \
| ((Vd & 0xF) << 12) | (0x2F << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
}
}
// VFP and ASIMD
void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd >= S0, "Passed invalid dest register to VADD");
_assert_msg_(DYNA_REC, Vn >= S0, "Passed invalid Vn to VADD");
_assert_msg_(DYNA_REC, Vm >= S0, "Passed invalid Vm to VADD");
bool single_reg = Vd < D0;
bool double_reg = Vd < Q0;
Vd = SubBase(Vd);
Vn = SubBase(Vn);
Vm = SubBase(Vm);
if (single_reg)
{
Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 12) | (0x5 << 9) \
| ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1));
}
else
{
if (double_reg)
{
Write32(NO_COND | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x3 << 20) \
| ((Vn & 0xF) << 16) | ((Vd & 0xF) << 12) | (0xB << 8) \
| ((Vn & 0x10) << 3) | ((Vm & 0x10) << 2) | (Vm & 0xF));
}
else
{
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use VADD with Quad Reg without support!");
Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) \
| (1 << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
}
}
}
void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd >= S0, "Passed invalid dest register to VSUB");
_assert_msg_(DYNA_REC, Vn >= S0, "Passed invalid Vn to VSUB");
_assert_msg_(DYNA_REC, Vm >= S0, "Passed invalid Vm to VSUB");
bool single_reg = Vd < D0;
bool double_reg = Vd < Q0;
Vd = SubBase(Vd);
Vn = SubBase(Vn);
Vm = SubBase(Vm);
if (single_reg)
{
Write32(NO_COND | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 12) | (0x5 << 9) \
| ((Vn & 0x1) << 7) | (1 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
}
else
{
if (double_reg)
{
Write32(NO_COND | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x3 << 20) \
| ((Vn & 0xF) << 16) | ((Vd & 0xF) << 12) | (0xB << 8) \
| ((Vn & 0x10) << 3) | (1 << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
}
else
{
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use VADD with Quad Reg without support!");
Write32((0xF2 << 24) | (1 << 21) | ((Vd & 0x10) << 18) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) \
| (1 << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
}
}
}
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
{
if (Dest > R15)
@@ -600,6 +864,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
{
// Move 64bit from Arm reg
_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON");
return;
}
}
}
@@ -613,13 +878,13 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
Src = (ARMReg)(Src - S0);
Write32(NO_COND | (0xE1 << 20) | ((Src & 0x1E) << 15) | (Dest << 12) \
| (0xA << 8) | ((Src & 0x1) << 7) | (1 << 4));
return;
}
else
{
// Move 64bit To Arm reg
_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON");
return;
}
}
else
@@ -632,32 +897,35 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
int SrcSize = Src < D0 ? 1 : Src < Q0 ? 2 : 4;
int DestSize = Dest < D0 ? 1 : Dest < Q0 ? 2 : 4;
bool Single = DestSize == 1;
bool Quad = DestSize == 4;
_assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes");
Dest = SubBase(Dest);
Src = SubBase(Src);
if (Single)
{
Dest = (ARMReg)(Dest - S0);
Src = (ARMReg)(Src - S0);
Write32(NO_COND | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | ((Dest & 0x1E) << 11) \
| (0x5 << 9) | (1 << 6) | ((Src & 0x1) << 5) | ((Src & 0x1E) >> 1));
}
else
{
// Double and quad
bool Quad = DestSize == 4;
if (Quad)
{
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD.");
// Gets encoded as a Double register
Dest = (ARMReg)((Dest - Q0) * 2);
Src = (ARMReg)((Src - Q0) * 2);
Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \
| ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \
| ((Src & 0x10) << 1) | (1 << 4) | (Src & 0xF));
}
else
{
Dest = (ARMReg)(Dest - D0);
Src = (ARMReg)(Src - D0);
Write32(NO_COND | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | ((Dest & 0xF) << 12) \
| (0x2D << 6) | ((Src & 0x10) << 1) | (Src & 0xF));
}
Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (1 << 21) | ((Src & 0xF) << 16) \
| ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (Quad << 6) \
| ((Src & 0x10) << 1) | (1 << 4) | (Src & 0xF));
}
}
+34 -8
View File
@@ -97,6 +97,13 @@ enum ShiftType
ST_ROR = 3,
ST_RRX = 4
};
enum IntegerSize
{
I_I8 = 0,
I_I16,
I_I32,
I_I64
};
enum
{
@@ -309,6 +316,9 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); }
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); }
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
struct FixupBranch
{
@@ -418,6 +428,7 @@ public:
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
void REV (ARMReg dest, ARMReg src);
void REV16 (ARMReg dest, ARMReg src);
void RSC (ARMReg dest, ARMReg src, Operand2 op2);
void RSCS(ARMReg dest, ARMReg src, Operand2 op2);
void TST ( ARMReg src, Operand2 op2);
@@ -459,6 +470,7 @@ public:
void LDR (ARMReg dest, ARMReg src, Operand2 op2 = 0);
// Offset adds to the base register in LDR
void LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
void LDRH(ARMReg dest, ARMReg src, Operand2 op = 0);
void LDRB(ARMReg dest, ARMReg src, Operand2 op2 = 0);
void STR (ARMReg dest, ARMReg src, Operand2 op2 = 0);
// Offset adds on to the destination register in STR
@@ -473,23 +485,37 @@ public:
// dest contains the result if the instruction managed to store the value
void STREX(ARMReg dest, ARMReg base, ARMReg op);
void DMB ();
void SVC(Operand2 op);
// NEON and ASIMD instructions
// None of these will be created with conditional since ARM
// is deprecating conditional execution of ASIMD instructions.
// Some ASIMD instructions don't even have a conditional encoding.
// ASIMD instructions don't even have a conditional encoding.
// Subtracts the base from the register to give us the real one
ARMReg SubBase(ARMReg Reg);
// NEON Only
void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VLDR(ARMReg dest, ARMReg Base, Operand2 op);
// VFP Only
void VLDR(ARMReg Dest, ARMReg Base, Operand2 op);
void VSTR(ARMReg Src, ARMReg Base, Operand2 op);
void VCMP(ARMReg Vd, ARMReg Vm);
// Compares against zero
void VCMP(ARMReg Vd);
void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSQRT(ARMReg Vd, ARMReg Vm);
// NEON and VFP
void VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VMOV(ARMReg Dest, ARMReg Src);
void QuickCallFunction(ARMReg scratchreg, void *func);
// Utility functions
void MOVI2R(ARMReg reg, u32 val);
void ARMABI_ShowConditions();
void ARMABI_Return();
void UpdateAPSR(bool NZCVQ, u8 Flags, bool GE, u8 GEval);
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
void ARMABI_MOVI2M(Operand2 op, Operand2 val);
}; // class ARMXEmitter
+14
View File
@@ -33,7 +33,9 @@
#include <string>
#include <list>
#include <set>
#ifndef __SYMBIAN32__
#include <type_traits>
#endif
#include "Common.h"
#include "FileUtil.h"
@@ -44,6 +46,18 @@ namespace std {
using tr1::is_pointer;
}
#endif
#ifdef __SYMBIAN32__
namespace std {
template <bool bool_value>
struct bool_constant {
typedef bool_constant<bool_value> type;
static const bool value = bool_value;
};
template <bool bool_value> const bool bool_constant<bool_value>::value;
template <typename T> struct is_pointer : public bool_constant<false> {};
template <typename T> struct is_pointer<T*> : public bool_constant<true> {};
}
#endif
template <class T>
struct LinkedListItem : public T
+2 -2
View File
@@ -318,7 +318,7 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text)
Len = LOG_PENDING_MAX - 16;
char ColorAttr[16] = "";
int ColorLen = 0;
size_t ColorLen = 0;
if (bUseColor)
{
// Not ANSI, since the console doesn't support it, but ANSI-like.
@@ -333,7 +333,7 @@ void ConsoleListener::SendToThread(LogTypes::LOG_LEVELS Level, const char *Text)
u32 prevLogWritePos = logWritePos;
if (logWritePos + ColorLen + Len >= LOG_PENDING_MAX)
{
for (u32 i = 0; i < ColorLen; ++i)
for (size_t i = 0; i < ColorLen; ++i)
logPending[(logWritePos + i) % LOG_PENDING_MAX] = ColorAttr[i];
logWritePos += ColorLen;
if (logWritePos >= LOG_PENDING_MAX)
+1 -1
View File
@@ -95,7 +95,7 @@ public:
return false;
}
values.clear();
for(int i = 0; i < temp.size(); i++)
for(size_t i = 0; i < temp.size(); i++)
{
std::vector<std::string> key_val;
SplitString(temp[i],'_',key_val);
+2
View File
@@ -1292,6 +1292,8 @@ void XEmitter::CVTDQ2PS(X64Reg regOp, OpArg arg) {WriteSSEOp(32, 0x5B, true, reg
void XEmitter::CVTPD2DQ(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0xE6, false, regOp, arg);}
void XEmitter::CVTPS2DQ(X64Reg regOp, OpArg arg) {WriteSSEOp(64, 0x5B, true, regOp, arg);}
void XEmitter::CVTSI2SS(X64Reg xregdest, OpArg arg) {WriteSSEOp(32, 0x2A, false, xregdest, arg);}
void XEmitter::CVTSS2SI(X64Reg xregdest, OpArg arg) {WriteSSEOp(32, 0x2D, false, xregdest, arg);}
void XEmitter::CVTTSS2SI(X64Reg xregdest, OpArg arg) {WriteSSEOp(32, 0x2C, false, xregdest, arg);}
void XEmitter::CVTTPS2DQ(X64Reg xregdest, OpArg arg) {WriteSSEOp(32, 0x5B, false, xregdest, arg);}
+2
View File
@@ -564,6 +564,8 @@ public:
void CVTDQ2PS(X64Reg regOp, OpArg arg);
void CVTPS2DQ(X64Reg regOp, OpArg arg);
void CVTSI2SS(X64Reg xregdest, OpArg arg); // Yeah, destination really is a GPR like EAX!
void CVTSS2SI(X64Reg xregdest, OpArg arg); // Yeah, destination really is a GPR like EAX!
void CVTTSS2SI(X64Reg xregdest, OpArg arg); // Yeah, destination really is a GPR like EAX!
void CVTTPS2DQ(X64Reg regOp, OpArg arg);
+1 -1
View File
@@ -55,7 +55,7 @@ namespace
if(dataSize == -1)
{
dataSize = pspFileSystem.GetFileInfo(filename).size;
*data = new u8[dataSize];
*data = new u8[(size_t)dataSize];
}
size_t result = pspFileSystem.ReadFile(handle, *data, dataSize);
+11 -2
View File
@@ -123,6 +123,12 @@ CISOFileBlockDevice::~CISOFileBlockDevice()
bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
{
if ((u32)blockNumber >= numBlocks)
{
memset(outPtr, 0, 2048);
return false;
}
u32 idx = index[blockNumber];
u32 idx2 = index[blockNumber+1];
u8 inbuffer[4096]; //too big
@@ -153,7 +159,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
if(inflateInit2(&z, -15) != Z_OK)
{
ERROR_LOG(LOADER, "deflateInit ERROR : %s\n", (z.msg) ? z.msg : "???");
return 1;
return false;
}
z.avail_in = readSize;
z.next_out = outPtr;
@@ -165,14 +171,17 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
//if (status != Z_OK)
{
ERROR_LOG(LOADER, "block %d:inflate : %s[%d]\n", blockNumber, (z.msg) ? z.msg : "error", status);
inflateEnd(&z);
return 1;
}
int cmp_size = blockSize - z.avail_out;
if (cmp_size != (int)blockSize)
{
ERROR_LOG(LOADER, "block %d : block size error %d != %d\n", blockNumber, cmp_size, blockSize);
return 1;
inflateEnd(&z);
return false;
}
inflateEnd(&z);
}
return true;
}
+2 -5
View File
@@ -31,9 +31,6 @@
#endif
#undef DeleteFile
#if HOST_IS_CASE_SENSITIVE
static bool FixFilenameCase(const std::string &path, std::string &filename)
@@ -248,7 +245,7 @@ bool DirectoryFileSystem::RenameFile(const std::string &from, const std::string
return retValue;
}
bool DirectoryFileSystem::DeleteFile(const std::string &filename) {
bool DirectoryFileSystem::RemoveFile(const std::string &filename) {
std::string fullName = GetLocalPath(filename);
#ifdef _WIN32
bool retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
@@ -266,7 +263,7 @@ bool DirectoryFileSystem::DeleteFile(const std::string &filename) {
fullName = GetLocalPath(fullName);
#ifdef _WIN32
retValue = (::DeleteFile(fullName.c_str()) == TRUE);
retValue = (::DeleteFileA(fullName.c_str()) == TRUE);
#else
retValue = (0 == unlink(fullName.c_str()));
#endif
+1 -1
View File
@@ -66,7 +66,7 @@ public:
bool MkDir(const std::string &dirname);
bool RmDir(const std::string &dirname);
bool RenameFile(const std::string &from, const std::string &to);
bool DeleteFile(const std::string &filename);
bool RemoveFile(const std::string &filename);
bool GetHostPath(const std::string &inpath, std::string &outpath);
private:
+2 -2
View File
@@ -110,7 +110,7 @@ public:
virtual bool MkDir(const std::string &dirname) = 0;
virtual bool RmDir(const std::string &dirname) = 0;
virtual bool RenameFile(const std::string &from, const std::string &to) = 0;
virtual bool DeleteFile(const std::string &filename) = 0;
virtual bool RemoveFile(const std::string &filename) = 0;
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0;
};
@@ -130,7 +130,7 @@ public:
virtual bool MkDir(const std::string &dirname) {return false;}
virtual bool RmDir(const std::string &dirname) {return false;}
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
virtual bool DeleteFile(const std::string &filename) {return false;}
virtual bool RemoveFile(const std::string &filename) {return false;}
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
};
+1 -1
View File
@@ -44,7 +44,7 @@ public:
virtual bool MkDir(const std::string &dirname) {return false;}
virtual bool RmDir(const std::string &dirname) {return false;}
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
virtual bool DeleteFile(const std::string &filename) {return false;}
virtual bool RemoveFile(const std::string &filename) {return false;}
private:
struct TreeEntry
+2 -2
View File
@@ -363,13 +363,13 @@ bool MetaFileSystem::RenameFile(const std::string &from, const std::string &to)
}
}
bool MetaFileSystem::DeleteFile(const std::string &filename)
bool MetaFileSystem::RemoveFile(const std::string &filename)
{
std::string of;
IFileSystem *system;
if (MapFilePath(filename, of, &system))
{
return system->DeleteFile(of);
return system->RemoveFile(of);
}
else
{
+1 -1
View File
@@ -89,7 +89,7 @@ public:
virtual bool MkDir(const std::string &dirname);
virtual bool RmDir(const std::string &dirname);
virtual bool RenameFile(const std::string &from, const std::string &to);
virtual bool DeleteFile(const std::string &filename);
virtual bool RemoveFile(const std::string &filename);
// TODO: void IoCtl(...)
+15 -3
View File
@@ -25,6 +25,7 @@
#include "Thread.h"
#include "../Core/CoreTiming.h"
#include "../Core/CoreParameter.h"
#include "../MIPS/MIPS.h"
#include "../HLE/HLE.h"
#include "sceAudio.h"
@@ -78,7 +79,7 @@ static int hCountTotal; //unused
static int vCount;
static int isVblank;
static bool hasSetMode;
double lastFrameTime;
static double lastFrameTime;
std::vector<WaitVBlankInfo> vblankWaitingThreads;
@@ -269,12 +270,11 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
host->EndFrame();
#ifdef _WIN32
static double lastFrameTime = 0.0;
// Best place to throttle the frame rate on non vsynced platforms is probably here. Let's try it.
time_update();
if (lastFrameTime == 0.0)
lastFrameTime = time_now_d();
if (!GetAsyncKeyState(VK_TAB)) {
if (!GetAsyncKeyState(VK_TAB) && !PSP_CoreParameter().headLess) {
while (time_now_d() < lastFrameTime + 1.0 / 60.0) {
Common::SleepCurrentThread(1);
time_update();
@@ -357,6 +357,18 @@ u32 sceDisplaySetFramebuf() {
return 0;
}
bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int mode) {
const FrameBufferState &fbState = mode == 1 ? latchedFramebuf : framebuf;
if (topaddr != NULL)
*topaddr = Memory::GetPointer(fbState.topaddr);
if (linesize != NULL)
*linesize = fbState.pspFramebufLinesize;
if (pixelFormat != NULL)
*pixelFormat = fbState.pspFramebufFormat;
return true;
}
u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelFormatPtr, int mode) {
const FrameBufferState &fbState = mode == 1 ? latchedFramebuf : framebuf;
DEBUG_LOG(HLE,"sceDisplayGetFramebuf(*%08x = %08x, *%08x = %08x, *%08x = %08x, %i)",
+3
View File
@@ -26,6 +26,9 @@ void Register_sceDisplay();
// will return true once after every end-of-frame.
bool __DisplayFrameDone();
// Get information about the current framebuffer.
bool __DisplayGetFramebuf(u8 **topaddr, u32 *linesize, u32 *pixelFormat, int mode);
typedef void (*VblankCallback)();
// Listen for vblank events. Only register during init.
void __DisplayListenVblank(VblankCallback callback);
+15 -3
View File
@@ -17,7 +17,6 @@
#ifdef _WIN32
#include <windows.h>
#undef DeleteFile
#endif
#include "../Config.h"
@@ -38,6 +37,9 @@
#include "sceKernelMemory.h"
#include "sceKernelThread.h"
// For headless screenshots.
#include "sceDisplay.h"
#define ERROR_ERRNO_FILE_NOT_FOUND 0x80010002
#define ERROR_MEMSTICK_DEVCTL_BAD_PARAMS 0x80220081
@@ -144,9 +146,10 @@ public:
p.Do(callbackID);
p.Do(callbackArg);
p.Do(asyncResult);
p.Do(closePending);
p.Do(pendingAsyncResult);
p.Do(sectorBlockMode);
p.Do(closePending);
p.Do(info);
p.Do(openMode);
p.DoMarker("File");
}
@@ -549,7 +552,7 @@ u32 sceIoRemove(const char *filename) {
if(!pspFileSystem.GetFileInfo(filename).exists)
return ERROR_ERRNO_FILE_NOT_FOUND;
pspFileSystem.DeleteFile(filename);
pspFileSystem.RemoveFile(filename);
return 0;
}
@@ -782,6 +785,15 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
SaveState::Verify();
// TODO: Maybe save/load to a file just to be sure?
return 0;
case 0x20: // EMULATOR_DEVCTL__EMIT_SCREENSHOT
u8 *topaddr;
u32 linesize, pixelFormat;
__DisplayGetFramebuf(&topaddr, &linesize, &pixelFormat, 0);
// TODO: Convert based on pixel format / mode / something?
host->SendDebugScreenshot(topaddr, linesize, 272);
return 0;
}
ERROR_LOG(HLE, "sceIoDevCtl: UNKNOWN PARAMETERS");
+1
View File
@@ -157,6 +157,7 @@ void __KernelDoState(PointerWrap &p)
p.DoMarker("KernelObjects");
__InterruptsDoState(p);
// Memory needs to be after kernel objects, which may free kernel memory.
__KernelMemoryDoState(p);
__KernelThreadingDoState(p);
__KernelAlarmDoState(p);
+1 -1
View File
@@ -1249,7 +1249,7 @@ void sceKernelCheckThreadStack()
u32 error;
Thread *t = kernelObjects.Get<Thread>(__KernelGetCurThread(), error);
if (t) {
u32 diff = abs((long)((s64)t->stackBlock - (s64)currentMIPS->r[MIPS_REG_SP]));
u32 diff = labs((long)((s64)t->stackBlock - (s64)currentMIPS->r[MIPS_REG_SP]));
WARN_LOG(HLE, "%i=sceKernelCheckThreadStack()", diff);
RETURN(diff);
} else {
+1
View File
@@ -63,6 +63,7 @@ public:
// Used for headless.
virtual void SendDebugOutput(const std::string &output) {}
virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) {}
};
extern Host *host;
+5 -6
View File
@@ -57,6 +57,7 @@ namespace MIPSComp
{
s32 simm = (s32)(s16)(op & 0xFFFF); // sign extension
u32 uimm = op & 0xFFFF;
u32 suimm = (u32)(s32)simm;
int rt = _RT;
int rs = _RS;
@@ -113,29 +114,27 @@ namespace MIPSComp
}
break;
/*
case 11: // R(rt) = R(rs) < uimm; break; //sltiu
{
gpr.MapDirtyIn(rt, rs);
Operand2 op2;
bool negated;
if (TryMakeOperand2_AllowNegation(uimm, op2, &negated)) {
if (TryMakeOperand2_AllowNegation(suimm, op2, &negated)) {
if (!negated)
CMP(gpr.R(rs), op2);
else
CMN(gpr.R(rs), op2);
} else {
ARMABI_MOVI2R(R0, uimm);
MOVI2R(R0, suimm);
CMP(gpr.R(rs), R0);
}
SetCC(CC_LO);
ARMABI_MOVI2R(gpr.R(rt), 1);
MOVI2R(gpr.R(rt), 1);
SetCC(CC_HS);
ARMABI_MOVI2R(gpr.R(rt), 0);
MOVI2R(gpr.R(rt), 0);
SetCC(CC_AL);
}
break;
*/
case 15: // R(rt) = uimm << 16; //lui
gpr.SetImm(rt, uimm << 16);
+2 -2
View File
@@ -266,10 +266,10 @@ const MIPSInstruction tableSpecial2[64] =
//24
{-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2}, {-2},
//32
INSTR("cvt.s.w", &Jit::Comp_Generic, Dis_FPU2op, Int_FPU2op, 0),
INSTR("cvt.s.w", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
{-2}, {-2}, {-2},
//36
INSTR("cvt.w.s", &Jit::Comp_Generic, Dis_FPU2op, Int_FPU2op, 0),
INSTR("cvt.w.s", &Jit::Comp_FPU2op, Dis_FPU2op, Int_FPU2op, 0),
{-2},
INSTR("dis.int", &Jit::Comp_Generic, Dis_Generic, Int_Interrupt, 0),
{-2},
+9 -6
View File
@@ -181,15 +181,12 @@ void Jit::Comp_FPU2op(u32 op)
fpr.ReleaseSpillLocks();
break;
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt
/* fpr.Lock(fd, fs); // this probably works, just badly tested
fpr.SpillLock(fd, fs); // this probably works, just badly tested
fpr.BindToRegister(fd, fd == fs, true);
SQRTSS(fpr.RX(fd), fpr.R(fs));
fpr.UnlockAll();
break;*/
Comp_Generic(op);
fpr.ReleaseSpillLocks();
return;
case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s
@@ -200,9 +197,15 @@ void Jit::Comp_FPU2op(u32 op)
fpr.ReleaseSpillLocks();
break;
case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w
fpr.StoreFromRegister(fs);
CVTSI2SS(XMM0, fpr.R(fs));
MOVSS(fpr.R(fd), XMM0);
break;
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s
case 32: //F(fd) = (float)FsI(fs); break; //cvt.s.w
case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s
default:
Comp_Generic(op);
+2 -3
View File
@@ -15,7 +15,6 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "Common/Log.h"
#include "Common/x64Emitter.h"
@@ -81,7 +80,7 @@ void FPURegCache::ReleaseSpillLocks() {
regs[i].locked = false;
}
void FPURegCache::BindToRegister(int i, bool doLoad, bool makeDirty) {
void FPURegCache::BindToRegister(const int i, bool doLoad, bool makeDirty) {
_assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm");
if (!regs[i].away) {
// Reg is at home in the memory register file. Let's pull it out.
@@ -206,4 +205,4 @@ void FPURegCache::FlushR(X64Reg reg) {
if (xregs[reg].mipsReg != -1) {
StoreFromRegister(xregs[reg].mipsReg);
}
}
}
+2 -1
View File
@@ -77,9 +77,10 @@ namespace SaveState
Memory::DoState(p);
MemoryStick_DoState(p);
currentMIPS->DoState(p);
pspFileSystem.DoState(p);
HLEDoState(p);
__KernelDoState(p);
// Kernel object destructors might close open files, so do the filesystem last.
pspFileSystem.DoState(p);
}
void Enqueue(SaveState::Operation op)
+2 -9
View File
@@ -124,7 +124,6 @@ static const int flushBeforeCommandList[] = {
GE_CMD_SIGNAL,
GE_CMD_FINISH,
GE_CMD_BJUMP,
GE_CMD_OFFSETADDR,
GE_CMD_REGION1,GE_CMD_REGION2,
GE_CMD_FRAMEBUFPTR,
GE_CMD_FRAMEBUFWIDTH,
@@ -515,6 +514,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
// Throughmode changed, let's make the proj matrix dirty.
shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
}
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
// This sets through-mode or not, as well.
break;
@@ -679,6 +679,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_TEXSIZE0:
gstate_c.curTextureWidth = 1 << (gstate.texsize[0] & 0xf);
gstate_c.curTextureHeight = 1 << ((gstate.texsize[0]>>8) & 0xf);
shaderManager_->DirtyUniform(DIRTY_UVSCALEOFFSET);
//fall thru - ignoring the mipmap sizes for now
case GE_CMD_TEXSIZE1:
case GE_CMD_TEXSIZE2:
@@ -799,16 +800,8 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_VIEWPORTY1:
case GE_CMD_VIEWPORTX2:
case GE_CMD_VIEWPORTY2:
break;
case GE_CMD_VIEWPORTZ1:
gstate_c.zScale = getFloat24(data) / 65535.f;
break;
case GE_CMD_VIEWPORTZ2:
gstate_c.zOff = getFloat24(data) / 65535.f;
break;
case GE_CMD_LIGHTENABLE0:
case GE_CMD_LIGHTENABLE1:
case GE_CMD_LIGHTENABLE2:
+35 -28
View File
@@ -77,7 +77,7 @@ void GenerateFragmentShader(char *buffer)
#if defined(GLSL_ES_1_0)
WRITE(p, "precision mediump float;\n");
WRITE(p, "precision lowp float;\n");
#elif !defined(FORCE_OPENGL_2_0)
WRITE(p, "#version 110\n");
#endif
@@ -86,30 +86,38 @@ void GenerateFragmentShader(char *buffer)
int doTexture = (gstate.textureMapEnable & 1) && !(gstate.clearmode & 1);
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
bool enableAlphaTest = (gstate.alphaTestEnable & 1) && !gstate.isModeClear();
bool enableColorTest = (gstate.colorTestEnable & 1) && !gstate.isModeClear();
if (doTexture)
WRITE(p, "uniform sampler2D tex;\n");
if ((gstate.alphaTestEnable & 1) || (gstate.colorTestEnable & 1)) {
if (enableAlphaTest || enableColorTest) {
WRITE(p, "uniform vec4 u_alphacolorref;\n");
}
WRITE(p, "uniform vec3 u_texenv;\n");
if (gstate.textureMapEnable & 1) {
WRITE(p, "uniform vec3 u_texenv;\n");
}
WRITE(p, "varying vec4 v_color0;\n");
if (lmode)
WRITE(p, "varying vec3 v_color1;\n");
if (enableFog) {
WRITE(p, "uniform vec3 u_fogcolor;\n");
#if defined(GLSL_ES_1_0)
WRITE(p, "varying mediump float v_fogdepth;\n");
#else
WRITE(p, "varying float v_fogdepth;\n");
#endif
}
if (doTexture)
WRITE(p, "varying vec2 v_texcoord;\n");
WRITE(p, "void main() {\n");
WRITE(p, " vec4 v;\n");
if (gstate.clearmode & 1)
{
// Clear mode does not allow any fancy shading.
WRITE(p, " v = v_color0;\n");
WRITE(p, " gl_FragColor = v_color0;\n");
}
else
{
@@ -119,59 +127,58 @@ void GenerateFragmentShader(char *buffer)
WRITE(p, " vec4 s = vec4(v_color1, 0.0);\n");
secondary = " + s";
} else {
WRITE(p, " vec4 s = vec4(0.0, 0.0, 0.0, 0.0);\n");
secondary = "";
}
if (gstate.textureMapEnable & 1) {
WRITE(p, " vec4 t = texture2D(tex, v_texcoord);\n");
WRITE(p, " vec4 p = clamp(v_color0, 0.0, 1.0);\n");
WRITE(p, " vec4 p = v_color0;\n");
if (gstate.texfunc & 0x100) { // texfmt == RGBA
switch (gstate.texfunc & 0x7) {
case GE_TEXFUNC_MODULATE:
WRITE(p, " v = t * p%s;\n", secondary); break;
WRITE(p, " vec4 v = t * p%s;\n", secondary); break;
case GE_TEXFUNC_DECAL:
WRITE(p, " v = vec4(1.0 - t.a * p.rgb + t.a * u_texenv.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(1.0 - t.a * p.rgb + t.a * u_texenv.rgb, p.a)%s;\n", secondary); break;
case GE_TEXFUNC_BLEND:
WRITE(p, " v = vec4((1.0 - t.rgb) * p.rgb + t.rgb * u_texenv.rgb, p.a * t.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4((1.0 - t.rgb) * p.rgb + t.rgb * u_texenv.rgb, p.a * t.a)%s;\n", secondary); break;
case GE_TEXFUNC_REPLACE:
WRITE(p, " v = t%s;\n", secondary); break;
WRITE(p, " vec4 v = t%s;\n", secondary); break;
case GE_TEXFUNC_ADD:
WRITE(p, " v = vec4(t.rgb + p.rgb, p.a * t.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(t.rgb + p.rgb, p.a * t.a)%s;\n", secondary); break;
default:
WRITE(p, " v = p;\n"); break;
WRITE(p, " vec4 v = p;\n"); break;
}
} else { // texfmt == RGB
switch (gstate.texfunc & 0x7) {
case GE_TEXFUNC_MODULATE:
WRITE(p, " v = vec4(t.rgb * p.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(t.rgb * p.rgb, p.a)%s;\n", secondary); break;
case GE_TEXFUNC_DECAL:
WRITE(p, " v = vec4(t.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary); break;
case GE_TEXFUNC_BLEND:
WRITE(p, " v = vec4(1.0 - t.rgb) * p.rgb + t.rgb * u_texenv.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(1.0 - t.rgb) * p.rgb + t.rgb * u_texenv.rgb, p.a)%s;\n", secondary); break;
case GE_TEXFUNC_REPLACE:
WRITE(p, " v = vec4(t.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(t.rgb, p.a)%s;\n", secondary); break;
case GE_TEXFUNC_ADD:
WRITE(p, " v = vec4(t.rgb + p.rgb, p.a)%s;\n", secondary); break;
WRITE(p, " vec4 v = vec4(t.rgb + p.rgb, p.a)%s;\n", secondary); break;
default:
WRITE(p, " v = p;\n"); break;
WRITE(p, " vec4 v = p;\n"); break;
}
}
} else {
// No texture mapping
WRITE(p, " v = clamp(v_color0, 0.0, 1.0)%s;\n", secondary);
WRITE(p, " vec4 v = v_color0 %s;\n", secondary);
}
// Color doubling
if (gstate.texfunc & 0x10000) {
WRITE(p, " v = v * vec4(2.0, 2.0, 2.0, 2.0);");
WRITE(p, " v = v * 2.0;\n");
}
if (gstate.alphaTestEnable & 1) {
if (enableAlphaTest) {
int alphaTestFunc = gstate.alphatest & 7;
const char *alphaTestFuncs[] = { "#", "#", " == ", " != ", " < ", " <= ", " > ", " >= " }; // never/always don't make sense
if (alphaTestFuncs[alphaTestFunc][0] != '#')
WRITE(p, "if (!(v.a %s u_alphacolorref.a)) discard;", alphaTestFuncs[alphaTestFunc]);
WRITE(p, " if (!(v.a %s u_alphacolorref.a)) discard;\n", alphaTestFuncs[alphaTestFunc]);
}
// Disabled for now until we actually find a need for it.
@@ -187,20 +194,20 @@ void GenerateFragmentShader(char *buffer)
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
WRITE(p, " gl_FragColor = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
} else {
WRITE(p, " gl_FragColor = v;\n");
}
}
#ifdef DEBUG_SHADER
if (doTexture) {
WRITE(p, " v = texture2D(tex, v_texcoord);\n");
WRITE(p, " gl_FragColor = texture2D(tex, v_texcoord);\n");
} else {
WRITE(p, " v = vec4(1,0,1,1);\n");
WRITE(p, " gl_FragColor = vec4(1,0,1,1);\n");
}
#endif
WRITE(p, " gl_FragColor = v;\n");
WRITE(p, "}\n");
}
+11 -2
View File
@@ -39,7 +39,7 @@ Shader::Shader(const char *code, uint32_t shaderType) {
OutputDebugString(code);
#endif
shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &code, 0);
glShaderSource(shader, 1, &code, 0);
glCompileShader(shader);
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
@@ -264,7 +264,16 @@ void LinkedShader::updateUniforms() {
// Texturing
if (u_uvscaleoffset != -1 && (dirtyUniforms & DIRTY_UVSCALEOFFSET)) {
const float uvscaleoff[4] = { gstate_c.uScale, gstate_c.vScale, gstate_c.uOff, gstate_c.vOff};
float uvscaleoff[4] = { gstate_c.uScale, gstate_c.vScale, gstate_c.uOff, gstate_c.vOff};
if (gstate.isModeThrough()) {
uvscaleoff[0] /= gstate_c.curTextureWidth;
uvscaleoff[1] /= gstate_c.curTextureHeight;
uvscaleoff[2] /= gstate_c.curTextureWidth;
uvscaleoff[3] /= gstate_c.curTextureHeight;
} else {
uvscaleoff[0] *= 2.0f;
uvscaleoff[1] *= 2.0f;
}
glUniform4fv(u_uvscaleoffset, 1, uvscaleoff);
}
+8 -11
View File
@@ -171,7 +171,7 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
bool wantDepthTest = gstate.isModeClear() || gstate.isDepthTestEnabled();
glstate.depthTest.set(wantDepthTest);
if(wantDepthTest) {
// Force GL_ALWAYS if mode clear
// Force GL_ALWAYS if mode clear - without depth test, no depth write.
int depthTestFunc = gstate.isModeClear() ? 1 : gstate.getDepthTestFunc();
glstate.depthFunc.set(ztests[depthTestFunc]);
}
@@ -208,10 +208,6 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
bool wantDepthWrite = gstate.isModeClear() || gstate.isDepthWriteEnabled();
glstate.depthWrite.set(wantDepthWrite ? GL_TRUE : GL_FALSE);
float depthRangeMin = gstate_c.zOff - gstate_c.zScale;
float depthRangeMax = gstate_c.zOff + gstate_c.zScale;
glstate.depthRange.set(depthRangeMin, depthRangeMax);
}
void TransformDrawEngine::UpdateViewportAndProjection() {
@@ -240,14 +236,13 @@ void TransformDrawEngine::UpdateViewportAndProjection() {
if (throughmode) {
// No viewport transform here. Let's experiment with using region.
glstate.viewport.set((0 + regionX1) * renderWidthFactor, (0 - regionY1) * renderHeightFactor, (regionX2 - regionX1) * renderWidthFactor, (regionY2 - regionY1) * renderHeightFactor);
glstate.depthRange.set(1.0, 0.0);
} else {
// These we can turn into a glViewport call, offset by offsetX and offsetY. Math after.
float vpXa = getFloat24(gstate.viewportx1);
float vpXb = getFloat24(gstate.viewportx2);
float vpYa = getFloat24(gstate.viewporty1);
float vpYb = getFloat24(gstate.viewporty2);
float vpZa = getFloat24(gstate.viewportz1); // / 65536.0f should map it to OpenGL's 0.0-1.0 Z range
float vpZb = getFloat24(gstate.viewportz2); // / 65536.0f
// The viewport transform appears to go like this:
// Xscreen = -offsetX + vpXb + vpXa * Xview
@@ -263,10 +258,6 @@ void TransformDrawEngine::UpdateViewportAndProjection() {
float vpWidth = fabsf(gstate_c.vpWidth);
float vpHeight = fabsf(gstate_c.vpHeight);
// TODO: These two should feed into glDepthRange somehow.
float vpZ0 = (vpZb - vpZa) / 65536.0f;
float vpZ1 = (vpZa * 2) / 65536.0f;
vpX0 *= renderWidthFactor;
vpY0 *= renderHeightFactor;
vpWidth *= renderWidthFactor;
@@ -277,5 +268,11 @@ void TransformDrawEngine::UpdateViewportAndProjection() {
glstate.viewport.set(vpX0, vpY0, vpWidth, vpHeight);
// Sadly, as glViewport takes integers, we will not be able to support sub pixel offsets this way. But meh.
// shaderManager_->DirtyUniform(DIRTY_PROJMATRIX);
float zScale = getFloat24(gstate.viewportz1) / 65535.f;
float zOff = getFloat24(gstate.viewportz2) / 65535.f;
float depthRangeMin = zOff - zScale;
float depthRangeMax = zOff + zScale;
glstate.depthRange.set(depthRangeMin, depthRangeMax);
}
}
+127 -57
View File
@@ -112,6 +112,8 @@ void TextureCache::InvalidateAll(bool force) {
}
TextureCache::TexCacheEntry *TextureCache::GetEntryAt(u32 texaddr) {
// If no CLUT, as in framebuffer textures, cache key is simply texaddr.
auto iter = cache.find(texaddr);
for (auto entry = cache.begin(); entry != cache.end(); ++entry) {
if (entry->second.addr == texaddr) {
return &entry->second;
@@ -121,11 +123,13 @@ TextureCache::TexCacheEntry *TextureCache::GetEntryAt(u32 texaddr) {
}
void TextureCache::NotifyFramebuffer(u32 address, FBO *fbo) {
// Must be in VRAM so | 0x04000000 it is.
TexCacheEntry *entry = GetEntryAt(address | 0x04000000);
if (entry) {
INFO_LOG(HLE, "Render to texture detected at %08x!", address);
if (!entry->fbo)
entry->fbo = fbo;
// TODO: Delete the original non-fbo texture too.
}
}
@@ -370,9 +374,9 @@ GLenum getClutDestFormat(GEPaletteFormat format) {
return 0;
}
const u8 texByteAlignMap[] = {2, 2, 2, 4};
static const u8 texByteAlignMap[] = {2, 2, 2, 4};
const GLuint MinFiltGL[8] = {
static const GLuint MinFiltGL[8] = {
GL_NEAREST,
GL_LINEAR,
GL_NEAREST,
@@ -383,11 +387,16 @@ const GLuint MinFiltGL[8] = {
GL_LINEAR_MIPMAP_LINEAR,
};
const GLuint MagFiltGL[2] = {
static const GLuint MagFiltGL[2] = {
GL_NEAREST,
GL_LINEAR
};
// OpenGL ES 2.0 workaround. Let's see if this hackery works.
#ifndef GL_TEXTURE_LOD_BIAS
#define GL_TEXTURE_LOD_BIAS 0x8501
#endif
// This should not have to be done per texture! OpenGL is silly yo
// TODO: Dirty-check this against the current texture.
void TextureCache::UpdateSamplingParams(TexCacheEntry &entry, bool force) {
@@ -396,8 +405,17 @@ void TextureCache::UpdateSamplingParams(TexCacheEntry &entry, bool force) {
bool sClamp = gstate.texwrap & 1;
bool tClamp = (gstate.texwrap>>8) & 1;
// TODO: remove this line when we support mipmaps
minFilt &= 1; // no mipmaps yet
if (entry.maxLevel == 0) {
// Enforce no mip filtering, for safety.
minFilt &= 1; // no mipmaps yet
} else {
// TODO: Is this a signed value? Which direction?
float lodBias = 0.0; // -(float)((gstate.texlevel >> 16) & 0xFF) / 16.0f;
if (force || entry.lodBias != lodBias) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, lodBias);
entry.lodBias = lodBias;
}
}
if (g_Config.bLinearFiltering) {
magFilt |= 1;
@@ -462,7 +480,7 @@ struct DXT5Block {
};
static inline u32 makecol(int r, int g, int b, int a) {
return (a << 24)|(r << 16)|(g << 8)|b;
return (a << 24) | (r << 16) | (g << 8) | b;
}
// This could probably be done faster by decoding two or four blocks at a time with SSE/NEON.
@@ -641,7 +659,6 @@ void TextureCache::SetTexture() {
return;
}
u8 level = 0;
u32 format = gstate.texformat & 0xF;
if (format >= 11) {
ERROR_LOG(G3D, "Unknown texture format %i", format);
@@ -649,38 +666,50 @@ void TextureCache::SetTexture() {
}
bool hasClut = formatUsesClut[format];
const u8 *texptr = Memory::GetPointer(texaddr);
u32 clutformat = gstate.clutformat & 3;
u32 clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2);
const u8 *texptr = Memory::GetPointer(texaddr);
u32 texhash = texptr ? MiniHash((const u32*)texptr) : 0;
u64 cachekey = texaddr;
if (formatUsesClut[format])
cachekey |= (u64)clutaddr << 32;
u64 cachekey = texaddr ^ texhash;
if (hasClut) {
cachekey |= (u64) clutaddr << 32;
int maxLevel = ((gstate.texmode >> 16) & 0x7);
// Adjust maxLevel to actually present levels..
for (int i = 0; i <= maxLevel; i++) {
// If encountering levels pointing to nothing, adjust max level.
u32 levelTexaddr = (gstate.texaddr[i] & 0xFFFFF0) | ((gstate.texbufwidth[i] << 8) & 0x0F000000);
if (!Memory::IsValidAddress(levelTexaddr)) {
maxLevel = i - 1;
break;
}
}
u32 texhash = MiniHash((const u32 *)Memory::GetPointer(texaddr));
int w = 1 << (gstate.texsize[0] & 0xf);
int h = 1 << ((gstate.texsize[0]>>8) & 0xf);
int h = 1 << ((gstate.texsize[0] >> 8) & 0xf);
// Check for FBO - slow!
TexCacheEntry *fboEntry = GetEntryAt(texaddr);
if (fboEntry && fboEntry->fbo) {
fbo_bind_color_as_texture(fboEntry->fbo, 0);
UpdateSamplingParams(*fboEntry, false);
int fbow, fboh;
fbo_get_dimensions(fboEntry->fbo, &fbow, &fboh);
gstate_c.curTextureWidth = w / fbow; // except not -
gstate_c.curTextureHeight = h / fboh;
return;
}
TexCache::iterator iter = cache.find(cachekey);
if (iter != cache.end()) {
//Validate the texture here (width, height etc)
TexCacheEntry &entry = iter->second;
// Check for FBO - slow!
if (entry.fbo) {
fbo_bind_color_as_texture(entry.fbo, 0);
UpdateSamplingParams(entry, false);
int fbow, fboh;
fbo_get_dimensions(entry.fbo, &fbow, &fboh);
// Almost certain this isn't right.
gstate_c.curTextureWidth = fbow;
gstate_c.curTextureHeight = fboh;
return;
}
//Validate the texture here (width, height etc)
int dim = gstate.texsize[0] & 0xF0F;
bool match = true;
@@ -710,6 +739,8 @@ void TextureCache::SetTexture() {
match = false;
}
}
if (entry.maxLevel != maxLevel)
match = false;
if (match) {
//got one!
@@ -738,6 +769,8 @@ void TextureCache::SetTexture() {
entry.format = format;
entry.frameCounter = gpuStats.numFrames;
entry.fbo = 0;
entry.maxLevel = maxLevel;
entry.lodBias = 0.0f;
if (format >= GE_TFMT_CLUT4 && format <= GE_TFMT_CLUT32) {
entry.clutformat = clutformat;
@@ -759,38 +792,86 @@ void TextureCache::SetTexture() {
for (u32 i = 0; i < (entry.sizeInRAM * 2) / 4; ++i)
entry.fullhash += *checkp++;
gstate_c.curTextureWidth=w;
gstate_c.curTextureHeight=h;
GLenum dstFmt = 0;
u32 texByteAlign = 1;
gstate_c.curTextureWidth = w;
gstate_c.curTextureHeight = h;
glGenTextures(1, &entry.texture);
glBindTexture(GL_TEXTURE_2D, entry.texture);
#ifdef USING_GLES2
// GLES2 doesn't have support for a "Max lod" which is critical as PSP games often
// don't specify mips all the way down. As a result, we either need to manually generate
// the bottom few levels or rely on OpenGL's autogen mipmaps instead, which might not
// be as good quality as the game's own (might even be better in some cases though).
// For now, I choose to use autogen mips on GLES2 and the game's own on other platforms.
// As is usual, GLES3 will solve this problem nicely but wide distribution of that is
// years away.
LoadTextureLevel(entry, 0);
if (entry.maxLevel > 0)
glGenerateMipmap(GL_TEXTURE_2D);
#else
for (int i = 0; i <= entry.maxLevel; i++) {
LoadTextureLevel(entry, i);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, entry.maxLevel);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, entry.maxLevel);
#endif
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4);
UpdateSamplingParams(entry, true);
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
cache[cachekey] = entry;
}
void TextureCache::LoadTextureLevel(TexCacheEntry &entry, int level)
{
void *finalBuf = NULL;
// TODO: only do this once
u32 texByteAlign = 1;
// TODO: Look into using BGRA for 32-bit textures when the GL_EXT_texture_format_BGRA8888 extension is available, as it's faster than RGBA on some chips.
GLenum dstFmt = 0;
// TODO: Actually decode the mipmaps.
switch (format)
u32 texaddr = (gstate.texaddr[level] & 0xFFFFF0) | ((gstate.texbufwidth[level] << 8) & 0x0F000000);
int bufw = gstate.texbufwidth[level] & 0x3ff;
int w = 1 << (gstate.texsize[level] & 0xf);
int h = 1 << ((gstate.texsize[level] >> 8) & 0xf);
const u8 *texptr = Memory::GetPointer(texaddr);
switch (entry.format)
{
case GE_TFMT_CLUT4:
dstFmt = getClutDestFormat((GEPaletteFormat)(gstate.clutformat & 3));
dstFmt = getClutDestFormat((GEPaletteFormat)(entry.clutformat));
switch (clutformat) {
switch (entry.clutformat) {
case GE_CMODE_16BIT_BGR5650:
case GE_CMODE_16BIT_ABGR5551:
case GE_CMODE_16BIT_ABGR4444:
{
ReadClut16(clutBuf16);
const u16 *clut = clutBuf16;
u32 clutSharingOff = 0;//gstate.mipmapShareClut ? 0 : level * 16;
u32 clutSharingOffset = 0; //(gstate.mipmapShareClut & 1) ? 0 : level * 16;
texByteAlign = 2;
if (!(gstate.texmode & 1)) {
const u8 *addr = Memory::GetPointer(texaddr);
for (int i = 0; i < bufw * h; i += 2)
{
u8 index = *addr++;
tmpTexBuf16[i + 0] = clut[GetClutIndex((index >> 0) & 0xf) + clutSharingOff];
tmpTexBuf16[i + 1] = clut[GetClutIndex((index >> 4) & 0xf) + clutSharingOff];
tmpTexBuf16[i + 0] = clut[GetClutIndex((index >> 0) & 0xf) + clutSharingOffset];
tmpTexBuf16[i + 1] = clut[GetClutIndex((index >> 4) & 0xf) + clutSharingOffset];
}
} else {
UnswizzleFromMem(texaddr, 0, level);
@@ -800,7 +881,7 @@ void TextureCache::SetTexture() {
u32 k, index;
for (k = 0; k < 8; k++) {
index = (n >> (k * 4)) & 0xf;
tmpTexBuf16[i + k] = clut[GetClutIndex(index) + clutSharingOff];
tmpTexBuf16[i + k] = clut[GetClutIndex(index) + clutSharingOffset];
}
}
}
@@ -863,11 +944,11 @@ void TextureCache::SetTexture() {
case GE_TFMT_4444:
case GE_TFMT_5551:
case GE_TFMT_5650:
if (format == GE_TFMT_4444)
if (entry.format == GE_TFMT_4444)
dstFmt = GL_UNSIGNED_SHORT_4_4_4_4;
else if (format == GE_TFMT_5551)
else if (entry.format == GE_TFMT_5551)
dstFmt = GL_UNSIGNED_SHORT_5_5_5_1;
else if (format == GE_TFMT_5650)
else if (entry.format == GE_TFMT_5650)
dstFmt = GL_UNSIGNED_SHORT_5_6_5;
texByteAlign = 2;
@@ -931,7 +1012,7 @@ void TextureCache::SetTexture() {
break;
case GE_TFMT_DXT5:
ERROR_LOG(G3D, "Unhandled compressed texture, format %i! swizzle=%i", format, gstate.texmode & 1);
ERROR_LOG(G3D, "Unhandled compressed texture, format %i! swizzle=%i", entry.format, gstate.texmode & 1);
dstFmt = GL_UNSIGNED_BYTE;
{
u32 *dst = tmpTexBuf32;
@@ -951,7 +1032,7 @@ void TextureCache::SetTexture() {
break;
default:
ERROR_LOG(G3D, "Unknown Texture Format %d!!!", format);
ERROR_LOG(G3D, "Unknown Texture Format %d!!!", entry.format);
finalBuf = tmpTexBuf32;
return;
}
@@ -999,19 +1080,8 @@ void TextureCache::SetTexture() {
//glPixelStorei(GL_PACK_ROW_LENGTH, bufw);
glPixelStorei(GL_PACK_ALIGNMENT, texByteAlign);
INFO_LOG(G3D, "Creating texture %i from %08x: %i x %i (stride: %i). fmt: %i", entry.texture, entry.addr, w, h, bufw, entry.format);
INFO_LOG(HLE, "Creating texture level %i/%i from %08x: %i x %i (stride: %i). fmt: %i", level, entry.maxLevel, texaddr, w, h, bufw, entry.format);
glGenTextures(1, &entry.texture);
glBindTexture(GL_TEXTURE_2D, entry.texture);
GLuint components = dstFmt == GL_UNSIGNED_SHORT_5_6_5 ? GL_RGB : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, components, w, h, 0, components, dstFmt, finalBuf);
// glGenerateMipmap(GL_TEXTURE_2D);
UpdateSamplingParams(entry, true);
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
cache[cachekey] = entry;
glTexImage2D(GL_TEXTURE_2D, level, components, w, h, 0, components, dstFmt, finalBuf);
}
+3
View File
@@ -58,6 +58,8 @@ private:
u32 texture; //GLuint
int invalidHint;
u32 fullhash;
int maxLevel;
float lodBias;
// Cache the current filter settings so we can avoid setting it again.
u8 magFilt;
@@ -70,6 +72,7 @@ private:
void *UnswizzleFromMem(u32 texaddr, u32 bytesPerPixel, u32 level);
void *readIndexedTex(int level, u32 texaddr, int bytesPerIndex);
void UpdateSamplingParams(TexCacheEntry &entry, bool force);
void LoadTextureLevel(TexCacheEntry &entry, int level);
TexCacheEntry *GetEntryAt(u32 texaddr);
+57 -28
View File
@@ -262,7 +262,7 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
}
Color4 lightDiff(gstate_c.lightColor[1][l], 0.0f);
Color4 diff = (lightDiff * *diffuse) * (dot * lightScale);
Color4 diff = (lightDiff * *diffuse) * (max(dot, 0.0f) * lightScale);
// Real PSP specular
Vec3 toViewer(0,0,1);
@@ -276,10 +276,10 @@ void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[
halfVec.Normalize();
dot = halfVec * norm;
if (dot >= 0)
if (dot > 0)
{
Color4 lightSpec(gstate_c.lightColor[2][l], 0.0f);
lightSum1 += (lightSpec * *specular * (powf(dot, specCoef_)*lightScale));
lightSum1 += (lightSpec * *specular * (powf(dot, specCoef_) * lightScale));
}
}
dots[l] = dot;
@@ -315,6 +315,12 @@ static const GlTypeInfo GLComp[] = {
{GL_UNSIGNED_BYTE, 2, GL_TRUE},// DEC_U8_2,
{GL_UNSIGNED_BYTE, 3, GL_TRUE},// DEC_U8_3,
{GL_UNSIGNED_BYTE, 4, GL_TRUE},// DEC_U8_4,
{GL_UNSIGNED_SHORT, 1, GL_TRUE},// DEC_U16_1,
{GL_UNSIGNED_SHORT, 2, GL_TRUE},// DEC_U16_2,
{GL_UNSIGNED_SHORT, 3, GL_TRUE},// DEC_U16_3,
{GL_UNSIGNED_SHORT, 4, GL_TRUE},// DEC_U16_4,
{GL_UNSIGNED_BYTE, 2, GL_FALSE},// DEC_U8A_2,
{GL_UNSIGNED_SHORT, 2, GL_FALSE},// DEC_U16A_2,
};
static inline void VertexAttribSetup(int attrib, int fmt, int stride, u8 *ptr) {
@@ -399,6 +405,13 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
vertexCount = 0x10000/3;
#endif
float uscale = 1.0f;
float vscale = 1.0f;
if (throughmode) {
uscale /= gstate_c.curTextureWidth;
vscale /= gstate_c.curTextureHeight;
}
Lighter lighter;
float fog_end = getFloat24(gstate.fog1);
float fog_slope = getFloat24(gstate.fog2);
@@ -430,6 +443,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
if (reader.hasUV()) {
reader.ReadUV(uv);
uv[0] *= uscale;
uv[1] *= vscale;
}
fogCoef = 1.0f;
// Scale UV?
@@ -529,8 +545,8 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
{
case 0: // UV mapping
// Texture scale/offset is only performed in this mode.
uv[0] = ruv[0]*gstate_c.uScale + gstate_c.uOff;
uv[1] = ruv[1]*gstate_c.vScale + gstate_c.vOff;
uv[0] = uscale * (ruv[0]*gstate_c.uScale + gstate_c.uOff);
uv[1] = vscale * (ruv[1]*gstate_c.vScale + gstate_c.vOff);
break;
case 1:
{
@@ -580,8 +596,12 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
memcpy(&transformed[index].x, v, 3 * sizeof(float));
transformed[index].fog = fogCoef;
memcpy(&transformed[index].u, uv, 2 * sizeof(float));
memcpy(&transformed[index].color0, c0, 4 * sizeof(float));
memcpy(&transformed[index].color1, c1, 3 * sizeof(float));
for (int i = 0; i < 4; i++) {
transformed[index].color0[i] = c0[i] * 255.0f;
}
for (int i = 0; i < 4; i++) {
transformed[index].color1[i] = c1[i] * 255.0f;
}
}
// Step 2: expand rectangles.
@@ -674,8 +694,8 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
}
glVertexAttribPointer(program->a_position, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
if (program->a_texcoord != -1) glVertexAttribPointer(program->a_texcoord, 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 4);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 6 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 10 * 4);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 6 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + 7 * 4);
if (drawIndexed) {
if (useVBO) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_[curVbo_]);
@@ -800,6 +820,7 @@ u32 TransformDrawEngine::ComputeHash() {
u32 fullhash = 0;
int vertexSize = dec.GetDecVtxFmt().stride;
// TODO: Add some caps both for numDrawCalls and num verts to check?
for (int i = 0; i < numDrawCalls; i++) {
if (!drawCalls[i].inds) {
fullhash += CityHash32((const char *)drawCalls[i].verts, vertexSize * drawCalls[i].vertexCount);
@@ -842,7 +863,7 @@ void TransformDrawEngine::ClearTrackedVertexArrays() {
void TransformDrawEngine::DecimateTrackedVertexArrays() {
int threshold = gpuStats.numFrames - VAI_KILL_AGE;
for (auto iter = vai_.begin(); iter != vai_.end(); ) {
if (iter->second->lastFrame < threshold ) {
if (iter->second->lastFrame < threshold) {
delete iter->second;
vai_.erase(iter++);
}
@@ -901,6 +922,7 @@ void TransformDrawEngine::Flush() {
u32 dataHash = ComputeHash();
vai->hash = dataHash;
vai->status = VertexArrayInfo::VAI_HASHING;
vai->drawsUntilNextFullHash = 0;
DecodeVerts(); // writes to indexGen
goto rotateVBO;
}
@@ -909,27 +931,33 @@ void TransformDrawEngine::Flush() {
// But if we get this far it's likely to be worth creating a vertex buffer.
case VertexArrayInfo::VAI_HASHING:
{
u32 newHash = ComputeHash();
vai->numDraws++;
// TODO: tweak
if (vai->numDraws > 100000) {
vai->status = VertexArrayInfo::VAI_RELIABLE;
}
if (newHash == vai->hash) {
gpuStats.numCachedDrawCalls++;
if (vai->drawsUntilNextFullHash == 0) {
u32 newHash = ComputeHash();
// exponential backoff up to 16 frames
vai->drawsUntilNextFullHash = std::min(16, vai->numDraws);
// TODO: tweak
//if (vai->numDraws > 1000) {
// vai->status = VertexArrayInfo::VAI_RELIABLE;
//}
if (newHash != vai->hash) {
vai->status = VertexArrayInfo::VAI_UNRELIABLE;
if (vai->vbo) {
glDeleteBuffers(1, &vai->vbo);
vai->vbo = 0;
}
if (vai->ebo) {
glDeleteBuffers(1, &vai->ebo);
vai->ebo = 0;
}
DecodeVerts();
goto rotateVBO;
}
} else {
vai->status = VertexArrayInfo::VAI_UNRELIABLE;
if (vai->vbo) {
glDeleteBuffers(1, &vai->vbo);
vai->vbo = 0;
}
if (vai->ebo) {
glDeleteBuffers(1, &vai->ebo);
vai->ebo = 0;
}
DecodeVerts();
goto rotateVBO;
vai->drawsUntilNextFullHash--;
// TODO: "mini-hashing" the first 32 bytes of the vertex/index data or something.
}
if (vai->vbo == 0) {
DecodeVerts();
vai->numVerts = indexGen.VertexCount();
@@ -951,6 +979,7 @@ void TransformDrawEngine::Flush() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
} else {
gpuStats.numCachedDrawCalls++;
glBindBuffer(GL_ARRAY_BUFFER, vai->vbo);
if (vai->ebo)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vai->ebo);
+3
View File
@@ -57,6 +57,7 @@ public:
numDraws = 0;
lastFrame = gpuStats.numFrames;
numVerts = 0;
drawsUntilNextFullHash = 0;
}
~VertexArrayInfo();
enum Status {
@@ -73,6 +74,7 @@ public:
u32 vbo;
u32 ebo;
// TODO: see if we can avoid having this full thing here.
DecVtxFormat decFmt;
// Precalculated parameter for drawdrawElements
@@ -83,6 +85,7 @@ public:
u8 numDCs;
int numDraws;
int lastFrame; // So that we can forget.
u16 drawsUntilNextFullHash;
};
+36 -16
View File
@@ -73,6 +73,12 @@ int DecFmtSize(u8 fmt) {
case DEC_U8_2: return 4;
case DEC_U8_3: return 4;
case DEC_U8_4: return 4;
case DEC_U16_1: return 4;
case DEC_U16_2: return 4;
case DEC_U16_3: return 8;
case DEC_U16_4: return 8;
case DEC_U8A_2: return 4;
case DEC_U16A_2: return 4;
default:
return 0;
}
@@ -118,10 +124,10 @@ void VertexDecoder::Step_WeightsU8() const
void VertexDecoder::Step_WeightsU16() const
{
float *wt = (float *)(decoded_ + decFmt.w0off);
u16 *wt = (u16 *)(decoded_ + decFmt.w0off);
const u16 *wdata = (const u16*)(ptr_);
for (int j = 0; j < nweights; j++)
wt[j] = (float)wdata[j] / 65535.0f;
wt[j] = wdata[j];
}
// Float weights should be uncommon, we can live with having to multiply these by 2.0
@@ -138,41 +144,42 @@ void VertexDecoder::Step_WeightsFloat() const
void VertexDecoder::Step_TcU8() const
{
float *uv = (float *)(decoded_ + decFmt.uvoff);
u8 *uv = (u8*)(decoded_ + decFmt.uvoff);
const u8 *uvdata = (const u8*)(ptr_ + tcoff);
for (int j = 0; j < 2; j++)
uv[j] = (float)uvdata[j] / 128.0f;
uv[0] = uvdata[0];
uv[1] = uvdata[1];
}
void VertexDecoder::Step_TcU16() const
{
float *uv = (float *)(decoded_ + decFmt.uvoff);
u16 *uv = (u16 *)(decoded_ + decFmt.uvoff);
const u16 *uvdata = (const u16*)(ptr_ + tcoff);
uv[0] = (float)uvdata[0] / 32768.0f;
uv[1] = (float)uvdata[1] / 32768.0f;
uv[0] = uvdata[0];
uv[1] = uvdata[1];
}
void VertexDecoder::Step_TcU16Through() const
{
float *uv = (float *)(decoded_ + decFmt.uvoff);
u16 *uv = (u16 *)(decoded_ + decFmt.uvoff);
const u16 *uvdata = (const u16*)(ptr_ + tcoff);
uv[0] = (float)uvdata[0] / (float)(gstate_c.curTextureWidth);
uv[1] = (float)uvdata[1] / (float)(gstate_c.curTextureHeight);
uv[0] = uvdata[0];
uv[1] = uvdata[1];
}
void VertexDecoder::Step_TcFloat() const
{
float *uv = (float *)(decoded_ + decFmt.uvoff);
const float *uvdata = (const float*)(ptr_ + tcoff);
memcpy(uv, uvdata, sizeof(float) * 2);
uv[0] = uvdata[0] * 0.5f;
uv[1] = uvdata[1] * 0.5f;
}
void VertexDecoder::Step_TcFloatThrough() const
{
float *uv = (float *)(decoded_ + decFmt.uvoff);
const float *uvdata = (const float*)(ptr_ + tcoff);
uv[0] = uvdata[0] / (float)(gstate_c.curTextureWidth);
uv[1] = uvdata[1] / (float)(gstate_c.curTextureHeight);
uv[0] = uvdata[0] * 0.5f;
uv[1] = uvdata[1] * 0.5f;
}
void VertexDecoder::Step_Color565() const
@@ -557,6 +564,9 @@ void VertexDecoder::SetVertexType(u32 fmt) {
if (weighttype == GE_VTYPE_WEIGHT_8BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U8_1;
weightSize = 1;
} else if (weighttype == GE_VTYPE_WEIGHT_16BIT >> GE_VTYPE_WEIGHT_SHIFT) {
fmtBase = DEC_U16_1;
weightSize = 2;
}
if (nweights < 5) {
@@ -580,8 +590,18 @@ void VertexDecoder::SetVertexType(u32 fmt) {
steps_[numSteps_++] = throughmode ? tcstep_through[tc] : tcstep[tc];
// All UV decode to DEC_FLOAT2 currently.
decFmt.uvfmt = DEC_FLOAT_2;
switch (tc) {
case GE_VTYPE_TC_8BIT >> GE_VTYPE_TC_SHIFT:
decFmt.uvfmt = throughmode ? DEC_U8A_2 : DEC_U8_2;
break;
case GE_VTYPE_TC_16BIT >> GE_VTYPE_TC_SHIFT:
decFmt.uvfmt = throughmode ? DEC_U16A_2 : DEC_U16_2;
break;
case GE_VTYPE_TC_FLOAT >> GE_VTYPE_TC_SHIFT:
decFmt.uvfmt = DEC_FLOAT_2;
break;
}
decFmt.uvoff = decOff;
decOff += DecFmtSize(decFmt.uvfmt);
}
+78 -30
View File
@@ -38,6 +38,12 @@ enum {
DEC_U8_2,
DEC_U8_3,
DEC_U8_4,
DEC_U16_1,
DEC_U16_2,
DEC_U16_3,
DEC_U16_4,
DEC_U8A_2,
DEC_U16A_2,
};
int DecFmtSize(u8 fmt);
@@ -58,8 +64,8 @@ struct TransformedVertex
{
float x, y, z, fog; // in case of morph, preblend during decode
float u; float v; // scaled by uscale, vscale, if there
float color0[4]; // prelit
float color1[3]; // prelit
u8 color0[4]; // prelit
u8 color1[3]; // prelit
};
DecVtxFormat GetTransformedVtxFormat(const DecVtxFormat &fmt);
@@ -189,16 +195,16 @@ public:
break;
case DEC_S16_3:
{
s16 *p = (s16 *)(data_ + decFmt_.posoff);
const s16 *p = (s16 *)(data_ + decFmt_.posoff);
for (int i = 0; i < 3; i++)
pos[i] = p[i] / 32767.0f;
pos[i] = p[i] * (1.f / 32768.f);
}
break;
case DEC_S8_3:
{
s8 *p = (s8 *)(data_ + decFmt_.posoff);
const s8 *p = (s8 *)(data_ + decFmt_.posoff);
for (int i = 0; i < 3; i++)
pos[i] = p[i] / 127.0f;
pos[i] = p[i] * (1.f / 128.f);
}
break;
default:
@@ -214,16 +220,16 @@ public:
break;
case DEC_S16_3:
{
s16 *p = (s16 *)(data_ + decFmt_.nrmoff);
const s16 *p = (s16 *)(data_ + decFmt_.nrmoff);
for (int i = 0; i < 3; i++)
nrm[i] = p[i] / 32767.0f;
nrm[i] = p[i] * (1.f / 32768.f);
}
break;
case DEC_S8_3:
{
s8 *p = (s8 *)(data_ + decFmt_.nrmoff);
const s8 *p = (s8 *)(data_ + decFmt_.nrmoff);
for (int i = 0; i < 3; i++)
nrm[i] = p[i] / 127.0f;
nrm[i] = p[i] * (1.f / 128.0f);
}
break;
default:
@@ -233,9 +239,37 @@ public:
}
void ReadUV(float uv[2]) {
const u8 *b = (const u8 *)(data_ + decFmt_.uvoff);
const u16 *s = (const u16 *)(data_ + decFmt_.uvoff);
const float *f = (const float *)(data_ + decFmt_.uvoff);
switch (decFmt_.uvfmt) {
case DEC_U8_2:
uv[0] = b[0] * (1.f / 128.f);
uv[1] = b[1] * (1.f / 128.f);
break;
case DEC_U16_2:
uv[0] = s[0] * (1.f / 32768.f);
uv[1] = s[1] * (1.f / 32768.f);
break;
case DEC_FLOAT_2:
memcpy(uv, data_ + decFmt_.uvoff, 8); break;
if (isThrough()) {
uv[0] = f[0];
uv[1] = f[1];
} else {
uv[0] = f[0] * 2.0f;
uv[1] = f[1] * 2.0f;
}
break;
case DEC_U16A_2:
{
const u16 *p = (const u16 *)(data_ + decFmt_.uvoff);
uv[0] = (float)p[0];
uv[1] = (float)p[1];
}
break;
default:
ERROR_LOG(G3D, "Reader: Unsupported UV Format");
break;
@@ -248,7 +282,7 @@ public:
{
const u8 *p = (const u8 *)(data_ + decFmt_.c0off);
for (int i = 0; i < 4; i++)
color[i] = p[i] / 255.0f;
color[i] = p[i] * (1.f / 255.f);
}
break;
case DEC_FLOAT_4:
@@ -265,7 +299,7 @@ public:
{
const u8 *p = (const u8 *)(data_ + decFmt_.c1off);
for (int i = 0; i < 3; i++)
color[i] = p[i] / 255.0f;
color[i] = p[i] * (1.f / 255.f);
}
break;
case DEC_FLOAT_4:
@@ -277,34 +311,48 @@ public:
}
void ReadWeights(float weights[8]) {
const float *f = (const float *)(data_ + decFmt_.w0off);
const u8 *p = (const u8 *)(data_ + decFmt_.w0off);
const u16 *s = (const u16 *)(data_ + decFmt_.w0off);
switch (decFmt_.w0fmt) {
case DEC_FLOAT_1: memcpy(weights, data_ + decFmt_.w0off, 4); break;
case DEC_FLOAT_2: memcpy(weights, data_ + decFmt_.w0off, 8); break;
case DEC_FLOAT_3: memcpy(weights, data_ + decFmt_.w0off, 12); break;
case DEC_FLOAT_4: memcpy(weights, data_ + decFmt_.w0off, 16); break;
case DEC_U8_1: weights[0] = p[0] / 128.f; break;
case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = p[i] / 128.f; break;
case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = p[i] / 128.f; break;
case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = p[i] / 128.f; break;
case DEC_FLOAT_1:
case DEC_FLOAT_2:
case DEC_FLOAT_3:
case DEC_FLOAT_4:
for (int i = 0; i <= decFmt_.w0fmt - DEC_FLOAT_1; i++)
weights[i] = f[i] * 2.0;
break;
case DEC_U8_1: weights[0] = p[0] * (1.f / 128.f); break;
case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i] = p[i] * (1.f / 128.f); break;
case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i] = p[i] * (1.f / 128.f); break;
case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i] = p[i] * (1.f / 128.f); break;
case DEC_U16_1: weights[0] = s[0] * (1.f / 32768.f); break;
case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i] = s[i] * (1.f / 32768.f); break;
case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i] = s[i] * (1.f / 32768.f); break;
case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i] = s[i] * (1.f / 32768.f); break;
default:
ERROR_LOG(G3D, "Reader: Unsupported W0 Format");
break;
}
f = (const float*)(data_ + decFmt_.w1off);
p = (const u8 *)(data_ + decFmt_.w1off);
s = (const u16 *)(data_ + decFmt_.w1off);
switch (decFmt_.w1fmt) {
case 0:
// It's fine for there to be w0 weights but not w1.
break;
case DEC_FLOAT_1: memcpy(weights + 4, data_ + decFmt_.w1off, 4); break;
case DEC_FLOAT_2: memcpy(weights + 4, data_ + decFmt_.w1off, 8); break;
case DEC_FLOAT_3: memcpy(weights + 4, data_ + decFmt_.w1off, 12); break;
case DEC_FLOAT_4: memcpy(weights + 4, data_ + decFmt_.w1off, 16); break;
case DEC_U8_1: weights[4] = p[0] / 128.f; break;
case DEC_U8_2: for (int i = 0; i < 2; i++) weights[i+4] = p[i] / 128.f; break;
case DEC_U8_3: for (int i = 0; i < 3; i++) weights[i+4] = p[i] / 128.f; break;
case DEC_U8_4: for (int i = 0; i < 4; i++) weights[i+4] = p[i] / 128.f; break;
case DEC_FLOAT_1:
case DEC_FLOAT_2:
case DEC_FLOAT_3:
case DEC_FLOAT_4:
for (int i = 0; i <= decFmt_.w1fmt - DEC_FLOAT_1; i++)
weights[i+4] = f[i] * 2.0;
break;
case DEC_U16_1: weights[4] = s[0] * (1.f / 32768.f); break;
case DEC_U16_2: for (int i = 0; i < 2; i++) weights[i+4] = s[i] * (1.f / 32768.f); break;
case DEC_U16_3: for (int i = 0; i < 3; i++) weights[i+4] = s[i] * (1.f / 32768.f); break;
case DEC_U16_4: for (int i = 0; i < 4; i++) weights[i+4] = s[i] * (1.f / 32768.f); break;
default:
ERROR_LOG(G3D, "Reader: Unsupported W1 Format");
break;
@@ -314,7 +362,7 @@ public:
bool hasColor0() const { return decFmt_.c0fmt != 0; }
bool hasNormal() const { return decFmt_.nrmfmt != 0; }
bool hasUV() const { return decFmt_.uvfmt != 0; }
bool isThrough() const { return (vtype_ & GE_VTYPE_THROUGH) != 0; }
void Goto(int index) {
data_ = base_ + index * decFmt_.stride;
}
+3 -3
View File
@@ -297,7 +297,7 @@ void GenerateVertexShader(int prim, char *buffer) {
const char *specular = (gstate.materialupdate & 4) ? "unlitColor" : "u_matspecular.rgb";
if (gstate.lightingEnable & 1) {
WRITE(p, " vec4 lightSum0 = vec4(0.0);\n");
WRITE(p, " vec4 lightSum0 = u_ambient * %s + vec4(u_matemissive, 0.0);\n", ambient);
WRITE(p, " vec3 lightSum1 = vec3(0.0);\n");
}
@@ -345,7 +345,7 @@ void GenerateVertexShader(int prim, char *buffer) {
if (gstate.lightingEnable & 1) {
// Sum up ambient, emissive here.
WRITE(p, " v_color0 = clamp(lightSum0 + u_ambient * %s + vec4(u_matemissive, 0.0), 0.0, 1.0);\n", ambient);
WRITE(p, " v_color0 = clamp(lightSum0, 0.0, 1.0);\n");
if (lmode) {
WRITE(p, " v_color1 = clamp(lightSum1, 0.0, 1.0);\n");
} else {
@@ -375,7 +375,7 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, " vec3 temp_tc = a_position.xyz;\n");
break;
case 1: // Use unscaled UV as source
WRITE(p, " vec3 temp_tc = vec3(a_texcoord.xy, 0.0);\n");
WRITE(p, " vec3 temp_tc = vec3(a_texcoord.xy * 2.0f, 0.0);\n");
break;
case 2: // Use normalized transformed normal as source
WRITE(p, " vec3 temp_tc = normalize(a_normal);\n");
+3 -3
View File
@@ -145,7 +145,7 @@ struct GPUgstate
clutformat,
texfilter,
texwrap,
padxxxxx,
texlevel,
texfunc,
texenvcolor,
texflush,
@@ -236,8 +236,8 @@ struct GPUStateCache
bool textureChanged;
float uScale,vScale,zScale;
float uOff,vOff,zOff;
float uScale,vScale;
float uOff,vOff;
float zMin, zMax;
float lightpos[4][3];
float lightdir[4][3];
+2 -2
View File
@@ -521,13 +521,13 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer) {
case GE_CMD_VIEWPORTZ1:
{
float zScale = getFloat24(data) / 65535.f;
sprintf(buffer, "Z scale: %f", zScale);
sprintf(buffer, "Viewport Z scale: %f", zScale);
}
break;
case GE_CMD_VIEWPORTZ2:
{
float zOff = getFloat24(data) / 65535.f;
sprintf(buffer, "Z pos: %f", zOff);
sprintf(buffer, "Viewport Z pos: %f", zOff);
}
break;
+2 -1
View File
@@ -48,7 +48,8 @@ SOURCES += ../Common/ColorUtil.cpp \
../Common/Timer.cpp \
../Common/Version.cpp \
../Common/Crypto/*.cpp
HEADERS += ../Common/ColorUtil.h \
HEADERS += ../Common/ChunkFile.h \
../Common/ColorUtil.h \
../Common/ConsoleListener.h \
../Common/ExtendedTrace.h \
../Common/FileSearch.h \
+270 -97
View File
@@ -17,22 +17,72 @@
#include "gfx_es2/fbo.h"
#include "gfx_es2/gl_state.h"
#include "GPU/GPUState.h"
#include "android/jni/ui_atlas.h"
#include "native/util/random/rng.h"
#include "native/base/timeutil.h"
#include "native/base/colorutil.h"
#include "qtemugl.h"
#include "QtHost.h"
void EmuThread_Start(QString filename, QtEmuGL* w)
namespace
{
static const int symbols[4] = {
I_CROSS,
I_CIRCLE,
I_SQUARE,
I_TRIANGLE
};
static const uint32_t colors[4] = {
/*
0xFF6666FF, // blue
0xFFFF6666, // red
0xFFFF66FF, // pink
0xFF66FF66, // green
*/
0xC0FFFFFF,
0xC0FFFFFF,
0xC0FFFFFF,
0xC0FFFFFF,
};
static void DrawBackground(float alpha) {
static float xbase[100] = {0};
static float ybase[100] = {0};
if (xbase[0] == 0.0f) {
GMRng rng;
for (int i = 0; i < 100; i++) {
xbase[i] = rng.F() * dp_xres;
ybase[i] = rng.F() * dp_yres;
}
}
glClearColor(0.1f,0.2f,0.43f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ui_draw2d.DrawImageStretch(I_BG, 0, 0, dp_xres, dp_yres);
float t = time_now();
for (int i = 0; i < 100; i++) {
float x = xbase[i];
float y = ybase[i] + 40*cos(i * 7.2 + t * 1.3);
float angle = sin(i + t);
int n = i & 3;
ui_draw2d.DrawImageRotated(symbols[n], x, y, 1.0f, angle, colorAlpha(colors[n], alpha * 0.1f));
}
}
}
void EmuThread_Start(QtEmuGL* w)
{
//_dbg_clear_();
fileToStart = filename;
glWindow = w;
glWindow->doneCurrent();
glWindow->start_rendering();
}
void EmuThread_Stop()
{
// DSound_UpdateSound();
Core_Stop();
if(glWindow)
{
glWindow->stop_rendering();
@@ -40,6 +90,31 @@ void EmuThread_Stop()
host->UpdateUI();
}
void EmuThread_StartGame(QString filename)
{
if(glWindow)
{
glWindow->start_game(filename);
}
}
void EmuThread_StopGame()
{
if(glWindow)
{
glWindow->stop_game();
}
}
void EmuThread_LockDraw(bool value)
{
if(glWindow)
{
glWindow->LockDraw(value);
}
}
void EmuThread::init(InputState *inputState)
{
input_state = inputState;
@@ -50,8 +125,6 @@ void EmuThread::run()
running = true;
setCurrentThreadName("EmuThread");
g_State.bEmuThreadStarted = true;
host->UpdateUI();
host->InitGL();
@@ -64,80 +137,181 @@ void EmuThread::run()
INFO_LOG(BOOT, "Starting up hardware.");
CoreParameter coreParameter;
coreParameter.fileToStart = fileToStart.toStdString();
coreParameter.enableSound = true;
coreParameter.gpuCore = GPU_GLES;
coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore;
coreParameter.enableDebugging = true;
coreParameter.printfEmuLog = false;
coreParameter.headLess = false;
coreParameter.renderWidth = 480 * g_Config.iWindowZoom;
coreParameter.renderHeight = 272 * g_Config.iWindowZoom;
coreParameter.outputWidth = dp_xres;
coreParameter.outputHeight = dp_yres;
coreParameter.pixelWidth = pixel_xres;
coreParameter.pixelHeight = pixel_yres;
coreParameter.startPaused = !g_Config.bAutoRun;
std::string error_string;
if (!PSP_Init(coreParameter, &error_string))
{
ERROR_LOG(BOOT, "Error loading: %s", error_string.c_str());
FinalShutdown();
return;
}
LayoutGamepad(dp_xres, dp_yres);
_dbg_update_();
host->UpdateDisassembly();
Core_EnableStepping(coreParameter.startPaused ? TRUE : FALSE);
g_State.bBooted = true;
#ifdef _DEBUG
host->UpdateMemView();
#endif
host->BootDone();
QElapsedTimer timer;
while(running) {
//UpdateGamepad(*input_state);
timer.start();
UpdateInputState(input_state);
gameMutex.lock();
bool gRun = gameRunning;
gameMutex.unlock();
for (int i = 0; i < controllistCount; i++) {
if (input_state->pad_buttons_down & controllist[i].emu_id) {
__CtrlButtonDown(controllist[i].psp_id);
if(gRun)
{
gameMutex.lock();
glWindow->makeCurrent();
if(needInitGame)
{
g_State.bEmuThreadStarted = true;
CoreParameter coreParameter;
coreParameter.fileToStart = fileToStart.toStdString();
coreParameter.enableSound = true;
coreParameter.gpuCore = GPU_GLES;
coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore;
coreParameter.enableDebugging = true;
coreParameter.printfEmuLog = false;
coreParameter.headLess = false;
coreParameter.renderWidth = 480 * g_Config.iWindowZoom;
coreParameter.renderHeight = 272 * g_Config.iWindowZoom;
coreParameter.outputWidth = dp_xres;
coreParameter.outputHeight = dp_yres;
coreParameter.pixelWidth = pixel_xres;
coreParameter.pixelHeight = pixel_yres;
coreParameter.startPaused = !g_Config.bAutoRun;
std::string error_string;
if (!PSP_Init(coreParameter, &error_string))
{
ERROR_LOG(BOOT, "Error loading: %s", error_string.c_str());
FinalShutdown();
return;
}
LayoutGamepad(dp_xres, dp_yres);
_dbg_update_();
host->UpdateDisassembly();
Core_EnableStepping(coreParameter.startPaused ? TRUE : FALSE);
g_State.bBooted = true;
#ifdef _DEBUG
host->UpdateMemView();
#endif
host->BootDone();
needInitGame = false;
}
if (input_state->pad_buttons_up & controllist[i].emu_id) {
__CtrlButtonUp(controllist[i].psp_id);
UpdateInputState(input_state);
for (int i = 0; i < controllistCount; i++) {
if (input_state->pad_buttons_down & controllist[i].emu_id) {
__CtrlButtonDown(controllist[i].psp_id);
}
if (input_state->pad_buttons_up & controllist[i].emu_id) {
__CtrlButtonUp(controllist[i].psp_id);
}
}
__CtrlSetAnalog(input_state->pad_lstick_x, input_state->pad_lstick_y);
EndInputState(input_state);
glstate.Restore();
glViewport(0, 0, pixel_xres, pixel_yres);
Matrix4x4 ortho;
ortho.setOrtho(0.0f, dp_xres, dp_yres, 0.0f, -1.0f, 1.0f);
glsl_bind(UIShader_Get());
glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr());
ReapplyGfxState();
Core_Run();
// Hopefully coreState is now CORE_NEXTFRAME
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
qint64 time = timer.elapsed();
const int frameTime = (1.0f/60.0f) * 1000;
gameMutex.unlock();
if(time < frameTime)
{
glWindow->doneCurrent();
msleep(frameTime-time);
glWindow->makeCurrent();
}
gameMutex.lock();
timer.start();
}
fbo_unbind();
UIShader_Prepare();
uiTexture->Bind(0);
glViewport(0, 0, pixel_xres, pixel_yres);
ui_draw2d.Begin(DBMODE_NORMAL);
//if (g_Config.bShowTouchControls)
// DrawGamepad(ui_draw2d);
glsl_bind(UIShader_Get());
ui_draw2d.End();
ui_draw2d.Flush(UIShader_Get());
// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
#if defined(USING_GLES2)
bool hasDiscard = false; // TODO
if (hasDiscard) {
//glDiscardFramebuffer(GL_COLOR_EXT | GL_DEPTH_EXT | GL_STENCIL_EXT);
}
#endif
glWindow->swapBuffers();
glWindow->doneCurrent();
gameMutex.unlock();
}
__CtrlSetAnalog(input_state->pad_lstick_x, input_state->pad_lstick_y);
else
{
gameMutex.lock();
glWindow->makeCurrent();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
EndInputState(input_state);
time_update();
float t = (float)frames_ / 60.0f;
frames_++;
glstate.Restore();
glViewport(0, 0, pixel_xres, pixel_yres);
Matrix4x4 ortho;
ortho.setOrtho(0.0f, dp_xres, dp_yres, 0.0f, -1.0f, 1.0f);
glsl_bind(UIShader_Get());
glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr());
float alpha = t;
if (t > 1.0f) alpha = 1.0f;
float alphaText = alpha;
//if (t > 2.0f) alphaText = 3.0f - t;
glstate.Restore();
glViewport(0, 0, pixel_xres, pixel_yres);
Matrix4x4 ortho;
ortho.setOrtho(0.0f, dp_xres, dp_yres, 0.0f, -1.0f, 1.0f);
glsl_bind(UIShader_Get());
glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr());
ReapplyGfxState();
ReapplyGfxState();
Core_Run();
UIShader_Prepare();
UIBegin();
DrawBackground(alpha);
// Hopefully coreState is now CORE_NEXTFRAME
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
ui_draw2d.SetFontScale(1.5f, 1.5f);
ui_draw2d.DrawText(UBUNTU48, "PPSSPP", dp_xres / 2, dp_yres / 2 - 30, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
ui_draw2d.SetFontScale(1.0f, 1.0f);
ui_draw2d.DrawText(UBUNTU24, "Created by Henrik Rydgard", dp_xres / 2, dp_yres / 2 + 40, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
ui_draw2d.DrawText(UBUNTU24, "Free Software under GPL 2.0", dp_xres / 2, dp_yres / 2 + 70, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
ui_draw2d.DrawText(UBUNTU24, "www.ppsspp.org", dp_xres / 2, dp_yres / 2 + 130, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
UIEnd();
glsl_bind(UIShader_Get());
ui_draw2d.Flush(UIShader_Get());
glWindow->swapBuffers();
glWindow->doneCurrent();
gameMutex.unlock();
qint64 time = timer.elapsed();
const int frameTime = (1.0f/60.0f) * 1000;
if(time < frameTime)
@@ -147,41 +321,18 @@ void EmuThread::run()
timer.start();
}
fbo_unbind();
UIShader_Prepare();
uiTexture->Bind(0);
glViewport(0, 0, pixel_xres, pixel_yres);
ui_draw2d.Begin(DBMODE_NORMAL);
//if (g_Config.bShowTouchControls)
// DrawGamepad(ui_draw2d);
glsl_bind(UIShader_Get());
ui_draw2d.End();
ui_draw2d.Flush(UIShader_Get());
// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
#if defined(USING_GLES2)
bool hasDiscard = false; // TODO
if (hasDiscard) {
//glDiscardFramebuffer(GL_COLOR_EXT | GL_DEPTH_EXT | GL_STENCIL_EXT);
}
#endif
glWindow->swapBuffers();
}
glWindow->doneCurrent();
if(gameRunning)
{
stopGame();
}
}
void EmuThread::Shutdown()
{
host->PrepareShutdown();
PSP_Shutdown();
FinalShutdown();
}
void EmuThread::FinalShutdown()
@@ -189,7 +340,6 @@ void EmuThread::FinalShutdown()
host->ShutdownGL();
delete uiTexture;
uiTexture = NULL;
@@ -197,10 +347,6 @@ void EmuThread::FinalShutdown()
gl_lost_manager_shutdown();
// TODO
//The CPU should return when a game is stopped and cleanup should be done here,
//so we can restart the plugins (or load new ones) for the next game
g_State.bEmuThreadStarted = false;
//_endthreadex(0);
//return 0;
}
@@ -210,4 +356,31 @@ void EmuThread::setRunning(bool value)
running = false;
}
void EmuThread::startGame(QString filename)
{
gameMutex.lock();
needInitGame = true;
gameRunning = true;
fileToStart = filename;
gameMutex.unlock();
}
void EmuThread::stopGame()
{
Core_Stop();
gameMutex.lock();
gameRunning = false;
PSP_Shutdown();
// TODO
//The CPU should return when a game is stopped and cleanup should be done here,
//so we can restart the plugins (or load new ones) for the next game
g_State.bEmuThreadStarted = false;
frames_ = 0;
gameMutex.unlock();
}
+13 -2
View File
@@ -1,5 +1,6 @@
#pragma once
#include <QThread>
#include <QMutex>
#include "input/input_state.h"
class QtEmuGL;
@@ -7,17 +8,27 @@ class QtEmuGL;
class EmuThread : public QThread
{
public:
EmuThread() : running(false) {}
EmuThread() : running(false), gameRunning(false), needInitGame(false), frames_(0) {}
void init(InputState* inputState);
void run();
void FinalShutdown();
void setRunning(bool value);
void startGame(QString filename);
void stopGame();
QMutex gameMutex;
public slots:
void Shutdown();
private:
InputState* input_state;
bool running;
bool gameRunning;
bool needInitGame;
int frames_;
};
void EmuThread_Start(QString filename, QtEmuGL* w);
void EmuThread_Start(QtEmuGL* w);
void EmuThread_Stop();
void EmuThread_StartGame(QString filename);
void EmuThread_StopGame();
void EmuThread_LockDraw(bool value);
+22 -51
View File
@@ -1,32 +1,29 @@
TARGET = PPSSPPQt
# Ubuntu user, remove multimedia
QT += core gui opengl multimedia
QT += core gui opengl
CONFIG += mobility
MOBILITY += multimedia
include(Settings.pri)
linux {
CONFIG += mobility link_pkgconfig
MOBILITY += multimedia
}
else {
QT += multimedia
}
# Libs
symbian: LIBS += -lCore.lib -lCommon.lib -lNative.lib -lcone -leikcore -lavkon -lezlib
blackberry: LIBS += -L. -lCore -lCommon -lNative -lscreen -lsocket -lstdc++
win32: LIBS += -L. -lCore -lCommon -lNative -lwinmm -lws2_32 -lkernel32 -luser32 -lgdi32 -lshell32 -lcomctl32 -ldsound -lxinput
linux: LIBS += -L. -lCore -lCommon -lNative
linux {
LIBS += -L. -lCore -lCommon -lNative
desktop_ui {
PRE_TARGETDEPS += ./libCommon.a ./libCore.a ./libNative.a
CONFIG += link_pkgconfig
packagesExist(sdl) {
DEFINES += QT_HAS_SDL
PKGCONFIG += sdl
DEFINES += QT_HAS_SDL
PKGCONFIG += sdl
}
}
TRANSLATIONS = languages/ppsspp_en.ts \
languages/ppsspp_pl.ts
# Main
SOURCES += ../native/base/QtMain.cpp
HEADERS += ../native/base/QtMain.h
@@ -41,51 +38,25 @@ SOURCES += ../android/jni/EmuScreen.cpp \
INCLUDEPATH += .. ../Common ../native
# Temporarily only use new UI for Linux desktop
linux:!mobile_platform {
SOURCES += mainwindow.cpp \
debugger_disasm.cpp \
EmuThread.cpp\
QtHost.cpp \
qtemugl.cpp \
ctrldisasmview.cpp \
ctrlregisterlist.cpp \
controls.cpp \
qkeyedit.cpp \
gamepaddialog.cpp
HEADERS += mainwindow.h \
debugger_disasm.h \
EmuThread.h \
QtHost.h \
qtemugl.h \
ctrldisasmview.h \
ctrlregisterlist.h \
controls.h \
qkeyedit.h \
gamepaddialog.h
desktop_ui {
MOC_DIR = moc
UI_DIR = ui
SOURCES += *.cpp
HEADERS += *.h
FORMS += *.ui
RESOURCES += resources.qrc
} else {
SOURCES += ../android/jni/NativeApp.cpp
}
# Packaging
symbian {
vendorinfo = "%{\"Qtness\"}" ":\"Qtness\""
packageheader = "$${LITERAL_HASH}{\"PPSSPP\"}, (0xE0095B1D), 0, 6, 1, TYPE=SA"
deployinfo.pkg_prerules = packageheader vendorinfo
deploy.pkg_prerules = "$${LITERAL_HASH}{\"PPSSPP\"}, (0xE0095B1D), 0, 6, 1, TYPE=SA" "%{\"Qtness\"}" ":\"Qtness\""
assets.sources = ../android/assets/ui_atlas.zim ../assets/ppge_atlas.zim
assets.path = E:/PPSSPP
DEPLOYMENT += deployinfo assets
DEPLOYMENT += deploy assets
ICON = ../assets/icon.svg
# 268MB maximum
# 268MB maximum
TARGET.EPOCHEAPSIZE = 0x40000 0x10000000
TARGET.EPOCSTACKSIZE = 0x10000
}
linux:!mobile_platform {
FORMS += mainwindow.ui \
debugger_disasm.ui \
controls.ui\
gamepaddialog.ui
RESOURCES += \
resources.qrc
}
+1 -2
View File
@@ -38,8 +38,7 @@ void QtHost::ShutdownGL()
void QtHost::SetWindowTitle(const char *message)
{
// Really need a better way to deal with versions.
QString title = "PPSSPP v0.5 - " + QString::fromUtf8(message);
QString title = "PPSSPP " + QString(PPSSPP_VERSION_STR) + " - " + QString::fromUtf8(message);
mainWindow->setWindowTitle(title);
}
+3 -2
View File
@@ -1,9 +1,11 @@
DEFINES += USING_QT_UI
blackberry|symbian|contains(MEEGO_EDITION,harmattan): CONFIG += mobile_platform
unix:!blackberry:!symbian:!macx: CONFIG += linux
linux:!mobile_platform: CONFIG += desktop_ui
# Global specific
QMAKE_CXXFLAGS += -std=c++0x -Wno-unused-function -Wno-unused-variable -Wno-multichar -Wno-uninitialized -Wno-ignored-qualifiers -Wno-missing-field-initializers -Wno-unused-parameter
QMAKE_CXXFLAGS += -Wno-unused-function -Wno-unused-variable -Wno-multichar -Wno-uninitialized -Wno-ignored-qualifiers -Wno-missing-field-initializers -Wno-unused-parameter
QMAKE_CXXFLAGS += -std=c++0x -ffast-math -fno-strict-aliasing
# Arch specific
contains(QT_ARCH, i686)|contains(QT_ARCH, x86)|contains(QT_ARCH, x86_64): {
@@ -34,4 +36,3 @@ symbian: {
DEFINES += __MARM_ARMV6__
CONFIG += 4.6.3
}
+13
View File
@@ -1,6 +1,8 @@
#include "controls.h"
#include "ui_controls.h"
#include "Core/Config.h"
#include "EmuThread.h"
#include <QTimer>
Controls_ controllist[] = {
{"Edit_Start", "Start", Qt::Key_1, PAD_BUTTON_START, CTRL_START},
@@ -43,6 +45,12 @@ Controls::~Controls()
void Controls::showEvent(QShowEvent*)
{
#ifdef Q_WS_X11
// Hack to remove the X11 crash with threaded opengl when opening the first dialog
EmuThread_LockDraw(true);
QTimer::singleShot(100, this, SLOT(releaseLock()));
#endif
for(int i = 0; i < controllistCount; i++)
{
if(g_Config.iMappingMap.find(i) != g_Config.iMappingMap.end())
@@ -62,6 +70,11 @@ void Controls::showEvent(QShowEvent*)
}
}
void Controls::releaseLock()
{
EmuThread_LockDraw(false);
}
void Controls::on_buttonBox_accepted()
{
for(int i = 0; i < controllistCount; i++)
+1
View File
@@ -32,6 +32,7 @@ public:
void showEvent(QShowEvent *);
private slots:
void releaseLock();
void on_buttonBox_accepted();
private:
+61 -32
View File
@@ -2,6 +2,7 @@
#include "ui_gamepaddialog.h"
#include <QTimer>
#include "Core/Config.h"
#include "EmuThread.h"
// Input
struct GamePadInfo
@@ -15,26 +16,26 @@ struct GamePadInfo
// Initial values are PS3 controller
GamePadInfo GamepadPadMapping[] = {
{0, 14, 0, "Prev_X", "Cross"}, //A
{0, 13, 0, "Prev_O", "Circle"}, //B
{0, 15, 0, "Prev_S", "Square"}, //X
{0, 12, 0, "Prev_T", "Triangle"}, //Y
{0, 10, 0, "Prev_LT", "Left Trigger"}, //LBUMPER
{0, 11, 0, "Prev_RT", "Right Trigger"}, //RBUMPER
{0, 3, 0, "Prev_Start", "Start"}, //START
{0, 0, 0, "Prev_Select", "Select"}, //SELECT
{0, 4, 0, "Prev_Up", "Up"}, //UP
{0, 6, 0, "Prev_Down", "Down"}, //DOWN
{0, 7, 0, "Prev_Left", "Left"}, //LEFT
{0, 5, 0, "Prev_Right", "Right"}, //RIGHT
{0, 0, 0, ""}, //MENU (event)
{0, 16, 0, "Prev_Home", "Home"}, //BACK
{0, 14, 0, "Prev_X", QT_TRANSLATE_NOOP("gamepadMapping", "Cross")}, //A
{0, 13, 0, "Prev_O", QT_TRANSLATE_NOOP("gamepadMapping", "Circle")}, //B
{0, 15, 0, "Prev_S", QT_TRANSLATE_NOOP("gamepadMapping", "Square")}, //X
{0, 12, 0, "Prev_T", QT_TRANSLATE_NOOP("gamepadMapping", "Triangle")}, //Y
{0, 10, 0, "Prev_LT", QT_TRANSLATE_NOOP("gamepadMapping", "Left Trigger")}, //LBUMPER
{0, 11, 0, "Prev_RT", QT_TRANSLATE_NOOP("gamepadMapping", "Right Trigger")}, //RBUMPER
{0, 3, 0, "Prev_Start", QT_TRANSLATE_NOOP("gamepadMapping", "Start")}, //START
{0, 0, 0, "Prev_Select", QT_TRANSLATE_NOOP("gamepadMapping", "Select")}, //SELECT
{0, 4, 0, "Prev_Up", QT_TRANSLATE_NOOP("gamepadMapping", "Up")}, //UP
{0, 6, 0, "Prev_Down", QT_TRANSLATE_NOOP("gamepadMapping", "Down")}, //DOWN
{0, 7, 0, "Prev_Left", QT_TRANSLATE_NOOP("gamepadMapping", "Left")}, //LEFT
{0, 5, 0, "Prev_Right", QT_TRANSLATE_NOOP("gamepadMapping", "Right")}, //RIGHT
{0, 0, 0, ""}, //MENU (event)
{0, 16, 0, "Prev_Home", QT_TRANSLATE_NOOP("gamepadMapping", "Home")}, //BACK
// Special case for analog stick
{1, 0, -1, "Prev_ALeft", "Stick left"},
{1, 0, 1, "Prev_ARight", "Stick right"},
{1, 1, -1, "Prev_AUp", "Stick up"},
{1, 1, 1, "Prev_ADown", "Stick bottom"}
{1, 0, -1, "Prev_ALeft", QT_TRANSLATE_NOOP("gamepadMapping", "Stick left")},
{1, 0, 1, "Prev_ARight", QT_TRANSLATE_NOOP("gamepadMapping", "Stick right")},
{1, 1, -1, "Prev_AUp", QT_TRANSLATE_NOOP("gamepadMapping", "Stick up")},
{1, 1, 1, "Prev_ADown", QT_TRANSLATE_NOOP("gamepadMapping", "Stick bottom")}
};
// id for mapping in config start at offset 200 to not get over key mapping
@@ -96,13 +97,41 @@ GamePadDialog::~GamePadDialog()
delete ui;
}
void GamePadDialog::showEvent(QShowEvent *)
{
#ifdef Q_WS_X11
// Hack to remove the X11 crash with threaded opengl when opening the first dialog
EmuThread_LockDraw(true);
QTimer::singleShot(100, this, SLOT(releaseLock()));
#endif
}
void GamePadDialog::changeEvent(QEvent *event)
{
QDialog::changeEvent(event);
if (0 != event)
{
if (event->type() == QEvent::LanguageChange)
{
ui->retranslateUi(this);
on_refreshListBtn_clicked();
}
}
}
void GamePadDialog::releaseLock()
{
EmuThread_LockDraw(false);
}
void GamePadDialog::on_refreshListBtn_clicked()
{
#if QT_HAS_SDL
if(m_joystick)
{
SDL_JoystickClose(m_joystick);
ui->JoyName->setText("<b>No GamePad</b>");
ui->JoyName->setText(tr("<b>No gamepad</b>"));
m_joystick = 0;
}
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
@@ -114,7 +143,7 @@ void GamePadDialog::on_refreshListBtn_clicked()
{
QListWidgetItem* item = new QListWidgetItem();
QString padName = SDL_JoystickName(i);
if(padName == "") padName = "<b>Unknown GamePad</b>";
if(padName == "") padName = tr("<b>Unknown gamepad</b>");
item->setText(padName);
item->setData(Qt::UserRole,i);
ui->GamePadList->addItem(item);
@@ -255,7 +284,7 @@ void GamePadDialog::on_SelectPadBtn_clicked()
ui->comboPSPButton->clear();
QTreeWidgetItem* buttonItem = new QTreeWidgetItem();
buttonItem->setText(0,"Buttons");
buttonItem->setText(0,tr("Buttons"));
ui->padValues->addTopLevelItem(buttonItem);
for(int i = 0; i < SDL_JoystickNumButtons(m_joystick); i++)
@@ -269,37 +298,37 @@ void GamePadDialog::on_SelectPadBtn_clicked()
buttonItem->addChild(item);
int id = i << 8;
ui->comboPadInput->addItem("Button "+QVariant(i).toString(),GetIntFromMapping(i,0,0));
ui->comboPadInput->addItem(tr("Button %1").arg(i),GetIntFromMapping(i,0,0));
}
QTreeWidgetItem* axesItem = new QTreeWidgetItem();
axesItem->setText(0,"Axes");
axesItem->setText(0,tr("Axes"));
ui->padValues->addTopLevelItem(axesItem);
for(int i = 0; i < SDL_JoystickNumAxes(m_joystick); i++)
{
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,QVariant(i).toString()+" Neg");
item->setText(0,tr("%1 Neg").arg(i));
item->setText(1,QVariant(0).toString());
item->setData(0, Qt::UserRole,1);
item->setData(0, Qt::UserRole+1,i);
item->setData(0, Qt::UserRole+2,-1);
axesItem->addChild(item);
ui->comboPadInput->addItem("Axes "+QVariant(i).toString()+" Neg",GetIntFromMapping(i,1,-1));
ui->comboPadInput->addItem(tr("Axes %1 Neg").arg(i),GetIntFromMapping(i,1,-1));
item = new QTreeWidgetItem();
item->setText(0,QVariant(i).toString()+" Pos");
item->setText(0,tr("%1 Pos").arg(i));
item->setText(1,QVariant(0).toString());
item->setData(0, Qt::UserRole,1);
item->setData(0, Qt::UserRole+1,i);
item->setData(0, Qt::UserRole+2,1);
axesItem->addChild(item);
ui->comboPadInput->addItem("Axes "+QVariant(i).toString()+" Pos",GetIntFromMapping(i,1,1));
ui->comboPadInput->addItem(tr("Axes %1 Pos").arg(i),GetIntFromMapping(i,1,1));
}
QTreeWidgetItem* hatsItem = new QTreeWidgetItem();
hatsItem->setText(0,"Hats");
hatsItem->setText(0,tr("Hats"));
ui->padValues->addTopLevelItem(hatsItem);
for(int i = 0; i < SDL_JoystickNumHats(m_joystick); i++)
@@ -312,14 +341,14 @@ void GamePadDialog::on_SelectPadBtn_clicked()
item->setData(0, Qt::UserRole+2,0);
hatsItem->addChild(item);
ui->comboPadInput->addItem("Button "+QVariant(i).toString(),GetIntFromMapping(i,2,0));
ui->comboPadInput->addItem(tr("Button %1").arg(i),GetIntFromMapping(i,2,0));
}
for(int i = 0; i < 18; i++)
{
if(GamepadPadMapping[i].Name != "")
{
ui->comboPSPButton->addItem(GamepadPadMapping[i].Name,i);
ui->comboPSPButton->addItem(QApplication::translate("gamepadMapping", GamepadPadMapping[i].Name.toStdString().c_str()),i);
}
}
@@ -334,9 +363,9 @@ void GamePadDialog::SetViewMode()
ui->refreshListBtn->setEnabled(true);
ui->SelectPadBtn->setEnabled(true);
if(!m_joystick)
ui->JoyName->setText("<b>No GamePad</b>");
ui->JoyName->setText(tr("<b>No gamepad</b>"));
else
ui->JoyName->setText(QString("<b>Current gamepad : ")+SDL_JoystickName(m_joyId)+"</b>");
ui->JoyName->setText(tr("<b>Current gamepad: %1</b>").arg(SDL_JoystickName(m_joyId)));
#endif
}
+4
View File
@@ -23,7 +23,11 @@ public:
void SetViewMode();
void SetCalibMode();
void CalibNextButton();
protected:
void showEvent(QShowEvent *);
void changeEvent(QEvent *);
private slots:
void releaseLock();
void on_refreshListBtn_clicked();
void on_SelectPadBtn_clicked();
+634
View File
@@ -0,0 +1,634 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="en_US">
<context>
<name>Controls</name>
<message>
<location filename="../controls.ui" line="20"/>
<source>Controls</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Debugger_Disasm</name>
<message>
<location filename="../debugger_disasm.ui" line="17"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="25"/>
<source>Ctr:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="38"/>
<source>&amp;Go to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="73"/>
<source>&amp;PC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="86"/>
<source>&amp;LR</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="118"/>
<source>Tab 1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="128"/>
<source>Tab 2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="153"/>
<source>&amp;Go</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="166"/>
<source>Stop</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="179"/>
<source>Step &amp;Into</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="192"/>
<source>Step &amp;Over</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="205"/>
<source>S&amp;kip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="218"/>
<source>Next &amp;HLE</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GamePadDialog</name>
<message>
<location filename="../gamepaddialog.ui" line="14"/>
<source>Gamepad Configuration</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="22"/>
<source>GamePad List</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="46"/>
<source>Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="53"/>
<source>Select</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="62"/>
<source>Gamepad Values :</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="86"/>
<source>TextLabel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="98"/>
<source>Assign Gamepad input</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="108"/>
<source> to PSP button/axis</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="118"/>
<source>Assign</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="127"/>
<source>Press buttons on your gamePad to verify mapping :</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="134"/>
<location filename="../gamepaddialog.cpp" line="366"/>
<source>&lt;b&gt;No gamepad&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="146"/>
<source>&lt;b&gt;Unknown gamepad&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="287"/>
<source>Buttons</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="301"/>
<location filename="../gamepaddialog.cpp" line="344"/>
<source>Button %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="304"/>
<source>Axes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="310"/>
<source>%1 Neg</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="317"/>
<source>Axes %1 Neg</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="320"/>
<source>%1 Pos</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="327"/>
<source>Axes %1 Pos</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="331"/>
<source>Hats</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="368"/>
<source>&lt;b&gt;Current gamepad: %1&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="20"/>
<source>PPSSPP</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="52"/>
<source>&amp;File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="66"/>
<source>&amp;Emulation</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="79"/>
<source>Debu&amp;g</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="91"/>
<source>&amp;Options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="95"/>
<source>&amp;Log Levels</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="99"/>
<source>G3D</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="108"/>
<source>HLE</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="117"/>
<source>Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="131"/>
<source>Zoom</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="140"/>
<source>Language</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="167"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="182"/>
<source>&amp;Open...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="187"/>
<source>&amp;Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="192"/>
<source>-</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="197"/>
<source>Quickload state</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="200"/>
<source>F4</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="205"/>
<source>Quicksave state</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="208"/>
<source>F2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="213"/>
<source>&amp;Load State File...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="218"/>
<source>&amp;Save State File...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="223"/>
<source>E&amp;xit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="228"/>
<source>&amp;Run</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="231"/>
<source>F7</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="236"/>
<source>&amp;Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="239"/>
<source>F8</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="244"/>
<source>R&amp;eset</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="252"/>
<source>&amp;Interpreter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="260"/>
<source>&amp;Slightly Faster Interpreter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="268"/>
<source>&amp;Dynarec</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="276"/>
<source>Load &amp;Map File...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="284"/>
<source>&amp;Save Map File...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="292"/>
<source>&amp;Reset Symbol Table</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="300"/>
<source>&amp;Disassembly</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="303"/>
<source>Ctrl+D</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="311"/>
<source>&amp;Log Console</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="314"/>
<source>Ctrl+L</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="322"/>
<source>Memory &amp;View...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="325"/>
<source>Ctrl+M</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="330"/>
<source>Keyboard &amp;Controls</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="335"/>
<source>&amp;Toggle Full Screen</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="338"/>
<source>F12</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="346"/>
<source>&amp;Buffered Rendering</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="349"/>
<source>F5</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="357"/>
<source>&amp;Hardware Transform</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="360"/>
<source>F6</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="368"/>
<source>&amp;Linear Filtering</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="376"/>
<source>&amp;Wireframe (experimental)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="384"/>
<source>&amp;Display Raw Framebuffer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="392"/>
<source>&amp;Show Debug Statistics</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="400"/>
<source>Screen &amp;1x</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="403"/>
<source>Ctrl+1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="411"/>
<source>Screen &amp;2x</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="414"/>
<source>Ctrl+2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="422"/>
<source>Screen &amp;3x</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="425"/>
<source>Ctrl+3</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="433"/>
<source>Screen &amp;4x</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="436"/>
<source>Ctrl+4</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="444"/>
<source>&amp;Fast Memory (dynarec, unstable)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="452"/>
<source>&amp;Ignore illegal reads/writes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="457"/>
<source>&amp;Go to http://www.ppsspp.org/</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="462"/>
<source>&amp;About PPSSPP...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="467"/>
<source>&amp;Use VBO</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="475"/>
<location filename="../mainwindow.ui" line="507"/>
<location filename="../mainwindow.ui" line="539"/>
<source>Debug</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="483"/>
<location filename="../mainwindow.ui" line="515"/>
<location filename="../mainwindow.ui" line="547"/>
<source>Warning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="491"/>
<location filename="../mainwindow.ui" line="531"/>
<location filename="../mainwindow.ui" line="563"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="499"/>
<location filename="../mainwindow.ui" line="523"/>
<location filename="../mainwindow.ui" line="555"/>
<source>Info</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="568"/>
<source>GamePad Controls</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="828"/>
<source>No translations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>gamepadMapping</name>
<message>
<location filename="../gamepaddialog.cpp" line="19"/>
<source>Cross</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="20"/>
<source>Circle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="21"/>
<source>Square</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="22"/>
<source>Triangle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="23"/>
<source>Left Trigger</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="24"/>
<source>Right Trigger</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="25"/>
<source>Start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="26"/>
<source>Select</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="27"/>
<source>Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="28"/>
<source>Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="29"/>
<source>Left</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="30"/>
<source>Right</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="32"/>
<source>Home</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="35"/>
<source>Stick left</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="36"/>
<source>Stick right</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="37"/>
<source>Stick up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="38"/>
<source>Stick bottom</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
+634
View File
@@ -0,0 +1,634 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="pl_PL">
<context>
<name>Controls</name>
<message>
<location filename="../controls.ui" line="20"/>
<source>Controls</source>
<translation></translation>
</message>
</context>
<context>
<name>Debugger_Disasm</name>
<message>
<location filename="../debugger_disasm.ui" line="17"/>
<source>Dialog</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="25"/>
<source>Ctr:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="38"/>
<source>&amp;Go to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="73"/>
<source>&amp;PC</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="86"/>
<source>&amp;LR</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="118"/>
<source>Tab 1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="128"/>
<source>Tab 2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="153"/>
<source>&amp;Go</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="166"/>
<source>Stop</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="179"/>
<source>Step &amp;Into</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="192"/>
<source>Step &amp;Over</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="205"/>
<source>S&amp;kip</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../debugger_disasm.ui" line="218"/>
<source>Next &amp;HLE</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GamePadDialog</name>
<message>
<location filename="../gamepaddialog.ui" line="14"/>
<source>Gamepad Configuration</source>
<translation>Konfiguracja kontrolera</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="22"/>
<source>GamePad List</source>
<translation>Lista kontrolerów</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="46"/>
<source>Refresh</source>
<translation>Odśwież</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="53"/>
<source>Select</source>
<translation>Wybierz</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="62"/>
<source>Gamepad Values :</source>
<translation>Wartości przycisków/osi:</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="86"/>
<source>TextLabel</source>
<translation></translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="98"/>
<source>Assign Gamepad input</source>
<translation>Przypisz przycisk</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="108"/>
<source> to PSP button/axis</source>
<translation>do przycisku/osi PSP</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="118"/>
<source>Assign</source>
<translation>Przypisz</translation>
</message>
<message>
<location filename="../gamepaddialog.ui" line="127"/>
<source>Press buttons on your gamePad to verify mapping :</source>
<translation>Naciśnij przyciski na kontrolerze:</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="134"/>
<location filename="../gamepaddialog.cpp" line="366"/>
<source>&lt;b&gt;No gamepad&lt;/b&gt;</source>
<translation>&lt;b&gt;Nie wykryto pada&lt;/b&gt;</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="146"/>
<source>&lt;b&gt;Unknown gamepad&lt;/b&gt;</source>
<translation>&lt;b&gt;Nieznany pad&lt;/b&gt;</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="287"/>
<source>Buttons</source>
<translation>Przyciski</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="301"/>
<location filename="../gamepaddialog.cpp" line="344"/>
<source>Button %1</source>
<translation>Przycisk %1</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="304"/>
<source>Axes</source>
<translation>Osie</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="310"/>
<source>%1 Neg</source>
<translation>%1 zanegowany</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="317"/>
<source>Axes %1 Neg</source>
<translation>Oś %1 zanegowana</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="320"/>
<source>%1 Pos</source>
<translation>%1 pozycja</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="327"/>
<source>Axes %1 Pos</source>
<translation>Pozycja osi %1</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="331"/>
<source>Hats</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="368"/>
<source>&lt;b&gt;Current gamepad: %1&lt;/b&gt;</source>
<translation>&lt;b&gt;Wybrany pad: %1&lt;/b&gt;</translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.ui" line="20"/>
<source>PPSSPP</source>
<translation>PPSSPP</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="52"/>
<source>&amp;File</source>
<translation>&amp;Plik</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="66"/>
<source>&amp;Emulation</source>
<translation>&amp;Emulacja</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="79"/>
<source>Debu&amp;g</source>
<translation>&amp;Debugger</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="91"/>
<source>&amp;Options</source>
<translation>&amp;Opcje</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="95"/>
<source>&amp;Log Levels</source>
<translation>P&amp;oziomy logowania</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="99"/>
<source>G3D</source>
<translation>G3D</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="108"/>
<source>HLE</source>
<translation>HLE</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="117"/>
<source>Default</source>
<translation>Domyślne</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="131"/>
<source>Zoom</source>
<translation>Zoom</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="140"/>
<source>Language</source>
<translation>Język</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="167"/>
<source>&amp;Help</source>
<translation>Pomo&amp;c</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="182"/>
<source>&amp;Open...</source>
<translation>&amp;Otwórz...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="187"/>
<source>&amp;Close</source>
<translation>&amp;Zamknij</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="192"/>
<source>-</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="197"/>
<source>Quickload state</source>
<translation>Wczytaj stan</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="200"/>
<source>F4</source>
<translation>F4</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="205"/>
<source>Quicksave state</source>
<translation>Zapisz stan</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="208"/>
<source>F2</source>
<translation>F2</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="213"/>
<source>&amp;Load State File...</source>
<translation>&amp;Wczytaj plik stanu...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="218"/>
<source>&amp;Save State File...</source>
<translation>&amp;Zapisz plik stanu...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="223"/>
<source>E&amp;xit</source>
<translation>Wyj&amp;dź</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="228"/>
<source>&amp;Run</source>
<translation>&amp;Uruchom</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="231"/>
<source>F7</source>
<translation>F7</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="236"/>
<source>&amp;Pause</source>
<translation>&amp;Pauza</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="239"/>
<source>F8</source>
<translation>F8</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="244"/>
<source>R&amp;eset</source>
<translation>&amp;Reset</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="252"/>
<source>&amp;Interpreter</source>
<translation>&amp;Interpreter</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="260"/>
<source>&amp;Slightly Faster Interpreter</source>
<translation>&amp;Szybszy interpreter</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="268"/>
<source>&amp;Dynarec</source>
<translation>R&amp;ekompilacja (Dynarec)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="276"/>
<source>Load &amp;Map File...</source>
<translation>&amp;Wczytaj plik mapy...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="284"/>
<source>&amp;Save Map File...</source>
<translation>&amp;Zapisz plik mapy...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="292"/>
<source>&amp;Reset Symbol Table</source>
<translation>Zresetuj &amp;tablicę symboli</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="300"/>
<source>&amp;Disassembly</source>
<translation>&amp;Dekompiluj</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="303"/>
<source>Ctrl+D</source>
<translation>Ctrl+D</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="311"/>
<source>&amp;Log Console</source>
<translation>&amp;Konsola logowania</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="314"/>
<source>Ctrl+L</source>
<translation>Ctrl+L</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="322"/>
<source>Memory &amp;View...</source>
<translation>Widok &amp;pamięci...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="325"/>
<source>Ctrl+M</source>
<translation>Ctrl+M</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="330"/>
<source>Keyboard &amp;Controls</source>
<translation>Ustawienia &amp;klawiatury</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="335"/>
<source>&amp;Toggle Full Screen</source>
<translation>&amp;Pełny ekran</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="338"/>
<source>F12</source>
<translation>F12</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="346"/>
<source>&amp;Buffered Rendering</source>
<translation>&amp;Buffered rendering</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="349"/>
<source>F5</source>
<translation>F5</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="357"/>
<source>&amp;Hardware Transform</source>
<translation>&amp;Hardware Transform</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="360"/>
<source>F6</source>
<translation>F6</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="368"/>
<source>&amp;Linear Filtering</source>
<translation>&amp;Linear Filtering</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="376"/>
<source>&amp;Wireframe (experimental)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="384"/>
<source>&amp;Display Raw Framebuffer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.ui" line="392"/>
<source>&amp;Show Debug Statistics</source>
<translation>Pokaż &amp;statystyki emulacji</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="400"/>
<source>Screen &amp;1x</source>
<translation>&amp;1x</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="403"/>
<source>Ctrl+1</source>
<translation>Ctrl+1</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="411"/>
<source>Screen &amp;2x</source>
<translation>&amp;2x</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="414"/>
<source>Ctrl+2</source>
<translation>Ctrl+2</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="422"/>
<source>Screen &amp;3x</source>
<translation>&amp;3x</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="425"/>
<source>Ctrl+3</source>
<translation>Ctrl+3</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="433"/>
<source>Screen &amp;4x</source>
<translation>&amp;4x</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="436"/>
<source>Ctrl+4</source>
<translation>Ctrl+4</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="444"/>
<source>&amp;Fast Memory (dynarec, unstable)</source>
<translation>&amp;Fast memory (wymagany Dynarec, niestabilne)</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="452"/>
<source>&amp;Ignore illegal reads/writes</source>
<translation>&amp;Ignoruj nieprawidłowe odczyty/zapisy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="457"/>
<source>&amp;Go to http://www.ppsspp.org/</source>
<translation>&amp;Idź do http://www.ppsspp.org</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="462"/>
<source>&amp;About PPSSPP...</source>
<translation>&amp;O PPSSPP...</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="467"/>
<source>&amp;Use VBO</source>
<translation>Użyj &amp;VBO</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="475"/>
<location filename="../mainwindow.ui" line="507"/>
<location filename="../mainwindow.ui" line="539"/>
<source>Debug</source>
<translation>Debug</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="483"/>
<location filename="../mainwindow.ui" line="515"/>
<location filename="../mainwindow.ui" line="547"/>
<source>Warning</source>
<translation>Ostrzeżenia</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="491"/>
<location filename="../mainwindow.ui" line="531"/>
<location filename="../mainwindow.ui" line="563"/>
<source>Error</source>
<translation>Błędy</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="499"/>
<location filename="../mainwindow.ui" line="523"/>
<location filename="../mainwindow.ui" line="555"/>
<source>Info</source>
<translation>Info</translation>
</message>
<message>
<location filename="../mainwindow.ui" line="568"/>
<source>GamePad Controls</source>
<translation>&amp;Ustawienia pada</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="828"/>
<source>No translations</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>gamepadMapping</name>
<message>
<location filename="../gamepaddialog.cpp" line="19"/>
<source>Cross</source>
<translation>Krzyżyk</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="20"/>
<source>Circle</source>
<translation>Kółko</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="21"/>
<source>Square</source>
<translation>Kwadrat</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="22"/>
<source>Triangle</source>
<translation>Trójkąt</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="23"/>
<source>Left Trigger</source>
<translation>Lewy trigger</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="24"/>
<source>Right Trigger</source>
<translation>Prawy trigger</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="25"/>
<source>Start</source>
<translation>Start</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="26"/>
<source>Select</source>
<translation>Select</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="27"/>
<source>Up</source>
<translation>Góra</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="28"/>
<source>Down</source>
<translation>Dół</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="29"/>
<source>Left</source>
<translation>Lewo</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="30"/>
<source>Right</source>
<translation>Prawo</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="32"/>
<source>Home</source>
<translation>Klawisz Home</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="35"/>
<source>Stick left</source>
<translation>Lewo (analog)</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="36"/>
<source>Stick right</source>
<translation>Prawo (analog)</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="37"/>
<source>Stick up</source>
<translation>Góra (analog)</translation>
</message>
<message>
<location filename="../gamepaddialog.cpp" line="38"/>
<source>Stick bottom</source>
<translation>Dół (analog)</translation>
</message>
</context>
</TS>
-101
View File
@@ -1,101 +0,0 @@
#include "mainui.h"
#include <QAudioOutput>
#include <QAudioFormat>
#include "base/display.h"
#include "base/logging.h"
#include "base/timeutil.h"
#include "file/zip_read.h"
#include "base/NativeApp.h"
#include "net/resolve.h"
#include "base/display.h"
void SimulateGamepad(InputState *input) {
input->pad_lstick_x = 0;
input->pad_lstick_y = 0;
input->pad_rstick_x = 0;
input->pad_rstick_y = 0;
if (input->pad_buttons & (1<<14))
input->pad_lstick_y=1;
else if (input->pad_buttons & (1<<15))
input->pad_lstick_y=-1;
if (input->pad_buttons & (1<<16))
input->pad_lstick_x=-1;
else if (input->pad_buttons & (1<<17))
input->pad_lstick_x=1;
}
MainUI::~MainUI() {
NativeShutdownGraphics();
}
bool MainUI::event(QEvent *e)
{
QList<QTouchEvent::TouchPoint> touchPoints;
switch(e->type())
{
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
touchPoints = static_cast<QTouchEvent *>(e)->touchPoints();
foreach (const QTouchEvent::TouchPoint &touchPoint, touchPoints) {
switch (touchPoint.state()) {
case Qt::TouchPointStationary:
break;
case Qt::TouchPointPressed:
case Qt::TouchPointReleased:
input_state.pointer_down[touchPoint.id()] = (touchPoint.state() == Qt::TouchPointPressed);
case Qt::TouchPointMoved:
input_state.pointer_x[touchPoint.id()] = touchPoint.pos().x() * dpi_scale;
input_state.pointer_y[touchPoint.id()] = touchPoint.pos().y() * dpi_scale;
break;
default:
break;
}
}
break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
input_state.pointer_down[0] = (e->type() == QEvent::MouseButtonPress);
case QEvent::MouseMove:
input_state.pointer_x[0] = ((QMouseEvent*)e)->pos().x() * dpi_scale;
input_state.pointer_y[0] = ((QMouseEvent*)e)->pos().y() * dpi_scale;
break;
case QEvent::KeyPress:
for (int b = 0; b < 14; b++) {
if (((QKeyEvent*)e)->key() == buttonMappings[b])
input_state.pad_buttons |= (1<<b);
}
break;
case QEvent::KeyRelease:
for (int b = 0; b < 14; b++) {
if (((QKeyEvent*)e)->key() == buttonMappings[b])
input_state.pad_buttons &= ~(1<<b);
}
break;
default:
return QWidget::event(e);
}
e->accept();
return true;
}
void MainUI::initializeGL()
{
#ifndef USING_GLES2
glewInit();
#endif
NativeInitGraphics();
}
void MainUI::paintGL()
{
SimulateGamepad(&input_state);
UpdateInputState(&input_state);
NativeUpdate(input_state);
EndInputState(&input_state);
NativeRender();
update();
}
+106 -5
View File
@@ -48,6 +48,7 @@ MainWindow::MainWindow(QWidget *parent) :
DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS));
*/
// Update();
createLanguageMenu();
UpdateMenus();
int zoom = g_Config.iWindowZoom;
@@ -55,16 +56,16 @@ MainWindow::MainWindow(QWidget *parent) :
if (zoom > 4) zoom = 4;
SetZoom(zoom);
EmuThread_Start(w);
if (!fileToStart.isNull())
{
SetPlaying(fileToStart);
//Update();
UpdateMenus();
EmuThread_Start(fileToStart, w);
EmuThread_StartGame(fileToStart);
}
else
BrowseAndBoot();
if (!fileToStart.isNull() && stateToLoad != NULL)
SaveState::Load(stateToLoad);
@@ -195,7 +196,7 @@ void MainWindow::BrowseAndBoot(void)
{
QFileInfo info(filename);
g_Config.currentDirectory = info.absolutePath().toStdString();
EmuThread_Start(filename, w);
EmuThread_StartGame(filename);
}
}
@@ -324,7 +325,7 @@ void MainWindow::on_action_EmulationStop_triggered()
if (memoryWindow[i])
SendMessage(memoryWindow[i]->GetDlgHandle(), WM_CLOSE, 0, 0);*/
EmuThread_Stop();
EmuThread_StopGame();
SetPlaying(0);
//Update();
UpdateMenus();
@@ -485,6 +486,7 @@ void MainWindow::on_action_OptionsHardwareTransform_triggered()
void MainWindow::on_action_FileExit_triggered()
{
on_action_EmulationStop_triggered();
EmuThread_Stop();
QApplication::exit(0);
}
@@ -778,3 +780,102 @@ void MainWindow::on_action_OptionsGamePadControls_triggered()
QMessageBox::information(this,"Gamepad","You need to compile with SDL to have Gamepad support.", QMessageBox::Ok);
#endif
}
void MainWindow::on_language_changed(QAction *action)
{
if (0 != action)
{
loadLanguage(action->data().toString());
}
}
void switchTranslator(QTranslator &translator, const QString &filename)
{
qApp->removeTranslator(&translator);
if (translator.load(filename))
qApp->installTranslator(&translator);
}
void MainWindow::loadLanguage(const QString& language)
{
if (currentLanguage != language)
{
currentLanguage = language;
QLocale locale = QLocale(currentLanguage);
QLocale::setDefault(locale);
QString languageName = QLocale::languageToString(locale.language());
switchTranslator(translator, QString("languages/ppsspp_%1.qm").arg(language));
}
}
void MainWindow::createLanguageMenu()
{
QActionGroup *langGroup = new QActionGroup(ui->menuLanguage);
langGroup->setExclusive(true);
connect(langGroup, SIGNAL(triggered(QAction *)), this, SLOT(on_language_changed(QAction *)));
QString defaultLocale = QLocale::system().name();
defaultLocale.truncate(defaultLocale.lastIndexOf('_'));
languagePath = QApplication::applicationDirPath();
languagePath.append("/languages");
QDir langDir(languagePath);
QStringList fileNames = langDir.entryList(QStringList("ppsspp_*.qm"));
if (fileNames.size() == 0)
{
QAction *action = new QAction(tr("No translations"), this);
action->setCheckable(false);
action->setDisabled(true);
ui->menuLanguage->addAction(action);
langGroup->addAction(action);
}
for (int i = 0; i < fileNames.size(); ++i)
{
QString locale = fileNames[i];
locale.truncate(locale.lastIndexOf('.'));
locale.remove(0, locale.indexOf('_') + 1);
//QString language = QLocale::languageToString(QLocale(locale).language());
QString language = QLocale(locale).nativeLanguageName();
QAction *action = new QAction(language, this);
action->setCheckable(true);
action->setData(locale);
ui->menuLanguage->addAction(action);
langGroup->addAction(action);
// TODO check en as default until we save language to config
if ("en" == locale)
{
action->setChecked(true);
currentLanguage = "en";
}
}
}
void MainWindow::changeEvent(QEvent *event)
{
QMainWindow::changeEvent(event);
if (0 != event)
{
switch (event->type())
{
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
case QEvent::LocaleChange:
{
QString locale = QLocale::system().name();
locale.truncate(locale.lastIndexOf('_'));
loadLanguage(locale);
}
break;
default:
break;
}
}
}
+12
View File
@@ -2,6 +2,7 @@
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTranslator>
#include "Core/Core.h"
#include "input/input_state.h"
@@ -135,7 +136,18 @@ private slots:
void on_action_OptionsGamePadControls_triggered();
void on_language_changed(QAction *action);
private:
void loadLanguage(const QString &language);
void createLanguageMenu();
void changeEvent(QEvent *);
QTranslator translator;
QTranslator qtTranslator;
QString currentLanguage;
QString languagePath;
Ui::MainWindow *ui;
QtEmuGL* w;
+7 -1
View File
@@ -44,7 +44,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@@ -135,6 +135,11 @@
<addaction name="action_OptionsScreen3x"/>
<addaction name="action_OptionsScreen4x"/>
</widget>
<widget class="QMenu" name="menuLanguage">
<property name="title">
<string>Language</string>
</property>
</widget>
<addaction name="action_OptionsControls"/>
<addaction name="action_OptionsGamePadControls"/>
<addaction name="separator"/>
@@ -155,6 +160,7 @@
<addaction name="action_OptionsFastMemory"/>
<addaction name="action_OptionsIgnoreIllegalReadsWrites"/>
<addaction name="separator"/>
<addaction name="menuLanguage"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
+22
View File
@@ -38,6 +38,28 @@ void QtEmuGL::stop_rendering()
thread.Shutdown();
}
void QtEmuGL::start_game(QString filename)
{
thread.startGame(filename);
}
void QtEmuGL::stop_game()
{
thread.stopGame();
}
void QtEmuGL::LockDraw(bool value)
{
if(value)
{
thread.gameMutex.lock();
}
else
{
thread.gameMutex.unlock();
}
}
void QtEmuGL::resizeEvent(QResizeEvent *evt)
{
// TODO
+3
View File
@@ -16,6 +16,9 @@ public:
void start_rendering();
void stop_rendering();
void start_game(QString filename);
void stop_game();
void LockDraw(bool value);
protected:
void initializeGL();
+1 -2
View File
@@ -61,8 +61,7 @@ with the mouse.
Alternatively, a Qt-based frontend is available in the Qt/ dir.
Open PPSSPPQt.pro with Qt Creator.
Install libsdl1.2 if you want to use USB Gamepad.
For Ubuntu user (>= 12.10) :
- Remove multimedia in PPSSPP.pro on line 3
If the build has an error about finding mobility or multimedia:
- Install the package "qtmobility-dev"
Building for OSX
+2
View File
@@ -191,6 +191,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
}
}
VFSShutdown();
LogManager::Shutdown();
DialogManager::DestroyAll();
timeEndPeriod(1);
+2 -2
View File
@@ -179,8 +179,8 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,176,217,50,14
PUSHBUTTON "Cancel",IDCANCEL,230,217,50,14
LTEXT "NOTE: Currently controls are NOT configurable.",IDC_STATIC,7,7,188,10
LISTBOX IDC_LISTCONTROLS,7,19,273,184,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
LTEXT "NOTE: Currently controls are NOT configurable.\nHowever: Xbox 360 controllers are supported! Just plug one in and use it!",IDC_STATIC,7,7,188,30
LISTBOX IDC_LISTCONTROLS,7,39,273,164,LBS_SORT | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
END
+3 -3
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.ppsspp.ppsspp"
android:versionCode="5"
android:versionName="0.5" >
android:versionCode="61"
android:versionName="0.61" >
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="8"/>
@@ -26,4 +26,4 @@
</activity>
</application>
</manifest>
</manifest>
+1
View File
@@ -451,6 +451,7 @@ static const char *credits[] =
"soywiz",
"kovensky",
"raven02",
"xele",
"",
"Written in C++ for speed and portability",
"",
+77
View File
@@ -0,0 +1,77 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Compare.h"
#include "FileUtil.h"
#include <math.h>
bool CompareOutput(const std::string bootFilename)
{
std::string expect_filename = bootFilename.substr(bootFilename.length() - 4) + ".expected";
if (File::Exists(expect_filename))
{
// TODO: Do the compare here
return true;
}
else
{
fprintf(stderr, "Expectation file %s not found", expect_filename.c_str());
return false;
}
}
inline int ComparePixel(u32 pix1, u32 pix2)
{
// For now, if they're different at all except alpha, it's an error.
if ((pix1 & 0xFFFFFF) != (pix2 & 0xFFFFFF))
return 1;
return 0;
}
double CompareScreenshot(const u8 *pixels, int w, int h, int stride, const std::string screenshotFilename, std::string &error)
{
u32 *pixels32 = (u32 *) pixels;
// We assume the bitmap is the specified size, not including whatever stride.
u32 *reference = (u32 *) calloc(w * h, sizeof(u32));
FILE *bmp = fopen(screenshotFilename.c_str(), "rb");
if (bmp)
{
// The bitmap header is 14 + 40 bytes. We could validate it but the test would fail either way.
fseek(bmp, 14 + 40, SEEK_SET);
fread(reference, sizeof(u32), w * h, bmp);
fclose(bmp);
}
else
{
error = "Unable to read screenshot: " + screenshotFilename;
free(reference);
return -1.0f;
}
u32 errors = 0;
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
errors += ComparePixel(pixels32[y * stride + x], reference[y * w + x]);
}
free(reference);
return (double) errors / (double) (w * h);
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <string>
#include "Globals.h"
bool CompareOutput(std::string bootFilename);
double CompareScreenshot(const u8 *pixels, int w, int h, int stride, const std::string screenshotFilename, std::string &error);
+16 -13
View File
@@ -13,6 +13,7 @@
#include "Log.h"
#include "LogManager.h"
#include "Compare.h"
#include "StubHost.h"
#ifdef _WIN32
#include "WindowsHeadlessHost.h"
@@ -59,10 +60,14 @@ void printUsage(const char *progname, const char *reason)
HEADLESSHOST_CLASS h1;
HeadlessHost h2;
if (typeid(h1) != typeid(h2))
{
fprintf(stderr, " --graphics use the full gpu backend (slower)\n");
fprintf(stderr, " --screenshot=FILE compare against a screenshot\n");
}
fprintf(stderr, " -i use the interpreter\n");
fprintf(stderr, " -f use the fast interpreter\n");
fprintf(stderr, " -j use jit (overrides -f)\n");
fprintf(stderr, " -j use jit (default)\n");
fprintf(stderr, " -c, --compare compare with output in file.expected\n");
fprintf(stderr, "\nSee headless.txt for details.\n");
}
@@ -77,6 +82,7 @@ int main(int argc, const char* argv[])
const char *bootFilename = 0;
const char *mountIso = 0;
const char *screenshotFilename = 0;
bool readMount = false;
for (int i = 1; i < argc; i++)
@@ -91,6 +97,8 @@ int main(int argc, const char* argv[])
readMount = true;
else if (!strcmp(argv[i], "-l") || !strcmp(argv[i], "--log"))
fullLog = true;
else if (!strcmp(argv[i], "-i"))
useJit = false;
else if (!strcmp(argv[i], "-j"))
useJit = true;
else if (!strcmp(argv[i], "-f"))
@@ -99,6 +107,8 @@ int main(int argc, const char* argv[])
autoCompare = true;
else if (!strcmp(argv[i], "--graphics"))
useGraphics = true;
else if (!strncmp(argv[i], "--screenshot=", strlen("--screenshot=")) && strlen(argv[i]) > strlen("--screenshot="))
screenshotFilename = argv[i] + strlen("--screenshot=");
else if (bootFilename == 0)
bootFilename = argv[i];
else
@@ -146,7 +156,7 @@ int main(int argc, const char* argv[])
coreParameter.fileToStart = bootFilename;
coreParameter.mountIso = mountIso ? mountIso : "";
coreParameter.startPaused = false;
coreParameter.cpuCore = useJit ? CPU_JIT : (fastInterpreter ? CPU_FASTINTERPRETER : CPU_INTERPRETER);
coreParameter.cpuCore = fastInterpreter ? CPU_FASTINTERPRETER : (useJit ? CPU_JIT : CPU_INTERPRETER);
coreParameter.gpuCore = headlessHost->isGLWorking() ? GPU_GLES : GPU_NULL;
coreParameter.enableSound = false;
coreParameter.headLess = true;
@@ -174,6 +184,9 @@ int main(int argc, const char* argv[])
host->BootDone();
if (screenshotFilename != 0)
headlessHost->SetComparisonScreenshot(screenshotFilename);
coreState = CORE_RUNNING;
while (coreState == CORE_RUNNING)
{
@@ -195,17 +208,7 @@ int main(int argc, const char* argv[])
headlessHost = NULL;
if (autoCompare)
{
std::string expect_filename = std::string(bootFilename).substr(strlen(bootFilename - 4)) + ".expected";
if (File::Exists(expect_filename))
{
// TODO: Do the compare here
}
else
{
fprintf(stderr, "Expectation file %s not found", expect_filename.c_str());
}
}
CompareOutput(bootFilename);
return 0;
}
+2
View File
@@ -145,6 +145,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\native\ext\glew\glew.c" />
<ClCompile Include="Compare.cpp" />
<ClCompile Include="Headless.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
@@ -177,6 +178,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Compare.h" />
<ClInclude Include="StubHost.h" />
<ClInclude Include="WindowsHeadlessHost.h" />
</ItemGroup>
+2
View File
@@ -4,6 +4,7 @@
<ClCompile Include="Headless.cpp" />
<ClCompile Include="..\native\ext\glew\glew.c" />
<ClCompile Include="WindowsHeadlessHost.cpp" />
<ClCompile Include="Compare.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="headless.txt" />
@@ -11,5 +12,6 @@
<ItemGroup>
<ClInclude Include="StubHost.h" />
<ClInclude Include="WindowsHeadlessHost.h" />
<ClInclude Include="Compare.h" />
</ItemGroup>
</Project>
+1
View File
@@ -50,6 +50,7 @@ public:
virtual bool AttemptLoadSymbolMap() {return false;}
virtual void SendDebugOutput(const std::string &output) { printf("%s", output.c_str()); }
virtual void SetComparisonScreenshot(const std::string &filename) {}
virtual bool isGLWorking() { return false; }
};
+49
View File
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "WindowsHeadlessHost.h"
#include "Compare.h"
#include <stdio.h>
#include <windows.h>
@@ -89,6 +90,54 @@ void WindowsHeadlessHost::SendDebugOutput(const std::string &output)
OutputDebugString(output.c_str());
}
void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h)
{
// We ignore the current framebuffer parameters and just grab the full screen.
const static int FRAME_WIDTH = 512;
const static int FRAME_HEIGHT = 272;
u8 *pixels = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4];
// TODO: Maybe this code should be moved into GLES_GPU.
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
std::string error;
double errors = CompareScreenshot(pixels, FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH, comparisonScreenshot, error);
if (errors < 0)
fprintf_s(out, "%s\n", error.c_str());
if (errors > 0)
{
fprintf_s(out, "Screenshot error: %f%%\n", errors * 100.0f);
// Lazy, just read in the original header to output the failed screenshot.
u8 header[14 + 40] = {0};
FILE *bmp = fopen(comparisonScreenshot.c_str(), "rb");
if (bmp)
{
fread(&header, sizeof(header), 1, bmp);
fclose(bmp);
}
FILE *saved = fopen("__testfailure.bmp", "wb");
if (saved)
{
fwrite(&header, sizeof(header), 1, saved);
fwrite(pixels, sizeof(u32), FRAME_WIDTH * FRAME_HEIGHT, saved);
fclose(saved);
fprintf_s(out, "Actual output written to: __testfailure.bmp\n");
}
}
delete [] pixels;
}
void WindowsHeadlessHost::SetComparisonScreenshot(const std::string &filename)
{
comparisonScreenshot = filename;
}
void WindowsHeadlessHost::InitGL()
{
glOkay = false;
+3
View File
@@ -35,6 +35,8 @@ public:
virtual bool isGLWorking() { return glOkay; }
virtual void SendDebugOutput(const std::string &output);
virtual void SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h);
virtual void SetComparisonScreenshot(const std::string &filename);
private:
bool ResizeGL();
@@ -45,4 +47,5 @@ private:
HDC hDC;
HGLRC hRC;
FILE *out;
std::string comparisonScreenshot;
};
+1 -1
Submodule native updated: f22ad17d40...3caced8524.
+12 -1
View File
@@ -109,6 +109,12 @@ tests_good = [
"threads/semaphores/refer/refer",
"threads/semaphores/signal/signal",
"threads/semaphores/wait/wait",
"threads/vpl/vpl",
"threads/vpl/delete",
"threads/vpl/free",
"threads/vpl/priority",
"threads/vpl/refer",
"threads/vpl/try",
"power/power",
"umd/callbacks/umd",
"umd/wait/wait",
@@ -124,11 +130,13 @@ tests_next = [
"threads/msgpipe/msgpipe",
"threads/scheduling/scheduling",
"threads/threads/threads",
"threads/vpl/vpl",
"threads/vtimers/vtimer",
"threads/vpl/allocate",
"threads/vpl/create",
"threads/wakeup/wakeup",
"gpu/simple/simple",
"gpu/triangle/triangle",
"gpu/commands/basic",
"hle/check_not_used_uids",
"font/fonttest",
"io/cwd/cwd",
@@ -222,6 +230,8 @@ def run_tests(test_list, args):
cmdline = [PPSSPP_EXE, elf_filename]
cmdline.extend([i for i in args if i not in ['-v', '-g']])
if os.path.exists(expected_filename + ".bmp"):
cmdline.extend(["--screenshot=" + expected_filename + ".bmp", "--graphics"])
c = Command(cmdline)
c.run(TIMEOUT)
@@ -231,6 +241,7 @@ def run_tests(test_list, args):
if c.timeout:
print(output)
print("Test exceded limit of %d seconds." % TIMEOUT)
tests_failed.append(test)
tcprint("##teamcity[testFailed name='%s' message='Test timeout']" % test)
tcprint("##teamcity[testFinished name='%s']" % test)
continue