[decomp] sky/time of day (#883)

* time of day

* goal code seems to work

* stars at wrong spot

* stars and sun work

* debugging clouds

* fix texture correction

* sky works

* cleanup, add profiler

* clean up

* final clean up

* offline tests

* missing include
This commit is contained in:
water111 2021-10-10 20:07:03 -04:00 committed by GitHub
parent d7eeddf2fc
commit b2052016e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
88 changed files with 5577 additions and 528 deletions

View file

@ -136,6 +136,13 @@ class Vector {
return *this;
}
Vector<T, Size>& operator/=(const T& val) {
for (int i = 0; i < Size; i++) {
m_data[i] /= val;
}
return *this;
}
Vector<T, Size> cross(const Vector<T, Size>& other) const {
static_assert(Size == 3, "Size for cross");
Vector<T, Size> result = {y() * other.z() - z() * other.y(), z() * other.x() - x() * other.z(),

View file

@ -83,4 +83,14 @@ T align4(T in) {
template <typename T>
T align64(T in) {
return (in + 63) & (~T(63));
}
inline u32 count_leading_zeros_u32(u32 in) {
#if defined(__GNUC__) || defined(__clang__)
return __builtin_clz(in);
#else
unsigned long result;
_BitScanReverse(&result, in);
return result;
#endif
}

25
common/util/colors.h Normal file
View file

@ -0,0 +1,25 @@
#pragma once
#include "common/common_types.h"
namespace colors {
// some reasonable colors that are different from each other
constexpr int COLOR_COUNT = 131;
u32 common_colors[COLOR_COUNT] = {
0xF0F8FE, 0xFAEBD7, 0x00FFFF, 0x70DB93, 0xF0FFFF, 0xF5F5DC, 0x000000, 0x0000FF, 0x9F5F9F,
0xB5A642, 0xD9D919, 0x8C7853, 0xA52A2A, 0x5F9EA0, 0xD2691E, 0xB87333, 0xFF7F50, 0xDC143C,
0x00FFFF, 0x00008B, 0x5C4033, 0x008B8B, 0xB8860B, 0xA9A9A9, 0x006400, 0xBDB76B, 0x8B008B,
0x4F4F2F, 0xFF8C00, 0x9932CD, 0x871F78, 0xE9967A, 0x6B238E, 0x2F4F4F, 0x97694F, 0x7093DB,
0x9400D3, 0x855E42, 0x545454, 0x856363, 0xD19275, 0xB22222, 0x238E23, 0xCD7F32, 0xDBDB70,
0xC0C0C0, 0x00FF00, 0x527F76, 0x93DB70, 0xFF69B4, 0x215E21, 0xCD5C5C, 0x4B0082, 0xFFFFF0,
0x9F9F5F, 0xE6E6FA, 0xC0D9D9, 0xF08080, 0xE0FFFF, 0xA8A8A8, 0x90EE90, 0xFFB6C1, 0x8F8FBD,
0xE9C2A6, 0x00FF00, 0x32CD32, 0xFF00FF, 0xE47833, 0x8E236B, 0x32CD99, 0x3232CD, 0x6B8E23,
0xEAEAAE, 0x9370DB, 0x426F42, 0x7F00FF, 0x7FFF00, 0x70DBDB, 0xDB7093, 0xA68064, 0x2F2F4F,
0xF5FFFA, 0xFFE4E1, 0x23238E, 0x4D4DFF, 0xFF6EC7, 0x00009C, 0xEBC79E, 0xCFB53B, 0x808000,
0xFF7F00, 0xFF2400, 0xDB70DB, 0xEEE8AA, 0x8FBC8F, 0xAFEEEE, 0xBC8F8F, 0xEAADEA, 0xB0E0E6,
0x800080, 0xD9D9F3, 0xFF0000, 0x5959AB, 0x4169E1, 0x8B4513, 0x6F4242, 0xF4A460, 0x8C1717,
0x238E68, 0x8E6B23, 0xE6E8FA, 0x3299CC, 0x007FFF, 0xFFFAFA, 0xFF1CAE, 0x00FF7F, 0x236B8E,
0x38B0DE, 0xDB9370, 0x008080, 0xD8BFD8, 0xFF6347, 0xADEAEA, 0x5C4033, 0x5C4033, 0x422F4F,
0xCC3299, 0xD8D8BF, 0xFFFFFF, 0xFFFF00, 0x99CC32,
};
} // namespace colors

View file

@ -2307,6 +2307,19 @@ void StoreInSymbolElement::push_to_stack(const Env& env, FormPool& pool, FormSta
auto val = pool.alloc_single_element_form<SimpleExpressionElement>(nullptr, m_value, m_my_idx);
val->update_children_from_stack(env, pool, stack, true);
if (m_cast_for_set) {
// we'd need to cast for set. Let's see if we can simplify it instead:
auto simplified = try_cast_simplify(val, *m_cast_for_set, pool, env, false);
if (simplified) {
if (m_cast_for_define && *m_cast_for_define == *m_cast_for_set) {
// if we'd need exactly the same cast for a define, we can drop it too
m_cast_for_define = {};
}
m_cast_for_set = {};
val = simplified;
}
}
auto elt = pool.alloc_element<SetFormFormElement>(sym, val, m_cast_for_set, m_cast_for_define);
elt->mark_popped();
stack.push_form_element(elt, true);

View file

@ -632,6 +632,12 @@ Mips2C_Line handle_generic_op2(const Instruction& i0,
instr_str};
}
Mips2C_Line handle_plain_op(const Instruction& /*i0*/,
const std::string& instr_str,
const std::string& op_name) {
return {fmt::format("c->{}();", op_name), instr_str};
}
Mips2C_Line handle_or(const Instruction& i0, const std::string& instr_str) {
if (is_gpr_3(i0, InstructionKind::OR, {}, rs7(), rr0())) {
// set reg_dest to #f : or reg_dest, s7, r0
@ -648,7 +654,7 @@ Mips2C_Line handle_or(const Instruction& i0, const std::string& instr_str) {
instr_str};
} else {
// actually do a logical OR of two registers: or a0, a1, a2
return handle_unknown(instr_str);
return handle_generic_op3(i0, instr_str, "_or");
}
}
@ -704,6 +710,8 @@ Mips2C_Line handle_non_likely_branch_bc(const Instruction& i0, const std::string
return {fmt::format("bc = ((s64){}) <= 0;", reg64_or_zero(i0.get_src(0))), instr_str};
case InstructionKind::BC1F:
return {fmt::format("bc = !cop1_bc;"), instr_str};
case InstructionKind::BC1T:
return {fmt::format("bc = cop1_bc;"), instr_str};
default:
return handle_unknown(instr_str);
}
@ -849,9 +857,13 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
case InstructionKind::MULT3:
case InstructionKind::PMINW:
case InstructionKind::PMAXW:
case InstructionKind::SUBU:
case InstructionKind::DSRAV:
return handle_generic_op3(i0, instr_str, {});
case InstructionKind::MULS:
return handle_generic_op3(i0, instr_str, "muls");
case InstructionKind::DIVS:
return handle_generic_op3(i0, instr_str, "divs");
case InstructionKind::ADDS:
return handle_generic_op3(i0, instr_str, "adds");
case InstructionKind::SUBS:
@ -893,6 +905,8 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
return handle_generic_op2(i0, instr_str, "mfc1");
case InstructionKind::MTC1:
return handle_generic_op2(i0, instr_str, "mtc1");
case InstructionKind::NEGS:
return handle_generic_op2(i0, instr_str, "negs");
case InstructionKind::CVTWS:
return handle_generic_op2(i0, instr_str, "cvtws");
case InstructionKind::CVTSW:
@ -901,11 +915,15 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
return handle_generic_op2(i0, instr_str, "pexew");
case InstructionKind::SQRTS:
return handle_generic_op2(i0, instr_str, "sqrts");
case InstructionKind::PLZCW:
return handle_generic_op2(i0, instr_str, "plzcw");
case InstructionKind::LUI:
return handle_lui(i0, instr_str);
case InstructionKind::CLTS:
output.needs_cop1_bc = true;
return handle_clts(i0, instr_str);
case InstructionKind::VWAITQ:
return handle_plain_op(i0, instr_str, "vwaitq");
default:
unknown_count++;
return handle_unknown(instr_str);

View file

@ -518,8 +518,10 @@
(generic-foreground 30) ;; ?
(alpha-tex0 31)
(sky-tex0 32)
(alpha-tex1 38)
(sky-tex1 39)
(bucket-45 45)
(bucket-46 46)
@ -3545,6 +3547,8 @@
(deftype dma-gif-packet (structure)
((dma-vif dma-packet :inline :offset-assert 0)
(gif uint64 2 :offset-assert 16) ;; guess
(gif0 uint64 :offset 16)
(gif1 uint64 :offset 24)
(quad uint128 2 :offset 0)
)
:method-count-assert 9
@ -4338,7 +4342,7 @@
;; - Symbols
(define-extern *fog-color* int)
(define-extern *fog-color* rgba)
(define-extern *default-regs-buffer* dma-buffer)
@ -5050,7 +5054,7 @@
(display? symbol :offset-assert 376)
(meta-inside? symbol :offset-assert 380)
(mood mood-context :offset-assert 384)
(mood-func function :offset-assert 388)
(mood-func (function mood-context float int none) :offset-assert 388)
(vis-bits pointer :offset-assert 392)
(all-visible? symbol :offset-assert 396)
(force-all-visible? symbol :offset-assert 400)
@ -7334,9 +7338,9 @@
)
(deftype sky-tng-data (basic)
((giftag-base qword :inline :offset-assert 16)
(giftag-roof qword :inline :offset-assert 32)
(giftag-ocean qword :inline :offset-assert 48)
((giftag-base gs-gif-tag :inline :offset-assert 16);; changed
(giftag-roof gs-gif-tag :inline :offset-assert 32)
(giftag-ocean gs-gif-tag :inline :offset-assert 48)
(fog vector :inline :offset-assert 64)
(sky uint32 8 :offset-assert 80)
(time float :offset-assert 112)
@ -7354,8 +7358,8 @@
((adgif-tmpl dma-gif-packet :inline :offset-assert 0)
(draw-tmpl dma-gif-packet :inline :offset-assert 32)
(blend-tmpl dma-gif-packet :inline :offset-assert 64)
(sky-data uint128 5 :offset-assert 96)
(cloud-data uint128 5 :offset-assert 176)
(sky-data qword 5 :inline :offset-assert 96)
(cloud-data qword 5 :inline :offset-assert 176)
)
:method-count-assert 9
:size-assert #x100
@ -7502,7 +7506,7 @@
:flag-assert #xb00000110
(:methods
(reset! (_type_) symbol 9)
(TODO-RENAME-10 (_type_ int float float vector) object 10) ; returns float or error string
(set-fade! (_type_ int float float vector) object 10) ; returns float or error string
)
)
@ -7549,7 +7553,7 @@
((active-count uint32 :offset-assert 4)
(interp float :offset-assert 8)
(current-interp float :offset-assert 12)
(moods uint64 2 :offset-assert 16)
(moods mood-context 2 :offset-assert 16)
(current-fog mood-fog :inline :offset-assert 32)
(current-sun mood-sun :inline :offset-assert 80)
(current-prt-color vector :inline :offset-assert 112)
@ -7559,7 +7563,7 @@
(title-light-group light-group :inline :offset-assert 1888)
(time float :offset-assert 2080)
(target-interp float :offset-assert 2084)
(erase-color uint32 :offset-assert 2088)
(erase-color rgba :offset-assert 2088)
(num-stars float :offset-assert 2092)
(light-masks-0 uint8 2 :offset-assert 2096)
(light-masks-1 uint8 2 :offset-assert 2098)
@ -17536,24 +17540,25 @@
;; - Functions
(define-extern make-sky-textures function)
(define-extern init-time-of-day (function none))
(define-extern make-sky-textures (function time-of-day-context int none))
(define-extern init-time-of-day (function none :behavior time-of-day-proc))
(define-extern update-sky-tng-data (function float none))
(define-extern time-of-day-update (function none))
(define-extern start-time-of-day (function int))
(define-extern time-of-day-setup (function symbol none))
(define-extern time-of-day-update (function none :behavior time-of-day-proc))
(define-extern start-time-of-day (function none))
(define-extern time-of-day-setup (function symbol symbol))
(define-extern set-time-of-day (function float none))
(define-extern init-time-of-day-context (function time-of-day-context float))
(define-extern update-time-of-day (function time-of-day-context none))
;; - Symbols
(define-extern time-of-day-tick state)
(define-extern time-of-day-tick (state time-of-day-proc))
(define-extern time-of-day-effect (function none)) ;; only 'nothing' is stored here, looks like dead code
;; - Unknowns
;;(define-extern sky-base-polygons object) ;; unknown type
(define-extern sky-base-polygons (inline-array sky-vertex))
;; ----------------------
@ -17580,37 +17585,37 @@
;; - Types
; (deftype sky-frame-data (structure)
; ((data UNKNOWN 18 :offset-assert 0)
; (world-homo-matrix matrix :inline :offset-assert 0)
; (hmge-scale vector :inline :offset-assert 64)
; (hvdf-offset vector :inline :offset-assert 80)
; (consts vector :inline :offset-assert 96)
; (pfog0 float :offset-assert 96)
; (radius float :offset-assert 100)
; (nokick float :offset-assert 108)
; (strip-giftag qword :inline :offset-assert 112)
; (col-adgif qword :inline :offset-assert 128)
; (save UNKNOWN 5 :offset-assert 144)
; (sun-fan-giftag qword :inline :offset-assert 224)
; (sun-strip-giftag qword :inline :offset-assert 240)
; (sun-alpha qword :inline :offset-assert 256)
; (sun-alpha-giftag qword :inline :offset-assert 272)
; )
; :method-count-assert 9
; :size-assert #x120
; :flag-assert #x900000120
; )
(deftype sky-frame-data (structure)
((data uint128 18 :offset-assert 0)
(world-homo-matrix matrix :inline :offset 0)
(hmge-scale vector :inline :offset 64)
(hvdf-offset vector :inline :offset 80)
(consts vector :inline :offset 96)
(pfog0 float :offset 96)
(radius float :offset 100)
(nokick float :offset 108)
(strip-giftag qword :inline :offset 112)
(col-adgif qword :inline :offset 128)
(save uint128 5 :offset 144)
(sun-fan-giftag qword :inline :offset 224)
(sun-strip-giftag qword :inline :offset 240)
(sun-alpha qword :inline :offset 256)
(sun-alpha-giftag qword :inline :offset 272)
)
:method-count-assert 9
:size-assert #x120
:flag-assert #x900000120
)
;; - Functions
(define-extern sky-add-frame-data function)
(define-extern sky-make-sun-data (function sky-parms int float none))
(define-extern sky-make-moon-data (function sky-parms float none))
(define-extern sky-make-light function)
(define-extern sky-make-light (function sky-parms light int rgba none))
(define-extern sky-init-upload-data function)
(define-extern sky-upload function)
(define-extern sky-draw function)
(define-extern sky-draw (function sky-parms none))
;; - Unknowns
@ -17625,29 +17630,29 @@
;; - Functions
(define-extern copy-sky-texture function)
(define-extern copy-cloud-texture function)
(define-extern init-sky-regs function)
(define-extern render-sky-tri function)
(define-extern close-sky-buffer function)
(define-extern set-tex-offset function)
(define-extern render-sky-quad function)
(define-extern sky-tng-setup-cloud-layer function)
(define-extern copy-sky-texture (function dma-buffer adgif-shader float none))
(define-extern copy-cloud-texture (function dma-buffer adgif-shader float none))
(define-extern init-sky-regs (function none))
(define-extern render-sky-tri (function (inline-array sky-vertex) dma-buffer none))
(define-extern close-sky-buffer (function dma-buffer none))
(define-extern set-tex-offset (function int int none))
(define-extern render-sky-quad (function int dma-buffer none))
(define-extern sky-tng-setup-cloud-layer (function float float vector (inline-array sky-vertex) none))
(define-extern draw-large-polygon function)
(define-extern init-sky-tng-data function)
(define-extern init-sky-tng-data (function sky-tng-data none))
(define-extern clip-polygon-against-positive-hyperplane function)
(define-extern clip-polygon-against-negative-hyperplane function)
(define-extern sky-duplicate-polys function)
(define-extern sky-tng-setup-clouds function)
(define-extern sky-tng-setup-clouds (function none))
(define-extern render-sky-tng (function time-of-day-context none))
;; - Unknowns
;;(define-extern *sky-work* object) ;; unknown type
(define-extern *sky-work* sky-work) ;; unknown type
(define-extern *sky-tng-data* sky-tng-data) ;; unknown type
;;(define-extern sky-roof-polygons object) ;; unknown type
;;(define-extern sky-cloud-polygons object) ;; unknown type
;;(define-extern sky-cloud-polygon-indices object) ;; unknown type
(define-extern sky-roof-polygons (inline-array sky-vertex)) ;; unknown type
(define-extern sky-cloud-polygons (inline-array sky-vertex)) ;; unknown type
(define-extern sky-cloud-polygon-indices (pointer uint8)) ;; unknown type
;; ----------------------

View file

@ -671,8 +671,8 @@
],
"time-of-day": [
[10, "(function none)"],
[12, "(function sparticle-system sparticle-cpuinfo int none)"]
[10, "(function none :behavior time-of-day-proc)"],
[12, "(function sparticle-system sparticle-cpuinfo none)"]
],
"basebutton": [

View file

@ -547,7 +547,15 @@
"particle-adgif",
"sp-launch-particles-var",
"sp-process-block-2d",
"sp-process-block-3d"
"sp-process-block-3d",
"draw-large-polygon",
"clip-polygon-against-positive-hyperplane",
"clip-polygon-against-negative-hyperplane",
"render-sky-quad",
"render-sky-tri",
"init-sky-regs",
"set-tex-offset",
"adgif-shader<-texture-with-update!"
]
}

View file

@ -799,6 +799,21 @@
["L733", "uint64", true]
],
"sky": [
["L13", "vu-function"]
],
"sky-tng": [
["L82", "sky-work"],
// 576 bytes, 32 bytes each
["L81", "(inline-array sky-vertex)", 12],
["L80", "(inline-array sky-vertex)", 12],
["L79", "(inline-array sky-vertex)", 72],
["L78", "(pointer uint8)", 48],
["L77", "vector"],
["L76", "vector"]
],
"effect-control": [
["L300", "float", true],
["L301", "float", true],

View file

@ -1201,7 +1201,8 @@
],
"update-time-of-day": [
[16, "(array float)"] // TODO - broken!
[16, "(array float)"], // TODO - broken!
[48, "vector"]
],
"check-drop-level-rain": [
@ -2783,5 +2784,17 @@
[32, "vector"]
],
"init-sky-regs": [
[16, "vector"]
],
"set-tex-offset": [
[16, "vector"]
],
"sky-tng-setup-cloud-layer": [
[16,["inline-array", "sky-vertex", 12]]
],
"placeholder-do-not-add-below!": []
}

View file

@ -2634,23 +2634,6 @@
[[15, 250], "s5", "symbol"]
],
"time-of-day-update": [
[[0, 999], "s6", "time-of-day-proc"]
],
"(anon-function 10 time-of-day)": [
[[0, 999], "s6", "time-of-day-proc"]
],
"init-time-of-day": [
[[0, 999], "s6", "time-of-day-proc"],
[[51, 54], "t9", "(function object object object)"]
],
"start-time-of-day": [
[[20, 23], "t9", "(function process function object)"]
],
"cam-master-effect": [
[[0, 999], "s6", "camera-master"]
],
@ -3934,6 +3917,82 @@
[2, "v1", "(pointer process-drawable)"]
],
"update-time-of-day": [
[46, "v0", "(array float)"]
],
"sky-make-light": [
[[10, 23], "a0", "sky-sun-data"]
],
"make-sky-textures": [
[[90, 94], "a0", "dma-packet"],
[[100, 103], "a0", "gs-gif-tag"],
[108, "a0", "(pointer gs-alpha)"],
[110, "a0", "(pointer gs-reg64)"],
[[121, 124], "v1", "dma-packet"]
],
"copy-cloud-texture": [
[[2, 48], "s5", "(pointer uint128)"],
[[28, 32], "s4", "adgif-shader"]
],
"copy-sky-texture": [
[[2, 48], "s5", "(pointer uint128)"],
[[28, 32], "s4", "adgif-shader"]
],
"render-sky-tng": [
[[244, 262], "s2", "(inline-array sky-vertex)"],
[[34, 38], "a0", "dma-packet"],
[[44, 47], "a0", "gs-gif-tag"],
[52, "a0", "(pointer gs-zbuf)"],
[54, "a0", "(pointer gs-reg64)"],
[56, "a0", "(pointer gs-test)"],
[58, "a0", "(pointer gs-reg64)"],
[60, "a0", "(pointer gs-alpha)"],
[62, "a0", "(pointer gs-reg64)"],
[[74, 78], "a0", "dma-packet"],
[[84, 87], "a0", "gs-gif-tag"],
[107, "s2", "(pointer gs-tex0)"],
[109, "s2", "(pointer gs-reg64)"],
[111, "s2", "(pointer gs-tex1)"],
[113, "s2", "(pointer gs-reg64)"],
[115, "s2", "(pointer gs-clamp)"],
[117, "s2", "(pointer gs-reg64)"],
[118, "s2", "(pointer uint64)"],
[120, "s2", "(pointer gs-reg64)"],
[[159, 166], "s3", "dma-packet"],
[[171, 175], "a0", "dma-packet"],
[[181, 184], "a0", "gs-gif-tag"],
[189, "s2", "(pointer gs-alpha)"],
[191, "s2", "(pointer gs-reg64)"],
[209, "s2", "(pointer gs-tex0)"],
[211, "s2", "(pointer gs-reg64)"],
[213, "s2", "(pointer gs-tex1)"],
[215, "s2", "(pointer gs-reg64)"],
[216, "s2", "(pointer gs-clamp)"],
[218, "s2", "(pointer gs-reg64)"],
[219, "s2", "(pointer int64)"],
[221, "s2", "(pointer gs-reg64)"],
[[303, 310], "s3", "dma-packet"],
[[312, 316], "v1", "dma-packet"]
],
"render-sky-tri": [
[5, "a0", "int"],
[[6, 50], "a0", "(inline-array sky-vertex)"],
[[25, 48], "a3", "(inline-array sky-vertex)"]
],
"render-sky-quad": [
[[9, 32], "a0", "(inline-array sky-vertex)"],
[[33, 62], "a3", "(inline-array sky-vertex)"]
],
"(method 10 effect-control)": [
[88, "v1", "collide-shape-moving"],
[143, "s3", "(pointer sparticle-launch-group)"],

View file

@ -273,6 +273,7 @@ goos::Object decompile_value_array(const TypeSpec& elt_type,
}
elt_bytes.push_back(word.get_byte(j % 4));
}
assert(elt_type != TypeSpec("uint128"));
array_def.push_back(decompile_value(elt_type, elt_bytes, ts));
}
@ -865,6 +866,10 @@ goos::Object bitfield_defs_print(const TypeSpec& type,
} else if (def.is_signed) {
result.push_back(
pretty_print::to_symbol(fmt::format(":{} {}", def.field_name, (s64)def.value)));
} else if (def.nested_field) {
result.push_back(pretty_print::to_symbol(fmt::format(
":{} {}", def.field_name,
bitfield_defs_print(def.nested_field->field_type, def.nested_field->fields).print())));
} else {
result.push_back(
pretty_print::to_symbol(fmt::format(":{} #x{:x}", def.field_name, def.value)));
@ -1087,6 +1092,7 @@ goos::Object decompile_boxed_array(const DecompilerLabel& label,
}
elt_bytes.push_back(word.get_byte(j % 4));
}
assert(content_type != TypeSpec("uint128"));
result.push_back(decompile_value(content_type, elt_bytes, ts));
}
return pretty_print::build_list(result);

View file

@ -61,9 +61,11 @@ set(RUNTIME_SOURCE
kernel/ksound.cpp
mips2c/mips2c_table.cpp
mips2c/functions/draw_string.cpp
mips2c/functions/sky_tng.cpp
mips2c/functions/sparticle.cpp
mips2c/functions/sparticle_launcher.cpp
mips2c/functions/test_func.cpp
mips2c/functions/texture.cpp
overlord/dma.cpp
overlord/fake_iso.cpp
overlord/iso.cpp
@ -88,7 +90,9 @@ set(RUNTIME_SOURCE
graphics/opengl_renderer/debug_gui.cpp
graphics/opengl_renderer/DirectRenderer.cpp
graphics/opengl_renderer/OpenGLRenderer.cpp
graphics/opengl_renderer/Profiler.cpp
graphics/opengl_renderer/Shader.cpp
graphics/opengl_renderer/SkyRenderer.cpp
graphics/opengl_renderer/SpriteRenderer.cpp
graphics/opengl_renderer/TextureUploadHandler.cpp
graphics/texture/TextureConverter.cpp

View file

@ -81,6 +81,10 @@ std::string GifTag::print() const {
return result;
}
std::string register_address_name(u32 reg) {
return register_address_name(GsRegisterAddress(reg));
}
std::string register_address_name(GsRegisterAddress reg) {
switch (reg) {
case GsRegisterAddress::PRIM:

View file

@ -59,10 +59,6 @@ struct GifTag {
u64 data[2];
};
struct AdGif {
GifTag giftag[5];
};
std::string reg_descriptor_name(GifTag::RegisterDescriptor reg);
enum class GsRegisterAddress : u8 {
@ -125,6 +121,7 @@ enum class GsRegisterAddress : u8 {
enum class TextureFormat { PSMZ32, PSMZ24, PSMZ16, PSMZ16S };
std::string register_address_name(GsRegisterAddress reg);
std::string register_address_name(u32 reg);
struct GsZbuf {
GsZbuf(u64 val) : data(val) {}
@ -332,4 +329,18 @@ struct GsTexa {
std::string print() const;
u64 data = 0;
};
// not including the giftag
struct AdGifData {
u64 tex0_data;
u64 tex0_addr;
u64 tex1_data;
u64 tex1_addr;
u64 mip_data;
u64 mip_addr;
u64 clamp_data;
u64 clamp_addr;
u64 alpha_data;
u64 alpha_addr;
};

View file

@ -0,0 +1,45 @@
#pragma once
#include "game/graphics/dma/gs.h"
class AdgifHelper {
public:
// takes the 5QW of adgif data
explicit AdgifHelper(const u8* data) {
memcpy(&m_data, data, 16 * 5);
m_tex0 = GsTex0(m_data.tex0_data);
m_tex1 = GsTex1(m_data.tex1_data);
m_alpha = GsAlpha(m_data.alpha_data);
}
bool is_normal_adgif() const {
return (u8)m_data.tex0_addr == (u32)GsRegisterAddress::TEX0_1 &&
(u8)m_data.tex1_addr == (u32)GsRegisterAddress::TEX1_1 &&
(u8)m_data.mip_addr == (u32)GsRegisterAddress::MIPTBP1_1 &&
(u8)m_data.clamp_addr == (u32)GsRegisterAddress::CLAMP_1 &&
(u8)m_data.alpha_addr == (u32)GsRegisterAddress::ALPHA_1;
}
std::string print() const {
std::string result;
result +=
fmt::format("[0] {}\n {}\n", register_address_name(m_data.tex0_addr), m_tex0.print());
result +=
fmt::format("[1] {}\n {}\n", register_address_name(m_data.tex1_addr), m_tex1.print());
result += fmt::format("[2] {}\n", register_address_name(m_data.mip_addr));
result += fmt::format("[3] {}\n", register_address_name(m_data.clamp_addr));
result +=
fmt::format("[4] {}\n {}\n", register_address_name(m_data.alpha_addr), m_alpha.print());
return result;
}
const GsAlpha& alpha() const { return m_alpha; }
const GsTex0& tex0() const { return m_tex0; }
private:
AdGifData m_data;
GsTex0 m_tex0;
GsTex1 m_tex1;
GsAlpha m_alpha;
};

View file

@ -9,7 +9,9 @@ std::string BucketRenderer::name_and_id() const {
EmptyBucketRenderer::EmptyBucketRenderer(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id) {}
void EmptyBucketRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
void EmptyBucketRenderer::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& /*prof*/) {
// an empty bucket should have 4 things:
// a NEXT in the bucket buffer
// a CALL that calls the default register buffer chain

View file

@ -5,6 +5,7 @@
#include "game/graphics/dma/dma_chain_read.h"
#include "game/graphics/opengl_renderer/Shader.h"
#include "game/graphics/texture/TexturePool.h"
#include "game/graphics/opengl_renderer/Profiler.h"
/*!
* Matches the bucket-id enum in GOAL
@ -12,9 +13,11 @@
enum class BucketId {
BUCKET0 = 0,
BUCKET1 = 1,
SKY_DRAW = 3,
TFRAG_TEX_LEVEL0 = 5,
SHRUB_TEX_LEVEL0 = 19,
ALPHA_TEX_LEVEL0 = 31,
SKY_LEVEL0 = 32,
PRIS_TEX_LEVEL0 = 48,
WATER_TEX_LEVEL0 = 57,
// ...
@ -49,7 +52,9 @@ struct SharedRenderState {
class BucketRenderer {
public:
BucketRenderer(const std::string& name, BucketId my_id) : m_name(name), m_my_id(my_id) {}
virtual void render(DmaFollower& dma, SharedRenderState* render_state) = 0;
virtual void render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) = 0;
std::string name_and_id() const;
virtual ~BucketRenderer() = default;
bool& enabled() { return m_enabled; }
@ -69,7 +74,7 @@ class BucketRenderer {
class EmptyBucketRenderer : public BucketRenderer {
public:
EmptyBucketRenderer(const std::string& name, BucketId my_id);
void render(DmaFollower& dma, SharedRenderState* render_state) override;
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
bool empty() const override { return true; }
void draw_debug_window() override {}
};

View file

@ -21,7 +21,7 @@ DirectRenderer::DirectRenderer(const std::string& name, BucketId my_id, int batc
glBufferData(GL_ARRAY_BUFFER, m_ogl.color_buffer_bytes, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer);
m_ogl.st_buffer_bytes = batch_size * 3 * 2 * sizeof(float);
m_ogl.st_buffer_bytes = batch_size * 3 * 3 * sizeof(float);
glBufferData(GL_ARRAY_BUFFER, m_ogl.st_buffer_bytes, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
@ -36,7 +36,9 @@ DirectRenderer::~DirectRenderer() {
/*!
* Render from a DMA bucket.
*/
void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
void DirectRenderer::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// if we're rendering from a bucket, we should start off we a totally reset state:
reset_state();
setup_common_state(render_state);
@ -45,7 +47,7 @@ void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
while (dma.current_tag_offset() != render_state->next_bucket) {
auto data = dma.read_and_advance();
if (data.size_bytes && m_enabled) {
render_vif(data.vif0(), data.vif1(), data.data, data.size_bytes, render_state);
render_vif(data.vif0(), data.vif1(), data.data, data.size_bytes, render_state, prof);
}
if (dma.current_tag_offset() == render_state->default_regs_buffer) {
@ -57,7 +59,7 @@ void DirectRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
}
if (m_enabled) {
flush_pending(render_state);
flush_pending(render_state, prof);
}
}
@ -91,7 +93,7 @@ float u32_to_sc(u32 in) {
return (flt - 0.5) * 16.0;
}
void DirectRenderer::flush_pending(SharedRenderState* render_state) {
void DirectRenderer::flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof) {
if (m_prim_buffer.vert_count == 0) {
return;
}
@ -117,12 +119,6 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
m_texture_state.needs_gl_update = false;
}
if (m_debug_state.wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
} else {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
if (m_debug_state.disable_texture) {
// a bit of a hack, this forces the non-textured shader always.
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
@ -131,6 +127,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
if (m_debug_state.red) {
render_state->shaders[ShaderId::DEBUG_RED].activate();
glDisable(GL_BLEND);
m_prim_gl_state_needs_gl_update = true;
m_blend_state_needs_gl_update = true;
}
// hacks
@ -151,8 +149,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
m_prim_buffer.rgba_u8.data());
if (m_prim_gl_state.texture_enable) {
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, m_prim_buffer.sts.size() * sizeof(math::Vector<float, 2>),
m_prim_buffer.sts.data());
glBufferSubData(GL_ARRAY_BUFFER, 0, m_prim_buffer.stqs.size() * sizeof(math::Vector<float, 3>),
m_prim_buffer.stqs.data());
}
// setup attributes:
@ -179,7 +177,7 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.st_buffer);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, // location 0 in the shader
2, // 3 floats per vert
3, // 3 floats per vert
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
0, // tightly packed
@ -190,8 +188,14 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
int draw_count = 0;
if (m_mode == Mode::SPRITE_CPU) {
assert(m_texture_state.tcc);
assert(m_prim_gl_state.texture_enable);
if (!m_prim_gl_state.texture_enable) {
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
} else {
assert(m_texture_state.tcc);
assert(m_prim_gl_state.texture_enable);
render_state->shaders[ShaderId::SPRITE_CPU].activate();
}
if (m_sprite_mode.do_first_draw) {
glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count);
draw_count++;
@ -201,6 +205,8 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
glDepthMask(GL_FALSE);
glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count);
glDepthMask(GL_TRUE);
m_prim_gl_state_needs_gl_update = true;
m_blend_state_needs_gl_update = true;
draw_count++;
}
} else {
@ -208,8 +214,20 @@ void DirectRenderer::flush_pending(SharedRenderState* render_state) {
draw_count++;
}
if (m_debug_state.wireframe) {
render_state->shaders[ShaderId::DEBUG_RED].activate();
glDisable(GL_BLEND);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawArrays(GL_TRIANGLES, 0, m_prim_buffer.vert_count);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
draw_count++;
}
glBindVertexArray(0);
m_triangles += draw_count * (m_prim_buffer.vert_count / 3);
int n_tris = draw_count * (m_prim_buffer.vert_count / 3);
prof.add_tri(n_tris);
prof.add_draw_call(draw_count);
m_triangles += n_tris;
m_draw_calls += draw_count;
m_prim_buffer.vert_count = 0;
}
@ -221,6 +239,8 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
if (m_texture_state.tcc) {
if (m_mode == Mode::SPRITE_CPU) {
render_state->shaders[ShaderId::SPRITE_CPU].activate();
} else if (m_mode == Mode::SKY) {
assert(false);
} else {
render_state->shaders[ShaderId::DIRECT_BASIC_TEXTURED].activate();
}
@ -229,7 +249,11 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
}
update_gl_texture(render_state);
} else {
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
if (m_mode == Mode::SKY) {
render_state->shaders[ShaderId::SKY].activate();
} else {
render_state->shaders[ShaderId::DIRECT_BASIC].activate();
}
}
if (state.fogging_enable) {
assert(false);
@ -255,8 +279,16 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state) {
} else {
tex = render_state->texture_pool->lookup(m_texture_state.texture_base_ptr);
}
if (!tex) {
// TODO Add back
fmt::print("Failed to find texture at {}, using random\n", m_texture_state.texture_base_ptr);
tex = render_state->texture_pool->get_random_texture();
if (tex) {
// fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name);
}
}
assert(tex);
// fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name);
// first: do we need to load the texture?
if (!tex->on_gpu) {
@ -266,8 +298,14 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
// Note: CLAMP and CLAMP_TO_EDGE are different...
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (m_clamp_state.clamp) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glUniform1i(
@ -327,7 +365,7 @@ void DirectRenderer::update_gl_test() {
}
if (state.alpha_test_enable) {
assert(false);
assert(state.alpha_test == GsTest::AlphaTest::ALWAYS);
}
if (state.depth_writes) {
@ -371,7 +409,8 @@ void DirectRenderer::render_vif(u32 vif0,
u32 vif1,
const u8* data,
u32 size,
SharedRenderState* render_state) {
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// here we process VIF data. Basically we just go forward, looking for DIRECTs.
// We skip stuff like flush and nops.
@ -395,7 +434,7 @@ void DirectRenderer::render_vif(u32 vif0,
assert(get_direct_qwc_or_nop(VifCode(vif)) == 0);
} else {
// aligned! do a gif transfer!
render_gif(data + offset_into_data, gif_qwc * 16, render_state);
render_gif(data + offset_into_data, gif_qwc * 16, render_state, prof);
offset_into_data += gif_qwc * 16;
}
} else {
@ -411,7 +450,10 @@ void DirectRenderer::render_vif(u32 vif0,
/*!
* Render GIF data.
*/
void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* render_state) {
void DirectRenderer::render_gif(const u8* data,
u32 size,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
assert(size >= 16);
bool eop = false;
@ -433,13 +475,13 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
auto format = tag.flg();
if (format == GifTag::Format::PACKED) {
if (tag.pre()) {
handle_prim(tag.prim(), render_state);
handle_prim(tag.prim(), render_state, prof);
}
for (u32 loop = 0; loop < tag.nloop(); loop++) {
for (u32 reg = 0; reg < nreg; reg++) {
switch (reg_desc[reg]) {
case GifTag::RegisterDescriptor::AD:
handle_ad(data + offset, render_state);
handle_ad(data + offset, render_state, prof);
break;
case GifTag::RegisterDescriptor::ST:
handle_st_packed(data + offset);
@ -448,13 +490,13 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
handle_rgbaq_packed(data + offset);
break;
case GifTag::RegisterDescriptor::XYZF2:
handle_xyzf2_packed(data + offset, render_state);
handle_xyzf2_packed(data + offset, render_state, prof);
break;
case GifTag::RegisterDescriptor::PRIM:
handle_prim_packed(data + offset, render_state);
handle_prim_packed(data + offset, render_state, prof);
break;
case GifTag::RegisterDescriptor::TEX0_1:
handle_tex0_1_packed(data + offset, render_state);
handle_tex0_1_packed(data + offset, render_state, prof);
break;
default:
fmt::print("Register {} is not supported in packed mode yet\n",
@ -473,13 +515,13 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
// reg_descriptor_name(reg_desc[reg]));
switch (reg_desc[reg]) {
case GifTag::RegisterDescriptor::PRIM:
handle_prim(register_data, render_state);
handle_prim(register_data, render_state, prof);
break;
case GifTag::RegisterDescriptor::RGBAQ:
handle_rgbaq(register_data);
break;
case GifTag::RegisterDescriptor::XYZF2:
handle_xyzf2(register_data, render_state);
handle_xyzf2(register_data, render_state, prof);
break;
default:
fmt::print("Register {} is not supported in reglist mode yet\n",
@ -501,7 +543,9 @@ void DirectRenderer::render_gif(const u8* data, u32 size, SharedRenderState* ren
// fmt::print("{}\n", GifTag(data).print());
}
void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state) {
void DirectRenderer::handle_ad(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
u64 value;
GsRegisterAddress addr;
memcpy(&value, data, sizeof(u64));
@ -509,22 +553,22 @@ void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state)
switch (addr) {
case GsRegisterAddress::ZBUF_1:
handle_zbuf1(value, render_state);
handle_zbuf1(value, render_state, prof);
break;
case GsRegisterAddress::TEST_1:
handle_test1(value, render_state);
handle_test1(value, render_state, prof);
break;
case GsRegisterAddress::ALPHA_1:
handle_alpha1(value, render_state);
handle_alpha1(value, render_state, prof);
break;
case GsRegisterAddress::PABE:
handle_pabe(value);
break;
case GsRegisterAddress::CLAMP_1:
handle_clamp1(value);
handle_clamp1(value, render_state, prof);
break;
case GsRegisterAddress::PRIM:
handle_prim(value, render_state);
handle_prim(value, render_state, prof);
break;
case GsRegisterAddress::TEX1_1:
@ -543,11 +587,13 @@ void DirectRenderer::handle_ad(const u8* data, SharedRenderState* render_state)
// TODO
break;
case GsRegisterAddress::TEX0_1:
handle_tex0_1(value, render_state);
handle_tex0_1(value, render_state, prof);
break;
case GsRegisterAddress::MIPTBP1_1:
// TODO this has the address of different mip levels.
break;
case GsRegisterAddress::TEXFLUSH:
break;
default:
fmt::print("Address {} is not supported\n", register_address_name(addr));
assert(false);
@ -565,22 +611,25 @@ void DirectRenderer::handle_tex1_1(u64 val) {
if (!(reg.mmin() == 1 || reg.mmin() == 4)) { // with mipmap off, both of these are linear
// lg::error("unsupported mmin");
}
//
}
void DirectRenderer::handle_tex0_1_packed(const u8* data, SharedRenderState* render_state) {
void DirectRenderer::handle_tex0_1_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
u64 val;
memcpy(&val, data, sizeof(u64));
handle_tex0_1(val, render_state);
handle_tex0_1(val, render_state, prof);
}
void DirectRenderer::handle_tex0_1(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_tex0_1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
GsTex0 reg(val);
// update tbp
if (m_texture_state.current_register != reg) {
flush_pending(render_state);
// fmt::print("flush due to tex0\n");
flush_pending(render_state, prof);
m_texture_state.texture_base_ptr = reg.tbp0();
m_texture_state.using_mt4hh = reg.psm() == GsTex0::PSM::PSMT4HH;
m_prim_gl_state_needs_gl_update = true;
@ -628,7 +677,9 @@ void DirectRenderer::handle_rgbaq_packed(const u8* data) {
m_prim_building.rgba_reg[3] = data[12];
}
void DirectRenderer::handle_xyzf2_packed(const u8* data, SharedRenderState* render_state) {
void DirectRenderer::handle_xyzf2_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
u32 x, y;
memcpy(&x, data, 4);
memcpy(&y, data + 4, 4);
@ -641,42 +692,52 @@ void DirectRenderer::handle_xyzf2_packed(const u8* data, SharedRenderState* rend
bool adc = upper & (1ull << 47);
assert(!adc);
// assert(!f);
handle_xyzf2_common(x, y, z, f, render_state);
handle_xyzf2_common(x, y, z, f, render_state, prof);
}
void DirectRenderer::handle_zbuf1(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_zbuf1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// note: we can basically ignore this. There's a single z buffer that's always configured the same
// way - 24-bit, at offset 448.
GsZbuf x(val);
assert(x.psm() == TextureFormat::PSMZ24);
assert(x.zbp() == 448);
bool write = !x.zmsk();
bool write = x.zmsk();
// assert(write);
if (write != m_test_state.depth_writes) {
flush_pending(render_state);
// fmt::print("flush due to depth write\n");
flush_pending(render_state, prof);
m_test_state_needs_gl_update = true;
m_test_state.depth_writes = !write;
m_test_state.depth_writes = write;
}
}
void DirectRenderer::handle_test1(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_test1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
GsTest reg(val);
assert(!reg.alpha_test_enable());
if (reg.alpha_test_enable()) {
assert(reg.alpha_test() == GsTest::AlphaTest::ALWAYS);
}
assert(!reg.date());
assert(!(val & 1));
if (m_test_state.current_register != reg) {
flush_pending(render_state);
// fmt::print("flush due to test\n");
flush_pending(render_state, prof);
m_test_state.from_register(reg);
m_test_state_needs_gl_update = true;
}
}
void DirectRenderer::handle_alpha1(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_alpha1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
GsAlpha reg(val);
if (m_blend_state.current_register != reg) {
flush_pending(render_state);
// fmt::print("flush due to alpha1\n");
flush_pending(render_state, prof);
m_blend_state.from_register(reg);
m_blend_state_needs_gl_update = true;
}
@ -686,17 +747,33 @@ void DirectRenderer::handle_pabe(u64 val) {
assert(val == 0); // not really sure how to handle this yet.
}
void DirectRenderer::handle_clamp1(u64 val) {
assert(val == 0b101); // clamp s and t.
void DirectRenderer::handle_clamp1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
assert(val == 0b101 || val == 0);
if (m_clamp_state.current_register != val) {
flush_pending(render_state, prof);
m_clamp_state.current_register = val;
if (val == 0b101) {
m_clamp_state.clamp = true;
} else {
m_clamp_state.clamp = false;
}
m_texture_state.needs_gl_update = true;
}
}
void DirectRenderer::handle_prim_packed(const u8* data, SharedRenderState* render_state) {
void DirectRenderer::handle_prim_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
u64 val;
memcpy(&val, data, sizeof(u64));
handle_prim(val, render_state);
handle_prim(val, render_state, prof);
}
void DirectRenderer::handle_prim(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_prim(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (m_prim_building.tri_strip_startup) {
m_prim_building.tri_strip_startup = 0;
m_prim_building.building_idx = 0;
@ -709,7 +786,8 @@ void DirectRenderer::handle_prim(u64 val, SharedRenderState* render_state) {
GsPrim prim(val);
if (m_prim_gl_state.current_register != prim || m_blend_state.alpha_blend_enable != prim.abe()) {
flush_pending(render_state);
// fmt::print("flush due to prim\n");
flush_pending(render_state, prof);
m_prim_gl_state.from_register(prim);
m_blend_state.alpha_blend_enable = prim.abe();
m_prim_gl_state_needs_gl_update = true;
@ -728,15 +806,17 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
u32 y,
u32 z,
u8 f,
SharedRenderState* render_state) {
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
assert(z < (1 << 24));
(void)f; // TODO: do something with this.
if (m_prim_buffer.is_full()) {
flush_pending(render_state);
// fmt::print("flush due to fill {} {}\n", m_prim_buffer.vert_count, m_prim_buffer.max_verts);
flush_pending(render_state, prof);
}
// assert(f == 0);
m_prim_building.building_st.at(m_prim_building.building_idx) = m_prim_building.st_reg;
m_prim_building.building_stq.at(m_prim_building.building_idx) = math::Vector<float, 3>(
m_prim_building.st_reg.x(), m_prim_building.st_reg.y(), m_prim_building.Q);
m_prim_building.building_rgba.at(m_prim_building.building_idx) = m_prim_building.rgba_reg;
m_prim_building.building_vert.at(m_prim_building.building_idx) = {x << 16, y << 16, z << 8};
m_prim_building.building_idx++;
@ -780,7 +860,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
if (m_prim_building.tri_strip_startup >= 3) {
for (int i = 0; i < 3; i++) {
m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i],
m_prim_building.building_st[i]);
m_prim_building.building_stq[i]);
}
}
@ -791,7 +871,7 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
m_prim_building.building_idx = 0;
for (int i = 0; i < 3; i++) {
m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i],
m_prim_building.building_st[i]);
m_prim_building.building_stq[i]);
}
}
break;
@ -807,10 +887,11 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
}
for (int i = 0; i < 3; i++) {
m_prim_buffer.push(m_prim_building.building_rgba[i], m_prim_building.building_vert[i],
m_prim_building.building_st[i]);
m_prim_building.building_stq[i]);
}
}
} break;
case GsPrim::Kind::LINE: {
if (m_prim_building.building_idx == 2) {
math::Vector<double, 3> pt0 = m_prim_building.building_vert[0].cast<double>();
@ -845,13 +926,15 @@ void DirectRenderer::handle_xyzf2_common(u32 x,
}
}
void DirectRenderer::handle_xyzf2(u64 val, SharedRenderState* render_state) {
void DirectRenderer::handle_xyzf2(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
u32 x = val & 0xffff;
u32 y = (val >> 16) & 0xffff;
u32 z = (val >> 32) & 0xffffff;
u32 f = (val >> 56) & 0xff;
handle_xyzf2_common(x, y, z, f, render_state);
handle_xyzf2_common(x, y, z, f, render_state, prof);
}
void DirectRenderer::reset_state() {
@ -915,15 +998,15 @@ void DirectRenderer::PrimGlState::from_register(GsPrim reg) {
DirectRenderer::PrimitiveBuffer::PrimitiveBuffer(int max_triangles) {
rgba_u8.resize(max_triangles * 3);
verts.resize(max_triangles * 3);
sts.resize(max_triangles * 3);
stqs.resize(max_triangles * 3);
max_verts = max_triangles * 3;
}
void DirectRenderer::PrimitiveBuffer::push(const math::Vector<u8, 4>& rgba,
const math::Vector<u32, 3>& vert,
const math::Vector<float, 2>& st) {
const math::Vector<float, 3>& st) {
rgba_u8[vert_count] = rgba;
verts[vert_count] = vert;
sts[vert_count] = st;
stqs[vert_count] = st;
vert_count++;
}

View file

@ -20,24 +20,33 @@ class DirectRenderer : public BucketRenderer {
public:
// specializations of direct renderer to handle certain outputs.
enum class Mode {
NORMAL, // use for general debug drawing, font.
SPRITE_CPU // use for sprites (does the appropriate alpha test)
NORMAL, // use for general debug drawing, font.
SPRITE_CPU, // use for sprites (does the appropriate alpha test tricks)
SKY // disables texture perspective correction
};
DirectRenderer(const std::string& name, BucketId my_id, int batch_size, Mode mode);
~DirectRenderer();
void render(DmaFollower& dma, SharedRenderState* render_state) override;
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
/*!
* Render directly from _VIF_ data.
* You can optionally provide two vif tags that come in front of data.
* These can be set to 0 if you don't have these.
*/
void render_vif(u32 vif0, u32 vif1, const u8* data, u32 size, SharedRenderState* render_state);
void render_vif(u32 vif0,
u32 vif1,
const u8* data,
u32 size,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
/*!
* Render directly from _GIF_ data.
*/
void render_gif(const u8* data, u32 size, SharedRenderState* render_state);
void render_gif(const u8* data,
u32 size,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void reset_state();
@ -49,30 +58,41 @@ class DirectRenderer : public BucketRenderer {
/*!
* If you don't use the render interface, call this at the very end.
*/
void flush_pending(SharedRenderState* render_state);
void flush_pending(SharedRenderState* render_state, ScopedProfilerNode& prof);
void draw_debug_window() override;
private:
void handle_ad(const u8* data, SharedRenderState* render_state);
void handle_zbuf1(u64 val, SharedRenderState* render_state);
void handle_test1(u64 val, SharedRenderState* render_state);
void handle_alpha1(u64 val, SharedRenderState* render_state);
void handle_ad(const u8* data, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_zbuf1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_test1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_alpha1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_pabe(u64 val);
void handle_clamp1(u64 val);
void handle_prim(u64 val, SharedRenderState* render_state);
void handle_prim_packed(const u8* data, SharedRenderState* render_state);
void handle_clamp1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_prim(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_prim_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_rgbaq(u64 val);
void handle_xyzf2(u64 val, SharedRenderState* render_state);
void handle_xyzf2(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_st_packed(const u8* data);
void handle_rgbaq_packed(const u8* data);
void handle_xyzf2_packed(const u8* data, SharedRenderState* render_state);
void handle_tex0_1_packed(const u8* data, SharedRenderState* render_state);
void handle_tex0_1(u64 val, SharedRenderState* render_state);
void handle_xyzf2_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_tex0_1_packed(const u8* data,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_tex0_1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_tex1_1(u64 val);
void handle_texa(u64 val);
void handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f, SharedRenderState* render_state);
void handle_xyzf2_common(u32 x,
u32 y,
u32 z,
u8 f,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void update_gl_prim(SharedRenderState* render_state);
void update_gl_blend();
@ -110,6 +130,12 @@ class DirectRenderer : public BucketRenderer {
} m_blend_state;
struct ClampState {
void from_register(u64 value);
u64 current_register = 0b101;
bool clamp = true;
} m_clamp_state;
// state set through the prim register that requires changing GL stuff.
struct PrimGlState {
void from_register(GsPrim reg);
@ -141,11 +167,11 @@ class DirectRenderer : public BucketRenderer {
std::array<math::Vector<u8, 4>, 3> building_rgba;
std::array<math::Vector<u32, 3>, 3> building_vert;
std::array<math::Vector<float, 2>, 3> building_st;
std::array<math::Vector<float, 3>, 3> building_stq;
int building_idx = 0;
int tri_strip_startup = 0;
float Q = 0;
float Q = 1.0;
} m_prim_building;
@ -153,7 +179,7 @@ class DirectRenderer : public BucketRenderer {
PrimitiveBuffer(int max_triangles);
std::vector<math::Vector<u8, 4>> rgba_u8;
std::vector<math::Vector<u32, 3>> verts;
std::vector<math::Vector<float, 2>> sts;
std::vector<math::Vector<float, 3>> stqs;
int vert_count = 0;
int max_verts = 0;
@ -161,7 +187,7 @@ class DirectRenderer : public BucketRenderer {
bool is_full() { return max_verts < (vert_count + 18); }
void push(const math::Vector<u8, 4>& rgba,
const math::Vector<u32, 3>& vert,
const math::Vector<float, 2>& st);
const math::Vector<float, 3>& stq);
} m_prim_buffer;
struct {

View file

@ -6,6 +6,8 @@
#include "game/graphics/opengl_renderer/SpriteRenderer.h"
#include "game/graphics/opengl_renderer/TextureUploadHandler.h"
#include "third-party/imgui/imgui.h"
#include "common/util/FileUtil.h"
#include "game/graphics/opengl_renderer/SkyRenderer.h"
// for the vif callback
#include "game/kernel/kmachine.h"
@ -21,7 +23,8 @@ void GLAPIENTRY opengl_error_callback(GLenum source,
const GLchar* message,
const void* /*userParam*/) {
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) {
lg::debug("OpenGL notification 0x{:X} S{:X} T{:X}: {}", id, source, type, message);
// On some drivers this prints on every single texture upload, which is too much spam
// lg::debug("OpenGL notification 0x{:X} S{:X} T{:X}: {}", id, source, type, message);
} else if (severity == GL_DEBUG_SEVERITY_LOW) {
lg::info("OpenGL message 0x{:X} S{:X} T{:X}: {}", id, source, type, message);
} else if (severity == GL_DEBUG_SEVERITY_MEDIUM) {
@ -56,7 +59,9 @@ OpenGLRenderer::OpenGLRenderer(std::shared_ptr<TexturePool> texture_pool)
*/
void OpenGLRenderer::init_bucket_renderers() {
init_bucket_renderer<EmptyBucketRenderer>("bucket0", BucketId::BUCKET0);
init_bucket_renderer<SkyRenderer>("sky", BucketId::SKY_DRAW);
init_bucket_renderer<TextureUploadHandler>("tfrag-tex-0", BucketId::TFRAG_TEX_LEVEL0);
init_bucket_renderer<SkyTextureHandler>("sky-tex-0", BucketId::SKY_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("shrub-tex-0", BucketId::SHRUB_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("alpha-tex-0", BucketId::ALPHA_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("pris-tex-0", BucketId::PRIS_TEX_LEVEL0);
@ -79,27 +84,46 @@ void OpenGLRenderer::init_bucket_renderers() {
/*!
* Main render function. This is called from the gfx loop with the chain passed from the game.
*/
void OpenGLRenderer::render(DmaFollower dma,
int window_width_px,
int window_height_px,
bool draw_debug_window,
bool dump_playback) {
m_render_state.dump_playback = dump_playback;
m_render_state.ee_main_memory = dump_playback ? nullptr : g_ee_main_mem;
void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
m_profiler.clear();
m_render_state.dump_playback = settings.playing_from_dump;
m_render_state.ee_main_memory = settings.playing_from_dump ? nullptr : g_ee_main_mem;
m_render_state.offset_of_s7 = offset_of_s7();
setup_frame(window_width_px, window_height_px);
m_render_state.texture_pool->remove_garbage_textures();
{
auto prof = m_profiler.root()->make_scoped_child("frame-setup");
setup_frame(settings.window_width_px, settings.window_height_px);
}
{
auto prof = m_profiler.root()->make_scoped_child("texture-gc");
m_render_state.texture_pool->remove_garbage_textures();
}
// draw_test_triangle();
// render the buckets!
dispatch_buckets(dma);
{
auto prof = m_profiler.root()->make_scoped_child("buckets");
dispatch_buckets(dma, prof);
}
if (draw_debug_window) {
if (settings.draw_render_debug_window) {
auto prof = m_profiler.root()->make_scoped_child("render-window");
draw_renderer_selection_window();
// add a profile bar for the imgui stuff
if (!m_render_state.dump_playback) {
vif_interrupt_callback();
}
}
m_profiler.finish();
if (settings.draw_profiler_window) {
m_profiler.draw();
}
if (settings.save_screenshot) {
finish_screenshot(settings.screenshot_path, settings.window_width_px,
settings.window_height_px);
}
}
void OpenGLRenderer::serialize(Serializer& ser) {
@ -109,6 +133,9 @@ void OpenGLRenderer::serialize(Serializer& ser) {
}
}
/*!
* Draw the per-renderer debug window
*/
void OpenGLRenderer::draw_renderer_selection_window() {
ImGui::Begin("Renderer Debug");
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
@ -145,7 +172,7 @@ void OpenGLRenderer::setup_frame(int window_width_px, int window_height_px) {
/*!
* This function finds buckets and dispatches them to the appropriate part.
*/
void OpenGLRenderer::dispatch_buckets(DmaFollower dma) {
void OpenGLRenderer::dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof) {
// The first thing the DMA chain should be a call to a common default-registers chain.
// this chain resets the state of the GS. After this is buckets
@ -176,7 +203,8 @@ void OpenGLRenderer::dispatch_buckets(DmaFollower dma) {
// loop over the buckets!
for (int bucket_id = 0; bucket_id < (int)BucketId::MAX_BUCKETS; bucket_id++) {
auto& renderer = m_bucket_renderers[bucket_id];
renderer->render(dma, &m_render_state);
auto bucket_prof = prof.make_scoped_child(renderer->name_and_id());
renderer->render(dma, &m_render_state, bucket_prof);
// should have ended at the start of the next chain
assert(dma.current_tag_offset() == m_render_state.next_bucket);
m_render_state.next_bucket += 16;
@ -246,3 +274,25 @@ void OpenGLRenderer::draw_test_triangle() {
glDeleteBuffers(1, &vertex_buffer);
glDeleteVertexArrays(1, &vao);
}
/*!
* Take a screenshot!
*/
void OpenGLRenderer::finish_screenshot(const std::string& output_name, int width, int height) {
std::vector<u32> buffer(width * height);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadBuffer(GL_BACK);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
// flip upside down in place
for (int h = 0; h < height / 2; h++) {
for (int w = 0; w < width; w++) {
std::swap(buffer[h * width + w], buffer[(height - h) * width + w]);
}
}
// set alpha. For some reason, image viewers do weird stuff with alpha.
for (auto& x : buffer) {
x |= 0xff000000;
}
file_util::write_rgba_png(output_name, buffer.data(), width, height);
}

View file

@ -6,30 +6,41 @@
#include "game/graphics/dma/dma_chain_read.h"
#include "game/graphics/opengl_renderer/Shader.h"
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "game/graphics/opengl_renderer/Profiler.h"
struct RenderOptions {
int window_height_px = 0;
int window_width_px = 0;
bool draw_render_debug_window = false;
bool draw_profiler_window = false;
bool playing_from_dump = false;
bool save_screenshot = false;
std::string screenshot_path;
};
class OpenGLRenderer {
public:
OpenGLRenderer(std::shared_ptr<TexturePool> texture_pool);
void render(DmaFollower dma,
int window_width_px,
int window_height_px,
bool draw_debug_window,
bool dump_playback);
void render(DmaFollower dma, const RenderOptions& settings);
void serialize(Serializer& ser);
private:
void setup_frame(int window_width_px, int window_height_px);
void draw_test_triangle();
void dispatch_buckets(DmaFollower dma);
void dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof);
void init_bucket_renderers();
void draw_renderer_selection_window();
void finish_screenshot(const std::string& output_name, int px, int py);
template <typename T, class... Args>
void init_bucket_renderer(const std::string& name, BucketId id, Args&&... args) {
m_bucket_renderers.at((int)id) = std::make_unique<T>(name, id, std::forward<Args>(args)...);
}
SharedRenderState m_render_state;
Profiler m_profiler;
std::array<std::unique_ptr<BucketRenderer>, (int)BucketId::MAX_BUCKETS> m_bucket_renderers;
};

View file

@ -0,0 +1,145 @@
#include <algorithm>
#include "Profiler.h"
#include "common/log/log.h"
#include "common/util/colors.h"
#include "third-party/imgui/imgui.h"
#include "third-party/fmt/core.h"
ProfilerNode::ProfilerNode(const std::string& name) : m_name(name) {}
ProfilerNode* ProfilerNode::make_child(const std::string& name) {
m_children.emplace_back(name);
return &m_children.back();
}
void ProfilerNode::finish() {
if (m_finished) {
lg::error("finish() called twice on {}\n", m_name);
} else {
m_stats.duration = m_timer.getSeconds();
float total_child_time = 0;
for (const auto& child : m_children) {
if (!child.finished()) {
lg::error("finish() not called on {}\n", child.name());
}
total_child_time += child.m_stats.duration;
m_stats.add_draw_stats(child.m_stats);
}
if (!m_children.empty()) {
float unknown_time = m_stats.duration - total_child_time;
if (unknown_time > 0.0001 || unknown_time > (m_stats.duration * 0.05)) {
ProfilerNode unk("unknown");
unk.m_stats.duration = unknown_time;
m_children.push_back(unk);
}
}
}
m_finished = true;
}
void ProfilerNode::sort(ProfilerSort mode) {
if (mode == ProfilerSort::NONE) {
return;
}
std::sort(m_children.begin(), m_children.end(),
[=](const ProfilerNode& a, const ProfilerNode& b) {
switch (mode) {
case ProfilerSort::DRAW_CALLS:
return a.m_stats.draw_calls > b.m_stats.draw_calls;
case ProfilerSort::TIME:
return a.m_stats.duration > b.m_stats.duration;
case ProfilerSort::TRIANGLES:
return a.m_stats.triangles > b.m_stats.triangles;
default:
assert(false);
}
});
for (auto& child : m_children) {
child.sort(mode);
}
}
ScopedProfilerNode ProfilerNode::make_scoped_child(const std::string& name) {
return ScopedProfilerNode(make_child(name));
}
Profiler::Profiler() : m_root("root") {}
void Profiler::clear() {
m_root = ProfilerNode("root");
}
void Profiler::finish() {
m_root.finish();
}
void Profiler::draw() {
ImGui::Begin("Profiler");
const char* listbox_entries[] = {"None", "Time", "Draw Calls", "Tris"};
ImGui::Combo("Sort", &m_mode_selector, listbox_entries, 4);
m_root.sort((ProfilerSort)m_mode_selector);
ImGui::SameLine();
bool all = ImGui::Button("Expand All");
ImGui::Dummy(ImVec2(0.0f, 80.0f));
draw_node(m_root, all, 0, 0.f);
ImGui::End();
}
u32 name_to_color(const std::string& name) {
u64 val = std::hash<std::string>{}(name);
return colors::common_colors[val % colors::COLOR_COUNT] | 0xff000000;
}
void Profiler::draw_node(ProfilerNode& node, bool expand, int depth, float start_time) {
u32 color = 0xFFFFFFFF;
constexpr int origin_x = 40;
constexpr int origin_y = 60;
constexpr int row_height = 15;
constexpr int px_per_ms = 200;
if (node.m_stats.duration > 0.00001) {
color = name_to_color(node.m_name);
}
bool color_orange = false;
ImGui::PushStyleColor(ImGuiCol_Text, color);
auto str =
fmt::format("{:20s} {:.2f}ms {:6d} tri {:4d} draw", node.m_name, node.m_stats.duration * 1000,
node.m_stats.triangles, node.m_stats.draw_calls);
if (node.m_children.empty()) {
ImGui::Text(" %s", str.c_str());
color_orange = ImGui::IsItemHovered();
} else {
if (expand) {
ImGui::SetNextTreeNodeOpen(true);
}
if (ImGui::TreeNode(node.m_name.c_str(), "%s", str.c_str())) {
color_orange = ImGui::IsItemHovered();
float child_start = start_time;
for (auto& child : node.m_children) {
draw_node(child, expand, depth + 1, child_start);
child_start += child.m_stats.duration;
}
ImGui::TreePop();
}
}
if (node.m_stats.duration > 0.00001 || color_orange) {
if (color_orange) {
color = 0xff00a5ff;
}
auto dl = ImGui::GetWindowDrawList();
auto window_pos = ImGui::GetWindowPos();
float x0 = window_pos.x + origin_x + px_per_ms * 1000 * start_time;
float x1 = x0 + px_per_ms * 1000 * node.m_stats.duration;
float y0 = window_pos.y + origin_y + depth * row_height;
float y1 = y0 + row_height;
dl->AddRectFilled(ImVec2(x0, y0), ImVec2(x1, y1), color);
}
ImGui::PopStyleColor();
}

View file

@ -0,0 +1,83 @@
#pragma once
#include <string>
#include <vector>
#include "common/common_types.h"
#include "common/util/Timer.h"
enum class ProfilerSort { NONE = 0, TIME = 1, DRAW_CALLS = 2, TRIANGLES = 3 };
struct ProfilerStats {
float duration = 0; // seconds
u32 draw_calls = 0;
u32 triangles = 0;
void add_draw_stats(const ProfilerStats& other) {
draw_calls += other.draw_calls;
triangles += other.triangles;
}
};
class ScopedProfilerNode;
class ProfilerNode {
public:
ProfilerNode(const std::string& name);
ProfilerNode* make_child(const std::string& name);
ScopedProfilerNode make_scoped_child(const std::string& name);
void sort(ProfilerSort mode);
void finish();
bool finished() const { return m_finished; }
const std::string& name() const { return m_name; }
void add_draw_call(int count = 1) { m_stats.draw_calls += count; }
void add_tri(int count = 1) { m_stats.triangles += count; }
private:
friend class Profiler;
std::string m_name;
ProfilerStats m_stats;
std::vector<ProfilerNode> m_children;
Timer m_timer;
bool m_finished = false;
};
class ScopedProfilerNode {
public:
ScopedProfilerNode(ProfilerNode* node) : m_node(node) {}
ScopedProfilerNode(const ScopedProfilerNode& other) = delete;
ScopedProfilerNode& operator=(const ScopedProfilerNode& other) = delete;
ProfilerNode* make_child(const std::string& name) { return m_node->make_child(name); }
ScopedProfilerNode make_scoped_child(const std::string& name) {
return m_node->make_scoped_child(name);
}
~ScopedProfilerNode() { m_node->finish(); }
void add_draw_call(int count = 1) { m_node->add_draw_call(count); }
void add_tri(int count = 1) { m_node->add_tri(count); }
private:
ProfilerNode* m_node;
};
class Profiler {
public:
Profiler();
void clear();
void draw();
void finish();
ProfilerNode* root() { return &m_root; }
private:
void draw_node(ProfilerNode& node, bool expand, int depth, float start_time);
struct BarEntry {
float duration;
float rgba[4];
};
int m_mode_selector = 0;
ProfilerNode m_root;
};

View file

@ -71,4 +71,6 @@ ShaderLibrary::ShaderLibrary() {
at(ShaderId::DEBUG_RED) = {"debug_red"};
at(ShaderId::SPRITE_CPU) = {"sprite_cpu"};
at(ShaderId::SPRITE_CPU_AFAIL) = {"sprite_cpu_afail"};
at(ShaderId::SKY) = {"sky"};
at(ShaderId::SKY_BLEND) = {"sky_blend"};
}

View file

@ -29,6 +29,8 @@ enum class ShaderId {
DEBUG_RED = 4,
SPRITE_CPU = 5,
SPRITE_CPU_AFAIL = 6,
SKY,
SKY_BLEND,
MAX_SHADERS
};

View file

@ -0,0 +1,370 @@
#include "SkyRenderer.h"
#include "third-party/imgui/imgui.h"
#include "game/graphics/pipelines/opengl.h"
#include "game/graphics/opengl_renderer/AdgifHandler.h"
#include "common/log/log.h"
// The sky texture system blends together sky textures from different levels and times of day
// to create the final sky texture.
// The sequence is:
// set-display-gs-state 8qw
// copy-sky-textures (between 0 and 8, usually 2.)
// copy-cloud-texture
// set alpha state
// reset display gs state
// and this happens twice: one for each level. Note that the first call to either of the copy
// functions will use "draw" mode instead of "blend"
// The results are stored in special sky textures.
// size of the sky texture is 64x96, but it's actually a 64x64 (clouds) and a 32x32 (sky)
SkyTextureHandler::SkyTextureHandler(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id) {
// generate textures for sky blending
glGenFramebuffers(2, m_framebuffers);
glGenTextures(2, m_textures);
GLint old_framebuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer);
// setup the framebuffers
for (int i = 0; i < 2; i++) {
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers[i]);
glBindTexture(GL_TEXTURE_2D, m_textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_sizes[i], m_sizes[i], 0, GL_RGBA,
GL_UNSIGNED_INT_8_8_8_8_REV, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textures[i], 0);
GLenum draw_buffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, draw_buffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
lg::error("SkyTextureHandler setup failed.");
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glGenBuffers(1, &m_gl_vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_gl_vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 6, nullptr, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, old_framebuffer);
// we only draw squares
m_vertex_data[0].x = 0;
m_vertex_data[0].y = 0;
m_vertex_data[1].x = 1;
m_vertex_data[1].y = 0;
m_vertex_data[2].x = 0;
m_vertex_data[2].y = 1;
m_vertex_data[3].x = 1;
m_vertex_data[3].y = 0;
m_vertex_data[4].x = 0;
m_vertex_data[4].y = 1;
m_vertex_data[5].x = 1;
m_vertex_data[5].y = 1;
}
SkyTextureHandler::~SkyTextureHandler() {
glDeleteFramebuffers(2, m_framebuffers);
glDeleteBuffers(1, &m_gl_vertex_buffer);
glDeleteTextures(2, m_textures);
}
void SkyTextureHandler::handle_sky_copies(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (!m_enabled) {
while (dma.current_tag().qwc == 6) {
dma.read_and_advance();
dma.read_and_advance();
}
return;
}
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLint old_viewport[4];
glGetIntegerv(GL_VIEWPORT, old_viewport);
GLint old_framebuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer);
while (dma.current_tag().qwc == 6) {
// assuming that the vif and gif-tag is correct
auto setup_data = dma.read_and_advance();
if (render_state->dump_playback) {
// continue;
}
// first is an adgif
AdgifHelper adgif(setup_data.data + 16);
assert(adgif.is_normal_adgif());
assert(adgif.alpha().data == 0x8000000068); // Cs + Cd
// next is the actual draw
auto draw_data = dma.read_and_advance();
assert(draw_data.size_bytes == 6 * 16);
GifTag draw_or_blend_tag(draw_data.data);
// the first draw overwrites the previous frame's draw by disabling alpha blend (ABE = 0)
bool is_first_draw = !GsPrim(draw_or_blend_tag.prim()).abe();
// here's we're relying on the format of the drawing to get the alpha/offset.
u32 coord;
u32 intensity;
memcpy(&coord, draw_data.data + (5 * 16), 4);
memcpy(&intensity, draw_data.data + 16, 4);
// we didn't parse the render-to-texture setup earlier, so we need a way to tell sky from
// clouds. we can look at the drawing coordinates to tell - the sky is smaller than the clouds.
int buffer_idx = 0;
if (coord == 0x200) {
// sky
buffer_idx = 0;
} else if (coord == 0x400) {
buffer_idx = 1;
} else {
assert(false); // bad data
}
// look up the source texture
auto tex = render_state->texture_pool->lookup(adgif.tex0().tbp0());
assert(tex);
if (!tex->on_gpu) {
render_state->texture_pool->upload_to_gpu(tex);
}
// setup for rendering!
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers[buffer_idx]);
glViewport(0, 0, m_sizes[buffer_idx], m_sizes[buffer_idx]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textures[buffer_idx], 0);
render_state->shaders[ShaderId::SKY_BLEND].activate();
// if the first is set, it disables alpha. we can just clear here, so it's easier to find
// in renderdoc.
if (is_first_draw) {
float clear[4] = {0, 0, 0, 0};
glClearBufferfv(GL_COLOR, 0, clear);
}
// intensities should be 0-128 (maybe higher is okay, but I don't see how this could be
// generated with the GOAL code.)
assert(intensity <= 128);
// todo - could do this on the GPU, but probably not worth it for <20 triangles...
float intensity_float = intensity / 128.f;
for (auto& vert : m_vertex_data) {
vert.intensity = intensity_float;
}
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
// will add.
glBlendFunc(GL_ONE, GL_ONE);
// setup draw data
glBindBuffer(GL_ARRAY_BUFFER, m_gl_vertex_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * 6, m_vertex_data);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, // location 0 in the shader
3, // 3 floats per vert
GL_FLOAT, // floats
GL_TRUE, // normalized, ignored,
0, // tightly packed
0
);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::SKY_BLEND].id(), "T0"), 0);
// Draw a sqaure
glDrawArrays(GL_TRIANGLES, 0, 6);
// 1 draw, 2 triangles
prof.add_draw_call(1);
prof.add_tri(2);
if (buffer_idx == 0) {
if (is_first_draw) {
m_stats.sky_draws++;
} else {
m_stats.sky_blends++;
}
} else {
if (is_first_draw) {
m_stats.cloud_draws++;
} else {
m_stats.cloud_blends++;
}
}
}
// put in pool.
for (int i = 0; i < 2; i++) {
// todo - these are hardcoded and rely on the vram layout.
u32 tbp = i == 0 ? 8064 : 8096;
// lookup existing, or create a new entry
TextureRecord* tex = render_state->texture_pool->lookup(tbp);
if (!tex) {
auto tsp = std::make_shared<TextureRecord>();
render_state->texture_pool->set_texture(tbp, tsp);
tex = tsp.get();
}
// update it
tex->gpu_texture = m_textures[i];
tex->on_gpu = true;
tex->only_on_gpu = true;
tex->do_gc = false;
tex->w = m_sizes[i];
tex->h = m_sizes[i];
tex->name = fmt::format("PC-SKY-{}", i);
}
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer);
glBindVertexArray(0);
glDeleteVertexArrays(1, &vao);
}
void SkyTextureHandler::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
m_stats = {};
// First thing should be a NEXT with two nops. this is a jump from buckets to sprite data
auto data0 = dma.read_and_advance();
assert(data0.vif1() == 0);
assert(data0.vif0() == 0);
assert(data0.size_bytes == 0);
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
// sky renderer didn't run, let's just get out of here.
for (int i = 0; i < 4; i++) {
dma.read_and_advance();
}
assert(dma.current_tag_offset() == render_state->next_bucket);
return;
}
// first is the set-display-gs-state
auto set_display = dma.read_and_advance();
assert(set_display.size_bytes == 8 * 16);
handle_sky_copies(dma, render_state, prof);
auto reset_alpha = dma.read_and_advance();
assert(reset_alpha.size_bytes == 16 * 2);
auto reset_gs = dma.read_and_advance();
assert(reset_gs.size_bytes == 16 * 8);
auto empty = dma.read_and_advance();
assert(empty.size_bytes == 0);
assert(empty.vif0() == 0);
assert(empty.vif1() == 0);
assert(dma.current_tag().kind == DmaTag::Kind::CALL);
dma.read_and_advance();
dma.read_and_advance(); // cnt
assert(dma.current_tag().kind == DmaTag::Kind::RET);
dma.read_and_advance(); // ret
dma.read_and_advance(); // ret
assert(dma.current_tag_offset() == render_state->next_bucket);
}
void SkyTextureHandler::draw_debug_window() {
ImGui::Separator();
ImGui::Text("Draw/Blend ( sky ): %d/%d", m_stats.sky_draws, m_stats.sky_blends);
ImGui::Text("Draw/Blend (cloud): %d/%d", m_stats.cloud_draws, m_stats.cloud_blends);
}
SkyRenderer::SkyRenderer(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id),
m_direct_renderer("sky-direct", my_id, 100, DirectRenderer::Mode::NORMAL) {}
void SkyRenderer::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
m_direct_renderer.reset_state();
m_frame_stats = {};
// First thing should be a NEXT with two nops. this is a jump from buckets to sprite data
auto data0 = dma.read_and_advance();
assert(data0.vif1() == 0);
assert(data0.vif0() == 0);
assert(data0.size_bytes == 0);
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
// sky renderer didn't run, let's just get out of here.
for (int i = 0; i < 4; i++) {
dma.read_and_advance();
}
assert(dma.current_tag_offset() == render_state->next_bucket);
return;
}
auto setup_packet = dma.read_and_advance();
assert(setup_packet.size_bytes == 16 * 4);
m_direct_renderer.render_gif(setup_packet.data, setup_packet.size_bytes, render_state, prof);
auto draw_setup_packet = dma.read_and_advance();
assert(draw_setup_packet.size_bytes == 16 * 5);
m_direct_renderer.render_gif(draw_setup_packet.data, draw_setup_packet.size_bytes, render_state,
prof);
// tex0: tbw = 1, th = 5, hw = 5, sky-base-block
// mmag/mmin = 1
// clamp
// drawing.
int dma_idx = 0;
while (dma.current_tag().kind == DmaTag::Kind::CNT) {
m_frame_stats.gif_packets++;
auto data = dma.read_and_advance();
assert(data.vifcode0().kind == VifCode::Kind::NOP);
assert(data.vifcode1().kind == VifCode::Kind::DIRECT);
assert(data.vifcode1().immediate == data.size_bytes / 16);
if (m_enabled) {
m_direct_renderer.render_gif(data.data, data.size_bytes, render_state, prof);
}
dma_idx++;
}
m_direct_renderer.flush_pending(render_state, prof);
auto empty = dma.read_and_advance();
assert(empty.size_bytes == 0);
assert(empty.vif0() == 0);
assert(empty.vif1() == 0);
assert(dma.current_tag().kind == DmaTag::Kind::CALL);
dma.read_and_advance();
dma.read_and_advance(); // cnt
assert(dma.current_tag().kind == DmaTag::Kind::RET);
dma.read_and_advance(); // ret
dma.read_and_advance(); // ret
assert(dma.current_tag_offset() == render_state->next_bucket);
}
void SkyRenderer::draw_debug_window() {
ImGui::Separator();
ImGui::Text("GIF packets: %d", m_frame_stats.gif_packets);
if (ImGui::TreeNode("direct")) {
m_direct_renderer.draw_debug_window();
ImGui::TreePop();
}
}

View file

@ -0,0 +1,57 @@
#pragma once
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "game/graphics/opengl_renderer/DirectRenderer.h"
/*!
* Handles texture blending for the sky.
* Will insert the result texture into the texture pool.
*/
class SkyTextureHandler : public BucketRenderer {
public:
SkyTextureHandler(const std::string& name, BucketId my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
~SkyTextureHandler();
private:
void handle_sky_copies(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
GLuint m_framebuffers[2]; // sky, clouds
GLuint m_textures[2]; // sky, clouds
int m_sizes[2] = {32, 64};
GLuint m_gl_vertex_buffer;
struct Vertex {
float x = 0;
float y = 0;
float intensity = 0;
};
struct FrameStats {
int sky_draws = 0;
int cloud_draws = 0;
int sky_blends = 0;
int cloud_blends = 0;
} m_stats;
Vertex m_vertex_data[6];
};
/*!
* Handles sky drawing.
*/
class SkyRenderer : public BucketRenderer {
public:
SkyRenderer(const std::string& name, BucketId my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
private:
DirectRenderer m_direct_renderer;
struct FrameStats {
int gif_packets = 0;
} m_frame_stats;
};

View file

@ -147,15 +147,17 @@ SpriteRenderer::SpriteRenderer(const std::string& name, BucketId my_id)
* Run the sprite distorter. Currently nothing uses sprite-distorter so this just skips through
* the table upload stuff that runs every frame, even if there are no sprites.
*/
void SpriteRenderer::render_distorter(DmaFollower& dma, SharedRenderState* render_state) {
void SpriteRenderer::render_distorter(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// Next thing should be the sprite-distorter setup
m_direct_renderer.reset_state();
while (dma.current_tag().qwc != 7) {
auto direct_data = dma.read_and_advance();
m_direct_renderer.render_vif(direct_data.vif0(), direct_data.vif1(), direct_data.data,
direct_data.size_bytes, render_state);
direct_data.size_bytes, render_state, prof);
}
m_direct_renderer.flush_pending(render_state);
m_direct_renderer.flush_pending(render_state, prof);
auto sprite_distorter_direct_setup = dma.read_and_advance();
assert(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP);
assert(sprite_distorter_direct_setup.vifcode1().kind == VifCode::Kind::DIRECT);
@ -233,9 +235,41 @@ void SpriteRenderer::render_3d(DmaFollower& dma) {
// TODO
}
void SpriteRenderer::render_2d_group0(DmaFollower& dma) {
void SpriteRenderer::render_2d_group0(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
(void)dma;
// TODO
while (looks_like_2d_chunk_start(dma)) {
m_debug_stats.blocks_2d_grp0++;
// 4 packets per chunk
// first is the header
u32 sprite_count = process_sprite_chunk_header(dma);
m_debug_stats.count_2d_grp0 += sprite_count;
// second is the vector data
u32 expected_vec_size = sizeof(SpriteVecData2d) * sprite_count;
auto vec_data = dma.read_and_advance();
assert(expected_vec_size <= sizeof(m_vec_data_2d));
unpack_to_no_stcycl(&m_vec_data_2d, vec_data, VifCode::Kind::UNPACK_V4_32, expected_vec_size,
SpriteDataMem::Vector, false, true);
// third is the adgif data
u32 expected_adgif_size = sizeof(AdGifData) * sprite_count;
auto adgif_data = dma.read_and_advance();
assert(expected_adgif_size <= sizeof(m_adgif));
unpack_to_no_stcycl(&m_adgif, adgif_data, VifCode::Kind::UNPACK_V4_32, expected_adgif_size,
SpriteDataMem::Adgif, false, true);
// fourth is the actual run!!!!!
auto run = dma.read_and_advance();
assert(run.vifcode0().kind == VifCode::Kind::NOP);
assert(run.vifcode1().kind == VifCode::Kind::MSCAL);
assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0);
if (m_enabled) {
do_2d_group0_block_cpu(sprite_count, render_state, prof);
}
}
}
void SpriteRenderer::render_fake_shadow(DmaFollower& dma) {
@ -249,7 +283,9 @@ void SpriteRenderer::render_fake_shadow(DmaFollower& dma) {
/*!
* Handle DMA data for group1 2d's (HUD)
*/
void SpriteRenderer::render_2d_group1(DmaFollower& dma, SharedRenderState* render_state) {
void SpriteRenderer::render_2d_group1(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// one time matrix data upload
auto mat_upload = dma.read_and_advance();
bool mat_ok = verify_unpack_with_stcycl(mat_upload, VifCode::Kind::UNPACK_V4_32, 4, 4, 80,
@ -275,7 +311,7 @@ void SpriteRenderer::render_2d_group1(DmaFollower& dma, SharedRenderState* rende
SpriteDataMem::Vector, false, true);
// third is the adgif data
u32 expected_adgif_size = sizeof(AdGif) * sprite_count;
u32 expected_adgif_size = sizeof(AdGifData) * sprite_count;
auto adgif_data = dma.read_and_advance();
assert(expected_adgif_size <= sizeof(m_adgif));
unpack_to_no_stcycl(&m_adgif, adgif_data, VifCode::Kind::UNPACK_V4_32, expected_adgif_size,
@ -287,12 +323,14 @@ void SpriteRenderer::render_2d_group1(DmaFollower& dma, SharedRenderState* rende
assert(run.vifcode1().kind == VifCode::Kind::MSCAL);
assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud);
if (m_enabled) {
do_2d_group1_block_cpu(sprite_count, render_state);
do_2d_group1_block_cpu(sprite_count, render_state, prof);
}
}
}
void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
void SpriteRenderer::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
m_debug_stats = {};
// First thing should be a NEXT with two nops. this is a jump from buckets to sprite data
auto data0 = dma.read_and_advance();
@ -310,7 +348,10 @@ void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
}
// First is the distorter
render_distorter(dma, render_state);
{
auto child = prof.make_scoped_child("distorter");
render_distorter(dma, render_state, child);
}
// next, sprite frame setup.
handle_sprite_frame_setup(dma);
@ -319,15 +360,21 @@ void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
render_3d(dma);
// 2d draw
render_2d_group0(dma);
m_sprite_renderer.reset_state();
{
auto child = prof.make_scoped_child("2d-group0");
render_2d_group0(dma, render_state, child);
}
// shadow draw
render_fake_shadow(dma);
// 2d draw (HUD)
m_sprite_renderer.reset_state();
render_2d_group1(dma, render_state);
m_sprite_renderer.flush_pending(render_state);
{
auto child = prof.make_scoped_child("2d-group1");
render_2d_group1(dma, render_state, child);
m_sprite_renderer.flush_pending(render_state, child);
}
// TODO finish this up.
// fmt::print("next bucket is 0x{}\n", render_state->next_bucket);
@ -345,6 +392,8 @@ void SpriteRenderer::render(DmaFollower& dma, SharedRenderState* render_state) {
void SpriteRenderer::draw_debug_window() {
ImGui::Separator();
ImGui::Text("2D Group 0 (World) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp0,
m_debug_stats.count_2d_grp0);
ImGui::Text("2D Group 1 (HUD) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp1,
m_debug_stats.count_2d_grp1);
ImGui::Checkbox("Extra Debug", &m_extra_debug);
@ -398,9 +447,11 @@ void imgui_vec(const Vector4f& vec, const char* name = nullptr, int indent = 0)
* - do this math on the GPU
* - special case the primitive buffer stuff
*/
void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state) {
void SpriteRenderer::do_2d_group1_block_cpu(u32 count,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (m_extra_debug) {
ImGui::Begin("Sprite Extra Debug");
ImGui::Begin("Sprite Extra Debug 2d_1");
}
// set up double buffering
@ -448,6 +499,9 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render
// lqi.xyzw vf01, vi02 | nop
Vector4f pos_vf01 = m_vec_data_2d[sprite_idx].xyz_sx;
if (m_extra_debug) {
imgui_vec(pos_vf01, "POS", 2);
}
// lqi.xyzw vf05, vi02 | nop
Vector4f flags_vf05 = m_vec_data_2d[sprite_idx].flag_rot_sy;
// lqi.xyzw vf11, vi02 | nop
@ -733,7 +787,7 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render
// SIXTEEN is xy3int
packet.xy3 = xy3_vf22_int;
m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state);
m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state, prof);
if (m_extra_debug) {
imgui_vec(vf12_rotated, "vf12", 2);
imgui_vec(vf13_rotated_trans, "vf13", 2);
@ -766,4 +820,368 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count, SharedRenderState* render
if (m_extra_debug) {
ImGui::End();
}
}
}
void SpriteRenderer::do_2d_group0_block_cpu(u32 count,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (m_extra_debug) {
ImGui::Begin("Sprite Extra Debug 2d_0");
}
Matrix4f camera_matrix = m_3d_matrix_data.camera; // vf25, vf26, vf27, vf28
for (u32 sprite_idx = 0; sprite_idx < count; sprite_idx++) {
if (m_extra_debug) {
ImGui::Text("Sprite: %d", sprite_idx);
}
SpriteHud2DPacket packet;
memset(&packet, 0, sizeof(packet));
// ilw.y vi08, 1(vi02) | nop vi08 = matrix
u32 offset_selector = m_vec_data_2d[sprite_idx].matrix();
assert(offset_selector == 0 || offset_selector == 1);
// moved this out of the loop.
// lq.xyzw vf25, 900(vi00) | nop vf25 = cam_mat
// lq.xyzw vf26, 901(vi00) | nop
// lq.xyzw vf27, 902(vi00) | nop
// lq.xyzw vf28, 903(vi00) | nop
// lq.xyzw vf30, 904(vi00) | nop vf30 = hvdf_offset
// vf30
Vector4f hvdf_offset = m_3d_matrix_data.hvdf_offset;
// lqi.xyzw vf01, vi02 | nop
Vector4f pos_vf01 = m_vec_data_2d[sprite_idx].xyz_sx;
if (m_extra_debug) {
imgui_vec(pos_vf01, "POS", 2);
}
// lqi.xyzw vf05, vi02 | nop
Vector4f flags_vf05 = m_vec_data_2d[sprite_idx].flag_rot_sy;
// lqi.xyzw vf11, vi02 | nop
Vector4f color_vf11 = m_vec_data_2d[sprite_idx].rgba;
// multiplications from the right column
Vector4f transformed_pos_vf02 = matrix_transform(camera_matrix, pos_vf01);
Vector4f scales_vf01 = pos_vf01; // now used for something else.
// lq.xyzw vf12, 1020(vi00) | mulaw.xyzw ACC, vf28, vf00
// vf12 is fog consts
Vector4f fog_consts_vf12(m_frame_data.fog_min, m_frame_data.fog_max, m_frame_data.max_scale,
m_frame_data.bonus);
// ilw.y vi08, 1(vi02) | maddax.xyzw ACC, vf25, vf01
// load offset selector for the next round.
// nop | madday.xyzw ACC, vf26, vf01
// nop | maddz.xyzw vf02, vf27, vf01
// move.w vf05, vf00 | addw.z vf01, vf00, vf05
// scales_vf01.z = sy
scales_vf01.z() = flags_vf05.w(); // start building the scale vector
flags_vf05.w() = 1.f; // what are we building in flags right now??
// nop | nop
// div Q, vf31.x, vf02.w | muly.z vf05, vf05, vf31
float Q = m_frame_data.pfog0 / transformed_pos_vf02.w();
flags_vf05.z() *= m_frame_data.deg_to_rad;
// nop | mul.xyzw vf03, vf02, vf29
Vector4f scaled_pos_vf03 = transformed_pos_vf02.elementwise_multiply(m_frame_data.hmge_scale);
// nop | nop
// nop | nop
// nop | mulz.z vf04, vf05, vf05 (ts)
// fmt::print("rot is {} degrees\n", flags_vf05.z() * 360.0 / (2.0 * M_PI));
// the load is for rotation stuff,
// lq.xyzw vf14, 1001(vi00) | clipw.xyz vf03, vf03 (used for fcand)
// iaddi vi06, vi00, 0x1 | adda.xyzw ACC, vf11, vf11 (used for fmand)
// upcoming fcand with 0x3f, that checks all of them.
bool fcand_result = clip_xyz_plus_minus(scaled_pos_vf03);
bool fmand_result = color_vf11.w() == 0; // (really w+w, but I don't think it matters?)
// L8:
// xgkick double buffer setup
// ior vi05, vi15, vi00 | mul.zw vf01, vf01, Q
scales_vf01.z() *= Q; // sy
scales_vf01.w() *= Q; // sx
// lq.xyzw vf06, 998(vi00) | mulz.xyzw vf15, vf05, vf04 (ts)
auto adgif_vf06 = m_frame_data.adgif_giftag;
// lq.xyzw vf14, 1002(vi00) ts| mula.xyzw ACC, vf05, vf14 (ts)
// fmand vi01, vi06 | mul.xyz vf02, vf02, Q
transformed_pos_vf02.x() *= Q;
transformed_pos_vf02.y() *= Q;
transformed_pos_vf02.z() *= Q;
// if (m_extra_debug) {
// imgui_vec(transformed_pos_vf02, "scaled xf");
// }
// ibne vi00, vi01, L10 | addz.x vf01, vf00, vf01
scales_vf01.x() = scales_vf01.z(); // = sy
if (fmand_result) {
if (m_extra_debug) {
ImGui::TextColored(ImVec4(0.8, 0.2, 0.2, 1.0), "fmand (1) reject");
ImGui::Separator();
}
continue; // reject!
}
// lqi.xyzw vf07, vi03 | mulz.xyzw vf16, vf15, vf04 (ts)
// vf07 is first use adgif
// lq.xyzw vf14, 1003(vi00) | madda.xyzw ACC, vf15, vf14 (ts both)
// lqi.xyzw vf08, vi03 | add.xyzw vf10, vf02, vf30
// vf08 is second user adgif
Vector4f offset_pos_vf10 = transformed_pos_vf02 + hvdf_offset;
// if (m_extra_debug) {
// ImGui::Text("sel %d", offset_selector);
// //ImGui::Text("hvdf off z: %f tf/w z: %f", hvdf_offset.z(), transformed_pos_vf02.z());
// imgui_vec(hvdf_offset, "hvdf");
// imgui_vec(transformed_pos_vf02, "tf'd");
// }
// lqi.xyzw vf09, vi03 | mulw.x vf01, vf01, vf01
// vf09 is third user adgif
scales_vf01.x() *= scales_vf01.w(); // x = sx * sy
// sqi.xyzw vf06, vi05 | mulz.xyzw vf15, vf16, vf04 (ts)
// FIRST ADGIF IS adgif_vf06
packet.adgif_giftag = adgif_vf06;
// lq.xyzw vf14, 1004(vi00) | madda.xyzw ACC, vf16, vf14 (ts both)
// sqi.xyzw vf07, vi05 | maxx.w vf10, vf10, vf12
// SECOND ADGIF is first user
// just do all 5 now.
packet.user_adgif = m_adgif[sprite_idx];
offset_pos_vf10.w() = std::max(offset_pos_vf10.w(), m_frame_data.fog_max);
// sqi.xyzw vf08, vi05 | maxz.zw vf01, vf01, vf31
// THIRD ADGIF is second user
scales_vf01.z() = std::max(scales_vf01.z(), m_frame_data.min_scale);
scales_vf01.w() = std::max(scales_vf01.w(), m_frame_data.min_scale);
// sqi.xyzw vf09, vi05 | mulz.xyzw vf16, vf15, vf04 (ts)
// FOURTH ADGIF is third user
// lq.xyzw vf14, 1005(vi00) | madda.xyzw ACC, vf15, vf14 (ts both)
// lqi.xyzw vf06, vi03 | mulw.x vf01, vf01, vf31
// vf06 is fourth user adgif
scales_vf01.x() *= m_frame_data.inv_area; // x = sx * sy * inv_area (area ratio)
// lqi.xyzw vf07, vi03 | miniy.w vf10, vf10, vf12
// vf07 is fifth user adgif
offset_pos_vf10.w() = std::min(offset_pos_vf10.w(), m_frame_data.fog_min);
// lq.xyzw vf08, 999(vi00) | miniz.zw vf01, vf01, vf12
// vf08 is 2d giftag 1 (NOTE THIS IS DIFFERENT FROM 2d 1)!!!!!
scales_vf01.z() = std::min(scales_vf01.z(), fog_consts_vf12.z());
scales_vf01.w() = std::min(scales_vf01.w(), fog_consts_vf12.z());
bool use_first_giftag = offset_selector == 0;
// ilw.x vi07, -2(vi02) | madd.xyzw vf05, vf16, vf14
auto flag_vi07 = m_vec_data_2d[sprite_idx].flag();
Vector4f vf05_sincos(0, 0, std::sin(flags_vf05.z()), std::cos(flags_vf05.z()));
// lqi.xyzw vf23, vi02 | miniw.x vf01, vf01, vf00
// pipeline
scales_vf01.x() = std::min(scales_vf01.x(), 1.f);
// nop | suby.w vf02, vf10, vf12 (unique)
transformed_pos_vf02.w() = offset_pos_vf10.w() - fog_consts_vf12.y();
// lqi.xyzw vf24, vi02 | mulx.w vf11, vf11, vf01
// pipeline
color_vf11.w() *= scales_vf01.x(); // is this right? doesn't this stall??
// fcand vi01, 0x3f | mulaw.xyzw ACC, vf28, vf00
// already computed pipeline
// lq.xyzw vf17, 1006(vi00) | maddax.xyzw ACC, vf25, vf23 (pipeline)
Vector4f basis_x_vf17 = m_frame_data.basis_x;
// fmand vi09, vi06 | nop
// ibne vi00, vi09, L6 | nop
if (transformed_pos_vf02.w() != 0) {
if (m_extra_debug) {
ImGui::TextColored(ImVec4(0.8, 0.2, 0.2, 1.0), "fmand (2) trick");
}
use_first_giftag = false;
}
// lq.xyzw vf18, 1007(vi00) | madday.xyzw ACC, vf26, vf23 (pipeline)
Vector4f basis_y_vf18 = m_frame_data.basis_y;
assert(flag_vi07 == 0);
Vector4f* xy_array = m_frame_data.xy_array + flag_vi07;
// lq.xyzw vf19, 980(vi07) | ftoi0.xyzw vf11, vf11
Vector4f xy0_vf19 = xy_array[0];
math::Vector<s32, 4> color_integer_vf11 = color_vf11.cast<s32>();
// lq.xyzw vf20, 981(vi07) | maddz.xyzw vf02, vf27, vf23 (pipeline)
Vector4f xy1_vf20 = xy_array[1];
// lq.xyzw vf21, 982(vi07) | mulaw.xyzw ACC, vf17, vf05
Vector4f xy2_vf21 = xy_array[2];
Vector4f acc = basis_x_vf17 * vf05_sincos.w();
// lq.xyzw vf22, 983(vi07) | msubz.xyzw vf12, vf18, vf05
Vector4f xy3_vf22 = xy_array[3];
Vector4f vf12_rotated = acc - (basis_y_vf18 * vf05_sincos.z());
// sq.xyzw vf11, 3(vi05) | mulaz.xyzw ACC, vf17, vf05
// EIGHTH is color integer
packet.color = color_integer_vf11;
acc = basis_x_vf17 * vf05_sincos.z();
// lqi.xyzw vf11, vi02 | maddw.xyzw vf13, vf18, vf05
// (pipeline)
Vector4f vf13_rotated_trans = acc + basis_y_vf18 * vf05_sincos.w();
// move.w vf24, vf00 | addw.z vf23, vf00, vf24 (pipeline both)
// div Q, vf31.x, vf02.w | mulw.xyzw vf12, vf12, vf01
// (pipeline)
vf12_rotated *= scales_vf01.w();
// ibne vi00, vi01, L9 | muly.z vf24, vf24, vf31 (pipeline)
if (fcand_result) {
if (m_extra_debug) {
ImGui::TextColored(ImVec4(0.8, 0.2, 0.2, 1.0), "fcand reject");
ImGui::Separator();
}
continue; // reject (could move earlier)
}
// ilw.y vi08, 1(vi02) | mulz.xyzw vf13, vf13, vf01
// (pipeline)
vf13_rotated_trans *= scales_vf01.z();
// LEFT OFF HERE!
// sqi.xyzw vf06, vi05 | mul.xyzw vf03, vf02, vf29
// FIFTH is fourth user
// sqi.xyzw vf07, vi05 | mulaw.xyzw ACC, vf10, vf00
// SIXTH is fifth user
acc = offset_pos_vf10;
// sqi.xyzw vf08, vi05 | maddax.xyzw ACC, vf12, vf19
// SEVENTH is giftag2
packet.sprite_giftag =
use_first_giftag ? m_frame_data.sprite_2d_giftag : m_frame_data.sprite_2d_giftag2;
acc += vf12_rotated * xy0_vf19.x();
// lq.xyzw vf06, 988(vi00) | maddy.xyzw vf19, vf13, vf19
Vector4f st0_vf06 = m_frame_data.st_array[0];
xy0_vf19 = acc + vf13_rotated_trans * xy0_vf19.y();
// lq.xyzw vf07, 989(vi00) | mulaw.xyzw ACC, vf10, vf00
Vector4f st1_vf07 = m_frame_data.st_array[1];
acc = offset_pos_vf10;
// lq.xyzw vf08, 990(vi00) | maddax.xyzw ACC, vf12, vf20
Vector4f st2_vf08 = m_frame_data.st_array[2];
acc += vf12_rotated * xy1_vf20.x();
// lq.xyzw vf09, 991(vi00) | maddy.xyzw vf20, vf13, vf20
Vector4f st3_vf09 = m_frame_data.st_array[3];
xy1_vf20 = acc + vf13_rotated_trans * xy1_vf20.y();
// sq.xyzw vf06, 1(vi05) | mulaw.xyzw ACC, vf10, vf00
// NINTH is st0
packet.st0 = st0_vf06;
acc = offset_pos_vf10;
// sq.xyzw vf07, 3(vi05) | maddax.xyzw ACC, vf12, vf21
// ELEVEN is st1
packet.st1 = st1_vf07;
acc += vf12_rotated * xy2_vf21.x();
// sq.xyzw vf08, 5(vi05) | maddy.xyzw vf21, vf13, vf21
// THIRTEEN is st2
packet.st2 = st2_vf08;
xy2_vf21 = acc + vf13_rotated_trans * xy2_vf21.y();
// sq.xyzw vf09, 7(vi05) | mulaw.xyzw ACC, vf10, vf00
// FIFTEEN is st3
packet.st3 = st3_vf09;
acc = offset_pos_vf10;
// nop | maddax.xyzw ACC, vf12, vf22
acc += vf12_rotated * xy3_vf22.x();
// nop | maddy.xyzw vf22, vf13, vf22
xy3_vf22 = acc + vf13_rotated_trans * xy3_vf22.y();
// lq.xyzw vf12, 1020(vi00) | ftoi4.xyzw vf19, vf19
// (pipeline)
auto xy0_vf19_int = (xy0_vf19 * 16.f).cast<s32>();
// lq.xyzw vf14, 1001(vi00) | ftoi4.xyzw vf20, vf20
// (pipeline)
auto xy1_vf20_int = (xy1_vf20 * 16.f).cast<s32>();
// move.xyzw vf05, vf24 | ftoi4.xyzw vf21, vf21
// (pipeline)
auto xy2_vf21_int = (xy2_vf21 * 16.f).cast<s32>();
// move.xyzw vf01, vf23 | ftoi4.xyzw vf22, vf22
// (pipeline)
auto xy3_vf22_int = (xy3_vf22 * 16.f).cast<s32>();
if (m_extra_debug) {
u32 zi = xy3_vf22_int.z() >> 4;
ImGui::Text("z (int): 0x%08x %s", zi, zi >= (1 << 24) ? "bad" : "");
ImGui::Text("z (flt): %f", (double)(((u32)zi) << 8) / UINT32_MAX);
}
// sq.xyzw vf19, 2(vi05) | mulz.z vf04, vf24, vf24 (pipeline)
// TENTH is xy0int
packet.xy0 = xy0_vf19_int;
// sq.xyzw vf20, 4(vi05) | clipw.xyz vf03, vf03 (pipeline)
// TWELVE is xy1int
packet.xy1 = xy1_vf20_int;
// sq.xyzw vf21, 6(vi05) | nop
// FOURTEEN is xy2int
packet.xy2 = xy2_vf21_int;
// sq.xyzw vf22, 8(vi05) | nop
// SIXTEEN is xy3int
packet.xy3 = xy3_vf22_int;
m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state, prof);
if (m_extra_debug) {
imgui_vec(vf12_rotated, "vf12", 2);
imgui_vec(vf13_rotated_trans, "vf13", 2);
ImGui::Separator();
}
// xgkick vi15 | nop
// iaddi vi04, vi04, -0x1 | nop
// iaddiu vi01, vi00, 0x672 | nop
// ibne vi00, vi04, L8 | nop
// isub vi15, vi01, vi15 | adda.xyzw ACC, vf11, vf11
// nop | nop :e
// nop | nop
// L9:
// iaddi vi04, vi04, -0x1 | nop
// iaddi vi02, vi02, -0x3 | nop
// ibne vi00, vi04, L7 | nop
// nop | nop
// nop | nop :e
// nop | nop
// L10:
// iaddi vi04, vi04, -0x1 | nop
// iaddi vi03, vi03, 0x4 | nop
// ibne vi00, vi04, L7 | nop
// nop | nop
// nop | nop :e
// nop | nop
}
if (m_extra_debug) {
ImGui::End();
}
}

View file

@ -27,7 +27,7 @@ struct SpriteFrameData {
Vector4f basis_x;
Vector4f basis_y;
GifTag sprite_3d_giftag;
AdGif screen_shader;
AdGifData screen_shader;
GifTag clipped_giftag;
Vector4f inv_hmge_scale;
Vector4f stq_offset;
@ -117,7 +117,7 @@ enum SpriteDataMem {
*/
struct SpriteHud2DPacket {
GifTag adgif_giftag; // starts the adgif shader. 0
AdGif user_adgif; // the adgif shader 16
AdGifData user_adgif; // the adgif shader 16
GifTag sprite_giftag; // 96
math::Vector<s32, 4> color;
Vector4f st0;
@ -146,18 +146,25 @@ static_assert(sizeof(SpriteFrameData) == 0x290, "SpriteFrameData size");
class SpriteRenderer : public BucketRenderer {
public:
SpriteRenderer(const std::string& name, BucketId my_id);
void render(DmaFollower& dma, SharedRenderState* render_state) override;
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
static constexpr int SPRITES_PER_CHUNK = 48;
private:
void render_distorter(DmaFollower& dma, SharedRenderState* render_state);
void render_distorter(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_sprite_frame_setup(DmaFollower& dma);
void render_3d(DmaFollower& dma);
void render_2d_group0(DmaFollower& dma);
void render_2d_group0(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void render_fake_shadow(DmaFollower& dma);
void render_2d_group1(DmaFollower& dma, SharedRenderState* render_state);
void do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state);
void render_2d_group1(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof);
void do_2d_group0_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof);
u8 m_sprite_distorter_setup[7 * 16]; // direct data
u8 m_sprite_direct_setup[3 * 16];
@ -166,9 +173,11 @@ class SpriteRenderer : public BucketRenderer {
SpriteHudMatrixData m_hud_matrix_data;
SpriteVecData2d m_vec_data_2d[SPRITES_PER_CHUNK];
AdGif m_adgif[SPRITES_PER_CHUNK];
AdGifData m_adgif[SPRITES_PER_CHUNK];
struct DebugStats {
int blocks_2d_grp0 = 0;
int count_2d_grp0 = 0;
int blocks_2d_grp1 = 0;
int count_2d_grp1 = 0;
} m_debug_stats;

View file

@ -7,7 +7,9 @@
TextureUploadHandler::TextureUploadHandler(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id) {}
void TextureUploadHandler::render(DmaFollower& dma, SharedRenderState* render_state) {
void TextureUploadHandler::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& /*prof*/) {
m_stats = {};
// this is the data we get from the PC Port modification.

View file

@ -14,7 +14,7 @@
class TextureUploadHandler : public BucketRenderer {
public:
TextureUploadHandler(const std::string& name, BucketId my_id);
void render(DmaFollower& dma, SharedRenderState* render_state) override;
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
void serialize(Serializer& ser) override;

View file

@ -84,10 +84,14 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
if (ImGui::BeginMenu("Windows")) {
ImGui::MenuItem("Frame Time Plot", nullptr, &m_draw_frame_time);
ImGui::MenuItem("Render Debug", nullptr, &m_draw_debug);
ImGui::MenuItem("Profiler", nullptr, &m_draw_profiler);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Gfx Dump")) {
ImGui::MenuItem("Screenshot Next Frame!", nullptr, &m_want_screenshot);
ImGui::InputText("File", m_screenshot_save_name, 30);
ImGui::Separator();
ImGui::MenuItem("Dump Next Frame!", nullptr, &m_want_save);
bool old_replay = m_want_replay;
ImGui::MenuItem("Load Saved Dump", nullptr, &m_want_replay);
@ -96,7 +100,7 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
}
ImGui::Separator();
ImGui::InputText("Filename", m_dump_save_name, 12);
ImGui::InputText("Dump", m_dump_save_name, 12);
ImGui::EndMenu();
}
}

View file

@ -39,19 +39,32 @@ class OpenGlDebugGui {
void finish_frame();
void draw(const DmaStats& dma_stats);
bool should_draw_render_debug() const { return m_draw_debug; }
bool should_draw_profiler() const { return m_draw_profiler; }
bool& want_save() { return m_want_save; }
bool& want_dump_replay() { return m_want_replay; }
bool& want_dump_load() { return m_want_dump_load; }
const char* dump_name() const { return m_dump_save_name; }
const char* screenshot_name() const { return m_screenshot_save_name; }
bool should_advance_frame() { return m_frame_timer.should_advance_frame(); }
bool get_screenshot_flag() {
if (m_want_screenshot) {
m_want_screenshot = false;
return true;
}
return false;
}
private:
FrameTimeRecorder m_frame_timer;
bool m_draw_frame_time = false;
bool m_draw_profiler = false;
bool m_draw_debug = false;
bool m_want_save = false;
bool m_want_replay = false;
bool m_want_dump_load = false;
bool m_want_screenshot = false;
char m_dump_save_name[256] = "dump.bin";
char m_screenshot_save_name[256] = "screenshot.png";
};

View file

@ -7,6 +7,7 @@ in vec2 tex_coord;
uniform sampler2D tex_T0;
void main() {
vec4 T0 = texture(tex_T0, tex_coord);
//vec4 T0 = texture(tex_T0, tex_coord);
vec4 T0 = textureProj(tex_T0, vec3(tex_coord, 1.0));
color = fragment_color * T0 * 2.0;
}

View file

@ -2,7 +2,7 @@
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec2 tex_coord_in;
layout (location = 2) in vec3 tex_coord_in;
out vec4 fragment_color;
out vec2 tex_coord;
@ -10,5 +10,5 @@ out vec2 tex_coord;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.);
tex_coord = tex_coord_in;
tex_coord = tex_coord_in.xy;
}

View file

@ -3,11 +3,13 @@
out vec4 color;
in vec4 fragment_color;
in vec2 tex_coord;
in vec3 tex_coord;
uniform sampler2D tex_T0;
void main() {
vec4 T0 = texture(tex_T0, tex_coord);
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
//vec4 T0 = textureProj(tex_T0, vec3(tex_coord.xy, 1.0));
T0.w = 1.0;
color = fragment_color * T0 * 2.0;
}

View file

@ -2,13 +2,13 @@
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec2 tex_coord_in;
layout (location = 2) in vec3 tex_coord_in;
out vec4 fragment_color;
out vec2 tex_coord;
out vec3 tex_coord;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z, 1.0);
gl_Position = vec4((position_in.x - 0.5) * 16. , -(position_in.y - 0.5) * 32, position_in.z, 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.a * 2);
tex_coord = tex_coord_in;
}

View file

@ -0,0 +1,13 @@
#version 330 core
out vec4 color;
in vec4 fragment_color;
in vec3 tex_coord;
uniform sampler2D tex_T0;
void main() {
vec4 T0 = texture(tex_T0, tex_coord.xy / tex_coord.z);
T0.w = 1.0;
color = fragment_color * T0 * 2.0;
}

View file

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 position_in;
layout (location = 1) in vec4 rgba_in;
layout (location = 2) in vec3 tex_coord_in;
out vec4 fragment_color;
noperspective out vec3 tex_coord;
void main() {
gl_Position = vec4((position_in.x - 0.5) * 16. , -(position_in.y - 0.5) * 32, position_in.z, 1.0);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.a * 2);
tex_coord = tex_coord_in;
}

View file

@ -0,0 +1,11 @@
#version 330 core
layout(location = 0) out vec4 color;
in vec3 tex_coord;
uniform sampler2D tex_T0;
void main() {
vec4 T0 = texture(tex_T0, tex_coord.xy);
color = vec4(((T0 )) * tex_coord.z);
}

View file

@ -0,0 +1,10 @@
#version 330 core
layout (location = 0) in vec3 position_in;
out vec3 tex_coord;
void main() {
gl_Position = vec4(position_in.x*2 -1, position_in.y*2-1, 0.0, 1.0);
tex_coord = position_in;
}

View file

@ -190,6 +190,13 @@ static void gl_kill_display(GfxDisplay* display) {
glfwDestroyWindow(display->window_glfw);
}
namespace {
std::string make_output_file_name(const std::string& file_name) {
file_util::create_dir_if_needed(file_util::get_file_path({"gfx_dumps"}));
return file_util::get_file_path({"gfx_dumps", file_name});
}
} // namespace
void make_gfx_dump() {
Timer ser_timer;
Serializer ser;
@ -203,10 +210,8 @@ void make_gfx_dump() {
ser_timer.getMs(), ((double)result.second) / (1 << 20),
((double)compressed.size() / (1 << 20)), compression_timer.getMs());
file_util::create_dir_if_needed(file_util::get_file_path({"gfx_dumps"}));
file_util::write_binary_file(
file_util::get_file_path({"gfx_dumps", g_gfx_data->debug_gui.dump_name()}), compressed.data(),
compressed.size());
file_util::write_binary_file(make_output_file_name(g_gfx_data->debug_gui.dump_name()),
compressed.data(), compressed.size());
}
void render_game_frame(int width, int height) {
@ -234,9 +239,17 @@ void render_game_frame(int width, int height) {
auto& chain = g_gfx_data->dma_copier.get_last_result();
g_gfx_data->frame_idx_of_input_data = g_gfx_data->frame_idx;
g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), width,
height, g_gfx_data->debug_gui.should_draw_render_debug(),
false);
RenderOptions options;
options.window_height_px = height;
options.window_width_px = width;
options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug();
options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler();
options.playing_from_dump = false;
options.save_screenshot = g_gfx_data->debug_gui.get_screenshot_flag();
if (options.save_screenshot) {
options.screenshot_path = make_output_file_name(g_gfx_data->debug_gui.screenshot_name());
}
g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), options);
}
// before vsync, mark the chain as rendered.
@ -252,8 +265,8 @@ void render_game_frame(int width, int height) {
void render_dump_frame(int width, int height) {
Timer deser_timer;
if (g_gfx_data->debug_gui.want_dump_load()) {
auto data = file_util::read_binary_file(
file_util::get_file_path({"gfx_dumps", g_gfx_data->debug_gui.dump_name()}));
auto data =
file_util::read_binary_file(make_output_file_name(g_gfx_data->debug_gui.dump_name()));
auto decompressed = compression::decompress_zstd(data.data(), data.size());
g_gfx_data->loaded_dump = Serializer(decompressed.data(), decompressed.size());
}
@ -268,8 +281,19 @@ void render_dump_frame(int width, int height) {
g_gfx_data->debug_gui.want_dump_load() = false;
auto& chain = g_gfx_data->dma_copier.get_last_result();
g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), width, height,
g_gfx_data->debug_gui.should_draw_render_debug(), true);
RenderOptions options;
options.window_height_px = height;
options.window_width_px = width;
options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug();
options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler();
options.playing_from_dump = true;
options.save_screenshot = g_gfx_data->debug_gui.get_screenshot_flag();
if (options.save_screenshot) {
options.screenshot_path = make_output_file_name(g_gfx_data->debug_gui.screenshot_name());
}
g_gfx_data->ogl_renderer.render(DmaFollower(chain.data.data(), chain.start_offset), options);
}
static void gl_render_display(GfxDisplay* display) {
@ -314,8 +338,9 @@ static void gl_render_display(GfxDisplay* display) {
// exit if display window was closed
if (glfwWindowShouldClose(window)) {
// Display::KillDisplay(window);
std::unique_lock<std::mutex> lock(g_gfx_data->sync_mutex);
MasterExit = 2;
g_gfx_data->sync_cv.notify_all();
}
}
@ -330,7 +355,7 @@ u32 gl_vsync() {
std::unique_lock<std::mutex> lock(g_gfx_data->sync_mutex);
auto init_frame = g_gfx_data->frame_idx_of_input_data;
g_gfx_data->sync_cv.wait(lock, [=] { return g_gfx_data->frame_idx > init_frame; });
g_gfx_data->sync_cv.wait(lock, [=] { return MasterExit || g_gfx_data->frame_idx > init_frame; });
return g_gfx_data->frame_idx & 1;
}

View file

@ -36,6 +36,16 @@ std::string GoalTexturePage::print() const {
}
void TextureRecord::serialize(Serializer& ser) {
if (only_on_gpu) {
assert(on_gpu);
if (ser.is_saving()) {
// we should download the texture and save it.
data.resize(w * h * 4);
glBindTexture(GL_TEXTURE_2D, gpu_texture);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data.data());
}
}
ser.from_str(&page_name);
ser.from_str(&name);
ser.from_ptr(&mip_level);
@ -46,6 +56,7 @@ void TextureRecord::serialize(Serializer& ser) {
ser.from_ptr(&data_segment);
ser.from_ptr(&on_gpu);
ser.from_ptr(&do_gc);
ser.from_ptr(&only_on_gpu);
ser.from_ptr(&gpu_texture);
ser.from_ptr(&dest);
ser.from_pod_vector(&data);
@ -53,6 +64,10 @@ void TextureRecord::serialize(Serializer& ser) {
ser.from_ptr(&max_a_zero);
ser.from_ptr(&min_a_nonzero);
ser.from_ptr(&max_a_nonzero);
if (ser.is_loading()) {
gpu_texture = -1;
}
}
void TextureData::serialize(Serializer& ser) {
@ -67,6 +82,7 @@ void TextureData::serialize(Serializer& ser) {
if (mt4hh_texture) {
ser.save<u8>(1); // has it.
mt4hh_texture->serialize(ser);
} else {
ser.save<u8>(0);
}
@ -75,9 +91,7 @@ void TextureData::serialize(Serializer& ser) {
if (has_normal) {
normal_texture = std::make_shared<TextureRecord>();
normal_texture->serialize(ser);
// after deserializing, nothing is on the GPU
normal_texture->on_gpu = false;
// there will be a duplicate copy of this texture in the bucket, we want this one to be gc'd
normal_texture->do_gc = true;
} else {
normal_texture.reset();
@ -284,6 +298,7 @@ void TexturePool::set_texture(u32 location, std::shared_ptr<TextureRecord> recor
if (m_textures.at(location).normal_texture) {
if (record->do_gc && m_textures.at(location).normal_texture != record) {
m_garbage_textures.push_back(std::move(m_textures[location].normal_texture));
fmt::print("replace add to garbage list {}\n", m_garbage_textures.back()->name);
}
}
m_textures[location].normal_texture = std::move(record);
@ -356,8 +371,8 @@ void TexturePool::draw_debug_for_tex(const std::string& name, TextureRecord& tex
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.3, 0.8, 0.3, 1.0));
}
if (ImGui::TreeNode(name.c_str())) {
ImGui::Text("P: %s sz: %d x %d mip %d GPU? %d psm %d cpsm %d", tex.page_name.c_str(), tex.w,
tex.h, tex.mip_level, tex.on_gpu, tex.psm, tex.cpsm);
ImGui::Text("P: %s sz: %d x %d mip %d GPU? %d psm %d cpsm %d dest %d", tex.page_name.c_str(),
tex.w, tex.h, tex.mip_level, tex.on_gpu, tex.psm, tex.cpsm, tex.dest);
if (tex.on_gpu) {
ImGui::Image((void*)tex.gpu_texture, ImVec2(tex.w, tex.h));
} else {
@ -401,6 +416,7 @@ void TexturePool::remove_garbage_textures() {
for (auto& t : m_garbage_textures) {
if (t->on_gpu) {
m_most_recent_gc_count_gpu++;
fmt::print("GC {}\n", t->name);
t->unload_from_gpu();
}
}
@ -409,5 +425,16 @@ void TexturePool::remove_garbage_textures() {
void TexturePool::discard(std::shared_ptr<TextureRecord> tex) {
assert(!tex->do_gc);
fmt::print("discard {}\n", tex->name);
m_garbage_textures.push_back(tex);
}
TextureRecord* TexturePool::get_random_texture() {
u32 idx = 8;
for (u32 i = 0; i < m_textures.size(); i++) {
if (m_textures.at((i + idx) % m_textures.size()).normal_texture) {
return m_textures.at((i + idx) % m_textures.size()).normal_texture.get();
}
}
return nullptr;
}

View file

@ -16,7 +16,8 @@ struct TextureRecord {
u16 w, h;
u8 data_segment;
bool on_gpu = false;
bool do_gc = true;
bool do_gc = true; // if set, will be unloaded from GPU when another is upload on top
bool only_on_gpu = false;
std::vector<u8> data;
u64 gpu_texture = 0;
u32 dest = -1;
@ -124,6 +125,8 @@ class TexturePool {
}
}
TextureRecord* get_random_texture();
void upload_to_gpu(TextureRecord* rec);
void relocate(u32 destination, u32 source, u32 format);

View file

@ -364,7 +364,8 @@ void load_and_link_dgo_from_c(const char* name, Ptr<kheapinfo> heap, u32 linkFla
char objName[64];
strcpy(objName, (dgoObj + 4).cast<char>().c()); // name from dgo object header
lg::debug("[link and exec] {} {} {}", objName, lastObjectLoaded, objSize);
lg::debug("[link and exec] {:18s} {} {:6d} heap-use {:8d} {:8d}", objName, lastObjectLoaded,
objSize, kheapused(kglobalheap), kheapused(kdebugheap));
link_and_exec(obj, objName, objSize, heap, linkFlag); // link now!
// inform IOP we are done

View file

@ -23,6 +23,7 @@
#include "common/goal_constants.h"
#include "common/log/log.h"
#include "common/util/Timer.h"
#include "game/mips2c/mips2c_table.h"
//! Controls link mode when EnableMethodSet = 0, MasterDebug = 1, DiskBoot = 0. Will enable a
//! warning message if EnableMethodSet = 1
@ -1712,6 +1713,8 @@ s32 test_function(s32 arg0, s32 arg1, s32 arg2, s32 arg3) {
*/
s32 InitHeapAndSymbol() {
Timer heap_init_timer;
// reset all mips2c functions
Mips2C::gLinkedFunctionTable = {};
// allocate memory for the symbol table
auto symbol_table = kmalloc(kglobalheap, 0x20000, KMALLOC_MEMSET, "symbol-table").cast<u32>();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,163 @@
//--------------------------MIPS2C---------------------
// clang-format off
#include "game/mips2c/mips2c_private.h"
#include "game/kernel/kscheme.h"
namespace Mips2C {
namespace adgif_shader_texture_with_update {
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
c->ld(a2, 16, a0); // ld a2, 16(a0)
c->addiu(v1, r0, 256); // addiu v1, r0, 256
c->andi(a2, a2, 513); // andi a2, a2, 513
c->mtc1(f0, v1); // mtc1 f0, v1
c->cvtsw(f0, f0); // cvt.s.w f0, f0
c->lbu(v1, 4, a1); // lbu v1, 4(a1)
c->lwc1(f1, 44, a1); // lwc1 f1, 44(a1)
c->daddiu(v1, v1, -1); // daddiu v1, v1, -1
c->divs(f0, f0, f1); // div.s f0, f0, f1
c->dsll(v1, v1, 2); // dsll v1, v1, 2
c->or_(a2, a2, v1); // or a2, a2, v1
c->lbu(v1, 7, a1); // lbu v1, 7(a1)
c->dsll(v1, v1, 19); // dsll v1, v1, 19
c->lbu(a3, 5, a1); // lbu a3, 5(a1)
c->or_(a2, a2, v1); // or a2, a2, v1
c->dsll(a3, a3, 5); // dsll a3, a3, 5
c->or_(a2, a2, a3); // or a2, a2, a3
c->ld(t1, 0, a0); // ld t1, 0(a0)
c->dsll(t1, t1, 27); // dsll t1, t1, 27
c->lbu(v1, 6, a1); // lbu v1, 6(a1)
c->dsra32(t1, t1, 30); // dsra32 t1, t1, 30
c->dsll(v1, v1, 20); // dsll v1, v1, 20
c->dsll32(t1, t1, 3); // dsll32 t1, t1, 3
c->lhu(a3, 10, a1); // lhu a3, 10(a1)
c->or_(t1, t1, v1); // or t1, t1, v1
c->lbu(v1, 26, a1); // lbu v1, 26(a1)
c->or_(t1, t1, a3); // or t1, t1, a3
c->dsll(v1, v1, 14); // dsll v1, v1, 14
c->or_(t1, t1, v1); // or t1, t1, v1
c->lhu(v1, 0, a1); // lhu v1, 0(a1)
c->plzcw(v1, v1); // plzcw v1, v1
c->addiu(t0, r0, 30); // addiu t0, r0, 30
c->subu(v1, t0, v1); // subu v1, t0, v1
c->lhu(a3, 2, a1); // lhu a3, 2(a1)
c->dsll(v1, v1, 26); // dsll v1, v1, 26
c->plzcw(a3, a3); // plzcw a3, a3
c->or_(t1, t1, v1); // or t1, t1, v1
c->subu(a3, t0, a3); // subu a3, t0, a3
c->dsll(a3, a3, 30); // dsll a3, a3, 30
c->addiu(v1, r0, 1); // addiu v1, r0, 1
c->or_(t1, t1, a3); // or t1, t1, a3
c->dsll32(v1, v1, 2); // dsll32 v1, v1, 2
c->or_(t1, t1, v1); // or t1, t1, v1
c->lhu(v1, 24, a1); // lhu v1, 24(a1)
c->dsll32(v1, v1, 5); // dsll32 v1, v1, 5
c->lhu(a3, 8, a1); // lhu a3, 8(a1)
c->dsll32(a3, a3, 19); // dsll32 a3, a3, 19
c->or_(t1, t1, v1); // or t1, t1, v1
c->or_(t1, t1, a3); // or t1, t1, a3
c->addiu(v1, r0, 1); // addiu v1, r0, 1
c->dsll32(v1, v1, 29); // dsll32 v1, v1, 29
c->cvtws(f0, f0); // cvt.w.s f0, f0
c->or_(t1, t1, v1); // or t1, t1, v1
c->mfc1(v1, f0); // mfc1 v1, f0
c->sd(t1, 0, a0); // sd t1, 0(a0)
c->plzcw(a3, v1); // plzcw a3, v1
c->subu(a3, t0, a3); // subu a3, t0, a3
c->lbu(t0, 7, a1); // lbu t0, 7(a1)
c->daddiu(t0, t0, -1); // daddiu t0, t0, -1
// nop // sll r0, r0, 0
bc = c->sgpr64(t0) == 0; // beq t0, r0, L22
// nop // sll r0, r0, 0
if (bc) {goto block_2;} // branch non-likely
c->daddiu(t0, a3, -4); // daddiu t0, a3, -4
c->dsll(a3, a3, 4); // dsll a3, a3, 4
c->dsrav(t0, v1, t0); // dsrav t0, v1, t0
c->daddiu(a3, a3, -175); // daddiu a3, a3, -175
c->andi(t0, t0, 15); // andi t0, t0, 15
// nop // sll r0, r0, 0
//beq r0, r0, L23 // beq r0, r0, L23
c->daddu(a3, a3, t0); // daddu a3, a3, t0
goto block_3; // branch always
block_2:
c->daddiu(t0, a3, -5); // daddiu t0, a3, -5
c->dsll(a3, a3, 5); // dsll a3, a3, 5
c->dsrav(t0, v1, t0); // dsrav t0, v1, t0
c->daddiu(a3, a3, -350); // daddiu a3, a3, -350
c->andi(t0, t0, 31); // andi t0, t0, 31
// nop // sll r0, r0, 0
c->daddu(a3, a3, t0); // daddu a3, a3, t0
// nop // sll r0, r0, 0
block_3:
c->andi(a3, a3, 4095); // andi a3, a3, 4095
c->lhu(t1, 12, a1); // lhu t1, 12(a1)
c->dsll32(a3, a3, 0); // dsll32 a3, a3, 0
c->lbu(v1, 27, a1); // lbu v1, 27(a1)
c->or_(a2, a2, a3); // or a2, a2, a3
c->dsll(v1, v1, 14); // dsll v1, v1, 14
c->sd(a2, 16, a0); // sd a2, 16(a0)
c->or_(a2, t1, v1); // or a2, t1, v1
c->lhu(v1, 14, a1); // lhu v1, 14(a1)
// nop // sll r0, r0, 0
c->lbu(a3, 28, a1); // lbu a3, 28(a1)
c->dsll(v1, v1, 20); // dsll v1, v1, 20
c->or_(a2, a2, v1); // or a2, a2, v1
c->dsll32(a3, a3, 2); // dsll32 a3, a3, 2
c->or_(a2, a2, a3); // or a2, a2, a3
c->lhu(v1, 16, a1); // lhu v1, 16(a1)
c->lbu(a3, 29, a1); // lbu a3, 29(a1)
c->dsll32(v1, v1, 8); // dsll32 v1, v1, 8
c->or_(a2, a2, v1); // or a2, a2, v1
c->dsll32(a3, a3, 22); // dsll32 a3, a3, 22
c->or_(a2, a2, a3); // or a2, a2, a3
c->lbu(t0, 4, a1); // lbu t0, 4(a1)
c->daddiu(t0, t0, -5); // daddiu t0, t0, -5
c->sd(a2, 32, a0); // sd a2, 32(a0)
bc = ((s64)c->sgpr64(t0)) < 0; // bltz t0, L24
c->lbu(a3, 30, a1); // lbu a3, 30(a1)
if (bc) {goto block_5;} // branch non-likely
c->lhu(a2, 18, a1); // lhu a2, 18(a1)
c->dsll(a3, a3, 14); // dsll a3, a3, 14
c->or_(a2, a2, a3); // or a2, a2, a3
c->lhu(v1, 20, a1); // lhu v1, 20(a1)
c->dsll(v1, v1, 20); // dsll v1, v1, 20
c->lbu(a3, 31, a1); // lbu a3, 31(a1)
c->or_(a2, a2, v1); // or a2, a2, v1
c->dsll32(a3, a3, 2); // dsll32 a3, a3, 2
c->or_(a2, a2, a3); // or a2, a2, a3
c->lhu(v1, 22, a1); // lhu v1, 22(a1)
c->dsll32(v1, v1, 8); // dsll32 v1, v1, 8
c->lbu(a3, 32, a1); // lbu a3, 32(a1)
c->or_(a2, a2, v1); // or a2, a2, v1
c->dsll32(a3, a3, 22); // dsll32 a3, a3, 22
c->or_(a2, a2, a3); // or a2, a2, a3
c->addiu(v1, r0, 54); // addiu v1, r0, 54
c->sd(a2, 64, a0); // sd a2, 64(a0)
// nop // sll r0, r0, 0
c->sw(v1, 72, a0); // sw v1, 72(a0)
// nop // sll r0, r0, 0
block_5:
c->mov64(v0, a0); // or v0, a0, r0
//jr ra // jr ra
c->daddu(sp, sp, r0); // daddu sp, sp, r0
goto end_of_function; // return
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
gLinkedFunctionTable.reg("adgif-shader<-texture-with-update!", execute, 128);
}
} // namespace adgif_shader<_texture_with_update
} // namespace Mips2C

View file

@ -6,6 +6,7 @@
#include "common/common_types.h"
#include "game/mips2c/mips2c_table.h"
#include "common/util/assert.h"
#include "common/util/BitUtils.h"
#include "third-party/fmt/core.h"
// This file contains utility functions for code generated by the mips2c pass.
@ -162,6 +163,12 @@ struct ExecutionContext {
float Q;
void copy_vfs_from_other(const ExecutionContext* other) {
for (int i = 0; i < 32; i++) {
vfs[i] = other->vfs[i];
}
}
u128 vf_src(int idx) {
if (idx == 0) {
u128 result;
@ -495,6 +502,9 @@ struct ExecutionContext {
}
void dsra(int dst, int src, int sa) { gprs[dst].ds64[0] = gpr_src(src).ds64[0] >> sa; }
void dsrav(int dst, int src, int sa) {
gprs[dst].ds64[0] = gpr_src(src).ds64[0] >> gpr_src(sa).du32[0];
}
void dsra32(int dst, int src, int sa) { gprs[dst].ds64[0] = gpr_src(src).ds64[0] >> (32 + sa); }
void sra(int dst, int src, int sa) { gprs[dst].ds64[0] = gpr_src(src).ds32[0] >> sa; }
void dsll(int dst, int src0, int sa) { gprs[dst].du64[0] = gpr_src(src0).du64[0] << sa; }
@ -518,7 +528,11 @@ struct ExecutionContext {
}
void dsubu(int dst, int src0, int src1) { gprs[dst].du64[0] = sgpr64(src0) - sgpr64(src1); }
void subu(int dst, int src0, int src1) {
gprs[dst].ds64[0] = gpr_src(src0).ds32[0] - gpr_src(src1).ds32[0];
}
void xor_(int dst, int src0, int src1) { gprs[dst].du64[0] = sgpr64(src0) ^ sgpr64(src1); }
void or_(int dst, int src0, int src1) { gprs[dst].du64[0] = sgpr64(src0) | sgpr64(src1); }
void movz(int dst, int src0, int src1) {
if (sgpr64(src1) == 0) {
@ -578,6 +592,21 @@ struct ExecutionContext {
gprs[dst].du16[7] = s0.du16[3];
}
u32 lzocw(s32 in) {
if (in < 0) {
in = ~in;
}
if (in == 0) {
return 32;
}
return count_leading_zeros_u32(in);
}
void plzcw(int dst, int src) {
gprs[dst].du32[0] = lzocw(gpr_src(src).ds32[0]) - 1;
gprs[dst].du32[1] = lzocw(gpr_src(src).ds32[1]) - 1;
}
void por(int dst, int src0, int src1) {
auto s0 = gpr_src(src0);
auto s1 = gpr_src(src1);
@ -646,6 +675,16 @@ struct ExecutionContext {
void muls(int dst, int src0, int src1) { fprs[dst] = fprs[src0] * fprs[src1]; }
void adds(int dst, int src0, int src1) { fprs[dst] = fprs[src0] + fprs[src1]; }
void subs(int dst, int src0, int src1) { fprs[dst] = fprs[src0] - fprs[src1]; }
void divs(int dst, int src0, int src1) {
assert(fprs[src1] != 0);
fprs[dst] = fprs[src0] / fprs[src1];
}
void negs(int dst, int src) {
u32 v;
memcpy(&v, &fprs[src], 4);
v ^= 0x80000000;
memcpy(&fprs[dst], &v, 4);
}
void cvtws(int dst, int src) {
// float to int
@ -659,6 +698,13 @@ struct ExecutionContext {
memcpy(&value, &fprs[src], 4);
fprs[dst] = value;
}
void vwaitq() {}
std::string print_vf_float(int vf) {
auto src = vf_src(vf);
return fmt::format("{} {} {} {}", src.f[0], src.f[1], src.f[2], src.f[3]);
}
};
} // namespace Mips2C

View file

@ -36,20 +36,60 @@ namespace sp_process_block_2d {
extern void link();
}
namespace draw_large_polygon {
extern void link();
}
namespace init_sky_regs {
extern void link();
}
namespace clip_polygon_against_positive_hyperplane {
extern void link();
}
namespace render_sky_quad {
extern void link();
}
namespace render_sky_tri {
extern void link();
}
namespace set_tex_offset {
extern void link();
}
namespace set_sky_vf27 {
extern void link();
}
namespace set_sky_vf23_value {
extern void link();
}
namespace adgif_shader_texture_with_update {
extern void link();
}
LinkedFunctionTable gLinkedFunctionTable;
Rng gRng;
std::unordered_map<std::string, std::vector<void (*)()>> gMips2CLinkCallbacks = {
{"font", {draw_string::link}},
{"sparticle-launcher",
{sp_init_fields::link, particle_adgif::link, sp_launch_particles_var::link}},
{"sparticle", {sp_process_block_3d::link, sp_process_block_2d::link}}};
{"sparticle", {sp_process_block_3d::link, sp_process_block_2d::link}},
{"texture", {adgif_shader_texture_with_update::link}},
{"sky-tng",
{draw_large_polygon::link, init_sky_regs::link, clip_polygon_against_positive_hyperplane::link,
render_sky_quad::link, render_sky_tri::link, set_tex_offset::link, set_sky_vf27::link,
set_sky_vf23_value::link}}};
void LinkedFunctionTable::reg(const std::string& name, u64 (*exec)(void*), u32 stack_size) {
const auto& it = m_executes.insert({name, {exec, Ptr<u8>()}});
if (!it.second) {
lg::error("MIPS2C Function {} is registered multiple times, ignoring later registrations.",
name);
return;
}
// this is short stub that will jump to the appropriate function.

View file

@ -7,7 +7,7 @@
;; Forward declarations for stuff we haven't written yet:
(define-extern external-cam-reset! (function none))
(define-extern time-of-day-setup (function symbol none))
(define-extern time-of-day-setup (function symbol symbol))
(define-extern *compact-actors* symbol)
(define-extern find-instance-by-name (function string instance))
(define-extern *edit-instance* string)

View file

@ -52,6 +52,10 @@
(deftype dma-gif-packet (structure)
((dma-vif dma-packet :inline :offset-assert 0)
(gif uint64 2 :offset-assert 16) ;; guess
;; these two were added to make it easier.
(gif0 uint64 :offset 16)
(gif1 uint64 :offset 24)
(quad uint128 2 :offset 0)
)
:method-count-assert 9

View file

@ -234,8 +234,10 @@
(generic-foreground 30) ;; ?
(alpha-tex0 31)
(sky-tex0 32)
(alpha-tex1 38)
(sky-tex1 39)
(bucket-45 45)
(bucket-46 46)

View file

@ -127,9 +127,21 @@
)
)
;; texture common
;; sky
;; todo - disabled sky
(when (logtest? *vu1-enable-user* 8)
(cond
((and (-> *time-of-day-context* sky) *sky-drawn*)
(render-sky-tng *time-of-day-context*)
)
(else
;; todo
)
)
)
;; tod update
(update-time-of-day *time-of-day-context*)
;; closest
;; ocean
;; merc

View file

@ -789,7 +789,7 @@
;; some nice blue. probably the same as the fog color for geyser/sandover/etc.
;; "default" fog color when resetting registers
(define *fog-color* #xc88029)
(define *fog-color* (the-as rgba (new 'static 'rgba :r #x29 :g #x80 :b #xc8)))
;; set up a DMA buffer. This will hold a message to set the GS state to normal.
;; these regs are NOT the ones mapped in the EE memory, but other internal GS registers.

View file

@ -126,9 +126,9 @@
)
(deftype sky-tng-data (basic)
((giftag-base qword :inline :offset-assert 16)
(giftag-roof qword :inline :offset-assert 32)
(giftag-ocean qword :inline :offset-assert 48)
((giftag-base gs-gif-tag :inline :offset-assert 16);; changed
(giftag-roof gs-gif-tag :inline :offset-assert 32)
(giftag-ocean gs-gif-tag :inline :offset-assert 48)
(fog vector :inline :offset-assert 64)
(sky uint32 8 :offset-assert 80)
(time float :offset-assert 112)
@ -146,8 +146,8 @@
((adgif-tmpl dma-gif-packet :inline :offset-assert 0)
(draw-tmpl dma-gif-packet :inline :offset-assert 32)
(blend-tmpl dma-gif-packet :inline :offset-assert 64)
(sky-data uint128 5 :offset-assert 96)
(cloud-data uint128 5 :offset-assert 176)
(sky-data qword 5 :inline :offset-assert 96)
(cloud-data qword 5 :inline :offset-assert 176)
)
:method-count-assert 9
:size-assert #x100
@ -166,3 +166,9 @@
(define *sky-drawn* #f)
(define *cloud-drawn* #f)
(declare-type time-of-day-context basic)
(define-extern update-sky-tng-data (function float none))
(define-extern make-sky-textures (function time-of-day-context int none))
(define-extern sky-base-polygons (inline-array sky-vertex))

File diff suppressed because it is too large Load diff

View file

@ -5,3 +5,138 @@
;; name in dgo: sky
;; dgos: GAME, ENGINE
(defun sky-make-sun-data ((arg0 sky-parms) (arg1 int) (arg2 float))
"Make sun data for the arg1th sun at arg2 time"
(let* ((s4-0 (-> arg0 orbit arg1))
(s3-0 (-> arg0 upload-data sun arg1))
(f0-1 (- arg2 (-> s4-0 high-noon)))
(f30-0 (* 2730.6667 f0-1))
(f28-0 (* (sin f30-0) (-> s4-0 dist)))
(f30-1 (cos f30-0))
)
(let* ((f24-0 (* f30-1 (-> s4-0 dist)))
(f26-0 (* f24-0 (cos-rad (-> s4-0 tilt))))
(f24-1 (* f24-0 (sin-rad (-> s4-0 tilt))))
(f22-0 (sin-rad (-> s4-0 rise)))
(f0-10 (cos-rad (-> s4-0 rise)))
)
(set! (-> s3-0 pos z) (- (+ (* f28-0 f0-10) (* f24-1 f22-0))))
(set! (-> s3-0 pos y) f26-0)
(set! (-> s3-0 pos x) (- (* f24-1 f0-10) (* f28-0 f22-0)))
)
(let ((f0-14 (if (< f30-1 0.0)
0.0
f30-1
)
)
)
(set!
(-> arg0 upload-data sun arg1 r-aurora)
(+ (* (-> s4-0 min-halo) (- 1.0 f0-14)) (* (-> s4-0 max-halo) f0-14))
)
)
)
(none)
)
(defun sky-make-moon-data ((arg0 sky-parms) (arg1 float))
"Make moon data for moon at arg1 time"
(let* ((s5-0 (-> arg0 orbit 2))
(gp-0 (-> arg0 upload-data moon))
(f0-1 (- arg1 (-> s5-0 high-noon)))
(f28-0 (* 2730.6667 f0-1))
(f30-0 (* (sin f28-0) (-> s5-0 dist)))
(f26-0 (* (cos f28-0) (-> s5-0 dist)))
(f28-1 (* f26-0 (cos-rad (-> s5-0 tilt))))
(f26-1 (* f26-0 (sin-rad (-> s5-0 tilt))))
(f24-0 (sin-rad (-> s5-0 rise)))
(f0-10 (cos-rad (-> s5-0 rise)))
)
(set! (-> gp-0 pos z) (- (+ (* f30-0 f0-10) (* f26-1 f24-0))))
(set! (-> gp-0 pos y) f28-1)
(set! (-> gp-0 pos x) (- (* f26-1 f0-10) (* f30-0 f24-0)))
)
(none)
)
;;;;;;;;;;;;;;;;;;;;;
;; Old Sky Renderer
;;;;;;;;;;;;;;;;;;;;;
(defun sky-make-light ((arg0 sky-parms) (arg1 light) (arg2 int) (arg3 rgba))
(let* ((v1-2 (-> arg0 orbit arg2))
(a0-1 (if (= arg2 2)
(-> arg0 upload-data moon)
(-> arg0 upload-data sun arg2)
)
)
(f0-0 0.003921569)
(f1-1 (/ 1.0 (-> v1-2 dist)))
(v1-3 arg1)
)
(set! (-> v1-3 direction x) (* (-> (the-as sky-sun-data a0-1) pos x) f1-1))
(set! (-> v1-3 direction y) (* (-> (the-as sky-sun-data a0-1) pos y) f1-1))
(set! (-> v1-3 direction z) (* (-> (the-as sky-sun-data a0-1) pos z) f1-1))
(set! (-> v1-3 color x) (* (the float (-> arg3 r)) f0-0))
(set! (-> v1-3 color y) (* (the float (-> arg3 g)) f0-0))
(set! (-> v1-3 color z) (* (the float (-> arg3 b)) f0-0))
(set! (-> v1-3 color w) 1.0)
(set! (-> v1-3 levels x) 1.0)
)
(none)
)
(deftype sky-frame-data (structure)
((data uint128 18 :offset-assert 0)
(world-homo-matrix matrix :inline :offset 0)
(hmge-scale vector :inline :offset 64)
(hvdf-offset vector :inline :offset 80)
(consts vector :inline :offset 96)
(pfog0 float :offset 96)
(radius float :offset 100)
(nokick float :offset 108)
(strip-giftag qword :inline :offset 112)
(col-adgif qword :inline :offset 128)
(save uint128 5 :offset 144)
(sun-fan-giftag qword :inline :offset 224)
(sun-strip-giftag qword :inline :offset 240)
(sun-alpha qword :inline :offset 256)
(sun-alpha-giftag qword :inline :offset 272)
)
:method-count-assert 9
:size-assert #x120
:flag-assert #x900000120
)
;; skipping old sky stuff (for now)
(define sky-vu1-block (new 'static 'vu-function))
;; TODO sky-init-upload-data
;; sky-add-frame-data
;; sky-upload
;; sky-draw
;; set the suns
(sky-set-sun-radii *sky-parms* 0 60.0 200.0 300.0)
(sky-set-sun-radii *sky-parms* 1 15.0 20.0 300.0)
(sky-set-sun-colors *sky-parms* 1
(new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x80)
(new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x80)
(new 'static 'rgba :r #xc2 :g #xfe :b #x78 :a #x20)
(new 'static 'rgba :r #xc2 :g #xfe :b #x78)
)
(sky-set-orbit *sky-parms* 0 12.5 -15.0 0.0 9950.0 300.0 300.0)
(sky-set-orbit *sky-parms* 1 4.0 0.0 60.0 9950.0 120.0 120.0)
(sky-set-orbit *sky-parms* 2 0.0 0.0 -10.0 9950.0 0.0 0.0)

View file

@ -645,17 +645,22 @@
)
)
; (dotimes (i num-sprites)
; (let ((spidx (+ i start-sprite-idx)))
; (when (or (= spidx (-> sprites num-sprites 0)) (= spidx (+ 1 (-> sprites num-sprites 0))))
; (let ((data (the sprite-vec-data-2d (&+ (-> sprites vec-data) (* 48 (+ i start-sprite-idx))))))
; (format #t "spidx: ~d~%")
; (inspect data)
; (inspect (-> data r-g-b-a))
; )
; )
; )
; )
#|
;(when (= mscal-addr 3)
(dotimes (i num-sprites)
(let ((spidx (+ i start-sprite-idx)))
;(when (or (= spidx (-> sprites num-sprites 0)) (= spidx (+ 1 (-> sprites num-sprites 0))))
(let ((data (the sprite-vec-data-2d (&+ (-> sprites vec-data) (* 48 (+ i start-sprite-idx))))))
(let ((vec (-> data x-y-z-sx)))
(format 0 "sp: ~d ~f ~f ~f~%" (+ i start-sprite-idx) (-> vec x) (-> vec y) (-> vec z))
)
)
; )
)
)
; )
|#
;; third packet is adgif data (5 qw/sprite)
(let ((qwc-pkt3 (* 5 num-sprites)))

View file

@ -2435,6 +2435,7 @@
)
;; TODO adgif-shader<-texture-with-update!
(def-mips2c adgif-shader<-texture-with-update! (function adgif-shader texture adgif-shader))
(defun adgif-shader-login ((shader adgif-shader))
"If not logged in already, link us and update from texture."

View file

@ -24,7 +24,7 @@
:flag-assert #xb00000110
(:methods
(reset! (_type_) symbol 9)
(TODO-RENAME-10 (_type_ int float float vector) object 10) ; returns float or error string
(set-fade! (_type_ int float float vector) object 10) ; returns float or error string
)
)
@ -74,7 +74,7 @@
((active-count uint32 :offset-assert 4)
(interp float :offset-assert 8)
(current-interp float :offset-assert 12)
(moods uint64 2 :offset-assert 16)
(moods mood-context 2 :offset-assert 16)
(current-fog mood-fog :inline :offset-assert 32)
(current-sun mood-sun :inline :offset-assert 80)
(current-prt-color vector :inline :offset-assert 112)
@ -84,7 +84,7 @@
(title-light-group light-group :inline :offset-assert 1888)
(time float :offset-assert 2080)
(target-interp float :offset-assert 2084)
(erase-color uint32 :offset-assert 2088)
(erase-color rgba :offset-assert 2088)
(num-stars float :offset-assert 2092)
(light-masks-0 uint8 2 :offset-assert 2096)
(light-masks-1 uint8 2 :offset-assert 2098)

View file

@ -5,4 +5,671 @@
;; name in dgo: time-of-day
;; dgos: GAME, ENGINE
(define *time-of-day-proc* (the (pointer time-of-day-proc) #f))
(defmethod asize-of time-of-day-palette ((obj time-of-day-palette))
"Compute the size in memory of a time-of-day-palette"
(the-as int (+ (-> obj type size) (* (* (-> obj height) (-> obj width)) 4)))
)
;; The time-of-day-effect function is a callback used before doing a time-of-day-update.
;; I think it's unused?
(define-extern time-of-day-effect (function none))
;; if undefined, set to nothing so we can still call it.
(if (zero? time-of-day-effect)
(set! time-of-day-effect nothing)
)
(defbehavior time-of-day-update time-of-day-proc ()
"Update the particles and sky tng renderer for time-of-day effects"
(time-of-day-effect)
;; spawn or kill stars, if needed.
(cond
;; should have stars in the sky
((and (or (>= (-> self hour) 19) (>= 5 (-> self hour))) ;; night time
(and (< 45.0 (-> *time-of-day-context* num-stars)) (-> *time-of-day-context* sky)) ;; sky + stars desired
)
;; see if we need more
(when (and *dproc* (< (-> self star-count) (the int (-> *time-of-day-context* num-stars))))
(spawn (-> self stars) (math-camera-pos))
(+! (-> self star-count) 1)
)
)
;; have stars, but don't want them
((> (-> self star-count) 0)
;; kill all stars.
(forall-particles-with-key
(-> self stars)
(lambda ((arg0 sparticle-system) (arg1 sparticle-cpuinfo))
(if (< (the-as uint #x493e0) (-> arg1 next-time))
(set! (-> arg1 next-time) (the-as uint 5))
(sparticle-kill-it arg0 arg1)
)
(none)
)
#t
#t
)
(set! (-> self star-count) 0)
0
)
)
;; spawn or kill sun, if needed
(cond
((and (>= (-> self time-of-day) 6.25)
(< (-> self time-of-day) 18.75)
(!= (-> *time-of-day-context* sun-fade) 0.0)
)
(when (and *dproc* (zero? (-> self sun-count)))
(spawn (-> self sun) (math-camera-pos))
(+! (-> self sun-count) 1)
)
)
((> (-> self sun-count) 0)
(kill-and-free-particles (-> self sun))
(set! (-> self sun-count) 0)
0
)
)
;; spawn or kill green sun, if needed
(cond
((and (or (>= (-> self time-of-day) 21.75) (>= 10.25 (-> self time-of-day)))
(!= (-> *time-of-day-context* sun-fade) 0.0)
)
(when (and *dproc* (zero? (-> self green-sun-count)))
(spawn (-> self green-sun) (math-camera-pos))
(+! (-> self green-sun-count) 1)
)
)
((> (-> self green-sun-count) 0)
(kill-and-free-particles (-> self green-sun))
(set! (-> self green-sun-count) 0)
0
)
)
;; update the sky renderer.
(update-sky-tng-data (-> self time-of-day))
0
(none)
)
;; State for just ticking time forward.
(defstate time-of-day-tick (time-of-day-proc)
:code
(behavior ()
(while #t
;; tick!
(+! (-> self frame) (the int (* (-> self time-ratio) (-> *display* time-adjust-ratio))))
;; now update time...
(when (>= (-> self frame) 300)
;; 300 ticks/second
(while (>= (-> self frame) 300)
(+! (-> self frame) -300)
(+! (-> self second) 1)
)
;; 60 sec/minute
(when (>= (-> self second) 60)
(while (>= (-> self second) 60)
(+! (-> self second) -60)
(+! (-> self minute) 1)
)
;; 60 min/hour
(when (>= (-> self minute) 60)
(while (>= (-> self minute) 60)
(+! (-> self minute) -60)
(+! (-> self hour) 1)
)
;; 24 hour/day
(when (>= (-> self hour) 24)
(while (>= (-> self hour) 24)
(+! (-> self hour) -24)
(+! (-> self day) 1)
)
;; 7 day/week
(when (>= (-> self day) 7)
(while (>= (-> self day) 7)
(+! (-> self day) -7)
(+! (-> self week) 1)
)
;; 4 week/month
(when (>= (-> self week) 4)
(while (>= (-> self week) 4)
(+! (-> self week) -4)
(+! (-> self month) 1)
)
;; 12 month/year
(when (>= (-> self month) 12)
(while (>= (-> self month) 12)
(+! (-> self month) -12)
(+! (-> self year) 1)
)
)
)
)
)
)
)
)
;; set the time of day float. This is in hours (0-24)
(format *stdcon* "~0kstars: ~d time ~d:~2d~%" (-> self star-count) (-> self hour) (-> self minute))
(let* ((f0-4 (the float (-> self frame)))
(f0-6 (+ (* 0.0033333334 f0-4) (the float (-> self second))))
(f0-8 (+ (* 0.016666668 f0-6) (the float (-> self minute))))
(f0-10 (+ (* 0.016666668 f0-8) (the float (-> self hour))))
)
(set! (-> self time-of-day) f0-10)
(set! (-> *time-of-day-context* time) f0-10)
)
(suspend)
)
(none)
)
:post time-of-day-update
)
(defbehavior init-time-of-day time-of-day-proc ()
"Initialize the time-of-day process"
(stack-size-set! (-> self main-thread) 128)
(set! (-> self year) 0)
(set! (-> self month) 0)
(set! (-> self week) 0)
(set! (-> self day) 0)
(set! (-> self hour) 0)
(set! (-> self minute) 0)
(set! (-> self second) 0)
(set! (-> self frame) 0)
(set! (-> self time-of-day) 0.0)
(if *time-of-day-fast*
(set! (-> self time-ratio) 18000.0)
(set! (-> self time-ratio) 300.0)
)
(set! (-> self star-count) 0)
(set! (-> self stars) (create-launch-control (-> *part-group-id-table* 34) self))
(set! (-> self sun) (create-launch-control (-> *part-group-id-table* 35) self))
(set! (-> self green-sun) (create-launch-control (-> *part-group-id-table* 36) self))
(go time-of-day-tick)
(none)
)
(defun start-time-of-day ()
"Start up the time of day process. Kill any existing ones"
(kill-by-name 'time-of-day-proc *active-pool*)
(let ((gp-0 (get-process *default-dead-pool* time-of-day-proc #x4000)))
(set! *time-of-day-proc*
(the-as (pointer time-of-day-proc)
(when gp-0
(let ((t9-2 (method-of-type time-of-day-proc activate)))
(t9-2 (the-as time-of-day-proc gp-0) *default-pool* 'time-of-day-proc (the-as pointer #x70004000))
)
(run-now-in-process gp-0 init-time-of-day)
(-> gp-0 ppointer )
)
)
)
)
(none)
)
(defun time-of-day-setup ((arg0 symbol))
"This function is weird. Returns if time of day will tick forward or not.
If you set arg0 it will toggle on/off time of day.
Otherwise, calling the function has no side effects."
(when arg0
(cond
((= (-> *time-of-day-proc* 0 time-ratio) 0.0)
(if *time-of-day-fast*
(set! (-> *time-of-day-proc* 0 time-ratio) 18000.0)
(set! (-> *time-of-day-proc* 0 time-ratio) 300.0)
)
(set! *time-of-day-mode* 8)
)
(else
(set! (-> *time-of-day-proc* 0 time-ratio) 0.0)
(set! *time-of-day-mode* 4)
(set! (-> *time-of-day-proc* 0 hour) 12)
(set! (-> *time-of-day-proc* 0 minute) 0)
0
)
)
)
(if (= (-> *time-of-day-proc* 0 time-ratio) 0.0)
#f
#t
)
)
(defun set-time-of-day ((arg0 float))
"Manually set the time of day."
(let ((v1-0 *time-of-day-proc*))
(set! (-> v1-0 0 hour) (the int arg0))
(let ((a0-1 (* 60.0 (- arg0 (the float (the int arg0))))))
(set! (-> v1-0 0 minute) (the int a0-1))
(set! (-> v1-0 0 second) (the int (* 60.0 (- a0-1 (the float (the int a0-1))))))
)
)
0
(none)
)
;; TODO time-of-day-interp-colors
;; TODO time-of-day-interp-colors-scratch
(defun init-time-of-day-context ((arg0 time-of-day-context))
"Set up the title-light-group."
(set-vector! (-> arg0 title-light-group dir0 color) 0.82 0.82 0.82 1.0)
(set-vector! (-> arg0 title-light-group dir1 color) 2.0 2.0 2.0 1.0)
(set-vector! (-> arg0 title-light-group ambi color) 0.5 0.5 0.5 1.0)
(set! (-> arg0 title-light-group dir0 levels x) 1.0)
(set! (-> arg0 title-light-group dir1 levels x) 1.0)
(let ((f0-14 1.0))
(set! (-> arg0 title-light-group ambi levels x) f0-14)
f0-14
)
)
(defun update-time-of-day ((arg0 time-of-day-context))
"Update the time of day context"
;; set defaults
(set! (-> arg0 sky) #f)
(set! (-> arg0 target-interp) 0.0)
;; TODO re-enable
#|
(when *target*
(set! (-> *target* draw light-index) (the-as uint 0))
(when (-> *target* sidekick)
(set! (-> *target* sidekick 0 draw light-index) (the-as uint 0))
0
)
)
|#
;; see if either level gives us a sky.
(dotimes (v1-12 (-> *level* length))
(let ((a0-4 (-> *level* level v1-12)))
(when (= (-> a0-4 status) 'active)
(if (-> a0-4 info sky)
(set! (-> arg0 sky) #t)
)
)
)
)
;; level distances
(let ((s4-0 (new 'stack-no-clear 'array 'float 2))) ;; was a boxed array, but the GOAL implementation seems buggy.
(set! (-> s4-0 0) 0.0)
(set! (-> s4-0 1) 0.0)
0.0
(let ((s5-0 0)
(f30-0 (-> arg0 current-interp))
)
(set! *lightning-frame-done* #f)
(set! *lightning-realtime-done* #f)
;; loop over levels and figure out which to use.
(dotimes (s3-0 2)
(let ((s2-0 (-> *level* level s3-0)))
(cond
((!= (-> s2-0 status) 'inactive)
;; level is good, use its mood
(set! (-> s4-0 s3-0) (-> s2-0 level-distance))
(set! (-> arg0 moods s3-0) (-> s2-0 mood))
;; run its mood callback
((-> s2-0 mood-func) (-> s2-0 mood) (-> arg0 time) s3-0)
;; sky count
(if (and (= (-> s2-0 status) 'active) (-> s2-0 info sky))
(+! s5-0 1)
)
)
(else
;; level is no good. Use the default mood in its place.
(set! (-> s4-0 s3-0) 4095996000.0)
(set! (-> arg0 moods s3-0) *default-mood*)
(update-mood-default *default-mood* (-> arg0 time) 0)
)
)
)
)
;; now pick desired interpolation weights
(let* ((f0-6 (-> s4-0 0))
(f1-0 (-> s4-0 1))
(f28-0 (cond
((= f1-0 4095996000.0)
;; second level is no good, just use first
0.0
)
((= f0-6 4095996000.0)
;; first level is no good, just use second.
1.0
)
((= f0-6 f1-0)
;; not sure why this is special cased...
0.5
)
;; this is a hack to pick the mood of village2 when we're closer to sunken, as long as
;; the camera is above 0.
((and (< 0.0 (-> *math-camera* trans y))
(= (-> *level* level0 name) 'village2)
(= (-> *level* level1 name) 'sunken)
)
0.0 ;; picks 0 = village2
)
((and (< 0.0 (-> *math-camera* trans y))
(= (-> *level* level0 name) 'sunken)
(= (-> *level* level1 name) 'village2)
)
1.0 ;; picks 1 = village 2
)
(else
;; interplate between them.
(/ f0-6 (+ f0-6 f1-0))
)
)
)
)
;; normally we will slowly ramp the interpolation weights.
;; but if we've just teleported, immediately snap to the new value.
(if *teleport*
(set! f30-0 f28-0)
)
;; ramp interpolation weights.
(when (not (or (paused?) (= f28-0 f30-0)))
(let ((f0-7 (- f30-0 f28-0)))
(set! f30-0 (cond
((= (-> *setting-control* current video-mode) 'pal)
(cond
((< (fabs f0-7) 0.00396)
;; close enough
f28-0
)
((< f0-7 0.0)
;; ramp up
(+ 0.00396 f30-0)
)
(else
;; ramp down
(+ -0.00396 f30-0)
)
)
)
((< (fabs f0-7) 0.0033)
;; close enough
f28-0
)
((< f0-7 0.0)
;; ramp up
(+ 0.0033 f30-0)
)
(else
;; ramp down.
(+ -0.0033 f30-0)
)
)
)
)
)
;; number of active skys
(set! (-> arg0 active-count) (the-as uint s5-0))
;; interpolation value between the two level moods.
(set! (-> arg0 interp) f28-0)
)
;; Do the interpolation
(set! (-> arg0 current-interp) f30-0)
(set! *sky-drawn* #f)
(set! *cloud-drawn* #f)
(let ((s5-1 (-> arg0 current-fog)))
(cond
((= f30-0 0.0)
;; special case: only use level 0
(let ((v1-67 (-> arg0 moods 0 current-fog)))
(set! (-> s5-1 fog-color quad) (-> v1-67 fog-color quad))
(set! (-> s5-1 fog-dists quad) (-> v1-67 fog-dists quad))
(set! (-> s5-1 erase-color quad) (-> v1-67 erase-color quad))
)
(set! (-> arg0 current-prt-color quad) (-> arg0 moods 0 current-prt-color quad))
(set! (-> arg0 current-sun sun-color quad) (-> arg0 moods 0 current-sun sun-color quad))
(set! (-> arg0 current-sun env-color quad) (-> arg0 moods 0 current-sun env-color quad))
(set! (-> arg0 current-shadow quad) (-> arg0 moods 0 current-shadow quad))
(set! (-> arg0 current-shadow-color quad) (-> arg0 moods 0 current-shadow-color quad))
(dotimes (s4-1 8)
(quad-copy! (the-as pointer (-> arg0 light-group s4-1)) (the-as pointer (-> arg0 moods 0 light-group s4-1)) 12)
)
(set! (-> arg0 num-stars) (-> arg0 moods 0 num-stars))
(set! (-> arg0 sun-fade) (-> *level* level0 info sun-fade))
)
((= f30-0 1.0)
;; special case: use only level 1
(let ((v1-88 (-> arg0 moods 1 current-fog)))
(set! (-> s5-1 fog-color quad) (-> v1-88 fog-color quad))
(set! (-> s5-1 fog-dists quad) (-> v1-88 fog-dists quad))
(set! (-> s5-1 erase-color quad) (-> v1-88 erase-color quad))
)
(set! (-> arg0 current-prt-color quad) (-> arg0 moods 1 current-prt-color quad))
(set! (-> arg0 current-sun sun-color quad) (-> arg0 moods 1 current-sun sun-color quad))
(set! (-> arg0 current-sun env-color quad) (-> arg0 moods 1 current-sun env-color quad))
(set! (-> arg0 current-shadow quad) (-> arg0 moods 1 current-shadow quad))
(set! (-> arg0 current-shadow-color quad) (-> arg0 moods 1 current-shadow-color quad))
(dotimes (s4-2 8)
(quad-copy! (the-as pointer (-> arg0 light-group s4-2)) (the-as pointer (-> arg0 moods 1 light-group s4-2)) 12)
)
(set! (-> arg0 num-stars) (-> arg0 moods 1 num-stars))
(set! (-> arg0 sun-fade) (-> *level* level1 info sun-fade))
)
(else
;; interpolate!
;; note: the array access here seems to be different from everywhere else and I suspect there was some
;; weird pointer math in the original code.
(let ((s4-3 (-> arg0 moods 0 current-fog))
(s3-1 (-> arg0 moods 1 current-fog))
)
(vector4-lerp! (-> s5-1 fog-color) (-> s4-3 fog-color) (-> s3-1 fog-color) f30-0)
(vector4-lerp! (-> s5-1 fog-dists) (-> s4-3 fog-dists) (-> s3-1 fog-dists) f30-0)
(vector4-lerp! (-> s5-1 erase-color) (-> s4-3 erase-color) (-> s3-1 erase-color) f30-0)
)
(vector4-lerp! (-> arg0 current-prt-color) (-> arg0 moods 0 current-prt-color) (-> arg0 moods 1 current-prt-color) f30-0)
(vector4-lerp!
(the-as vector (-> arg0 current-sun))
(the-as vector (-> arg0 moods 0 current-sun))
(the-as vector (-> arg0 moods 1 current-sun))
f30-0
)
(vector4-lerp! (-> arg0 current-sun env-color) (-> arg0 moods 0 current-sun env-color) (-> arg0 moods 1 current-sun env-color) f30-0)
(vector4-lerp! (-> arg0 current-shadow) (-> arg0 moods 0 current-shadow) (-> arg0 moods 1 current-shadow) f30-0)
(vector4-lerp! (-> arg0 current-shadow-color) (-> arg0 moods 0 current-shadow-color) (-> arg0 moods 1 current-shadow-color) f30-0)
(dotimes (s4-4 8)
(dotimes (s3-2 3)
(let ((s2-1 (+ (+ (* 48 s3-2) 156 (* 192 s4-4)) (the-as int arg0))))
(let ((s1-0 (+ (+ (* 48 s3-2) 156 (* 192 s4-4)) (the-as int (-> arg0 moods 0))) )
(s0-0 (+ (+ (* 48 s3-2) 156 (* 192 s4-4)) (the-as int (-> arg0 moods 1))) )
)
(vector4-lerp! (the-as vector (+ s2-1 0)) (the-as vector (+ s1-0 0)) (the-as vector (+ s0-0 0)) f30-0)
(vector4-lerp! (the-as vector (+ s2-1 16)) (the-as vector (+ s1-0 16)) (the-as vector (+ s0-0 16)) f30-0)
(vector4-lerp! (the-as vector (+ s2-1 32)) (the-as vector (+ s1-0 32)) (the-as vector (+ s0-0 32)) f30-0)
)
(vector-normalize! (the-as vector (+ s2-1 0)) 1.0)
)
)
(let ((s3-3 (+ (the-as uint (-> arg0 light-group 0 ambi)) (* 192 s4-4)))
(s2-2 (+ (the-as uint (-> arg0 moods 0 light-group 0 ambi)) (* 192 s4-4)))
(s1-1 (+ (the-as uint (-> arg0 moods 1 light-group 0 ambi)) (* 192 s4-4)))
)
(vector4-lerp! (the-as vector (+ s3-3 0)) (the-as vector (+ s2-2 0)) (the-as vector (+ s1-1 0)) f30-0)
(vector4-lerp! (the-as vector (+ s3-3 16)) (the-as vector (+ s2-2 16)) (the-as vector (+ s1-1 16)) f30-0)
(vector4-lerp! (the-as vector (+ s3-3 32)) (the-as vector (+ s2-2 32)) (the-as vector (+ s1-1 32)) f30-0)
)
)
(set! (-> arg0 num-stars) (+ (-> arg0 moods 0 num-stars) (* (- (-> arg0 moods 1 num-stars) (-> arg0 moods 0 num-stars)) f30-0)))
(let ((f0-20 (-> *level* level0 info sun-fade)))
(set! (-> arg0 sun-fade) (+ f0-20 (* f30-0 (- (-> *level* level1 info sun-fade) f0-20))))
)
)
)
;; setup sky stuff
(dotimes (s4-5 2)
(make-sky-textures arg0 s4-5)
)
(set! (-> sky-base-polygons 0 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 1 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 2 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 3 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 4 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 5 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 6 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 7 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 8 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 9 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 10 col quad) (-> s5-1 erase-color quad))
(set! (-> sky-base-polygons 11 col quad) (-> s5-1 erase-color quad))
)
)
)
(set! (-> arg0 current-sun env-color x) (* 0.5019608 (-> arg0 current-sun env-color x)))
(set! (-> arg0 current-sun env-color y) (* 0.5019608 (-> arg0 current-sun env-color y)))
(set! (-> arg0 current-sun env-color z) (* 0.5019608 (-> arg0 current-sun env-color z)))
(set! (-> arg0 current-sun env-color w) (* 0.5019608 (-> arg0 current-sun env-color w)))
(let ((v1-179 (-> arg0 current-fog)))
(set! *fog-color*
(new 'static 'rgba
:r (the int (-> v1-179 fog-color x))
:g (the int (-> v1-179 fog-color y))
:b (the int (-> v1-179 fog-color z))
)
)
)
(let ((v1-184 (-> arg0 current-fog erase-color)))
(set! (-> arg0 erase-color)
(new 'static 'rgba
:a #x80
:b (the int (-> v1-184 z))
:g (the int (-> v1-184 y))
:r (the int (-> v1-184 x))
)
)
)
(set! (-> *math-camera* fog-start) (-> arg0 current-fog fog-dists x))
(set! (-> *math-camera* fog-end) (-> arg0 current-fog fog-dists y))
(set! (-> *math-camera* fog-max) (-> arg0 current-fog fog-dists z))
(set! (-> *math-camera* fog-min) (-> arg0 current-fog fog-dists w))
;; interp target lights.
(let* ((v1-195 0 #|(-> *target* draw light-index)|#) ;; TODO
(f30-1 (-> arg0 target-interp))
(s4-6 (-> arg0 light-group))
(s5-2 (-> arg0 light-group v1-195))
)
(when (nonzero? v1-195)
(cond
((= f30-1 1.0)
)
((= f30-1 0.0)
(quad-copy! (the-as pointer (-> arg0 light-group v1-195)) (the-as pointer (-> arg0 light-group)) 12)
)
(else
(dotimes (s3-4 4)
(vector4-lerp!
(the-as vector (+ (the-as uint (-> s5-2 dir0)) (* 48 s3-4)))
(the-as vector (+ (the-as uint (-> s4-6 0)) (* 48 s3-4)))
(the-as vector (+ (the-as uint (-> s5-2 dir0)) (* 48 s3-4)))
f30-1
)
(vector4-lerp!
(the-as vector (+ (the-as uint (-> s5-2 dir0 color)) (* 48 s3-4)))
(the-as vector (+ (the-as uint (-> s4-6 0 dir0 color)) (* 48 s3-4)))
(the-as vector (+ (the-as uint (-> s5-2 dir0 color)) (* 48 s3-4)))
f30-1
)
(vector4-lerp!
(the-as vector (+ (the-as uint (-> s5-2 dir0 levels)) (* 48 s3-4)))
(the-as vector (+ (the-as uint (-> s4-6 0 dir0 levels)) (* 48 s3-4)))
(the-as vector (+ (the-as uint (-> s5-2 dir0 levels)) (* 48 s3-4)))
f30-1
)
(vector-normalize!
(the-as vector (+ (the-as uint (-> s5-2 dir0)) (* 48 s3-4)))
1.0
)
)
)
)
;; some shadow thing.
(let ((a2-30 (new 'stack-no-clear 'vector)))
(set! (-> a2-30 x) (- (-> s5-2 dir0 direction x)))
(set! (-> a2-30 y) (- (-> s5-2 dir0 direction y)))
(set! (-> a2-30 z) (- (-> s5-2 dir0 direction z)))
(when (< (-> s5-2 dir0 direction y) 0.9063)
(let* ((f0-56 0.4226)
(f1-17 (-> a2-30 x))
(f1-19 (* f1-17 f1-17))
(f2-7 (-> a2-30 z))
(f0-57 (/ f0-56 (sqrtf (+ f1-19 (* f2-7 f2-7)))))
)
(set! (-> a2-30 x) (* (-> a2-30 x) f0-57))
(set! (-> a2-30 y) -0.9063)
(set! (-> a2-30 z) (* (-> a2-30 z) f0-57))
)
)
(vector4-lerp! (-> arg0 current-shadow) (-> arg0 current-shadow) a2-30 f30-1)
)
(vector-normalize! (-> arg0 current-shadow) 1.0)
)
)
(reset! *palette-fade-controls*)
0
(none)
)
(defmethod set-fade! palette-fade-controls ((obj palette-fade-controls) (arg0 int) (arg1 float) (arg2 float) (arg3 vector))
(cond
((and (>= arg0 0) (< arg0 8))
(let ((v1-3 (-> obj control arg0)))
(when (< arg2 (-> v1-3 actor-dist))
(if arg3
(set! (-> v1-3 trans quad) (-> arg3 quad))
)
(set! (-> v1-3 fade) (fmax 0.0 (fmin 1.993 arg1)))
(let ((f0-3 arg2))
(set! (-> v1-3 actor-dist) f0-3)
f0-3
)
)
)
)
(else
(format 0 "ERROR: Bogus palette-fade-control index!~%")
)
)
)
(defmethod reset! palette-fade-controls ((obj palette-fade-controls))
(countdown (v1-0 8)
(let ((a1-2 (-> obj control v1-0)))
(set! (-> a1-2 fade) 0.0)
(set! (-> a1-2 actor-dist) 4096000000.0)
)
)
#f
)
;; start the time of day process!!
(start-time-of-day)

View file

@ -130,7 +130,7 @@
(display? symbol :offset-assert 376)
(meta-inside? symbol :offset-assert 380)
(mood mood-context :offset-assert 384)
(mood-func function :offset-assert 388)
(mood-func (function mood-context float int none) :offset-assert 388)
(vis-bits pointer :offset-assert 392)
(all-visible? symbol :offset-assert 396)
(force-all-visible? symbol :offset-assert 400)

View file

@ -274,7 +274,7 @@
(set! (-> s5-1 load-name) level-name)
)
(set! (-> s5-1 mood) (the mood-context (-> s5-1 info mood value)))
(set! (-> s5-1 mood-func) (the function (-> s5-1 info mood-func value)))
(set! (-> s5-1 mood-func) (the (function mood-context float int none) (-> s5-1 info mood-func value)))
(set! (-> s5-1 display?) #f)
(set! (-> s5-1 force-all-visible?) #f)
(set! (-> s5-1 force-inside?) #f)
@ -493,8 +493,7 @@
(when (nonzero? (-> bsp adgifs))
(let ((adgifs (-> bsp adgifs)))
(dotimes (i (-> adgifs length))
;; TODO
;;(adgif-shader-login-no-remap (-> adgifs data i)) TODO texture.gc
(adgif-shader-login-no-remap (-> adgifs data i))
)
)
)

View file

@ -495,12 +495,12 @@
(defmacro set-vector! (v xv yv zv wv)
"Set all fields in a vector"
(with-gensyms (vec)
`(let ((vec ,v))
(set! (-> vec x) ,xv)
(set! (-> vec y) ,yv)
(set! (-> vec z) ,zv)
(set! (-> vec w) ,wv)
vec
`(let ((,vec ,v))
(set! (-> ,vec x) ,xv)
(set! (-> ,vec y) ,yv)
(set! (-> ,vec z) ,zv)
(set! (-> ,vec w) ,wv)
,vec
)
)
)

View file

@ -251,7 +251,6 @@
(s3-0 (new 'stack-no-clear 'vector))
)
(format #t "adjust launch~%")
;; use the field-init-spec to create a totally new launchinfo.
(sp-init-fields!
(-> s5-0 launchrot)
@ -288,6 +287,7 @@
(+! (-> arg0 launchrot z) (-> s3-0 z))
)
;; if desired, apply addition y rotation.
(when (!= (-> s5-0 rotate-y) 0.0)
(let ((s3-1 (new 'stack-no-clear 'matrix)))
@ -689,7 +689,6 @@
(defun sp-relaunch-particle-2d ((arg0 object) (arg1 sparticle-launcher) (arg2 sparticle-cpuinfo) (arg3 sprite-vec-data-3d))
"relaunch a 2d particle"
(sp-relaunch-setup-fields arg0 arg1 arg2 arg3)
(format #t "here we are... ~A~%" (logtest? (-> arg2 flags) (sp-cpuinfo-flag aux-list)))
(when (logtest? (-> arg2 flags) (sp-cpuinfo-flag aux-list))
(set! (-> arg2 func) add-to-sprite-aux-list)
(set! (-> arg3 r-g-b-a w) 0.0)

View file

@ -301,7 +301,6 @@
(when (= a3-0 t0-0)
;; wrap
(set! a3-0 0)
(format #t "wrapped!!~%")
)
)
)

View file

@ -1534,6 +1534,12 @@
;; definition for function target-joint-pos
(defun target-joint-pos ()
;; added hack
(when (and *target* (zero? (-> *target* draw)))
;; just return 0, we have the fake target
(return (new 'static 'vector))
)
(let ((v1-0 *target*))
(if v1-0
(vector<-cspace!

View file

@ -34,7 +34,11 @@
(matrix-transpose! (-> *math-camera* camera-rot) (-> *math-camera* inv-camera-rot))
;; fake some value here
(set! (-> *math-camera* fov-correction-factor) 1.0)
;;(set! (-> *math-camera* fov-correction-factor) 1000.0)
(set! (-> *math-camera* fov) (degrees 64.0))
(let ((f0-28 (fmin 11650.845 (-> *math-camera* fov))))
(set! (-> *math-camera* fov-correction-factor) (* 0.00008583069 f0-28))
)
;; do the math
(set! (-> *math-camera* trans quad) (-> location quad))
@ -185,10 +189,10 @@
(set! (-> trans rot x) (+ -54.13336 (-> trans rot x)))
)
(if (logtest? (-> *cpad-list* cpads pad-idx button0-abs 0) (pad-buttons left))
(set! (-> trans rot y) (+ 546.13336 (-> trans rot y)))
(set! (-> trans rot y) (+ 150.13336 (-> trans rot y)))
)
(if (logtest? (-> *cpad-list* cpads pad-idx button0-abs 0) (pad-buttons right))
(set! (-> trans rot y) (+ -546.13336 (-> trans rot y)))
(set! (-> trans rot y) (+ -150.13336 (-> trans rot y)))
)
(set! (-> trans scale x) 1.)

View file

@ -592,3 +592,12 @@
"Create a pointer to an object on the scratchpad."
`(the-as (pointer ,type) (&+ *fake-scratchpad-data* ,offset))
)
(defmacro def-mips2c (name type)
"Define a mips2c object."
`(begin
(define-extern ,name ,type)
(set! ,name (the-as ,type (__pc-get-mips2c ,(symbol->string name))))
)
)

View file

@ -211,7 +211,7 @@
(set! (-> s3-0 intensity) arg1)
)
)
(TODO-RENAME-10 *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans))
(set-fade! *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans))
)
)

View file

@ -243,7 +243,7 @@
)
)
)
(TODO-RENAME-10
(set-fade!
*palette-fade-controls*
3
(-> self deadly-fade)

View file

@ -275,6 +275,9 @@ StackVarAddrVal* FunctionEnv::allocate_aligned_stack_variable(const TypeSpec& ts
int size_bytes,
int align_bytes) {
require_aligned_stack();
if (align_bytes > 16) {
fmt::print("\n\n\nBad stack align: {} bytes for {}\n\n\n\n", align_bytes, ts.print());
}
assert(align_bytes <= 16);
int align_slots = (align_bytes + emitter::GPR_SIZE - 1) / emitter::GPR_SIZE;
while (m_stack_var_slots_used % align_slots) {

View file

@ -1103,7 +1103,7 @@ Val* Compiler::compile_stack_new(const goos::Object& form,
assert(stride == info.stride);
int size_in_bytes = info.stride * constant_count;
auto addr = fe->allocate_aligned_stack_variable(ts, size_in_bytes, stride);
auto addr = fe->allocate_aligned_stack_variable(ts, size_in_bytes, 16);
return addr;
} else {
auto ti = m_ts.lookup_type(type_of_object);

View file

@ -564,6 +564,9 @@ bool Debugger::get_symbol_value(const std::string& sym_name, u32* output) {
* Starts the debugger watch thread which watches the target process to see if it stops.
*/
void Debugger::start_watcher() {
if (m_watcher_running) {
stop_watcher();
}
assert(!m_watcher_running);
m_watcher_running = true;
m_watcher_should_stop = false;
@ -609,6 +612,7 @@ void Debugger::watcher() {
break;
case xdbg::SignalInfo::DISAPPEARED:
printf("Target has disappeared. Maybe it quit or was killed.\n");
handle_disappearance();
break;
default:
printf("[Debugger] unhandled signal in watcher: %d\n", int(signal_info.kind));
@ -629,6 +633,14 @@ void Debugger::watcher() {
}
}
void Debugger::handle_disappearance() {
m_watcher_should_stop = true;
xdbg::close_memory(m_debug_context.tid, &m_memory_handle);
xdbg::detach_and_resume(m_debug_context.tid);
m_context_valid = false;
m_attached = false;
}
Debugger::SignalInfo Debugger::pop_signal() {
{
std::unique_lock<std::mutex> lock(m_watcher_mutex);

View file

@ -165,6 +165,7 @@ class Debugger {
void stop_watcher();
void watcher();
void update_continue_info();
void handle_disappearance();
struct Breakpoint {
u32 goal_addr = 0; // address to break at

View file

@ -980,7 +980,7 @@
(define *thunder-id2* (new-sound-id))
;; definition for symbol *thunder-id*, type sound-id
(define *thunder-id* (the-as sound-id 0))
(define *thunder-id* (new 'static 'sound-id))
;; definition for symbol *thunder-count*, type int
(define *thunder-count* 0)
@ -4014,7 +4014,3 @@
(update-mood-itimes arg0)
(none)
)

View file

@ -48,6 +48,8 @@
(deftype dma-gif-packet (structure)
((dma-vif dma-packet :inline :offset-assert 0)
(gif uint64 2 :offset-assert 16)
(gif0 uint64 :offset 16)
(gif1 uint64 :offset 24)
(quad uint128 2 :offset 0)
)
:method-count-assert 9

View file

@ -790,8 +790,8 @@
(the-as gif-tag (format #t "~Tregs15: ~4d~%" (-> obj regs15)))
)
;; definition for symbol *fog-color*, type int
(define *fog-color* #xc88029)
;; definition for symbol *fog-color*, type rgba
(define *fog-color* (new 'static 'rgba :r #x29 :g #x80 :b #xc8))
;; definition for symbol *default-regs-buffer*, type dma-buffer
(define *default-regs-buffer* (new 'global 'dma-buffer 1024))

View file

@ -226,16 +226,16 @@
;; definition of type sky-tng-data
(deftype sky-tng-data (basic)
((giftag-base qword :inline :offset-assert 16)
(giftag-roof qword :inline :offset-assert 32)
(giftag-ocean qword :inline :offset-assert 48)
(fog vector :inline :offset-assert 64)
(sky uint32 8 :offset-assert 80)
(time float :offset-assert 112)
(off-s-0 uint16 :offset-assert 116)
(off-t-0 uint16 :offset-assert 118)
(off-s-1 uint16 :offset-assert 120)
(off-t-1 uint16 :offset-assert 122)
((giftag-base gs-gif-tag :inline :offset-assert 16)
(giftag-roof gs-gif-tag :inline :offset-assert 32)
(giftag-ocean gs-gif-tag :inline :offset-assert 48)
(fog vector :inline :offset-assert 64)
(sky uint32 8 :offset-assert 80)
(time float :offset-assert 112)
(off-s-0 uint16 :offset-assert 116)
(off-t-0 uint16 :offset-assert 118)
(off-s-1 uint16 :offset-assert 120)
(off-t-1 uint16 :offset-assert 122)
)
:method-count-assert 9
:size-assert #x7c
@ -260,11 +260,11 @@
;; definition of type sky-work
(deftype sky-work (structure)
((adgif-tmpl dma-gif-packet :inline :offset-assert 0)
(draw-tmpl dma-gif-packet :inline :offset-assert 32)
(blend-tmpl dma-gif-packet :inline :offset-assert 64)
(sky-data uint128 5 :offset-assert 96)
(cloud-data uint128 5 :offset-assert 176)
((adgif-tmpl dma-gif-packet :inline :offset-assert 0)
(draw-tmpl dma-gif-packet :inline :offset-assert 32)
(blend-tmpl dma-gif-packet :inline :offset-assert 64)
(sky-data qword 5 :inline :offset-assert 96)
(cloud-data qword 5 :inline :offset-assert 176)
)
:method-count-assert 9
:size-assert #x100

View file

@ -3154,143 +3154,7 @@
)
;; definition for function adgif-shader<-texture-with-update!
;; WARN: Unsupported inline assembly instruction kind - [plzcw v1, v1]
;; WARN: Unsupported inline assembly instruction kind - [subu v1, t0, v1]
;; WARN: Unsupported inline assembly instruction kind - [plzcw a3, a3]
;; WARN: Unsupported inline assembly instruction kind - [subu a3, t0, a3]
;; WARN: Unsupported inline assembly instruction kind - [plzcw a3, v1]
;; WARN: Unsupported inline assembly instruction kind - [subu a3, t0, a3]
(defun adgif-shader<-texture-with-update! ((arg0 adgif-shader) (arg1 texture))
(local-vars
(v1-11 uint128)
(v1-12 int)
(a3-4 uint128)
(a3-5 int)
(a3-9 uint128)
(a3-10 int)
(a3-13 int)
(a3-22 uint)
)
(let* ((a2-0 (-> arg0 tex1))
(v1-0 256)
(a2-1 (incomplete-bitfield-access a2-0))
(f0-1 (the float v1-0))
(v1-1 (-> arg1 num-mips))
(f1-0 (-> arg1 uv-dist))
(v1-2 (+ v1-1 -1))
(f0-2 (/ f0-1 f1-0))
(a2-2 (logior a2-1 (* v1-2 4)))
(v1-5 (shl (-> arg1 mip-shift) 19))
(a3-0 (-> arg1 tex1-control))
(a2-4 (logior (logior a2-2 v1-5) (* a3-0 32)))
)
(let* ((t1-1 (incomplete-bitfield-access (-> arg0 tex0)))
(v1-6 (-> arg1 psm))
(t1-2 (sar t1-1 62))
(v1-7 (shl (the-as int v1-6) 20))
(t1-3 (shl t1-2 35))
(a3-2 (-> arg1 dest 0))
(t1-4 (logior t1-3 v1-7))
(v1-8 (-> arg1 width 0))
(t1-6 (logior (logior t1-4 a3-2) (shl v1-8 14)))
)
(let ((v1-10 (the-as uint128 (-> arg1 wu))))
(.plzcw v1-11 (the-as uint v1-10))
)
(let ((t0-0 30))
(.subu v1-12 t0-0 (the-as int v1-11))
(let ((a3-3 (the-as uint128 (-> arg1 hu)))
(v1-13 (shl v1-12 26))
)
(.plzcw a3-4 (the-as uint a3-3))
(let ((t1-7 (logior t1-6 v1-13)))
(.subu a3-5 t0-0 (the-as int a3-4))
(let* ((a3-6 (shl a3-5 30))
(v1-14 1)
(t1-9 (logior (logior t1-7 a3-6) (shl v1-14 34)))
(v1-17 (shl (-> arg1 clutdest) 37))
(a3-8 (shl (-> arg1 clutpsm) 51))
(t1-11 (logior (logior t1-9 v1-17) a3-8))
(v1-19 (shl 1 61))
(f0-3 (the int f0-2))
(t1-12 (logior t1-11 v1-19))
(v1-20 (the-as uint128 f0-3))
)
(set! (-> arg0 tex0) (the-as gs-tex0 t1-12))
(.plzcw a3-9 (the-as int v1-20))
(.subu a3-10 t0-0 (the-as int a3-9))
(let ((t0-2 (+ (-> arg1 mip-shift) -1)))
(nop!)
(b! (zero? t0-2) cfg-2 :delay (nop!))
)
(let* ((t0-3 (+ a3-10 -4))
(a3-11 (* a3-10 16))
(t0-4 (sar (the-as int v1-20) t0-3))
(a3-12 (+ a3-11 -175))
(t0-5 (logand t0-4 15))
)
(nop!)
(b! #t cfg-3 :delay (set! a3-13 (+ a3-12 t0-5)))
)
(label cfg-2)
(let* ((t0-6 (+ a3-10 -5))
(a3-14 (* a3-10 32))
(t0-7 (sar (the-as int v1-20) t0-6))
(a3-15 (+ a3-14 -350))
(t0-8 (logand t0-7 31))
)
(nop!)
(set! a3-13 (+ a3-15 t0-8))
)
)
)
)
)
)
(nop!)
(label cfg-3)
(let* ((a3-16 (logand a3-13 4095))
(t1-13 (-> arg1 dest 1))
(a3-17 (shl a3-16 32))
(v1-21 (-> arg1 width 1))
(a2-5 (logior a2-4 a3-17))
(v1-22 (shl v1-21 14))
)
(set! (-> arg0 tex1) a2-5)
(let ((a2-6 (logior t1-13 v1-22))
(v1-23 (-> arg1 dest 2))
)
(nop!)
(let* ((a3-18 (-> arg1 width 2))
(a2-8 (logior (logior a2-6 (shl v1-23 20)) (shl a3-18 34)))
(v1-25 (-> arg1 dest 3))
(a3-20 (-> arg1 width 3))
(a2-10 (logior (logior a2-8 (shl v1-25 40)) (shl a3-20 54)))
(t0-10 (+ (-> arg1 num-mips) -5))
)
(set! (-> arg0 miptbp1) (the-as gs-miptbp a2-10))
(b! (< (the-as int t0-10) 0) cfg-5 :delay (set! a3-22 (-> arg1 width 4)))
)
)
)
)
(let* ((a2-12 (logior (-> arg1 dest 4) (shl a3-22 14)))
(v1-28 (shl (-> arg1 dest 5) 20))
(a3-24 (-> arg1 width 5))
(a2-14 (logior (logior a2-12 v1-28) (shl a3-24 34)))
(v1-30 (shl (-> arg1 dest 6) 40))
(a3-26 (-> arg1 width 6))
(a2-16 (logior (logior a2-14 v1-30) (shl a3-26 54)))
(v1-31 54)
)
(set! (-> arg0 alpha) (the-as gs-miptbp a2-16))
(nop!)
(set! (-> arg0 quad 4 vector4w z) v1-31)
)
(nop!)
(label cfg-5)
arg0
)
;; ERROR: function was not converted to expressions. Cannot decompile.
;; definition for function adgif-shader-login
(defun adgif-shader-login ((shader adgif-shader))

View file

@ -304,7 +304,7 @@
(define GSH_ENABLE #f)
;; definition for symbol GSH_BUCKET, type bucket-id
(define GSH_BUCKET (the-as bucket-id 3))
(define GSH_BUCKET (bucket-id bucket-3))
;; definition for symbol GSH_WHICH_STAT, type int
(define GSH_WHICH_STAT 1)

View file

@ -30,7 +30,7 @@
:flag-assert #xb00000110
(:methods
(reset! (_type_) symbol 9)
(TODO-RENAME-10 (_type_ int float float vector) object 10)
(set-fade! (_type_ int float float vector) object 10)
)
)
@ -123,27 +123,27 @@
;; definition of type time-of-day-context
(deftype time-of-day-context (basic)
((active-count uint32 :offset-assert 4)
(interp float :offset-assert 8)
(current-interp float :offset-assert 12)
(moods uint64 2 :offset-assert 16)
(current-fog mood-fog :inline :offset-assert 32)
(current-sun mood-sun :inline :offset-assert 80)
(current-prt-color vector :inline :offset-assert 112)
(current-shadow vector :inline :offset-assert 128)
(current-shadow-color vector :inline :offset-assert 144)
(light-group light-group 9 :inline :offset-assert 160)
(title-light-group light-group :inline :offset-assert 1888)
(time float :offset-assert 2080)
(target-interp float :offset-assert 2084)
(erase-color uint32 :offset-assert 2088)
(num-stars float :offset-assert 2092)
(light-masks-0 uint8 2 :offset-assert 2096)
(light-masks-1 uint8 2 :offset-assert 2098)
(light-interp uint32 2 :offset-assert 2100)
(sky symbol :offset-assert 2108)
(sun-fade float :offset-assert 2112)
(title-updated symbol :offset-assert 2116)
((active-count uint32 :offset-assert 4)
(interp float :offset-assert 8)
(current-interp float :offset-assert 12)
(moods mood-context 2 :offset-assert 16)
(current-fog mood-fog :inline :offset-assert 32)
(current-sun mood-sun :inline :offset-assert 80)
(current-prt-color vector :inline :offset-assert 112)
(current-shadow vector :inline :offset-assert 128)
(current-shadow-color vector :inline :offset-assert 144)
(light-group light-group 9 :inline :offset-assert 160)
(title-light-group light-group :inline :offset-assert 1888)
(time float :offset-assert 2080)
(target-interp float :offset-assert 2084)
(erase-color rgba :offset-assert 2088)
(num-stars float :offset-assert 2092)
(light-masks-0 uint8 2 :offset-assert 2096)
(light-masks-1 uint8 2 :offset-assert 2098)
(light-interp uint32 2 :offset-assert 2100)
(sky symbol :offset-assert 2108)
(sun-fade float :offset-assert 2112)
(title-updated symbol :offset-assert 2116)
)
:method-count-assert 9
:size-assert #x848

View file

@ -139,47 +139,47 @@
;; definition of type level
(deftype level (basic)
((name symbol :offset-assert 4)
(load-name symbol :offset-assert 8)
(nickname symbol :offset-assert 12)
(index int32 :offset-assert 16)
(status symbol :offset-assert 20)
(other level :offset-assert 24)
(heap kheap :inline :offset-assert 32)
(bsp bsp-header :offset-assert 48)
(art-group load-dir-art-group :offset-assert 52)
(info level-load-info :offset-assert 56)
(texture-page texture-page 9 :offset-assert 60)
(loaded-texture-page texture-page 16 :offset-assert 96)
(loaded-texture-page-count int32 :offset-assert 160)
(foreground-sink-group dma-foreground-sink-group 3 :inline :offset-assert 176)
(foreground-draw-engine engine 3 :offset-assert 272)
(entity entity-links-array :offset-assert 284)
(ambient entity-ambient-data-array :offset-assert 288)
(closest-object float 9 :offset-assert 292)
(upload-size int32 9 :offset-assert 328)
(level-distance meters :offset-assert 364)
(inside-sphere? symbol :offset-assert 368)
(inside-boxes? symbol :offset-assert 372)
(display? symbol :offset-assert 376)
(meta-inside? symbol :offset-assert 380)
(mood mood-context :offset-assert 384)
(mood-func function :offset-assert 388)
(vis-bits pointer :offset-assert 392)
(all-visible? symbol :offset-assert 396)
(force-all-visible? symbol :offset-assert 400)
(linking basic :offset-assert 404)
(vis-info level-vis-info 8 :offset-assert 408)
(vis-self-index int32 :offset-assert 440)
(vis-adj-index int32 :offset-assert 444)
(vis-buffer uint8 2048 :offset-assert 448)
(mem-usage-block memory-usage-block :offset-assert 2496)
(mem-usage int32 :offset-assert 2500)
(code-memory-start pointer :offset-assert 2504)
(code-memory-end pointer :offset-assert 2508)
(texture-mask uint32 9 :offset-assert 2512)
(force-inside? symbol :offset-assert 2548)
(pad uint8 56 :offset-assert 2552)
((name symbol :offset-assert 4)
(load-name symbol :offset-assert 8)
(nickname symbol :offset-assert 12)
(index int32 :offset-assert 16)
(status symbol :offset-assert 20)
(other level :offset-assert 24)
(heap kheap :inline :offset-assert 32)
(bsp bsp-header :offset-assert 48)
(art-group load-dir-art-group :offset-assert 52)
(info level-load-info :offset-assert 56)
(texture-page texture-page 9 :offset-assert 60)
(loaded-texture-page texture-page 16 :offset-assert 96)
(loaded-texture-page-count int32 :offset-assert 160)
(foreground-sink-group dma-foreground-sink-group 3 :inline :offset-assert 176)
(foreground-draw-engine engine 3 :offset-assert 272)
(entity entity-links-array :offset-assert 284)
(ambient entity-ambient-data-array :offset-assert 288)
(closest-object float 9 :offset-assert 292)
(upload-size int32 9 :offset-assert 328)
(level-distance meters :offset-assert 364)
(inside-sphere? symbol :offset-assert 368)
(inside-boxes? symbol :offset-assert 372)
(display? symbol :offset-assert 376)
(meta-inside? symbol :offset-assert 380)
(mood mood-context :offset-assert 384)
(mood-func (function mood-context float int none) :offset-assert 388)
(vis-bits pointer :offset-assert 392)
(all-visible? symbol :offset-assert 396)
(force-all-visible? symbol :offset-assert 400)
(linking basic :offset-assert 404)
(vis-info level-vis-info 8 :offset-assert 408)
(vis-self-index int32 :offset-assert 440)
(vis-adj-index int32 :offset-assert 444)
(vis-buffer uint8 2048 :offset-assert 448)
(mem-usage-block memory-usage-block :offset-assert 2496)
(mem-usage int32 :offset-assert 2500)
(code-memory-start pointer :offset-assert 2504)
(code-memory-end pointer :offset-assert 2508)
(texture-mask uint32 9 :offset-assert 2512)
(force-inside? symbol :offset-assert 2548)
(pad uint8 56 :offset-assert 2552)
)
:method-count-assert 29
:size-assert #xa30

View file

@ -239,7 +239,7 @@
(set! (-> s3-0 intensity) arg1)
)
)
(TODO-RENAME-10 *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans))
(set-fade! *palette-fade-controls* (+ arg0 1) arg1 0.0 (-> s3-0 trans))
)
)
@ -281,7 +281,3 @@
f30-0
)
)

View file

@ -272,7 +272,7 @@
)
)
)
(TODO-RENAME-10
(set-fade!
*palette-fade-controls*
3
(-> self deadly-fade)

View file

@ -63,6 +63,8 @@ const std::unordered_set<std::string> g_functions_expected_to_reject = {
// display
"vblank-handler", // asm
"vif1-handler", "vif1-handler-debug",
// texture
"adgif-shader<-texture-with-update!", // mips2c
// sparticle
"sp-launch-particles-var", "particle-adgif", "sp-init-fields!", "memcpy", "sp-process-block-2d",
"sp-process-block-3d",