Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/GPUCommon.h
5654 views
1
#pragma once
2
3
#include <vector>
4
#include <list>
5
6
#include "ppsspp_config.h"
7
#include "Common/Common.h"
8
#include "Common/Swap.h"
9
#include "Core/MemMap.h"
10
#include "Common/MemoryUtil.h"
11
#include "GPU/GPU.h"
12
#include "GPU/Debugger/Record.h"
13
#include "GPU/Debugger/Breakpoints.h"
14
#include "GPU/GPUDefinitions.h"
15
#include "GPU/Common/GPUDebugInterface.h"
16
17
#if defined(__ANDROID__)
18
#include <atomic>
19
#endif
20
21
// X11, sigh.
22
#ifdef None
23
#undef None
24
#endif
25
26
class FramebufferManagerCommon;
27
class TextureCacheCommon;
28
class DrawEngineCommon;
29
class GraphicsContext;
30
struct PspGeListArgs;
31
struct GPUgstate;
32
class PointerWrap;
33
struct VirtualFramebuffer;
34
35
namespace Draw {
36
class DrawContext;
37
}
38
39
struct DisplayLayoutConfig;
40
41
inline bool IsTrianglePrim(GEPrimitiveType prim) {
42
// TODO: KEEP_PREVIOUS is mistakenly treated as TRIANGLE here... This isn't new.
43
//
44
// Interesting optimization, but not confident in performance:
45
// static const bool p[8] = { false, false, false, true, true, true, false, true };
46
// 10111000 = 0xB8;
47
// return (0xB8U >> (u8)prim) & 1;
48
49
return prim > GE_PRIM_LINE_STRIP && prim != GE_PRIM_RECTANGLES;
50
}
51
52
class GPUCommon : public GPUDebugInterface {
53
public:
54
// The constructor might run on the loader thread.
55
GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
56
57
// FinishInitOnMainThread runs on the main thread, of course.
58
virtual void FinishInitOnMainThread() {}
59
60
virtual ~GPUCommon() {}
61
62
Draw::DrawContext *GetDrawContext() {
63
return draw_;
64
}
65
66
virtual void DeviceLost() = 0;
67
virtual void DeviceRestore(Draw::DrawContext *draw) = 0;
68
69
virtual u32 CheckGPUFeatures() const = 0;
70
71
virtual void UpdateCmdInfo() = 0;
72
73
virtual bool IsStarted() {
74
return true;
75
}
76
virtual void Reinitialize();
77
78
virtual void BeginHostFrame(const DisplayLayoutConfig &config);
79
virtual void EndHostFrame();
80
81
void InterruptStart(int listid);
82
void InterruptEnd(int listid);
83
void SyncEnd(GPUSyncType waitType, int listid, bool wokeThreads);
84
void EnableInterrupts(bool enable) {
85
interruptsEnabled_ = enable;
86
}
87
88
virtual void CheckDisplayResized() = 0;
89
virtual void CheckConfigChanged(const DisplayLayoutConfig &config) = 0;
90
91
virtual void NotifyDisplayResized();
92
virtual void NotifyRenderResized(const DisplayLayoutConfig &config);
93
virtual void NotifyConfigChanged();
94
95
void DumpNextFrame();
96
97
virtual void PreExecuteOp(u32 op, u32 diff) {}
98
99
DLResult ProcessDLQueue();
100
101
u32 UpdateStall(int listid, u32 newstall, bool *runList);
102
u32 EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<PspGeListArgs> args, bool head, bool *runList);
103
u32 DequeueList(int listid);
104
virtual int ListSync(int listid, int mode);
105
virtual u32 DrawSync(int mode);
106
int GetStack(int index, u32 stackPtr);
107
virtual bool GetMatrix24(GEMatrixType type, u32_le *result, u32 cmdbits);
108
virtual void ResetMatrices();
109
virtual void DoState(PointerWrap &p);
110
bool BusyDrawing();
111
u32 Continue(bool *runList);
112
u32 Break(int mode);
113
114
virtual bool FramebufferDirty() = 0;
115
virtual bool FramebufferReallyDirty() = 0;
116
117
virtual void ReapplyGfxState();
118
119
// Returns true if we should split the call across GE execution.
120
// For example, a debugger is active.
121
bool ShouldSplitOverGe() const;
122
123
uint32_t SetAddrTranslation(uint32_t value) override;
124
uint32_t GetAddrTranslation() override;
125
126
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) = 0;
127
virtual void CopyDisplayToOutput(const DisplayLayoutConfig &config, bool reallyDirty) = 0;
128
virtual bool PresentedThisFrame() const = 0;
129
130
// Invalidate any cached content sourced from the specified range.
131
// If size = -1, invalidate everything.
132
virtual void InvalidateCache(u32 addr, int size, GPUInvalidationType type) = 0;
133
134
// These return true if they handled the operation enough that the actual memory operation should be skipped. Not always a clear-cut case...
135
virtual bool PerformMemoryCopy(u32 dest, u32 src, int size, GPUCopyFlag flags = GPUCopyFlag::NONE);
136
virtual bool PerformMemorySet(u32 dest, u8 v, int size);
137
138
virtual bool PerformReadbackToMemory(u32 dest, int size);
139
virtual bool PerformWriteColorFromMemory(u32 dest, int size);
140
141
virtual void PerformWriteFormattedFromMemory(u32 addr, int size, int width, GEBufferFormat format);
142
virtual bool PerformWriteStencilFromMemory(u32 dest, int size, WriteStencil flags);
143
144
virtual void ExecuteOp(u32 op, u32 diff) = 0;
145
146
void Execute_OffsetAddr(u32 op, u32 diff);
147
void Execute_Vaddr(u32 op, u32 diff);
148
void Execute_Iaddr(u32 op, u32 diff);
149
void Execute_Origin(u32 op, u32 diff);
150
void Execute_Jump(u32 op, u32 diff);
151
void Execute_BJump(u32 op, u32 diff);
152
void Execute_Call(u32 op, u32 diff);
153
void Execute_Ret(u32 op, u32 diff);
154
void Execute_End(u32 op, u32 diff);
155
156
void Execute_BoundingBox(u32 op, u32 diff);
157
158
void Execute_MorphWeight(u32 op, u32 diff);
159
160
void Execute_ImmVertexAlphaPrim(u32 op, u32 diff);
161
162
void Execute_Unknown(u32 op, u32 diff);
163
164
static int EstimatePerVertexCost();
165
166
void Flush() override;
167
168
#ifdef USE_CRT_DBG
169
#undef new
170
#endif
171
void *operator new(size_t s) {
172
return AllocateAlignedMemory(s, 16);
173
}
174
void operator delete(void *p) {
175
FreeAlignedMemory(p);
176
}
177
#ifdef USE_CRT_DBG
178
#define new DBG_NEW
179
#endif
180
181
// From GPUDebugInterface.
182
bool GetCurrentDisplayList(DisplayList &list) override;
183
bool GetCurrentDrawAsDebugVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
184
int GetCurrentPrimCount() override;
185
FramebufferManagerCommon *GetFramebufferManagerCommon() override {
186
return nullptr;
187
}
188
189
TextureCacheCommon *GetTextureCacheCommon() override {
190
return nullptr;
191
}
192
193
std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
194
std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
195
return "N/A";
196
}
197
bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
198
199
std::vector<DisplayList> ActiveDisplayLists() override;
200
void ResetListPC(int listID, u32 pc) override;
201
void ResetListStall(int listID, u32 stall) override;
202
void ResetListState(int listID, DisplayListState state) override;
203
204
GPUDebugOp DisassembleOp(u32 pc, u32 op) override;
205
std::vector<GPUDebugOp> DisassembleOpRange(u32 startpc, u32 endpc) override;
206
207
u32 GetRelativeAddress(u32 data) override;
208
u32 GetVertexAddress() override;
209
u32 GetIndexAddress() override;
210
const GPUgstate &GetGState() override;
211
void SetCmdValue(u32 op) override;
212
213
DisplayList* getList(int listid) {
214
return &dls[listid];
215
}
216
217
const std::list<int> &GetDisplayListQueue() override {
218
return dlQueue;
219
}
220
const DisplayList &GetDisplayList(int index) override {
221
return dls[index];
222
}
223
224
s64 GetListTicks(int listid) const {
225
if (listid >= 0 && listid < DisplayListMaxCount) {
226
return dls[listid].waitUntilTicks;
227
}
228
return -1;
229
}
230
231
virtual void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) const {
232
primaryInfo = reportingPrimaryInfo_;
233
fullInfo = reportingFullInfo_;
234
}
235
236
void PSPFrame();
237
238
GPURecord::Recorder *GetRecorder() override {
239
return &recorder_;
240
}
241
GPUBreakpoints *GetBreakpoints() override {
242
return &breakpoints_;
243
}
244
245
void ClearBreakNext() override;
246
void SetBreakNext(GPUDebug::BreakNext next) override;
247
void SetBreakCount(int c, bool relative = false) override;
248
GPUDebug::BreakNext GetBreakNext() const override {
249
return breakNext_;
250
}
251
int GetBreakCount() const override {
252
return breakAtCount_;
253
}
254
bool SetRestrictPrims(std::string_view rule) override;
255
std::string_view GetRestrictPrims() override {
256
return restrictPrimRule_;
257
}
258
259
int PrimsThisFrame() const override {
260
return primsThisFrame_;
261
}
262
int PrimsLastFrame() const override {
263
return primsLastFrame_;
264
}
265
266
void NotifyFlush();
267
268
protected:
269
// While debugging is active, these may block.
270
void NotifyDisplay(u32 framebuf, u32 stride, int format);
271
272
bool NeedsSlowInterpreter() const;
273
GPUDebug::NotifyResult NotifyCommand(u32 pc, GPUBreakpoints *breakpoints);
274
275
virtual void ClearCacheNextFrame() {}
276
277
virtual void CheckRenderResized(const DisplayLayoutConfig &config) {}
278
279
void SetDrawType(DrawType type, GEPrimitiveType prim) {
280
if (type != lastDraw_) {
281
// We always flush when drawing splines/beziers so no need to do so here
282
gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
283
lastDraw_ = type;
284
}
285
// Prim == RECTANGLES can cause CanUseHardwareTransform to flip, so we need to dirty.
286
// Also, culling may be affected so dirty the raster state.
287
if (IsTrianglePrim(prim) != IsTrianglePrim(lastPrim_)) {
288
Flush();
289
gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_GEOMETRYSHADER_STATE);
290
lastPrim_ = prim;
291
}
292
}
293
294
virtual void CheckDepthUsage(VirtualFramebuffer *vfb) {}
295
virtual void FastRunLoop(DisplayList &list) = 0;
296
297
bool SlowRunLoop(DisplayList &list); // Returns false on breakpoint.
298
void UpdatePC(u32 currentPC, u32 newPC);
299
void UpdateState(GPURunState state);
300
void FastLoadBoneMatrix(u32 target);
301
void FlushImm();
302
void DoBlockTransfer(u32 skipDrawReason);
303
304
// TODO: Unify this. Vulkan and OpenGL are different due to how they buffer data.
305
virtual void FinishDeferred() {}
306
307
void AdvanceVerts(u32 vertType, int count, int bytesRead) {
308
if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
309
const int indexShift = ((vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1;
310
gstate_c.indexAddr += count << indexShift;
311
} else {
312
gstate_c.vertexAddr += bytesRead;
313
}
314
}
315
316
virtual void BuildReportingInfo() = 0;
317
318
virtual void UpdateMSAALevel(Draw::DrawContext *draw) {}
319
320
enum {
321
DisplayListMaxCount = 64
322
};
323
324
DrawEngineCommon *drawEngineCommon_ = nullptr;
325
326
// TODO: These should live in GPUCommonHW.
327
FramebufferManagerCommon *framebufferManager_ = nullptr;
328
TextureCacheCommon *textureCache_ = nullptr;
329
330
bool flushOnParams_ = true;
331
332
GraphicsContext *gfxCtx_;
333
Draw::DrawContext *draw_ = nullptr;
334
335
typedef std::list<int> DisplayListQueue;
336
337
int nextListID;
338
DisplayList dls[DisplayListMaxCount];
339
DisplayList *currentList;
340
DisplayListQueue dlQueue;
341
342
bool interruptRunning = false;
343
GPURunState gpuState = GPUSTATE_RUNNING;
344
bool isbreak; // This doesn't mean debugger breakpoints.
345
u64 drawCompleteTicks;
346
u64 busyTicks;
347
348
int downcount;
349
u64 startingTicks;
350
u32 cycleLastPC;
351
int cyclesExecuted;
352
353
bool resumingFromDebugBreak_ = false;
354
bool dumpNextFrame_ = false;
355
bool dumpThisFrame_ = false;
356
bool useFastRunLoop_ = false;
357
bool interruptsEnabled_ = false;
358
bool displayResized_ = false;
359
bool renderResized_ = false;
360
bool configChanged_ = false;
361
DrawType lastDraw_ = DRAW_UNKNOWN;
362
GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
363
364
int vertexCost_ = 0;
365
366
// No idea how big this buffer needs to be.
367
enum {
368
MAX_IMMBUFFER_SIZE = 32,
369
};
370
371
TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE];
372
int immCount_ = 0;
373
GEPrimitiveType immPrim_ = GE_PRIM_INVALID;
374
uint32_t immFlags_ = 0;
375
bool immFirstSent_ = false;
376
377
uint32_t edramTranslation_ = 0x400;
378
379
// When matrix data overflows, the CPU visible values wrap and bleed between matrices.
380
// But this doesn't actually change the values used by rendering.
381
// The CPU visible values affect the GPU when list contexts are restored.
382
// Note: not maintained by all backends, here for save stating.
383
union {
384
struct {
385
u32 bone[12 * 8];
386
u32 world[12];
387
u32 view[12];
388
u32 proj[16];
389
u32 tgen[12];
390
};
391
u32 all[12 * 8 + 12 + 12 + 16 + 12];
392
} matrixVisible;
393
394
std::string reportingPrimaryInfo_;
395
std::string reportingFullInfo_;
396
397
// Debugging state
398
bool debugRecording_ = false;
399
400
GPURecord::Recorder recorder_;
401
GPUBreakpoints breakpoints_;
402
403
GPUDebug::BreakNext breakNext_ = GPUDebug::BreakNext::NONE;
404
int breakAtCount_ = -1;
405
406
int primsLastFrame_ = 0;
407
int primsThisFrame_ = 0;
408
int thisFlipNum_ = 0;
409
410
bool primAfterDraw_ = false;
411
412
uint32_t skipPcOnce_ = 0;
413
414
std::vector<std::pair<int, int>> restrictPrimRanges_;
415
std::string restrictPrimRule_;
416
417
private:
418
void DoExecuteCall(u32 target);
419
void PopDLQueue();
420
void CheckDrawSync();
421
};
422
423