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 #if defined(_M_SSE)
15 #include <emmintrin.h>
16 #endif
17 
18 class FramebufferManagerCommon;
19 class TextureCacheCommon;
20 class DrawEngineCommon;
21 class GraphicsContext;
22 namespace Draw {
23 	class DrawContext;
24 }
25 
26 enum DrawType {
27 	DRAW_UNKNOWN,
28 	DRAW_PRIM,
29 	DRAW_SPLINE,
30 	DRAW_BEZIER,
31 };
32 
33 enum {
34 	FLAG_FLUSHBEFORE = 1,
35 	FLAG_FLUSHBEFOREONCHANGE = 2,
36 	FLAG_EXECUTE = 4,
37 	FLAG_EXECUTEONCHANGE = 8,
38 	FLAG_READS_PC = 16,
39 	FLAG_WRITES_PC = 32,
40 	FLAG_DIRTYONCHANGE = 64,  // NOTE: Either this or FLAG_EXECUTE*, not both!
41 };
42 
43 struct TransformedVertex {
44 	union {
45 		struct {
46 			float x, y, z, fog;     // in case of morph, preblend during decode
47 		};
48 		float pos[4];
49 	};
50 	union {
51 		struct {
52 			float u; float v; float w;   // scaled by uscale, vscale, if there
53 		};
54 		float uv[3];
55 	};
56 	union {
57 		u8 color0[4];   // prelit
58 		u32 color0_32;
59 	};
60 	union {
61 		u8 color1[4];   // prelit
62 		u32 color1_32;
63 	};
64 };
65 
66 class GPUCommon : public GPUInterface, public GPUDebugInterface {
67 public:
68 	GPUCommon(GraphicsContext *gfxCtx, Draw::DrawContext *draw);
69 	virtual ~GPUCommon();
70 
GetDrawContext()71 	Draw::DrawContext *GetDrawContext() override {
72 		return draw_;
73 	}
74 	virtual void CheckGPUFeatures() = 0;
75 
76 	void UpdateCmdInfo();
77 
IsReady()78 	bool IsReady() override {
79 		return true;
80 	}
CancelReady()81 	void CancelReady() override {
82 	}
83 	void Reinitialize() override;
84 
85 	void BeginHostFrame() override;
86 	void EndHostFrame() override;
87 
88 	void InterruptStart(int listid) override;
89 	void InterruptEnd(int listid) override;
90 	void SyncEnd(GPUSyncType waitType, int listid, bool wokeThreads) override;
EnableInterrupts(bool enable)91 	void EnableInterrupts(bool enable) override {
92 		interruptsEnabled_ = enable;
93 	}
94 
95 	void Resized() override;
96 	void DumpNextFrame() override;
97 
98 	void ExecuteOp(u32 op, u32 diff) override;
99 	void PreExecuteOp(u32 op, u32 diff) override;
100 
101 	bool InterpretList(DisplayList &list) override;
102 	void ProcessDLQueue();
103 	u32  UpdateStall(int listid, u32 newstall) override;
104 	u32  EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<PspGeListArgs> args, bool head) override;
105 	u32  DequeueList(int listid) override;
106 	int  ListSync(int listid, int mode) override;
107 	u32  DrawSync(int mode) override;
108 	int  GetStack(int index, u32 stackPtr) override;
109 	void DoState(PointerWrap &p) override;
110 	bool BusyDrawing() override;
111 	u32  Continue() override;
112 	u32  Break(int mode) override;
113 	void ReapplyGfxState() override;
114 
115 	void CopyDisplayToOutput(bool reallyDirty) override = 0;
116 	void InitClear() override = 0;
117 	bool PerformMemoryCopy(u32 dest, u32 src, int size) override;
118 	bool PerformMemorySet(u32 dest, u8 v, int size) override;
119 	bool PerformMemoryDownload(u32 dest, int size) override;
120 	bool PerformMemoryUpload(u32 dest, int size) override;
121 
122 	void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
123 	void NotifyVideoUpload(u32 addr, int size, int width, int format) override;
124 	bool PerformStencilUpload(u32 dest, int size) override;
125 
126 	void Execute_OffsetAddr(u32 op, u32 diff);
127 	void Execute_Vaddr(u32 op, u32 diff);
128 	void Execute_Iaddr(u32 op, u32 diff);
129 	void Execute_Origin(u32 op, u32 diff);
130 	void Execute_Jump(u32 op, u32 diff);
131 	void Execute_JumpFast(u32 op, u32 diff);
132 	void Execute_BJump(u32 op, u32 diff);
133 	void Execute_Call(u32 op, u32 diff);
134 	void Execute_CallFast(u32 op, u32 diff);
135 	void Execute_Ret(u32 op, u32 diff);
136 	void Execute_End(u32 op, u32 diff);
137 
138 	void Execute_VertexType(u32 op, u32 diff);
139 	void Execute_VertexTypeSkinning(u32 op, u32 diff);
140 
141 	void Execute_Prim(u32 op, u32 diff);
142 	void Execute_Bezier(u32 op, u32 diff);
143 	void Execute_Spline(u32 op, u32 diff);
144 	void Execute_BoundingBox(u32 op, u32 diff);
145 	void Execute_BlockTransferStart(u32 op, u32 diff);
146 
147 	void Execute_LoadClut(u32 op, u32 diff);
148 
149 	void Execute_TexSize0(u32 op, u32 diff);
150 	void Execute_TexLevel(u32 op, u32 diff);
151 
152 	void Execute_WorldMtxNum(u32 op, u32 diff);
153 	void Execute_WorldMtxData(u32 op, u32 diff);
154 	void Execute_ViewMtxNum(u32 op, u32 diff);
155 	void Execute_ViewMtxData(u32 op, u32 diff);
156 	void Execute_ProjMtxNum(u32 op, u32 diff);
157 	void Execute_ProjMtxData(u32 op, u32 diff);
158 	void Execute_TgenMtxNum(u32 op, u32 diff);
159 	void Execute_TgenMtxData(u32 op, u32 diff);
160 	void Execute_BoneMtxNum(u32 op, u32 diff);
161 	void Execute_BoneMtxData(u32 op, u32 diff);
162 
163 	void Execute_MorphWeight(u32 op, u32 diff);
164 
165 	void Execute_ImmVertexAlphaPrim(u32 op, u32 diff);
166 
167 	void Execute_Unknown(u32 op, u32 diff);
168 
169 	int EstimatePerVertexCost();
170 
171 	// Note: Not virtual!
172 	void Flush();
173 
174 #ifdef USE_CRT_DBG
175 #undef new
176 #endif
new(size_t s)177 	void *operator new(size_t s) {
178 		return AllocateAlignedMemory(s, 16);
179 	}
delete(void * p)180 	void operator delete(void *p) {
181 		FreeAlignedMemory(p);
182 	}
183 #ifdef USE_CRT_DBG
184 #define new DBG_NEW
185 #endif
186 
187 	// From GPUDebugInterface.
188 	bool GetCurrentDisplayList(DisplayList &list) override;
189 	bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override;
190 	bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override;
191 	bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override;
192 	bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override;
193 	bool GetCurrentClut(GPUDebugBuffer &buffer) override;
194 	bool GetCurrentSimpleVertices(int count, std::vector<GPUDebugVertex> &vertices, std::vector<u16> &indices) override;
195 	bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
196 
DebugGetShaderIDs(DebugShaderType shader)197 	std::vector<std::string> DebugGetShaderIDs(DebugShaderType shader) override { return std::vector<std::string>(); };
DebugGetShaderString(std::string id,DebugShaderType shader,DebugShaderStringType stringType)198 	std::string DebugGetShaderString(std::string id, DebugShaderType shader, DebugShaderStringType stringType) override {
199 		return "N/A";
200 	}
201 	bool DescribeCodePtr(const u8 *ptr, std::string &name) override;
202 
203 	std::vector<DisplayList> ActiveDisplayLists() override;
204 	void ResetListPC(int listID, u32 pc) override;
205 	void ResetListStall(int listID, u32 stall) override;
206 	void ResetListState(int listID, DisplayListState state) override;
207 
208 	GPUDebugOp DissassembleOp(u32 pc, u32 op) override;
209 	std::vector<GPUDebugOp> DissassembleOpRange(u32 startpc, u32 endpc) override;
210 
211 	void NotifySteppingEnter() override;
212 	void NotifySteppingExit() override;
213 
214 	u32 GetRelativeAddress(u32 data) override;
215 	u32 GetVertexAddress() override;
216 	u32 GetIndexAddress() override;
217 	GPUgstate GetGState() override;
218 	void SetCmdValue(u32 op) override;
219 
UpdateUVScaleOffset()220 	void UpdateUVScaleOffset() {
221 #ifdef _M_SSE
222 		__m128i values = _mm_slli_epi32(_mm_load_si128((const __m128i *)&gstate.texscaleu), 8);
223 		_mm_storeu_si128((__m128i *)&gstate_c.uv, values);
224 #elif PPSSPP_PLATFORM(ARM_NEON)
225 		const uint32x4_t values = vshlq_n_u32(vld1q_u32(&gstate.texscaleu), 8);
226 		vst1q_u32(&gstate_c.uv, values);
227 #else
228 		gstate_c.uv.uScale = getFloat24(gstate.texscaleu);
229 		gstate_c.uv.vScale = getFloat24(gstate.texscalev);
230 		gstate_c.uv.uOff = getFloat24(gstate.texoffsetu);
231 		gstate_c.uv.vOff = getFloat24(gstate.texoffsetv);
232 #endif
233 	}
234 
getList(int listid)235 	DisplayList* getList(int listid) override {
236 		return &dls[listid];
237 	}
238 
GetDisplayLists()239 	const std::list<int>& GetDisplayLists() override {
240 		return dlQueue;
241 	}
242 	std::vector<FramebufferInfo> GetFramebufferList() override;
ClearShaderCache()243 	void ClearShaderCache() override {}
CleanupBeforeUI()244 	void CleanupBeforeUI() override {}
245 
GetListTicks(int listid)246 	s64 GetListTicks(int listid) override {
247 		if (listid >= 0 && listid < DisplayListMaxCount) {
248 			return dls[listid].waitTicks;
249 		}
250 		return -1;
251 	}
252 
253 	bool FramebufferDirty() override;
254 	bool FramebufferReallyDirty() override;
255 
256 	typedef void (GPUCommon::*CmdFunc)(u32 op, u32 diff);
257 
GetReportingInfo(std::string & primaryInfo,std::string & fullInfo)258 	void GetReportingInfo(std::string &primaryInfo, std::string &fullInfo) override {
259 		primaryInfo = reportingPrimaryInfo_;
260 		fullInfo = reportingFullInfo_;
261 	}
262 
263 protected:
264 	void DeviceLost() override;
265 	void DeviceRestore() override;
266 
SetDrawType(DrawType type,GEPrimitiveType prim)267 	void SetDrawType(DrawType type, GEPrimitiveType prim) {
268 		if (type != lastDraw_) {
269 			// We always flush when drawing splines/beziers so no need to do so here
270 			gstate_c.Dirty(DIRTY_UVSCALEOFFSET | DIRTY_VERTEXSHADER_STATE);
271 			lastDraw_ = type;
272 		}
273 		// Prim == RECTANGLES can cause CanUseHardwareTransform to flip, so we need to dirty.
274 		// Also, culling may be affected so dirty the raster state.
275 		if ((prim == GE_PRIM_RECTANGLES) != (lastPrim_ == GE_PRIM_RECTANGLES)) {
276 			Flush();
277 			gstate_c.Dirty(DIRTY_RASTER_STATE | DIRTY_VERTEXSHADER_STATE);
278 			lastPrim_ = prim;
279 		}
280 	}
281 
282 	void BeginFrame() override;
283 	void UpdateVsyncInterval(bool force);
284 
285 	virtual void FastRunLoop(DisplayList &list);
286 
287 	void SlowRunLoop(DisplayList &list);
288 	void UpdatePC(u32 currentPC, u32 newPC);
289 	void UpdateState(GPURunState state);
290 	void PopDLQueue();
291 	void CheckDrawSync();
292 	int  GetNextListIndex();
293 	virtual void FastLoadBoneMatrix(u32 target);
294 
295 	// TODO: Unify this.
FinishDeferred()296 	virtual void FinishDeferred() {}
297 
298 	void DoBlockTransfer(u32 skipDrawReason);
299 	void DoExecuteCall(u32 target);
300 
AdvanceVerts(u32 vertType,int count,int bytesRead)301 	void AdvanceVerts(u32 vertType, int count, int bytesRead) {
302 		if ((vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) {
303 			int indexShift = ((vertType & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT) - 1;
304 			gstate_c.indexAddr += count << indexShift;
305 		} else {
306 			gstate_c.vertexAddr += bytesRead;
307 		}
308 	}
309 
310 	size_t FormatGPUStatsCommon(char *buf, size_t size);
311 
312 	FramebufferManagerCommon *framebufferManager_ = nullptr;
313 	TextureCacheCommon *textureCache_ = nullptr;
314 	DrawEngineCommon *drawEngineCommon_ = nullptr;
315 	ShaderManagerCommon *shaderManager_ = nullptr;
316 
317 	GraphicsContext *gfxCtx_;
318 	Draw::DrawContext *draw_;
319 
320 	struct CommandInfo {
321 		uint64_t flags;
322 		GPUCommon::CmdFunc func;
323 	};
324 
325 	static CommandInfo cmdInfo_[256];
326 
327 	typedef std::list<int> DisplayListQueue;
328 
329 	int nextListID;
330 	DisplayList dls[DisplayListMaxCount];
331 	DisplayList *currentList;
332 	DisplayListQueue dlQueue;
333 
334 	bool interruptRunning = false;
335 	GPURunState gpuState = GPUSTATE_RUNNING;
336 	bool isbreak;
337 	u64 drawCompleteTicks;
338 	u64 busyTicks;
339 
340 	int downcount;
341 	u64 startingTicks;
342 	u32 cycleLastPC;
343 	int cyclesExecuted;
344 
345 	bool dumpNextFrame_ = false;
346 	bool dumpThisFrame_ = false;
347 	bool debugRecording_;
348 	bool interruptsEnabled_;
349 	bool resized_ = false;
350 	DrawType lastDraw_ = DRAW_UNKNOWN;
351 	GEPrimitiveType lastPrim_ = GE_PRIM_INVALID;
352 
353 	int vertexCost_ = 0;
354 
355 	// No idea how big this buffer needs to be.
356 	enum {
357 		MAX_IMMBUFFER_SIZE = 32,
358 	};
359 
360 	TransformedVertex immBuffer_[MAX_IMMBUFFER_SIZE];
361 	int immCount_ = 0;
362 	GEPrimitiveType immPrim_;
363 
364 	std::string reportingPrimaryInfo_;
365 	std::string reportingFullInfo_;
366 
367 private:
368 	void FlushImm();
369 	// Debug stats.
370 	double timeSteppingStarted_;
371 	double timeSpentStepping_;
372 	int lastVsync_ = -1;
373 };
374 
375 struct CommonCommandTableEntry {
376 	uint8_t cmd;
377 	uint8_t flags;
378 	uint64_t dirty;
379 	GPUCommon::CmdFunc func;
380 };
381 
382 extern const CommonCommandTableEntry commonCommandTable[];
383 extern size_t commonCommandTableSize;
384