Git pull
This commit is contained in:
commit
f21706bc17
|
@ -820,25 +820,25 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||||
// VFP Specific
|
// VFP Specific
|
||||||
struct VFPEnc
|
struct VFPEnc
|
||||||
{
|
{
|
||||||
u16 opc1;
|
s16 opc1;
|
||||||
u16 opc2;
|
s16 opc2;
|
||||||
};
|
};
|
||||||
// Double/single, Neon
|
// Double/single, Neon
|
||||||
const VFPEnc VFPOps[][2] = {
|
const VFPEnc VFPOps[][2] = {
|
||||||
{{0xE0, 0xA0}, {0x20, 0xD1}}, // VMLA
|
{{0xE0, 0xA0}, {0x20, 0xD1}}, // 0: VMLA
|
||||||
{{0xE0, 0xA4}, {0x22, 0xD1}}, // VMLS
|
{{0xE0, 0xA4}, {0x22, 0xD1}}, // 1: VMLS
|
||||||
{{0xE3, 0xA0}, {0x20, 0xD0}}, // VADD
|
{{0xE3, 0xA0}, {0x20, 0xD0}}, // 2: VADD
|
||||||
{{0xE3, 0xA4}, {0x22, 0xD0}}, // VSUB
|
{{0xE3, 0xA4}, {0x22, 0xD0}}, // 3: VSUB
|
||||||
{{0xE2, 0xA0}, {0x30, 0xD1}}, // VMUL
|
{{0xE2, 0xA0}, {0x30, 0xD1}}, // 4: VMUL
|
||||||
{{0xEB, 0xAC}, {0x3B, 0x30}}, // VABS
|
{{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 5: VABS(Vn(0x0) used for encoding)
|
||||||
{{0xE8, 0xA0}, { -1, -1}}, // VDIV
|
{{0xE8, 0xA0}, { -1, -1}}, // 6: VDIV
|
||||||
{{0xEB, 0xA4}, { -1, -1}}, // VNEG
|
{{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 7: VNEG(Vn(0x1) used for encoding)
|
||||||
{{0xEB, 0xAC}, { -1, -1}}, // VSQRT
|
{{0xEB, 0xAC}, { -1, -1}}, // 8: VSQRT (Vn(0x1) used for encoding)
|
||||||
{{0xED, 0xA2}, { -1, -1}}, // VCMP
|
{{0xEB, 0xA4}, { -1, -1}}, // 9: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding)
|
||||||
{{0xED, 0xAA}, { -1, -1}}, // VCMPE
|
{{0xEB, 0xAC}, { -1, -1}}, // 10: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding)
|
||||||
{{ -1, -1}, {0x3B, 0x70}}, // VABSi
|
{{ -1, -1}, {0x3B, 0x30}}, // 11: VABSi
|
||||||
};
|
};
|
||||||
const char *VFPOps[] = {
|
const char *VFPOpNames[] = {
|
||||||
"VMLA",
|
"VMLA",
|
||||||
"VMLS",
|
"VMLS",
|
||||||
"VADD",
|
"VADD",
|
||||||
|
@ -861,10 +861,10 @@ u32 ARMXEmitter::EncodeVd(ARMReg Vd)
|
||||||
ARMReg Reg = SubBase(Vd);
|
ARMReg Reg = SubBase(Vd);
|
||||||
|
|
||||||
if (quad_reg)
|
if (quad_reg)
|
||||||
((Reg & 0x10) << 18) | ((Reg & 0xF) << 12);
|
return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 12);
|
||||||
else
|
else
|
||||||
if (double_reg)
|
if (double_reg)
|
||||||
return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 16);
|
return ((Reg & 0x10) << 18) | ((Reg & 0xF) << 12);
|
||||||
else
|
else
|
||||||
return ((Reg & 0x1) << 22) | ((Reg & 0x1E) << 11);
|
return ((Reg & 0x1) << 22) | ((Reg & 0x1E) << 11);
|
||||||
}
|
}
|
||||||
|
@ -875,7 +875,7 @@ u32 ARMXEmitter::EncodeVn(ARMReg Vn)
|
||||||
|
|
||||||
ARMReg Reg = SubBase(Vn);
|
ARMReg Reg = SubBase(Vn);
|
||||||
if (quad_reg)
|
if (quad_reg)
|
||||||
((Reg & 0xF) << 16) | ((Reg & 0x10) << 3);
|
return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3);
|
||||||
else
|
else
|
||||||
if (double_reg)
|
if (double_reg)
|
||||||
return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3);
|
return ((Reg & 0xF) << 16) | ((Reg & 0x10) << 3);
|
||||||
|
@ -890,7 +890,7 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm)
|
||||||
ARMReg Reg = SubBase(Vm);
|
ARMReg Reg = SubBase(Vm);
|
||||||
|
|
||||||
if (quad_reg)
|
if (quad_reg)
|
||||||
((Reg & 0x10) << 2) | (Reg & 0xF);
|
return ((Reg & 0x10) << 2) | (Reg & 0xF);
|
||||||
else
|
else
|
||||||
if (double_reg)
|
if (double_reg)
|
||||||
return ((Reg & 0x10) << 2) | (Reg & 0xF);
|
return ((Reg & 0x10) << 2) | (Reg & 0xF);
|
||||||
|
@ -900,18 +900,31 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm)
|
||||||
void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||||
{
|
{
|
||||||
bool quad_reg = Vd >= Q0;
|
bool quad_reg = Vd >= Q0;
|
||||||
bool double_reg = Vd >= D0;
|
bool double_reg = Vd >= D0 && Vd < Q0;
|
||||||
|
|
||||||
VFPEnc enc = VFPOps[Op][quad_reg];
|
VFPEnc enc = VFPOps[Op][quad_reg];
|
||||||
if (enc.opc1 == (u16)-1 && enc.opc1 == (u16)-1)
|
if (enc.opc1 == -1 && enc.opc1 == -1)
|
||||||
_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOps[Op], quad_reg ? "NEON" : "VFP");
|
_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP");
|
||||||
u32 VdEnc = EncodeVd(Vd);
|
u32 VdEnc = EncodeVd(Vd);
|
||||||
u32 VnEnc = EncodeVn(Vn);
|
u32 VnEnc = EncodeVn(Vn);
|
||||||
u32 VmEnc = EncodeVm(Vm);
|
u32 VmEnc = EncodeVm(Vm);
|
||||||
u32 cond = quad_reg ? (0xF << 28) : condition;
|
u32 cond = quad_reg ? (0xF << 28) : condition;
|
||||||
|
|
||||||
Write32(cond | enc.opc1 | VnEnc | VdEnc | enc.opc2 | VmEnc);
|
Write32(cond | (enc.opc1 << 20) | VnEnc | VdEnc | (enc.opc2 << 4) | (quad_reg << 6) | (double_reg << 8) | VmEnc);
|
||||||
}
|
}
|
||||||
|
void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(0, Vd, Vn, Vm); }
|
||||||
|
void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); }
|
||||||
|
void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); }
|
||||||
|
void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); }
|
||||||
|
void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); }
|
||||||
|
void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(5, Vd, D0, Vm); }
|
||||||
|
void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); }
|
||||||
|
void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(7, Vd, D1, Vm); }
|
||||||
|
void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D1, Vm); }
|
||||||
|
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(9, Vd, D4, Vm); }
|
||||||
|
void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D4, Vm); }
|
||||||
|
void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(9, Vd, D5, D0); }
|
||||||
|
void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(10, Vd, D5, D0); }
|
||||||
|
|
||||||
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
|
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
|
||||||
{
|
{
|
||||||
|
@ -970,43 +983,6 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset)
|
||||||
| ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2));
|
| ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm, bool E)
|
|
||||||
{
|
|
||||||
_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(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x34 << 16) | ((Vd & 0x1E) << 11) \
|
|
||||||
| (E << 7) | (0x29 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x34 << 16) | ((Vd & 0xF) << 12) \
|
|
||||||
| (E << 7) | (0x2C << 6) | ((Vm & 0x10) << 1) | (Vm & 0xF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void ARMXEmitter::VCMP(ARMReg Vd, bool E)
|
|
||||||
{
|
|
||||||
_assert_msg_(DYNA_REC, Vd < Q0, "Passed invalid Vd to VCMP");
|
|
||||||
bool single_reg = Vd < D0;
|
|
||||||
|
|
||||||
Vd = SubBase(Vd);
|
|
||||||
|
|
||||||
if (single_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x35 << 16) | ((Vd & 0x1E) << 11) \
|
|
||||||
| (E << 7) | (0x29 << 6));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x35 << 16) | ((Vd & 0xF) << 12) \
|
|
||||||
| (E << 7) | (0x2C << 6));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARMXEmitter::VMRS_APSR() {
|
void ARMXEmitter::VMRS_APSR() {
|
||||||
Write32(condition | 0xEF10A10 | (15 << 12));
|
Write32(condition | 0xEF10A10 | (15 << 12));
|
||||||
|
@ -1018,229 +994,7 @@ void ARMXEmitter::VMSR(ARMReg Rt) {
|
||||||
Write32(condition | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10);
|
Write32(condition | (0xEE << 20) | (1 << 16) | (Rt << 12) | 0xA10);
|
||||||
}
|
}
|
||||||
|
|
||||||
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(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | ((Vn & 0x1E) << 15) \
|
|
||||||
| ((Vd & 0x1E) << 11) | (0xA << 8) | ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) \
|
|
||||||
| (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write32(condition | (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(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \
|
|
||||||
| ((Vd & 0x1E) << 11) | (0x2B << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \
|
|
||||||
| ((Vd & 0xF) << 12) | (0x2F << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// VFP and ASIMD
|
// 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(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \
|
|
||||||
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \
|
|
||||||
| ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (double_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (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(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x3 << 20) \
|
|
||||||
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \
|
|
||||||
| ((Vn & 0x1) << 7) | (1 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (double_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// VFP and ASIMD
|
|
||||||
void ARMXEmitter::VMUL(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(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x2 << 20) \
|
|
||||||
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \
|
|
||||||
| ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (double_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1C << 23) | ((Vd & 0x10) << 18) | (0x2 << 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 VMUL with Quad Reg without support!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
|
||||||
{
|
|
||||||
_assert_msg_(DYNA_REC, Vd >= S0, "Passed invalid dest register to VMLA");
|
|
||||||
_assert_msg_(DYNA_REC, Vn >= S0, "Passed invalid Vn to VMLA");
|
|
||||||
_assert_msg_(DYNA_REC, Vm >= S0, "Passed invalid Vm to VMLA");
|
|
||||||
bool single_reg = Vd < D0;
|
|
||||||
bool double_reg = Vd < Q0;
|
|
||||||
|
|
||||||
Vd = SubBase(Vd);
|
|
||||||
Vn = SubBase(Vn);
|
|
||||||
Vm = SubBase(Vm);
|
|
||||||
|
|
||||||
if (single_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1C << 23) | ((Vd & 0x1) << 22) | (0x0 << 20) \
|
|
||||||
| ((Vn & 0x1E) << 15) | ((Vd & 0x1E) << 11) | (0x5 << 9) \
|
|
||||||
| ((Vn & 0x1) << 7) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_assert_msg_(DYNA_REC, false, "VMLA: Please implement!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm)
|
|
||||||
{
|
|
||||||
_assert_msg_(DYNA_REC, Vd < Q0, "VABS doesn't currently support Quad reg");
|
|
||||||
_assert_msg_(DYNA_REC, Vd >= S0, "VABS doesn't support ARM Regs");
|
|
||||||
bool single_reg = Vd < D0;
|
|
||||||
bool double_reg = Vd < Q0;
|
|
||||||
|
|
||||||
Vd = SubBase(Vd);
|
|
||||||
Vm = SubBase(Vm);
|
|
||||||
|
|
||||||
if (single_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (0xEB << 20) | ((Vd & 0x1) << 22) | ((Vd & 0x1E) << 11) \
|
|
||||||
| (0xAC << 4) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (double_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (0xEB << 20) | ((Vd & 0x10) << 18) | ((Vd & 0xF) << 12) \
|
|
||||||
| (0xBC << 4) | ((Vm & 0x10) << 1) | (Vm & 0xF));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use VADD with Quad Reg without support!");
|
|
||||||
// XXX: TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm)
|
|
||||||
{
|
|
||||||
bool single_reg = Vd < D0;
|
|
||||||
|
|
||||||
Vd = SubBase(Vd);
|
|
||||||
Vm = SubBase(Vm);
|
|
||||||
|
|
||||||
if (single_reg)
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1D << 23) | ((Vd & 0x1) << 22) | (0x31 << 16) \
|
|
||||||
| ((Vd & 0x1E) << 11) | (0x29 << 6) | ((Vm & 0x1) << 5) | (Vm >> 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write32(condition | (0x1D << 23) | ((Vd & 0x10) << 18) | (0x31 << 16) \
|
|
||||||
| ((Vd & 0xF) << 12) | (0x2D << 6) | ((Vm & 0x10) << 2) | (Vm & 0xF));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high)
|
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high)
|
||||||
{
|
{
|
||||||
_assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg");
|
_assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg");
|
||||||
|
|
|
@ -358,6 +358,10 @@ private:
|
||||||
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
|
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
|
||||||
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
|
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
|
||||||
|
|
||||||
|
u32 EncodeVd(ARMReg Vd);
|
||||||
|
u32 EncodeVn(ARMReg Vn);
|
||||||
|
u32 EncodeVm(ARMReg Vm);
|
||||||
|
void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
|
|
||||||
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
|
||||||
|
|
||||||
|
@ -528,9 +532,11 @@ public:
|
||||||
// VFP Only
|
// VFP Only
|
||||||
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
|
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
|
||||||
void VSTR(ARMReg Src, ARMReg Base, s16 offset);
|
void VSTR(ARMReg Src, ARMReg Base, s16 offset);
|
||||||
void VCMP(ARMReg Vd, ARMReg Vm, bool E);
|
void VCMP(ARMReg Vd, ARMReg Vm);
|
||||||
|
void VCMPE(ARMReg Vd, ARMReg Vm);
|
||||||
// Compares against zero
|
// Compares against zero
|
||||||
void VCMP(ARMReg Vd, bool E);
|
void VCMP(ARMReg Vd);
|
||||||
|
void VCMPE(ARMReg Vd);
|
||||||
void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
void VSQRT(ARMReg Vd, ARMReg Vm);
|
void VSQRT(ARMReg Vd, ARMReg Vm);
|
||||||
|
|
||||||
|
@ -541,6 +547,7 @@ public:
|
||||||
void VNEG(ARMReg Vd, ARMReg Vm);
|
void VNEG(ARMReg Vd, ARMReg Vm);
|
||||||
void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
void VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
void VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
|
void VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
|
||||||
void VMOV(ARMReg Dest, ARMReg Src, bool high);
|
void VMOV(ARMReg Dest, ARMReg Src, bool high);
|
||||||
void VMOV(ARMReg Dest, ARMReg Src);
|
void VMOV(ARMReg Dest, ARMReg Src);
|
||||||
void VCVT(ARMReg Dest, ARMReg Src, int flags);
|
void VCVT(ARMReg Dest, ARMReg Src, int flags);
|
||||||
|
|
|
@ -395,7 +395,7 @@ std::string UTF16ToUTF8(const std::wstring& input)
|
||||||
std::string output;
|
std::string output;
|
||||||
output.resize(size);
|
output.resize(size);
|
||||||
|
|
||||||
if (size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr))
|
if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr))
|
||||||
output.clear();
|
output.clear();
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -408,7 +408,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input)
|
||||||
std::wstring output;
|
std::wstring output;
|
||||||
output.resize(size);
|
output.resize(size);
|
||||||
|
|
||||||
if (size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size()))
|
if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size()))
|
||||||
output.clear();
|
output.clear();
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace OGL
|
||||||
|
|
||||||
static const u32 UBO_LENGTH = 32*1024*1024;
|
static const u32 UBO_LENGTH = 32*1024*1024;
|
||||||
|
|
||||||
|
GLintptr ProgramShaderCache::s_vs_data_size;
|
||||||
|
GLintptr ProgramShaderCache::s_ps_data_size;
|
||||||
GLintptr ProgramShaderCache::s_vs_data_offset;
|
GLintptr ProgramShaderCache::s_vs_data_offset;
|
||||||
u8 *ProgramShaderCache::s_ubo_buffer;
|
u8 *ProgramShaderCache::s_ubo_buffer;
|
||||||
u32 ProgramShaderCache::s_ubo_buffer_size;
|
u32 ProgramShaderCache::s_ubo_buffer_size;
|
||||||
|
@ -169,8 +171,8 @@ void ProgramShaderCache::UploadConstants()
|
||||||
if(s_ubo_dirty) {
|
if(s_ubo_dirty) {
|
||||||
s_buffer->Alloc(s_ubo_buffer_size);
|
s_buffer->Alloc(s_ubo_buffer_size);
|
||||||
size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size);
|
size_t offset = s_buffer->Upload(s_ubo_buffer, s_ubo_buffer_size);
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_vs_data_offset);
|
glBindBufferRange(GL_UNIFORM_BUFFER, 1, s_buffer->getBuffer(), offset, s_ps_data_size);
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_ubo_buffer_size - s_vs_data_offset);
|
glBindBufferRange(GL_UNIFORM_BUFFER, 2, s_buffer->getBuffer(), offset + s_vs_data_offset, s_vs_data_size);
|
||||||
s_ubo_dirty = false;
|
s_ubo_dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,10 +390,10 @@ void ProgramShaderCache::Init(void)
|
||||||
GLint Align;
|
GLint Align;
|
||||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &Align);
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &Align);
|
||||||
|
|
||||||
GLintptr const ps_data_size = ROUND_UP(C_PENVCONST_END * sizeof(float) * 4, Align);
|
s_ps_data_size = C_PENVCONST_END * sizeof(float) * 4;
|
||||||
GLintptr const vs_data_size = ROUND_UP(C_VENVCONST_END * sizeof(float) * 4, Align);
|
s_vs_data_size = C_VENVCONST_END * sizeof(float) * 4;
|
||||||
s_vs_data_offset = ps_data_size;
|
s_vs_data_offset = ROUND_UP(s_ps_data_size, Align);
|
||||||
s_ubo_buffer_size = ps_data_size + vs_data_size;
|
s_ubo_buffer_size = ROUND_UP(s_ps_data_size, Align) + ROUND_UP(s_vs_data_size, Align);
|
||||||
|
|
||||||
// We multiply by *4*4 because we need to get down to basic machine units.
|
// We multiply by *4*4 because we need to get down to basic machine units.
|
||||||
// So multiply by four to get how many floats we have from vec4s
|
// So multiply by four to get how many floats we have from vec4s
|
||||||
|
|
|
@ -125,6 +125,8 @@ private:
|
||||||
static PCacheEntry* last_entry;
|
static PCacheEntry* last_entry;
|
||||||
static SHADERUID last_uid;
|
static SHADERUID last_uid;
|
||||||
|
|
||||||
|
static GLintptr s_vs_data_size;
|
||||||
|
static GLintptr s_ps_data_size;
|
||||||
static GLintptr s_vs_data_offset;
|
static GLintptr s_vs_data_offset;
|
||||||
static u8 *s_ubo_buffer;
|
static u8 *s_ubo_buffer;
|
||||||
static u32 s_ubo_buffer_size;
|
static u32 s_ubo_buffer_size;
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "ConfigManager.h"
|
#include "ConfigManager.h"
|
||||||
#include "VertexManager.h"
|
#include "VertexManager.h"
|
||||||
#include "SamplerCache.h"
|
#include "SamplerCache.h"
|
||||||
|
#include "StreamBuffer.h"
|
||||||
|
|
||||||
#include "main.h" // Local
|
#include "main.h" // Local
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -132,47 +133,62 @@ static std::vector<u32> s_efbCache[2][EFB_CACHE_WIDTH * EFB_CACHE_HEIGHT]; // 2
|
||||||
|
|
||||||
int GetNumMSAASamples(int MSAAMode)
|
int GetNumMSAASamples(int MSAAMode)
|
||||||
{
|
{
|
||||||
|
int samples, maxSamples;
|
||||||
switch (MSAAMode)
|
switch (MSAAMode)
|
||||||
{
|
{
|
||||||
case MULTISAMPLE_OFF:
|
case MULTISAMPLE_OFF:
|
||||||
return 1;
|
samples = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case MULTISAMPLE_2X:
|
case MULTISAMPLE_2X:
|
||||||
return 2;
|
samples = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
case MULTISAMPLE_4X:
|
case MULTISAMPLE_4X:
|
||||||
case MULTISAMPLE_CSAA_8X:
|
case MULTISAMPLE_CSAA_8X:
|
||||||
case MULTISAMPLE_CSAA_16X:
|
case MULTISAMPLE_CSAA_16X:
|
||||||
return 4;
|
samples = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
case MULTISAMPLE_8X:
|
case MULTISAMPLE_8X:
|
||||||
case MULTISAMPLE_CSAA_8XQ:
|
case MULTISAMPLE_CSAA_8XQ:
|
||||||
case MULTISAMPLE_CSAA_16XQ:
|
case MULTISAMPLE_CSAA_16XQ:
|
||||||
return 8;
|
samples = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
samples = 1;
|
||||||
}
|
}
|
||||||
|
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
|
||||||
|
|
||||||
|
if(samples <= maxSamples) return samples;
|
||||||
|
|
||||||
|
ERROR_LOG(VIDEO, "MSAA Bug: %d samples selected, but only %d supported by gpu.", samples, maxSamples);
|
||||||
|
return maxSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetNumMSAACoverageSamples(int MSAAMode)
|
int GetNumMSAACoverageSamples(int MSAAMode)
|
||||||
{
|
{
|
||||||
if (!s_bHaveCoverageMSAA)
|
int samples;
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (g_ActiveConfig.iMultisampleMode)
|
switch (g_ActiveConfig.iMultisampleMode)
|
||||||
{
|
{
|
||||||
case MULTISAMPLE_CSAA_8X:
|
case MULTISAMPLE_CSAA_8X:
|
||||||
case MULTISAMPLE_CSAA_8XQ:
|
case MULTISAMPLE_CSAA_8XQ:
|
||||||
return 8;
|
samples = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
case MULTISAMPLE_CSAA_16X:
|
case MULTISAMPLE_CSAA_16X:
|
||||||
case MULTISAMPLE_CSAA_16XQ:
|
case MULTISAMPLE_CSAA_16XQ:
|
||||||
return 16;
|
samples = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
samples = 0;
|
||||||
}
|
}
|
||||||
|
if(s_bHaveCoverageMSAA || samples == 0) return samples;
|
||||||
|
|
||||||
|
ERROR_LOG(VIDEO, "MSAA Bug: CSAA selected, but not supported by gpu.");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init functions
|
// Init functions
|
||||||
|
@ -244,9 +260,11 @@ Renderer::Renderer()
|
||||||
bSuccess = false;
|
bSuccess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GLEW_ARB_sampler_objects)
|
if (!GLEW_ARB_sampler_objects && bSuccess)
|
||||||
{
|
{
|
||||||
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_sampler_objects.");
|
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_ARB_sampler_objects."
|
||||||
|
"GPU: Does your video card support OpenGL 3.2?"
|
||||||
|
"Please report this issue, then there will be a workaround");
|
||||||
bSuccess = false;
|
bSuccess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +285,13 @@ Renderer::Renderer()
|
||||||
ERROR_LOG(VIDEO, "buggy driver detected. Disable UBO");
|
ERROR_LOG(VIDEO, "buggy driver detected. Disable UBO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if(g_Config.backend_info.bSupportsGLPinnedMemory && !strcmp(gl_vendor, "Advanced Micro Devices, Inc.")) {
|
||||||
|
g_Config.backend_info.bSupportsGLPinnedMemory = false;
|
||||||
|
ERROR_LOG(VIDEO, "some fglrx versions have broken pinned memory support, so it's disabled for fglrx");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
OSD::AddMessage(StringFromFormat("Missing Extensions: %s%s%s%s%s%s",
|
OSD::AddMessage(StringFromFormat("Missing Extensions: %s%s%s%s%s%s",
|
||||||
g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ",
|
g_ActiveConfig.backend_info.bSupportsDualSourceBlend ? "" : "DualSourceBlend ",
|
||||||
|
@ -277,13 +302,13 @@ Renderer::Renderer()
|
||||||
g_ActiveConfig.backend_info.bSupportsGLSync ? "" : "Sync "
|
g_ActiveConfig.backend_info.bSupportsGLSync ? "" : "Sync "
|
||||||
).c_str(), 5000);
|
).c_str(), 5000);
|
||||||
|
|
||||||
|
if (!bSuccess)
|
||||||
|
return; // TODO: fail
|
||||||
|
|
||||||
s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
|
s_LastMultisampleMode = g_ActiveConfig.iMultisampleMode;
|
||||||
s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
|
s_MSAASamples = GetNumMSAASamples(s_LastMultisampleMode);
|
||||||
s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
|
s_MSAACoverageSamples = GetNumMSAACoverageSamples(s_LastMultisampleMode);
|
||||||
|
|
||||||
if (!bSuccess)
|
|
||||||
return; // TODO: fail
|
|
||||||
|
|
||||||
// Decide frambuffer size
|
// Decide frambuffer size
|
||||||
s_backbuffer_width = (int)GLInterface->GetBackBufferWidth();
|
s_backbuffer_width = (int)GLInterface->GetBackBufferWidth();
|
||||||
s_backbuffer_height = (int)GLInterface->GetBackBufferHeight();
|
s_backbuffer_height = (int)GLInterface->GetBackBufferHeight();
|
||||||
|
|
|
@ -491,7 +491,9 @@ void TextureCache::DisableStage(unsigned int stage)
|
||||||
|
|
||||||
void TextureCache::SetStage ()
|
void TextureCache::SetStage ()
|
||||||
{
|
{
|
||||||
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
|
// -1 is the initial value as we don't know which testure should be bound
|
||||||
|
if(s_ActiveTexture != (u32)-1)
|
||||||
|
glActiveTexture(GL_TEXTURE0 + s_ActiveTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::SetNextStage ( unsigned int stage )
|
void TextureCache::SetNextStage ( unsigned int stage )
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "../../Plugin_VideoOGL/Src/GLUtil.h"
|
#include "../../Plugin_VideoOGL/Src/GLUtil.h"
|
||||||
#include "../../Plugin_VideoOGL/Src/RasterFont.h"
|
#include "../../Plugin_VideoOGL/Src/RasterFont.h"
|
||||||
|
#include "../../Plugin_VideoOGL/Src/ProgramShaderCache.h"
|
||||||
#include "SWRenderer.h"
|
#include "SWRenderer.h"
|
||||||
#include "SWStatistics.h"
|
#include "SWStatistics.h"
|
||||||
|
|
||||||
|
@ -30,6 +31,7 @@ static GLint uni_tex = -1;
|
||||||
static GLuint program;
|
static GLuint program;
|
||||||
|
|
||||||
// Rasterfont isn't compatible with GLES
|
// Rasterfont isn't compatible with GLES
|
||||||
|
// degasus: I think it does, but I can't test it
|
||||||
#ifndef USE_GLES
|
#ifndef USE_GLES
|
||||||
OGL::RasterFont* s_pfont = NULL;
|
OGL::RasterFont* s_pfont = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,6 +47,7 @@ void SWRenderer::Shutdown()
|
||||||
#ifndef USE_GLES
|
#ifndef USE_GLES
|
||||||
delete s_pfont;
|
delete s_pfont;
|
||||||
s_pfont = 0;
|
s_pfont = 0;
|
||||||
|
OGL::ProgramShaderCache::Shutdown();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +90,8 @@ void SWRenderer::Prepare()
|
||||||
CreateShaders();
|
CreateShaders();
|
||||||
// TODO: Enable for GLES once RasterFont supports GLES
|
// TODO: Enable for GLES once RasterFont supports GLES
|
||||||
#ifndef USE_GLES
|
#ifndef USE_GLES
|
||||||
|
// ogl rasterfont depends on ogl programshadercache
|
||||||
|
OGL::ProgramShaderCache::Init();
|
||||||
s_pfont = new OGL::RasterFont();
|
s_pfont = new OGL::RasterFont();
|
||||||
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
||||||
#endif
|
#endif
|
||||||
|
@ -103,6 +108,9 @@ void SWRenderer::RenderText(const char* pstr, int left, int top, u32 color)
|
||||||
left * 2.0f / (float)nBackbufferWidth - 1,
|
left * 2.0f / (float)nBackbufferWidth - 1,
|
||||||
1 - top * 2.0f / (float)nBackbufferHeight,
|
1 - top * 2.0f / (float)nBackbufferHeight,
|
||||||
0, nBackbufferWidth, nBackbufferHeight, color);
|
0, nBackbufferWidth, nBackbufferHeight, color);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue