CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/GPUCommon.h
Views: 1401
1
#pragma once
2
3
#include "ppsspp_config.h"
4
#include "Common/Common.h"
5
#include "Common/MemoryUtil.h"
6
#include "GPU/GPUInterface.h"
7
#include "GPU/GPUState.h"
8
#include "GPU/Common/GPUDebugInterface.h"
9
10
#if defined(__ANDROID__)
11
#include <atomic>
12
#endif
13
14
class FramebufferManagerCommon;
15
class TextureCacheCommon;
16
class DrawEngineCommon;
17
class GraphicsContext;
18
struct VirtualFramebuffer;
19
20
namespace Draw {
21
class DrawContext;
22
}
23
24
enum DrawType {
25
DRAW_UNKNOWN,
26
DRAW_PRIM,
27
DRAW_SPLINE,
28
DRAW_BEZIER,
29
};
30
31
enum {
32
FLAG_FLUSHBEFOREONCHANGE = 2,
33
FLAG_EXECUTE = 4,
34
FLAG_EXECUTEONCHANGE = 8,
35
FLAG_READS_PC = 16,
36
FLAG_WRITES_PC = 32,
37
FLAG_DIRTYONCHANGE = 64, // NOTE: Either this or FLAG_EXECUTE*, not both!
38
};
39
40
struct TransformedVertex {
41
union {
42
struct {
43
float x, y, z, pos_w; // in case of morph, preblend during decode
44
};
45
float pos[4];
46
};
47
union {
48
struct {
49
float u; float v; float uv_w; // scaled by uscale, vscale, if there
50
};
51
float uv[3];
52
};
53
float fog;
54
union {
55
u8 color0[4]; // prelit
56
u32 color0_32;
57
};
58
union {
59
u8 color1[4]; // prelit
60
u32 color1_32;
61
};
62
63
void CopyFromWithOffset(const TransformedVertex &other, float xoff, float yoff) {
64
this->x = other.x + xoff;
65
this->y = other.y + yoff;
66
memcpy(&this->z, &other.z, sizeof(*this) - sizeof(float) * 2);
67
}
68
};
69
70
inline bool IsTrianglePrim(GEPrimitiveType prim) {
71
// TODO: KEEP_PREVIOUS is mistakenly treated as TRIANGLE here... This isn't new.
72
//
73
// Interesting optimization, but not confident in performance:
74
// static const bool p[8] = { false, false, false, true, true, true, false, true };
75
// 10111000 = 0xB8;
76
// return (0xB8U >> (u8)prim) & 1;
77
78
return prim > GE_PRIM_LINE_STRIP && prim != GE_PRIM_RECTANGLES;
79
}
80
81
82
class GPUCommon : public GPUInterface, public GPUDebugInterface {
83
public:
84
GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
85
86
Draw::DrawContext *GetDrawContext() override {
87
return draw_;
88
}
89
virtual u32 CheckGPUFeatures() const = 0;
90
91
virtual void UpdateCmdInfo() = 0;
92
93
bool IsStarted() override {
94
return true;
95
}
96
void Reinitialize() override;
97
98
void BeginHostFrame() override;
99
void EndHostFrame() override;
100
101
void InterruptStart(int listid) override;
102
void InterruptEnd(int listid) override;
103
void SyncEnd(GPUSyncType waitType, int listid, bool wokeThreads) override;
104
void EnableInterrupts(bool enable) override {
105
interruptsEnabled_ = enable;
106
}
107
108
void NotifyDisplayResized() override;
109
void NotifyRenderResized() override;
110
void NotifyConfigChanged() override;
111
112
void DumpNextFrame() override;
113
114
virtual void PreExecuteOp(u32 op, u32 diff) {}
115
116
bool InterpretList(DisplayList &list);
117
void ProcessDLQueue();
118
u32 UpdateStall(int listid, u32 newstall) override;
119
u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<PspGeListArgs> args, bool head) override;
120
u32 DequeueList(int listid) override;
121
int ListSync(int listid, int mode) override;
122
u32 DrawSync(int mode) override;
123
int GetStack(int index, u32 stackPtr) override;
124
bool GetMatrix24(GEMatrixType type, u32_le *result, u32 cmdbits) override;
125
void ResetMatrices() override;
126
void DoState(PointerWrap &p) override;
127
bool BusyDrawing() override;
128
u32 Continue() override;
129
u32 Break(int mode) override;
130
void ReapplyGfxState() override;
131
uint32_t SetAddrTranslation(uint32_t value) override;
132
uint32_t GetAddrTranslation() override;
133
134
void CopyDisplayToOutput(bool reallyDirty) override = 0;
135
bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE) override;
136
bool PerformMemorySet(u32 dest, u8 v, int size) override;
137
bool PerformReadbackToMemory(u32 dest, int size) override;
138
bool PerformWriteColorFromMemory(u32 dest, int size) override;
139
140
void PerformWriteFormattedFromMemory(u32 addr, int size, int width, GEBufferFormat format) override;
141
bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags) override;
142
143
void Execute_OffsetAddr(u32 op, u32 diff);
144
void Execute_Vaddr(u32 op, u32 diff);
145
void Execute_Iaddr(u32 op, u32 diff);
146
void Execute_Origin(u32 op, u32 diff);
147
void Execute_Jump(u32 op, u32 diff);
148
void Execute_BJump(u32 op, u32 diff);
149
void Execute_Call(u32 op, u32 diff);
150
void Execute_Ret(u32 op, u32 diff);
151
void Execute_End(u32 op, u32 diff);
152
153
void Execute_BoundingBox(u32 op, u32 diff);
154
155
void Execute_MorphWeight(u32 op, u32 diff);
156
157
void Execute_ImmVertexAlphaPrim(u32 op, u32 diff);
158
159
void Execute_Unknown(u32 op, u32 diff);
160
161
static int EstimatePerVertexCost();
162
163
// Note: Not virtual!
164
void Flush();
165
void DispatchFlush() override;
166
167
#ifdef USE_CRT_DBG
168
#undef new
169
#endif
170
void *operator new(size_t s) {
171
return AllocateAlignedMemory(s, 16);
172
}
173
void operator delete(void *p) {
174
FreeAlignedMemory(p);
175
}
176
#ifdef USE_CRT_DBG
177
#define new DBG_NEW
178
#endif
179
180
// From GPUDebugInterface.
181
bool GetCurrentDisplayList(DisplayList &list) override;
182
bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
183
184
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
185
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
186
return "N/A";
187
}
188
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
189
190
std::vector<DisplayList> ActiveDisplayLists() override;
191
void ResetListPC(int listID, u32 pc) override;
192
void ResetListStall(int listID, u32 stall) override;
193
void ResetListState(int listID, DisplayListState state) override;
194
195
GPUDebugOp DissassembleOp(u32 pc, u32 op) override;
196
std::vector<GPUDebugOp> DissassembleOpRange(u32 startpc, u32 endpc) override;
197
198
void NotifySteppingEnter() override;
199
void NotifySteppingExit() override;
200
201
u32 GetRelativeAddress(u32 data) override;
202
u32 GetVertexAddress() override;
203
u32 GetIndexAddress() override;
204
GPUgstate GetGState() override;
205
void SetCmdValue(u32 op) override;
206
207
DisplayList* getList(int listid) override {
208
return &dls[listid];
209
}
210
211
const std::list<int>& GetDisplayLists() override {
212
return dlQueue;
213
}
214
215
s64 GetListTicks(int listid) const override {
216
if (listid >= 0 && listid < DisplayListMaxCount) {
217
return dls[listid].waitTicks;
218
}
219
return -1;
220
}
221
222
void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override {
223
primaryInfo = reportingPrimaryInfo_;
224
fullInfo = reportingFullInfo_;
225
}
226
227
bool PresentedThisFrame() const override;
228
229
protected:
230
void ClearCacheNextFrame() override {}
231
232
virtual void CheckRenderResized() {}
233
234
void SetDrawType(DrawType type, GEPrimitiveType prim) {
235
if (type != lastDraw_) {
236
// We always flush when drawing splines/beziers so no need to do so here
237
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
238
lastDraw_ = type;
239
}
240
// Prim == RECTANGLES can cause CanUseHardwareTransform to flip, so we need to dirty.
241
// Also, culling may be affected so dirty the raster state.
242
if (IsTrianglePrim(prim) != IsTrianglePrim(lastPrim_)) {
243
Flush();
244
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
245
lastPrim_ = prim;
246
}
247
}
248
249
void PSPFrame() override;
250
251
virtual void CheckDepthUsage(VirtualFramebuffer *vfb) {}
252
virtual void FastRunLoop(DisplayList &list) = 0;
253
254
void SlowRunLoop(DisplayList &list);
255
void UpdatePC(u32 currentPC, u32 newPC);
256
void UpdateState(GPURunState state);
257
void FastLoadBoneMatrix(u32 target);
258
void FlushImm();
259
void DoBlockTransfer(u32 skipDrawReason);
260
261
// TODO: Unify this. Vulkan and OpenGL are different due to how they buffer data.
262
virtual void FinishDeferred() {}
263
264
void AdvanceVerts(u32 vertType, int count, int bytesRead) {
265
if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
266
int indexShift = ((vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1;
267
gstate_c.indexAddr += count << indexShift;
268
} else {
269
gstate_c.vertexAddr += bytesRead;
270
}
271
}
272
273
virtual void BuildReportingInfo() = 0;
274
275
virtual void UpdateMSAALevel(Draw::DrawContext *draw) {}
276
277
DrawEngineCommon *drawEngineCommon_ = nullptr;
278
279
// TODO: These should live in GPUCommonHW.
280
FramebufferManagerCommon *framebufferManager_ = nullptr;
281
TextureCacheCommon *textureCache_ = nullptr;
282
283
bool flushOnParams_ = true;
284
285
GraphicsContext *gfxCtx_;
286
Draw::DrawContext *draw_;
287
288
typedef std::list<int> DisplayListQueue;
289
290
int nextListID;
291
DisplayList dls[DisplayListMaxCount];
292
DisplayList *currentList;
293
DisplayListQueue dlQueue;
294
295
bool interruptRunning = false;
296
GPURunState gpuState = GPUSTATE_RUNNING;
297
bool isbreak;
298
u64 drawCompleteTicks;
299
u64 busyTicks;
300
301
int downcount;
302
u64 startingTicks;
303
u32 cycleLastPC;
304
int cyclesExecuted;
305
306
bool dumpNextFrame_ = false;
307
bool dumpThisFrame_ = false;
308
bool debugRecording_;
309
bool interruptsEnabled_;
310
bool displayResized_ = false;
311
bool renderResized_ = false;
312
bool configChanged_ = false;
313
DrawType lastDraw_ = DRAW_UNKNOWN;
314
GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
315
316
int vertexCost_ = 0;
317
318
// No idea how big this buffer needs to be.
319
enum {
320
MAX_IMMBUFFER_SIZE = 32,
321
};
322
323
TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE];
324
int immCount_ = 0;
325
GEPrimitiveType immPrim_ = GE_PRIM_INVALID;
326
uint32_t immFlags_ = 0;
327
bool immFirstSent_ = false;
328
329
uint32_t edramTranslation_ = 0x400;
330
331
// When matrix data overflows, the CPU visible values wrap and bleed between matrices.
332
// But this doesn't actually change the values used by rendering.
333
// The CPU visible values affect the GPU when list contexts are restored.
334
// Note: not maintained by all backends, here for save stating.
335
union {
336
struct {
337
u32 bone[12 * 8];
338
u32 world[12];
339
u32 view[12];
340
u32 proj[16];
341
u32 tgen[12];
342
};
343
u32 all[12 * 8 + 12 + 12 + 16 + 12];
344
} matrixVisible;
345
346
std::string reportingPrimaryInfo_;
347
std::string reportingFullInfo_;
348
349
private:
350
void DoExecuteCall(u32 target);
351
void PopDLQueue();
352
void CheckDrawSync();
353
int GetNextListIndex();
354
355
// Debug stats.
356
double timeSteppingStarted_;
357
double timeSpentStepping_;
358
};
359
360