summaryrefslogtreecommitdiffstatshomepage
path: root/scripts/src/tools.lua
blob: a2e5ad7349640bd3c93c7c9b731708f88b583d20 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
-- license:BSD-3-Clause
-- copyright-holders:MAMEdev Team

---------------------------------------------------------------------------
--
--   tools.lua
--
--   Rules for the building of tools
--
---------------------------------------------------------------------------

--------------------------------------------------
-- romcmp
--------------------------------------------------

project("romcmp")
uuid ("1b40275b-194c-497b-8abd-9338775a21b8")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/romcmp.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- chdman
--------------------------------------------------

project("chdman")
uuid ("7d948868-42db-432a-9bb5-70ce5c5f4620")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
	MAME_DIR .. "3rdparty",
}
includedirs {
	ext_includedir("flac"),
}

files {
	MAME_DIR .. "src/tools/chdman.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
	MAME_DIR .. "src/version.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- jedutil
--------------------------------------------------

project("jedutil")
uuid ("bda60edb-f7f5-489f-b232-23d33c43dda1")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/jedutil.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- unidasm
--------------------------------------------------

project("unidasm")
uuid ("65f81d3b-299a-4b08-a3fa-d5241afa9fd1")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"dasm",
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/emu",
	MAME_DIR .. "src/lib/util",
	MAME_DIR .. "3rdparty",
}

files {
	MAME_DIR .. "src/tools/unidasm.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- ldresample
--------------------------------------------------

project("ldresample")
uuid ("3401561a-4407-4e13-9c6d-c0801330f7cc")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
	MAME_DIR .. "3rdparty",
}
includedirs {
	ext_includedir("flac"),
}

files {
	MAME_DIR .. "src/tools/ldresample.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- ldverify
--------------------------------------------------

project("ldverify")
uuid ("3e66560d-b928-4227-928b-eadd0a10f00a")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
	MAME_DIR .. "3rdparty",
}
includedirs {
	ext_includedir("flac"),
}

files {
	MAME_DIR .. "src/tools/ldverify.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- regrep
--------------------------------------------------

project("regrep")
uuid ("7f6de580-d800-4e8d-bed6-9fc86829584d")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/regrep.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- srcclean
---------------------------------------------------

project("srcclean")
uuid ("4dd58139-313a-42c5-965d-f378bdeed220")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/srcclean.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- src2html
--------------------------------------------------

project("src2html")
uuid ("b31e963a-09ef-4696-acbd-e663e35ce6f7")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/src2html.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- split
--------------------------------------------------

project("split")
uuid ("8ef6ff18-3199-4cc2-afd0-d64033070faa")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/split.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- pngcmp
--------------------------------------------------

project("pngcmp")
uuid ("61f647d9-b129-409b-9c62-8acf98ed39be")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/pngcmp.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- nltool
--------------------------------------------------

project("nltool")
uuid ("853a03b7-fa37-41a8-8250-0dc23dd935d6")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	"netlist",
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
	MAME_DIR .. "src/lib/netlist",
}

files {
	MAME_DIR .. "src/lib/netlist/prg/nltool.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- nlwav
--------------------------------------------------

project("nlwav")
uuid ("7c5396d1-2a1a-4c93-bed6-6b8fa182054a")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"utils",
	"ocore_" .. _OPTIONS["osd"],
	"netlist",
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib/util",
	MAME_DIR .. "src/lib/netlist",
}

files {
	MAME_DIR .. "src/lib/netlist/prg/nlwav.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- castool
--------------------------------------------------

project("castool")
uuid ("7d9ed428-e2ba-4448-832d-d882a64d5c22")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"formats",
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/castool.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- floptool
--------------------------------------------------

project("floptool")
uuid ("85d8e3a6-1661-4ac9-8c21-281d20cbaf5b")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"formats",
	"emu",
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib",
	MAME_DIR .. "src/lib/util",
}

files {
	MAME_DIR .. "src/tools/floptool.cpp",
	MAME_DIR .. "src/emu/emucore.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- imgtool
--------------------------------------------------

project("imgtool")
uuid ("f3707807-e587-4297-a5d8-bc98f3d0b1ca")
kind "ConsoleApp"

flags {
	"Symbols", -- always include minimum symbols for executables
}

if _OPTIONS["SEPARATE_BIN"]~="1" then
	targetdir(MAME_DIR)
end

links {
	"formats",
	"emu",
	"utils",
	ext_lib("expat"),
	"7z",
	"ocore_" .. _OPTIONS["osd"],
	ext_lib("zlib"),
	ext_lib("flac"),
}

includedirs {
	MAME_DIR .. "src/osd",
	MAME_DIR .. "src/lib",
	MAME_DIR .. "src/lib/util",
	ext_includedir("zlib"),
	MAME_DIR .. "src/tools/imgtool",
}

files {
	MAME_DIR .. "src/tools/imgtool/main.cpp",
	MAME_DIR .. "src/tools/imgtool/main.h",
	MAME_DIR .. "src/tools/imgtool/stream.cpp",
	MAME_DIR .. "src/tools/imgtool/stream.h",
	MAME_DIR .. "src/tools/imgtool/library.cpp",
	MAME_DIR .. "src/tools/imgtool/library.h",
	MAME_DIR .. "src/tools/imgtool/modules.cpp",
	MAME_DIR .. "src/tools/imgtool/modules.h",
	MAME_DIR .. "src/tools/imgtool/iflopimg.cpp",
	MAME_DIR .. "src/tools/imgtool/iflopimg.h",
	MAME_DIR .. "src/tools/imgtool/filter.cpp",
	MAME_DIR .. "src/tools/imgtool/filter.h",
	MAME_DIR .. "src/tools/imgtool/filteoln.cpp",
	MAME_DIR .. "src/tools/imgtool/filtbas.cpp",
	MAME_DIR .. "src/tools/imgtool/imgtool.cpp",
	MAME_DIR .. "src/tools/imgtool/imgtool.h",
	MAME_DIR .. "src/tools/imgtool/imgterrs.cpp",
	MAME_DIR .. "src/tools/imgtool/imgterrs.h",
	MAME_DIR .. "src/tools/imgtool/imghd.cpp",
	MAME_DIR .. "src/tools/imgtool/imghd.h",
	MAME_DIR .. "src/tools/imgtool/charconv.cpp",
	MAME_DIR .. "src/tools/imgtool/charconv.h",
	MAME_DIR .. "src/tools/imgtool/formats/vt_dsk.cpp",
	MAME_DIR .. "src/tools/imgtool/formats/vt_dsk.h",
	MAME_DIR .. "src/tools/imgtool/formats/coco_dsk.cpp",
	MAME_DIR .. "src/tools/imgtool/formats/coco_dsk.h",
	MAME_DIR .. "src/tools/imgtool/modules/amiga.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/macbin.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/rsdos.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/os9.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/mac.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/ti99.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/ti990hd.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/concept.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/fat.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/fat.h",
	MAME_DIR .. "src/tools/imgtool/modules/pc_flop.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/pc_hard.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/prodos.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/vzdos.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/thomson.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/macutil.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/macutil.h",
	MAME_DIR .. "src/tools/imgtool/modules/cybiko.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/cybikoxt.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/psion.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/bml3.cpp",
	MAME_DIR .. "src/tools/imgtool/modules/hp48.cpp",
}

configuration { "mingw*" or "vs*" }
	targetextension ".exe"

configuration { }

strip()

--------------------------------------------------
-- aueffectutil
--------------------------------------------------

if _OPTIONS["targetos"] == "macosx" then
	project("aueffectutil")
		uuid ("3db8316d-fad7-4f5b-b46a-99373c91550e")
		kind "ConsoleApp"

		flags {
			"Symbols", -- always include minimum symbols for executables
		}

		if _OPTIONS["SEPARATE_BIN"]~="1" then
			targetdir(MAME_DIR)
		end

		linkoptions {
			"-sectcreate __TEXT __info_plist " .. MAME_DIR .. "src/tools/aueffectutil-Info.plist",
		}

		dependency {
			{ "aueffectutil",  MAME_DIR .. "src/tools/aueffectutil-Info.plist", true  },
		}

		links {
			"AudioUnit.framework",
			"AudioToolbox.framework",
			"CoreAudio.framework",
			"CoreAudioKit.framework",
			"CoreServices.framework",
		}

		files {
			MAME_DIR .. "src/tools/aueffectutil.mm",
		}

        configuration { }

		strip()
end
/span> 13, 5 }; // Using this matrix allows iteagle video memory tests to pass u8 const dither_helper::s_dither_matrix_2x2[16] = { 8, 10, 8, 10, 11, 9, 11, 9, 8, 10, 8, 10, 11, 9, 11, 9 }; static const rectangle global_cliprect(-4096, 4095, -4096, 4095); //************************************************************************** // STATIC HELPERS //************************************************************************** //------------------------------------------------- // compute_wfloat - compute the pseudo-floating // point version of the iterated W value //------------------------------------------------- inline s32 ATTR_FORCE_INLINE compute_wfloat(s64 iterw) { int exp = count_leading_zeros_64(iterw) - 16; if (exp < 0) return 0x0000; if (exp >= 16) return 0xffff; return ((exp << 12) | ((iterw >> (35 - exp)) ^ 0x1fff)) + 1; } //------------------------------------------------- // clamped_argb - clamp the incoming ARGB color // according to the clamping settings, or do the // fake pseudo-clamp described in the Voodoo // manual //------------------------------------------------- inline rgbaint_t ATTR_FORCE_INLINE clamped_argb(const rgbaint_t &iterargb, reg_fbz_colorpath const fbzcp) { rgbaint_t result(iterargb); result.shr_imm(20); // clamped case is easy if (fbzcp.rgbzw_clamp() != 0) { result.clamp_to_uint8(); return result; } // for each component: // result = val & 0xfff; // if (result == 0xfff) result = 0; // if (result == 0x100) result = 0xff; // check against 0xfff and force to 0 rgbaint_t temp1(result); rgbaint_t temp2(result); temp1.cmpeq_imm(0xfff); temp2.cmpeq_imm(0x100); result.andnot_reg(temp1); result.or_reg(temp2); result.and_imm(0xff); return result; } //------------------------------------------------- // clamped_z - clamp the Z value according to the // clamping settings, or do the fake pseudo-clamp // described in the Voodoo manual //------------------------------------------------- inline s32 ATTR_FORCE_INLINE clamped_z(s32 iterz, reg_fbz_colorpath const fbzcp) { // clamped case is easy if (fbzcp.rgbzw_clamp() != 0) return std::clamp(iterz >> 12, 0, 0xffff); // non-clamped case has specific behaviors u32 result = u32(iterz) >> 12; if (result == 0xfffff) return 0; if (result == 0x10000) return 0xffff; return result & 0xffff; } //------------------------------------------------- // clamped_w - clamp the W value according to the // clamping settings, or do the fake pseudo-clamp // described in the Voodoo manual //------------------------------------------------- inline s32 ATTR_FORCE_INLINE clamped_w(s64 iterw, reg_fbz_colorpath const fbzcp) { // clamped case is easy if (fbzcp.rgbzw_clamp() != 0) return std::clamp(s32(iterw >> 48), 0, 0xff); // non-clamped case has specific behaviors u32 result = u64(iterw) >> 48; if (result == 0xffff) return 0; if (result == 0x100) return 0xff; return result & 0xff; } //------------------------------------------------- // fast_log2 - computes the log2 of a double- // precision value as a 24.8 value; if the double // was converted from a fixed-point integer, the // number of fractional bits should be specified // by fracbits //------------------------------------------------- inline s32 ATTR_FORCE_INLINE fast_log2(double value, int fracbits = 0) { // negative values return 0 if (UNEXPECTED(value < 0)) return 0; // convert the value to a raw integer union { double d; u64 i; } temp; temp.d = value; // we only care about the 11-bit exponent and top 7 bits of mantissa // (sign is already assured to be 0) u32 ival = temp.i >> 45; // extract exponent, unbias, and adjust for fixed-point fraction s32 exp = (ival >> 7) - 1023 - fracbits; // use top 7 bits of mantissa to look up fractional log static u8 const s_log2_table[128] = { 0, 2, 5, 8, 11, 14, 16, 19, 22, 25, 27, 30, 33, 35, 38, 40, 43, 46, 48, 51, 53, 56, 58, 61, 63, 65, 68, 70, 73, 75, 77, 80, 82, 84, 87, 89, 91, 93, 96, 98, 100, 102, 104, 106, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 132, 134, 136, 138, 140, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 162, 164, 166, 168, 170, 172, 173, 175, 177, 179, 181, 182, 184, 186, 188, 189, 191, 193, 194, 196, 198, 200, 201, 203, 205, 206, 208, 209, 211, 213, 214, 216, 218, 219, 221, 222, 224, 225, 227, 229, 230, 232, 233, 235, 236, 238, 239, 241, 242, 244, 245, 247, 248, 250, 251, 253, 254 }; // combine the integral and fractional parts return (exp << 8) | s_log2_table[ival & 127]; } //------------------------------------------------- // compute_lodbase - compute the base LOD value //------------------------------------------------- inline s32 ATTR_FORCE_INLINE compute_lodbase(s64 dsdx, s64 dsdy, s64 dtdx, s64 dtdy) { // compute (ds^2 + dt^2) in both X and Y; note that these values are // each .32, so the square is a .64 fixed point value double fdsdx = double(dsdx); double fdsdy = double(dsdy); double fdtdx = double(dtdx); double fdtdy = double(dtdy); double texdx = fdsdx * fdsdx + fdtdx * fdtdx; double texdy = fdsdy * fdsdy + fdtdy * fdtdy; // pick whichever is larger double maxval = std::max(texdx, texdy); // use our fast reciprocal/log on this value; 64 to indicate how many // bits of fractional resolution in the source, and divide by 2 because // we really want the log of the square root return fast_log2(maxval, 64) / 2; } //************************************************************************** // RASTERIZER PARAMS //************************************************************************** //------------------------------------------------- // operator== - compare all values //------------------------------------------------- bool rasterizer_params::operator==(rasterizer_params const &rhs) const { return (m_generic == rhs.m_generic && m_fbzcp == rhs.m_fbzcp && m_fbzmode == rhs.m_fbzmode && m_alphamode == rhs.m_alphamode && m_fogmode == rhs.m_fogmode && m_texmode0 == rhs.m_texmode0 && m_texmode1 == rhs.m_texmode1); } //------------------------------------------------- // compute - compute the normalized rasterizer // parameters based on the current register state //------------------------------------------------- void rasterizer_params::compute(voodoo_regs &regs, voodoo_regs *tmu0regs, voodoo_regs *tmu1regs) { // these values are normalized to ignore irrelevant bits m_generic = 0; m_fbzcp = regs.fbz_colorpath().normalize(); m_fbzmode = regs.fbz_mode().normalize(); m_alphamode = regs.alpha_mode().normalize(); m_fogmode = regs.fog_mode().normalize(); m_texmode0 = reg_texture_mode::NONE; m_texmode1 = reg_texture_mode::NONE; if (!regs.fbi_init3().disable_tmus()) { if (tmu0regs != nullptr && tmu0regs->texture_lod().lod_min() < 32) { m_texmode0 = tmu0regs->texture_mode().normalize(); m_generic |= GENERIC_TEX0; if (tmu0regs->trexinit_send_tmu_config()) m_texmode0 |= reg_texture_mode::TMU_CONFIG_MASK; } if (tmu1regs != nullptr && tmu1regs->texture_lod().lod_min() < 32) { m_texmode1 = tmu1regs->texture_mode().normalize(); m_generic |= GENERIC_TEX1; } } compute_equations(); } //------------------------------------------------- // compute_equations - compute equations based // on the captured state //------------------------------------------------- void rasterizer_params::compute_equations() { // start with the color equation m_color_equation = color_equation::from_fbzcp(m_fbzcp); // if it doesn't consume any texels, zap the textures; we're done if (!m_color_equation.uses_any(color_source::texel0)) { m_texmode0 = m_texmode1 = reg_texture_mode::NONE; m_generic = 0; return; } // check the TMU1 equation if (m_generic & GENERIC_TEX1) { m_tex1_equation = color_equation::from_texmode(m_texmode1, color_source::texel1, color_source::zero); // if it's identity, mark it and clear out the equation mask if (m_tex1_equation.is_identity(color_source::texel1)) { m_generic |= GENERIC_TEX1_IDENTITY; m_texmode1 &= ~reg_texture_mode::EQUATION_MASK; } } // check the TMU0 equation if (m_generic & GENERIC_TEX0) { m_tex0_equation = color_equation::from_texmode(m_texmode0, color_source::texel0, (m_generic & GENERIC_TEX1) ? color_source::texel1 : color_source::zero); // special case the send configuration if (!(m_texmode0 & reg_texture_mode::TMU_CONFIG_MASK)) { if (m_tex0_equation.is_identity(color_source::texel0)) { // if identity returning ourself, the downstream TMU doesn't matter m_generic = (m_generic & ~(GENERIC_TEX1 | GENERIC_TEX1_IDENTITY)) | GENERIC_TEX0_IDENTITY; m_texmode0 &= ~reg_texture_mode::EQUATION_MASK; m_texmode1 = reg_texture_mode::NONE; } else if (m_tex0_equation.is_identity(color_source::texel1)) { // if identity returning the downstream value, we're just a passthrough and we don't matter m_generic &= ~GENERIC_TEX0; m_texmode0 = reg_texture_mode::NONE; } } } } //------------------------------------------------- // hash - return a hash of the current values //------------------------------------------------- u32 rasterizer_params::hash() const { return m_generic ^ rotl_32(m_alphamode, 0) ^ rotl_32(m_fbzmode, 6) ^ rotl_32(m_fbzcp, 12) ^ rotl_32(m_fogmode, 18) ^ rotl_32(m_texmode0, 24) ^ rotl_32(m_texmode1, 30); } //************************************************************************** // DITHER HELPER //************************************************************************** //------------------------------------------------- // init_static - initialize static tables //------------------------------------------------- void dither_helper::init_static() { // create static dithering tables s_dither4_lookup = std::make_unique<u8[]>(256*4*4*2); s_dither2_lookup = std::make_unique<u8[]>(256*4*4*2); s_nodither_lookup = std::make_unique<u8[]>(256*4*2); for (int val = 0; val < 256*4*4*2; val++) { int color = (val >> 0) & 0xff; int g = (val >> 8) & 1; int x = (val >> 9) & 3; int y = (val >> 11) & 3; if (!g) { s_dither4_lookup[val] = dither_rb(color, s_dither_matrix_4x4[y * 4 + x]); s_dither2_lookup[val] = dither_rb(color, s_dither_matrix_2x2[y * 4 + x]); } else { s_dither4_lookup[val] = dither_g(color, s_dither_matrix_4x4[y * 4 + x]); s_dither2_lookup[val] = dither_g(color, s_dither_matrix_2x2[y * 4 + x]); } } for (int val = 0; val < 256*4*2; val++) { int color = (val >> 0) & 0xff; int g = (val >> 8) & 1; if (!g) s_nodither_lookup[val] = color >> 3; else s_nodither_lookup[val] = color >> 2; } } //************************************************************************** // COLOR SOURCE //************************************************************************** //------------------------------------------------- // simplify - simplify the individual values //------------------------------------------------- void color_source::simplify() { // convert inverted zero to one if (m_rgb == (ZERO | FLAG_INVERTED)) m_rgb = ONE; if (m_alpha == (ZERO | FLAG_INVERTED)) m_alpha = ONE; } //------------------------------------------------- // string - return a string version of the // components //------------------------------------------------- std::string color_source::as_string() const { static char const * const s_names[] = { "zero", "one", "color0", "color1", "iterargb", "clampz", "clipw", "", "texel0", "texel1", "detailfactor", "lodfrac", "color/iterargb via texel0 alpha" }; static char const * const s_flags[] = { "", ".alphaexpanded", ".inverted", ".alphaexpanded.inverted", }; std::string result; // determine global tags char const *tag = ""; if (is_constant()) tag = "[const]"; else if (is_constant_or_iterated()) tag = "[iter]"; // simplest case: RGB and alpha are the same and non-ambiguous if (m_alpha == m_rgb || (is_uniform_alpha() && (alpha_base() == DETAIL_FACTOR || alpha_base() == LOD_FRACTION))) return string_format("{ %s%s }%s", s_names[alpha_base()], s_flags[alpha_flags()], tag); // slightly less simple: RGB and alpha are both smeared alpha values if (is_uniform_alpha()) return string_format("{ %s.alpha%s }%s", s_names[alpha_base()], s_flags[alpha_flags()], tag); // full complexity case char const *tag_alpha = ""; char const *tag_rgb = ""; if (tag[0] == 0) { if (is_alpha_constant()) tag_alpha = "[const]"; else if (is_alpha_constant_or_iterated()) tag_alpha = "[iter]"; if (is_rgb_constant()) tag_rgb = "[const]"; else if (is_rgb_constant_or_iterated()) tag_rgb = "[iter]"; } return string_format("{ %s%s%s, %s%s%s }%s", s_names[alpha_base()], s_flags[alpha_flags()], tag_alpha, s_names[rgb_base()], s_flags[rgb_flags()], tag_rgb, tag); } // constant values color_source const color_source::zero(color_source::ZERO, color_source::ZERO); color_source const color_source::one(color_source::ONE, color_source::ONE); color_source const color_source::iterated_argb(color_source::ITERATED_ARGB, color_source::ITERATED_ARGB); color_source const color_source::color0(color_source::COLOR0, color_source::COLOR0); color_source const color_source::color1(color_source::COLOR1, color_source::COLOR1); color_source const color_source::texel0(color_source::TEXEL0, color_source::TEXEL0); color_source const color_source::texel1(color_source::TEXEL1, color_source::TEXEL1); //************************************************************************** // COLOR EQUATION //************************************************************************** //------------------------------------------------- // simplify - simplify an equation for optimal // SIMD operations //------------------------------------------------- void color_equation::simplify() { // simplify each internally m_color.simplify(); m_subtract.simplify(); m_multiply.simplify(); m_add.simplify(); // if subtract is zero, we can maybe swap things between color and multiply to // make things neater if (m_subtract.is_zero()) { bool swap = false; // if both are split types and swapping will line one up, do it for sure if (!m_color.is_uniform() && !m_multiply.is_uniform()) if (m_multiply.alpha_base() == m_color.rgb_base() || m_multiply.rgb_base() == m_color.alpha_base()) swap = true; // if neither is a constant/iterated and swapping will make one of them into // a constant/iterated, do it if (!m_color.is_constant_or_iterated() && !m_multiply.is_constant_or_iterated()) if (m_color.is_rgb_constant_or_iterated() != m_color.is_alpha_constant_or_iterated() && m_multiply.is_rgb_constant_or_iterated() != m_multiply.is_alpha_constant_or_iterated()) swap = true; // do the swap if (swap) { auto temp = m_color.rgb(); m_color.set_rgb(m_multiply.rgb()); m_multiply.set_rgb(temp); } // always prefer the multiply to be constant if (m_color.is_constant_or_iterated() && !m_multiply.is_constant_or_iterated()) { color_source temp = m_color; m_color = m_multiply; m_multiply = temp; } // if we're just combining rgb/alpha with constant 0/1, consolidate if (m_multiply.alpha() == color_source::ONE && m_multiply.is_rgb_zero() && m_add.is_alpha_zero()) { m_add.set_alpha(m_color.alpha()); m_multiply = color_source::zero; } if (m_multiply.is_alpha_zero() && m_multiply.is_rgb_one() && m_add.is_rgb_zero()) { m_add.set_rgb(m_color.rgb()); m_multiply = color_source::zero; } if (!m_add.is_zero() && !m_multiply.is_zero()) { // if the multiply is RGB and the add is alpha, combine if (m_multiply.is_alpha_zero() && m_add.is_rgb_zero()) { if (m_multiply.rgb_base() == m_add.alpha_base()) { m_multiply.set_alpha(m_add.alpha()); m_add.set_alpha(color_source::ZERO); m_color.set_alpha(color_source::ONE); } else { m_color.set_alpha(m_add.alpha()); m_add.set_alpha(color_source::ZERO); m_multiply.set_alpha(color_source::ONE); } } // if the multiply is alpha and the add is RGB, combine if (m_multiply.is_rgb_zero() && m_add.is_alpha_zero()) { if (m_multiply.alpha() == m_add.rgb()) { m_multiply.set_rgb(m_add.rgb()); m_add.set_rgb(color_source::ZERO); m_color.set_rgb(color_source::ONE); } else { m_color.set_rgb(m_add.rgb()); m_add.set_rgb(color_source::ZERO); m_multiply.set_rgb(color_source::ONE); } } } } // if the alpha multiply is zero, it doesn't matter what the color/subtract alpha is if (m_multiply.is_alpha_zero()) { m_color.set_alpha(m_color.rgb()); m_subtract.set_alpha(m_subtract.rgb()); } if (m_multiply.is_rgb_zero()) { m_color.set_rgb(m_color.alpha()); m_subtract.set_rgb(m_subtract.alpha()); } // if color is zero and subtract is zero, that means the multiply is irrelevant if (m_color.is_zero() && m_subtract.is_zero()) m_multiply = color_source::zero; } //------------------------------------------------- // as_string - return a string version of the // equation //------------------------------------------------- std::string color_equation::as_string() const { // attempt to simplify // blend factor of zero ignores earlier stuff if (m_multiply.is_zero()) return m_add.as_string(); // blend multiply of one is an add if (m_multiply.is_one()) { std::string result = m_color.as_string(); if (!m_subtract.is_zero()) { result += " - "; result += m_subtract.as_string(); } if (!m_add.is_zero()) { result += " + "; result += m_add.as_string(); } return result; } // otherwise a proper blend std::string result; if (!m_subtract.is_zero()) result += "("; result += m_color.as_string(); if (!m_subtract.is_zero()) { result += " - "; result += m_subtract.as_string(); result += ")"; } result += " * "; result += m_multiply.as_string(); if (!m_add.is_zero()) { result += " + "; result += m_add.as_string(); } return result; } //------------------------------------------------- // from_fbzcp - compute the color equation based // on the fbs colorpath //------------------------------------------------- color_equation color_equation::from_fbzcp(reg_fbz_colorpath const fbzcp) { // determine other color color_source other_color; switch (fbzcp.cc_rgbselect()) { case 0: other_color.set_rgb(color_source::iterated_argb.rgb()); break; case 1: other_color.set_rgb(color_source::texel0.rgb()); break; case 2: other_color.set_rgb(color_source::color1.rgb()); break; } switch (fbzcp.cc_aselect()) { case 0: other_color.set_alpha(color_source::iterated_argb.alpha()); break; case 1: other_color.set_alpha(color_source::texel0.alpha()); break; case 2: other_color.set_alpha(color_source::color1.alpha()); break; } // determine local color color_source local_color; if (fbzcp.cc_localselect_override() == 0) local_color.set_rgb((fbzcp.cc_localselect() == 0) ? color_source::iterated_argb.rgb() : color_source::color0.rgb()); else local_color.set_rgb(color_source::COLOR0_OR_ITERATED_VIA_TEXEL_ALPHA); switch (fbzcp.cca_localselect()) { case 0: local_color.set_alpha(color_source::iterated_argb.alpha()); break; case 1: local_color.set_alpha(color_source::color0.alpha()); break; case 2: local_color.set_alpha(color_source::CLAMPZ); break; case 3: local_color.set_alpha(color_source::CLAMPW); break; } // select blend color color_equation equation; if (!fbzcp.cc_zero_other()) equation.color().set_rgb(other_color.rgb()); if (!fbzcp.cca_zero_other()) equation.color().set_alpha(other_color.alpha()); // determine subtraction color if (fbzcp.cc_sub_clocal()) equation.subtract().set_rgb(local_color.rgb()); if (fbzcp.cca_sub_clocal()) equation.subtract().set_alpha(local_color.alpha()); // determine blend factor switch (fbzcp.cc_mselect()) { case 1: equation.multiply().set_rgb(local_color.rgb()); break; case 2: equation.multiply().set_rgb_from_alpha(other_color.alpha()); break; case 3: equation.multiply().set_rgb_from_alpha(local_color.alpha()); break; case 4: equation.multiply().set_rgb_from_alpha(color_source::texel0.alpha()); break; case 5: /*if (type >= VOODOO_2)*/ equation.multiply().set_rgb(color_source::texel0.rgb()); break; } switch (fbzcp.cca_mselect()) { case 1: case 3: equation.multiply().set_alpha(local_color.alpha()); break; case 2: equation.multiply().set_alpha(other_color.alpha()); break; case 4: equation.multiply().set_alpha(color_source::texel0.alpha()); break; } if (!fbzcp.cc_reverse_blend()) equation.multiply().invert_rgb(); if (!fbzcp.cca_reverse_blend()) equation.multiply().invert_alpha(); // determine add color switch (fbzcp.cc_add_aclocal()) { case 1: equation.add().set_rgb(local_color.rgb()); break; case 2: equation.add().set_rgb_from_alpha(local_color.alpha()); break; } if (fbzcp.cca_add_aclocal()) equation.add().set_alpha(local_color.alpha()); equation.simplify(); return equation; } //------------------------------------------------- // from_texmode - compute the color equation based // on the fbs colorpath //------------------------------------------------- color_equation color_equation::from_texmode(reg_texture_mode const texmode, color_source texel_color, color_source input_color) { color_source other_color = input_color; color_source local_color = texel_color; color_equation equation; if (!texmode.tc_zero_other()) equation.color().set_rgb(other_color.rgb()); if (!texmode.tca_zero_other()) equation.color().set_alpha(other_color.alpha()); if (texmode.tc_sub_clocal()) equation.subtract().set_rgb(local_color.rgb()); if (texmode.tca_sub_clocal()) equation.subtract().set_alpha(local_color.alpha()); switch (texmode.tc_mselect()) { case 1: equation.multiply().set_rgb(local_color.rgb()); break; case 2: equation.multiply().set_rgb_from_alpha(other_color.alpha()); break; case 3: equation.multiply().set_rgb_from_alpha(local_color.alpha()); break; case 4: equation.multiply().set_rgb_from_alpha(color_source::DETAIL_FACTOR); break; case 5: equation.multiply().set_rgb_from_alpha(color_source::LOD_FRACTION); break; } switch (texmode.tca_mselect()) { case 1: case 3: equation.multiply().set_alpha(local_color.alpha()); break; case 2: equation.multiply().set_alpha(other_color.alpha()); break; case 4: equation.multiply().set_alpha(color_source::DETAIL_FACTOR); break; case 5: equation.multiply().set_alpha(color_source::LOD_FRACTION); break; } if (!texmode.tc_reverse_blend()) equation.multiply().invert_rgb(); if (!texmode.tca_reverse_blend()) equation.multiply().invert_alpha(); switch (texmode.tc_add_aclocal()) { case 1: equation.add().set_rgb(local_color.rgb()); break; case 2: equation.add().set_rgb_from_alpha(local_color.alpha()); break; } if (texmode.tca_add_aclocal()) equation.add().set_alpha(local_color.alpha()); equation.simplify(); return equation; } //************************************************************************** // RASTER TEXTURE //************************************************************************** //------------------------------------------------- // recompute - recompute state based on parameters //------------------------------------------------- void rasterizer_texture::recompute(voodoo_regs const &regs, u8 *ram, u32 mask, rgb_t const *lookup, u32 addrmask, u8 addrshift) { m_ram = ram; m_mask = mask; m_lookup = lookup; // extract LOD parameters auto const texlod = regs.texture_lod(); m_lodmin = texlod.lod_min() << 6; m_lodmax = texlod.lod_max() << 6; m_lodbias = s8(texlod.lod_bias() << 2) << 4; // determine which LODs are present m_lodmask = 0x1ff; if (texlod.lod_tsplit()) m_lodmask = texlod.lod_odd() ? 0x0aa : 0x155; // determine base texture width/height m_wmask = m_hmask = 0xff; if (texlod.lod_s_is_wider()) m_hmask >>= texlod.lod_aspect(); else m_wmask >>= texlod.lod_aspect(); // determine the bpp of the texture auto const texmode = regs.texture_mode(); int bppscale = texmode.format() >> 3; // start with the base of LOD 0 u32 base = regs.texture_baseaddr(); if (addrshift == 0 && BIT(base, 0) != 0) fatalerror("Unsupported tiled texture in Voodoo device"); base = (base & addrmask) << addrshift; m_lodoffset[0] = base & mask; // LODs 1-3 are different depending on whether we are in multitex mode // Several Voodoo 2 games leave the upper bits of TLOD == 0xff, meaning we think // they want multitex mode when they really don't -- disable for now // Enable for Voodoo 3 or Viper breaks - VL. // Add check for upper nibble not equal to zero to fix funkball -- TG if (texlod.tmultibaseaddr() && texlod.magic() == 0) { base = (regs.texture_baseaddr_1() & addrmask) << addrshift; m_lodoffset[1] = base & mask; base = (regs.texture_baseaddr_2() & addrmask) << addrshift; m_lodoffset[2] = base & mask; base = (regs.texture_baseaddr_3_8() & addrmask) << addrshift; m_lodoffset[3] = base & mask; } else { if (m_lodmask & (1 << 0)) base += (((m_wmask >> 0) + 1) * ((m_hmask >> 0) + 1)) << bppscale; m_lodoffset[1] = base & mask; if (m_lodmask & (1 << 1)) base += (((m_wmask >> 1) + 1) * ((m_hmask >> 1) + 1)) << bppscale; m_lodoffset[2] = base & mask; if (m_lodmask & (1 << 2)) base += (((m_wmask >> 2) + 1) * ((m_hmask >> 2) + 1)) << bppscale; m_lodoffset[3] = base & mask; } // remaining LODs make sense for (int lod = 4; lod <= 8; lod++) { if (m_lodmask & (1 << (lod - 1))) { u32 size = ((m_wmask >> (lod - 1)) + 1) * ((m_hmask >> (lod - 1)) + 1); if (size < 4) size = 4; base += size << bppscale; } m_lodoffset[lod] = base & mask; } // compute the detail parameters auto const texdetail = regs.texture_detail(); m_detailmax = texdetail.detail_max(); m_detailbias = s8(texdetail.detail_bias() << 2) << 6; m_detailscale = texdetail.detail_scale(); } //------------------------------------------------- // lookup_single_texel - look up the texel at the // given S,T coordinate based on the format and // return a decoded RGB value //------------------------------------------------- inline rgb_t rasterizer_texture::lookup_single_texel(u32 format, u32 texbase, s32 s, s32 t) { if (format < 8) return m_lookup[*(u8 *)&m_ram[(texbase + t + s) & m_mask]]; else if (format >= 10 && format <= 12) return m_lookup[*(u16 *)&m_ram[(texbase + 2*(t + s)) & m_mask]]; else { u32 texel = *(u16 *)&m_ram[(texbase + 2*(t + s)) & m_mask]; return (m_lookup[texel & 0xff] & 0xffffff) | ((texel & 0xff00) << 16); } } //------------------------------------------------- // fetch_texel - fetch the texel value based on // the S,T coordinates and LOD //------------------------------------------------- inline rgbaint_t ATTR_FORCE_INLINE rasterizer_texture::fetch_texel(reg_texture_mode const texmode, dither_helper const &dither, s32 x, double iters, double itert, double iterw, s32 &lod, u8 bilinear_mask) { // determine the S/T/LOD values for this texture; iterated S/T are // in 32.32 format and we want final S/T in 24.8 format s32 s, t; if (texmode.enable_perspective()) { // iterws is also 32.32, so division would leave no fractional bits; // the 256 factor is there to produce 8 bits of fraction double recip = 256.0 / iterw; s = s32(iters * recip); t = s32(itert * recip); // compute the log2 of the non-reciprocal W value; negating it gives // the log2 of the reciprocal, so we subtract instead of add it lod -= fast_log2(iterw, 32); } else { // scale the .32 values down to .8 values as doubles to avoid 64-bit // integers s = s32(iters * (1.0 / (1 << 24))); t = s32(itert * (1.0 / (1 << 24))); } // clamp S/T if the iterated W is negative if (texmode.clamp_neg_w() && iterw < 0) s = t = 0; // clamp the LOD after applying bias and dither lod += m_lodbias; if (texmode.enable_lod_dither()) lod += dither.raw_4x4(x) << 4; lod = std::clamp<s32>(lod, m_lodmin, m_lodmax); // now the LOD is in range; if we don't own this LOD, take the next one s32 ilod = lod >> 8; ilod += (~m_lodmask >> ilod) & 1; // fetch the texture base u32 texbase = m_lodoffset[ilod]; // compute the maximum s and t values at this LOD s32 smax = m_wmask >> ilod; s32 tmax = m_hmask >> ilod; // determine whether we are point-sampled or bilinear rgbaint_t result; if ((lod == m_lodmin && !texmode.magnification_filter()) || (lod != m_lodmin && !texmode.minification_filter())) { // incorporate the fraction shift into ilod ilod += 8; s >>= ilod; t >>= ilod; // clamp/wrap S/T if necessary if (texmode.clamp_s()) s = std::clamp(s, 0, smax); if (texmode.clamp_t()) t = std::clamp(t, 0, tmax); s &= smax; t &= tmax; t *= smax + 1; // fetch texel data result.set(lookup_single_texel(texmode.format(), texbase, s, t)); } else { // adjust S/T for the LOD and strip off all but the low 8 bits of the fraction s >>= ilod; t >>= ilod; // also subtract 1/2 texel so that (0.5,0.5) = a full (0,0) texel s -= 0x80; t -= 0x80; // extract the fractions u32 sfrac = s & bilinear_mask; u32 tfrac = t & bilinear_mask; // now toss the rest s >>= 8; t >>= 8; s32 s1 = s + 1; s32 t1 = t + 1; // clamp/wrap S/T if necessary if (texmode.clamp_s()) { if (s < 0) s = s1 = 0; else if (s >= smax) s = s1 = smax; } s &= smax; s1 &= smax; if (texmode.clamp_t()) { if (t < 0) t = t1 = 0; else if (t >= tmax) t = t1 = tmax; } t &= tmax; t1 &= tmax; t *= smax + 1; t1 *= smax + 1; // fetch texel data u32 texel0 = lookup_single_texel(texmode.format(), texbase, s, t); u32 texel1 = lookup_single_texel(texmode.format(), texbase, s1, t); u32 texel2 = lookup_single_texel(texmode.format(), texbase, s, t1); u32 texel3 = lookup_single_texel(texmode.format(), texbase, s1, t1); result.bilinear_filter_rgbaint(texel0, texel1, texel2, texel3, sfrac, tfrac); } return result; } //------------------------------------------------- // combine_texture - color combine unit for // texture pixels //------------------------------------------------- inline rgbaint_t ATTR_FORCE_INLINE rasterizer_texture::combine_texture(reg_texture_mode const texmode, rgbaint_t const &c_local, rgbaint_t const &c_other, s32 lod) { // select zero/other for RGB rgbaint_t blend_color; if (texmode.tc_zero_other()) blend_color.zero(); else blend_color.set(c_other); // select zero/other for alpha if (texmode.tca_zero_other()) blend_color.zero_alpha(); else blend_color.merge_alpha16(c_other); // subtract local color if (texmode.tc_sub_clocal() || texmode.tca_sub_clocal()) { rgbaint_t sub_val; // potentially subtract c_local if (!texmode.tc_sub_clocal()) sub_val.zero(); else sub_val.set(c_local); if (!texmode.tca_sub_clocal()) sub_val.zero_alpha(); else sub_val.merge_alpha16(c_local); blend_color.sub(sub_val); } // blend RGB rgbaint_t blend_factor; switch (texmode.tc_mselect()) { default: // reserved case 0: // zero blend_factor.zero(); break; case 1: // c_local blend_factor.set(c_local); break; case 2: // a_other blend_factor.set(c_other.select_alpha32()); break; case 3: // a_local blend_factor.set(c_local.select_alpha32()); break; case 4: // LOD (detail factor) if (m_detailbias <= lod) blend_factor.zero(); else { u8 tmp; tmp = (((m_detailbias - lod) << m_detailscale) >> 8); if (tmp > m_detailmax) tmp = m_detailmax; blend_factor.set_all(tmp); } break; case 5: // LOD fraction blend_factor.set_all(lod & 0xff); break; } // blend alpha switch (texmode.tca_mselect()) { default: // reserved case 0: // zero blend_factor.zero_alpha(); break; case 1: // c_local blend_factor.merge_alpha16(c_local); break; case 2: // a_other blend_factor.merge_alpha16(c_other); break; case 3: // a_local blend_factor.merge_alpha16(c_local); break; case 4: // LOD (detail factor) if (m_detailbias <= lod) blend_factor.zero_alpha(); else { u8 tmp; tmp = (((m_detailbias - lod) << m_detailscale) >> 8); if (tmp > m_detailmax) tmp = m_detailmax; blend_factor.set_a16(tmp); } break; case 5: // LOD fraction blend_factor.set_a16(lod & 0xff); break; } // reverse the RGB blend if (!texmode.tc_reverse_blend()) blend_factor.xor_imm_rgba(0, 0xff, 0xff, 0xff); // reverse the alpha blend if (!texmode.tca_reverse_blend()) blend_factor.xor_imm_rgba(0xff, 0, 0, 0); blend_factor.add_imm(1); // add clocal or alocal to RGB rgbaint_t add_val; switch (texmode.tc_add_aclocal()) { case 3: // reserved case 0: // nothing add_val.zero(); break; case 1: // add c_local add_val.set(c_local); break; case 2: // add_alocal add_val.set(c_local.select_alpha32()); break; } // add clocal or alocal to alpha if (!texmode.tca_add_aclocal()) add_val.zero_alpha(); else add_val.merge_alpha16(c_local); // scale add and clamp blend_color.scale_add_and_clamp(blend_factor, add_val); // invert if (texmode.tc_invert_output()) blend_color.xor_imm_rgba(0, 0xff, 0xff, 0xff); if (texmode.tca_invert_output()) blend_color.xor_imm_rgba(0xff, 0, 0, 0); return blend_color; } //************************************************************************** // RASTERIZER NCC TEXELS //************************************************************************** //------------------------------------------------- // recompute - constructor //------------------------------------------------- void rasterizer_palette::compute_ncc(u32 const *regs) { // generate all 256 possibilities u8 const *ybase = reinterpret_cast<u8 const *>(regs); for (int index = 0; index < 256; index++) { // start with the intensity s32 y = ybase[BYTE4_XOR_LE(BIT(index, 4, 4))]; // look up the I/Q values s32 i = regs[4 + BIT(index, 2, 2)]; s32 q = regs[8 + BIT(index, 0, 2)]; // add the coloring s32 r = std::clamp(y + (s32(i << 5) >> 23) + (s32(q << 5) >> 23), 0, 255); s32 g = std::clamp(y + (s32(i << 14) >> 23) + (s32(q << 14) >> 23), 0, 255); s32 b = std::clamp(y + (s32(i << 23) >> 23) + (s32(q << 23) >> 23), 0, 255); // fill in the table m_texel[index] = rgb_t(0xff, r, g, b); } } //************************************************************************** // VOODOO RENDERER //************************************************************************** //------------------------------------------------- // voodoo_renderer - constructor //------------------------------------------------- voodoo_renderer::voodoo_renderer(running_machine &machine, u16 tmu_config, const rgb_t *rgb565, voodoo_regs &fbi_regs, voodoo_regs *tmu0_regs, voodoo_regs *tmu1_regs) : poly_manager(machine), m_bilinear_mask(0xf0), m_tmu_config(tmu_config), m_rowpixels(0), m_yorigin(0), m_fbi_reg(fbi_regs), m_tmu0_reg(tmu0_regs), m_tmu1_reg(tmu1_regs), m_rgb565(rgb565), m_fogdelta_mask(0xff), m_thread_stats(WORK_MAX_THREADS) { // empty the hash table std::fill(std::begin(m_raster_hash), std::end(m_raster_hash), nullptr); // register our arrays register_poly_array(m_textures); register_poly_array(m_palettes); // add all predefined rasterizers for (static_rasterizer_info const *info = s_predef_raster_table; info->params.generic() != 0xffffffff; info++) add_rasterizer(info->params, info->mfp, false); // create entries for the generic rasterizers as well rasterizer_params dummy_params; for (int index = 0; index < std::size(m_generic_rasterizer); index++) m_generic_rasterizer[index] = add_rasterizer(dummy_params, generic_rasterizer(index), true); } //------------------------------------------------- // register_save - register for saving states //------------------------------------------------- void voodoo_renderer::register_save(save_proxy &save) { save.save_item(NAME(m_rowpixels)); save.save_item(NAME(m_yorigin)); save.save_item(NAME(m_fogblend)); save.save_item(NAME(m_fogdelta)); } //------------------------------------------------- // alloc_poly - allocate a new poly_data object // and compute the raster parameters //------------------------------------------------- poly_data &voodoo_renderer::alloc_poly() { // allocate poly data and compute the rasterization parameters poly_data &poly = object_data().next(); poly.raster.compute(m_fbi_reg, m_tmu0_reg, m_tmu1_reg); return poly; } //------------------------------------------------- // enqueue_fastfill - enqueue a fastfill operation // using a custom renderer //------------------------------------------------- u32 voodoo_renderer::enqueue_fastfill(poly_data &poly) { // if we're not clearing anything, take no time auto const fbzmode = poly.raster.fbzmode(); if (!fbzmode.rgb_buffer_mask() && !fbzmode.aux_buffer_mask()) return 0; // generate a dither pattern if clearing the RGB buffer if (fbzmode.rgb_buffer_mask()) { for (int y = 0; y < 4; y++) { dither_helper dither(y, fbzmode); for (int x = 0; x < 4; x++) poly.dither[y * 4 + x] = dither.pixel(x, poly.color1); } } // create a block of 64 identical extents vertex_t v1(poly.clipleft, poly.cliptop); vertex_t v2(poly.clipright, poly.clipbottom); return render_tile<0>(global_cliprect, render_delegate(&voodoo_renderer::rasterizer_fastfill, this), v1, v2); } //------------------------------------------------- // enqueue_triangle - enqueue a triangle //------------------------------------------------- u32 voodoo_renderer::enqueue_triangle(poly_data &poly, vertex_t const *vert) { // compute the hash of the raster parameters u32 fullhash = poly.raster.hash(); u32 hash = fullhash % RASTER_HASH_SIZE; // find the appropriate hash entry rasterizer_info *prev = nullptr; rasterizer_info *info; for (info = m_raster_hash[hash]; info != nullptr; prev = info, info = info->next) if (info->fullhash == fullhash && info->params == poly.raster) { // got it, move us to the head of the list if (prev != nullptr) { prev->next = info->next; info->next = m_raster_hash[hash]; m_raster_hash[hash] = info; } break; } // determine the index of the generic rasterizer if (info == nullptr) { // add a new one if we're logging usage if (LOG_RASTERIZERS) info = add_rasterizer(poly.raster, generic_rasterizer(poly.raster.generic()), true); else info = m_generic_rasterizer[poly.raster.generic()]; } // set the info and render the triangle info->polys++; poly.info = info; return render_triangle<0>(global_cliprect, poly.info->callback, vert[0], vert[1], vert[2]); } //------------------------------------------------- // stipple_test - test against the stipple // pattern; the enable flag is not checked here, // so must be checked by the caller //------------------------------------------------- inline bool ATTR_FORCE_INLINE voodoo_renderer::stipple_test(thread_stats_block &threadstats, reg_fbz_mode const fbzmode, s32 x, s32 scry, u32 &stipple) { // rotate mode if (fbzmode.stipple_pattern() == 0) { stipple = (stipple >> 1) | (stipple << 31); if (s32(stipple) >= 0) { threadstats.stipple_count++; return false; } } // pattern mode else { int stipple_index = ((scry & 3) << 3) | (~x & 7); if (BIT(stipple, stipple_index) == 0) { threadstats.stipple_count++; return false; } } return true; } //------------------------------------------------- // compute_depthval - compute the value for depth // according to the configured flags //------------------------------------------------- inline s32 ATTR_FORCE_INLINE voodoo_renderer::compute_depthval(poly_data const &poly, reg_fbz_mode const fbzmode, reg_fbz_colorpath const fbzcp, s32 wfloat, s32 iterz) { s32 result; if (fbzmode.wbuffer_select()) { if (!fbzmode.depth_float_select()) result = wfloat; else if ((iterz & 0xf0000000) != 0) result = 0x0000; else if ((iterz & 0x0ffff000) == 0) result = 0xffff; else { int exp = count_leading_zeros_32(iterz) - 4; return ((exp << 12) | ((iterz >> (15 - exp)) ^ 0x1fff)) + 1; } } else result = clamped_z(iterz, fbzcp); if (fbzmode.enable_depth_bias()) result = std::clamp(result + s16(poly.zacolor), 0, 0xffff); return result; } //------------------------------------------------- // depth_test - perform depth testing; the enable // flag is not checked here, so must be checked by // the caller //------------------------------------------------- inline bool ATTR_FORCE_INLINE voodoo_renderer::depth_test(thread_stats_block &threadstats, reg_fbz_mode const fbzmode, s32 depthdest, s32 depthsource) { // test against the depth buffer switch (fbzmode.depth_function()) { case 0: // depthOP = never threadstats.zfunc_fail++; return false; case 1: // depthOP = less than if (depthsource >= depthdest) { threadstats.zfunc_fail++; return false; } break; case 2: // depthOP = equal if (depthsource != depthdest) { threadstats.zfunc_fail++; return false; } break; case 3: // depthOP = less than or equal if (depthsource > depthdest) { threadstats.zfunc_fail++; return false; } break; case 4: // depthOP = greater than if (depthsource <= depthdest) { threadstats.zfunc_fail++; return false; } break; case 5: // depthOP = not equal if (depthsource == depthdest) { threadstats.zfunc_fail++; return false; } break; case 6: // depthOP = greater than or equal if (depthsource < depthdest) { threadstats.zfunc_fail++; return false; } break; case 7: // depthOP = always break; } return true; } //------------------------------------------------- // combine_color - core color combining logic //------------------------------------------------- inline bool ATTR_FORCE_INLINE voodoo_renderer::combine_color(rgbaint_t &color, thread_stats_block &threadstats, poly_data const &poly, reg_fbz_colorpath const fbzcp, reg_fbz_mode const fbzmode, rgbaint_t texel, s32 iterz, s64 iterw, rgb_t chromakey) { // compute c_other rgbaint_t c_other; switch (fbzcp.cc_rgbselect()) { case 0: // iterated RGB c_other.set(color); break; case 1: // texture RGB c_other.set(texel); break; case 2: // color1 RGB c_other.set(poly.color1); break; default: // reserved - voodoo3 LFB RGB c_other.zero(); break; } // handle chroma key if (fbzmode.enable_chromakey()) if (!chroma_key_test(threadstats, c_other, chromakey)) return false; // compute a_other switch (fbzcp.cc_aselect()) { case 0: // iterated alpha c_other.merge_alpha16(color); break; case 1: // texture alpha c_other.merge_alpha16(texel); break; case 2: // color1 alpha c_other.set_a16(poly.color1.a()); break; default: // reserved - voodoo3 LFB Alpha c_other.zero_alpha(); break; } // handle alpha mask if (fbzmode.enable_alpha_mask()) if (!alpha_mask_test(threadstats, c_other.get_a())) return false; // compute c_local rgbaint_t c_local; if (fbzcp.cc_localselect_override() == 0) { if (fbzcp.cc_localselect() == 0) // iterated RGB c_local.set(color); else // color0 RGB c_local.set(poly.color0); } else { if (!(texel.get_a() & 0x80)) // iterated RGB c_local.set(color); else // color0 RGB c_local.set(poly.color0); } // compute a_local switch (fbzcp.cca_localselect()) { default: case 0: // iterated alpha c_local.merge_alpha16(color); break; case 1: // color0 alpha c_local.set_a16(poly.color0.a()); break; case 2: // clamped iterated Z[27:20] c_local.set_a16(u8(clamped_z(iterz, fbzcp) >> 8)); break; case 3: // clamped iterated W[39:32] (Voodoo 2 only) c_local.set_a16(u8(clamped_w(iterw, fbzcp))); break; } // select zero or c_other rgbaint_t blend_color; if (fbzcp.cc_zero_other()) blend_color.zero(); else blend_color.set(c_other); // select zero or a_other if (fbzcp.cca_zero_other()) blend_color.zero_alpha(); else blend_color.merge_alpha16(c_other); // subtract a/c_local if (fbzcp.cc_sub_clocal() || fbzcp.cca_sub_clocal()) { rgbaint_t sub_val; if (!fbzcp.cc_sub_clocal()) sub_val.zero(); else sub_val.set(c_local); if (!fbzcp.cca_sub_clocal()) sub_val.zero_alpha(); else sub_val.merge_alpha16(c_local); blend_color.sub(sub_val); } // blend RGB rgbaint_t blend_factor; switch (fbzcp.cc_mselect()) { default: // reserved case 0: // 0 blend_factor.zero(); break; case 1: // c_local blend_factor.set(c_local); break; case 2: // a_other blend_factor.set(c_other.select_alpha32()); break; case 3: // a_local blend_factor.set(c_local.select_alpha32()); break; case 4: // texture alpha blend_factor.set(texel.select_alpha32()); break; case 5: // texture RGB (Voodoo 2 only) blend_factor.set(texel); break; } // blend alpha switch (fbzcp.cca_mselect()) { default: // reserved case 0: // 0 blend_factor.zero_alpha(); break; case 1: // a_local case 3: // a_local blend_factor.merge_alpha16(c_local); break; case 2: // a_other blend_factor.merge_alpha16(c_other); break; case 4: // texture alpha blend_factor.merge_alpha16(texel); break; } // reverse the RGB blend if (!fbzcp.cc_reverse_blend()) blend_factor.xor_imm_rgba(0, 0xff, 0xff, 0xff); // reverse the alpha blend if (!fbzcp.cca_reverse_blend()) blend_factor.xor_imm_rgba(0xff, 0, 0, 0); // add clocal or alocal to RGB rgbaint_t add_val; switch (fbzcp.cc_add_aclocal()) { case 3: // reserved case 0: // nothing add_val.zero(); break; case 1: // add c_local add_val.set(c_local); break; case 2: // add_alocal add_val.set(c_local.select_alpha32()); break; } // add clocal or alocal to alpha if (!fbzcp.cca_add_aclocal()) add_val.zero_alpha(); else add_val.merge_alpha16(c_local); // add and clamp blend_factor.add_imm(1); blend_color.scale_add_and_clamp(blend_factor, add_val); // invert if (fbzcp.cca_invert_output()) blend_color.xor_imm_rgba(0xff, 0, 0, 0); if (fbzcp.cc_invert_output()) blend_color.xor_imm_rgba(0, 0xff, 0xff, 0xff); color.set(blend_color); return true; } //------------------------------------------------- // alpha_mask_test - perform alpha mask testing; // the enable flag is not checked here, so must // be checked by the caller //------------------------------------------------- inline bool ATTR_FORCE_INLINE voodoo_renderer::alpha_mask_test(thread_stats_block &threadstats, u32 alpha) { if ((alpha & 1) == 0) { threadstats.afunc_fail++; return false; } return true; } //------------------------------------------------- // alpha_test - perform alpha testing; the enable // flag is not checked here, so must be checked // by the caller //------------------------------------------------- inline bool ATTR_FORCE_INLINE voodoo_renderer::alpha_test(thread_stats_block &threadstats, reg_alpha_mode const alphamode, u32 alpha, u32 alpharef) { switch (alphamode.alphafunction()) { case 0: // alphaOP = never threadstats.afunc_fail++; return false; case 1: // alphaOP = less than if (alpha >= alpharef) { threadstats.afunc_fail++; return false; } break; case 2: // alphaOP = equal if (alpha != alpharef) { threadstats.afunc_fail++; return false; } break; case 3: // alphaOP = less than or equal if (alpha > alpharef) { threadstats.afunc_fail++; return false; } break; case 4: // alphaOP = greater than if (alpha <= alpharef) { threadstats.afunc_fail++; return false; } break; case 5: // alphaOP = not equal if (alpha == alpharef) { threadstats.afunc_fail++; return false; } break; case 6: // alphaOP = greater than or equal if (alpha < alpharef) { threadstats.afunc_fail++; return false; } break; case 7: // alphaOP = always break; } return true; } //------------------------------------------------- // chroma_key_test - perform chroma key testing; // the enable flag is not checked here, so must // be checked by the caller //------------------------------------------------- inline bool ATTR_FORCE_INLINE voodoo_renderer::chroma_key_test(thread_stats_block &threadstats, rgbaint_t const &colorin, rgb_t chromakey) { rgb_t color = colorin.to_rgba(); // non-range version auto const chromarange = m_fbi_reg.chroma_range(); if (!chromarange.enable()) { if (((color ^ chromakey) & 0xffffff) == 0) { threadstats.chroma_fail++; return false; } } // tricky range version else { s32 low, high, test; int results; // check blue low = chromakey.b(); high = chromarange.blue(); test = color.b(); results = (test >= low && test <= high); results ^= chromarange.blue_exclusive(); results <<= 1; // check green low = chromakey.g(); high = chromarange.green(); test = color.g(); results |= (test >= low && test <= high); results ^= chromarange.green_exclusive(); results <<= 1; // check red low = chromakey.r(); high = chromarange.red(); test = color.r(); results |= (test >= low && test <= high); results ^= chromarange.red_exclusive(); // final result if (chromarange.union_mode()) { if (results != 0) { threadstats.chroma_fail++; return false; } } else { if (results == 7) { threadstats.chroma_fail++; return false; } } } return true; } //------------------------------------------------- // apply_fogging - perform fogging; the enable // flag is not checked here, so must be checked by // the caller //------------------------------------------------- inline void ATTR_FORCE_INLINE voodoo_renderer::apply_fogging(rgbaint_t &color, rgb_t fogcolor, u32 depthbias, reg_fbz_mode const fbzmode, reg_fog_mode const fogmode, reg_fbz_colorpath const fbzcp, s32 x, dither_helper const &dither, s32 wfloat, s32 iterz, s64 iterw, rgbaint_t const &iterargb) { // constant fog bypasses everything else rgbaint_t fog_color_local(fogcolor); if (fogmode.fog_constant()) { // if fog_mult is 0, we add this to the original color if (fogmode.fog_mult() == 0) { fog_color_local.add(color); fog_color_local.clamp_to_uint8(); } } // non-constant fog comes from several sources else { s32 fogblend = 0; // if fog_add is zero, we start with the fog color if (fogmode.fog_add()) fog_color_local.zero(); // if fog_mult is zero, we subtract the incoming color // Need to check this, manual states 9 bits if (!fogmode.fog_mult()) fog_color_local.sub(color); // fog blending mode switch (fogmode.fog_zalpha()) { case 0: // fog table { s32 fog_depth = wfloat; // add the bias for fog selection if (fbzmode.enable_depth_bias()) fog_depth = std::clamp(fog_depth + s16(depthbias), 0, 0xffff); // perform the multiply against lower 8 bits of wfloat s32 delta = m_fogdelta[fog_depth >> 10]; s32 deltaval = (delta & m_fogdelta_mask) * ((fog_depth >> 2) & 0xff); // fog zones allow for negating this value if (fogmode.fog_zones() && (delta & 2)) deltaval = -deltaval; deltaval >>= 6; // apply dither if (fogmode.fog_dither()) deltaval += dither.raw_4x4(x); deltaval >>= 4; // add to the blending factor fogblend = m_fogblend[fog_depth >> 10] + deltaval; break; } case 1: // iterated A fogblend = iterargb.get_a(); break; case 2: // iterated Z fogblend = clamped_z(iterz, fbzcp) >> 8; break; case 3: // iterated W - Voodoo 2 only fogblend = clamped_w(iterw, fbzcp); break; } // perform the blend fogblend++; // if fog_mult is 0, we add this to the original color fog_color_local.scale_imm_and_clamp(s16(fogblend)); if (fogmode.fog_mult() == 0) { fog_color_local.add(color); fog_color_local.clamp_to_uint8(); } } fog_color_local.merge_alpha16(color); color.set(fog_color_local); } //------------------------------------------------- // alpha_blend - perform alpha blending; the // enable flag is not checked here, so must be // checked by the caller //------------------------------------------------- inline void ATTR_FORCE_INLINE voodoo_renderer::alpha_blend(rgbaint_t &color, reg_fbz_mode const fbzmode, reg_alpha_mode const alphamode, s32 x, dither_helper const &dither, int dpix, u16 *depth, rgbaint_t const &prefog) { // extract destination pixel rgbaint_t dst_color(m_rgb565[dpix]); int da = 0xff; if (fbzmode.enable_alpha_planes()) dst_color.set_a16(da = depth[x]); // apply dither subtraction if (fbzmode.alpha_dither_subtract()) { int dith = dither.subtract(x); dst_color.add_imm_rgba(0, dith, dith >> 1, dith); } // compute source portion int sa = color.get_a(); int ta; rgbaint_t src_scale; switch (alphamode.srcrgbblend()) { default: // reserved case 0: // AZERO src_scale.zero(); break; case 1: // ASRC_ALPHA ta = sa + 1; src_scale.set_all(ta); break; case 2: // A_COLOR src_scale = dst_color; src_scale.add_imm(1); break; case 3: // ADST_ALPHA ta = da + 1; src_scale.set_all(ta); break; case 4: // AONE src_scale.set_all(256); break; case 5: // AOMSRC_ALPHA ta = 0x100 - sa; src_scale.set_all(ta); break; case 6: // AOM_COLOR src_scale.set_all(0x100); src_scale.sub(dst_color); break; case 7: // AOMDST_ALPHA ta = 0x100 - da; src_scale.set_all(ta); break; case 15: // ASATURATE ta = 0x100 - da; if (sa < ta) ta = sa; ta++; src_scale.set_all(ta); break; } // set src_scale alpha int src_alpha_scale = (alphamode.srcalphablend() == 4) ? 256 : 0; src_scale.set_a16(src_alpha_scale); // add in dest portion rgbaint_t dst_scale; switch (alphamode.dstrgbblend()) { default: // reserved case 0: // AZERO dst_scale.zero(); break; case 1: // ASRC_ALPHA ta = sa + 1; dst_scale.set_all(ta); break; case 2: // A_COLOR dst_scale.set(color); dst_scale.add_imm(1); break; case 3: // ADST_ALPHA ta = da + 1; dst_scale.set_all(ta); break; case 4: // AONE dst_scale.set_all(256); break; case 5: // AOMSRC_ALPHA ta = 0x100 - sa; dst_scale.set_all(ta); break; case 6: // AOM_COLOR dst_scale.set_all(0x100); dst_scale.sub(color); break; case 7: // AOMDST_ALPHA ta = 0x100 - da; dst_scale.set_all(ta); break; case 15: // A_COLORBEFOREFOG dst_scale.set(prefog); dst_scale.add_imm(1); break; } // set dst_scale alpha int dest_alpha_scale = (alphamode.dstalphablend() == 4) ? 256 : 0; dst_scale.set_a16(dest_alpha_scale); // main blend color.scale2_add_and_clamp(src_scale, dst_color, dst_scale); } //------------------------------------------------- // write_pixel - write the pixel to the // destination buffer, and the depth to the depth // buffer //------------------------------------------------- inline void ATTR_FORCE_INLINE voodoo_renderer::write_pixel(thread_stats_block &threadstats, reg_fbz_mode const fbzmode, dither_helper const &dither, u16 *destbase, u16 *depthbase, s32 x, rgbaint_t const &color, s32 depthval) { // write to framebuffer if (fbzmode.rgb_buffer_mask()) destbase[x] = dither.pixel(x, color); // write to aux buffer if (fbzmode.aux_buffer_mask()) { if (fbzmode.enable_alpha_planes() == 0) depthbase[x] = depthval; else depthbase[x] = color.get_a(); } // track pixel writes to the frame buffer regardless of mask threadstats.pixels_out++; } //------------------------------------------------- // pixel_pipeline - run a pixel through the // pipeline //------------------------------------------------- void voodoo_renderer::pixel_pipeline(thread_stats_block &threadstats, u16 *dest, u16 *depth, s32 x, s32 scry, rgb_t src_color, u16 sz) { threadstats.pixels_in++; // apply clipping auto const fbzmode = m_fbi_reg.fbz_mode(); if (fbzmode.enable_clipping()) { if (x < m_fbi_reg.clip_left() || x >= m_fbi_reg.clip_right() || scry < m_fbi_reg.clip_top() || scry >= m_fbi_reg.clip_bottom()) { threadstats.clip_fail++; return; } } // handle stippling if (fbzmode.enable_stipple()) { u32 stipple = m_fbi_reg.stipple(); if (!stipple_test(threadstats, fbzmode, x, scry, stipple)) return; } // Depth testing value for lfb pipeline writes is directly from write data, no biasing is used s32 depthval = u32(sz); // Perform depth testing if (fbzmode.enable_depthbuf() && !depth_test(threadstats, fbzmode, depth[x], (fbzmode.depth_source_compare() == 0) ? depthval : u16(m_fbi_reg.za_color()))) return; // use the RGBA we stashed above rgbaint_t color(src_color); // handle chroma key if (fbzmode.enable_chromakey() && !chroma_key_test(threadstats, color, m_fbi_reg.chroma_key().argb())) return; // handle alpha mask if (fbzmode.enable_alpha_mask() && !alpha_mask_test(threadstats, color.get_a())) return; // handle alpha test auto const alphamode = m_fbi_reg.alpha_mode(); if (alphamode.alphatest() && !alpha_test(threadstats, alphamode, color.get_a(), alphamode.alpharef())) return; // perform fogging auto const fogmode = m_fbi_reg.fog_mode(); dither_helper dither(scry, fbzmode, fogmode); rgbaint_t prefog(color); if (fogmode.enable_fog()) { s32 iterz = sz << 12; s64 iterw = m_fbi_reg.lfb_mode().write_w_select() ? u32(m_fbi_reg.za_color() << 16) : u32(sz << 16); apply_fogging(color, m_fbi_reg.fog_color().argb(), m_fbi_reg.za_color(), fbzmode, fogmode, m_fbi_reg.fbz_colorpath(), x, dither, depthval, iterz, iterw, rgbaint_t(0)); } // wait for any outstanding work to finish wait("pixel_pipeline"); // perform alpha blending if (alphamode.alphablend()) alpha_blend(color, fbzmode, alphamode, x, dither, dest[x], depth, prefog); // pixel pipeline part 2 handles final output write_pixel(threadstats, fbzmode, dither, dest, depth, x, color, depthval); } //------------------------------------------------- // rasterizer - core scanline rasterizer //------------------------------------------------- template<u32 GenericFlags, u32 FbzCp, u32 FbzMode, u32 AlphaMode, u32 FogMode, u32 TexMode0, u32 TexMode1> void voodoo_renderer::rasterizer(s32 y, const voodoo_renderer::extent_t &extent, const poly_data &poly, int threadid) { thread_stats_block &threadstats = m_thread_stats[threadid]; reg_texture_mode const texmode0(TexMode0, (GenericFlags & rasterizer_params::GENERIC_TEX0) ? poly.raster.texmode0() : 0); reg_texture_mode const texmode1(TexMode1, (GenericFlags & rasterizer_params::GENERIC_TEX1) ? poly.raster.texmode1() : 0); reg_fbz_colorpath const fbzcp(FbzCp, poly.raster.fbzcp()); reg_alpha_mode const alphamode(AlphaMode, poly.raster.alphamode()); reg_fbz_mode const fbzmode(FbzMode, poly.raster.fbzmode()); reg_fog_mode const fogmode(FogMode, poly.raster.fogmode()); double iters0, itert0, iterw0, iters1, itert1, iterw1; double deltas0, deltat0, deltaw0, deltas1, deltat1, deltaw1; u32 stipple = poly.stipple; // determine the screen Y s32 scry = y; if (fbzmode.y_origin()) scry = m_yorigin - y; // pre-increment the pixels_in unconditionally s32 startx = extent.startx; s32 stopx = extent.stopx; threadstats.pixels_in += stopx - startx; // apply clipping if (fbzmode.enable_clipping()) { // Y clipping buys us the whole scanline if (scry < poly.cliptop || scry >= poly.clipbottom) { threadstats.clip_fail += stopx - startx; return; } // X clipping s32 tempclip = poly.clipright; // check for start outsize of clipping boundary if (startx >= tempclip) { threadstats.clip_fail += stopx - startx; return; } // clip the right side if (stopx > tempclip) { threadstats.clip_fail += stopx - tempclip; stopx = tempclip; } // clip the left side tempclip = poly.clipleft; if (startx < tempclip) { threadstats.clip_fail += tempclip - startx; startx = tempclip; } } // get pointers to the target buffer and depth buffer u16 *dest = poly.destbase + scry * m_rowpixels; u16 *depth = poly.depthbase + scry * m_rowpixels; // compute the starting parameters s32 dx = startx - (poly.ax >> 4); s32 dy = y - (poly.ay >> 4); s32 iterr = (poly.startr + dy * poly.drdy + dx * poly.drdx) << 8; s32 iterg = (poly.startg + dy * poly.dgdy + dx * poly.dgdx) << 8; s32 iterb = (poly.startb + dy * poly.dbdy + dx * poly.dbdx) << 8; s32 itera = (poly.starta + dy * poly.dady + dx * poly.dadx) << 8; rgbaint_t iterargb, iterargb_delta; iterargb.set(itera, iterr, iterg, iterb); iterargb_delta.set(poly.dadx, poly.drdx, poly.dgdx, poly.dbdx); iterargb_delta.shl_imm(8); s32 iterz = poly.startz + dy * poly.dzdy + dx * poly.dzdx; s64 iterw = (poly.startw + dy * poly.dwdy + dx * poly.dwdx) << 16; s64 iterw_delta = poly.dwdx << 16; s32 lodbase0 = 0; if (GenericFlags & rasterizer_params::GENERIC_TEX0) { deltas0 = double(poly.ds0dx); deltat0 = double(poly.dt0dx); deltaw0 = double(poly.dw0dx); iters0 = double(poly.starts0 + dy * poly.ds0dy + dx * poly.ds0dx); itert0 = double(poly.startt0 + dy * poly.dt0dy + dx * poly.dt0dx); iterw0 = double(poly.startw0 + dy * poly.dw0dy + dx * poly.dw0dx); lodbase0 = compute_lodbase(poly.ds0dx, poly.ds0dy, poly.dt0dx, poly.dt0dy); } s32 lodbase1 = 0; if (GenericFlags & rasterizer_params::GENERIC_TEX1) { deltas1 = double(poly.ds1dx); deltat1 = double(poly.dt1dx); deltaw1 = double(poly.dw1dx); iters1 = double(poly.starts1 + dy * poly.ds1dy + dx * poly.ds1dx); itert1 = double(poly.startt1 + dy * poly.dt1dy + dx * poly.dt1dx); iterw1 = double(poly.startw1 + dy * poly.dw1dy + dx * poly.dw1dx); lodbase1 = compute_lodbase(poly.ds1dx, poly.ds1dy, poly.dt1dx, poly.dt1dy); } poly.info->scanlines++; // loop in X dither_helper dither(scry, fbzmode, fogmode); for (s32 x = startx; x < stopx; x++) { do { // handle stippling if (fbzmode.enable_stipple() && !stipple_test(threadstats, fbzmode, x, scry, stipple)) break; // compute "floating point" W value (used for depth and fog) s32 wfloat = compute_wfloat(iterw); // compute depth value (W or Z) for this pixel s32 depthval = compute_depthval(poly, fbzmode, fbzcp, wfloat, iterz); // depth testing if (fbzmode.enable_depthbuf() && !depth_test(threadstats, fbzmode, depth[x], (fbzmode.depth_source_compare() == 0) ? depthval : u16(poly.zacolor))) break; // run the texture pipeline on TMU1 to produce a value in texel rgbaint_t texel(0); if (GenericFlags & rasterizer_params::GENERIC_TEX1) { s32 lod1 = lodbase1; rgbaint_t texel_t1 = poly.tex1->fetch_texel(texmode1, dither, x, iters1, itert1, iterw1, lod1, m_bilinear_mask); if (GenericFlags & rasterizer_params::GENERIC_TEX1_IDENTITY) texel = texel_t1; else texel = poly.tex1->combine_texture(texmode1, texel_t1, texel, lod1); } // run the texture pipeline on TMU0 to produce a final result in texel if (GenericFlags & rasterizer_params::GENERIC_TEX0) { // the seq_8_downld flag is repurposed in the rasterizer to indicate // we should send the configuration byte if (!texmode0.seq_8_downld()) { s32 lod0 = lodbase0; rgbaint_t texel_t0 = poly.tex0->fetch_texel(texmode0, dither, x, iters0, itert0, iterw0, lod0, m_bilinear_mask); if (GenericFlags & rasterizer_params::GENERIC_TEX0_IDENTITY) texel = texel_t0; else texel = poly.tex0->combine_texture(texmode0, texel_t0, texel, lod0); } else texel.set(m_tmu_config); } // colorpath pipeline selects source colors and does blending rgbaint_t color = clamped_argb(iterargb, fbzcp); if (!combine_color(color, threadstats, poly, fbzcp, fbzmode, texel, iterz, iterw, poly.chromakey)) break; // handle alpha test if (alphamode.alphatest() && !alpha_test(threadstats, alphamode, color.get_a(), poly.alpharef)) break; // perform fogging rgbaint_t prefog(color); if (fogmode.enable_fog()) apply_fogging(color, poly.fogcolor, poly.zacolor, fbzmode, fogmode, fbzcp, x, dither, wfloat, iterz, iterw, iterargb); // perform alpha blending if (alphamode.alphablend()) alpha_blend(color, fbzmode, alphamode, x, dither, dest[x], depth, prefog); // store the pixel and depth value write_pixel(threadstats, fbzmode, dither, dest, depth, x, color, depthval); } while (0); // update the iterated parameters iterargb += iterargb_delta; iterz += poly.dzdx; iterw += iterw_delta; if (GenericFlags & rasterizer_params::GENERIC_TEX0) { iters0 += deltas0; itert0 += deltat0; iterw0 += deltaw0; } if (GenericFlags & rasterizer_params::GENERIC_TEX1) { iters1 += deltas1; itert1 += deltat1; iterw1 += deltaw1; } } } //------------------------------------------------- // rasterizer_fastfill - custom scanline // rasterizer for fastfill operations //------------------------------------------------- void voodoo_renderer::rasterizer_fastfill(s32 y, const voodoo_renderer::extent_t &extent, const poly_data &poly, int threadid) { thread_stats_block &threadstats = m_thread_stats[threadid]; auto const fbzmode = poly.raster.fbzmode(); s32 startx = extent.startx; s32 stopx = extent.stopx; int x; // determine the screen Y s32 scry = y; if (fbzmode.y_origin()) scry = m_yorigin - y; // fill this RGB row if (fbzmode.rgb_buffer_mask()) { const u16 *ditherow = &poly.dither[(y & 3) * 4]; u64 expanded = *(u64 *)ditherow; u16 *dest = poly.destbase + scry * m_rowpixels; for (x = startx; x < stopx && (x & 3) != 0; x++) dest[x] = ditherow[x & 3]; for ( ; x < (stopx & ~3); x += 4) *(u64 *)&dest[x] = expanded; for ( ; x < stopx; x++) dest[x] = ditherow[x & 3]; threadstats.pixels_out += stopx - startx; } // fill this dest buffer row if (fbzmode.aux_buffer_mask() && poly.depthbase != nullptr) { u16 depth = poly.zacolor; u64 expanded = (u64(depth) << 48) | (u64(depth) << 32) | (u64(depth) << 16) | u64(depth); u16 *dest = poly.depthbase + scry * m_rowpixels; for (x = startx; x < stopx && (x & 3) != 0; x++) dest[x] = depth; for ( ; x < (stopx & ~3); x += 4) *(u64 *)&dest[x] = expanded; for ( ; x < stopx; x++) dest[x] = depth; } } //------------------------------------------------- // generic_rasterizer - return a pointer to a // generic rasterizer based on a texture enable // mask //------------------------------------------------- voodoo_renderer::rasterizer_mfp voodoo_renderer::generic_rasterizer(u8 texmask) { switch (texmask & 15) { default: case 0: return &voodoo_renderer::rasterizer<0, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; case 1: return &voodoo_renderer::rasterizer<1, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; case 2: return &voodoo_renderer::rasterizer<2, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; case 3: return &voodoo_renderer::rasterizer<3, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; case 4: return &voodoo_renderer::rasterizer<4, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; case 5: return &voodoo_renderer::rasterizer<5, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; case 6: return &voodoo_renderer::rasterizer<6, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; case 7: return &voodoo_renderer::rasterizer<7, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; case 8: return &voodoo_renderer::rasterizer<8, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; case 9: return &voodoo_renderer::rasterizer<9, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; case 10: return &voodoo_renderer::rasterizer<10, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; case 11: return &voodoo_renderer::rasterizer<11, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; case 12: return &voodoo_renderer::rasterizer<12, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::NONE>; case 13: return &voodoo_renderer::rasterizer<13, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::NONE>; case 14: return &voodoo_renderer::rasterizer<14, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::NONE, reg_texture_mode::DECODE_LIVE>; case 15: return &voodoo_renderer::rasterizer<15, reg_fbz_colorpath::DECODE_LIVE, reg_fbz_mode::DECODE_LIVE, reg_alpha_mode::DECODE_LIVE, reg_fog_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE, reg_texture_mode::DECODE_LIVE>; } } //------------------------------------------------- // add_rasterizer - add a rasterizer to our // hash table //------------------------------------------------- rasterizer_info *voodoo_renderer::add_rasterizer(rasterizer_params const &params, rasterizer_mfp rasterizer, bool is_generic) { rasterizer_info &info = m_rasterizer_list.emplace_back(); // fill in the data info.next = nullptr; info.callback = voodoo_renderer::render_delegate(rasterizer, this); info.display = 0; info.is_generic = is_generic; info.scanlines = 0; info.polys = 0; info.fullhash = params.hash(); info.params = params; // hook us into the hash table u32 hash = info.fullhash % RASTER_HASH_SIZE; if (!is_generic || LOG_RASTERIZERS) { info.next = m_raster_hash[hash]; m_raster_hash[hash] = &info; } if (LOG_RASTERIZERS && params.fbzcp().raw() != 0) { osd_printf_info("Adding rasterizer : gen=%02X cp=%08X am=%08X fog=%08X fbz=%08X tm0=%08X tm1=%08X (hash=%d)\n", params.generic(), params.fbzcp().raw(), params.alphamode().raw(), params.fogmode().raw(), params.fbzmode().raw(), params.texmode0().raw(), params.texmode1().raw(), hash); // explicitly recompute the equations since static rasterizers don't have them rasterizer_params computed(params); computed.compute_equations(); osd_printf_info(" Color: %s\n", computed.colorpath_equation().as_string().c_str()); if (computed.generic() & rasterizer_params::GENERIC_TEX0) { if (computed.generic() & rasterizer_params::GENERIC_TEX0_IDENTITY) osd_printf_info(" Tex0: Identity\n"); else osd_printf_info(" Tex0: %s\n", computed.tex0_equation().as_string().c_str()); } if (computed.generic() & rasterizer_params::GENERIC_TEX1) { if (computed.generic() & rasterizer_params::GENERIC_TEX1_IDENTITY) osd_printf_info(" Tex1: Identity\n"); else osd_printf_info(" Tex1: %s\n", computed.tex1_equation().as_string().c_str()); } } return &info; } //------------------------------------------------- // dump_rasterizer_stats - dump statistics on // the current rasterizer usage patterns //------------------------------------------------- void voodoo_renderer::dump_rasterizer_stats() { if (!LOG_RASTERIZERS) return; static u8 display_index; rasterizer_info *cur, *best; int hash; osd_printf_info("----\n"); display_index++; // loop until we've displayed everything while (1) { best = nullptr; // find the highest entry for (hash = 0; hash < RASTER_HASH_SIZE; hash++) for (cur = m_raster_hash[hash]; cur != nullptr; cur = cur->next) if (cur->display != display_index && (best == nullptr || cur->scanlines > best->scanlines)) best = cur; // if we're done, we're done if (best == nullptr || best->scanlines == 0) break; // print it osd_printf_info("%s RASTERIZER( 0x%02X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) // %8d %10d\n", best->is_generic ? " " : "// ", best->params.generic(), best->params.fbzcp().raw(), best->params.alphamode().raw(), best->params.fogmode().raw(), best->params.fbzmode().raw(), best->params.texmode0().raw(), best->params.texmode1().raw(), best->polys, best->scanlines); // reset best->display = display_index; } } //************************************************************************** // GAME-SPECIFIC RASTERIZERS //************************************************************************** #define RASTERIZER(generic, fbzcp, alpha, fog, fbz, tex0, tex1) \ { &voodoo_renderer::rasterizer<generic, fbzcp, fbz, alpha, fog, tex0, tex1>, rasterizer_params(generic, fbzcp, alpha, fog, fbz, tex0, tex1) }, static_rasterizer_info s_predef_raster_table[] = { // wg3dh RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000000DF, 0xFFFFFFFF ) // 3286099 20381549 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000009F, 0xFFFFFFFF ) // 2489030 17200373 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 3014599 13488668 // RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 698012 11525474 // RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x00000ADF, 0xFFFFFFFF ) // 119292 6768046 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 218912 6316948 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000089F, 0xFFFFFFFF ) // 176840 6033269 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x0000005F, 0xFFFFFFFF ) // 272493 1528924 RASTERIZER( 0x05, 0x00480035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 11590 1026235 // mace RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 6375980 96752762 RASTERIZER( 0x05, 0x00602401, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 877666 12853963 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 537316 12467938 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 674113 11249705 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 371317 9571618 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000008F, 0xFFFFFFFF ) // 682233 9124733 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x000000CF, 0xFFFFFFFF ) // 498471 8420845 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 90032 5376303 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0000080F, 0xFFFFFFFF ) // 107465 5176593 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x00000ADF, 0xFFFFFFFF ) // 13184 5007304 // sfrush RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000001F ) // 1355672 19357520 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 1297788 14089416 RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000081F ) // 607380 12402671 RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000001F ) // 665621 10647858 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x000000DF, 0xFFFFFFFF ) // 714734 10358977 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 708263 9010666 RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000081F ) // 187026 4932870 RASTERIZER( 0x0A, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0xFFFFFFFF, 0x000000DF ) // 45383 4310253 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 308972 3302296 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0379, 0x0000001F, 0xFFFFFFFF ) // 285502 2946170 RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x082708DF, 0x0000001F ) // 443667 2634580 // RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 112446 2477427 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 195197 2339499 RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x082708DF, 0x0000001F ) // 365543 2303916 // sfrushrk // RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000001F ) // 1419527 23908786 // RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 963906 14481970 RASTERIZER( 0x0A, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0xFFFFFFFF, 0x0000001F ) // 174421 10184608 // RASTERIZER( 0x0B, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x00000000, 0x0000081F ) // 384547 7885615 // RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x000000DF, 0xFFFFFFFF ) // 244858 4208409 RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 206798 3960712 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000001, 0x000B0779, 0x000008DF, 0xFFFFFFFF ) // 153642 3621111 // RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000001F, 0xFFFFFFFF ) // 108089 3590760 // RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0x0000081F, 0xFFFFFFFF ) // 219585 2909829 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000001, 0x000B0379, 0x0000001F, 0xFFFFFFFF ) // 187042 2805524 RASTERIZER( 0x0A, 0x00600C09, 0x00045119, 0x00000001, 0x000B0779, 0xFFFFFFFF, 0x000000DF ) // 25554 2515514 // calspeed RASTERIZER( 0x05, 0x01022819, 0x00000009, 0x00000001, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 4701502 50735847 RASTERIZER( 0x05, 0x01022819, 0x00000009, 0x00000001, 0x000B073B, 0x0000000F, 0xFFFFFFFF ) // 1634191 24047354 RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0000080F, 0xFFFFFFFF ) // 742857 14056518 RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 1299926 12893822 RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0000080F, 0xFFFFFFFF ) // 543774 11318818 RASTERIZER( 0x05, 0x00002815, 0x00045119, 0x00000001, 0x000B07F9, 0x0000000F, 0xFFFFFFFF ) // 40320 5118555 RASTERIZER( 0x05, 0x01022C19, 0x00000009, 0x00000001, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 227824 3146670 RASTERIZER( 0x05, 0x01022C19, 0x00000009, 0x00000001, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 35644 2681027 RASTERIZER( 0x00, 0x0102001A, 0x00045119, 0x00000001, 0x000A0321, 0xFFFFFFFF, 0xFFFFFFFF ) // 24976 2363490 RASTERIZER( 0x05, 0x00602819, 0x00045119, 0x00000001, 0x000B07F9, 0x0000080F, 0xFFFFFFFF ) // 28316 2004570 // vaportrx RASTERIZER( 0x05, 0x00482405, 0x00000000, 0x00000000, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 1446198 21480806 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0739, 0x000000CF, 0xFFFFFFFF ) // 1707856 9876920 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x000000C9, 0xFFFFFFFF ) // 739894 9863144 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0339, 0x00000ACF, 0xFFFFFFFF ) // 460944 9848421 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B07F9, 0x00000ACF, 0xFFFFFFFF ) // 219658 4982710 RASTERIZER( 0x05, 0x00482405, 0x00000009, 0x00000000, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 268313 4748332 RASTERIZER( 0x05, 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x0000000F, 0xFFFFFFFF ) // 283627 3457853 RASTERIZER( 0x05, 0x00482435, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 34206 2494986 RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x00000000, 0x000B0339, 0x0000000F, 0xFFFFFFFF ) // 153391 2048929 // blitz RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 5465143 29568854 RASTERIZER( 0x05, 0x00002C35, 0x00515110, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 671263 19501211 RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 239790 17412073 RASTERIZER( 0x05, 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x000000C9, 0xFFFFFFFF ) // 1174048 13394869 RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x00000A0F, 0xFFFFFFFF ) // 781255 6391702 RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 47802 3412779 RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 79490 3088491 RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 15232 2566323 RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 177716 2320638 RASTERIZER( 0x05, 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 18686 1741744 // blitz99 RASTERIZER( 0x05, 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 5757356 35675229 // RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 270977 16139833 // RASTERIZER( 0x05, 0x00002C35, 0x64515119, 0x00000000, 0x000B0799, 0x00000A0F, 0xFFFFFFFF ) // 869068 7819874 // RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 57874 5309214 // RASTERIZER( 0x05, 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x000000C9, 0xFFFFFFFF ) // 380688 4597915 // RASTERIZER( 0x05, 0x00006136, 0x40515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 18141 2099641 // RASTERIZER( 0x05, 0x00002C35, 0x40515119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 92655 1928223 // RASTERIZER( 0x05, 0x00002C35, 0x40515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 131380 1908198 // RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 86764 1760469 RASTERIZER( 0x05, 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 189197 1504639 // blitz2k // RASTERIZER( 0x05, 0x00000035, 0x00000009, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 5486749 33668808 // RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 275360 15899691 // RASTERIZER( 0x05, 0x00002C35, 0x00515119, 0x00000000, 0x000B0799, 0x00000A0F, 0xFFFFFFFF ) // 801050 7476260 // RASTERIZER( 0x05, 0x01422439, 0x00000000, 0x00000000, 0x000B073B, 0x000000C9, 0xFFFFFFFF ) // 461364 5981963 // RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 93786 5079967 RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000000, 0x000B073B, 0x00000ACF, 0xFFFFFFFF ) // 16252 2943314 RASTERIZER( 0x05, 0x00002C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 200589 2563939 // RASTERIZER( 0x05, 0x00006136, 0x00515119, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 18221 2335412 // RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 90486 2212467 // carnevil RASTERIZER( 0x05, 0x00002425, 0x00045119, 0x00000000, 0x00030679, 0x00000A0F, 0xFFFFFFFF ) // 420627 4298755 RASTERIZER( 0x05, 0x00002435, 0x00045119, 0x00000000, 0x000302F9, 0x0000080F, 0xFFFFFFFF ) // 112660 2916676 RASTERIZER( 0x05, 0x00002435, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 36468 735846 RASTERIZER( 0x05, 0x00000035, 0x08045119, 0x00000000, 0x000306F9, 0x00000AC9, 0xFFFFFFFF ) // 6996 212717 RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x00000000, 0x00030679, 0x00000A0F, 0xFFFFFFFF ) // 754 190433 // hyprdriv RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 146568 18142019 RASTERIZER( 0x05, 0x01422C19, 0x00000000, 0x00000001, 0x000B073B, 0x00000A0F, 0xFFFFFFFF ) // 771521 12744098 RASTERIZER( 0x05, 0x00582435, 0x00515110, 0x00000001, 0x000B0739, 0x00000AC9, 0xFFFFFFFF ) // 997666 12173827 RASTERIZER( 0x00, 0x0142612A, 0x00000000, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) // 2064812 11818083 RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 67518 8476957 RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x00000A0F, 0xFFFFFFFF ) // 3404038 8059738 RASTERIZER( 0x00, 0x0142611A, 0x00045110, 0x00000001, 0x000B0739, 0xFFFFFFFF, 0xFFFFFFFF ) // 797160 3625519 RASTERIZER( 0x05, 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x00000A1F, 0xFFFFFFFF ) // 154937 3337816 RASTERIZER( 0x05, 0x00582C35, 0x00515110, 0x00000001, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 19770 2887063 RASTERIZER( 0x05, 0x01420039, 0x00000000, 0x00000001, 0x000B073B, 0x0000000F, 0xFFFFFFFF ) // 392772 2654749 RASTERIZER( 0x05, 0x01422429, 0x00000000, 0x00000001, 0x000B073B, 0x0000001F, 0xFFFFFFFF ) // 101694 2333476 RASTERIZER( 0x05, 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x00000A1F, 0xFFFFFFFF ) // 152748 2258208 RASTERIZER( 0x05, 0x00580035, 0x00000000, 0x00000001, 0x000B073B, 0x0000001F, 0xFFFFFFFF ) // 164822 2100196 // gauntleg RASTERIZER( 0x0B, 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 1846512 77235960 RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 1733863 14067084 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x0000004F, 0xFFFFFFFF ) // 1517970 13213493 // RASTERIZER( 0x05, 0x00600C09, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 2449825 12337057 RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000000F ) // 193539 10327282 RASTERIZER( 0x0B, 0x00600039, 0x00045119, 0x00000000, 0x000B0779, 0x0C22480F, 0x00000ACF ) // 173388 5900312 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000004F ) // 272048 5557244 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x00000A4F ) // 38452 4404158 RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000080F ) // 93156 4365283 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x00000A4F, 0xFFFFFFFF ) // 51416 3857019 RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 220103 2783489 // gauntdl RASTERIZER( 0x0B, 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 4613022 100488623 RASTERIZER( 0x0B, 0x0060743A, 0x00045110, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 2989550 50643553 RASTERIZER( 0x0B, 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x00000ACF ) // 741940 22885885 RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 2843876 16209403 RASTERIZER( 0x0B, 0x0060743A, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22488F, 0x00000ACF ) // 349018 11700233 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x000000CF, 0xFFFFFFFF ) // 798144 7819799 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x000008CF ) // 217622 7362228 RASTERIZER( 0x0B, 0x00602439, 0x00044110, 0x00000000, 0x000B0379, 0x00000009, 0x0000000F ) // 111605 6859677 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x00000ACF ) // 42994 6006533 RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 1174759 5414174 RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000009, 0x0000000F ) // 1358847 5366960 RASTERIZER( 0x05, 0x00602C19, 0x00045110, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 1317912 5103516 // warfa RASTERIZER( 0x0B, 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000ACF ) // 5549270 83260187 // RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 2450037 34142048 RASTERIZER( 0x0B, 0x00602419, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22400F, 0x00000A0F ) // 1406309 22020895 RASTERIZER( 0x05, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 3121611 13535796 RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000000, 0x0000000F ) // 3821464 12671381 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x104008CF, 0x000008CF ) // 1045140 10170316 RASTERIZER( 0x0B, 0x00602439, 0x00044119, 0x000000C1, 0x000B0779, 0x0582480F, 0x0000080F ) // 43674 7349020 // RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x00000000, 0x000B0779, 0x00000000, 0x0000000F ) // 864570 6795448 RASTERIZER( 0x0B, 0x00602C19, 0x00045119, 0x000000C1, 0x000B0779, 0x00000000, 0x0000080F ) // 531132 6584618 RASTERIZER( 0x0B, 0x00602439, 0x00045119, 0x000000C1, 0x000B0779, 0x0C22480F, 0x00000ACF ) // 169887 6529727 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x10400ACF, 0x000008CF ) // 420204 5602132 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x000000C1, 0x000B0779, 0x104000CF, 0x000008CF ) // 306432 4918886 // RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 5627690 79723246 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x00000A0F, 0xFFFFFFFF ) // 250480 17957361 RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000000F, 0x0000000F ) // 4264955 17065131 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 789463 11602094 RASTERIZER( 0x0B, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x000008CF ) // 452695 11374291 RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0000080F ) // 2219901 10964372 RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x0000000F ) // 2985476 10576909 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 430488 6729680 RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x000008CF, 0x000008CF ) // 317486 5192722 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 551185 3395443 RASTERIZER( 0x0B, 0x00602409, 0x00045119, 0x00000000, 0x000B0779, 0x0000088F, 0x0000080F ) // 276296 3024329 // nbashowt RASTERIZER( 0x05, 0x00002C35, 0x00045119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 12589303 89992094 RASTERIZER( 0x05, 0x00002435, 0x00045119, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 528689 41431369 RASTERIZER( 0x05, 0x00002C35, 0x00045119, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 4346462 21676464 RASTERIZER( 0x05, 0x00002C35, 0x00044110, 0x00000000, 0x000A0321, 0x00000A0F, 0xFFFFFFFF ) // 1311258 15990693 RASTERIZER( 0x05, 0x00582435, 0x00045110, 0x00000000, 0x000B0739, 0x00000AC9, 0xFFFFFFFF ) // 498752 8603534 // RASTERIZER( 0x05, 0x00000035, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 262625 8248367 RASTERIZER( 0x05, 0x00582C35, 0x00045110, 0x00000000, 0x000B0739, 0x00000ACF, 0xFFFFFFFF ) // 146310 7881711 RASTERIZER( 0x05, 0x01424039, 0x00045110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 353983 6698613 RASTERIZER( 0x05, 0x01422439, 0x00044119, 0x00000000, 0x000A0321, 0x00000A0F, 0xFFFFFFFF ) // 105456 5867982 // sf2049 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000000F, 0xFFFFFFFF ) // 4535144 87108835 RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x000008CF, 0xFFFFFFFF ) // 3460768 36622999 RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x000000CF, 0xFFFFFFFF ) // 1167220 12527933 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x000008CF, 0xFFFFFFFF ) // 294802 12127575 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000088F, 0xFFFFFFFF ) // 192929 11588013 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0000080F, 0xFFFFFFFF ) // 322059 10421128 RASTERIZER( 0x03, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x0A452A0F, 0x0E47200F ) // 1449341 8868943 RASTERIZER( 0x05, 0x00482435, 0x00045117, 0x000000C1, 0x000B0339, 0x0000000F, 0xFFFFFFFF ) // 874920 7250149 RASTERIZER( 0x05, 0x00482435, 0x00045119, 0x000000C1, 0x000B0339, 0x0000000F, 0xFFFFFFFF ) // 874920 6973439 RASTERIZER( 0x05, 0x00602401, 0x00045119, 0x000000C1, 0x00030279, 0x00000A0F, 0xFFFFFFFF ) // 453774 6485154 RASTERIZER( 0x05, 0x00602409, 0x00045119, 0x000000C1, 0x000B0779, 0x00000A0F, 0xFFFFFFFF ) // 220733 5697617 RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x000B0379, 0x0000000F, 0xFFFFFFFF ) // 348786 4416017 // cartfury RASTERIZER( 0x05, 0x00000035, 0x00045119, 0x000000C1, 0x00030F39, 0x00000A0F, 0xFFFFFFFF ) // 3719502 47429534 RASTERIZER( 0x05, 0x00420039, 0x00000000, 0x000000C1, 0x00030F39, 0x0000000F, 0xFFFFFFFF ) // 4821876 25433268 RASTERIZER( 0x05, 0x0142A409, 0x00000000, 0x000000C1, 0x00030F3B, 0x00000ACF, 0xFFFFFFFF ) // 1704143 16287730 RASTERIZER( 0x05, 0x00580035, 0x00045119, 0x000000C1, 0x00030B39, 0x00000A0F, 0xFFFFFFFF ) // 576134 13181152 RASTERIZER( 0x05, 0x0142A409, 0x00000000, 0x00000000, 0x00030B39, 0x00000A0F, 0xFFFFFFFF ) // 2447036 13056499 RASTERIZER( 0x05, 0x00420039, 0x00000000, 0x00000000, 0x00030F39, 0x00000A0F, 0xFFFFFFFF ) // 1597651 11909086 RASTERIZER( 0x05, 0x00422439, 0x00000000, 0x000000C1, 0x00030F3B, 0x00000A0F, 0xFFFFFFFF ) // 1100912 11879195 RASTERIZER( 0x05, 0x00420039, 0x00000000, 0x00000000, 0x00030F3B, 0x00000A0F, 0xFFFFFFFF ) // 1714391 11199323 RASTERIZER( 0x05, 0x00582435, 0x00045110, 0x00000000, 0x00030BF9, 0x000000C9, 0xFFFFFFFF ) // 975518 11030280 // gradius4 RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030BFB, 0x00000AC7, 0xFFFFFFFF ) // 1261361 78858051 RASTERIZER( 0x05, 0x0000303A, 0x00004119, 0x00000000, 0x00030BFB, 0x000000C7, 0xFFFFFFFF ) // 398143 72518712 RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x00000A87, 0xFFFFFFFF ) // 1716273 15992169 RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 812651 15723260 RASTERIZER( 0x05, 0x00582435, 0x00005119, 0x00000000, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 595637 13777035 RASTERIZER( 0x05, 0x00000015, 0x00005119, 0x00000000, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 675880 12288373 RASTERIZER( 0x00, 0x02422E12, 0x00005119, 0x00000000, 0x00030F7B, 0xFFFFFFFF, 0xFFFFFFFF ) // 404825 10544497 RASTERIZER( 0x05, 0x00000005, 0x00005119, 0x00000000, 0x00030FFB, 0x00000AC7, 0xFFFFFFFF ) // 444690 6872107 RASTERIZER( 0x00, 0x02420002, 0x00000009, 0x00000000, 0x00030F7B, 0xFFFFFFFF, 0xFFFFFFFF ) // 5455064 5726069 RASTERIZER( 0x05, 0x00580021, 0x00005119, 0x00000000, 0x00030FFB, 0x00000AC7, 0xFFFFFFFF ) // 242000 5057019 // nbapbp RASTERIZER( 0x05, 0x00426E19, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 2926955 28637513 RASTERIZER( 0x05, 0x00424219, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 607076 17008880 RASTERIZER( 0x05, 0x00422809, 0x00004610, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 562460 12415476 RASTERIZER( 0x05, 0x02004219, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC1, 0xFFFFFFFF ) // 79809 7045963 RASTERIZER( 0x05, 0x02004219, 0x00000000, 0x00000001, 0x00030B7B, 0x00000AC7, 0xFFFFFFFF ) // 94254 6047743 RASTERIZER( 0x05, 0x00006E19, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 352375 4465810 RASTERIZER( 0x05, 0x00422A19, 0x00004610, 0x00000001, 0x00030BFB, 0x00000AC7, 0xFFFFFFFF ) // 58835 3500582 RASTERIZER( 0x05, 0x00004219, 0x00000000, 0x00000001, 0x00030F7B, 0x00000AC7, 0xFFFFFFFF ) // 176291 2268659 RASTERIZER( 0x05, 0x00424219, 0x00000000, 0x00000001, 0x00030B7B, 0x00000AC7, 0xFFFFFFFF ) // 13304 2250402 // virtpool RASTERIZER( 0x05, 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 494481 13370166 RASTERIZER( 0x05, 0x00002421, 0x00000000, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 45923 3905828 RASTERIZER( 0x05, 0x00002425, 0x00445110, 0x00000000, 0x000B07F9, 0x00000A0F, 0xFFFFFFFF ) // 57946 3043998 RASTERIZER( 0x05, 0x00482405, 0x00045110, 0x00000000, 0x000B0739, 0x00000A0F, 0xFFFFFFFF ) // 235221 962382 RASTERIZER( 0x05, 0x00002421, 0x00000000, 0x00000000, 0x000B0739, 0x00000A09, 0xFFFFFFFF ) // 12297 930523 // gtfore01 RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x00010F79, 0x00000ACD, 0xFFFFFFFF ) // 807566 29151846 RASTERIZER( 0x0B, 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x00000A0D ) // 2116043 18259224 RASTERIZER( 0x0B, 0x00002429, 0x00000000, 0x000000C1, 0x00010FF9, 0x00000A09, 0x00000A0F ) // 43784 3594532 RASTERIZER( 0x0B, 0x00002425, 0x00045110, 0x000000C1, 0x00010FF9, 0x00000ACD, 0x00000ACD ) // 14899 1391390 // gtfore02 RASTERIZER( 0x0B, 0x00002425, 0x00045119, 0x000000C1, 0x00010F79, 0x0C224A0D, 0x00000ACD ) // 776841 12879143 // gtfore06 RASTERIZER( 0x05, 0x00482405, 0x00045119, 0x000000C1, 0x00010FF9, 0x00000ACD, 0xFFFFFFFF ) // 51144 2582597 { nullptr, rasterizer_params(0xffffffff) } }; }