Nugget
Loading...
Searching...
No Matches
gte-kernels.hh
Go to the documentation of this file.
1/*
2
3MIT License
4
5Copyright (c) 2023 PCSX-Redux authors
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26
27#pragma once
28
29#include <stdint.h>
30
31namespace psyqo {
32
33namespace GTE {
34
46namespace Kernels {
47
48// Shift factor: Unsigned (no change) or Shifted (>> 12)
49enum SF : unsigned { Unshifted, Shifted };
50// Low limit: Unlimited (-2^15) or Limited (0)
51enum LM : unsigned { Unlimited, Limited };
52
53// Coordinate and Perspective Transformation
54
55// RTPS - Perspective Transformation (single)
56// pers(([rt]·[v0]) >> 12 + [tr]) -> sxy2
57// 14 cycles
58static inline void rtps() {
59#ifndef PS1_PC_PORT
60 asm volatile("cop2 0x0180001");
61#endif
62}
63
64// RTPT - Perspective Transformation (triple)
65// pers(([rt]·[v0]) >> 12 + [tr]) -> sxy0
66// pers(([rt]·[v1]) >> 12 + [tr]) -> sxy1
67// pers(([rt]·[v2]) >> 12 + [tr]) -> sxy2
68// 22 cycles
69static inline void rtpt() {
70#ifndef PS1_PC_PORT
71 asm volatile("cop2 0x0280030");
72#endif
73}
74
75// Depth Queuing
76
77// DCPL - Depth Cue Color light
78// (1 - dp)·[rgb·sv] + dp·[fc] -> rgb, lv, sv
79// 8 cycles
80static inline void dpcl() {
81#ifndef PS1_PC_PORT
82 asm volatile("cop2 0x0680029");
83#endif
84}
85
86// DPCS - Depth Cueing (single)
87// (1 - dp)·[rgb] + dp·[fc] -> rgb, lv, sv
88// 8 cycles
89static inline void dpcs() {
90#ifndef PS1_PC_PORT
91 asm volatile("cop2 0x0780010");
92#endif
93}
94
95// DPCT - Depth Cueing (triple)
96// (1 - dp)·[rgb0] + dp·[fc] -> rgb0, lv, sv
97// (1 - dp)·[rgb1] + dp·[fc] -> rgb1, lv, sv
98// (1 - dp)·[rgb2] + dp·[fc] -> rgb2, lv, sv
99// 17 cycles
100static inline void dpct() {
101#ifndef PS1_PC_PORT
102 asm volatile("cop2 0x0f8002a");
103#endif
104}
105
106// INTPL - Interpolation of a vector and far color
107// (1 - dp)·[sv] + dp·[fc] -> rgb2, lv, sv
108// 8 cycles
109static inline void intpl() {
110#ifndef PS1_PC_PORT
111 asm volatile("cop2 0x0980011");
112#endif
113}
114
115// Termwise Vector Square
116// [sv.x² >> 12, sv.y² >> 12, sv.z² >> 12] -> lv, sv
117// 5 cycles
118template <SF sf = Shifted>
119static inline void sqr() {
120#ifndef PS1_PC_PORT
121 if constexpr (sf == Shifted) {
122 asm volatile("cop2 0x0a80428");
123 } else {
124 asm volatile("cop2 0x0a00428");
125 }
126#endif
127}
128
129// Light Source Calculations
130
131// NCS - Normal color (single)
132// limit(([ll]·[v0]) >> 12) -> sv
133// limit(([lc]·[sv]) >> 12) + [bk] -> rgb2
134// 14 cycles
135static inline void ncs() {
136#ifndef PS1_PC_PORT
137 asm volatile("cop2 0x0c8041e");
138#endif
139}
140
141// NCT - Normal color (triple)
142// limit(([ll]·[v0]) >> 12) -> sv
143// limit(([lc]·[sv]) >> 12) + [bk] -> rgb0
144// limit(([ll]·[v1]) >> 12) -> sv
145// limit(([lc]·[sv]) >> 12) + [bk] -> rgb1
146// limit(([ll]·[v2]) >> 12) -> sv
147// limit(([lc]·[sv]) >> 12) + [bk] -> rgb2
148// 30 cycles
149static inline void nct() {
150#ifndef PS1_PC_PORT
151 asm volatile("cop2 0x0d80420");
152#endif
153}
154
155// NCDS - Normal color depth cue (single vector)
156// limit(([ll]·[v0]) >> 12) -> sv
157// limit(([lc]·[sv]) >> 12) + [bk] -> sv
158// (1 - dp)·[rgb·sv] + dp·[fc] -> rgb2
159// 19 cycles
160static inline void ncds() {
161#ifndef PS1_PC_PORT
162 asm volatile("cop2 0x0e80413");
163#endif
164}
165
166// NCDT - Normal color depth cue (triple vectors)
167// limit(([ll]·[v0]) >> 12) -> sv
168// limit(([lc]·[sv]) >> 12) + [bk] -> sv
169// (1 - dp)·[rgb·sv] + dp·[fc] -> rgb0
170// limit(([ll]·[v1]) >> 12) -> sv
171// limit(([lc]·[sv]) >> 12) + [bk] -> sv
172// (1 - dp)·[rgb·sv] + dp·[fc] -> rgb1
173// limit(([ll]·[v2]) >> 12) -> sv
174// limit(([lc]·[sv]) >> 12) + [bk] -> sv
175// (1 - dp)·[rgb·sv] + dp·[fc] -> rgb2
176// 44 cycles
177static inline void ncdt() {
178#ifndef PS1_PC_PORT
179 asm volatile("cop2 0x0f80416");
180#endif
181}
182
183// NCCS - Normal Color Color (single vector)
184// limit(([ll]·[v0]) >> 12) -> sv
185// limit(([lc]·[sv]) >> 12) + [bk] -> sv
186// [rgb·sv] -> rgb2
187// 17 cycles
188static inline void nccs() {
189#ifndef PS1_PC_PORT
190 asm volatile("cop2 0x0108041b");
191#endif
192}
193
194// NCCT - Normal Color Color (triple vector)
195// limit(([ll]·[v0]) >> 12) -> sv
196// limit(([lc]·[sv]) >> 12) + [bk] -> sv
197// [rgb·sv] -> rgb0
198// limit(([ll]·[v1]) >> 12) -> sv
199// limit(([lc]·[sv]) >> 12) + [bk] -> sv
200// [rgb·sv] -> rgb1
201// limit(([ll]·[v2]) >> 12) -> sv
202// limit(([lc]·[sv]) >> 12) + [bk] -> sv
203// [rgb·sv] -> rgb2
204// 39 cycles
205static inline void ncct() {
206#ifndef PS1_PC_PORT
207 asm volatile("cop2 0x0118043f");
208#endif
209}
210
211// Color Depth Que
212// limit(([lc]·[sv]) >> 12) + [bk] -> sv
213// (1 - dp)·[rgb·sv] + dp·[fc] -> rgb2
214// 13 cycles
215static inline void cdp() {
216#ifndef PS1_PC_PORT
217 asm volatile("cop2 0x01280414");
218#endif
219}
220
221// Color Color
222// limit(([lc]·[sv]) >> 12) + [bk] -> sv
223// [rgb·sv] -> rgb2
224// 11 cycles
225static inline void cc() {
226#ifndef PS1_PC_PORT
227 asm volatile("cop2 0x0138041c");
228#endif
229}
230
231// NCLIP - Normal clipping
232// sx0*sy1 + sx1*sy2 + sx2*sy0 - sx0*sy2 - sx1*sy0 - sx2*sy1 -> opz
233// aka determinant of the matrix
234// [sx1 - sx0, sy1 - sy0]
235// [sx2 - sx0, sy2 - sy0]
236// 8 cycles
237static inline void nclip() {
238#ifndef PS1_PC_PORT
239 asm volatile("cop2 0x01400006");
240#endif
241}
242
243// Z Average
244
245// AVSZ3 - Average of three Z values (for Triangles)
246// zsf3 * (sz0 + sz1 + sz2) -> otz
247// 5 cycles
248static inline void avsz3() {
249#ifndef PS1_PC_PORT
250 asm volatile("cop2 0x0158002d");
251#endif
252}
253
254// AVSZ4 - Average of four Z values (for Quads)
255// zsf4 * (sz0 + sz1 + sz2 + sz4) -> otz
256// 6 cycles
257static inline void avsz4() {
258#ifndef PS1_PC_PORT
259 asm volatile("cop2 0x0168002e");
260#endif
261}
262
263// Cross Product (improperly named Outer Product in Sony's lingo)
264// rt.22 * ir3 - rt.33 * ir2 -> ir1
265// rt.33 * ir1 - rt.11 * ir3 -> ir2
266// rt.11 * ir2 - rt.22 * ir1 -> ir3
267// 6 cycles
268template <SF sf = Shifted>
269static inline void cp() {
270#ifndef PS1_PC_PORT
271 if constexpr (sf == Shifted) {
272 asm volatile("cop2 0x0178000c");
273 } else {
274 asm volatile("cop2 0x0170000c");
275 }
276#endif
277}
278
279// General Interpolation
280
281// General purpose interpolation
282// dp·[sv] -> lv, sv
283// 5 cycles
284template <SF sf = Shifted>
285static inline void gpf() {
286#ifndef PS1_PC_PORT
287 if constexpr (sf == Shifted) {
288 asm volatile("cop2 0x0198003d");
289 } else {
290 asm volatile("cop2 0x0190003d");
291 }
292#endif
293}
294
295// General purpose interpolation with base
296// [lv] + dp·[sv] -> lv, sv
297// 5 cycles
298template <SF sf = Shifted>
299static inline void gpl() {
300#ifndef PS1_PC_PORT
301 if constexpr (sf == Shifted) {
302 asm volatile("cop2 0x01a8003e");
303 } else {
304 asm volatile("cop2 0x01a0003e");
305 }
306#endif
307}
308
309// All of the MVMVA operations take 8 cycles to complete.
310// The MVMVA operation is the basis for the matrix math operations.
311// The functions defined right underneath are simply aliases. They
312// are provided for convenience, as programmers may know them from
313// the original PS1 SDK documentation, but using the MVMVA operation
314// directly may actually be more readable.
315
316// Multiplication Matrix: Rotation, Light Source Direction, Light Source Color
317enum class MX : unsigned { RT, LL, LC };
318// Multiplication Vector
319enum class MV : unsigned { V0, V1, V2, IR };
320// Translation Vector: Translation, Back Color, Front Color, Zero
321enum class TV : unsigned { TR, BK, FC, Zero };
322
323// Multiply vector by matrix and add vector
324template <MX mx, MV v, TV cv = TV::Zero, SF sf = Shifted, LM lm = Unlimited>
325void mvmva() {
326#ifndef PS1_PC_PORT
327 constexpr uint32_t op =
328 (4 << 20) | (sf << 19) | (uint32_t(mx) << 17) | (uint32_t(v) << 15) | (uint32_t(cv) << 13) | (lm << 10) | 18;
329 asm volatile("cop2 %0" : : "i"(op));
330#endif
331}
332
333// Coordinate Conversion, Light Source Calculations
334// ([rt]·[v0]) >> 12 + [tr] -> lv, sv
335static inline void rt() { mvmva<MX::RT, MV::V0, TV::TR>(); }
336// limit(([ll]·[v0]) >> 12) -> lv, sv
337static inline void ll() { mvmva<MX::LL, MV::V0, TV::Zero, SF::Shifted, LM::Limited>(); }
338// limit(([lc]·[sv]) >> 12) + [bk] -> lv, sv
339static inline void lc() { mvmva<MX::LC, MV::IR, TV::BK, SF::Shifted, LM::Limited>(); }
340// [rt]·[sv] -> lv
341static inline void rtir_sf0() { mvmva<MX::RT, MV::IR, TV::Zero, SF::Unshifted>(); }
342
343// General Matrix Operations
344// ([rt]·[v0]) >> 12 -> lv, sv
345static inline void rtv0() { mvmva<MX::RT, MV::V0, TV::Zero>(); }
346// ([rt]·[v1]) >> 12 -> lv, sv
347static inline void rtv1() { mvmva<MX::RT, MV::V1, TV::Zero>(); }
348// ([rt]·[v2]) >> 12 -> lv, sv
349static inline void rtv2() { mvmva<MX::RT, MV::V2, TV::Zero>(); }
350// ([rt]·[sv]) >> 12 -> lv, sv
351static inline void rtir() { mvmva<MX::RT, MV::IR, TV::Zero>(); }
352// ([rt]·[v0]) >> 12 + [tr] -> lv, sv
353static inline void rtv0tr() { mvmva<MX::RT, MV::V0, TV::TR>(); }
354// ([rt]·[v1]) >> 12 + [tr] -> lv, sv
355static inline void rtv1tr() { mvmva<MX::RT, MV::V1, TV::TR>(); }
356// ([rt]·[v2]) >> 12 + [tr] -> lv, sv
357static inline void rtv2tr() { mvmva<MX::RT, MV::V2, TV::TR>(); }
358// ([rt]·[sv]) >> 12 + [tr] -> lv, sv
359static inline void rtirtr() { mvmva<MX::RT, MV::IR, TV::TR>(); }
360// ([rt]·[v0]) >> 12 + [bk] -> lv, sv
361static inline void rtv0bk() { mvmva<MX::RT, MV::V0, TV::BK>(); }
362// ([rt]·[v1]) >> 12 + [bk] -> lv, sv
363static inline void rtv1bk() { mvmva<MX::RT, MV::V1, TV::BK>(); }
364// ([rt]·[v2]) >> 12 + [bk] -> lv, sv
365static inline void rtv2bk() { mvmva<MX::RT, MV::V2, TV::BK>(); }
366// ([rt]·[sv]) >> 12 + [bk] -> lv, sv
367static inline void rtirbk() { mvmva<MX::RT, MV::IR, TV::BK>(); }
368// ([rt]·[v0]) >> 12 + [fc] -> lv, sv
369static inline void rtv0fc() { mvmva<MX::RT, MV::V0, TV::FC>(); }
370// ([rt]·[v1]) >> 12 + [fc] -> lv, sv
371static inline void rtv1fc() { mvmva<MX::RT, MV::V1, TV::FC>(); }
372// ([rt]·[v2]) >> 12 + [fc] -> lv, sv
373static inline void rtv2fc() { mvmva<MX::RT, MV::V2, TV::FC>(); }
374// ([rt]·[sv]) >> 12 + [fc] -> lv, sv
375static inline void rtirfc() { mvmva<MX::RT, MV::IR, TV::FC>(); }
376// ([ll]·[v0]) >> 12 -> lv, sv
377static inline void llv0() { mvmva<MX::LL, MV::V0, TV::Zero>(); }
378// ([ll]·[v1]) >> 12 -> lv, sv
379static inline void llv1() { mvmva<MX::LL, MV::V1, TV::Zero>(); }
380// ([ll]·[v2]) >> 12 -> lv, sv
381static inline void llv2() { mvmva<MX::LL, MV::V2, TV::Zero>(); }
382// ([ll]·[sv]) >> 12 -> lv, sv
383static inline void llir() { mvmva<MX::LL, MV::IR, TV::Zero>(); }
384// ([ll]·[v0]) >> 12 + [tr] -> lv, sv
385static inline void llv0tr() { mvmva<MX::LL, MV::V0, TV::TR>(); }
386// ([ll]·[v1]) >> 12 + [tr] -> lv, sv
387static inline void llv1tr() { mvmva<MX::LL, MV::V1, TV::TR>(); }
388// ([ll]·[v2]) >> 12 + [tr] -> lv, sv
389static inline void llv2tr() { mvmva<MX::LL, MV::V2, TV::TR>(); }
390// ([ll]·[sv]) >> 12 + [tr] -> lv, sv
391static inline void llirtr() { mvmva<MX::LL, MV::IR, TV::TR>(); }
392// ([ll]·[v0]) >> 12 + [bk] -> lv, sv
393static inline void llv0bk() { mvmva<MX::LL, MV::V0, TV::BK>(); }
394// ([ll]·[v1]) >> 12 + [bk] -> lv, sv
395static inline void llv1bk() { mvmva<MX::LL, MV::V1, TV::BK>(); }
396// ([ll]·[v2]) >> 12 + [bk] -> lv, sv
397static inline void llv2bk() { mvmva<MX::LL, MV::V2, TV::BK>(); }
398// ([ll]·[sv]) >> 12 + [bk] -> lv, sv
399static inline void llirbk() { mvmva<MX::LL, MV::IR, TV::BK>(); }
400// ([ll]·[v0]) >> 12 + [fc] -> lv, sv
401static inline void llv0fc() { mvmva<MX::LL, MV::V0, TV::FC>(); }
402// ([ll]·[v1]) >> 12 + [fc] -> lv, sv
403static inline void llv1fc() { mvmva<MX::LL, MV::V1, TV::FC>(); }
404// ([ll]·[v2]) >> 12 + [fc] -> lv, sv
405static inline void llv2fc() { mvmva<MX::LL, MV::V2, TV::FC>(); }
406// ([ll]·[sv]) >> 12 + [fc] -> lv, sv
407static inline void llirfc() { mvmva<MX::LL, MV::IR, TV::FC>(); }
408// ([lc]·[v0]) >> 12 -> lv, sv
409static inline void lcv0() { mvmva<MX::LC, MV::V0, TV::Zero>(); }
410// ([lc]·[v1]) >> 12 -> lv, sv
411static inline void lcv1() { mvmva<MX::LC, MV::V1, TV::Zero>(); }
412// ([lc]·[v2]) >> 12 -> lv, sv
413static inline void lcv2() { mvmva<MX::LC, MV::V2, TV::Zero>(); }
414// ([lc]·[sv]) >> 12 -> lv, sv
415static inline void lcir() { mvmva<MX::LC, MV::IR, TV::Zero>(); }
416// ([lc]·[v0]) >> 12 + [tr] -> lv, sv
417static inline void lcv0tr() { mvmva<MX::LC, MV::V0, TV::TR>(); }
418// ([lc]·[v1]) >> 12 + [tr] -> lv, sv
419static inline void lcv1tr() { mvmva<MX::LC, MV::V1, TV::TR>(); }
420// ([lc]·[v2]) >> 12 + [tr] -> lv, sv
421static inline void lcv2tr() { mvmva<MX::LC, MV::V2, TV::TR>(); }
422// ([lc]·[sv]) >> 12 + [tr] -> lv, sv
423static inline void lcirtr() { mvmva<MX::LC, MV::IR, TV::TR>(); }
424// ([lc]·[v0]) >> 12 + [bk] -> lv, sv
425static inline void lcv0bk() { mvmva<MX::LC, MV::V0, TV::BK>(); }
426// ([lc]·[v1]) >> 12 + [bk] -> lv, sv
427static inline void lcv1bk() { mvmva<MX::LC, MV::V1, TV::BK>(); }
428// ([lc]·[v2]) >> 12 + [bk] -> lv, sv
429static inline void lcv2bk() { mvmva<MX::LC, MV::V2, TV::BK>(); }
430// ([lc]·[sv]) >> 12 + [bk] -> lv, sv
431static inline void lcirbk() { mvmva<MX::LC, MV::IR, TV::BK>(); }
432// ([lc]·[v0]) >> 12 + [fc] -> lv, sv
433static inline void lcv0fc() { mvmva<MX::LC, MV::V0, TV::FC>(); }
434// ([lc]·[v1]) >> 12 + [fc] -> lv, sv
435static inline void lcv1fc() { mvmva<MX::LC, MV::V1, TV::FC>(); }
436// ([lc]·[v2]) >> 12 + [fc] -> lv, sv
437static inline void lcv2fc() { mvmva<MX::LC, MV::V2, TV::FC>(); }
438// ([lc]·[sv]) >> 12 + [fc] -> lv, sv
439static inline void lcirfc() { mvmva<MX::LC, MV::IR, TV::FC>(); }
440
441} // namespace Kernels
442
443} // namespace GTE
444
445} // namespace psyqo
LM
Definition gte-kernels.hh:51
@ Limited
Definition gte-kernels.hh:51
@ Unlimited
Definition gte-kernels.hh:51
SF
Definition gte-kernels.hh:49
@ Shifted
Definition gte-kernels.hh:49
@ Unshifted
Definition gte-kernels.hh:49
TV
Definition gte-kernels.hh:321
void mvmva()
Definition gte-kernels.hh:325
MV
Definition gte-kernels.hh:319
MX
Definition gte-kernels.hh:317
Definition lua.hh:38
void uint32_t(classId, spec)