Skip to content

Commit f87e13f

Browse files
authored
Merge pull request #22435 from hrydgard/softgpu-depth-swizzle
SoftGPU: Implement depth swizzle (address translation), also for CPU access
2 parents 8d0cb09 + 50ba8e4 commit f87e13f

32 files changed

Lines changed: 598 additions & 99 deletions

‎Core/MIPS/ARM/ArmCompLoadStore.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ namespace MIPSComp
284284
MIPSGPReg rt = _RT;
285285
MIPSGPReg rs = _RS;
286286
int o = op>>26;
287+
// 16-bit accesses can go through the depth layout (Memory::DepthMirrored16).
288+
if (Memory::DepthMirrorsActive() && (o == 33 || o == 37 || o == 41)) {
289+
DISABLE;
290+
}
287291
if (((op >> 29) & 1) == 0 && rt == MIPS_REG_ZERO) {
288292
// Don't load anything into $zr
289293
return;

‎Core/MIPS/ARM64/Arm64CompLoadStore.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ namespace MIPSComp {
279279
MIPSGPReg rt = _RT;
280280
MIPSGPReg rs = _RS;
281281
int o = op >> 26;
282+
// 16-bit accesses can go through the depth layout (Memory::DepthMirrored16).
283+
if (Memory::DepthMirrorsActive() && (o == 33 || o == 37 || o == 41)) {
284+
DISABLE;
285+
}
282286
if (((op >> 29) & 1) == 0 && rt == MIPS_REG_ZERO) {
283287
// Don't load anything into $zr
284288
return;

‎Core/MIPS/IR/IRNativeCommon.cpp‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,10 +280,17 @@ void IRNativeBackend::CompileIRInst(IRInst inst) {
280280
CompIR_Div(inst);
281281
break;
282282

283-
case IROp::Load8:
284-
case IROp::Load8Ext:
285283
case IROp::Load16:
286284
case IROp::Load16Ext:
285+
// 16-bit accesses can go through the depth layout (Memory::DepthMirrored16).
286+
if (Memory::DepthMirrorsActive())
287+
CompIR_Generic(inst);
288+
else
289+
CompIR_Load(inst);
290+
break;
291+
292+
case IROp::Load8:
293+
case IROp::Load8Ext:
287294
case IROp::Load32:
288295
case IROp::Load32Linked:
289296
CompIR_Load(inst);
@@ -302,8 +309,14 @@ void IRNativeBackend::CompileIRInst(IRInst inst) {
302309
CompIR_VecLoad(inst);
303310
break;
304311

305-
case IROp::Store8:
306312
case IROp::Store16:
313+
if (Memory::DepthMirrorsActive())
314+
CompIR_Generic(inst);
315+
else
316+
CompIR_Store(inst);
317+
break;
318+
319+
case IROp::Store8:
307320
case IROp::Store32:
308321
CompIR_Store(inst);
309322
break;

‎Core/MIPS/IR/IRPassSimplify.cpp‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "Common/Data/Convert/SmallDataConvert.h"
77
#include "Common/Log.h"
88
#include "Core/Config.h"
9+
#include "Core/MemMap.h"
910
#include "Core/MIPS/MIPSVFPUUtils.h"
1011
#include "Core/MIPS/IR/IRAnalysis.h"
1112
#include "Core/MIPS/IR/IRInterpreter.h"
@@ -1357,7 +1358,10 @@ bool ReduceLoads(const IRWriter &in, IRWriter &out, const IROptions &opts) {
13571358
for (int i = 0, n = (int)in.GetInstructions().size(); i < n; i++) {
13581359
IRInst inst = in.GetInstructions()[i];
13591360

1360-
if (inst.op == IROp::Load32 || inst.op == IROp::Load16 || inst.op == IROp::Load16Ext) {
1361+
// With the depth mirrors, a load's width decides whether it goes through the depth layout
1362+
// (Memory::DepthMirrored16), so 16-bit loads keep theirs, and no load becomes one.
1363+
const bool depthMirrors = Memory::DepthMirrorsActive();
1364+
if (inst.op == IROp::Load32 || ((inst.op == IROp::Load16 || inst.op == IROp::Load16Ext) && !depthMirrors)) {
13611365
int dest = IRDestGPR(GetIRMeta(inst));
13621366
for (int j = i + 1; j < n; j++) {
13631367
const IRInstMeta laterInst = GetIRMeta(in.GetInstructions()[j]);
@@ -1375,7 +1379,7 @@ bool ReduceLoads(const IRWriter &in, IRWriter &out, const IROptions &opts) {
13751379
if (mask == 0xff) {
13761380
nextSkip = j;
13771381
}
1378-
} else if ((mask & 0xffff0000) == 0 && inst.op == IROp::Load32) {
1382+
} else if ((mask & 0xffff0000) == 0 && inst.op == IROp::Load32 && !depthMirrors) {
13791383
inst.op = IROp::Load16;
13801384
if (mask == 0xffff) {
13811385
nextSkip = j;

‎Core/MIPS/x86/CompLoadStore.cpp‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ namespace MIPSComp {
302302
MIPSGPReg rs = _RS;
303303
MIPSGPReg rt = _RT;
304304
int o = op>>26;
305+
// 16-bit accesses can go through the depth layout (Memory::DepthMirrored16).
306+
if (Memory::DepthMirrorsActive() && (o == 33 || o == 37 || o == 41)) {
307+
DISABLE;
308+
}
305309
if (((op >> 29) & 1) == 0 && rt == MIPS_REG_ZERO) {
306310
// Don't load anything into $zr
307311
return;

‎Core/MemMap.cpp‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ static u8 *m_pUncachedVRAM[4];
8282
// Required for HD Remasters to work properly.
8383
// This replaces RAM_NORMAL_SIZE at runtime.
8484
u32 g_MemorySize;
85+
int g_depthTranslationIndex = DepthTranslationIndex(0x400);
86+
87+
bool DepthMirrorsActive() {
88+
return PSP_CoreParameter().gpuCore == GPUCORE_SOFTWARE;
89+
}
90+
91+
u32 DepthMirroredSlow(u32 address) {
92+
if (!DepthMirrorsActive())
93+
return address;
94+
const DepthLayout &layout = DEPTH_LAYOUTS[(address >> 22) & 1][g_depthTranslationIndex];
95+
return (address & 0x40000000) | 0x04000000 | layout.Stored(address & 0x001FFFFF);
96+
}
8597
// Used to store the PSP model on game startup.
8698
u32 g_PSPModel;
8799
u32 g_UserPartitionSize;

‎Core/MemMap.h‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "Common/CommonTypes.h"
3030
#include "Common/Swap.h"
3131
#include "Core/Opcode.h"
32+
#include "GPU/Common/DepthSwizzle.h"
3233

3334
// PPSSPP is very aggressive about trying to do memory accesses directly, for speed.
3435
// This can be a problem when debugging though, as stray memory reads and writes will
@@ -192,7 +193,25 @@ inline float ReadUnchecked_Float(const u32 address) {
192193
#endif
193194
}
194195

195-
inline u16 ReadUnchecked_U16(const u32 address) {
196+
// With the software renderer, which stores depth as the GE does, VRAM's 0x04200000 and 0x04600000 mirrors show it
197+
// through the GE's 16-bit and 32-bit color layouts (GPU/Common/DepthSwizzle.h, ppsspp-re geprobe exp88). Only 16-bit
198+
// accesses go through them: games read and write depth with nothing else. The layouts are fixed but for the EDRAM
199+
// address translation, which the software renderer keeps here as DepthTranslationIndex().
200+
extern int g_depthTranslationIndex;
201+
202+
// Whether the depth mirrors apply the layouts: only with the software renderer. Hardware renderers keep depth
203+
// plain and handle the games that need the layout their own way.
204+
bool DepthMirrorsActive();
205+
u32 DepthMirroredSlow(u32 address);
206+
207+
inline u32 DepthMirrored16(u32 address) {
208+
if ((address & 0xBFA00000) == 0x04200000)
209+
return DepthMirroredSlow(address);
210+
return address;
211+
}
212+
213+
inline u16 ReadUnchecked_U16(u32 address) {
214+
address = DepthMirrored16(address);
196215
#ifdef MASKED_PSP_MEMORY
197216
return *(u16_le *)(base + (address & MEMVIEW32_MASK));
198217
#else
@@ -233,6 +252,7 @@ inline void WriteUnchecked_Float(float data, u32 address) {
233252
}
234253

235254
inline void WriteUnchecked_U16(u16 data, u32 address) {
255+
address = DepthMirrored16(address);
236256
#ifdef MASKED_PSP_MEMORY
237257
*(u16_le *)(base + (address & MEMVIEW32_MASK)) = data;
238258
#else

‎Core/MemMapFunctions.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ u8 ReadOrException_U8(const u32 address) {
134134

135135
u16 ReadOrException_U16(const u32 address) {
136136
u16_le value = 0;
137-
ReadMemoryOrException<u16_le>(value, address);
137+
ReadMemoryOrException<u16_le>(value, DepthMirrored16(address));
138138
return (u16)value;
139139
}
140140

@@ -155,7 +155,7 @@ void WriteOrException_U8(const u8 _Data, const u32 address) {
155155
}
156156

157157
void WriteOrException_U16(const u16 _Data, const u32 address) {
158-
WriteMemoryOrException<u16_le>(address, _Data);
158+
WriteMemoryOrException<u16_le>(DepthMirrored16(address), _Data);
159159
}
160160

161161
void WriteOrException_U32(const u32 _Data, const u32 address) {

‎GPU/CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ set(GPU_SOURCES
8080
Common/DepthBufferCommon.cpp
8181
Common/DepthRaster.cpp
8282
Common/DepthRaster.h
83+
Common/DepthSwizzle.h
8384
Common/TextureShaderCommon.cpp
8485
Common/TextureShaderCommon.h
8586
Common/DepalettizeShaderCommon.cpp

‎GPU/Common/DepthSwizzle.h‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) 2012- PPSSPP Project.
2+
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, version 2.0 or later versions.
6+
7+
// This program is distributed in the hope that it will be useful,
8+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
// GNU General Public License 2.0 for more details.
11+
12+
// A copy of the GPL 2.0 should have been included with the program.
13+
// If not, see http://www.gnu.org/licenses/
14+
15+
// Official git repository and contact information can be found at
16+
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17+
18+
#pragma once
19+
20+
#include <cstdint>
21+
22+
// Where the GE stores a depth buffer in VRAM (ppsspp-re geprobe exp8-exp10, docs/ge-precision-and-depth-layout.md).
23+
// The depth pixel at linear VRAM offset L (zbuf + (y * stride + x) * 2) is stored at Stored(L): with a 32-bit
24+
// color buffer, address bits 5 to log2(T) - 1 rotate left by one (bits 9 and 10 swap at T 0), then
25+
// (T << 3) | 0x40 is XORed in (0x600 at T 0). T is sceGeEdramSetAddrTranslation's value: 0, 0x200, 0x400,
26+
// 0x800 or 0x1000. The offsets are absolute, independent of the buffer's address and stride.
27+
//
28+
// Bits 0-4 never change, so each 32-byte aligned run of 16 pixels is stored together. The CPU (and texturing)
29+
// sees the same mapping through VRAM's mirrors: an access at 0x04200000 + L goes to Stored(L) of the 16-bit
30+
// layout, at 0x04600000 + L to the 32-bit one's (exp88).
31+
struct DepthLayout {
32+
uint32_t rotMask = 0;
33+
int rotShift = 0;
34+
uint32_t xorBits = 0;
35+
36+
constexpr uint32_t Stored(uint32_t offset) const {
37+
const uint32_t f = offset & rotMask;
38+
return ((offset & ~rotMask) | (((f << 1) | (f >> rotShift)) & rotMask)) ^ xorBits;
39+
}
40+
};
41+
42+
constexpr DepthLayout GetDepthLayout(uint32_t translation, bool color32) {
43+
DepthLayout layout;
44+
if (translation == 0) {
45+
layout.xorBits = 0x600;
46+
if (color32) {
47+
layout.rotMask = 0x600;
48+
layout.rotShift = 1;
49+
}
50+
return layout;
51+
}
52+
layout.xorBits = (translation << 3) | 0x40;
53+
int top = 0;
54+
while ((2u << top) <= translation)
55+
top++;
56+
// Bits 5 to top - 1.
57+
if (color32 && top - 5 > 1) {
58+
layout.rotMask = ((1u << (top - 5)) - 1) << 5;
59+
layout.rotShift = top - 5 - 1;
60+
}
61+
return layout;
62+
}
63+
64+
// The translations as an index 0 to 4: 0, 0x200, 0x400, 0x800, 0x1000.
65+
constexpr int DepthTranslationIndex(uint32_t translation) {
66+
int index = 0;
67+
while (translation >= 0x200 && index < 4) {
68+
translation >>= 1;
69+
index++;
70+
}
71+
return index;
72+
}
73+
74+
constexpr uint32_t DepthTranslationFromIndex(int index) {
75+
return index == 0 ? 0 : 0x100 << index;
76+
}
77+
78+
// Every layout there is, by [color32][translation index].
79+
inline constexpr DepthLayout DEPTH_LAYOUTS[2][5] = {
80+
{ GetDepthLayout(0, false), GetDepthLayout(0x200, false), GetDepthLayout(0x400, false), GetDepthLayout(0x800, false), GetDepthLayout(0x1000, false) },
81+
{ GetDepthLayout(0, true), GetDepthLayout(0x200, true), GetDepthLayout(0x400, true), GetDepthLayout(0x800, true), GetDepthLayout(0x1000, true) },
82+
};
83+
84+
// A couple of exp8-exp10's measurements (TestDepthSwizzle has more).
85+
static_assert(DEPTH_LAYOUTS[0][2].Stored(0x088000) == 0x08a040, "16-bit layout at the default translation");
86+
static_assert(DEPTH_LAYOUTS[1][0].Stored(0x03171e) == 0x03111e, "32-bit layout at translation 0");

0 commit comments

Comments
 (0)