1 #pragma once
2 
3 #include <thread>
4 #include <vector>
5 #include <functional>
6 #include <atomic>
7 #include <array>
8 #include "signal/Signal.h"
9 
10 #include "bitmap/Bitmap.h"
11 #include "Types.h"
12 #include "Convertible.h"
13 #include "../MailBox.h"
14 #include "../Integer64.h"
15 #include "zip/ZipArchiveWriter.h"
16 #include "zip/ZipArchiveReader.h"
17 
18 class CFrameDump;
19 class CGsPacketMetadata;
20 class CINTC;
21 
22 #define PREF_CGSHANDLER_PRESENTATION_MODE "renderer.presentationmode"
23 #define PREF_CGSHANDLER_WIDESCREEN "renderer.widescreen"
24 
25 enum GS_REGS
26 {
27 	GS_REG_PRIM = 0x00,
28 	GS_REG_RGBAQ = 0x01,
29 	GS_REG_ST = 0x02,
30 	GS_REG_UV = 0x03,
31 	GS_REG_XYZF2 = 0x04,
32 	GS_REG_XYZ2 = 0x05,
33 	GS_REG_TEX0_1 = 0x06,
34 	GS_REG_TEX0_2 = 0x07,
35 	GS_REG_CLAMP_1 = 0x08,
36 	GS_REG_CLAMP_2 = 0x09,
37 	GS_REG_FOG = 0x0A,
38 	GS_REG_XYZF3 = 0x0C,
39 	GS_REG_XYZ3 = 0x0D,
40 	GS_REG_TEX1_1 = 0x14,
41 	GS_REG_TEX1_2 = 0x15,
42 	GS_REG_TEX2_1 = 0x16,
43 	GS_REG_TEX2_2 = 0x17,
44 	GS_REG_XYOFFSET_1 = 0x18,
45 	GS_REG_XYOFFSET_2 = 0x19,
46 	GS_REG_PRMODECONT = 0x1A,
47 	GS_REG_PRMODE = 0x1B,
48 	GS_REG_TEXCLUT = 0x1C,
49 	GS_REG_MIPTBP1_1 = 0x34,
50 	GS_REG_MIPTBP1_2 = 0x35,
51 	GS_REG_MIPTBP2_1 = 0x36,
52 	GS_REG_MIPTBP2_2 = 0x37,
53 	GS_REG_TEXA = 0x3B,
54 	GS_REG_FOGCOL = 0x3D,
55 	GS_REG_TEXFLUSH = 0x3F,
56 	GS_REG_SCISSOR_1 = 0x40,
57 	GS_REG_SCISSOR_2 = 0x41,
58 	GS_REG_ALPHA_1 = 0x42,
59 	GS_REG_ALPHA_2 = 0x43,
60 	GS_REG_COLCLAMP = 0x46,
61 	GS_REG_TEST_1 = 0x47,
62 	GS_REG_TEST_2 = 0x48,
63 	GS_REG_PABE = 0x49,
64 	GS_REG_FBA_1 = 0x4A,
65 	GS_REG_FBA_2 = 0x4B,
66 	GS_REG_FRAME_1 = 0x4C,
67 	GS_REG_FRAME_2 = 0x4D,
68 	GS_REG_ZBUF_1 = 0x4E,
69 	GS_REG_ZBUF_2 = 0x4F,
70 	GS_REG_BITBLTBUF = 0x50,
71 	GS_REG_TRXPOS = 0x51,
72 	GS_REG_TRXREG = 0x52,
73 	GS_REG_TRXDIR = 0x53,
74 	GS_REG_HWREG = 0x54,
75 	GS_REG_SIGNAL = 0x60,
76 	GS_REG_FINISH = 0x61,
77 	GS_REG_LABEL = 0x62,
78 };
79 
80 class CGSHandler
81 {
82 public:
83 	enum RAMSIZE
84 	{
85 		RAMSIZE = 0x00400000,
86 	};
87 
88 	enum PRESENTATION_MODE
89 	{
90 		PRESENTATION_MODE_FILL,
91 		PRESENTATION_MODE_FIT,
92 		PRESENTATION_MODE_ORIGINAL
93 	};
94 
95 	enum PRIVATE_REGISTER
96 	{
97 		GS_PMODE = 0x12000000,
98 		GS_SMODE2 = 0x12000020,
99 		GS_DISPFB1 = 0x12000070,
100 		GS_DISPLAY1 = 0x12000080,
101 		GS_DISPFB2 = 0x12000090,
102 		GS_DISPLAY2 = 0x120000A0,
103 		GS_CSR_ALT = 0x12000400, // Used by funslower demo
104 		GS_CSR = 0x12001000,
105 		GS_IMR = 0x12001010,
106 		GS_BUSDIR = 0x12001040,
107 		GS_SIGLBLID = 0x12001080,
108 	};
109 
110 	enum
111 	{
112 		CSR_SIGNAL_EVENT = 0x0001,
113 		CSR_FINISH_EVENT = 0x0002,
114 		CSR_HSYNC_INT = 0x0004,
115 		CSR_VSYNC_INT = 0x0008,
116 		CSR_RESET = 0x0200,
117 		CSR_FIELD = 0x2000,
118 		CSR_FIFO_STATUS = 0xC000,
119 		CSR_FIFO_NEITHER = 0x0000,
120 		CSR_FIFO_EMPTY = 0x4000,
121 		CSR_FIFO_FULL = 0x8000
122 	};
123 
124 	struct PRESENTATION_PARAMS
125 	{
126 		uint32 windowWidth;
127 		uint32 windowHeight;
128 		PRESENTATION_MODE mode;
129 	};
130 
131 	struct PRESENTATION_VIEWPORT
132 	{
133 		int32 offsetX = 0;
134 		int32 offsetY = 0;
135 		int32 width = 0;
136 		int32 height = 0;
137 	};
138 
139 	enum PSM
140 	{
141 		PSMCT32 = 0x00,
142 		PSMCT24 = 0x01,
143 		PSMCT16 = 0x02,
144 		PSMCT24_UNK = 0x09, //Used by FFX (in menus)
145 		PSMCT16S = 0x0A,
146 		PSMT8 = 0x13,
147 		PSMT4 = 0x14,
148 		PSMT8H = 0x1B,
149 		PSMCT32_UNK = 0x20, //Used by movies in LotR: RotK
150 		PSMT4HL = 0x24,
151 		PSMT4HH = 0x2C,
152 		PSMZ32 = 0x30,
153 		PSMZ24 = 0x31,
154 		PSMZ16 = 0x32,
155 		PSMZ16S = 0x3A,
156 		PSM_MAX = 0x40,
157 	};
158 
159 	enum PRIM_TYPE
160 	{
161 		PRIM_POINT,
162 		PRIM_LINE,
163 		PRIM_LINESTRIP,
164 		PRIM_TRIANGLE,
165 		PRIM_TRIANGLESTRIP,
166 		PRIM_TRIANGLEFAN,
167 		PRIM_SPRITE,
168 		PRIM_INVALID,
169 	};
170 
171 	enum ALPHABLEND_ABD
172 	{
173 		ALPHABLEND_ABD_CS,
174 		ALPHABLEND_ABD_CD,
175 		ALPHABLEND_ABD_ZERO,
176 		ALPHABLEND_ABD_INVALID
177 	};
178 
179 	enum ALPHABLEND_C
180 	{
181 		ALPHABLEND_C_AS,
182 		ALPHABLEND_C_AD,
183 		ALPHABLEND_C_FIX,
184 		ALPHABLEND_C_INVALID
185 	};
186 
187 	enum DEPTH_TEST_METHOD
188 	{
189 		DEPTH_TEST_NEVER,
190 		DEPTH_TEST_ALWAYS,
191 		DEPTH_TEST_GEQUAL,
192 		DEPTH_TEST_GREATER
193 	};
194 
195 	enum ALPHA_TEST_METHOD
196 	{
197 		ALPHA_TEST_NEVER,
198 		ALPHA_TEST_ALWAYS,
199 		ALPHA_TEST_LESS,
200 		ALPHA_TEST_LEQUAL,
201 		ALPHA_TEST_EQUAL,
202 		ALPHA_TEST_GEQUAL,
203 		ALPHA_TEST_GREATER,
204 		ALPHA_TEST_NOTEQUAL,
205 		ALPHA_TEST_MAX
206 	};
207 
208 	enum ALPHA_TEST_FAIL_METHOD
209 	{
210 		ALPHA_TEST_FAIL_KEEP,
211 		ALPHA_TEST_FAIL_FBONLY,
212 		ALPHA_TEST_FAIL_ZBONLY,
213 		ALPHA_TEST_FAIL_RGBONLY
214 	};
215 
216 	enum TEX0_FUNCTION
217 	{
218 		TEX0_FUNCTION_MODULATE,
219 		TEX0_FUNCTION_DECAL,
220 		TEX0_FUNCTION_HIGHLIGHT,
221 		TEX0_FUNCTION_HIGHLIGHT2,
222 		TEX0_FUNCTION_MAX
223 	};
224 
225 	enum CLAMP_MODE
226 	{
227 		CLAMP_MODE_REPEAT,
228 		CLAMP_MODE_CLAMP,
229 		CLAMP_MODE_REGION_CLAMP,
230 		CLAMP_MODE_REGION_REPEAT,
231 		CLAMP_MODE_MAX
232 	};
233 
234 	enum REGISTER_MAX
235 	{
236 		REGISTER_MAX = 0x80
237 	};
238 
239 	//Reg 0x00
240 	struct PRIM : public convertible<uint64>
241 	{
242 		unsigned int nType : 3;
243 		unsigned int nShading : 1;
244 		unsigned int nTexture : 1;
245 		unsigned int nFog : 1;
246 		unsigned int nAlpha : 1;
247 		unsigned int nAntiAliasing : 1;
248 		unsigned int nUseUV : 1;
249 		unsigned int nContext : 1;
250 		unsigned int nUseFloat : 1;
251 		unsigned int nReserved0 : 21;
252 		uint32 nReserved1;
253 	};
254 	static_assert(sizeof(PRIM) == sizeof(uint64), "Size of PRIM struct must be 8 bytes.");
255 
256 	//Reg 0x01
257 	struct RGBAQ : public convertible<uint64>
258 	{
259 		uint8 nR;
260 		uint8 nG;
261 		uint8 nB;
262 		uint8 nA;
263 		float nQ;
264 	};
265 	static_assert(sizeof(RGBAQ) == sizeof(uint64), "Size of RGBAQ struct must be 8 bytes.");
266 
267 	//Reg 0x02
268 	struct ST : public convertible<uint64>
269 	{
270 		float nS;
271 		float nT;
272 	};
273 	static_assert(sizeof(ST) == sizeof(uint64), "Size of ST struct must be 8 bytes.");
274 
275 	//Reg 0x03
276 	struct UV : public convertible<uint64>
277 	{
278 		uint16 nU;
279 		uint16 nV;
280 		uint32 nReserved;
281 
GetUUV282 		float GetU() const
283 		{
284 			return static_cast<float>(nU & 0x3FFF) / 16.0f;
285 		}
GetVUV286 		float GetV() const
287 		{
288 			return static_cast<float>(nV & 0x3FFF) / 16.0f;
289 		}
290 	};
291 	static_assert(sizeof(UV) == sizeof(uint64), "Size of UV struct must be 8 bytes.");
292 
293 	//Reg 0x04/0x0C
294 	struct XYZF : public convertible<uint64>
295 	{
296 		unsigned int nX : 16;
297 		unsigned int nY : 16;
298 		unsigned int nZ : 24;
299 		unsigned int nF : 8;
300 
GetXXYZF301 		float GetX()
302 		{
303 			return static_cast<float>(nX) / 16.0f;
304 		}
GetYXYZF305 		float GetY()
306 		{
307 			return static_cast<float>(nY) / 16.0f;
308 		}
309 	};
310 	static_assert(sizeof(XYZF) == sizeof(uint64), "Size of XYZF struct must be 8 bytes.");
311 
312 	//Reg 0x05/0x0D
313 	struct XYZ : public convertible<uint64>
314 	{
315 		unsigned int nX : 16;
316 		unsigned int nY : 16;
317 		uint32 nZ;
318 
GetXXYZ319 		float GetX()
320 		{
321 			return static_cast<float>(nX) / 16.0f;
322 		}
GetYXYZ323 		float GetY()
324 		{
325 			return static_cast<float>(nY) / 16.0f;
326 		}
GetZXYZ327 		float GetZ()
328 		{
329 			return static_cast<float>(nZ);
330 		}
331 	};
332 	static_assert(sizeof(XYZ) == sizeof(uint64), "Size of XYZ struct must be 8 bytes.");
333 
334 	//Reg 0x06/0x07
335 	struct TEX0 : public convertible<uint64>
336 	{
337 		unsigned int nBufPtr : 14;
338 		unsigned int nBufWidth : 6;
339 		unsigned int nPsm : 6;
340 		unsigned int nWidth : 4;
341 		unsigned int nPad0 : 2;
342 		unsigned int nPad1 : 2;
343 		unsigned int nColorComp : 1;
344 		unsigned int nFunction : 2;
345 		unsigned int nCBP : 14;
346 		unsigned int nCPSM : 4;
347 		unsigned int nCSM : 1;
348 		unsigned int nCSA : 5;
349 		unsigned int nCLD : 3;
GetBufPtrTEX0350 		uint32 GetBufPtr() const
351 		{
352 			return nBufPtr * 256;
353 		}
GetBufWidthTEX0354 		uint32 GetBufWidth() const
355 		{
356 			return nBufWidth * 64;
357 		}
GetWidthTEX0358 		uint32 GetWidth() const
359 		{
360 			return (1 << nWidth);
361 		}
GetHeightTEX0362 		uint32 GetHeight() const
363 		{
364 			return (1 << (nPad0 | (nPad1 << 2)));
365 		}
GetCLUTPtrTEX0366 		uint32 GetCLUTPtr() const
367 		{
368 			return nCBP * 256;
369 		}
370 	};
371 	static_assert(sizeof(TEX0) == sizeof(uint64), "Size of TEX0 struct must be 8 bytes.");
372 
373 	//Reg 0x08/0x09
374 	struct CLAMP : public convertible<uint64>
375 	{
376 		unsigned int nWMS : 2;
377 		unsigned int nWMT : 2;
378 		unsigned int nMINU : 10;
379 		unsigned int nMAXU : 10;
380 		unsigned int nReserved0 : 8;
381 		unsigned int nReserved1 : 2;
382 		unsigned int nMAXV : 10;
383 		unsigned int nReserved2 : 20;
GetMinUCLAMP384 		unsigned int GetMinU()
385 		{
386 			return nMINU;
387 		}
GetMaxUCLAMP388 		unsigned int GetMaxU()
389 		{
390 			return nMAXU;
391 		}
GetMinVCLAMP392 		unsigned int GetMinV()
393 		{
394 			return (nReserved0) | (nReserved1 << 8);
395 		}
GetMaxVCLAMP396 		unsigned int GetMaxV()
397 		{
398 			return nMAXV;
399 		}
400 	};
401 	static_assert(sizeof(CLAMP) == sizeof(uint64), "Size of CLAMP struct must be 8 bytes.");
402 
403 	//Reg 0x14/0x15
404 	struct TEX1 : public convertible<uint64>
405 	{
406 		unsigned int nLODMethod : 1;
407 		unsigned int nReserved0 : 1;
408 		unsigned int nMaxMip : 3;
409 		unsigned int nMagFilter : 1;
410 		unsigned int nMinFilter : 3;
411 		unsigned int nMipBaseAddr : 1;
412 		unsigned int nReserved1 : 9;
413 		unsigned int nLODL : 2;
414 		unsigned int nReserved2 : 11;
415 		unsigned int nLODK : 12;
416 		unsigned int nReserved3 : 20;
417 
GetKTEX1418 		float GetK() const
419 		{
420 			int16 temp = nLODK | ((nLODK & 0x800) ? 0xF000 : 0x0000);
421 			return static_cast<float>(temp) / 16.0f;
422 		}
423 	};
424 	static_assert(sizeof(TEX1) == sizeof(uint64), "Size of TEX1 struct must be 8 bytes.");
425 
426 	//Reg 0x16/0x17
427 	struct TEX2 : public convertible<uint64>
428 	{
429 		unsigned int nReserved0 : 20;
430 		unsigned int nPsm : 6;
431 		unsigned int nReserved1 : 6;
432 		unsigned int nReserved2 : 5;
433 		unsigned int nCBP : 14;
434 		unsigned int nCPSM : 4;
435 		unsigned int nCSM : 1;
436 		unsigned int nCSA : 5;
437 		unsigned int nCLD : 3;
GetCLUTPtrTEX2438 		uint32 GetCLUTPtr()
439 		{
440 			return nCBP * 256;
441 		}
442 	};
443 	static_assert(sizeof(TEX2) == sizeof(uint64), "Size of TEX2 struct must be 8 bytes.");
444 
445 	//Reg 0x18/0x19
446 	struct XYOFFSET : public convertible<uint64>
447 	{
448 		uint16 nOffsetX;
449 		uint16 nReserved0;
450 		uint16 nOffsetY;
451 		uint16 nReserved1;
GetXXYOFFSET452 		float GetX()
453 		{
454 			return static_cast<float>(nOffsetX) / 16.0f;
455 		}
GetYXYOFFSET456 		float GetY()
457 		{
458 			return static_cast<float>(nOffsetY) / 16.0f;
459 		}
460 	};
461 	static_assert(sizeof(XYOFFSET) == sizeof(uint64), "Size of XYOFFSET struct must be 8 bytes.");
462 
463 	//Reg 0x1B
464 	struct PRMODE : public convertible<uint64>
465 	{
466 		unsigned int nReserved0 : 3;
467 		unsigned int nShading : 1;
468 		unsigned int nTexture : 1;
469 		unsigned int nFog : 1;
470 		unsigned int nAlpha : 1;
471 		unsigned int nAntiAliasing : 1;
472 		unsigned int nUseUV : 1;
473 		unsigned int nContext : 1;
474 		unsigned int nUseFloat : 1;
475 		unsigned int nReserved1 : 21;
476 		uint32 nReserved2;
477 	};
478 	static_assert(sizeof(PRMODE) == sizeof(uint64), "Size of PRMODE struct must be 8 bytes.");
479 
480 	//Reg 0x34/0x35
481 	struct MIPTBP1 : public convertible<uint64>
482 	{
483 		unsigned int tbp1 : 14;
484 		unsigned int tbw1 : 6;
485 		unsigned int pad0 : 12;
486 		unsigned int pad1 : 2;
487 		unsigned int tbw2 : 6;
488 		unsigned int tbp3 : 14;
489 		unsigned int tbw3 : 6;
490 		unsigned int reserved : 4;
GetTbp1MIPTBP1491 		uint32 GetTbp1() const
492 		{
493 			return tbp1 * 256;
494 		}
GetTbp2MIPTBP1495 		uint32 GetTbp2() const
496 		{
497 			return (pad0 | (pad1 << 12)) * 256;
498 		}
GetTbp3MIPTBP1499 		uint32 GetTbp3() const
500 		{
501 			return tbp3 * 256;
502 		}
GetTbw1MIPTBP1503 		uint32 GetTbw1() const
504 		{
505 			return tbw1 * 64;
506 		}
GetTbw2MIPTBP1507 		uint32 GetTbw2() const
508 		{
509 			return tbw2 * 64;
510 		}
GetTbw3MIPTBP1511 		uint32 GetTbw3() const
512 		{
513 			return tbw3 * 64;
514 		}
515 	};
516 	static_assert(sizeof(MIPTBP1) == sizeof(uint64), "Size of MIPTBP1 struct must be 8 bytes.");
517 
518 	//Reg 0x36/0x37
519 	struct MIPTBP2 : public convertible<uint64>
520 	{
521 		unsigned int tbp4 : 14;
522 		unsigned int tbw4 : 6;
523 		unsigned int pad0 : 12;
524 		unsigned int pad1 : 2;
525 		unsigned int tbw5 : 6;
526 		unsigned int tbp6 : 14;
527 		unsigned int tbw6 : 6;
528 		unsigned int reserved : 4;
GetTbp4MIPTBP2529 		uint32 GetTbp4() const
530 		{
531 			return tbp4 * 256;
532 		}
GetTbp5MIPTBP2533 		uint32 GetTbp5() const
534 		{
535 			return (pad0 | (pad1 << 12)) * 256;
536 		}
GetTbp6MIPTBP2537 		uint32 GetTbp6() const
538 		{
539 			return tbp6 * 256;
540 		}
GetTbw4MIPTBP2541 		uint32 GetTbw4() const
542 		{
543 			return tbw4 * 64;
544 		}
GetTbw5MIPTBP2545 		uint32 GetTbw5() const
546 		{
547 			return tbw5 * 64;
548 		}
GetTbw6MIPTBP2549 		uint32 GetTbw6() const
550 		{
551 			return tbw6 * 64;
552 		}
553 	};
554 	static_assert(sizeof(MIPTBP2) == sizeof(uint64), "Size of MIPTBP2 struct must be 8 bytes.");
555 
556 	//Reg 0x3B
557 	struct TEXA : public convertible<uint64>
558 	{
559 		unsigned int nTA0 : 8;
560 		unsigned int nReserved0 : 7;
561 		unsigned int nAEM : 1;
562 		unsigned int nReserved1 : 16;
563 		unsigned int nTA1 : 8;
564 		unsigned int nReserved2 : 24;
565 	};
566 	static_assert(sizeof(TEXA) == sizeof(uint64), "Size of TEXA struct must be 8 bytes.");
567 
568 	//Reg 0x3D
569 	struct FOGCOL : public convertible<uint64>
570 	{
571 		unsigned int nFCR : 8;
572 		unsigned int nFCG : 8;
573 		unsigned int nFCB : 8;
574 		unsigned int nReserved0 : 8;
575 		unsigned int nReserved1 : 32;
576 	};
577 	static_assert(sizeof(FOGCOL) == sizeof(uint64), "Size of FOGCOL struct must be 8 bytes.");
578 
579 	//Reg 0x3F
580 	struct TEXCLUT : public convertible<uint64>
581 	{
582 		unsigned int nCBW : 6;
583 		unsigned int nCOU : 6;
584 		unsigned int nCOV : 10;
585 		unsigned int nReserved1 : 10;
586 		unsigned int nReserved2 : 32;
GetBufWidthTEXCLUT587 		uint32 GetBufWidth() const
588 		{
589 			return nCBW * 64;
590 		}
GetOffsetUTEXCLUT591 		uint32 GetOffsetU() const
592 		{
593 			return nCOU * 16;
594 		}
GetOffsetVTEXCLUT595 		uint32 GetOffsetV() const
596 		{
597 			return nCOV;
598 		}
599 	};
600 	static_assert(sizeof(TEXCLUT) == sizeof(uint64), "Size of TEXCLUT struct must be 8 bytes.");
601 
602 	//Reg 0x40/0x41
603 	struct SCISSOR : public convertible<uint64>
604 	{
605 		unsigned int scax0 : 11;
606 		unsigned int reserved0 : 5;
607 		unsigned int scax1 : 11;
608 		unsigned int reserved1 : 5;
609 		unsigned int scay0 : 11;
610 		unsigned int reserved2 : 5;
611 		unsigned int scay1 : 11;
612 		unsigned int reserved3 : 5;
613 	};
614 	static_assert(sizeof(SCISSOR) == sizeof(uint64), "Size of SCISSOR struct must be 8 bytes.");
615 
616 	//Reg 0x42/0x43
617 	struct ALPHA : public convertible<uint64>
618 	{
619 		unsigned int nA : 2;
620 		unsigned int nB : 2;
621 		unsigned int nC : 2;
622 		unsigned int nD : 2;
623 		unsigned int nReserved0 : 24;
624 		unsigned int nFix : 8;
625 		unsigned int nReserved1 : 24;
626 	};
627 	static_assert(sizeof(ALPHA) == sizeof(uint64), "Size of ALPHA struct must be 8 bytes.");
628 
629 	//Reg 0x47/0x48
630 	struct TEST : public convertible<uint64>
631 	{
632 		unsigned int nAlphaEnabled : 1;
633 		unsigned int nAlphaMethod : 3;
634 		unsigned int nAlphaRef : 8;
635 		unsigned int nAlphaFail : 2;
636 		unsigned int nDestAlphaEnabled : 1;
637 		unsigned int nDestAlphaMode : 1;
638 		unsigned int nDepthEnabled : 1;
639 		unsigned int nDepthMethod : 2;
640 		unsigned int nReserved0 : 13;
641 		uint32 nReserved1;
642 	};
643 	static_assert(sizeof(TEST) == sizeof(uint64), "Size of TEST struct must be 8 bytes.");
644 
645 	//Reg 0x4C/0x4D
646 	struct FRAME : public convertible<uint64>
647 	{
648 		unsigned int nPtr : 9;
649 		unsigned int nReserved0 : 7;
650 		unsigned int nWidth : 6;
651 		unsigned int nReserved1 : 2;
652 		unsigned int nPsm : 6;
653 		unsigned int nReserved2 : 2;
654 		unsigned int nMask : 32;
GetBasePtrFRAME655 		uint32 GetBasePtr() const
656 		{
657 			return nPtr * 8192;
658 		}
GetWidthFRAME659 		uint32 GetWidth() const
660 		{
661 			return nWidth * 64;
662 		}
663 	};
664 	static_assert(sizeof(FRAME) == sizeof(uint64), "Size of FRAME struct must be 8 bytes.");
665 
666 	//Reg 0x4E/0x4F
667 	struct ZBUF : public convertible<uint64>
668 	{
669 		unsigned int nPtr : 9;
670 		unsigned int nReserved0 : 15;
671 		unsigned int nPsm : 4;
672 		unsigned int nReserved1 : 4;
673 		unsigned int nMask : 1;
674 		unsigned int nReserved2 : 31;
GetBasePtrZBUF675 		uint32 GetBasePtr() const
676 		{
677 			return nPtr * 8192;
678 		}
679 	};
680 	static_assert(sizeof(ZBUF) == sizeof(uint64), "Size of ZBUF struct must be 8 bytes.");
681 
682 	//Reg 0x50
683 	struct BITBLTBUF : public convertible<uint64>
684 	{
685 		unsigned int nSrcPtr : 14;
686 		unsigned int nReserved0 : 2;
687 		unsigned int nSrcWidth : 6;
688 		unsigned int nReserved1 : 2;
689 		unsigned int nSrcPsm : 6;
690 		unsigned int nReserved2 : 2;
691 		unsigned int nDstPtr : 14;
692 		unsigned int nReserved3 : 2;
693 		unsigned int nDstWidth : 6;
694 		unsigned int nReserved4 : 2;
695 		unsigned int nDstPsm : 6;
696 		unsigned int nReserved5 : 2;
GetSrcPtrBITBLTBUF697 		uint32 GetSrcPtr() const
698 		{
699 			return nSrcPtr * 256;
700 		}
GetSrcWidthBITBLTBUF701 		uint32 GetSrcWidth() const
702 		{
703 			return nSrcWidth * 64;
704 		}
GetDstPtrBITBLTBUF705 		uint32 GetDstPtr() const
706 		{
707 			return nDstPtr * 256;
708 		}
GetDstWidthBITBLTBUF709 		uint32 GetDstWidth() const
710 		{
711 			return nDstWidth * 64;
712 		}
713 	};
714 	static_assert(sizeof(BITBLTBUF) == sizeof(uint64), "Size of BITBLTBUF struct must be 8 bytes.");
715 
716 	//Reg 0x51
717 	struct TRXPOS : public convertible<uint64>
718 	{
719 		unsigned int nSSAX : 11;
720 		unsigned int nReserved0 : 5;
721 		unsigned int nSSAY : 11;
722 		unsigned int nReserved1 : 5;
723 		unsigned int nDSAX : 11;
724 		unsigned int nReserved2 : 5;
725 		unsigned int nDSAY : 11;
726 		unsigned int nDIR : 2;
727 		unsigned int nReserved3 : 3;
728 	};
729 	static_assert(sizeof(TRXPOS) == sizeof(uint64), "Size of TRXPOS struct must be 8 bytes.");
730 
731 	//Reg 0x52
732 	struct TRXREG : public convertible<uint64>
733 	{
734 		unsigned int nRRW : 12;
735 		unsigned int nReserved0 : 20;
736 		unsigned int nRRH : 12;
737 		unsigned int nReserved1 : 20;
738 	};
739 	static_assert(sizeof(TRXREG) == sizeof(uint64), "Size of TRXREG struct must be 8 bytes.");
740 
741 	//Reg 0x60
742 	struct SIGNAL : public convertible<uint64>
743 	{
744 		unsigned int id : 32;
745 		unsigned int idmsk : 32;
746 	};
747 	static_assert(sizeof(SIGNAL) == sizeof(uint64), "Size of SIGNAL struct must be 8 bytes.");
748 
749 	//Reg 0x62
750 	struct LABEL : public convertible<uint64>
751 	{
752 		unsigned int id : 32;
753 		unsigned int idmsk : 32;
754 	};
755 	static_assert(sizeof(LABEL) == sizeof(uint64), "Size of LABEL struct must be 8 bytes.");
756 
757 	typedef std::pair<uint8, uint64> RegisterWrite;
758 	typedef std::vector<RegisterWrite> RegisterWriteList;
759 	typedef std::function<CGSHandler*(void)> FactoryFunction;
760 
761 	typedef Framework::CSignal<void()> FlipCompleteEvent;
762 	typedef Framework::CSignal<void(uint32)> NewFrameEvent;
763 
764 	CGSHandler(bool = true);
765 	virtual ~CGSHandler();
766 
767 	static void RegisterPreferences();
768 	void NotifyPreferencesChanged();
769 
770 	void SetIntc(CINTC*);
771 	void Reset();
772 	virtual void SetPresentationParams(const PRESENTATION_PARAMS&);
773 
774 	virtual void SaveState(Framework::CZipArchiveWriter&);
775 	virtual void LoadState(Framework::CZipArchiveReader&);
776 	void Copy(const CGSHandler*);
777 
778 	void SetFrameDump(CFrameDump*);
779 
780 	bool GetDrawEnabled() const;
781 	void SetDrawEnabled(bool);
782 
783 	void WritePrivRegister(uint32, uint32);
784 	uint32 ReadPrivRegister(uint32);
785 
786 	void SetLoggingEnabled(bool);
787 	static std::string DisassembleWrite(uint8, uint64);
788 
789 	void SetVBlank();
790 	void ResetVBlank();
791 
792 	void FeedImageData(const void*, uint32);
793 	void ReadImageData(void*, uint32);
794 
WriteRegister(const RegisterWrite & write)795 	inline void WriteRegister(const RegisterWrite& write)
796 	{
797 		assert(m_writeBufferSize < REGISTERWRITEBUFFER_SIZE);
798 		if(m_writeBufferSize == REGISTERWRITEBUFFER_SIZE) return;
799 		m_writeBuffer[m_writeBufferSize++] = write;
800 	}
801 
802 	void ProcessWriteBuffer(const CGsPacketMetadata*);
803 	void SubmitWriteBuffer();
804 	void FlushWriteBuffer();
805 
806 	virtual void SetCrt(bool, unsigned int, bool);
807 	void Initialize();
808 	void Release();
809 	virtual void ProcessHostToLocalTransfer() = 0;
810 	virtual void ProcessLocalToHostTransfer() = 0;
811 	virtual void ProcessLocalToLocalTransfer() = 0;
812 	virtual void ProcessClutTransfer(uint32, uint32) = 0;
813 	void Flip(bool = false);
814 	void Finish();
815 	virtual void ReadFramebuffer(uint32, uint32, void*) = 0;
816 
817 	void MakeLinearCLUT(const TEX0&, std::array<uint32, 256>&) const;
818 
819 	virtual uint8* GetRam() const;
820 	uint64* GetRegisters();
821 
822 	uint64 GetSMODE2() const;
823 	void SetSMODE2(uint64);
824 
825 	uint64 GetBUSDIR() const;
826 
827 	int GetPendingTransferCount() const;
828 	void NotifyEvent(uint32);
829 
830 	unsigned int GetCrtWidth() const;
831 	unsigned int GetCrtHeight() const;
832 	uint32 GetCrtFrameRate() const;
833 	uint32 GetCrtHSyncFrequency() const;
834 	bool GetCrtIsInterlaced() const;
835 	bool GetCrtIsFrameMode() const;
836 	std::pair<uint64, uint64> GetCurrentDisplayInfo();
837 	unsigned int GetCurrentReadCircuit();
838 
839 	static std::pair<uint32, uint32> GetTransferInvalidationRange(const BITBLTBUF&, const TRXREG&, const TRXPOS&);
840 
841 	virtual Framework::CBitmap GetScreenshot();
842 
843 	void SendGSCall(CMailBox::FunctionType&&);
844 	void SendGSCall(const CMailBox::FunctionType&, bool = false, bool = false);
845 
846 	void ProcessSingleFrame();
847 
848 	FlipCompleteEvent OnFlipComplete;
849 	NewFrameEvent OnNewFrame;
850 
851 protected:
852 	struct DELAYED_REGISTER
853 	{
854 		uint32 heldValue;
855 		INTEGER64 value;
856 	};
857 
858 	enum CLUTSIZE
859 	{
860 		CLUTSIZE = 0x400,
861 		CLUTENTRYCOUNT = (CLUTSIZE / 2)
862 	};
863 
864 	enum
865 	{
866 		REGISTERWRITEBUFFER_SIZE = 0x100000,
867 		REGISTERWRITEBUFFER_SUBMIT_THRESHOLD = 0x100
868 	};
869 
870 	enum MAG_FILTER
871 	{
872 		MAG_FILTER_NEAREST = 0,
873 		MAG_FILTER_LINEAR = 1
874 	};
875 
876 	enum MIN_FILTER
877 	{
878 		MIN_FILTER_NEAREST = 0,
879 		MIN_FILTER_LINEAR = 1,
880 		MIN_FILTER_NEAREST_MIP_NEAREST = 2,
881 		MIN_FILTER_NEAREST_MIP_LINEAR = 3,
882 		MIN_FILTER_LINEAR_MIP_NEAREST = 4,
883 		MIN_FILTER_LINEAR_MIP_LINEAR = 5
884 	};
885 
886 	//-----------------------------------
887 	//Private Registers
888 	enum CRT_MODE : uint32
889 	{
890 		CRT_MODE_NTSC = 0x02,
891 		CRT_MODE_PAL = 0x03,
892 		CRT_MODE_VGA_640_75 = 0x1C,
893 	};
894 
895 	struct SMODE2 : public convertible<uint64>
896 	{
897 		unsigned int interlaced : 1;
898 		unsigned int ffmd : 1;
899 		unsigned int dpms : 2;
900 		unsigned int reserved0 : 28;
901 		unsigned int reserved1;
902 	};
903 	static_assert(sizeof(SMODE2) == sizeof(uint64), "Size of SMODE2 struct must be 8 bytes.");
904 
905 	struct DISPFB : public convertible<uint64>
906 	{
907 		unsigned int nBufPtr : 9;
908 		unsigned int nBufWidth : 6;
909 		unsigned int nPSM : 5;
910 		unsigned int nReserved0 : 12;
911 		unsigned int nX : 11;
912 		unsigned int nY : 11;
913 		unsigned int nReserved1 : 10;
GetBufPtrDISPFB914 		uint32 GetBufPtr() const
915 		{
916 			return nBufPtr * 8192;
917 		};
GetBufWidthDISPFB918 		uint32 GetBufWidth() const
919 		{
920 			return nBufWidth * 64;
921 		};
922 	};
923 	static_assert(sizeof(DISPFB) == sizeof(uint64), "Size of DISPFB struct must be 8 bytes.");
924 
925 	struct DISPLAY : public convertible<uint64>
926 	{
927 		unsigned int nX : 12;
928 		unsigned int nY : 11;
929 		unsigned int nMagX : 4;
930 		unsigned int nMagY : 5;
931 		unsigned int nW : 12;
932 		unsigned int nH : 12;
933 		unsigned int reserved : 8;
934 	};
935 	static_assert(sizeof(DISPLAY) == sizeof(uint64), "Size of DISPLAY struct must be 8 bytes.");
936 
937 	struct SIGLBLID : public convertible<uint64>
938 	{
939 		unsigned int sigid : 32;
940 		unsigned int lblid : 32;
941 	};
942 	static_assert(sizeof(SIGLBLID) == sizeof(uint64), "Size of SIGLBLID struct must be 8 bytes.");
943 
944 	struct TRXCONTEXT
945 	{
946 		uint32 nSize;
947 		uint32 nRealSize;
948 		uint32 nRRX;
949 		uint32 nRRY;
950 		bool nDirty;
951 	};
952 
953 	typedef bool (CGSHandler::*TRANSFERWRITEHANDLER)(const void*, uint32);
954 	typedef void (CGSHandler::*TRANSFERREADHANDLER)(void*, uint32);
955 
956 	void LogWrite(uint8, uint64);
957 	void LogPrivateWrite(uint32);
958 
959 	void WriteToDelayedRegister(uint32, uint32, DELAYED_REGISTER&);
960 
961 	void ThreadProc();
962 	virtual void InitializeImpl() = 0;
963 	virtual void ReleaseImpl() = 0;
964 	void ResetBase();
965 	virtual void ResetImpl();
966 	virtual void NotifyPreferencesChangedImpl();
967 	virtual void FlipImpl();
968 	virtual void MarkNewFrame();
969 	virtual void WriteRegisterImpl(uint8, uint64);
970 	void FeedImageDataImpl(const uint8*, uint32);
971 	void ReadImageDataImpl(void*, uint32);
972 	void SubmitWriteBufferImpl(uint32, uint32);
973 
974 	void BeginTransfer();
975 
976 	virtual void BeginTransferWrite();
977 	virtual void TransferWrite(const uint8*, uint32);
978 
979 	TRANSFERWRITEHANDLER m_transferWriteHandlers[PSM_MAX];
980 	TRANSFERREADHANDLER m_transferReadHandlers[PSM_MAX];
981 
982 	bool TransferWriteHandlerInvalid(const void*, uint32);
983 	template <typename Storage>
984 	bool TransferWriteHandlerGeneric(const void*, uint32);
985 	bool TransferWriteHandlerPSMT4(const void*, uint32);
986 	bool TransferWriteHandlerPSMCT24(const void*, uint32);
987 	bool TransferWriteHandlerPSMT8H(const void*, uint32);
988 	template <uint32, uint32>
989 	bool TransferWriteHandlerPSMT4H(const void*, uint32);
990 
991 	void TransferReadHandlerInvalid(void*, uint32);
992 	template <typename Storage>
993 	void TransferReadHandlerGeneric(void*, uint32);
994 	void TransferReadHandlerPSMCT24(void*, uint32);
995 
996 	virtual void SyncCLUT(const TEX0&);
997 	bool ProcessCLD(const TEX0&);
998 	template <typename Indexor>
999 	bool ReadCLUT4_16(const TEX0&);
1000 	template <typename Indexor>
1001 	bool ReadCLUT8_16(const TEX0&);
1002 	void ReadCLUT4(const TEX0&);
1003 	void ReadCLUT8(const TEX0&);
1004 
1005 	static bool IsCompatibleFramebufferPSM(unsigned int, unsigned int);
1006 
1007 	PRESENTATION_VIEWPORT GetPresentationViewport() const;
1008 
1009 	bool m_loggingEnabled;
1010 
1011 	uint64 m_nPMODE;              //0x12000000
1012 	uint64 m_nSMODE2;             //0x12000020
1013 	DELAYED_REGISTER m_nDISPFB1;  //0x12000070
1014 	DELAYED_REGISTER m_nDISPLAY1; //0x12000080
1015 	DELAYED_REGISTER m_nDISPFB2;  //0x12000090
1016 	DELAYED_REGISTER m_nDISPLAY2; //0x120000A0
1017 	uint64 m_nCSR;                //0x12001000
1018 	uint64 m_nIMR;                //0x12001010
1019 	uint64 m_nBUSDIR;             //0x12001040
1020 	uint64 m_nSIGLBLID;           //0x12001080
1021 
1022 	PRESENTATION_PARAMS m_presentationParams;
1023 
1024 	TRXCONTEXT m_trxCtx;
1025 
1026 	uint64 m_nReg[REGISTER_MAX];
1027 
1028 	uint8* m_pRAM;
1029 
1030 	uint16* m_pCLUT;
1031 	uint32 m_nCBP0;
1032 	uint32 m_nCBP1;
1033 
1034 	uint32 m_drawCallCount;
1035 
1036 	//Rename to register write buffer?
1037 	RegisterWrite* m_writeBuffer;
1038 	uint32 m_writeBufferSize = 0;
1039 	uint32 m_writeBufferProcessIndex = 0;
1040 	uint32 m_writeBufferSubmitIndex = 0;
1041 
1042 	CRT_MODE m_crtMode;
1043 	std::thread m_thread;
1044 	std::recursive_mutex m_registerMutex;
1045 	std::atomic<int> m_transferCount;
1046 	bool m_threadDone;
1047 	CFrameDump* m_frameDump;
1048 	bool m_drawEnabled = true;
1049 	CINTC* m_intc = nullptr;
1050 	bool m_gsThreaded = true;
1051 	bool m_flipped = false;
1052 
1053 private:
1054 	CMailBox m_mailBox;
1055 };
1056