diff --git a/.gitignore b/.gitignore index e09aea03..58c926f2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ CMakeLists.txt gltf_to_t3d website/html *.exe -*.pak \ No newline at end of file +*.pak +docs/_* +node_modules/ diff --git a/breakingChanges.md b/breakingChanges.md new file mode 100644 index 00000000..8d8c8bf7 --- /dev/null +++ b/breakingChanges.md @@ -0,0 +1,29 @@ +# Breaking changes + +## Precision fix (2026-09-28) + +This change increased depth precision, and by extension UV and position too by a bit. +However some existing bugs had to be fixed that caused a mismatch of units: + +### Projection Near/Far + +`t3d_viewport_set_projection` and `t3d_viewport_set_perspective` where wrong internally. +It resulted in a `far` value that was twice as far as it was supposed to be, at least for clipping. +Please re-adjust to the true value you need, otherwise geometry will clip too early now. + +### Fog Range + +`t3d_fog_set_range` was internally not correctly mapped to the world-space units. +This resulted in its near/far to refer to around double the amount. +Please re-adjust to the true value you need, otherwise fog will be too strong now. + +`t3d_fog_set_range` now also requires a viewport to be attached. +Please do so before a call, and re-set fog for every viewport (e.g. in split-screens). + +### Near-Clipping + +Before, geometry was clipped against the near-plane, +now it does so against the cameras eye instead. +The region between near and the eye will be drawn with a clamped minimum depth value. +Be aware geometry can now be a lot closer to the camera, and ideally make sure the camera doesn't get too close (which was a good idea before the changes too). +If you relied on some kind of effect that artificially moved the near-plane further, this is no longer supported. \ No newline at end of file diff --git a/examples/03_objects/main.c b/examples/03_objects/main.c index 14a23fc0..c345cfe6 100644 --- a/examples/03_objects/main.c +++ b/examples/03_objects/main.c @@ -148,7 +148,7 @@ int main() } timeUpdate = get_time_ms() - timeUpdate; - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(65.0f), 10.0f, 100.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(65.0f), 10.0f, 200.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); // ======== Draw (3D) ======== // diff --git a/examples/04_dynamic/main.c b/examples/04_dynamic/main.c index c272a33d..76b35446 100644 --- a/examples/04_dynamic/main.c +++ b/examples/04_dynamic/main.c @@ -105,7 +105,7 @@ int main() fm_vec3_t camPos = {{sinf(camAngle) * 45.0f, 35.0f, cosf(camAngle) * 60.0f}}; - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 10.0f, 150.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 10.0f, 200.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); // transform mesh @@ -184,7 +184,7 @@ int main() } // Draw room: - t3d_fog_set_range(0.4f, 80.0f); + t3d_fog_set_range(0.8f, 160.0f); t3d_fog_set_enabled(true); t3d_light_set_ambient(colorAmbient); diff --git a/examples/05_splitscreen/main.c b/examples/05_splitscreen/main.c index aa245f5d..d290a8ff 100644 --- a/examples/05_splitscreen/main.c +++ b/examples/05_splitscreen/main.c @@ -132,8 +132,6 @@ int main() t3d_screen_clear_color(RGBA32(160, 110, 200, 0xFF)); t3d_screen_clear_depth(); - t3d_fog_set_range(120.0f, 850.0f); - for(int v=0; vmodelMatFP[frameIdx], diff --git a/examples/13_cel_shading/main.c b/examples/13_cel_shading/main.c index bc4d3611..d8d9f911 100644 --- a/examples/13_cel_shading/main.c +++ b/examples/13_cel_shading/main.c @@ -200,7 +200,7 @@ int main() }}; fm_vec3_lerp(¤tPos, ¤tPos, &targetPos, 0.2f); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 5.0f, 120.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 5.0f, 240.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); t3d_mat4fp_from_srt_euler(&model->modelMatFP[frameIdx], @@ -231,6 +231,7 @@ int main() // ======== Draw ======== // rdpq_attach(display_get(), display_get_zbuf()); t3d_frame_start(); + rdpq_mode_dithering(DITHER_NONE_NONE); t3d_viewport_attach(&viewport); t3d_screen_clear_color(RGBA32(217, 174, 147, 0xFF)); diff --git a/examples/14_outline/main.c b/examples/14_outline/main.c index de3f5a52..762ec6a5 100644 --- a/examples/14_outline/main.c +++ b/examples/14_outline/main.c @@ -127,7 +127,7 @@ int main() fm_vec3_lerp(¤tPos, ¤tPos, &targetPos, 0.2f); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 5.0f, 120.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 5.0f, 240.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); float scale = 0.13f; diff --git a/examples/15_pointlight/main.c b/examples/15_pointlight/main.c index 872583cf..0eb1c8e5 100644 --- a/examples/15_pointlight/main.c +++ b/examples/15_pointlight/main.c @@ -196,7 +196,7 @@ int main() 3.0f, 250.0f ); } else { - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(65.0f), 3.0f, 220.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(65.0f), 10.0f, 400.0f); } t3d_viewport_look_at(&viewport, &camPos, &camTargetCurr, &(fm_vec3_t){{0,1,0}}); diff --git a/examples/16_light_clip/main.c b/examples/16_light_clip/main.c index 31c61cf5..a0cc5882 100644 --- a/examples/16_light_clip/main.c +++ b/examples/16_light_clip/main.c @@ -119,7 +119,7 @@ int main() camPos.v[2] = fm_sinf(angleHor) * fm_cosf(angleVer) * camDist; fm_vec3_lerp(&camPosCurrent, &camPosCurrent, &camPos, deltaTime * 5.0f); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(64.0f), 2.0f, 200.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(64.0f), 5.0f, 320.0f); t3d_viewport_look_at(&viewport, &camPosCurrent, &camTarget, &(fm_vec3_t){{0,1,0}}); // ----------- DRAW (3D) ------------ // diff --git a/examples/17_culling/main.c b/examples/17_culling/main.c index 641f7257..1efd57f1 100644 --- a/examples/17_culling/main.c +++ b/examples/17_culling/main.c @@ -126,9 +126,9 @@ int main() fm_vec3_add(&camTarget, &camPos, &camDir); if(currentModel == 0) { - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(75.0f), 1.0f, 160.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(75.0f), 2.0f, 420.0f); } else { - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(60.0f), 4.0f, 110.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(60.0f), 2.0f, 320.0f); } t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); @@ -195,7 +195,7 @@ int main() t3d_screen_clear_depth(); - t3d_fog_set_range(37.0f, 180.0f); + t3d_fog_set_range(45.0f, 340.0f); t3d_fog_set_enabled(true); t3d_light_set_ambient((uint8_t[]){0xFF, 0xFF, 0xFF, 0xFF}); diff --git a/examples/18_particles/main.c b/examples/18_particles/main.c index 708a1108..e3c8ccd5 100644 --- a/examples/18_particles/main.c +++ b/examples/18_particles/main.c @@ -228,7 +228,7 @@ int main() t3d_mat4fp_from_srt_euler(&matPartFP[frameIdx], particleMatScale.v, particleRot.v, particlePos.v); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(80.0f), 5.0f, 250.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(80.0f), 7.0f, 420.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); // ======== Draw (3D) ======== // @@ -275,6 +275,8 @@ int main() // so any push/pop here will not affect t3d and vice versa. // Also make sure that the first stack operation you do after 'tpx_state_from_t3d' is a push and not a set. tpx_matrix_push(&matPartFP[frameIdx]); + tpx_state_set_base_size(72); + // While each particle has its own size, there is a global scaling factor that can be set. // This can only scale particles down, so the range is 0.0 - 1.0. tpx_state_set_scale(partSizeX, partSizeY); diff --git a/examples/19_particles_tex/main.c b/examples/19_particles_tex/main.c index e50c4764..a3650728 100644 --- a/examples/19_particles_tex/main.c +++ b/examples/19_particles_tex/main.c @@ -256,7 +256,7 @@ int main() t3d_mat4fp_from_srt_euler(&matPartFP[frameIdx], particleMatScale.v, particleRot.v, particlePos.v); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(80.0f), 5.0f, 250.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(80.0f), 7.0f, 420.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); // ======== Draw (3D) ======== // @@ -317,6 +317,7 @@ int main() tpx_state_from_t3d(); tpx_matrix_push(&matPartFP[frameIdx]); + tpx_state_set_base_size(72); tpx_state_set_scale(partSizeX, partSizeY); float tileIdx = fm_floorf(timeTile) * 32; diff --git a/examples/20_mipmaps/main.c b/examples/20_mipmaps/main.c index 70a5e100..f672ac27 100644 --- a/examples/20_mipmaps/main.c +++ b/examples/20_mipmaps/main.c @@ -136,7 +136,7 @@ int main() }}; fm_vec3_lerp(¤tPos, ¤tPos, &trargetPos, 0.2f); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 14.0f, 240.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 14.0f, 450.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); t3d_mat4fp_from_srt_euler(&model->modelMatFP[frameIdx], diff --git a/examples/21_fresnel/main.c b/examples/21_fresnel/main.c index 3cc9d72a..405c3f1e 100644 --- a/examples/21_fresnel/main.c +++ b/examples/21_fresnel/main.c @@ -174,7 +174,7 @@ int main() }}; fm_vec3_lerp(¤tPos, ¤tPos, &trargetPos, 0.2f); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 4.0f, 100.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 6.0f, 200.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); t3d_mat4fp_from_srt_euler(&models->modelMatFP[frameIdx], diff --git a/examples/22_bigtex/src/scene/camera.cpp b/examples/22_bigtex/src/scene/camera.cpp index 96728301..91fa82d1 100644 --- a/examples/22_bigtex/src/scene/camera.cpp +++ b/examples/22_bigtex/src/scene/camera.cpp @@ -65,7 +65,7 @@ void Camera::update(float deltaTime) { target.v[1] = pos.v[1] + dir.v[1]; target.v[2] = pos.v[2] + dir.v[2]; - t3d_viewport_set_projection(viewport, T3D_DEG_TO_RAD(70.0f), 4.0f, 180.0f); + t3d_viewport_set_projection(viewport, T3D_DEG_TO_RAD(70.0f), 5.0f, 360.0f); t3d_viewport_look_at(viewport, pos, target, {0,1,0}); } diff --git a/examples/23_hdr/main.c b/examples/23_hdr/main.c index a926a5fe..a6e4ce58 100644 --- a/examples/23_hdr/main.c +++ b/examples/23_hdr/main.c @@ -222,7 +222,7 @@ int main() displayMetrics = false; } - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 2.5f, 150.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 4.0f, 300.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); t3d_mat4fp_from_srt_euler(&rotMatFP[frameIdx], diff --git a/examples/24_hdr_bloom/src/scene/scenes/sceneEnv.cpp b/examples/24_hdr_bloom/src/scene/scenes/sceneEnv.cpp index eae235ff..154cd2da 100644 --- a/examples/24_hdr_bloom/src/scene/scenes/sceneEnv.cpp +++ b/examples/24_hdr_bloom/src/scene/scenes/sceneEnv.cpp @@ -47,8 +47,8 @@ SceneEnv::SceneEnv() bgIndex = 1; camera.fov = T3D_DEG_TO_RAD(85.0f); - camera.near = 1.0f; - camera.far = 100.0f; + camera.near = 1.5f; + camera.far = 200.0f; camera.pos = {0.0, 0.0, 20.0}; camera.target = {0,0,0}; diff --git a/examples/24_hdr_bloom/src/scene/scenes/sceneMagic.cpp b/examples/24_hdr_bloom/src/scene/scenes/sceneMagic.cpp index 0da48693..8318e42c 100644 --- a/examples/24_hdr_bloom/src/scene/scenes/sceneMagic.cpp +++ b/examples/24_hdr_bloom/src/scene/scenes/sceneMagic.cpp @@ -24,7 +24,7 @@ SceneMagic::SceneMagic() { camera.fov = T3D_DEG_TO_RAD(75.0f); camera.near = 3.0f; - camera.far = 200.0f; + camera.far = 400.0f; camera.target = {0,0,0}; flyCam.camPos = {-50.0, 0.0, 0.0}; diff --git a/examples/24_hdr_bloom/src/scene/scenes/sceneMain.cpp b/examples/24_hdr_bloom/src/scene/scenes/sceneMain.cpp index e95f117d..528ef2fd 100644 --- a/examples/24_hdr_bloom/src/scene/scenes/sceneMain.cpp +++ b/examples/24_hdr_bloom/src/scene/scenes/sceneMain.cpp @@ -29,7 +29,7 @@ SceneMain::SceneMain() camera.fov = T3D_DEG_TO_RAD(80.0f); camera.near = 5.0f; - camera.far = 295.0f; + camera.far = 600.0f; //camera.pos = {0.0, -40.0, -400.0}; camera.pos = {0, 0, 10}; diff --git a/examples/24_hdr_bloom/src/scene/scenes/scenePixel.cpp b/examples/24_hdr_bloom/src/scene/scenes/scenePixel.cpp index 93f2d11e..5ee4aed9 100644 --- a/examples/24_hdr_bloom/src/scene/scenes/scenePixel.cpp +++ b/examples/24_hdr_bloom/src/scene/scenes/scenePixel.cpp @@ -28,7 +28,7 @@ ScenePixel::ScenePixel() { camera.fov = T3D_DEG_TO_RAD(70.0f); camera.near = 1.0f; - camera.far = 100.0f; + camera.far = 200.0f; camera.pos = {-50.0, 50.0, 50.0}; camera.target = {0,0,0}; diff --git a/examples/97_cliptest/.gitignore b/examples/97_cliptest/.gitignore new file mode 100644 index 00000000..b5c3a349 --- /dev/null +++ b/examples/97_cliptest/.gitignore @@ -0,0 +1,2 @@ +*.actual.png +*.diff.png \ No newline at end of file diff --git a/examples/97_cliptest/Makefile b/examples/97_cliptest/Makefile new file mode 100644 index 00000000..062d8180 --- /dev/null +++ b/examples/97_cliptest/Makefile @@ -0,0 +1,27 @@ +BUILD_DIR=build +T3D_INST=$(shell realpath ../..) + +include $(N64_INST)/include/n64.mk +include $(T3D_INST)/t3d.mk + +N64_CFLAGS += -std=gnu2x -Os $(CT_FLAGS) + +src = main.c + +all: t3d_97_cliptest.z64 + +$(BUILD_DIR)/t3d_97_cliptest.elf: $(src:%.c=$(BUILD_DIR)/%.o) + +t3d_97_cliptest.z64: N64_ROM_TITLE="Tiny3D - ClipTest" + +clean: + rm -rf $(BUILD_DIR) *.z64 + +build_lib: + rm -rf $(BUILD_DIR) *.z64 + make -C $(T3D_INST) + make all + +-include $(wildcard $(BUILD_DIR)/*.d) + +.PHONY: all clean diff --git a/examples/97_cliptest/main.c b/examples/97_cliptest/main.c new file mode 100644 index 00000000..422ca29c --- /dev/null +++ b/examples/97_cliptest/main.c @@ -0,0 +1,178 @@ +#include +#include + +/** + * Clipping benchmark / test scene (97_cliptest). + * + * Draws a fixed set of hand-made triangles that force every clipping case + * (one side plane, two side planes, all four, vertices behind the camera), + * plus a few reference triangles that are not clipped or are rejected. + * All vertex attributes are used: depth, shaded colour, UVs, fog. + * Nothing is animated, every frame is identical; 'cliptest.js' profiles the + * RSP commands and compares a screenshot. + * + * Debugging: 'make CT_FLAGS=-DONLY_TRI=n' builds a ROM that draws only triangle n, + * 'make CT_FLAGS=-DONLY_MASK=0x..' one that draws only the triangles whose bit is set. + */ + +typedef struct { + int16_t pos[3]; + uint32_t rgba; + int16_t st[2]; // texture pixels +} Vert; + +// Camera at z=-40 looking at the origin, FOV 85 deg (4:3): +// at z=0 the screen spans about +-49 x / +-37 y, the guard band (2x) +-98 / +-73. +// A vertex at |x| or |y| >= 200 is always outside the guard band, z <= -50 is behind the camera. +#define RED 0xFF0000FF +#define GREEN 0x00FF00FF +#define BLUE 0x0000FFFF +#define YELLOW 0xFFFF00FF +#define CYAN 0x00FFFFFF +#define PINK 0xFF00FFFF +#define WHITE 0xFFFFFFFF + +static const Vert VERTS[] = { + // 0: +X plane only + {{ 10, -10, 0}, RED, {0, 0}}, {{ 200, -20, 5}, GREEN, {96, 0}}, {{ 10, 20, -5}, BLUE, {0, 64}}, + // 3: -X plane only + {{ -10, -15, 0}, YELLOW, {0, 0}}, {{-200, -5, 10}, CYAN, {96, 0}}, {{ -10, 15, -8}, PINK, {0, 64}}, + // 6: +Y plane only + {{ -20, 10, 0}, GREEN, {0, 0}}, {{ 20, 5, 10}, BLUE, {32, 0}}, {{ 0, 200, 0}, RED, {0, 96}}, + // 9: -Y plane only + {{ -20, -10, 0}, CYAN, {0, 0}}, {{ 20, -5, -5}, PINK, {32, 0}}, {{ 5,-200, 20}, YELLOW, {0, 96}}, + // 12: +X and +Y (corner) + {{ 0, 0, 0}, WHITE, {0, 0}}, {{ 200, 30, 0}, RED, {64, 0}}, {{ 30, 200, 0}, BLUE, {0, 64}}, + // 15: -X and -Y (corner) + {{ 0, 0, 5}, WHITE, {0, 0}}, {{-200, -30, 0}, GREEN, {64, 0}}, {{ -30,-200, 10}, YELLOW, {0, 64}}, + // 18: huge background triangle, crosses all four side planes + {{-300,-300, 15}, RED, {0, 0}}, {{ 300,-300, 15}, GREEN, {128, 0}}, {{ 0, 300, 15}, BLUE, {64,128}}, + // 21: one vertex behind the camera + {{ -15, -5, -10}, CYAN, {0, 0}}, {{ 15, -5, -10}, PINK, {32, 0}}, {{ 0, -30, -60}, WHITE, {16, 32}}, + // 24: two vertices behind the camera + {{ 0, 10, -10}, YELLOW, {16, 0}}, {{ -40, 20, -70}, RED, {0, 32}}, {{ 40, 20, -70}, GREEN, {32, 32}}, + // 27: tilted floor quad, far edge in front, near edge behind the camera (2 tris) + {{ -60, -25, 60}, BLUE, {0, 0}}, {{ 60, -25, 60}, CYAN, {64, 0}}, {{ 60, -25, -60}, PINK, {64, 64}}, {{ -60, -25, -60}, WHITE, {0, 64}}, + // 31: reference quad, fully inside (2 tris, never clipped) + {{ -8, -8, -5}, RED, {0, 0}}, {{ 8, -8, -5}, GREEN, {32, 0}}, {{ 8, 8, -5}, BLUE, {32, 32}}, {{ -8, 8, -5}, WHITE, {0, 32}}, + // 35: fully outside, rejected + {{ 200, 200, 0}, RED, {0, 0}}, {{ 250, 200, 0}, GREEN, {32, 0}}, {{ 200, 250, 0}, BLUE, {0, 32}}, + // 38: crosses the screen edge but stays inside the guard band (scissor only, no clipping) + {{ 30, 0, 0}, YELLOW, {0, 0}}, {{ 80, -20, 0}, CYAN, {32, 0}}, {{ 80, 20, 0}, PINK, {32, 32}}, +}; +#define VERT_COUNT (sizeof(VERTS) / sizeof(VERTS[0])) + +static const uint8_t TRIS[][3] = { + {0,1,2}, {3,4,5}, {6,7,8}, {9,10,11}, {12,13,14}, {15,16,17}, {18,19,20}, + {21,22,23}, {24,25,26}, + {27,28,29}, {27,29,30}, + {31,32,33}, {31,33,34}, + {35,36,37}, + {38,39,40}, +}; +#define TRI_COUNT (sizeof(TRIS) / sizeof(TRIS[0])) + +int main() +{ + debug_init_isviewer(); + debug_init_usblog(); + + display_init(RESOLUTION_320x240, DEPTH_16_BPP, 3, GAMMA_NONE, FILTERS_RESAMPLE); + rdpq_init(); + t3d_init((T3DInitParams){}); + + T3DMat4FP* modelMatFP = malloc_uncached(sizeof(T3DMat4FP)); + t3d_mat4fp_identity(modelMatFP); + + // procedural 32x32 checker texture, no filesystem needed + surface_t tex = surface_alloc(FMT_RGBA16, 32, 32); + for(int y=0; y<32; ++y) { + uint16_t *row = (uint16_t*)((uint8_t*)tex.buffer + y * tex.stride); + for(int x=0; x<32; ++x) { + bool check = ((x >> 3) ^ (y >> 3)) & 1; + uint32_t r = check ? 31 : 8 + (x >> 1); + uint32_t g = check ? 31 : 8 + (y >> 1); + uint32_t b = check ? 31 : 20; + row[x] = (r << 11) | (g << 6) | (b << 1) | 1; + } + } + data_cache_hit_writeback(tex.buffer, tex.stride * 32); + + // pack vertices (UVs are 10.5 fixed point pixel coordinates) + uint32_t packedCount = (VERT_COUNT + 1) / 2; + T3DVertPacked* vertices = malloc_uncached(sizeof(T3DVertPacked) * packedCount); + uint16_t norm = t3d_vert_pack_normal(&(T3DVec3){{0, 0, 1}}); + for(uint32_t i=0; iposB[0] = v->pos[0]; p->posB[1] = v->pos[1]; p->posB[2] = v->pos[2]; + p->rgbaB = v->rgba; p->normB = norm; + p->stB[0] = v->st[0] << 5; p->stB[1] = v->st[1] << 5; + } else { + p->posA[0] = v->pos[0]; p->posA[1] = v->pos[1]; p->posA[2] = v->pos[2]; + p->rgbaA = v->rgba; p->normA = norm; + p->stA[0] = v->st[0] << 5; p->stA[1] = v->st[1] << 5; + } + } + + const T3DVec3 camPos = {{0, 0, -40}}; + const T3DVec3 camTarget = {{0, 0, 0}}; + uint8_t colorAmbient[4] = {80, 80, 80, 0xFF}; + uint8_t colorDir[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + T3DVec3 lightDirVec = {{0.0f, 0.0f, 1.0f}}; + + T3DViewport viewport = t3d_viewport_create(); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 10.0f, 100.0f); + t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(T3DVec3){{0, 1, 0}}); + + rspq_block_t *dplDraw = NULL; + + for(;;) + { + rdpq_attach(display_get(), display_get_zbuf()); + t3d_frame_start(); + t3d_viewport_attach(&viewport); + + t3d_screen_clear_color(RGBA32(30, 30, 60, 0)); + t3d_screen_clear_depth(); + + t3d_light_set_ambient(colorAmbient); + t3d_light_set_directional(0, colorDir, &lightDirVec); + t3d_light_set_count(1); + + rdpq_set_fog_color(RGBA32(120, 120, 140, 0xFF)); + t3d_fog_set_range(30.0f, 120.0f); + t3d_fog_set_enabled(true); + + rdpq_mode_combiner(RDPQ_COMBINER_TEX_SHADE); + rdpq_mode_fog(RDPQ_FOG_STANDARD); + rdpq_tex_upload(TILE0, &tex, &(rdpq_texparms_t){.s.repeats = REPEAT_INFINITE, .t.repeats = REPEAT_INFINITE}); + + t3d_state_set_drawflags(T3D_FLAG_SHADED | T3D_FLAG_TEXTURED | T3D_FLAG_DEPTH); + + if(!dplDraw) { + rspq_block_begin(); + t3d_matrix_push(modelMatFP); + t3d_vert_load(vertices, 0, packedCount * 2); + t3d_matrix_pop(1); + for(uint32_t i=0; i> i) & 1))continue; + #endif + t3d_tri_draw(TRIS[i][0], TRIS[i][1], TRIS[i][2]); + } + t3d_tri_sync(); + dplDraw = rspq_block_end(); + } + rspq_block_run(dplDraw); + + rdpq_detach_show(); + } + + t3d_destroy(); + return 0; +} diff --git a/examples/98_depthtest/.gitignore b/examples/98_depthtest/.gitignore new file mode 100644 index 00000000..569c1ff3 --- /dev/null +++ b/examples/98_depthtest/.gitignore @@ -0,0 +1,2 @@ +*.html +data/* \ No newline at end of file diff --git a/examples/98_depthtest/Makefile b/examples/98_depthtest/Makefile new file mode 100644 index 00000000..27ed9c93 --- /dev/null +++ b/examples/98_depthtest/Makefile @@ -0,0 +1,27 @@ +BUILD_DIR=build +T3D_INST=$(shell realpath ../..) + +include $(N64_INST)/include/n64.mk +include $(T3D_INST)/t3d.mk + +N64_CFLAGS += -std=gnu2x -Os $(DT_FLAGS) + +src = main.c + +all: t3d_98_depthtest.z64 + +$(BUILD_DIR)/t3d_98_depthtest.elf: $(src:%.c=$(BUILD_DIR)/%.o) + +t3d_98_depthtest.z64: N64_ROM_TITLE="Tiny3D - Depth Test" + +clean: + rm -rf $(BUILD_DIR) *.z64 + +build_lib: + rm -rf $(BUILD_DIR) *.z64 + make -C $(T3D_INST) + make all + +-include $(wildcard $(BUILD_DIR)/*.d) + +.PHONY: all clean diff --git a/examples/98_depthtest/depthtest.js b/examples/98_depthtest/depthtest.js new file mode 100644 index 00000000..fa94702e --- /dev/null +++ b/examples/98_depthtest/depthtest.js @@ -0,0 +1,357 @@ +// Depth precision measurement driver for 98_depthtest. +// +// Usage: ares-test examples/98_depthtest/depthtest.js [preset=0] [scenes=sweep,plane,sep] [dump] [label] +// preset: 0 = 10/12800, 1 = 10/1000, 2 = 10/150, 3 = 1/100 +// dump: any non-empty value -> the raw measurements (sweep samples, plane depth +// buffers, colour classification maps, SEP patterns) are printed as one JSON +// document between "DTDUMP-BEGIN" / "DTDUMP-END" lines (see dump.sh), so the +// results can be visualised (tools/depth_report.html) without re-running. +// label: free-form name stored in the dump (defaults to the ROM file name) +// +// Drives the ROM through its scenes via controller input, reads the decoded +// 18-bit z-buffer (ares.depthBuffer) / colour buffer at the exact moment each +// frame completes (the ROM prints its "DT ..." line right after rspq_wait, +// onLog fires on that line), and condenses everything into a few numbers: +// +// SWEEP bits log2(distinct stored depth values over [near, far]) +// inversions steps where Z decreases although w increases (max size) +// vertex err max / p99 of |dw|/w, from the residual against a +// least-squares fit Z = A + B/w (mapping-agnostic) +// PLANE slope err single quad vs analytic depth (|dw|/w max / rms) +// vertex err dense grid vs analytic depth +// coplanar max |Z_single - Z_dense| in integer Z units +// decal fail % pixels where a coplanar DECAL pass lost +// opaque fight % pixels where a coplanar opaque pass lost +// SEP separable g/d per distance: smallest gap that (reliably) resolves +// +// Analytic plane depth uses pixel centres at (px+0.5, py+0.5); the RDP's +// exact sample convention may differ by a fraction of a pixel, which mostly +// affects the grazing far rows - treat the plane's absolute numbers as +// slightly pessimistic and the coplanar / % numbers as exact. + +const [rom, presetArg, scenesArg, dumpArg, labelArg] = ares.args; +if (!rom) throw new Error("usage: depthtest.js [preset] [scenes] [dump] [label]"); +const PRESET = parseInt(presetArg || "0", 10); +const SCENES = (scenesArg || "sweep,plane,sep").split(","); +const DUMP = !!dumpArg; +const dump = { format: 1, rom: rom.split("/").pop(), label: labelArg || rom.split("/").pop(), preset: PRESET, + screen: { w: 320, h: 240 }, fovDeg: 60 }; + +// base64 of a Uint32Array (little endian), used for the 320x240 depth buffers +function b64u32(arr) { + const bytes = new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength); + const T = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let out = "", i = 0; + for (; i + 2 < bytes.length; i += 3) { + const n = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; + out += T[n >> 18] + T[(n >> 12) & 63] + T[(n >> 6) & 63] + T[n & 63]; + } + if (i < bytes.length) { + const n = (bytes[i] << 16) | ((i + 1 < bytes.length ? bytes[i + 1] : 0) << 8); + out += T[n >> 18] + T[(n >> 12) & 63] + (i + 1 < bytes.length ? T[(n >> 6) & 63] : "=") + "="; + } + return out; +} + +const W = 320, H = 240, FOV_DEG = 60, ASPECT = W / H; +const TAN_HALF = Math.tan(FOV_DEG / 2 * Math.PI / 180); +const SUB_COUNT = [2, 4, 2], STEP_COUNT = [2000, 4, 8]; +const SEP_GRID = 4; + +ares.setRenderer("angrylion"); +ares.loadRom(rom); +ares.resume(); +if (!ares.waitLog("DT ready", 60)) throw new Error("ROM did not boot:\n" + ares.log()); + +const p1 = ares.controller(1); + +// ---- ROM state tracking + input ------------------------------------------- +const cur = { scene: 0, sub: 0, step: 0, preset: 0 }; +const marker = (s) => `DT scene=${s.scene} sub=${s.sub} step=${s.step} `; + +// hold a button until the ROM reports the expected state (its frames can be +// longer than one VI, so a fixed-length press could be missed) +function pressUntil(btn, expect) { + ares.clearLog(); + p1.hold(btn); + const ok = ares.waitLog(marker(expect), 20); + p1.release(btn); + ares.waitVI(); ares.waitVI(); + if (!ok) throw new Error(`button ${btn}: ROM never reached ${JSON.stringify(expect)}\n` + ares.log().slice(-800)); + Object.assign(cur, expect); +} + +function setPreset(p) { + while (cur.preset !== p) pressUntil("R", { ...cur, preset: (cur.preset + 1) % 4 }); +} +function setScene(scene, sub, step) { + while (cur.scene !== scene) { + pressUntil("C-Right", { scene: (cur.scene + 1) % 3, sub: 0, step: 0, preset: cur.preset }); + } + while (cur.sub !== sub) pressUntil("A", { ...cur, sub: (cur.sub + 1) % SUB_COUNT[scene] }); + if (cur.step !== step) { + if (cur.step !== 0) pressUntil("Z", { ...cur, step: 0 }); + while (step - cur.step >= 100) pressUntil("Up", { ...cur, step: Math.min(cur.step + 100, STEP_COUNT[scene] - 1) }); + while (cur.step < step) pressUntil("Right", { ...cur, step: cur.step + 1 }); + } +} + +// ---- capture ---------------------------------------------------------------- +function parseLine(line) { + const o = {}; + for (const tok of line.slice(3).split(" ")) { + const eq = tok.indexOf("="); + if (eq > 0) o[tok.slice(0, eq)] = tok.slice(eq + 1); + } + return o; +} +let onFrame = null; +ares.onLog((line) => { + if (!onFrame || !line.startsWith("DT scene=")) return; + onFrame(parseLine(line)); +}); + +// wait until the current state has been rendered and captured once +function captureCurrent(fn) { + let done = false; + onFrame = (st) => { + if (done) return; + if (+st.scene !== cur.scene || +st.sub !== cur.sub || +st.step !== cur.step) return; + fn(st); done = true; + }; + ares.clearLog(); + if (!ares.waitLog(marker(cur), 20)) throw new Error("no frame for " + marker(cur)); + onFrame = null; + if (!done) throw new Error("capture missed for " + marker(cur)); +} + +const depthFull = () => new Uint32Array(ares.depthBuffer(W, H).data); +function depthRegion(x, y, w, h) { return new Uint32Array(ares.depthBuffer(W, H, { x, y, width: w, height: h }).data); } +function shotRGB() { + const s = ares.screenshot(); + return { w: s.width, h: s.height, px: new Uint8Array(s.data) }; +} +function classify(shot, x, y) { // x,y in 320x240 space -> "red" | "green" | "other" + const sx = Math.floor((x + 0.5) * shot.w / W), sy = Math.floor((y + 0.5) * shot.h / H); + const i = (sy * shot.w + sx) * 4, r = shot.px[i], g = shot.px[i + 1], b = shot.px[i + 2]; + if (r > 128 && g < 100 && b < 100) return "red"; + if (g > 128 && r < 100 && b < 100) return "green"; + return "other"; +} + +const fmtPct = (v) => (v * 100).toFixed(4) + "%"; +const fmt = (v, d = 2) => (typeof v === "number" ? v.toFixed(d) : String(v)); + +// ---- SWEEP ----------------------------------------------------------------- +let fit = null; // {A, B}: Z = A + B/w (18-bit units) +function runSweep(info) { + setScene(0, 0, 0); + const samples = []; // {step, w, z, spread} + const RX = 128, RY = 104, RW = 64, RH = 32; + onFrame = (st) => { + if (+st.scene !== 0 || +st.sub !== 0) return; + const step = +st.step; + if (samples.length && samples[samples.length - 1].step === step) return; + const z = depthRegion(RX, RY, RW, RH); + const counts = new Map(); + for (const v of z) counts.set(v, (counts.get(v) || 0) + 1); + let mode = 0, modeN = 0; + for (const [v, n] of counts) if (n > modeN) { mode = v; modeN = n; } + samples.push({ step, w: +st.w, z: mode, spread: z.length - modeN }); + }; + ares.clearLog(); + if (!ares.waitLog(marker(cur), 20)) throw new Error("sweep: no first frame"); + // auto-advance: one step per frame + p1.hold("Start"); + if (!ares.waitLog("step=1 ", 20)) throw new Error("sweep: auto-advance did not start"); + p1.release("Start"); + if (!ares.waitLog(`step=${STEP_COUNT[0] - 1} `, 600)) throw new Error("sweep: did not reach the last step"); + ares.waitVI(); ares.waitVI(); + onFrame = null; + cur.step = STEP_COUNT[0] - 1; + + samples.sort((a, b) => a.w - b.w); + const n = samples.length; + // least squares Z = A + B * (1/w) + let sx = 0, sy = 0, sxx = 0, sxy = 0; + for (const s of samples) { const x = 1 / s.w; sx += x; sy += s.z; sxx += x * x; sxy += x * s.z; } + const B = (n * sxy - sx * sy) / (n * sxx - sx * sx); + const A = (sy - B * sx) / n; + fit = { A, B }; + + const distinct = new Set(samples.map((s) => s.z)).size; + let inversions = 0, maxInv = 0; + for (let i = 1; i < n; ++i) { + const d = samples[i - 1].z - samples[i].z; + if (d > 0) { inversions++; maxInv = Math.max(maxInv, d); } + } + const relErr = samples.map((s) => Math.abs(s.z - (A + B / s.w)) * s.w / Math.abs(B)); + const zErr = samples.map((s) => Math.abs(s.z - (A + B / s.w)) / 8); + const sortedRel = [...relErr].sort((a, b) => a - b); + const p99 = sortedRel[Math.floor(0.99 * (n - 1))]; + const maxRel = sortedRel[n - 1]; + const maxZ = Math.max(...zErr); + const rmsZ = Math.sqrt(zErr.reduce((a, v) => a + v * v, 0) / n); + const nonUniform = samples.filter((s) => s.spread > 0).length; + const zMin = samples[0].z / 8, zMax = samples[n - 1].z / 8; + + console.log(`\n== SWEEP ${info} (${n} samples, w ${fmt(samples[0].w)} .. ${fmt(samples[n - 1].w)})`); + console.log(` stored codes : ${distinct} (${Math.log2(distinct).toFixed(2)} bits) Z range ${zMin.toFixed(1)} .. ${zMax.toFixed(1)} (integer units, 0..32767)`); + console.log(` inversions : ${inversions} (max ${(maxInv / 8).toFixed(2)} Z units)`); + console.log(` vertex error : max ${maxZ.toFixed(2)} / rms ${rmsZ.toFixed(2)} Z units; |dw|/w max ${fmtPct(maxRel)} p99 ${fmtPct(p99)}`); + console.log(` fit : Z = ${A.toFixed(1)} + ${B.toFixed(1)}/w (18-bit units)`); + if (nonUniform) console.log(` WARNING: ${nonUniform} samples had non-uniform depth across the flat quad (max spread px)`); + const res = { distinct, bits: Math.log2(distinct), inversions, maxInv: maxInv / 8, maxZ, rmsZ, maxRel, p99 }; + if (DUMP) dump.sweep = { region: { x: RX, y: RY, w: RW, h: RH }, samples, fit: { A, B }, result: res }; + return res; +} + +// ---- PLANE ----------------------------------------------------------------- +function runPlane(info) { + const res = {}; + // sub 0 single, sub 1 dense: depth + const depths = {}; + let params = null; + for (const sub of [0, 1]) { + setScene(1, sub, 0); + captureCurrent((st) => { depths[sub] = depthFull(); params = st; }); + } + const h = +params.h; + const emptyZ = depths[0][0]; // pixel (0,0) is always background + const isFilled = (buf, x, y) => x >= 0 && y >= 0 && x < W && y < H && buf[y * W + x] < emptyZ; + // footprint: filled in both, eroded by 2 px + const inFoot = (x, y) => { + for (let dy = -2; dy <= 2; ++dy) for (let dx = -2; dx <= 2; ++dx) + if (!isFilled(depths[0], x + dx, y + dy) || !isFilled(depths[1], x + dx, y + dy)) return false; + return true; + }; + let nPix = 0, copMax = 0, copSq = 0; + const err = { 0: { max: 0, sq: 0 }, 1: { max: 0, sq: 0 } }; + for (let y = 0; y < H; ++y) for (let x = 0; x < W; ++x) { + if (!inFoot(x, y)) continue; + nPix++; + const zs = depths[0][y * W + x], zd = depths[1][y * W + x]; + const cop = Math.abs(zs - zd) / 8; + copMax = Math.max(copMax, cop); copSq += cop * cop; + if (fit) { + const ndcY = 1 - (y + 0.5) / H * 2; + if (ndcY >= 0) continue; + const w = h / (-ndcY * TAN_HALF); + const zi = fit.A + fit.B / w; + for (const sub of [0, 1]) { + const rel = Math.abs(depths[sub][y * W + x] - zi) * w / Math.abs(fit.B); + err[sub].max = Math.max(err[sub].max, rel); err[sub].sq += rel * rel; + } + } + } + // sub 2 decal, sub 3 opaque: colour + const fails = {}; + for (const sub of [2, 3]) { + setScene(1, sub, 0); + let shot = null; + captureCurrent(() => { shot = shotRGB(); }); + let red = 0, green = 0; + const map = new Array(H); + for (let y = 0; y < H; ++y) { + let row = ""; + for (let x = 0; x < W; ++x) { + const c = classify(shot, x, y); + row += c === "red" ? "r" : c === "green" ? "g" : "."; + if (!inFoot(x, y)) continue; + if (c === "red") red++; else if (c === "green") green++; + } + map[y] = row; + } + fails[sub] = red / Math.max(1, red + green); + if (DUMP) (dump.planeMaps = dump.planeMaps || {})[sub] = map.join("\n"); + } + console.log(`\n== PLANE ${info} (h=${h}, ${nPix} px evaluated)`); + if (fit) { + console.log(` slope error (single quad) : |dw|/w max ${fmtPct(err[0].max)} rms ${fmtPct(Math.sqrt(err[0].sq / nPix))}`); + console.log(` vertex error (dense grid) : |dw|/w max ${fmtPct(err[1].max)} rms ${fmtPct(Math.sqrt(err[1].sq / nPix))}`); + } else { + console.log(` (run the sweep first to get absolute errors against the fitted mapping)`); + } + console.log(` coplanar |Zsingle - Zdense| : max ${copMax.toFixed(2)} rms ${Math.sqrt(copSq / nPix).toFixed(2)} Z units`); + console.log(` decal fail : ${fmtPct(fails[2])} of the plane`); + console.log(` opaque coplanar fight : ${fmtPct(fails[3])} of the plane lost by the dense mesh`); + const out = { slopeMax: err[0].max, vertexMax: err[1].max, copMax, decalFail: fails[2], fight: fails[3], + slopeRms: Math.sqrt(err[0].sq / Math.max(1, nPix)), vertexRms: Math.sqrt(err[1].sq / Math.max(1, nPix)), nPix }; + if (DUMP) { + dump.plane = { params, h, emptyZ, depthSingle: b64u32(depths[0]), depthDense: b64u32(depths[1]), + decalMap: (dump.planeMaps || {})[2], opaqueMap: (dump.planeMaps || {})[3], result: out }; + delete dump.planeMaps; + } + return out; +} + +// ---- SEP ------------------------------------------------------------------- +function runSep(info) { + const rows = []; + for (const sub of [0, 1]) { + for (let step = 0; step < STEP_COUNT[2]; ++step) { + setScene(2, sub, step); + let shot = null, params = null; + captureCurrent((st) => { shot = shotRGB(); params = st; }); + const gaps = params.gapFrac.split(",").map(Number); + const d = +params.d; + const cellW = W / SEP_GRID, cellH = H / SEP_GRID; + const pass = []; + for (let cell = 0; cell < SEP_GRID * SEP_GRID; ++cell) { + const cx = (cell % SEP_GRID + 0.5) * cellW, cy = (Math.floor(cell / SEP_GRID) + 0.5) * cellH; + // front quad covers 40% of the cell; evaluate its central part + const ex = cellW * 0.4 * 0.5 * 0.6, ey = cellH * 0.4 * 0.5 * 0.5; + let red = 0, green = 0, tot = 0; + for (let y = Math.round(cy - ey); y <= Math.round(cy + ey); ++y) + for (let x = Math.round(cx - ex); x <= Math.round(cx + ex); ++x) { + const c = classify(shot, x, y); tot++; + if (c === "red") red++; else if (c === "green") green++; + } + pass.push(red === 0 && green > tot * 0.5); + } + // cells are ordered by decreasing gap: "reliable" = the last cell of the + // initial run of passes, "smallest" = the smallest gap that passed at all + let smallest = null; + for (let c = 0; c < pass.length; ++c) if (pass[c]) smallest = gaps[c]; + const firstFail = pass.indexOf(false); + const reliable = firstFail === -1 ? gaps[gaps.length - 1] : (firstFail === 0 ? null : gaps[firstFail - 1]); + rows.push({ sub, step, d, gaps, pattern: pass.map((p) => (p ? "#" : ".")).join(""), reliable, smallest }); + } + } + console.log(`\n== SEP ${info} (cells: gap/d from ${fmt(Math.pow(2, -3), 4)} down to ${fmt(Math.pow(2, -(3 + 0.75 * 15)), 6)}, '#' = resolved)`); + console.log(` tilt d pattern reliable g/d smallest passing g/d`); + for (const r of rows) { + console.log(` ${r.sub ? "30" : " 0"} ${r.d.toFixed(2).padStart(9)} ${r.pattern} ${r.reliable === null ? " none" : fmtPct(r.reliable).padStart(11)} ${r.smallest === null ? "none" : fmtPct(r.smallest)}`); + } + if (DUMP) dump.sep = rows; + return rows; +} + +// ---- main ------------------------------------------------------------------ +setPreset(PRESET); +// read the preset's near/far from the ROM's own line +let presetInfo = ""; +captureCurrent((st) => { presetInfo = `near=${st.near} far=${st.far}`; }); +console.log(`\n#### depth test: ${rom} preset ${PRESET} (${presetInfo})`); + +const results = {}; +if (SCENES.includes("sweep")) results.sweep = runSweep(presetInfo); +if (SCENES.includes("plane")) results.plane = runPlane(presetInfo); +if (SCENES.includes("sep")) results.sep = runSep(presetInfo); + +console.log("\n#### summary " + presetInfo); +if (results.sweep) console.log(` bits ${results.sweep.bits.toFixed(2)} | inversions ${results.sweep.inversions} (max ${results.sweep.maxInv.toFixed(1)}) | vertex err max ${results.sweep.maxZ.toFixed(1)} Z, |dw|/w p99 ${fmtPct(results.sweep.p99)}`); +if (results.plane) console.log(` coplanar max ${results.plane.copMax.toFixed(1)} Z | decal fail ${fmtPct(results.plane.decalFail)} | opaque fight ${fmtPct(results.plane.fight)}`); +if (results.sep) { + const r0 = results.sep.filter((r) => r.sub === 0); + console.log(` separable g/d (flat): ` + r0.map((r) => `${r.d.toFixed(0)}:${r.reliable === null ? "none" : fmtPct(r.reliable)}`).join(" ")); +} +console.log("#### done"); +if (DUMP) { + dump.near = +presetInfo.match(/near=(\S+)/)[1]; + dump.far = +presetInfo.match(/far=(\S+)/)[1]; + dump.summary = { sweep: results.sweep, plane: results.plane }; + console.log("DTDUMP-BEGIN"); + console.log(JSON.stringify(dump)); + console.log("DTDUMP-END"); +} diff --git a/examples/98_depthtest/dump.sh b/examples/98_depthtest/dump.sh new file mode 100755 index 00000000..3029c71e --- /dev/null +++ b/examples/98_depthtest/dump.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Run the depth bench once and store its raw measurements as JSON, so that the +# results can be visualised later (tools/depth_report.html) without re-running. +# examples/98_depthtest/dump.sh [label] +set -euo pipefail +ROM=$1; PRESET=$2; OUT=$3; LABEL=${4:-$(basename "$ROM" .z64)} +HERE="$(cd "$(dirname "$0")" && pwd)" +TMP="$(mktemp)" +ares-test "$HERE/depthtest.js" "$ROM" "$PRESET" sweep,plane,sep dump "$LABEL" 2>&1 | sed 's/\x1b\[[0-9;]*m//g' > "$TMP" || true +grep -E '^(#### | |== )' "$TMP" || true +awk '/^DTDUMP-BEGIN$/{f=1; next} /^DTDUMP-END$/{f=0} f' "$TMP" > "$OUT" +rm -f "$TMP" +[ -s "$OUT" ] || { echo "no dump produced" >&2; exit 1; } +echo "wrote $OUT ($(stat -c %s "$OUT") bytes)" diff --git a/examples/98_depthtest/main.c b/examples/98_depthtest/main.c new file mode 100644 index 00000000..f3aa54cc --- /dev/null +++ b/examples/98_depthtest/main.c @@ -0,0 +1,361 @@ +#include +#include +#include + +/** + * 98_depthtest - depth precision measurement scenes. + * + * Deterministic test scenes for measuring the real depth pipeline + * (vertex Z, slopes, z-buffer encoding, comparator) under an emulator that + * exposes the 18-bit z-buffer. Nothing here depends on time or frame rate: + * the whole state is a handful of integers changed via controller input, + * and every frame is rendered synchronously (rspq_wait) and re-rendered + * identically until the state changes. + * + * Camera: origin, looking down -Z, vertical FOV 60deg, screen 320x240. + * + * Scenes (C-left / C-right): + * 0 SWEEP - view-aligned quad at distance w(step), log-spaced between + * 1.05*near and 0.99*far over SWEEP_STEPS steps. Every pixel + * must hold the same code; the sweep gives bits / monotonicity / + * vertex error (fit Z = A + B/w on the host). + * sub 0: quad covers ~80% of the screen (never clipped) + * sub 1: quad 2.5x oversized (goes through the clipper) + * 1 PLANE - floor plane y = -h from z=-z0 (near) to z=-z1 (far), + * per-pixel ideal depth is analytic on the host. + * sub 0: single quad (2 tris), red -> slope error + * sub 1: dense grid PLANE_DIV^2, green -> vertex error + * sub 2: single opaque red + dense DECAL green -> decal fail % + * sub 3: single opaque red + dense opaque green (coplanar fight) + * step: selects the plane height h (0..3), see printout + * 2 SEP - 4x4 cells; each cell = red back quad at distance d and an + * inset green front quad at d - g, g/d log-spaced per cell + * (see the printed gap list). A cell passes when the inset is + * all green. step = distance index (SEP_DISTANCES, log-spaced), + * sub 0: view-aligned, sub 1: both quads tilted 30deg about X. + * + * Controls: + * D-pad left/right step -1/+1 D-pad down/up step -100/+100 + * C-left/C-right scene -1/+1 A / B sub +1/-1 + * L / R near/far preset -1/+1 + * Z step = 0 Start auto-advance step each frame + * + * Protocol (ISViewer/usblog): every rendered frame prints one line + * "DT scene= sub= step= near= far= " + * after the frame has fully completed. In addition the current + * scene/sub/step is encoded into the colour buffer as a 24-cell barcode on + * the bottom row (y >= MARKER_Y, outside the measured area), MSB first, + * 4x4 px per bit, green = 1 / dark blue = 0: scene(4) sub(4) step(16). + */ + +#define SCREEN_W 320 +#define SCREEN_H 240 +#define FOV_DEG 60.0f +#define SWEEP_STEPS 2000 +#define SEP_DISTANCES 8 +#define SEP_GRID 4 +#define PLANE_DIV 32 +#define MARKER_Y 232 +#define MARKER_CELL 4 + +typedef struct { float near, far; } Preset; +static const Preset PRESETS[] = {{10, 12800}, {10, 1000}, {10, 150}, {1, 100}}; +#define PRESET_COUNT (sizeof(PRESETS) / sizeof(PRESETS[0])) + +enum { SCENE_SWEEP, SCENE_PLANE, SCENE_SEP, SCENE_COUNT }; +static const int SUB_COUNT[SCENE_COUNT] = {2, 4, 2}; +static const int STEP_COUNT[SCENE_COUNT] = {SWEEP_STEPS, 4, SEP_DISTANCES}; + +// initial state can be set at compile time (e.g. -DDT_INIT_SCENE=2) for scripted runs +#ifndef DT_INIT_SCENE +#define DT_INIT_SCENE 0 +#endif +#ifndef DT_INIT_SUB +#define DT_INIT_SUB 0 +#endif +#ifndef DT_INIT_STEP +#define DT_INIT_STEP 0 +#endif +#ifndef DT_INIT_PRESET +#define DT_INIT_PRESET 0 +#endif + +static struct { + int scene, sub, step, preset; + bool autoAdvance; +} st = {DT_INIT_SCENE, DT_INIT_SUB, DT_INIT_STEP, DT_INIT_PRESET, false}; + +static float tanHalfFov, aspect; + +// ---- pools (reset per frame; safe because every frame ends in rspq_wait) -- +#define VERT_POOL 4096 +#define MAT_POOL 64 +static T3DVertPacked *vertPool; +static T3DMat4FP *matPool; +static int vertUsed, matUsed; +static uint16_t packedNormal; + +static T3DVertPacked *vertAlloc(int count) { + int packed = (count + 1) / 2; + assertf(vertUsed + packed <= VERT_POOL / 2, "vertex pool exhausted"); + T3DVertPacked *p = &vertPool[vertUsed]; + vertUsed += packed; + return p; +} + +static T3DMat4FP *matAlloc(void) { + assertf(matUsed < MAT_POOL, "matrix pool exhausted"); + return &matPool[matUsed++]; +} + +static void setVert(T3DVertPacked *buf, int i, float x, float y, float z, uint32_t rgba) { + T3DVertPacked *p = &buf[i >> 1]; + int16_t px = (int16_t)lroundf(x), py = (int16_t)lroundf(y), pz = (int16_t)lroundf(z); + if (i & 1) { + p->posB[0] = px; p->posB[1] = py; p->posB[2] = pz; + p->rgbaB = rgba; p->normB = packedNormal; p->stB[0] = 0; p->stB[1] = 0; + } else { + p->posA[0] = px; p->posA[1] = py; p->posA[2] = pz; + p->rgbaA = rgba; p->normA = packedNormal; p->stA[0] = 0; p->stA[1] = 0; + } +} + +// quad in the XY plane at z=0, centred, half extents hx/hy (under `mat`) +static void drawQuadXY(float hx, float hy, uint32_t color, const T3DMat4FP *mat) { + T3DVertPacked *v = vertAlloc(4); + setVert(v, 0, -hx, -hy, 0, color); + setVert(v, 1, hx, -hy, 0, color); + setVert(v, 2, hx, hy, 0, color); + setVert(v, 3, -hx, hy, 0, color); + t3d_matrix_push(mat); + t3d_vert_load(v, 0, 4); + t3d_tri_draw(0, 1, 2); + t3d_tri_draw(0, 2, 3); + t3d_tri_sync(); + t3d_matrix_pop(1); +} + +// floor plane y=-h, x in [-hw, hw] (nx segments), z at zs[0..nz] (world coords, identity matrix) +static void drawFloorGrid(float h, float hw, const int32_t *zs, int nz, int nx, uint32_t color) { + assertf(2 * (nx + 1) <= T3D_VERTEX_CACHE_SIZE, "too many columns"); + T3DMat4FP *ident = matAlloc(); + t3d_mat4fp_identity(ident); + t3d_matrix_push(ident); + for (int j = 0; j < nz; ++j) { + int cols = nx + 1; + T3DVertPacked *v = vertAlloc(2 * cols); + for (int i = 0; i < cols; ++i) { + float x = -hw + 2.0f * hw * (float)i / (float)nx; + setVert(v, i, x, -h, (float)zs[j], color); + setVert(v, cols + i, x, -h, (float)zs[j + 1], color); + } + t3d_vert_load(v, 0, 2 * cols); + for (int i = 0; i < nx; ++i) { + t3d_tri_draw(i, i + 1, cols + i); + t3d_tri_draw(i + 1, cols + i + 1, cols + i); + } + t3d_tri_sync(); + } + t3d_matrix_pop(1); +} + +static void setMatSRT(T3DMat4FP *m, float sx, float sy, float sz, float rx, float tx, float ty, float tz) { + t3d_mat4fp_from_srt_euler(m, (float[3]){sx, sy, sz}, (float[3]){rx, 0, 0}, (float[3]){tx, ty, tz}); +} + +// ---- scenes --------------------------------------------------------------- + +static float sweepDistance(int step, float near, float far) { + // tiny3d's near clip currently sits at 2fn/(2f-n) (up to ~3.5% beyond near), start past it + float w0 = near * 1.05f, w1 = far * 0.99f; + return w0 * powf(w1 / w0, (float)step / (float)(SWEEP_STEPS - 1)); +} + +static void sceneSweep(float near, float far, char *info, size_t infoLen) { + float w = sweepDistance(st.step, near, far); + float cover = st.sub == 0 ? 0.8f : 2.5f; + float hy = w * tanHalfFov * cover, hx = hy * aspect; + T3DMat4FP *m = matAlloc(); + setMatSRT(m, hx / 1000.0f, hy / 1000.0f, 1.0f, 0, 0, 0, -w); + drawQuadXY(1000, 1000, 0xFFFFFFFF, m); + snprintf(info, infoLen, "w=%.7g cover=%.2f", w, cover); +} + +static void scenePlane(float near, float far, char *info, size_t infoLen) { + // h: fraction of the near-plane half height; the near edge of the plane + // must stay inside the frustum so nothing gets clipped + const float hFrac[4] = {0.8f, 0.5f, 0.3f, 0.95f}; + float z0f = near * 1.1f, z1f = far * 0.95f; + float h = roundf(z0f * tanHalfFov * hFrac[st.step]); + float hw = roundf(0.9f * z0f * tanHalfFov * aspect); + static int32_t zs[PLANE_DIV + 1]; + for (int j = 0; j <= PLANE_DIV; ++j) + zs[j] = -(int32_t)lroundf(z0f * powf(z1f / z0f, (float)j / (float)PLANE_DIV)); + int32_t zSingle[2] = {zs[0], zs[PLANE_DIV]}; + + const uint32_t RED = 0xFF0000FF, GREEN = 0x00FF00FF; + switch (st.sub) { + case 0: drawFloorGrid(h, hw, zSingle, 1, 1, RED); break; + case 1: drawFloorGrid(h, hw, zs, PLANE_DIV, PLANE_DIV, GREEN); break; + case 2: + drawFloorGrid(h, hw, zSingle, 1, 1, RED); + rdpq_change_other_modes_raw(SOM_ZMODE_MASK, SOM_ZMODE_DECAL); + drawFloorGrid(h, hw, zs, PLANE_DIV, PLANE_DIV, GREEN); + rdpq_change_other_modes_raw(SOM_ZMODE_MASK, 0); + break; + case 3: + drawFloorGrid(h, hw, zSingle, 1, 1, RED); + drawFloorGrid(h, hw, zs, PLANE_DIV, PLANE_DIV, GREEN); + break; + } + int n = snprintf(info, infoLen, "h=%g hw=%g div=%d zs=", h, hw, PLANE_DIV); + for (int j = 0; j <= PLANE_DIV && n < (int)infoLen; ++j) + n += snprintf(info + n, infoLen - n, "%ld%s", zs[j], j < PLANE_DIV ? "," : ""); +} + +static float sepGapFrac(int cell) { + // g/d from 1/8 down to ~1/19500, log-spaced over the 16 cells + return powf(2.0f, -(3.0f + 0.75f * (float)cell)); +} + +static void sceneSep(float near, float far, char *info, size_t infoLen) { + float d0 = near * 1.2f, d1 = far * 0.9f; + float d = d0 * powf(d1 / d0, (float)st.step / (float)(SEP_DISTANCES - 1)); + float tilt = st.sub == 1 ? T3D_DEG_TO_RAD(30.0f) : 0.0f; + const uint32_t RED = 0xFF0000FF, GREEN = 0x00FF00FF; + + for (int cy = 0; cy < SEP_GRID; ++cy) { + for (int cx = 0; cx < SEP_GRID; ++cx) { + int cell = cy * SEP_GRID + cx; + float g = d * sepGapFrac(cell); + // cell centre in NDC (y up), half size of a cell in NDC + float ncx = -1.0f + (2.0f * cx + 1.0f) / SEP_GRID; + float ncy = 1.0f - (2.0f * cy + 1.0f) / SEP_GRID; + float nh = 1.0f / SEP_GRID; + + // back quad: cell shrunk to 90%, at distance d + float db = d; + T3DMat4FP *mb = matAlloc(); + setMatSRT(mb, 1, 1, 1, tilt, ncx * db * tanHalfFov * aspect, ncy * db * tanHalfFov, -db); + drawQuadXY(nh * 0.9f * db * tanHalfFov * aspect, nh * 0.9f * db * tanHalfFov, RED, mb); + + // front quad: cell shrunk to 40%, at distance d - g + float df = d - g; + T3DMat4FP *mf = matAlloc(); + setMatSRT(mf, 1, 1, 1, tilt, ncx * df * tanHalfFov * aspect, ncy * df * tanHalfFov, -df); + drawQuadXY(nh * 0.4f * df * tanHalfFov * aspect, nh * 0.4f * df * tanHalfFov, GREEN, mf); + } + } + int n = snprintf(info, infoLen, "d=%.7g tiltDeg=%d grid=%d gapFrac=", d, st.sub == 1 ? 30 : 0, SEP_GRID); + for (int c = 0; c < SEP_GRID * SEP_GRID && n < (int)infoLen; ++c) + n += snprintf(info + n, infoLen - n, "%.6g%s", sepGapFrac(c), c < SEP_GRID * SEP_GRID - 1 ? "," : ""); +} + +// ---- state marker (colour buffer only, bottom row) -------------------------- +static void drawMarker(void) { + uint32_t bits = ((uint32_t)st.scene << 20) | ((uint32_t)st.sub << 16) | ((uint32_t)st.step & 0xFFFF); + for (int b = 0; b < 24; ++b) { + bool one = (bits >> (23 - b)) & 1; + rdpq_set_mode_fill(one ? RGBA32(0, 255, 0, 255) : RGBA32(0, 0, 128, 255)); + int x = b * MARKER_CELL; + rdpq_fill_rectangle(x, MARKER_Y, x + MARKER_CELL, MARKER_Y + MARKER_CELL); + } +} + +// ---- input ----------------------------------------------------------------- +static void clampState(void) { + if (st.scene < 0) st.scene = SCENE_COUNT - 1; + if (st.scene >= SCENE_COUNT) st.scene = 0; + if (st.sub < 0) st.sub = SUB_COUNT[st.scene] - 1; + if (st.sub >= SUB_COUNT[st.scene]) st.sub = 0; + if (st.step < 0) st.step = 0; + if (st.step >= STEP_COUNT[st.scene]) st.step = STEP_COUNT[st.scene] - 1; + if (st.preset < 0) st.preset = PRESET_COUNT - 1; + if (st.preset >= (int)PRESET_COUNT) st.preset = 0; +} + +static void handleInput(void) { + joypad_poll(); + joypad_buttons_t btn = joypad_get_buttons_pressed(JOYPAD_PORT_1); + if (btn.d_right) st.step += 1; + if (btn.d_left) st.step -= 1; + if (btn.d_up) st.step += 100; + if (btn.d_down) st.step -= 100; + if (btn.c_right) { st.scene += 1; st.sub = 0; st.step = 0; } + if (btn.c_left) { st.scene -= 1; st.sub = 0; st.step = 0; } + if (btn.a) st.sub += 1; + if (btn.b) st.sub -= 1; + if (btn.r) st.preset += 1; + if (btn.l) st.preset -= 1; + if (btn.z) st.step = 0; + if (btn.start) st.autoAdvance = !st.autoAdvance; + if (st.autoAdvance) { + if (st.step + 1 >= STEP_COUNT[st.scene]) st.autoAdvance = false; + else st.step += 1; + } + clampState(); +} + +int main(void) { + debug_init_isviewer(); + debug_init_usblog(); + + display_init(RESOLUTION_320x240, DEPTH_16_BPP, 3, GAMMA_NONE, FILTERS_DISABLED); + rdpq_init(); + joypad_init(); + t3d_init((T3DInitParams){}); + + vertPool = malloc_uncached(sizeof(T3DVertPacked) * (VERT_POOL / 2)); + matPool = malloc_uncached(sizeof(T3DMat4FP) * MAT_POOL); + packedNormal = t3d_vert_pack_normal(&(fm_vec3_t){{0, 0, 1}}); + + T3DViewport viewport = t3d_viewport_create(); + tanHalfFov = tanf(T3D_DEG_TO_RAD(FOV_DEG) * 0.5f); + aspect = (float)SCREEN_W / (float)SCREEN_H; + + const fm_vec3_t camPos = {{0, 0, 0}}; + const fm_vec3_t camTarget = {{0, 0, -1}}; + uint8_t colorAmbient[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + + static char info[1024]; + debugf("DT ready screen=%dx%d fovDeg=%g aspect=%.7g sweepSteps=%d presets=%d\n", + SCREEN_W, SCREEN_H, (double)FOV_DEG, (double)aspect, SWEEP_STEPS, (int)PRESET_COUNT); + + for (;;) { + handleInput(); + const Preset *p = &PRESETS[st.preset]; + + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(FOV_DEG), p->near, p->far); + t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0, 1, 0}}); + + vertUsed = 0; + matUsed = 0; + info[0] = 0; + + rdpq_attach(display_get(), display_get_zbuf()); + t3d_frame_start(); + t3d_viewport_attach(&viewport); + + rdpq_mode_combiner(RDPQ_COMBINER_SHADE); + t3d_screen_clear_color(RGBA32(0, 0, 0, 0xFF)); + t3d_screen_clear_depth(); + t3d_light_set_ambient(colorAmbient); + t3d_light_set_count(0); + t3d_state_set_drawflags(T3D_FLAG_SHADED | T3D_FLAG_DEPTH); + + switch (st.scene) { + case SCENE_SWEEP: sceneSweep(p->near, p->far, info, sizeof(info)); break; + case SCENE_PLANE: scenePlane(p->near, p->far, info, sizeof(info)); break; + case SCENE_SEP: sceneSep(p->near, p->far, info, sizeof(info)); break; + } + + drawMarker(); + // report while still attached: the frame is complete (rspq_wait) and the + // RDP's colour/depth image registers still point at this frame's buffers, + // so a host reading them on this line sees exactly the finished frame + rspq_wait(); + debugf("DT scene=%d sub=%d step=%d near=%g far=%g %s\n", + st.scene, st.sub, st.step, (double)p->near, (double)p->far, info); + rdpq_detach_show(); + } +} diff --git a/examples/98_depthtest/report.sh b/examples/98_depthtest/report.sh new file mode 100755 index 00000000..1e16746d --- /dev/null +++ b/examples/98_depthtest/report.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Build a self-contained depth report (tools/depth_report.html with all dumps embedded) +# and print its path. Open it directly in a browser, no server needed. +# examples/98_depthtest/report.sh [out.html] [dump.json ...] (default: all of data/*_p0.json) +set -euo pipefail +HERE="$(cd "$(dirname "$0")" && pwd)" +OUT="${1:-$HERE/report.html}"; shift || true +if [ $# -eq 0 ]; then set -- "$HERE"/data/tiny3d_noNR_p0.json "$HERE"/data/tiny3d_nrfix_p0.json "$HERE"/data/f3dex3_p0.json "$HERE"/data/f3dex3_zfrac{6,4,3,2,1,0}_p0.json; fi +python3 "$HERE/../../tools/depth_report_embed.py" "$OUT" "$@" diff --git a/examples/99_testscene/main.c b/examples/99_testscene/main.c index 3572f69c..485c3809 100644 --- a/examples/99_testscene/main.c +++ b/examples/99_testscene/main.c @@ -31,14 +31,9 @@ int main() //rdpq_debug_start(); //rdpq_debug_log(true); - bool testClip = false; - joypad_init(); t3d_init((T3DInitParams){}); T3DViewport viewport = t3d_viewport_create_buffered(FB_COUNT); - if(testClip) { - viewport.guardBandScale = 1; - } t3d_debug_print_init(); sprite_t *spriteLogo = sprite_load("rom:/logo.ia8.sprite"); @@ -49,8 +44,7 @@ int main() // Now allocate a fixed-point matrix, this is what t3d uses internally. T3DMat4FP* modelMatFP = malloc_uncached(sizeof(T3DMat4FP)); - fm_vec3_t camPos = {{2.9232f, 67.6248f, 61.1093f}}; - if(testClip)camPos = (fm_vec3_t){{2.9232f, 37.6248f, 31.1093f}}; + fm_vec3_t camPos = {{2.9232f, 67.6248f, 61.1093f}}; fm_vec3_t camTarget = {{0,0,0}}; fm_vec3_t camDir = {{0,0,1}}; @@ -95,6 +89,12 @@ int main() vertFxTime = fmaxf(vertFxTime - deltaTime, 0.0f); + if(btn.r) { + viewport.guardBandScale = 1; + camPos.v[1] -= 40; + camPos.v[2] -= 52; + } + { float camSpeed = deltaTime * 0.001f; float camRotSpeed = deltaTime * 0.00001f; @@ -181,7 +181,7 @@ int main() fm_mat4_scale(&modelMat, &(fm_vec3_t){{modelScale, modelScale, modelScale}}); t3d_mat4_to_fixed(modelMatFP, &modelMat); - t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 2.0f, 150.0f); + t3d_viewport_set_projection(&viewport, T3D_DEG_TO_RAD(85.0f), 2.0f, 300.0f); t3d_viewport_look_at(&viewport, &camPos, &camTarget, &(fm_vec3_t){{0,1,0}}); // ----------- DRAW ------------ // @@ -197,7 +197,7 @@ int main() t3d_screen_clear_color(RGBA32(0, 0, 0, 0xFF)); t3d_screen_clear_depth(); - t3d_fog_set_range(17.0f, 100.0f); + t3d_fog_set_range(22.0f, 200.0f); t3d_fog_set_enabled(true); t3d_light_set_ambient(colorAmbient); // one global ambient light, always active diff --git a/examples/99_testscene/rsp_profile.js b/examples/99_testscene/rsp_profile.js deleted file mode 100644 index 0a745cd5..00000000 --- a/examples/99_testscene/rsp_profile.js +++ /dev/null @@ -1,87 +0,0 @@ -const frames = 30; - -ares.setRenderer("angrylion"); - -ares.loadRom("t3d_99_testscene.z64"); -ares.resume(); - -ares.waitFrames(40); -ares.waitRspCommand("Screen Size"); -ares.rspProfileStart(); -ares.waitRspCommand("Screen Size", frames); - -const t = ares.rspProfile(); -const usPerFrame = c => c / frames / 62.5; // 62.5 MHz -> µs per game frame - -console.log(""); -console.log("RSP profile over " + frames + " game frames (lostRows: " + t.lostRows + ")"); -console.log("total: " + Math.round(t.totalCycles) + " cycles = " + - usPerFrame(t.totalCycles).toFixed(2) + " us/frame (commands " + - usPerFrame(t.commandCycles).toFixed(2) + ", rspq overhead " + - usPerFrame(t.overheadCycles).toFixed(2) + ")"); -console.log(""); -console.log("command".padEnd(30) + "count".padStart(8) + "avg cyc".padStart(10) + - "cyc/frame".padStart(12) + "us/frame".padStart(10) + "share".padStart(8)); - -const perfMap = {}; -for (const r of t.rows) -{ - if(r.overlay !== 'tiny3d') continue; - const name = r.overhead ? "rspq: " + r.overheadType - : (r.overlay ? r.overlay + "/" : "") + r.name; - - const usPF = usPerFrame(r.cycles); - perfMap[name] = usPF; - console.log(name.padEnd(30) + - String(r.count).padStart(8) + - r.avg.toFixed(1).padStart(10) + - String(Math.round(r.cycles / frames)).padStart(12) + - usPF.toFixed(2).padStart(10) + - ((r.cycles / t.totalCycles) * 100).toFixed(1).padStart(7) + "%"); -} - -// grouped summary for the vertex/triangle refactor work -const GROUPS = [ - { label: "triangles (Draw+Strip+Seq)", names: ["Tri Draw", "Tri Strip", "Tri Seq"] }, - { label: "vertices (Vert Load)", names: ["Vert Load"] }, -]; -console.log(""); -console.log("group".padEnd(30) + "count".padStart(8) + "avg cyc".padStart(10) + - "cyc/frame".padStart(12) + "us/frame".padStart(10) + "share".padStart(8)); -for (const g of GROUPS) { - let count = 0, cycles = 0; - for (const r of t.rows) { - if (!r.overhead && r.overlay === "tiny3d" && g.names.includes(r.name)) { - count += r.count; cycles += r.cycles; - } - } - console.log(g.label.padEnd(30) + - String(count).padStart(8) + - (count ? (cycles / count) : 0).toFixed(1).padStart(10) + - String(Math.round(cycles / frames)).padStart(12) + - usPerFrame(cycles).toFixed(1).padStart(10) + - ((cycles / t.totalCycles) * 100).toFixed(1).padStart(7) + "%"); -} - -//const shot = ares.screenshot(); -//shot.save("rsp_profile.png"); - -console.log("========================================="); -//console.log(perfMap); -const lastPerf = {"tiny3d/Tri Strip":3608.464,"tiny3d/Vert Load":2445.296,"tiny3d/Tri Seq":979.744,"tiny3d/Tri Draw":47.024,"tiny3d/Matrix Stack":17.12,"tiny3d/Proj Set":0.816,"tiny3d/Set Word":0.56,"tiny3d/Light Set":0.4341333333333333,"tiny3d/Screen Size":0.336,"tiny3d/Fog State":0.32,"tiny3d/Draw Flags":0.24}; - -// now compare and check if something got slower: -let foundWorse = false; -for (const [name, usPF] of Object.entries(perfMap)) { - const last = lastPerf[name]; - if (last === undefined) { - console.log("new: " + name + " " + usPF.toFixed(2) + " us/frame"); - } else if (usPF > last) { - console.log("slower: " + name + " " + usPF.toFixed(2) + " us/frame (was " + last.toFixed(2) + ")"); - foundWorse = true; - } else if (usPF < last) { - console.log("faster: " + name + " " + usPF.toFixed(2) + " us/frame (was " + last.toFixed(2) + ")"); - } -} - -if(!foundWorse)console.log("Performance OK"); diff --git a/src/t3d/rsp/clipping.rspl b/src/t3d/rsp/clipping.rspl index 294191e9..df5f282a 100644 --- a/src/t3d/rsp/clipping.rspl +++ b/src/t3d/rsp/clipping.rspl @@ -1,23 +1,22 @@ -// force specific order, 'clipTriangle' must be first -function clipTriangle(u32<$t0> arraySize, u32<$a0> ptrVertA, u32<$a1> ptrVertB, u32<$a2> ptrVertC); -function triToScreenSpace(u32<$s6> ptr); +// CLIP_BUFFER_TMP and CLIP_BUFFER_RESULT differ only in this bit (checked by a static_assert in t3d.c) +#define CLIP_BUFFER_XOR 0x100 +#define CLIP_BUFFER_SIZE 252 // 7 * TRI_SIZE +// polygons up to this size (4 vertices) lie above the second RDP command slot (static_assert in t3d.c) +#define CLIP_FAN_ASYNC_MAX_SIZE 145 -macro returnBack() { - u16 tmp = load(CLIP_RA); - // restore old DMEM address for indices, this is expected to persist for tri-strips - s16<$s4> oldDMEM = load(RSPQ_SCRATCH_MEM, 18); - goto tmp; -} +// force specific order, 'clipTriangle' must be first +function clipTriangle(u32<$t0> arraySize, u32<$a0> ptrVertA, u32<$a1> ptrVertB, u32<$a2> ptrVertC, u32<$t4> clipMask); /** * Calculates the intersection point against a clipping plane. * ---- Output ---- * @param resPosUV new point / UV (in .xyzw / .XY) * @param resColor new color (in .xyzw) - * @param newClipCode new clip-code for the interpolated-point + * @param newClipCode new clip-code for the interpolated-point (only if 'remainingPlanes' != 0) * * ---- Input ---- - * @param planePtr DMEM address for the plane normals + * @param planeNorm current plane normal, already shifted & scaled (in .xyzw and .XYZW) + * @param remainingPlanes planes still to be processed after this one, if zero no clip-code is computed * * @param posBase base point inside the frustum * @param colorBase base color inside the frustum @@ -26,7 +25,7 @@ macro returnBack() { */ macro intersection( vec32 resPosUV, vec16 resColor, u32 newClipCode, - u32 planePtr, + vec32 planeNorm, u32 remainingPlanes, vec32 posBase, vec16 colorBase, vec32 pos, vec16 color ) { @@ -35,37 +34,22 @@ macro intersection( vec32 vpos; vec16 colorDiff; - // load and transform current clipping plane - vec32 planeNorm:sint = load_vec_s8(planePtr); - // contains last clip-code for current plane // when set, switch points for interpolation to have consistent results // if not done, it will result in tiny sub-pixel gaps between edges if(newClipCode) { - planeNorm:sint.XYZW = planeNorm:sint.xyzw; - planeNorm:sfract = 0; - posUVDiff = posBase - pos; vpos = pos; vpos.XYZW = posBase.xyzw; - planeNorm >>= 8; - colorDiff = colorBase - color; } else { - planeNorm:sint.XYZW = planeNorm:sint.xyzw; - planeNorm:sfract = 0; - posUVDiff = pos - posBase; vpos = posBase; vpos.XYZW = pos.xyzw; - planeNorm >>= 8; - colorDiff = color - colorBase; } - planeNorm *= normScaleWInv:ufract; - vec32 dot = dotXYZW(vpos, planeNorm); vec32 fac = dot - dot.X; @@ -96,11 +80,16 @@ macro intersection( } } - vec32 clipBase = resPosUV * normScaleWInv:ufract; - vec32 clipPlaneW = guardBandScale * resPosUV.wwwwWWWW; + // the clip-code is only consumed by later planes, skip it on the last one + if(remainingPlanes) + { + // x/y are pre-divided by the guard-band factor (see T3DCmd_VertLoad), so W is the bound + vec32 clipBase = resPosUV * normScaleWInv:ufract; - newClipCode = clip(clipBase, clipPlaneW.w); - newClipCode = packClipCode(newClipCode); + clipBase.z = clipBase.w; + newClipCode = clip(clipBase, resPosUV.w); + newClipCode = packClipCode(newClipCode); + } } /** @@ -112,20 +101,32 @@ macro intersection( * @param ptrVertA vertex 0 of the tri. to be clipped * @param ptrVertB vertex 1 * @param ptrVertC vertex 2 + * @param clipMask OR of the 3 clip-codes (bits 8-12), as computed by the triangle code */ @Align(8) -function clipTriangle(u32<$t0> arraySize, u16<$a0> ptrVertA, u16<$a1> ptrVertB, u16<$a2> ptrVertC) +function clipTriangle(u32<$t0> arraySize, u16<$a0> ptrVertA, u16<$a1> ptrVertB, u16<$a2> ptrVertC, u32<$t4> clipMask) { u8<$v0> faceCull; // stays across triangles, no need to load here // u8<$sp> _unused; arraySize = TRI_SIZE_3; // 3-verts by default - // The loop streams vertices in and out at the same time. - // To avoid corruption, alternate between two buffers. - u32 ptrBuff0 = CLIP_BUFFER_RESULT; - u32 ptrBuff1 = CLIP_BUFFER_TMP; - u32 ptrWrite = CLIP_BUFFER_TMP; + // Planes to process: bit 0/1 = -x/-y, bit 3/4 = +x/+y, as flagged by the vertex loop. + // Bit 2 (camera plane, w < 0) is never set: the four side planes meet at w = 0 and remove + // every point behind the camera on their own, the third plane is always skipped. + // Planes no vertex crosses are skipped, the polygon would pass through unchanged. + clipMask >>= 8; + + // The buffers are filled from their END downwards, so we can double buffer RDP commands with <= 4 vertices. + + u32 parity = 0x96696996; // mask of odd-even flags + parity >>= clipMask; + parity &= 1; + parity <<= 8; + u32 ptrBuff1 = CLIP_BUFFER_RESULT; + ptrBuff1 += CLIP_BUFFER_SIZE; // end of the buffer + ptrBuff1 -= parity; // odd: start in CLIP_BUFFER_TMP, even: in CLIP_BUFFER_RESULT + u32 ptrWrite = ptrBuff1; // copy original verts into the first buffer (@TODO: avoid this somehow?) { @@ -138,7 +139,7 @@ function clipTriangle(u32<$t0> arraySize, u16<$a0> ptrVertA, u16<$a1> ptrVertB, s32 planeIdx = 1; { - // backup old tile-index whicg is stored in the clip-code + // backup old tile-index which is stored in the clip-code u8 oldClip = load(ptrVertA, VTX_ATTR_CLIPFLAGS); store(oldClip, RSPQ_SCRATCH_MEM, 20); } @@ -149,115 +150,198 @@ function clipTriangle(u32<$t0> arraySize, u16<$a0> ptrVertA, u16<$a1> ptrVertB, normScaleWInv.w = 0xFFFF; normScaleWInv.W = 0xFFFF; - vec16 guardBandScale = load(CLIPPING_PLANES).xy; - guardBandScale = guardBandScale.y; + // UVs are lerped as biased u16 values (ST ^ 0x8000) in the FRACTION lanes X/Y with the int lanes zero. + // With the s16 texcoords in the int lanes the 32-bit subtract saturates once two vertices are more + // than 1024 texels apart (vsub clamps the int half), which sheared textures on clipped triangles. + vec16 uvIntMask = VZERO - 1; + uvIntMask.XYZW = VZERO.xyzw; + vec16 uvBias = VZERO; + uvBias.X = 0x8000; + uvBias.Y = 0x8000; // check 5 planes, we shift instead of incr. for direct clip-code checks // the z-far plane is ignored loop { - u32 ptrLast = ptrWrite - TRI_SIZE; - - vec16 lastColor = load_vec_u8(ptrLast, VTX_ATTR_RGBA); - vec32 lastPosUV = load(ptrLast, VTX_ATTR_CLIPPOSi).xyzw; - lastPosUV:sint.XY = load(ptrLast, VTX_ATTR_ST).xy; - u8 lastClipCode = load(ptrLast, VTX_ATTR_CLIPFLAGS); - - undef ptrLast; - - swap(ptrBuff0, ptrBuff1); - - ptrWrite = ptrBuff1; - u32 ptrRead = ptrBuff0; - u32 ptrReadEnd = ptrBuff0 + arraySize; - - // check all clipped points so far - loop + u32 planeActive = clipMask & planeIdx; + if(planeActive) { - vec32 currentPosUV = load(ptrRead, VTX_ATTR_CLIPPOSi).xyzw; - currentPosUV:sint.XY = load(ptrRead, VTX_ATTR_ST).xy; - vec16 currentColor = load_vec_u8(ptrRead, VTX_ATTR_RGBA); + clipMask ^= planeIdx; // planes remaining after this one - u8 clipCode = load(ptrRead, VTX_ATTR_CLIPFLAGS); - - // check if the current and last point are contained in the clip-plane - u8 exclIntersect = clipCode ^ lastClipCode; - u8 isInsideCurr = ~clipCode; - exclIntersect &= planeIdx; - isInsideCurr &= planeIdx; + // load and transform current clipping plane (once per plane) + vec32 planeNorm:sint = load_vec_s8(planePtr); + planeNorm:sint.XYZW = planeNorm:sint.xyzw; + planeNorm:sfract = 0; + planeNorm >>= 8; + planeNorm *= normScaleWInv:ufract; - if(exclIntersect) - { - lastClipCode &= planeIdx; - intersection( - lastPosUV, lastColor, lastClipCode, // output - planePtr, - lastPosUV, lastColor, currentPosUV, currentColor); + u32 ptrLast = ptrWrite; // last emitted vertex (lowest address) - emitClippedTri(ptrWrite, lastClipCode, lastPosUV, lastColor); - } + vec16 lastColor = load_vec_u8(ptrLast, VTX_ATTR_RGBA); + vec32 lastPosUV = load(ptrLast, VTX_ATTR_CLIPPOSi).xyzw; + lastPosUV:sfract.XY = load(ptrLast, VTX_ATTR_ST).xy; + lastPosUV:sint &= uvIntMask; // UV int lanes must be zero (biased u16 lerp, see above) + lastPosUV:sfract ^= uvBias; + u8 lastClipCode = load(ptrLast, VTX_ATTR_CLIPFLAGS); - lastPosUV = currentPosUV; - lastClipCode = clipCode; - lastColor = currentColor; + undef ptrLast; - if(isInsideCurr) { - emitClippedTri(ptrWrite, lastClipCode, lastPosUV, lastColor); - } + ptrBuff1 ^= CLIP_BUFFER_XOR; // ping-pong between the two buffers - ptrRead += TRI_SIZE; + ptrWrite = ptrBuff1; + u32 ptrRead = ptrBuff1 ^ CLIP_BUFFER_XOR; + u32 ptrReadEnd = ptrRead - arraySize; - } while(ptrRead != ptrReadEnd) + // check all clipped points so far + loop + { + ptrRead -= TRI_SIZE; + vec32 currentPosUV = load(ptrRead, VTX_ATTR_CLIPPOSi).xyzw; + currentPosUV:sfract.XY = load(ptrRead, VTX_ATTR_ST).xy; + currentPosUV:sint &= uvIntMask; + currentPosUV:sfract ^= uvBias; + vec16 currentColor = load_vec_u8(ptrRead, VTX_ATTR_RGBA); + + u8 clipCode = load(ptrRead, VTX_ATTR_CLIPFLAGS); + + // check if the current and last point are contained in the clip-plane + u8 exclIntersect = clipCode ^ lastClipCode; + u8 isInsideCurr = ~clipCode; + exclIntersect &= planeIdx; + isInsideCurr &= planeIdx; + + if(exclIntersect) + { + lastClipCode &= planeIdx; + intersection( + lastPosUV, lastColor, lastClipCode, // output + planeNorm, clipMask, + lastPosUV, lastColor, currentPosUV, currentColor); + + emitClippedTri(ptrWrite, lastClipCode, lastPosUV, lastColor); + } + + lastPosUV = currentPosUV; + lastClipCode = clipCode; + lastColor = currentColor; + + if(isInsideCurr) { + emitClippedTri(ptrWrite, lastClipCode, lastPosUV, lastColor); + } + + } while(ptrRead != ptrReadEnd) + + arraySize = ptrBuff1 - ptrWrite; + if(arraySize == 0)goto CLIP_RETURN; + } planeIdx <<= 1; - arraySize = ptrWrite - ptrBuff1; - - if(arraySize == 0)goto CLIP_RETURN; - planePtr += 0x04; } while(planeIdx != 0b100'000) CLIP_END: - u32<$s6> ptrVertIn = CLIP_BUFFER_RESULT; - u32<$s5> ptrVertInEnd = ptrVertIn + arraySize; - ptrVertInEnd -= TRI_SIZE_2; + // Convert the whole polygon back into screen-space, two vertices at a time (lanes xyzw / XYZW). + // Same math as T3DCmd_VertLoad + { + u32 ptrConvA = ptrWrite; // lowest vertex of the final polygon - // convert the base-vertex and the one from the first iteration - // for each triangle-fan part we then only need to convert one new vert - @Relative triToScreenSpace(ptrVertIn); - ptrVertIn += TRI_SIZE_2; - @Relative triToScreenSpace(ptrVertIn); + loop + { + u16 oldClipFlag = load(RSPQ_SCRATCH_MEM, 20); + u32 ptrConvB = ptrConvA + TRI_SIZE; + if(ptrConvB == ptrBuff1) { + ptrConvB = ptrConvA; // odd vertex count: convert the last vertex twice (writes the same values) + } + + vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; // s16.16 + vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + + // write dummy clip-codes to avoid re-clipping + // we must set the 5 LSBs (clip codes), but preserve the 3 MSBs (tile index) + // the reject code (0xFF = never rejected) sits in the second byte + oldClipFlag = oldClipFlag & ((0b111'00000) << 8); + oldClipFlag |= 0xFF; + + vec32 posClip = load(ptrConvA, VTX_ATTR_CLIPPOSi).xyzw; + posClip.XYZW = load(ptrConvB, VTX_ATTR_CLIPPOSi).xyzw; + + vec32 invWRaw; + invWRaw.w = invert_half(posClip).w; + invWRaw.W = invert_half(posClip).W; + + // one round of NR + vec32 invW; + invW:sfract = posClip * invWRaw.wwwwWWWW; // still x0.5 due to invert + vec16 nrD = normScaleW:ufract - invW:ufract.wwwwWWWW; // d = 1 - t, as 0xFFFF - t + invW = invWRaw + invWRaw; // 2*y0 (lanes w/W) + invW *= nrD:ufract.zzzzZZZZ; // -> 0.5/w (lane z = 0xFFFF, x/y hold 1/guard-band) + undef nrD; + + store(invW.w, ptrConvA, VTX_ATTR_INVWi); + store(invW.W, ptrConvB, VTX_ATTR_INVWi); + + // perspective division + invW = posClip * invW.wwwwWWWW; + posClip = invW * screenSize; + posClip:sint = screenOffset:sint +* 1; + undef invW; + + store(posClip:sint.xy, ptrConvA, VTX_ATTR_XY); + store(posClip:sint.z, ptrConvA, VTX_ATTR_Z); + store(oldClipFlag, ptrConvA, VTX_ATTR_CLIPFLAGS); + + store(posClip:sint.XY, ptrConvB, VTX_ATTR_XY); + store(posClip:sint.Z, ptrConvB, VTX_ATTR_Z); + store(oldClipFlag, ptrConvB, VTX_ATTR_CLIPFLAGS); + + ptrConvA += TRI_SIZE_2; + } while(ptrConvA < ptrBuff1) + } + + // draw clipped triangles as a triangle-fan around vertex 0 (the highest slot). + // With at most 4 vertices the polygon is above the second RDP command slot, so we can double-bufffer still + u32<$s4> ptrVert0 = ptrBuff1 - TRI_SIZE; + u32<$s6> ptrVertIn = ptrVert0; + u32<$s5> ptrVertInEnd = ptrWrite + TRI_SIZE; // second to last vertex + s32<$s0> fanWait = arraySize - CLIP_FAN_ASYNC_MAX_SIZE; // negative: at most 4 vertices - // draw clipped triangles as a triangle-fan loop { - ptrVertIn += TRI_SIZE_2; - @Relative triToScreenSpace(ptrVertIn); // Note: this moves 'ptrVertIn' back by TRI_SIZE + ptrVertIn -= TRI_SIZE; - ptrVertA = CLIP_BUFFER_RESULT; + ptrVertA = ptrVert0; ptrVertB = ptrVertIn; - ptrVertC = ptrVertIn + TRI_SIZE; + ptrVertC = ptrVertIn - TRI_SIZE; #ifdef DRAW_TRIS RDPQ_Triangle_Send_Async(ptrVertA, ptrVertB, ptrVertC, faceCull); - RDPQ_Triangle_Send_End(); + if(fanWait >= 0) { + RDPQ_Triangle_Send_End(); + } RDPQ_Triangle_Clip: #endif } while(ptrVertIn != ptrVertInEnd) + undef ptrVert0; // $s4 is reused for the restored DMEM address CLIP_RETURN: - returnBack(); + + u16 tmp = load(CLIP_RA); + // restore old DMEM address for indices, this is expected to persist for tri-strips + s16<$s4> oldDMEM = load(RSPQ_SCRATCH_MEM, 18); + goto tmp; } /** - * Copies a vertex, only includes data relevant for clipping. + * Copies a vertex, only includes data relevant for clipping (buffer filled downwards). * @param ptrDst DMEM address to copy to * @param ptrSrc DMEM address to copy from */ macro copyClippingVertex(u32 ptrDst, u32 ptrSrc) { + ptrDst -= TRI_SIZE; vec16 tmp1 = load(ptrSrc, 0x00).xyzw; vec16 tmp2 = load(ptrSrc, 0x08).xyzw; vec16 tmp3 = load(ptrSrc, 0x10).xyzw; @@ -267,13 +351,11 @@ macro copyClippingVertex(u32 ptrDst, u32 ptrSrc) store(tmp2.xyzw, ptrDst, 0x08); store(tmp3.xyzw, ptrDst, 0x10); store(tmp4.xyzw, ptrDst, 0x18); - - ptrDst += TRI_SIZE; } /** * Emits a clipped triangle into the current clipping-buffer. - * Note: this advances the buffer-pointer by TRI_SIZE. + * Note: buffers are filled downwards, this moves the pointer back by TRI_SIZE first. * * @param ptrWrite destination buffer * @param lastClipCode CC to save @@ -282,51 +364,15 @@ macro copyClippingVertex(u32 ptrDst, u32 ptrSrc) */ macro emitClippedTri(u32 ptrWrite, u8 lastClipCode, vec32 lastPosUV, vec16 lastColor) { + ptrWrite -= TRI_SIZE; @Barrier("uv") store_vec_u8(lastColor, ptrWrite, VTX_ATTR_RGBA); - @Barrier("uv") store(lastPosUV:sint.XY, ptrWrite, VTX_ATTR_ST); + vec16 stOut = lastPosUV:sfract ^ uvBias; // back to s16 + @Barrier("uv") store(stOut.XY, ptrWrite, VTX_ATTR_ST); store(lastClipCode:u8, ptrWrite, VTX_ATTR_CLIPFLAGS); store(lastPosUV.xyzw, ptrWrite, VTX_ATTR_CLIPPOSi); - ptrWrite += TRI_SIZE; -} - -/** - * Converts a triangle generated from clipping back into screen-space. - * @param ptr vertex to be converted - */ -function triToScreenSpace(u32<$s6> ptr) -{ - // Note: these values need to be loaded each time, as RDPQ_Triangle wipes most regs - vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzw; - screenSize:sfract = 0; - screenSize >>= 8; - - vec16 vecOne = 1; - - // write dummy clip-codes to avoid re-clipping - // we must set the 5 LSBs (clip codes), but preserve the 3 MSBs (tile index) - u16<$t0> oldClipFlag = load(RSPQ_SCRATCH_MEM, 20); - oldClipFlag = oldClipFlag & ((0b111'00000) << 8); - oldClipFlag |= 0xFF; - - vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzw; - - vec32 invW; - vec32 posClip = load(ptr, VTX_ATTR_CLIPPOSi).xyzw; - invW.w = invert_half(posClip).w; - store(invW.w, ptr, VTX_ATTR_INVWi); - - posClip *= invW.w; - posClip *= screenSize; - - posClip:sint = screenOffset:sint +* 1; - - @Barrier("cc") store(posClip:sint.xyzw, ptr, VTX_ATTR_XY); - @Barrier("cc") store(oldClipFlag, ptr, VTX_ATTR_CLIPFLAGS); - - ptr -= TRI_SIZE; } // insert dummy commands to make the data section match command<0> Cmd_DummyStart(u32 vert0, u32 ptrVertB) {} -command<12> Cmd_DummyEnd() {} \ No newline at end of file +command<12> Cmd_DummyEnd() {} diff --git a/src/t3d/rsp/rsp_tiny3d.S b/src/t3d/rsp/rsp_tiny3d.S index ca632eb8..11ee7299 100644 --- a/src/t3d/rsp/rsp_tiny3d.S +++ b/src/t3d/rsp/rsp_tiny3d.S @@ -23,7 +23,7 @@ #define RDPQ_TRIANGLE_VTX3_DMEM 2,v1 #define TRI_SIZE 36 #define TRI_SIZE_2 72 -#define TRI_SIZE_3 108 +#define TRI_SIZE_3 108 #define RDP_CMD_MAX_SIZE 176 #define LIGHT_SIZE 16 #define MATRIX_SIZE 0x40 @@ -109,7 +109,7 @@ .data RSPQ_BeginOverlayHeader RSPQ_DefineCommand T3DCmd_TriDraw, 8 - RSPQ_DefineCommand T3DCmd_SetScreenSize, 16 + RSPQ_DefineCommand T3DCmd_SetScreenSize, 24 RSPQ_DefineCommand T3DCmd_MatrixStack, 8 RSPQ_DefineCommand T3DCmd_SetWord, 8 RSPQ_DefineCommand T3DCmd_VertLoad, 12 @@ -134,13 +134,15 @@ .align 3 MATRIX_NORMAL: .ds.b 24 .align 1 - FOG_SCALE_OFFSET: .half 0, 0, 32767, 0 - .align 4 - SCREEN_SCALE_OFFSET: .half 0, 0, 0, 0, 0, 0, 16383, 255 + VERT_CONSTS: .half -32768, -32768, 0, -32768, -32513, 32767, 0, 0 .align 4 NORMAL_MASK_SHIFT: .half 63488, 2016, 31, 0, 1, 32, 2048, 0 .align 3 - CLIPPING_PLANES: .byte 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, -1, 0, 1, 0, -1 + CLIPPING_PLANES: .byte 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1, 0, 1, 0, -1 + .align 3 + SCREEN_SCALE: .half 0, 0, 0, 0, 0, 0, 0, 0 + .align 1 + SCREEN_OFFSET: .half 0, 0, 16383, -32513 .align 1 RDPQ_TRI_BUFF_OFFSET: .half 0 .align 1 @@ -156,7 +158,7 @@ .align 2 SEGMENT_TABLE: .word 0, 0, 0, 0, 0, 0, 0, 0 .align 2 - COLOR_AMBIENT: .word 0xFFFFFFFF, 0xFFFFFFFF + COLOR_AMBIENT: .word 4294967295, 4294967295 .align 2 #if RSPQ_PROFILE LIGHT_DIR_COLOR: .ds.b 32 @@ -191,9 +193,9 @@ CLIP_BUFFER_TMP: .ds.b 252 .align 4 #if RSPQ_PROFILE - CLIP_BUFFER_RESULT: .ds.b 272 + CLIP_BUFFER_RESULT: .ds.b 236 #else - CLIP_BUFFER_RESULT: .ds.b 288 + CLIP_BUFFER_RESULT: .ds.b 252 #endif TEMP_STATE_MEM_END: @@ -210,325 +212,324 @@ CLIPPING_CODE_TARGET: j DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 addiu $t0, $t0, -1 T3DCmd_VertLoad: - srl $s4, $a2, 16 ## L:331 | ^ | u32<$s4> prt3d = addressInOut >> 16; - srl $s6, $a1, 24 ## L:278 | 2 | u32 segment = addrIn >> 24; - andi $t0, $a0, 65535 ## L:333 | 3 | u32<$t0> copySize = bufferSize & 0xFFFF; - lw $s6, %lo(SEGMENT_TABLE)($s6) ## L:279 | 4 | segment = load(segment, SEGMENT_TABLE); - addu $s7, $s4, $t0 ## L:334 | 5 | u32 ptr3dEnd = prt3d + copySize; - addiu $t0, $t0, -1 ## L:338 | 6 | dma_in_async(prt3d, dmaAddrRDRAM, copySize); - or $t2, $zero, $zero ## L:338 | 7 | dma_in_async(prt3d, dmaAddrRDRAM, copySize); - jal DMAExec ## L:338 | 8 | dma_in_async(prt3d, dmaAddrRDRAM, copySize); ## Args: $t0, $t1, $s0, $s4, $t2 - addu $s0, $a1, $s6 ## L:280 | *10 | addrOut = addrIn + segment; - ori $s6, $zero, %lo(MATRIX_NORMAL) ## L:270 | 11 | u16 address = MATRIX_NORMAL; - ldv $v19, 0, 8, $s6 ## L:272 | 12 | mat1 = load(address, 0x08).xyzwxyzw; - ldv $v18, 0, 16, $s6 ## L:273 | 13 | mat2 = load(address, 0x10).xyzwxyzw; - ldv $v19, 8, 8, $s6 ## L:272 | 14 | mat1 = load(address, 0x08).xyzwxyzw; - ldv $v20, 0, 0, $s6 ## L:271 | 15 | mat0 = load(address, 0x00).xyzwxyzw; - ldv $v20, 8, 0, $s6 ## L:271 | 16 | mat0 = load(address, 0x00).xyzwxyzw; - jal loadCurrentMVPMat ## L:345 | 17 | loadCurrentMVPMat(mat0, mat1, mat2, mat3); ## Args: $v27, $v25, $v23, $v21 - ldv $v18, 8, 16, $s6 ## L:273 | *19 | mat2 = load(address, 0x10).xyzwxyzw; - ori $at, $zero, %lo(NORMAL_MASK_SHIFT) ## L:347 | 20 | vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; - ldv $v16, 0, 8, $at ## L:348 | 21 | vec16 normShift = load(NORMAL_MASK_SHIFT, 0x08).xyzwxyzw; - ldv $v17, 0, 0, $at ## L:347 | 22 | vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; - ldv $v17, 8, 0, $at ## L:347 | 23 | vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; - ldv $v16, 8, 8, $at ## L:348 | 24 | vec16 normShift = load(NORMAL_MASK_SHIFT, 0x08).xyzwxyzw; - ori $at, $zero, %lo(CLIPPING_PLANES) ## L:350 | 25 | vec16 guardBandScale = load(CLIPPING_PLANES).xy; - llv $v15, 0, 0, $at ## L:350 | 26 | vec16 guardBandScale = load(CLIPPING_PLANES).xy; - ori $at, $zero, %lo(SCREEN_SCALE_OFFSET) ## L:353 | 27 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ldv $v12, 0, 8, $at ## L:357 | 28 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - andi $s6, $a2, 65535 ## L:363 | 29 | u32 ptrBuffA = addressInOut & 0xFFFF; - addiu $s5, $s6, 65500 ## L:364 | 30 | u32 ptrBuffB = ptrBuffA - 36; - lbu $s2, %lo(ACTIVE_LIGHT_SIZE + 0) ## L:368 | 31 | u8 ptrLightEnd = load(ACTIVE_LIGHT_SIZE); - ldv $v12, 8, 8, $at ## L:357 | 32 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - ldv $v13, 0, 0, $at ## L:353 | 33 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ldv $v13, 8, 0, $at ## L:353 | 34 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ori $at, $zero, %lo(FOG_SCALE_OFFSET) ## L:358 | 35 | vec16 fogScaleOffset = load(FOG_SCALE_OFFSET).xyzw; - vor $v15, $v00, $v15.e1 ## L:351 | ^ | guardBandScale = guardBandScale.y; - ldv $v11, 0, 0, $at ## L:358 | 36 | vec16 fogScaleOffset = load(FOG_SCALE_OFFSET).xyzw; - vmudl $v14, $v00, $v31.e7 ## L:355 | ^ | screenSize >>= 4; - lbu $k0, %lo(TRI_COMMAND + 0) ## L:384 | 37 | u8 isUnlit = load(TRI_COMMAND); - lbu $s0, %lo(CLIP_CODE_ORG_ADDR + 0) ## L:388 | 38 | u8<$s0> baseTileMask = load(CLIP_CODE_ORG_ADDR); - vmadm $v13, $v13, $v31.e7 ## L:355 | ^ | screenSize >>= 4; - ori $at, $zero, %lo(NORM_SCALE_W) ## L:361 | 39 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - vmadn $v14, $v00, $v00 ## L:355 | ^ | screenSize >>= 4; - ldv $v10, 0, 0, $at ## L:361 | 40 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - ldv $v10, 8, 0, $at ## L:361 | 41 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - ori $at, $zero, %lo(UV_GEN_PARAMS) ## L:373 | 42 | uvGenArgs.XYZW = load(UV_GEN_PARAMS).xyzw; - ldv $v09, 8, 0, $at ## L:373 | 43 | uvGenArgs.XYZW = load(UV_GEN_PARAMS).xyzw; - addiu $s6, $s6, 65464 ## L:379 | 44 | ptrBuffA -= 72; - vmov $v11.e6, $v11.e2 ## L:359 | ^ | fogScaleOffset.Z = fogScaleOffset.z; - ori $at, $zero, %lo(SCREEN_UVGEN_SCALE) ## L:374 | 45 | uvGenArgs.W = load(SCREEN_UVGEN_SCALE).x; - lbu $s1, %lo(FOG_STORE_OFFSET + 0) ## L:378 | 46 | u8 fogStoreOffset = load(FOG_STORE_OFFSET); - addiu $s2, $s2, %lo(LIGHT_DIR_COLOR) ## L:369 | 47 | ptrLightEnd += LIGHT_DIR_COLOR; - lsv $v09, 14, 0, $at ## L:374 | 48 | uvGenArgs.W = load(SCREEN_UVGEN_SCALE).x; - ori $at, $zero, %lo(UV_GEN_PARAMS) ## L:375 | 49 | uvGenArgs.xy = load(UV_GEN_PARAMS).xy; - llv $v09, 0, 0, $at ## L:375 | 50 | uvGenArgs.xy = load(UV_GEN_PARAMS).xy; - jal DMAWaitIdle ## L:392 | 51 | dma_await(); - llv $v09, 4, 0, $at ## L:376 | *53 | uvGenArgs.zw = load(UV_GEN_PARAMS).xy; - lqv $v08, 0, 0, $s4 ## L:395 | 54 | vec16 pos = load(prt3d, 0x00); - vand $v07, $v17, $v08.h3 ## L:396 | ***58 | vec16 norm = normMask & pos.wwwwWWWW; - vmudn $v07, $v07, $v16.v ## L:397 | ***62 | norm *= normShift; + ## hot-path cycles: 141 + srl $s6, $a1, 24 ## L:291 | ^ | u32 segment = addrIn >> 24; + srl $s4, $a2, 16 ## L:347 | 2 | u32<$s4> prt3d = addressInOut >> 16; + or $t2, $zero, $zero ## L:354 | 3 | dma_in_async(prt3d, dmaAddrRDRAM, copySize); + lw $s6, %lo(SEGMENT_TABLE)($s6) ## L:292 | 4 | segment = load(segment, SEGMENT_TABLE); + andi $t0, $a0, 65535 ## L:349 | 5 | u32<$t0> copySize = bufferSize & 0xFFFF; + addu $s7, $s4, $t0 ## L:350 | 6 | u32 ptr3dEnd = prt3d + copySize; + addiu $t0, $t0, -1 ## L:354 | 7 | dma_in_async(prt3d, dmaAddrRDRAM, copySize); + jal DMAExec ## L:354 | 8 | dma_in_async(prt3d, dmaAddrRDRAM, copySize); ## Args: $t0, $t1, $s0, $s4, $t2 + addu $s0, $a1, $s6 ## L:293 | 9 | addrOut = addrIn + segment; + ori $s6, $zero, %lo(MATRIX_NORMAL) ## L:283 | 10 | u16 address = MATRIX_NORMAL; + ldv $v19, 0, 8, $s6 ## L:285 | 11 | mat1 = load(address, 0x08).xyzwxyzw; + ldv $v19, 8, 8, $s6 ## L:285 | 12 | mat1 = load(address, 0x08).xyzwxyzw; + ldv $v18, 0, 16, $s6 ## L:286 | 13 | mat2 = load(address, 0x10).xyzwxyzw; + ldv $v20, 0, 0, $s6 ## L:284 | 14 | mat0 = load(address, 0x00).xyzwxyzw; + ldv $v20, 8, 0, $s6 ## L:284 | 15 | mat0 = load(address, 0x00).xyzwxyzw; + jal loadCurrentMVPMat ## L:361 | 16 | loadCurrentMVPMat(mat0, mat1, mat2, mat3); ## Args: $v27, $v25, $v23, $v21 + ldv $v18, 8, 16, $s6 ## L:286 | 17 | mat2 = load(address, 0x10).xyzwxyzw; + vsubc $v29, $v00, $v30.e7 ## L:406 | 18 | VTEMP = VZERO - 1; + ori $at, $zero, %lo(NORMAL_MASK_SHIFT) ## L:363 | ^ | vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; + ldv $v17, 8, 0, $at ## L:363 | 19 | vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; + ldv $v16, 0, 8, $at ## L:364 | 20 | vec16 normShift = load(NORMAL_MASK_SHIFT, 0x08).xyzwxyzw; + lbu $k0, %lo(TRI_COMMAND + 0) ## L:403 | 21 | u8 isUnlit = load(TRI_COMMAND); + ldv $v17, 0, 0, $at ## L:363 | 22 | vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; + ldv $v16, 8, 8, $at ## L:364 | 23 | vec16 normShift = load(NORMAL_MASK_SHIFT, 0x08).xyzwxyzw; + ori $at, $zero, %lo(SCREEN_SCALE) ## L:367 | 24 | normMask.w = load(SCREEN_SCALE, 6).x; + lbu $s2, %lo(ACTIVE_LIGHT_SIZE + 0) ## L:385 | 25 | u8 ptrLightEnd = load(ACTIVE_LIGHT_SIZE); + lsv $v17, 6, 6, $at ## L:367 | 26 | normMask.w = load(SCREEN_SCALE, 6).x; + ori $t8, $zero, %lo(COLOR_AMBIENT) ## L:404 | 27 | u32 ptrAmbient = COLOR_AMBIENT; + lsv $v17, 14, 6, $at ## L:368 | 28 | normMask.W = load(SCREEN_SCALE, 6).x; + ori $at, $zero, %lo(VERT_CONSTS) ## L:371 | 29 | fogClampSlope.x = load(VERT_CONSTS, 0x08).x; + andi $s6, $a2, 65535 ## L:380 | 30 | u32 ptrBuffA = addressInOut & 0xFFFF; + lsv $v15, 0, 8, $at ## L:371 | 31 | fogClampSlope.x = load(VERT_CONSTS, 0x08).x; + ori $at, $zero, %lo(SCREEN_SCALE) ## L:372 | 32 | fogClampSlope.w = load(SCREEN_SCALE, 14).x; + lsv $v15, 14, 14, $at ## L:373 | 33 | fogClampSlope.W = load(SCREEN_SCALE, 14).x; + lsv $v15, 6, 14, $at ## L:372 | 34 | fogClampSlope.w = load(SCREEN_SCALE, 14).x; + ori $at, $zero, %lo(SCREEN_OFFSET) ## L:377 | 35 | vec16<$v12> screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ori $sp, $zero, %lo(SCREEN_SCALE) ## L:399 | 36 | u16 ptrScreenScale = SCREEN_SCALE; + addiu $s5, $s6, 65500 ## L:381 | 37 | u32 ptrBuffB = ptrBuffA - 36; + sdv $v29, 0, 0, $s7 ## L:407 | 38 | store(VTEMP.xyzw, ptr3dEnd, 0); + ldv $v12, 8, 0, $at ## L:377 | 39 | vec16<$v12> screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ldv $v12, 0, 0, $at ## L:377 | 40 | vec16<$v12> screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ori $at, $zero, %lo(NORM_SCALE_W) ## L:378 | 41 | vec16<$v10> normScaleW = load(NORM_SCALE_W).xyzwxyzw; + ldv $v10, 0, 0, $at ## L:378 | 42 | vec16<$v10> normScaleW = load(NORM_SCALE_W).xyzwxyzw; + lbu $s1, %lo(FOG_STORE_OFFSET + 0) ## L:395 | 43 | u8 fogStoreOffset = load(FOG_STORE_OFFSET); + addiu $s6, $s6, 65464 ## L:396 | 44 | ptrBuffA -= 72; + ldv $v10, 8, 0, $at ## L:378 | 45 | vec16<$v10> normScaleW = load(NORM_SCALE_W).xyzwxyzw; + ori $at, $zero, %lo(UV_GEN_PARAMS) ## L:390 | 46 | uvGenArgs.XYZW = load(UV_GEN_PARAMS).xyzw; + ldv $v09, 8, 0, $at ## L:390 | 47 | uvGenArgs.XYZW = load(UV_GEN_PARAMS).xyzw; + ori $at, $zero, %lo(SCREEN_UVGEN_SCALE) ## L:391 | 48 | uvGenArgs.W = load(SCREEN_UVGEN_SCALE).x; + addiu $s2, $s2, %lo(LIGHT_DIR_COLOR) ## L:386 | 49 | ptrLightEnd += LIGHT_DIR_COLOR; + lsv $v09, 14, 0, $at ## L:391 | 50 | uvGenArgs.W = load(SCREEN_UVGEN_SCALE).x; + ori $at, $zero, %lo(UV_GEN_PARAMS) ## L:392 | 51 | uvGenArgs.xy = load(UV_GEN_PARAMS).xy; + llv $v09, 0, 0, $at ## L:392 | 52 | uvGenArgs.xy = load(UV_GEN_PARAMS).xy; + beq $k0, $zero, LABEL_T3DCmd_VertLoad_0001 ## L:410 | 53 | if(isUnlit) { + llv $v09, 4, 0, $at ## L:393 | 54 | uvGenArgs.zw = load(UV_GEN_PARAMS).xy; + ori $s2, $zero, %lo(LIGHT_DIR_COLOR) ## L:411 | 55 | ptrLightEnd = LIGHT_DIR_COLOR; + or $t8, $zero, $s7 ## L:412 | 56 | ptrAmbient = ptr3dEnd; + LABEL_T3DCmd_VertLoad_0001: + jal DMAWaitIdle ## L:423 | 57 | dma_await(); + lbu $s0, %lo(CLIP_CODE_ORG_ADDR + 0) ## L:419 | 58 | u8<$s0> baseTileMask = load(CLIP_CODE_ORG_ADDR); + lqv $v08, 0, 0, $s4 ## L:426 | 59 | vec16<$v08> pos = load(prt3d, 0x00); + vand $v07, $v17, $v08.h3 ## L:428 | ***63 | vec16<$v07> norm = normMask & pos.wwwwWWWW; + j LOOP_START ## L:435 | ^ | goto LOOP_START; + vmudn $v07, $v07, $v16.v ## L:429 | ****68 | norm *= normShift; + LOOP_TRAIL: + slv $v03, 0, 12, $s6 ## L:439 | 1 | store(uv.xy, ptrBuffA, 0x0C); + beq $s4, $s7, RSPQ_Loop ## L:441 | 2 | if(prt3d == ptr3dEnd)goto RSPQ_Loop; + slv $v03, 4, 12, $s5 ## L:440 | *4 | store(uv.zw, ptrBuffB, 0x0C); LOOP_START: - vor $v03, $v00, $v11.e2 ## L:410 | 63 | vec16 lightColor = fogScaleOffset.z; - lbu $a2, 19($s4) ## L:413 | ^ | baseTile = load(prt3d, 0x13); - vmulf $v29, $v20, $v07.h0 ## L:424 | **66 | VTEMP:sfract = matN0:sfract * norm.xxxxXXXX; - ori $s3, $zero, %lo(LIGHT_DIR_COLOR) ## L:431 | ^ | ptrLight = LIGHT_DIR_COLOR; - vmacf $v29, $v19, $v07.h1 ## L:425 | 67 | VTEMP:sfract = matN1:sfract +* norm.yyyyYYYY; - lbu $t8, 15($s3) ## L:435 | ^ | u8 isPointLight = load(ptrLight, 15); - vmacf $v07, $v18, $v07.h2 ## L:426 | 68 | norm = matN2:sfract +* norm.zzzzZZZZ; - vmudn $v06, $v28, $v08.h0 ## L:212 | 69 | out = mat0 * vec.xxxxXXXX; - addiu $s5, $s5, 72 ## L:419 | ^ | ptrBuffB += 72; - vmadh $v05, $v27, $v08.h0 ## L:212 | 70 | out = mat0 * vec.xxxxXXXX; - and $a2, $a2, $s0 ## L:414 | ^ | baseTile &= baseTileMask; - vmadn $v06, $v26, $v08.h1 ## L:213 | 71 | out = mat1 +* vec.yyyyYYYY; - lhu $k1, %lo(VERTEX_FX_FUNC + 0) ## L:420 | ^ | vertexFxFunc = load(VERTEX_FX_FUNC); - vmadh $v05, $v25, $v08.h1 ## L:213 | 72 | out = mat1 +* vec.yyyyYYYY; - lpv $v02, 0, 8, $s3 ## L:434 | ^ | vec16 lightDirVec = load_vec_s8(ptrLight, 8); - vmadn $v06, $v24, $v08.h2 ## L:214 | 73 | out = mat2 +* vec.zzzzZZZZ; - or $t9, $zero, $zero ## L:416 | ^ | u8 mvMatrixLoaded = 0; - addiu $s6, $s6, 72 ## L:418 | 74 | ptrBuffA += 72; - vmadh $v05, $v23, $v08.h2 ## L:214 | ^ | out = mat2 +* vec.zzzzZZZZ; - vmadn $v06, $v22, $v30.e7 ## L:215 | 75 | out = mat3 +* 1; - bne $k0, $zero, LIGHT_LOOP_END ## L:438 | ^ | if(isUnlit)goto LIGHT_LOOP_END; - vmadh $v05, $v21, $v30.e7 ## L:215 | *77 | out = mat3 +* 1; - beq $s3, $s2, LIGHT_LOOP_END ## L:441 | 78 | if(ptrLight != ptrLightEnd) - luv $v03, 0, -8, $s3 ## L:439 | *80 | lightColor = load_vec_u8(ptrLight, -8); - LABEL_T3DCmd_VertLoad_0003: - vmulf $v01, $v07, $v02.v ## L:445 | 81 | vec16 lightDirScale = norm:sfract * lightDirVec:sfract; - luv $v04, 0, 0, $s3 ## L:446 | ^ | color = load_vec_u8(ptrLight); - bne $t8, $zero, pointLight ## L:448 | 82 | if(isPointLight) { - ori $ra, $zero, LABEL_T3DCmd_VertLoad_0005 ## L:964 | *84 | dma_out(dmaDest, addrRDRAM, 0x40); - LABEL_T3DCmd_VertLoad_0005: - addiu $s3, $s3, 16 ## L:462 | 85 | ptrLight += 16; - vmulu $v29, $v04, $v01.h0 ## L:456 | ^ | VTEMP = color:ufract * lightDirScale:ufract.xxxxXXXX; - vmacu $v29, $v04, $v01.h1 ## L:457 | 86 | VTEMP = color:ufract +* lightDirScale:ufract.yyyyYYYY; - lbu $t8, 15($s3) ## L:464 | ^ | isPointLight = load(ptrLight, 15); - vmacu $v29, $v04, $v01.h2 ## L:458 | 87 | VTEMP = color:ufract +* lightDirScale:ufract.zzzzZZZZ; - lpv $v02, 0, 8, $s3 ## L:463 | ^ | lightDirVec = load_vec_s8(ptrLight, 8); - bne $s3, $s2, LABEL_T3DCmd_VertLoad_0003 ## L:464 | 88 | isPointLight = load(ptrLight, 15); - vadd $v03, $v03, $v29.v ## L:460 | ***92 | lightColor:sint += VTEMP; - LIGHT_LOOP_END: - vmudm $v02, $v15, $v06.h3 ## L:470 | 93 | vec32 clipPlaneW = guardBandScale * posClip.wwwwWWWW; - luv $v04, 0, 16, $s4 ## L:472 | ^ | color = load_vec_u8(prt3d, 0x10); - ori $ra, $zero, LABEL_T3DCmd_VertLoad_0006 ## L:964 | 94 | dma_out(dmaDest, addrRDRAM, 0x40); - vmadh $v01, $v15, $v05.h3 ## L:470 | ^ | vec32 clipPlaneW = guardBandScale * posClip.wwwwWWWW; - vmadn $v02, $v00, $v00 ## L:470 | 95 | vec32 clipPlaneW = guardBandScale * posClip.wwwwWWWW; - bne $t9, $zero, loadCurrentMVPMat ## L:475 | ^ | if(mvMatrixLoaded) { - addu $fp, $s6, $s1 ## L:473 | *97 | fogA = ptrBuffA + fogStoreOffset; + vmudn $v14, $v28, $v08.h0 ## L:222 | ****************************************************************69 | out = mat0 * vec.xxxxXXXX; + lhu $k1, %lo(VERTEX_FX_FUNC + 0) ## L:459 | ^ | vertexFxFunc = load(VERTEX_FX_FUNC); + vmadh $v13, $v27, $v08.h0 ## L:222 | 70 | out = mat0 * vec.xxxxXXXX; + vmadn $v14, $v26, $v08.h1 ## L:223 | 71 | out = mat1 +* vec.yyyyYYYY; + ori $s3, $zero, %lo(LIGHT_DIR_COLOR) ## L:471 | ^ | ptrLight = LIGHT_DIR_COLOR; + vmadh $v13, $v25, $v08.h1 ## L:223 | 72 | out = mat1 +* vec.yyyyYYYY; + lpv $v02, 0, 8, $s3 ## L:474 | ^ | vec16<$v02> lightDirVec = load_vec_s8(ptrLight, 8); + vmadn $v14, $v24, $v08.h2 ## L:224 | 73 | out = mat2 +* vec.zzzzZZZZ; + lbu $a2, 19($s4) ## L:452 | ^ | baseTile = load(prt3d, 0x13); + addiu $s5, $s5, 72 ## L:458 | 74 | ptrBuffB += 72; + vmadh $v13, $v23, $v08.h2 ## L:224 | ^ | out = mat2 +* vec.zzzzZZZZ; + vmadn $v14, $v22, $v30.e7 ## L:225 | 75 | out = mat3 +* 1; + addiu $s6, $s6, 72 ## L:457 | ^ | ptrBuffA += 72; + lbu $k0, 15($s3) ## L:475 | 76 | u8 isPointLight = load(ptrLight, 15); + vmadh $v13, $v21, $v30.e7 ## L:225 | ^ | out = mat3 +* 1; + vmulf $v29, $v20, $v07.h0 ## L:464 | 77 | VTEMP:sfract = matN0:sfract * norm.xxxxXXXX; + addu $fp, $s6, $s1 ## L:460 | ^ | fogA = ptrBuffA + fogStoreOffset; + luv $v11, 0, 0, $t8 ## L:480 | 78 | lightColor = load_vec_u8(ptrAmbient, 0); + vmacf $v29, $v19, $v07.h1 ## L:465 | ^ | VTEMP:sfract = matN1:sfract +* norm.yyyyYYYY; + vmacf $v07, $v18, $v07.h2 ## L:466 | 79 | norm = matN2:sfract +* norm.zzzzZZZZ; + or $t9, $zero, $zero ## L:455 | ^ | u8<$t9> mvMatrixLoaded = 0; + and $a2, $a2, $s0 ## L:453 | 80 | baseTile &= baseTileMask; + vmudl $v06, $v14, $v10.v ## L:482 | ^ | posClip = orgPosClip * normScaleW:ufract; + vmadm $v05, $v13, $v10.v ## L:482 | 81 | posClip = orgPosClip * normScaleW:ufract; + beq $s3, $s2, LABEL_T3DCmd_VertLoad_0003 ## L:484 | ^ | if(ptrLight != ptrLightEnd) + vmadn $v06, $v00, $v00 ## L:482 | 82 | posClip = orgPosClip * normScaleW:ufract; + LABEL_T3DCmd_VertLoad_0004: + luv $v04, 0, 0, $s3 ## L:489 | 83 | color = load_vec_u8(ptrLight); + vmulf $v01, $v07, $v02.v ## L:488 | ^ | vec16<$v01> lightDirScale = norm:sfract * lightDirVec:sfract; + bne $k0, $zero, pointLight ## L:491 | 84 | if(isPointLight) { + ori $ra, $zero, LABEL_T3DCmd_VertLoad_0006 ## L:965 | 85 | if(doMultiply) { LABEL_T3DCmd_VertLoad_0006: - vch $v29, $v05, $v05.h3 ## L:483 | 98 | u32 rejCodes = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v06, $v06.h3 ## L:483 | 99 | u32 rejCodes = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:483 | 100 | u32 rejCodes = clip(posClip, posClip.wwwwWWWW); - vch $v29, $v05, $v01 ## L:484 | ^ | u32 clipCodes = clip(posClip, clipPlaneW); - vcl $v29, $v06, $v02 ## L:484 | 101 | u32 clipCodes = clip(posClip, clipPlaneW); - addu $sp, $s5, $s1 ## L:541 | ^ | fogB = ptrBuffB + fogStoreOffset; - TAG_LightMul: vmulf $v04, $v04, $v03.v ## L:499 | 102 | color:sfract *= lightColor:ufract; - lqv $v08, 0, 32, $s4 ## L:565 | ^ | pos = load(prt3d, 0x20); - vmudl $v06, $v06, $v10.v ## L:501 | 103 | posClip *= normScaleW:ufract; - cfc2 $t3, $vcc ## L:484 | ^ | u32 clipCodes = clip(posClip, clipPlaneW); - vmadm $v05, $v05, $v10.v ## L:501 | 104 | posClip *= normScaleW:ufract; - srl $t5, $t4, 4 ## L:493 | ^ | rejCodesB = rejCodes >> 4; - andi $t5, $t5, 1799 ## L:253 | 105 | res = clipCode & 0b0000'0111'0000'0111; - vmadn $v06, $v00, $v00 ## L:501 | ^ | posClip *= normScaleW:ufract; - srl $t7, $t3, 4 ## L:486 | 106 | clipCodeB = clipCodes >> 4; - andi $t6, $t4, 1799 ## L:253 | 107 | res = clipCode & 0b0000'0111'0000'0111; - vmudm $v04, $v04, $v31.e6 ## L:503 | ^ | color >>= 7; - sdv $v05, 0, 16, $s6 ## L:511 | 108 | store(posClip.xyzw, ptrBuffA, 0x10); - vrcph $v13.e3, $v05.e3 ## L:517 | ^ | screenSize.w = invert_half(posClip).w; - sdv $v06, 0, 24, $s6 ## L:511 | 109 | store(posClip.xyzw, ptrBuffA, 0x10); - vrcpl $v14.e3, $v06.e3 ## L:517 | ^ | screenSize.w = invert_half(posClip).w; - sdv $v06, 8, 24, $s5 ## L:512 | 110 | store(posClip.XYZW, ptrBuffB, 0x10); - vrcph $v13.e3, $v05.e7 ## L:518 | ^ | screenSize.W = invert_half(posClip).W; - andi $t8, $t3, 775 ## L:245 | 111 | res = clipCode & 0b0000'0011'0000'0111; - vrcpl $v14.e7, $v06.e7 ## L:518 | ^ | screenSize.W = invert_half(posClip).W; - vrcph $v13.e7, $v00.e7 ## L:518 | 112 | screenSize.W = invert_half(posClip).W; - srl $t2, $t8, 5 ## L:246 | ^ | u32 tmp = res >> 5; - vmudh $v04, $v04, $v09.e6 ## L:504 | 113 | color:sint *= uvGenArgs:sint.Z; - sdv $v05, 8, 16, $s5 ## L:512 | ^ | store(posClip.XYZW, ptrBuffB, 0x10); - or $t8, $t8, $t2 ## L:247 | 114 | res |= tmp; - vaddc $v03, $v06, $v11.e1 ## L:529 | ^ | fog:ufract = posClip + fogScaleOffset:ufract.y; - vadd $v02, $v05, $v11.e0 ## L:530 | 115 | fog:sint = posClip + fogScaleOffset.x; - andi $t7, $t7, 775 ## L:245 | ^ | res = clipCode & 0b0000'0011'0000'0111; - srl $t2, $t7, 5 ## L:246 | 116 | u32 tmp = res >> 5; - vmudl $v29, $v06, $v14.h3 ## L:532 | ^ | posClip *= screenSize.wwwwWWWW; - vmadm $v29, $v05, $v14.h3 ## L:532 | 117 | posClip *= screenSize.wwwwWWWW; - or $t8, $t8, $a2 ## L:490 | ^ | clipCodeA |= baseTile; - suv $v04, 0, 8, $s6 ## L:506 | 118 | @Barrier("color-fog") store_vec_u8(color.x, ptrBuffA, 0x08); ## Barrier: 0x1 - vmadn $v06, $v06, $v13.h3 ## L:532 | ^ | posClip *= screenSize.wwwwWWWW; - ssv $v14, 6, 34, $s6 ## L:522 | 119 | store(screenSize.w, ptrBuffA, 0x20); - vmadh $v05, $v05, $v13.h3 ## L:532 | ^ | posClip *= screenSize.wwwwWWWW; - vmudh $v02, $v02, $v11.e3 ## L:534 | 120 | fog:sint *= fogScaleOffset:sint.w; - ssv $v14, 14, 34, $s5 ## L:523 | ^ | store(screenSize.W, ptrBuffB, 0x20); - ssv $v13, 6, 32, $s6 ## L:522 | 121 | store(screenSize.w, ptrBuffA, 0x20); - or $t7, $t7, $t2 ## L:247 | 122 | res |= tmp; - vmudl $v29, $v06, $v14.v ## L:536 | ^ | posClip *= screenSize; - srl $t2, $t6, 5 ## L:254 | 123 | u32 tmp = res >> 5; - vmadm $v29, $v05, $v14.v ## L:536 | ^ | posClip *= screenSize; - suv $v04, 4, 8, $s5 ## L:507 | 124 | @Barrier("color-fog") store_vec_u8(color.X, ptrBuffB, 0x08); ## Barrier: 0x1 - vmadn $v06, $v06, $v13.v ## L:536 | ^ | posClip *= screenSize; - vmadh $v05, $v05, $v13.v ## L:536 | 125 | posClip *= screenSize; - or $t7, $t7, $a2 ## L:491 | ^ | clipCodeB |= baseTile; - vsub $v29, $v11, $v02.h2 ## L:538 | 126 | VTEMP:sint = fogScaleOffset - fog:sint.zzzzZZZZ; - ssv $v13, 14, 32, $s5 ## L:523 | ^ | store(screenSize.W, ptrBuffB, 0x20); - nor $t6, $t6, $t2 ## L:255 | 127 | res = res ~| tmp; - srl $t2, $t5, 5 ## L:254 | 128 | u32 tmp = res >> 5; - vmadh $v05, $v12, $v30.e7 ## L:545 | ^ | posClip:sint = screenOffset:sint +* 1; - ldv $v03, 0, 24, $s4 ## L:551 | 129 | vec16 uv = load(prt3d, 0x18).xyzw; - addiu $s4, $s4, 32 ## L:570 | 130 | prt3d += 0x20; - nor $t5, $t5, $t2 ## L:255 | 131 | res = res ~| tmp; - vmudn $v29, $v29, $v30.e6 ## L:547 | ^ | VTEMP <<= 1; - sdv $v05, 0, 0, $s6 ## L:553 | 132 | @Barrier("pos-cc") store(posClip:sint.xyzw, ptrBuffA, 0x00); ## Barrier: 0x2 - vor $v02, $v00, $v07 ## L:566 | ^ | vec16 oldNorm = norm; - vand $v07, $v17, $v08.h3 ## L:567 | 133 | norm = normMask & pos.wwwwWWWW; - sdv $v05, 8, 0, $s5 ## L:554 | ^ | @Barrier("pos-cc") store(posClip:sint.XYZW, ptrBuffB, 0x00); ## Barrier: 0x2 - sb $t8, 6($s6) ## L:557 | 134 | @Barrier("pos-cc") store(clipCodeA:u8, ptrBuffA, 0x06); ## Barrier: 0x2 - sb $t6, 7($s6) ## L:558 | 135 | @Barrier("pos-cc") store(rejCodesA:u8, ptrBuffA, 0x07); ## Barrier: 0x2 - sb $t7, 6($s5) ## L:560 | 136 | @Barrier("pos-cc") store(clipCodeB:u8, ptrBuffB, 0x06); ## Barrier: 0x2 - ssv $v29, 4, 0, $fp ## L:548 | 137 | @Barrier("color-fog") store(VTEMP:sint.z, fogA); ## Barrier: 0x1 - vmudn $v07, $v07, $v16.v ## L:568 | ^ | norm *= normShift; - sb $t5, 7($s5) ## L:561 | 138 | @Barrier("pos-cc") store(rejCodesB:u8, ptrBuffB, 0x07); ## Barrier: 0x2 - vaddc $v03, $v03, $v09.v ## L:563 | ^ | uv += uvGenArgs; - jal $k1 ## L:572 | 139 | vertexFxFunc(); - ssv $v29, 12, 0, $sp ## L:549 | *141 | @Barrier("color-fog") store(VTEMP:sint.Z, fogB); ## Barrier: 0x1 -VertexFX_None: - slv $v03, 0, 12, $s6 - # emux_trace_stop - bne $s4, $s7, LOOP_START - slv $v03, 4, 12, $s5 - j RSPQ_Loop - -#if RSPQ_PROFILE == 1 - nop - VertexFX_Spherical: - VertexFX_CelShadeColor: - VertexFX_CelShadeAlpha: - VertexFX_Outline: - j VertexFX_None - nop -#endif - -#if RSPQ_PROFILE == 0 + addiu $s3, $s3, 16 ## L:503 | 86 | ptrLight += 16; + ori $ra, $zero, LABEL_T3DCmd_VertLoad_0007 ## L:965 | 87 | if(doMultiply) { + vmulu $v29, $v04, $v01.h0 ## L:499 | ^ | VTEMP = color:ufract * lightDirScale:ufract.xxxxXXXX; + lbu $k0, 15($s3) ## L:505 | 88 | isPointLight = load(ptrLight, 15); + vmacu $v29, $v04, $v01.h1 ## L:500 | ^ | VTEMP = color:ufract +* lightDirScale:ufract.yyyyYYYY; + vmacu $v29, $v04, $v01.h2 ## L:501 | 89 | VTEMP = color:ufract +* lightDirScale:ufract.zzzzZZZZ; + beq $t9, $s3, loadCurrentMVPMat ## L:507 | ^ | if(mvMatrixLoaded == ptrLight) { + lpv $v02, 0, 8, $s3 ## L:504 | 90 | lightDirVec = load_vec_s8(ptrLight, 8); + LABEL_T3DCmd_VertLoad_0007: + bne $s3, $s2, LABEL_T3DCmd_VertLoad_0004 ## L:511 | 91 | lightColor:sint += VTEMP; + vadd $v11, $v11, $v29.v ## L:511 | *93 | lightColor:sint += VTEMP; + LABEL_T3DCmd_VertLoad_0003: + vch $v29, $v13, $v13.h3 ## L:524 | 94 | u32 rejCodes = clip(orgPosClip, orgPosClip.wwwwWWWW); + sdv $v05, 0, 16, $s6 ## L:553 | ^ | store(posClip.xyzw, ptrBuffA, 0x10); + luv $v04, 0, 16, $s4 ## L:517 | 95 | color = load_vec_u8(prt3d, 0x10); + vcl $v29, $v14, $v14.h3 ## L:524 | ^ | u32 rejCodes = clip(orgPosClip, orgPosClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:524 | 96 | u32 rejCodes = clip(orgPosClip, orgPosClip.wwwwWWWW); + vch $v29, $v05, $v13.h3 ## L:525 | ^ | u32 clipCodes = clip(posClip, orgPosClip.wwwwWWWW); + ldv $v03, 0, 24, $s4 ## L:590 | 97 | uv = load(prt3d, 0x18).xyzw; + vrcph $v16.e3, $v05.e3 ## L:558 | ^ | invWRaw.w = invert_half(posClip).w; + vcl $v29, $v06, $v14.h3 ## L:525 | 98 | u32 clipCodes = clip(posClip, orgPosClip.wwwwWWWW); + ldv $v13, 0, 0, $sp ## L:577 | ^ | orgPosClip = load(ptrScreenScale).xyzwxyzw; + vrcpl $v08.e3, $v06.e3 ## L:558 | 99 | invWRaw.w = invert_half(posClip).w; + srl $t5, $t4, 4 ## L:534 | ^ | rejCodesB = rejCodes >> 4; + andi $t6, $t4, 1803 ## L:266 | 100 | res = clipCode & 0b0000'0111'0000'1011; + vrcph $v16.e3, $v05.e7 ## L:559 | ^ | invWRaw.W = invert_half(posClip).W; + vrcpl $v08.e7, $v06.e7 ## L:559 | 101 | invWRaw.W = invert_half(posClip).W; + cfc2 $t3, $vcc ## L:525 | ^ | u32 clipCodes = clip(posClip, orgPosClip.wwwwWWWW); + ldv $v13, 8, 0, $sp ## L:577 | 102 | orgPosClip = load(ptrScreenScale).xyzwxyzw; + vrcph $v16.e7, $v00.e7 ## L:559 | ^ | invWRaw.W = invert_half(posClip).W; + vmudh $v29, $v12, $v30.e7 ## L:541 | 103 | VTEMP:sint = screenOffset:sint * 1; + ldv $v14, 8, 8, $sp ## L:577 | ^ | orgPosClip = load(ptrScreenScale).xyzwxyzw; + vmadn $v29, $v15, $v05.h2 ## L:542 | 104 | VTEMP:sint = fogClampSlope:ufract +* posClip:sint.zzzzZZZZ; + addiu $s4, $s4, 32 ## L:613 | ^ | prt3d += 0x20; + vmadh $v01, $v17, $v05.h2 ## L:543 | 105 | vec16<$v01> fogV = normMask:sint +* posClip:sint.zzzzZZZZ; + andi $k0, $t3, 771 ## L:256 | ^ | res = clipCode & 0b0000'0011'0000'0011; + srl $t2, $k0, 5 ## L:257 | 106 | u32 tmp = res >> 5; + vmudl $v02, $v06, $v08.h3 ## L:563 | ^ | invW:sfract = posClip * invWRaw.wwwwWWWW; + vmadm $v02, $v05, $v08.h3 ## L:563 | 107 | invW:sfract = posClip * invWRaw.wwwwWWWW; + andi $t5, $t5, 1803 ## L:266 | ^ | res = clipCode & 0b0000'0111'0000'1011; + vmadn $v02, $v06, $v16.h3 ## L:563 | 108 | invW:sfract = posClip * invWRaw.wwwwWWWW; + or $k0, $k0, $t2 ## L:258 | ^ | res |= tmp; + srl $t7, $t3, 4 ## L:527 | 109 | clipCodeB = clipCodes >> 4; + vlt $v01, $v01, $v15.e0 ## L:544 | ^ | fogV = min(fogV, fogClampSlope.xxxxxxxx); + andi $t7, $t7, 771 ## L:256 | 110 | res = clipCode & 0b0000'0011'0000'0011; + srl $t2, $t7, 5 ## L:257 | 111 | u32 tmp = res >> 5; + TAG_LightMul: vmulf $v04, $v04, $v11.v ## L:549 | ^ | color:sfract *= lightColor:ufract; + vsubc $v29, $v10, $v02.h3 ## L:567 | 112 | VTEMP = normScaleW:ufract - invW:ufract.wwwwWWWW; + or $t7, $t7, $t2 ## L:258 | ^ | res |= tmp; + srl $t2, $t6, 4 ## L:267 | 113 | u32 tmp = res >> 4; + vaddc $v02, $v08, $v08.v ## L:568 | ^ | invW = invWRaw + invWRaw; + sdv $v06, 8, 24, $s5 ## L:554 | 114 | store(posClip.XYZW, ptrBuffB, 0x10); + vadd $v11, $v16, $v16.v ## L:568 | ^ | invW = invWRaw + invWRaw; + nor $t6, $t6, $t2 ## L:268 | 115 | res = res ~| tmp; + vmudm $v04, $v04, $v31.e6 ## L:550 | ^ | color >>= 7; + srl $t2, $t5, 4 ## L:267 | 116 | u32 tmp = res >> 4; + or $t7, $t7, $a2 ## L:532 | 117 | clipCodeB |= baseTile; + vmudl $v02, $v02, $v29.h2 ## L:569 | ^ | invW *= VTEMP:ufract.zzzzZZZZ; + vmadm $v11, $v11, $v29.h2 ## L:569 | 118 | invW *= VTEMP:ufract.zzzzZZZZ; + ldv $v14, 0, 8, $sp ## L:577 | ^ | orgPosClip = load(ptrScreenScale).xyzwxyzw; + sdv $v05, 8, 16, $s5 ## L:554 | 119 | store(posClip.XYZW, ptrBuffB, 0x10); + vmadn $v02, $v00, $v00 ## L:569 | ^ | invW *= VTEMP:ufract.zzzzZZZZ; + nor $t5, $t5, $t2 ## L:268 | 120 | res = res ~| tmp; + sb $t6, 7($s6) ## L:601 | 121 | store(rejCodesA:u8, ptrBuffA, 0x07); + ssv $v11, 6, 32, $s6 ## L:571 | 122 | store(invW.w, ptrBuffA, 0x20); + vmudh $v04, $v04, $v09.e6 ## L:551 | ^ | color:sint *= uvGenArgs:sint.Z; + vmudl $v29, $v06, $v02.h3 ## L:575 | 123 | invW = posClip * invW.wwwwWWWW; + ssv $v02, 6, 34, $s6 ## L:571 | ^ | store(invW.w, ptrBuffA, 0x20); + vmadm $v29, $v05, $v02.h3 ## L:575 | 124 | invW = posClip * invW.wwwwWWWW; + ssv $v02, 14, 34, $s5 ## L:572 | ^ | store(invW.W, ptrBuffB, 0x20); + vmadn $v02, $v06, $v11.h3 ## L:575 | 125 | invW = posClip * invW.wwwwWWWW; + ssv $v11, 14, 32, $s5 ## L:572 | ^ | store(invW.W, ptrBuffB, 0x20); + suv $v04, 4, 8, $s5 ## L:584 | 126 | @Barrier("color-fog-b") store_vec_u8(color.X, ptrBuffB, 0x08); ## Barrier: 0x2 + vmadh $v11, $v05, $v11.h3 ## L:575 | ^ | invW = posClip * invW.wwwwWWWW; + lqv $v08, 0, 0, $s4 ## L:608 | 127 | pos = load(prt3d, 0x20); + or $k0, $k0, $a2 ## L:531 | *129 | clipCodeA |= baseTile; + vmudl $v05, $v02, $v14.v ## L:578 | ^ | posClip = invW * orgPosClip; + vmadm $v05, $v11, $v14.v ## L:578 | 130 | posClip = invW * orgPosClip; + sdv $v06, 0, 24, $s6 ## L:553 | ^ | store(posClip.xyzw, ptrBuffA, 0x10); + sb $t5, 7($s5) ## L:604 | 131 | store(rejCodesB:u8, ptrBuffB, 0x07); + vmadn $v06, $v02, $v13.v ## L:578 | ^ | posClip = invW * orgPosClip; + suv $v04, 0, 8, $s6 ## L:583 | 132 | @Barrier("color-fog-a") store_vec_u8(color.x, ptrBuffA, 0x08); ## Barrier: 0x1 + vmadh $v05, $v11, $v13.v ## L:578 | ^ | posClip = invW * orgPosClip; + sbv $v01, 15, 36, $fp ## L:587 | 133 | @Barrier("color-fog-b") store_byte_lo(fogV.W, fogA, 36); ## Barrier: 0x2 + vmadh $v05, $v12, $v30.e7 ## L:579 | ^ | posClip:sint = screenOffset:sint +* 1; + sb $t7, 6($s5) ## L:603 | 134 | store(clipCodeB:u8, ptrBuffB, 0x06); + vor $v11, $v00, $v07 ## L:609 | ^ | vec16<$v11> oldNorm = norm; + sbv $v01, 7, 0, $fp ## L:586 | 135 | @Barrier("color-fog-a") store_byte_lo(fogV.w, fogA); ## Barrier: 0x1 + vand $v07, $v17, $v08.h3 ## L:610 | ^ | norm = normMask & pos.wwwwWWWW; + sb $k0, 6($s6) ## L:600 | 136 | store(clipCodeA:u8, ptrBuffA, 0x06); + slv $v05, 8, 0, $s5 ## L:597 | 137 | store(posClip:sint.XY, ptrBuffB, 0x00); + vaddc $v03, $v03, $v09.v ## L:606 | ^ | uv += uvGenArgs; + ssv $v05, 12, 4, $s5 ## L:598 | 138 | store(posClip:sint.Z, ptrBuffB, 0x04); + ssv $v05, 4, 4, $s6 ## L:595 | 139 | store(posClip:sint.z, ptrBuffA, 0x04); + vmudn $v07, $v07, $v16.v ## L:611 | ^ | norm *= normShift; + jal $k1 ## L:615 | 140 | vertexFxFunc(); + slv $v05, 0, 0, $s6 ## L:594 | 141 | store(posClip:sint.xy, ptrBuffA, 0x00); VertexFX_Spherical: - vge $v05, $v05, $v00.e0 ## L:607 - vsubc $v04, $v05, $v12.v ## L:608 - vlt $v04, $v04, $v12 ## L:609 - vmulf $v03, $v02, $v09.v ## L:610 - vmudn $v04, $v04, $v09.e7 ## L:612 - vaddc $v03, $v03, $v09.e0 ## L:616 - vmulf $v04, $v04, $v02.h2 ## L:613 - vmulf $v04, $v04, $v09.e0 ## L:614 - vaddc $v03, $v03, $v04.v ## L:617 - slv $v03, 0, 12, $s6 ## L:619 - bne $s4, $s7, LOOP_START ## L:585 - slv $v03, 8, 12, $s5 ## L:620 - j RSPQ_Loop ## L:585 + ## hot-path cycles: 34 + vge $v05, $v05, $v00.e0 ## L:644 | ^ | posClipInt = posClipInt >= 0; + vsubc $v04, $v05, $v12.v ## L:645 | ***5 | uvOffsetFactor = posClipInt - screenOffset; + vlt $v04, $v04, $v12 ## L:646 | ***9 | uvOffsetFactor = uvOffsetFactor < screenOffset; + vmulf $v03, $v11, $v09.v ## L:647 | 10 | uv:sfract = normal * uvGenArgs; + vmudn $v04, $v04, $v09.e7 ## L:649 | **13 | uvOffsetFactor *= uvGenArgs.W; + vaddc $v03, $v03, $v09.e0 ## L:653 | 14 | uv += uvGenArgs.x; + vmulf $v04, $v04, $v11.h2 ## L:650 | **17 | uvOffsetFactor:sfract *= normal.zzzzZZZZ; + vmulf $v04, $v04, $v09.e0 ## L:651 | ***21 | uvOffsetFactor:sfract *= uvGenArgs.x; + vaddc $v03, $v03, $v04.v ## L:654 | ***25 | uv += uvOffsetFactor; + slv $v03, 0, 12, $s6 ## L:656 | ***29 | store(uv.xy, ptrBuffA, 0x0C); + bne $s4, $s7, LOOP_START ## L:622 | 30 | if(prt3d == ptr3dEnd)goto RSPQ_Loop; + slv $v03, 8, 12, $s5 ## L:657 | 31 | store(uv.XY, ptrBuffB, 0x0C); + j RSPQ_Loop ## L:622 | 32 | if(prt3d == ptr3dEnd)goto RSPQ_Loop; VertexFX_CelShadeColor: - vge $v04, $v04, $v04 - vge $v04, $v04, $v04 - vmov $v03.e0, $v04.e0 - vmov $v03.e2, $v04.e4 - slv $v03, 4, 12, $s5 - bne $s4, $s7, LOOP_START - slv $v03, 0, 12, $s6 - j RSPQ_Loop + ## hot-path cycles: 11 + vge $v04, $v04, $v04.h1 ## L:660 | ^ | color = max(color, color.yyyyYYYY); + vge $v04, $v04, $v04.h2 ## L:661 | ***5 | color = max(color, color.zzzzZZZZ); + vmov $v03.e0, $v04.e0 ## L:662 | ***9 | uv.x = color.x; + j LOOP_TRAIL ## L:664 | ^ | goto LOOP_TRAIL; + vmov $v03.e2, $v04.e4 ## L:663 | *11 | uv.z = color.X; VertexFX_CelShadeAlpha: - vmov $v03.e0, $v04.e3 - vmov $v03.e2, $v04.e7 - slv $v03, 4, 12, $s5 - bne $s4, $s7, LOOP_START - slv $v03, 0, 12, $s6 - j RSPQ_Loop + ## hot-path cycles: 3 + vmov $v03.e0, $v04.e3 ## L:673 | ^ | uv.x = color.w; + j LOOP_TRAIL ## L:676 | ^ | goto LOOP_TRAIL; + vmov $v03.e2, $v04.e7 ## L:674 | *3 | uv.z = color.W; VertexFX_Outline: - vmulf $v29, $v02, $v09.v - vmadh $v05, $v05, $v30.e7 - slv $v05, 8, 0, $s5 - bne $s4, $s7, LOOP_START - slv $v05, 0, 0, $s6 - j RSPQ_Loop - nop -#endif - + ## hot-path cycles: 11 + vmulf $v29, $v11, $v09.v ## L:681 | ^ | VTEMP = normal:sfract * uvGenArgs; + vmadh $v05, $v05, $v30.e7 ## L:682 | 2 | posClipInt:sint = posClipInt:sint +* 1; + slv $v05, 0, 0, $s6 ## L:687 | ***6 | store(posClipInt.xy, ptrBuffA, 0x00); + bne $s4, $s7, LOOP_START ## L:609 | 7 | if(prt3d == ptr3dEnd)goto RSPQ_Loop; + slv $v05, 8, 0, $s5 ## L:688 | 8 | store(posClipInt.XY, ptrBuffB, 0x00); + j RSPQ_Loop ## L:609 | 9 | if(prt3d == ptr3dEnd)goto RSPQ_Loop; + nop ## L:609 | *11 | if(prt3d == ptr3dEnd)goto RSPQ_Loop; pointLight: - bne $t9, $zero, LABEL_pointLight_000C ## L:683 | ^ | if(!mvMatrixLoaded) { - lhu $t7, 14($s3) ## L:682 | *3 | lightSize:u16 = load(ptrLight, 14); - ori $at, $zero, %lo(MATRIX_MV) ## L:260 | 4 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; - ldv $v26, 0, 24, $at ## L:261 | 5 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; - ldv $v26, 8, 24, $at ## L:261 | 6 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; - ldv $v27, 0, 0, $at ## L:260 | 7 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; - ldv $v28, 0, 8, $at ## L:260 | 8 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; - ldv $v23, 0, 32, $at ## L:262 | 9 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; - ldv $v24, 0, 40, $at ## L:262 | 10 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; - ldv $v28, 8, 8, $at ## L:260 | 11 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; - ldv $v27, 8, 0, $at ## L:260 | 12 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; - ldv $v21, 0, 48, $at ## L:263 | 13 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; - ldv $v24, 8, 40, $at ## L:262 | 14 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; - ldv $v25, 0, 16, $at ## L:261 | 15 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; - vmudn $v28, $v28, $v08.h0 ## L:212 | ^ | out = mat0 * vec.xxxxXXXX; - ldv $v25, 8, 16, $at ## L:261 | 16 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; - ldv $v23, 8, 32, $at ## L:262 | 17 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; - ldv $v22, 0, 56, $at ## L:263 | 18 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; - vmadh $v27, $v27, $v08.h0 ## L:212 | ^ | out = mat0 * vec.xxxxXXXX; - ldv $v22, 8, 56, $at ## L:263 | 19 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; - vmadn $v28, $v26, $v08.h1 ## L:213 | ^ | out = mat1 +* vec.yyyyYYYY; - ldv $v21, 8, 48, $at ## L:263 | 20 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; - vmadh $v27, $v25, $v08.h1 ## L:213 | ^ | out = mat1 +* vec.yyyyYYYY; - vmadn $v28, $v24, $v08.h2 ## L:214 | 21 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v27, $v23, $v08.h2 ## L:214 | 22 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v28, $v22, $v30.e7 ## L:215 | 23 | out = mat3 +* 1; - vmadh $v27, $v21, $v30.e7 ## L:215 | 24 | out = mat3 +* 1; - vmudl $v28, $v28, $v31.e3 ## L:689 | **27 | vertPos >>= 4; - vmadm $v27, $v27, $v31.e3 ## L:689 | 28 | vertPos >>= 4; - addiu $t9, $zero, 1 ## L:690 | ^ | mvMatrixLoaded = 1; - vmadn $v28, $v00, $v00 ## L:689 | 29 | vertPos >>= 4; + ## hot-path cycles: 89 + bne $t9, $zero, LABEL_pointLight_000A ## L:719 | ^ | if(!mvMatrixLoaded) { + lhu $t7, 14($s3) ## L:718 | 2 | lightSize:u16 = load(ptrLight, 14); + ori $at, $zero, %lo(MATRIX_MV) ## L:273 | 3 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; + ldv $v27, 0, 0, $at ## L:273 | 4 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; + ldv $v27, 8, 0, $at ## L:273 | 5 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; + ldv $v28, 0, 8, $at ## L:273 | 6 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; + ldv $v28, 8, 8, $at ## L:273 | 7 | mat0 = load(MATRIX_MV, 0x00).xyzwxyzw; + ldv $v25, 0, 16, $at ## L:274 | 8 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; + ldv $v25, 8, 16, $at ## L:274 | 9 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; + ldv $v26, 0, 24, $at ## L:274 | 10 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; + ldv $v26, 8, 24, $at ## L:274 | 11 | mat1 = load(MATRIX_MV, 0x10).xyzwxyzw; + ldv $v23, 8, 32, $at ## L:275 | 12 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; + ldv $v24, 8, 40, $at ## L:275 | 13 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; + ldv $v21, 8, 48, $at ## L:276 | 14 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; + ldv $v22, 8, 56, $at ## L:276 | 15 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; + vmudn $v28, $v28, $v08.h0 ## L:222 | ^ | out = mat0 * vec.xxxxXXXX; + ldv $v24, 0, 40, $at ## L:275 | 16 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; + vmadh $v27, $v27, $v08.h0 ## L:222 | ^ | out = mat0 * vec.xxxxXXXX; + ldv $v23, 0, 32, $at ## L:275 | 17 | mat2 = load(MATRIX_MV, 0x20).xyzwxyzw; + vmadn $v28, $v26, $v08.h1 ## L:223 | ^ | out = mat1 +* vec.yyyyYYYY; + ldv $v22, 0, 56, $at ## L:276 | 18 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; + ldv $v21, 0, 48, $at ## L:276 | 19 | mat3 = load(MATRIX_MV, 0x30).xyzwxyzw; + vmadh $v27, $v25, $v08.h1 ## L:223 | ^ | out = mat1 +* vec.yyyyYYYY; + vmadn $v28, $v24, $v08.h2 ## L:224 | 20 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v27, $v23, $v08.h2 ## L:224 | 21 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v28, $v22, $v30.e7 ## L:225 | 22 | out = mat3 +* 1; + vmadh $v27, $v21, $v30.e7 ## L:225 | 23 | out = mat3 +* 1; + vmudl $v28, $v28, $v31.e3 ## L:725 | **26 | vertPos >>= 4; + or $t9, $zero, $s2 ## L:726 | ^ | mvMatrixLoaded = ptrLightEnd; + vmadm $v27, $v27, $v31.e3 ## L:725 | 27 | vertPos >>= 4; + vmadn $v28, $v00, $v00 ## L:725 | 28 | vertPos >>= 4; + LABEL_pointLight_000A: + ldv $v23, 0, 8, $s3 ## L:733 | ^ | ptPos:sint.xyzw = load(ptrLight, 8).xyzw; + ldv $v23, 8, 8, $s3 ## L:734 | 29 | ptPos:sint.XYZW = load(ptrLight, 8).xyzw; + vmudm $v23, $v23, $v31.e5 ## L:736 | ***33 | ptPos = ptPos:sint >> 6; + vmadn $v24, $v00, $v00 ## L:736 | 34 | ptPos = ptPos:sint >> 6; + vsubc $v24, $v24, $v28.v ## L:737 | ***38 | ptPos = ptPos - vertPos; + vsub $v23, $v23, $v27.v ## L:737 | 39 | ptPos = ptPos - vertPos; + vmudl $v21, $v24, $v24.v ## L:740 | **42 | lightVertDot = ptPos * ptPos; + vmadm $v21, $v23, $v24.v ## L:740 | 43 | lightVertDot = ptPos * ptPos; + vmadn $v22, $v24, $v23.v ## L:740 | 44 | lightVertDot = ptPos * ptPos; + vmadh $v21, $v23, $v23.v ## L:740 | 45 | lightVertDot = ptPos * ptPos; + vaddc $v26, $v22, $v22.h1 ## L:741 | **48 | mat1 = lightVertDot + lightVertDot.yyyyYYYY; + andi $t7, $t7, 32767 ## L:729 | ^ | lightSize &= 0x7FFF; + vadd $v25, $v21, $v21.h1 ## L:741 | 49 | mat1 = lightVertDot + lightVertDot.yyyyYYYY; + vaddc $v22, $v22, $v26.h2 ## L:742 | **52 | lightVertDot = lightVertDot + mat1.zzzzZZZZ; + sll $t7, $t7, 16 ## L:730 | ^ | lightSize <<= 16; + vadd $v21, $v21, $v25.h2 ## L:742 | 53 | lightVertDot = lightVertDot + mat1.zzzzZZZZ; + mtc2 $t7, $v26.e3 ## L:744 | ^ | mat1.w = lightSize; + srl $at, $t7, 16 ## L:744 | 54 | mat1.w = lightSize; + mtc2 $at, $v25.e3 ## L:744 | **57 | mat1.w = lightSize; + vrsqh $v21.e0, $v21.e0 ## L:750 | ^ | lightVertDot.x = invert_half_sqrt(lightVertDot).x; + lbu $t7, 14($s3) ## L:746 | 58 | lightSize:u8 = load(ptrLight, 14); + vrsql $v22.e0, $v22.e0 ## L:750 | ^ | lightVertDot.x = invert_half_sqrt(lightVertDot).x; + vrsqh $v21.e0, $v21.e4 ## L:751 | **61 | lightVertDot.X = invert_half_sqrt(lightVertDot).X; + vrsql $v22.e4, $v22.e4 ## L:751 | 62 | lightVertDot.X = invert_half_sqrt(lightVertDot).X; + vrsqh $v21.e4, $v00.e0 ## L:751 | 63 | lightVertDot.X = invert_half_sqrt(lightVertDot).X; + vmudl $v01, $v22, $v26.e3 ## L:752 | **66 | lightRes = lightVertDot * mat1.w; + sra $t7, $t7, 7 ## L:747 | ^ | lightSize >>= 7; + vmadm $v01, $v21, $v26.e3 ## L:752 | 67 | lightRes = lightVertDot * mat1.w; + vmadn $v01, $v22, $v25.e3 ## L:752 | 68 | lightRes = lightVertDot * mat1.w; + bne $t7, $zero, LABEL_pointLight_000B ## L:754 | ^ | if(!lightSize) { + vmadh $v01, $v21, $v25.e3 ## L:752 | 69 | lightRes = lightVertDot * mat1.w; + vmudn $v22, $v22, $v31.e7 ## L:757 | 70 | lightVertDot *= 256; + vmadh $v21, $v21, $v31.e7 ## L:757 | 71 | lightVertDot *= 256; + vmulf $v01, $v01, $v01.v ## L:759 | *73 | lightRes:sfract *= lightRes:sfract; + vmudl $v08, $v24, $v22.h0 ## L:761 | 74 | pos:sint = ptPos * lightVertDot.xxxxXXXX; + vmadm $v08, $v23, $v22.h0 ## L:761 | 75 | pos:sint = ptPos * lightVertDot.xxxxXXXX; + vmadn $v08, $v24, $v21.h0 ## L:761 | 76 | pos:sint = ptPos * lightVertDot.xxxxXXXX; + vmadh $v08, $v23, $v21.h0 ## L:761 | 77 | pos:sint = ptPos * lightVertDot.xxxxXXXX; + vmulf $v08, $v08, $v01.h0 ## L:762 | ***81 | pos:sfract *= lightRes:sfract.xxxxXXXX; + beq $zero, $zero, LABEL_pointLight_000C ## L:765 | ^ | lightRes = pos:sfract * norm:sfract; + vmulf $v01, $v08, $v07.v ## L:765 | ****86 | lightRes = pos:sfract * norm:sfract; + LABEL_pointLight_000B: + vmulf $v01, $v01, $v01.v ## L:768 | 1 | lightRes:sfract *= lightRes:sfract; + vmov $v01.e6, $v00.e0 ## L:770 | 2 | lightRes.Y = 0; lightRes.Z = 0; + vmov $v01.e2, $v00.e0 ## L:769 | 3 | lightRes.y = 0; lightRes.z = 0; + vmov $v01.e5, $v00.e0 ## L:770 | 4 | lightRes.Y = 0; lightRes.Z = 0; + vmov $v01.e1, $v00.e0 ## L:769 | 5 | lightRes.y = 0; lightRes.z = 0; LABEL_pointLight_000C: - ldv $v23, 0, 8, $s3 ## L:697 | ^ | ptPos:sint.xyzw = load(ptrLight, 8).xyzw; - ldv $v23, 8, 8, $s3 ## L:698 | 30 | ptPos:sint.XYZW = load(ptrLight, 8).xyzw; - andi $t7, $t7, 32767 ## L:693 | ***34 | lightSize &= 0x7FFF; - vmudm $v23, $v23, $v31.e5 ## L:700 | ^ | ptPos = ptPos:sint >> 6; - vmadn $v24, $v00, $v00 ## L:700 | 35 | ptPos = ptPos:sint >> 6; - sll $t7, $t7, 16 ## L:694 | ^ | lightSize <<= 16; - vsubc $v24, $v24, $v28.v ## L:701 | ***39 | ptPos = ptPos - vertPos; - vsub $v23, $v23, $v27.v ## L:701 | 40 | ptPos = ptPos - vertPos; - vmudl $v29, $v24, $v24.v ## L:704 | **43 | lightVertDot = ptPos * ptPos; - vmadm $v29, $v23, $v24.v ## L:704 | 44 | lightVertDot = ptPos * ptPos; - vmadn $v22, $v24, $v23.v ## L:704 | 45 | lightVertDot = ptPos * ptPos; - vmadh $v21, $v23, $v23.v ## L:704 | 46 | lightVertDot = ptPos * ptPos; - vaddc $v26, $v22, $v22.h1 ## L:705 | **49 | mat1 = lightVertDot + lightVertDot.yyyyYYYY; - vadd $v25, $v21, $v21.h1 ## L:705 | 50 | mat1 = lightVertDot + lightVertDot.yyyyYYYY; - vaddc $v22, $v22, $v26.h2 ## L:706 | **53 | lightVertDot = lightVertDot + mat1.zzzzZZZZ; - mtc2 $t7, $v26.e3 ## L:708 | ^ | mat1.w = lightSize; - vadd $v21, $v21, $v25.h2 ## L:706 | 54 | lightVertDot = lightVertDot + mat1.zzzzZZZZ; - srl $at, $t7, 16 ## L:708 | ^ | mat1.w = lightSize; - vrsqh $v21.e0, $v21.e0 ## L:714 | ***58 | lightVertDot.x = invert_half_sqrt(lightVertDot).x; - lbu $t7, 14($s3) ## L:710 | ^ | lightSize:u8 = load(ptrLight, 14); - vrsql $v22.e0, $v22.e0 ## L:714 | 59 | lightVertDot.x = invert_half_sqrt(lightVertDot).x; - mtc2 $at, $v25.e3 ## L:708 | ^ | mat1.w = lightSize; - sra $t7, $t7, 7 ## L:711 | **62 | lightSize >>= 7; - vrsqh $v21.e0, $v21.e4 ## L:715 | ^ | lightVertDot.X = invert_half_sqrt(lightVertDot).X; - vrsql $v22.e4, $v22.e4 ## L:715 | 63 | lightVertDot.X = invert_half_sqrt(lightVertDot).X; - vrsqh $v21.e4, $v00.e0 ## L:715 | 64 | lightVertDot.X = invert_half_sqrt(lightVertDot).X; - vmudl $v29, $v22, $v26.e3 ## L:716 | **67 | lightRes = lightVertDot * mat1.w; - vmadm $v29, $v21, $v26.e3 ## L:716 | 68 | lightRes = lightVertDot * mat1.w; - vmadn $v29, $v22, $v25.e3 ## L:716 | 69 | lightRes = lightVertDot * mat1.w; - bne $t7, $zero, LABEL_pointLight_000D ## L:718 | ^ | if(!lightSize) { - vmadh $v01, $v21, $v25.e3 ## L:716 | *71 | lightRes = lightVertDot * mat1.w; - vmudn $v22, $v22, $v31.e7 ## L:721 | 72 | lightVertDot *= 256; - vmadh $v21, $v21, $v31.e7 ## L:721 | 73 | lightVertDot *= 256; - vmulf $v01, $v01, $v01.v ## L:723 | *75 | lightRes:sfract *= lightRes:sfract; - vmudl $v29, $v24, $v22.h0 ## L:725 | 76 | pos:sint = ptPos * lightVertDot.xxxxXXXX; - vmadm $v29, $v23, $v22.h0 ## L:725 | 77 | pos:sint = ptPos * lightVertDot.xxxxXXXX; - vmadn $v29, $v24, $v21.h0 ## L:725 | 78 | pos:sint = ptPos * lightVertDot.xxxxXXXX; - vmadh $v08, $v23, $v21.h0 ## L:725 | 79 | pos:sint = ptPos * lightVertDot.xxxxXXXX; - vmulf $v08, $v08, $v01.h0 ## L:726 | ***83 | pos:sfract *= lightRes:sfract.xxxxXXXX; - jr $ra - vmulf $v01, $v08, $v07.v ## L:729 | ***87 | lightRes = pos:sfract * norm:sfract; - LABEL_pointLight_000D: - vmulf $v01, $v01, $v01.v ## L:732 | *91 | lightRes:sfract *= lightRes:sfract; - vmov $v01.e5, $v00.e0 ## L:734 | 92 | lightRes.Y = 0; lightRes.Z = 0; - vmov $v01.e6, $v00.e0 ## L:734 | 93 | lightRes.Y = 0; lightRes.Z = 0; - vmov $v01.e2, $v00.e0 ## L:733 | 94 | lightRes.y = 0; lightRes.z = 0; - jr $ra ## L:735 | ^ | } - vmov $v01.e1, $v00.e0 ## L:733 | 95 | lightRes.y = 0; lightRes.z = 0; + jr $ra ## L:771 | *********************************************************************************87 | } loadCurrentMVPMat: ori $at, $zero, %lo(MATRIX_MVP) ldv $v28, 8, 8, $at @@ -550,19 +551,20 @@ loadCurrentMVPMat: ldv $v21, 8, 48, $at .align 3 T3DCmd_SetScreenSize: - srl $s7, $a0, 8 ## L:742 | ^ | u16 uvgenScaleFactor = guardBandFactor >> 8; - sh $a3, %lo(6 + NORM_SCALE_W)($zero) ## L:740 | 2 | store(depthAndWScale:s16, NORM_SCALE_W, 6); - andi $a0, $a0, 15 ## L:746 | 3 | guardBandFactor &= 0xF; - subu $s6, $zero, $a0 ## L:747 | 4 | s8 guardBandFactorNeg = ZERO - guardBandFactor; - sb $s6, %lo(19 + CLIPPING_PLANES)($zero) ## L:753 | 5 | store(guardBandFactorNeg, CLIPPING_PLANES, 19); - sh $s7, %lo(SCREEN_UVGEN_SCALE)($zero) ## L:743 | 6 | store(uvgenScaleFactor, SCREEN_UVGEN_SCALE); - sb $a0, %lo(7 + CLIPPING_PLANES)($zero) ## L:750 | 7 | store(guardBandFactor, CLIPPING_PLANES, 7); - sb $a0, %lo(3 + CLIPPING_PLANES)($zero) ## L:749 | 8 | store(guardBandFactor, CLIPPING_PLANES, 3); - sb $s6, %lo(15 + CLIPPING_PLANES)($zero) ## L:752 | 9 | store(guardBandFactorNeg, CLIPPING_PLANES, 15); - sw $a3, %lo(4 + SCREEN_SCALE_OFFSET)($zero) ## L:736 | 10 | store(depthAndWScale:u32, SCREEN_SCALE_OFFSET, 0x04); - sw $a2, %lo(0 + SCREEN_SCALE_OFFSET)($zero) ## L:737 | 11 | store(screenScaleXY, SCREEN_SCALE_OFFSET, 0x00); - j RSPQ_Loop ## L:754 | 12 | } - sw $a1, %lo(8 + SCREEN_SCALE_OFFSET)($zero) ## L:738 | *14 | store(screenOffsetXY, SCREEN_SCALE_OFFSET, 0x08); + ## hot-path cycles: 14 + lw $t5, %lo(RSPQ_DMEM_BUFFER -4)($gp) + lw $t4, %lo(RSPQ_DMEM_BUFFER -8)($gp) + srl $s7, $a3, 16 ## L:792 | 3 | u32 zScaleInt = depthAndWScale >> 16; + srl $s5, $a0, 8 ## L:802 | 4 | u16 uvgenScaleFactor = guardBandFactor >> 8; + sh $s7, %lo(4 + SCREEN_SCALE)($zero) ## L:793 | 5 | store(zScaleInt:u16, SCREEN_SCALE, 0x04); + srl $s6, $t5, 16 ## L:797 | 6 | u32 zScaleFrac = depthScaleFrac >> 16; + sw $a1, %lo(0 + SCREEN_OFFSET)($zero) ## L:795 | 7 | store(screenOffsetXY, SCREEN_OFFSET, 0x00); + sw $t4, %lo(8 + SCREEN_SCALE)($zero) ## L:796 | 8 | store(screenScaleXYFrac, SCREEN_SCALE, 0x08); + sh $s6, %lo(12 + SCREEN_SCALE)($zero) ## L:798 | 9 | store(zScaleFrac:u16, SCREEN_SCALE, 0x0C); + sh $a3, %lo(6 + NORM_SCALE_W)($zero) ## L:800 | 10 | store(depthAndWScale:s16, NORM_SCALE_W, 6); + sh $s5, %lo(SCREEN_UVGEN_SCALE)($zero) ## L:803 | 11 | store(uvgenScaleFactor, SCREEN_UVGEN_SCALE); + j RSPQ_Loop ## L:804 | 12 | + sw $a2, %lo(0 + SCREEN_SCALE)($zero) ## L:794 | *14 | store(screenScaleXY, SCREEN_SCALE, 0x00); T3DCmd_SetFogState: j RSPQ_Loop sb $a0, %lo(FOG_STORE_OFFSET)($zero) diff --git a/src/t3d/rsp/rsp_tiny3d.rspl b/src/t3d/rsp/rsp_tiny3d.rspl index 0507e451..feef95a7 100644 --- a/src/t3d/rsp/rsp_tiny3d.rspl +++ b/src/t3d/rsp/rsp_tiny3d.rspl @@ -80,13 +80,12 @@ state alignas(8) vec16 MATRIX_MV[4]; alignas(8) u16 MATRIX_NORMAL[3][4]; // fractional normal matrix - // Fog settings: index 0/1 is the scale as a s16.16, index 3 the scale as a s16 int. - // The third value is used as a limiter to prevent overflows. - s16 FOG_SCALE_OFFSET[4] = {0, 0, 32767, 0}; - - vec16 SCREEN_SCALE_OFFSET = { - 0, 0, 0, 0, // screen size scale (.xyzw) - 0, 0, 0x3FFF, 0x00FF // screen size offset (.XYZW), W is used for a fake clipping-code in 'triToScreenSpace' + // constants for T3DCmd_VertLoad + s16 VERT_CONSTS[8] = { + 0x8000, 0x8000, 0, 0x8000, // per-lane lower clamp of the screen-space vector (only relevant for Z) + 0x80FF, // upper clamp of fog value + 0x7FFF, // default light color when unlit + 0, 0 // (unused) }; vec16 NORMAL_MASK_SHIFT = { @@ -104,11 +103,19 @@ state // X Y Z | guard 1, 0, 0, 1, 0, 1, 0, 1, - 0, 0, 1, 1, + 0, 0, 0, 1, // near plane is ignored and sits at w=0 1, 0, 0, -1, 0, 1, 0, -1 }; + // s16.16 screen-size scale: int x,y,z,w | fract x,y,z,w. + // The w/W is the fog slope + alignas(8) s16 SCREEN_SCALE[8] = {0}; + + s16 SCREEN_OFFSET[4] = { + 0, 0, 0x3FFF, 0x80FF // screen size offset (.XYZ), W is the fog offset + }; + u16 RDPQ_TRI_BUFF_OFFSET = {0}; u16 SCREEN_UVGEN_SCALE = {0}; @@ -126,7 +133,7 @@ state u32 SEGMENT_TABLE[8] = {0}; // Lighting - u32 COLOR_AMBIENT[2] = {0xFFFFFFFF, 0xFFFFFFFF}; // RGBA8 (duplicated) | (saved IMEM) + u32 COLOR_AMBIENT[2] = {0xFFFFFFFF, 0xFFFFFFFF}; // RGBA8 (duplicated) alignas(4) u8 LIGHT_DIR_COLOR[LIGHT_SIZE][LIGHT_COUNT]; // RGBA8 (duplicated) | Direction packed as s8 (duplicated) // with profiling enabled, check assembly @@ -136,9 +143,11 @@ state u32 TRI_COMMAND = {0}; // for RDPQ_Triangle s32 MATRIX_STACK_PTR = {0}; // current matrix stack pointer in RDRAM, set once during init - u16 FOG_STORE_OFFSET = {TRI_SIZE_2}; // offset (relative to current vertex) where to store fog, set to 72 for no fog u8 FACE_CULLING = {0}; // 0=cull front, 1=cull back, 2=no-culling + // Note: accessed byte-wide (lbu/sb), must stay u8 (the shipped .S layout depends on it) + u8 FOG_STORE_OFFSET = {TRI_SIZE_2}; // offset (relative to current vertex) where to store fog, set to 72 for no fog u8 ACTIVE_LIGHT_SIZE = {0}; // light count * light size + u8 _UNUSED_ = {0}; u16 VERTEX_FX_FUNC = {0}; // points top the current 'VertexFX_' function in IMEM u16 CLIP_CODE_SIZE = {0}; // size to copy @@ -168,7 +177,7 @@ state * s16.16 | InvW | 0x20 * -------+-----------+-0x24--- */ - alignas(16) + alignas(8) u8 VERT_BUFFER[VERT_BUFFER_COUNT][TRI_SIZE]; } @@ -181,8 +190,9 @@ temp_state { // Last buffer where final clipping triangles are stored. // During clipping, vertices alternate between CLIP_BUFFER_TMP & B. + // For clipping: 7 is the maximum, 3 + one per plane. near-plane sits at w=0 and avoids an extra clip alignas(16) - u8 CLIP_BUFFER_RESULT[8][TRI_SIZE]; + u8 CLIP_BUFFER_RESULT[7][TRI_SIZE]; } #include "inc/math.rspl" @@ -201,21 +211,23 @@ macro dmaInAsync(u32 addrRDRAM, u32 addrDMEM, u32 size) @Barrier("DMA") set_dma_read(size); } -// Packs +xyz & -xyz into a single byte +// Packs the clipping code into a single byte: bit 0/1 = -x/-y, bit 3/4 = +x/+y (guard-band). +// Bit 2 (camera plane, w < 0) is left empty, clipping fills it in from the reject code. +// Current tile is stored in the 3 MSBs. macro packClipCode(u32 res, u32 clipCode) { - // Note: z-far is not clipped, only rejected - // instead the current tile is stored in the 3 MSB - res = clipCode & 0b0000'0011'0000'0111; + res = clipCode & 0b0000'0011'0000'0011; // +x,+y,-x,-y (the z lane is not a clipping plane) u32 tmp = res >> 5; // -zyx +xyx res |= tmp; } -// Same as packClipCode, inverts the clipcode to only use one operation later on +// Same for rejection, inverted (NOR) so the triangle code can AND the three bytes. +// Layout: bit 0/1 = -x/-y, bit 3 = w < 0 (camera plane, no near plane), +// bit 4/5 = +x/+y, bit 6 = far, bits 2/7 are always 1. macro packRejectCode(u32 res, u32 clipCode) { - res = clipCode & 0b0000'0111'0000'0111; - u32 tmp = res >> 5; // -zyx +xyx + res = clipCode & 0b0000'0111'0000'1011; + u32 tmp = res >> 4; // far,+y,+x w,-y,-x res = res ~| tmp; } @@ -244,6 +256,9 @@ macro resolveSegmentAddr(u32 addrOut, u32 addrIn) { addrOut = addrIn + segment; } +macro traceStart() { asm("andi $zero, $zero, 0"); } +macro traceEnd() { asm("andi $zero, $zero, 1"); } + #ifdef OVERLAY_CLIPPING #include "clipping.rspl" #else @@ -310,19 +325,20 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) vec16 normMask = load(NORMAL_MASK_SHIFT, 0x00).xyzwxyzw; vec16 normShift = load(NORMAL_MASK_SHIFT, 0x08).xyzwxyzw; + // lane w/W of the normal mask are zero and the matching normShift lanes are zero too, + // so the transformed normal ignores them: free to hold the fog slope's integer half + normMask.w = load(SCREEN_SCALE, 6).x; + normMask.W = load(SCREEN_SCALE, 6).x; - vec16 guardBandScale = load(CLIPPING_PLANES).xy; - guardBandScale = guardBandScale.y; - - vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - screenSize:sfract = 0; - screenSize >>= 8; + vec16 fogClampSlope; + fogClampSlope.x = load(VERT_CONSTS, 0x08).x; // fog upper clamp (0x80FF) + fogClampSlope.w = load(SCREEN_SCALE, 14).x; // fog slope, fractional + fogClampSlope.W = load(SCREEN_SCALE, 14).x; - vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - vec16 fogScaleOffset = load(FOG_SCALE_OFFSET).xyzw; - fogScaleOffset.Z = fogScaleOffset.z; + vec32 orgPosClip; - vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + vec16<$v12> screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + vec16<$v10> normScaleW = load(NORM_SCALE_W).xyzwxyzw; u32 ptrBuffA = addressInOut & 0xFFFF; // ptr to first output vertex u32 ptrBuffB = ptrBuffA - TRI_SIZE; // ptr to second output vertex @@ -333,7 +349,7 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) ptrLightEnd += LIGHT_DIR_COLOR; // Note: also loads COLOR_EXPOSURE into .z, and 0 into .w - vec16 uvGenArgs; + vec16<$v09> uvGenArgs; uvGenArgs.XYZW = load(UV_GEN_PARAMS).xyzw; uvGenArgs.W = load(SCREEN_UVGEN_SCALE).x; uvGenArgs.xy = load(UV_GEN_PARAMS).xy; @@ -342,13 +358,27 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) u8 fogStoreOffset = load(FOG_STORE_OFFSET); ptrBuffA -= TRI_SIZE_2; // move one back since it increments at the start of the loop - s16 fogA, fogB; + s16 fogA; + u16 ptrScreenScale = SCREEN_SCALE; u16 vertexFxFunc; + u8 isUnlit = load(TRI_COMMAND); + u32 ptrAmbient = COLOR_AMBIENT; + { + VTEMP = VZERO - 1; + store(VTEMP.xyzw, ptr3dEnd, 0); + } + if(isUnlit) { + ptrLightEnd = LIGHT_DIR_COLOR; + ptrAmbient = ptr3dEnd; + } + + undef isUnlit; undef dmaAddrRDRAM; undef addressInOut; + u8<$s0> baseTileMask = load(CLIP_CODE_ORG_ADDR); u8<$a2> baseTile; @@ -356,32 +386,41 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) dma_await(); // de-phased part of the loop to avoid stalls, this is also done at the end - vec16 pos = load(prt3d, 0x00); - vec16 norm = normMask & pos.wwwwWWWW; + vec16<$v08> pos = load(prt3d, 0x00); + + vec16<$v07> norm = normMask & pos.wwwwWWWW; norm *= normShift; - // Process all vertices and apply transformation & lighting. - // This always handles 2 vertices at once, most sitting in one register. + vec32<$v05> posClip; + vec16<$v04> color; + vec16<$v03> uv; + + goto LOOP_START; + + // end of loop, pulled up here to save a cycle with vertex-effects + LOOP_TRAIL: + store(uv.xy, ptrBuffA, VTX_ATTR_ST); + store(uv.zw, ptrBuffB, VTX_ATTR_ST); + if(prt3d == ptr3dEnd)goto RSPQ_Loop; + + LOOP_START: { - LOOP_START: // asm("emux_trace_start"); - // Position & Normals - vec32 posClip; - vec16 color; // loads 1.0 to force full light by default (aka unlit) // later the ambient light is loaded over this in case lighting is enabled - vec16 lightColor = fogScaleOffset.z; + vec16 lightColor; // Load the alpha value from the first vertex, which *may* contain the base-tile... baseTile = load(prt3d, 0x13); baseTile &= baseTileMask; //...now mask it away it that feature isn't enabled - u8 mvMatrixLoaded = 0; + u8<$t9> mvMatrixLoaded = 0; { ptrBuffA += TRI_SIZE_2; ptrBuffB += TRI_SIZE_2; vertexFxFunc = load(VERTEX_FX_FUNC); + fogA = ptrBuffA + fogStoreOffset; // load & transform normals, this in not needed when no directional light is present // however, an if-statement + the lost ability for reordering is not worth it. (@TODO: do more tests) @@ -390,27 +429,30 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) norm = matN2:sfract +* norm.zzzzZZZZ; // object-space to clip-space - mulMat4Vec3(mat0, mat1, mat2, mat3, pos, posClip); + mulMat4Vec3(mat0, mat1, mat2, mat3, pos, orgPosClip); ptrLight = LIGHT_DIR_COLOR; // directional - vec16 lightDirVec = load_vec_s8(ptrLight, 8); + vec16<$v02> lightDirVec = load_vec_s8(ptrLight, 8); u8 isPointLight = load(ptrLight, 15); // W=0 for directional, W=scale for point lights - s32 lightSize; + s32<$t7> lightSize; + + // light color, accumulates directional lights + // by default white to get the unlit flag to work + lightColor = load_vec_u8(ptrAmbient, 0); - if(isUnlit)goto LIGHT_LOOP_END; - lightColor = load_vec_u8(ptrLight, -8); // light color, accumulates directional lights + posClip = orgPosClip * normScaleW:ufract; if(ptrLight != ptrLightEnd) { loop { - vec16 lightDirScale = norm:sfract * lightDirVec:sfract; + vec16<$v01> lightDirScale = norm:sfract * lightDirVec:sfract; color = load_vec_u8(ptrLight); if(isPointLight) { - pointLight(ptrLight, mat0, mat1, mat2, mat3, pos, norm, + pointLight(ptrLight, ptrLightEnd, mat0, mat1, mat2, mat3, pos, norm, lightDirScale, color, mvMatrixLoaded, lightSize); } @@ -421,31 +463,29 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) VTEMP = color:ufract +* lightDirScale:ufract.yyyyYYYY; VTEMP = color:ufract +* lightDirScale:ufract.zzzzZZZZ; - lightColor:sint += VTEMP; // @TODO: pre-fill ACC with lightColor (didn't work as it got *0.99 each iter.) - ptrLight += LIGHT_SIZE; lightDirVec = load_vec_s8(ptrLight, 8); isPointLight = load(ptrLight, 15); - } while(ptrLight != ptrLightEnd) - } - LIGHT_LOOP_END: - } - vec32 clipPlaneW = guardBandScale * posClip.wwwwWWWW; + if(mvMatrixLoaded == ptrLight) { + loadCurrentMVPMat(mat0, mat1, mat2, mat3); + } - color = load_vec_u8(prt3d, 0x10); - fogA = ptrBuffA + fogStoreOffset; + lightColor:sint += VTEMP; // @TODO: pre-fill ACC with lightColor (didn't work as it got *0.99 each iter.) - if(mvMatrixLoaded) { - loadCurrentMVPMat(mat0, mat1, mat2, mat3); + } while(ptrLight != ptrLightEnd) + } } - + color = load_vec_u8(prt3d, 0x10); + // calc. clipping codes (rejection & clip-prevention) u32 clipCodeA, clipCodeB, rejCodesA, rejCodesB; { - u32 rejCodes = clip(posClip, posClip.wwwwWWWW); // Clip-Code for rejection (no band-guard) - u32 clipCodes = clip(posClip, clipPlaneW); // Clip code for clipping (incl. band-guard) + // posClip has x/y already divided by the guard-band factor + // (NORM_SCALE_W lanes x/y, compensated by SCREEN_SCALE) + u32 rejCodes = clip(orgPosClip, orgPosClip.wwwwWWWW); // Clip-Code for rejection (no band-guard) + u32 clipCodes = clip(posClip, orgPosClip.wwwwWWWW); // Clip code for clipping (incl. band-guard) clipCodeB = clipCodes >> 4; clipCodeA = packClipCode(clipCodes); @@ -458,77 +498,78 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) rejCodesA = packRejectCode(rejCodes); rejCodesB = packRejectCode(rejCodesB); } - undef clipPlaneW; - @Tag("LightMul") - color:sfract *= lightColor:ufract; + // Fog (lanes w/W): clipZ * slope + offset, taken from the clip-space Z as soon as it exists + // (could be done with the screen-space multiply in W, but it's faster here) + VTEMP:sint = screenOffset:sint * 1; // acc = offset << 16 + VTEMP:sint = fogClampSlope:ufract +* posClip:sint.zzzzZZZZ; // slopeFrac + vec16<$v01> fogV = normMask:sint +* posClip:sint.zzzzZZZZ; // slopeInt + fogV = min(fogV, fogClampSlope.xxxxxxxx); - posClip *= normScaleW:ufract; + vec32 invWRaw; // only needs lanes w/W + @Tag("LightMul") + color:sfract *= lightColor:ufract; color >>= 7; color:sint *= uvGenArgs:sint.Z; - @Barrier("color-fog") store_vec_u8(color.x, ptrBuffA, VTX_ATTR_RGBA); - @Barrier("color-fog") store_vec_u8(color.X, ptrBuffB, VTX_ATTR_RGBA); - - //undef lightColor; - store(posClip.xyzw, ptrBuffA, VTX_ATTR_CLIPPOSi); store(posClip.XYZW, ptrBuffB, VTX_ATTR_CLIPPOSi); undef lightColor; - // calc. inverse W, this is stored in an unused slot in screenSize to avoid stalls - screenSize.w = invert_half(posClip).w; - screenSize.W = invert_half(posClip).W; - - // backup clip-pos in case that clipping is required - // also store inv-W here (in place of W) - store(screenSize.w, ptrBuffA, VTX_ATTR_INVWi); - store(screenSize.W, ptrBuffB, VTX_ATTR_INVWi); + invWRaw.w = invert_half(posClip).w; + invWRaw.W = invert_half(posClip).W; - // Fog - { - vec32 fog; - // add offset, to avoid loads, int/fract are stored in the same vector - fog:ufract = posClip + fogScaleOffset:ufract.y; - fog:sint = posClip + fogScaleOffset.x; + // do one round of NR + vec32 invW; + invW:sfract = posClip * invWRaw.wwwwWWWW; // still x0.5 due to invert - posClip *= screenSize.wwwwWWWW; // (contains inverse W) + // d = 1 - t, computed as 0xFFFF - t (normScaleW lane z = 0xFFFF, x/y hold 1/guard-band) + // also avoids the later W=1 special case in the triangle code + VTEMP = normScaleW:ufract - invW:ufract.wwwwWWWW; + invW = invWRaw + invWRaw; // 2*y0 (lanes w/W) + invW *= VTEMP:ufract.zzzzZZZZ; // -> 0.5/w - fog:sint *= fogScaleOffset:sint.w; + store(invW.w, ptrBuffA, VTX_ATTR_INVWi); + store(invW.W, ptrBuffB, VTX_ATTR_INVWi); - posClip *= screenSize; + // perspective division + invW = posClip * invW.wwwwWWWW; + + orgPosClip = load(ptrScreenScale).xyzwxyzw; + posClip = invW * orgPosClip; + posClip:sint = screenOffset:sint +* 1; - VTEMP:sint = fogScaleOffset - fog:sint.zzzzZZZZ; - } + undef invW; - fogB = ptrBuffB + fogStoreOffset; + @Barrier("color-fog-a") store_vec_u8(color.x, ptrBuffA, VTX_ATTR_RGBA); + @Barrier("color-fog-b") store_vec_u8(color.X, ptrBuffB, VTX_ATTR_RGBA); - // save fog here, to make this branch-less, fogStoreOffset contains the offset to save it to. - // if enabled this points to alpha of VTX_ATTR_RGBA, otherwise to UVs which get overwritten later - posClip:sint = screenOffset:sint +* 1; + @Barrier("color-fog-a") store_byte_lo(fogV.w, fogA); + @Barrier("color-fog-b") store_byte_lo(fogV.W, fogA, TRI_SIZE); + undef fogV; - VTEMP <<= 1; - @Barrier("color-fog") store(VTEMP:sint.z, fogA); - @Barrier("color-fog") store(VTEMP:sint.Z, fogB); + uv = load(prt3d, 0x18).xyzw; - vec16 uv = load(prt3d, 0x18).xyzw; + //@Barrier("pos-cc") store(posClip:sint.xyzw, ptrBuffA, VTX_ATTR_XY); + //@Barrier("pos-cc") store(posClip:sint.XYZW, ptrBuffB, VTX_ATTR_XY); + store(posClip:sint.xy, ptrBuffA, VTX_ATTR_XY); + store(posClip:sint.z, ptrBuffA, VTX_ATTR_Z); - @Barrier("pos-cc") store(posClip:sint.xyzw, ptrBuffA, VTX_ATTR_XY); - @Barrier("pos-cc") store(posClip:sint.XYZW, ptrBuffB, VTX_ATTR_XY); + store(posClip:sint.XY, ptrBuffB, VTX_ATTR_XY); + store(posClip:sint.Z, ptrBuffB, VTX_ATTR_Z); - // pack the first clip-code to get rid of one save + have more SUs - @Barrier("pos-cc") store(clipCodeA:u8, ptrBuffA, VTX_ATTR_CLIPFLAGS); - @Barrier("pos-cc") store(rejCodesA:u8, ptrBuffA, VTX_ATTR_REJFLAGS); + store(clipCodeA:u8, ptrBuffA, VTX_ATTR_CLIPFLAGS); + store(rejCodesA:u8, ptrBuffA, VTX_ATTR_REJFLAGS); - @Barrier("pos-cc") store(clipCodeB:u8, ptrBuffB, VTX_ATTR_CLIPFLAGS); - @Barrier("pos-cc") store(rejCodesB:u8, ptrBuffB, VTX_ATTR_REJFLAGS); + store(clipCodeB:u8, ptrBuffB, VTX_ATTR_CLIPFLAGS); + store(rejCodesB:u8, ptrBuffB, VTX_ATTR_REJFLAGS); uv += uvGenArgs; pos = load(prt3d, 0x20); // load next pos - vec16 oldNorm = norm; + vec16<$v11> oldNorm = norm; norm = normMask & pos.wwwwWWWW; norm *= normShift; @@ -545,7 +586,7 @@ command<4> T3DCmd_VertLoad(u32 bufferSize, u32 rdramVerts, u32 addressInOut) @NoRegAlloc function pointLight( - u16<$s3> ptrLight, + u16<$s3> ptrLight, u8<$s2> ptrLightEnd, vec32<$v27> vertPos, vec32<$v25> mat1, vec32<$v23> ptPos, vec32<$v21> lightVertDot, vec16<$v08> pos, vec16<$v07> norm, vec16<$v01> lightRes, vec16<$v04> color, @@ -560,7 +601,7 @@ function pointLight( mulMat4Vec3(vertPos, mat1, ptPos, lightVertDot, pos, vertPos); vertPos >>= 4; - mvMatrixLoaded = 1; + mvMatrixLoaded = ptrLightEnd; } lightSize &= 0x7FFF; // MSB is "use-normal" flag @@ -624,26 +665,28 @@ function loadCurrentMVPMat(vec32<$v27> mat0, vec32<$v25> mat1, vec32<$v23> mat2, * @param screenScale screen-size * 2 * @param depthAndWScale fractional 16bit scales to normalize W and depth */ -command<1> T3DCmd_SetScreenSize(s8 guardBandFactor, u32 screenOffsetXY, u32 screenScaleXY, u32 depthAndWScale) +command<1> T3DCmd_SetScreenSize( + s8 guardBandFactor, u32 screenOffsetXY, u32 screenScaleXY, u32 depthAndWScale, + u32<$t4> screenScaleXYFrac, u32<$t5> depthScaleFrac +) { - store(depthAndWScale:u32, SCREEN_SCALE_OFFSET, 0x04); // (writes garbage into W, saves a shift) - store(screenScaleXY, SCREEN_SCALE_OFFSET, 0x00); - store(screenOffsetXY, SCREEN_SCALE_OFFSET, 0x08); + // scale is s16.16 (SCREEN_SCALE layout: int x,y,z,w | fract x,y,z,w) + // Only the z lane is written here: the w lanes of SCREEN_SCALE / SCREEN_OFFSET hold the fog + // slope/offset (t3d_fog_set_range) and must survive viewport changes. + u32 zScaleInt = depthAndWScale >> 16; + store(zScaleInt:u16, SCREEN_SCALE, 0x04); // z int scale + store(screenScaleXY, SCREEN_SCALE, 0x00); // x/y int scale + store(screenOffsetXY, SCREEN_OFFSET, 0x00); + store(screenScaleXYFrac, SCREEN_SCALE, 0x08); + u32 zScaleFrac = depthScaleFrac >> 16; + store(zScaleFrac:u16, SCREEN_SCALE, 0x0C); // z fract scale store(depthAndWScale:s16, NORM_SCALE_W, 6); u16 uvgenScaleFactor = guardBandFactor >> 8; store(uvgenScaleFactor, SCREEN_UVGEN_SCALE); - // guard-band multiplier (W value of the clipping plane, integer) - guardBandFactor &= 0xF; - s8 guardBandFactorNeg = ZERO - guardBandFactor; - store(guardBandFactor, CLIPPING_PLANES, 3); // +X Plane - store(guardBandFactor, CLIPPING_PLANES, 7); // +Y Plane - //store(guardBandFactor, CLIPPING_PLANES, 11); // +Z Plane - store(guardBandFactorNeg, CLIPPING_PLANES, 15); // -X Plane - store(guardBandFactorNeg, CLIPPING_PLANES, 19); // -Y Plane } /** diff --git a/src/t3d/rsp/rsp_tiny3d_clipping.S b/src/t3d/rsp/rsp_tiny3d_clipping.S index c841a57c..1c225745 100644 --- a/src/t3d/rsp/rsp_tiny3d_clipping.S +++ b/src/t3d/rsp/rsp_tiny3d_clipping.S @@ -30,6 +30,9 @@ #define DRAW_TRIS 1 #define DP_STATUS_END_VALID 512 #define RDPQ_DYNAMIC_BUFFER_SIZE 65536 +#define CLIP_BUFFER_XOR 0x100 +#define CLIP_BUFFER_SIZE 252 +#define CLIP_FAN_ASYNC_MAX_SIZE 145 #include #include #include "./rspq_triangle.inc" @@ -134,13 +137,15 @@ .align 3 MATRIX_NORMAL: .ds.b 24 .align 1 - FOG_SCALE_OFFSET: .half 0, 0, 32767, 0 - .align 4 - SCREEN_SCALE_OFFSET: .half 0, 0, 0, 0, 0, 0, 16383, 255 + VERT_CONSTS: .half 32768, 32768, 0, 32768, 33023, 32767, 0, 0 .align 4 NORMAL_MASK_SHIFT: .half 63488, 2016, 31, 0, 1, 32, 2048, 0 .align 3 - CLIPPING_PLANES: .byte 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, -1, 0, 1, 0, -1 + CLIPPING_PLANES: .byte 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1, 0, 1, 0, -1 + .align 3 + SCREEN_SCALE: .half 0, 0, 0, 0, 0, 0, 0, 0 + .align 1 + SCREEN_OFFSET: .half 0, 0, 16383, 33023 .align 1 RDPQ_TRI_BUFF_OFFSET: .half 0 .align 1 @@ -156,14 +161,9 @@ .align 2 SEGMENT_TABLE: .word 0, 0, 0, 0, 0, 0, 0, 0 .align 2 - COLOR_AMBIENT: .ds.b 8 + COLOR_AMBIENT: .word 4294967295, 4294967295 .align 2 - #if RSPQ_PROFILE - LIGHT_DIR_COLOR: .ds.b 32 - _RSPQ_OVL_PROFILESLOT: .long 0, 0 - #else LIGHT_DIR_COLOR: .ds.b 112 - #endif .align 2 TRI_COMMAND: .word 0 .align 2 @@ -190,11 +190,7 @@ .align 4 CLIP_BUFFER_TMP: .ds.b 252 .align 4 - #if RSPQ_PROFILE - CLIP_BUFFER_RESULT: .ds.b 272 - #else - CLIP_BUFFER_RESULT: .ds.b 288 - #endif + CLIP_BUFFER_RESULT: .ds.b 252 TEMP_STATE_MEM_END: .text @@ -202,254 +198,301 @@ OVERLAY_CODE_START: .align 3 clipTriangle: - ldv $v02, 0, 8, $a0 ## L:536 | ^ | vec16 tmp2 = load(ptrSrc, 0x08).xyzw; - ldv $v01, 0, 0, $a0 ## L:535 | 2 | vec16 tmp1 = load(ptrSrc, 0x00).xyzw; - ldv $v04, 0, 24, $a0 ## L:538 | 3 | vec16 tmp4 = load(ptrSrc, 0x18).xyzw; - ldv $v03, 0, 16, $a0 ## L:537 | 4 | vec16 tmp3 = load(ptrSrc, 0x10).xyzw; - ori $t3, $zero, %lo(CLIP_BUFFER_TMP) ## L:402 | 5 | u32 ptrWrite = CLIP_BUFFER_TMP; - ori $at, $zero, %lo(NORM_SCALE_W) ## L:421 | 6 | normScaleWInv.x = load(NORM_SCALE_W).w; - sdv $v01, 0, 0, $t3 ## L:540 | 7 | store(tmp1.xyzw, ptrDst, 0x00); - sdv $v02, 0, 8, $t3 ## L:541 | 8 | store(tmp2.xyzw, ptrDst, 0x08); - sdv $v04, 0, 24, $t3 ## L:543 | 9 | store(tmp4.xyzw, ptrDst, 0x18); - sdv $v03, 0, 16, $t3 ## L:542 | 10 | store(tmp3.xyzw, ptrDst, 0x10); - ldv $v01, 0, 0, $a1 ## L:535 | 11 | vec16 tmp1 = load(ptrSrc, 0x00).xyzw; - ldv $v03, 0, 16, $a1 ## L:537 | 12 | vec16 tmp3 = load(ptrSrc, 0x10).xyzw; - ldv $v02, 0, 8, $a1 ## L:536 | 13 | vec16 tmp2 = load(ptrSrc, 0x08).xyzw; - ldv $v04, 0, 24, $a1 ## L:538 | 14 | vec16 tmp4 = load(ptrSrc, 0x18).xyzw; - addiu $t3, $t3, 36 ## L:545 | 15 | ptrDst += 36; - ori $t1, $zero, %lo(CLIP_BUFFER_RESULT) ## L:400 | 16 | u32 ptrBuff0 = CLIP_BUFFER_RESULT; - sdv $v03, 0, 16, $t3 ## L:542 | 17 | store(tmp3.xyzw, ptrDst, 0x10); - sdv $v04, 0, 24, $t3 ## L:543 | 18 | store(tmp4.xyzw, ptrDst, 0x18); - sdv $v02, 0, 8, $t3 ## L:541 | 19 | store(tmp2.xyzw, ptrDst, 0x08); - sdv $v01, 0, 0, $t3 ## L:540 | 20 | store(tmp1.xyzw, ptrDst, 0x00); - ldv $v04, 0, 24, $a2 ## L:538 | 21 | vec16 tmp4 = load(ptrSrc, 0x18).xyzw; - ldv $v01, 0, 0, $a2 ## L:535 | 22 | vec16 tmp1 = load(ptrSrc, 0x00).xyzw; - ori $t4, $zero, %lo(CLIPPING_PLANES) ## L:411 | 23 | u32 planePtr = CLIPPING_PLANES; - addiu $t3, $t3, 36 ## L:545 | 24 | ptrDst += 36; - ldv $v03, 0, 16, $a2 ## L:537 | 25 | vec16 tmp3 = load(ptrSrc, 0x10).xyzw; - sdv $v01, 0, 0, $t3 ## L:540 | 26 | store(tmp1.xyzw, ptrDst, 0x00); - lbu $t6, 6($a0) ## L:416 | 27 | u8 oldClip = load(ptrVertA, 0x06); - lsv $v01, 0, 6, $at ## L:421 | 28 | normScaleWInv.x = load(NORM_SCALE_W).w; - ldv $v02, 0, 8, $a2 ## L:536 | 29 | vec16 tmp2 = load(ptrSrc, 0x08).xyzw; - addiu $t5, $zero, 1 ## L:412 | 30 | s32 planeIdx = 1; - ori $at, $zero, 0xFFFF ## L:423 | 31 | normScaleWInv.w = 0xFFFF; - sdv $v04, 0, 24, $t3 ## L:543 | 32 | store(tmp4.xyzw, ptrDst, 0x18); - vor $v01, $v00, $v01.e0 ## L:422 | ^ | normScaleWInv = normScaleWInv.x; - mtc2 $at, $v01.e3 ## L:423 | 33 | normScaleWInv.w = 0xFFFF; - mtc2 $at, $v01.e7 ## L:424 | 34 | normScaleWInv.W = 0xFFFF; - ori $at, $zero, %lo(CLIPPING_PLANES) ## L:426 | 35 | vec16 guardBandScale = load(CLIPPING_PLANES).xy; - ori $t2, $zero, %lo(CLIP_BUFFER_TMP) ## L:401 | 36 | u32 ptrBuff1 = CLIP_BUFFER_TMP; - sdv $v02, 0, 8, $t3 ## L:541 | 37 | store(tmp2.xyzw, ptrDst, 0x08); - llv $v02, 0, 0, $at ## L:426 | 38 | vec16 guardBandScale = load(CLIPPING_PLANES).xy; - sb $t6, %lo(20 + RSPQ_SCRATCH_MEM)($zero) ## L:417 | 39 | store(oldClip, RSPQ_SCRATCH_MEM, 20); - addiu $t0, $zero, 108 ## L:396 | 40 | arraySize = 108; - sdv $v03, 0, 16, $t3 ## L:542 | 41 | store(tmp3.xyzw, ptrDst, 0x10); - addiu $t3, $t3, 36 ## L:545 | 42 | ptrDst += 36; - vor $v02, $v00, $v02.e1 ## L:427 | ^ | guardBandScale = guardBandScale.y; + ## hot-path cycles: 265 + ori $t2, $zero, %lo(CLIP_BUFFER_RESULT) ## L:426 | ^ | u32 ptrBuff1 = CLIP_BUFFER_RESULT; + ldv $v02, 0, 8, $a0 ## L:646 | 2 | vec16 tmp2 = load(ptrSrc, 0x08).xyzw; + ldv $v01, 0, 0, $a0 ## L:645 | 3 | vec16 tmp1 = load(ptrSrc, 0x00).xyzw; + addiu $t2, $t2, 252 ## L:427 | 4 | ptrBuff1 += 252; + lui $t1, 0x9669 ## L:422 | 5 | u32 parity = 0x96696996; + ori $t1, $t1, 0x6996 ## L:422 | 6 | u32 parity = 0x96696996; + srl $t4, $t4, 8 ## L:418 | 7 | clipMask >>= 8; + srlv $t1, $t1, $t4 ## L:423 | 8 | parity >>= clipMask; + andi $t1, $t1, 1 ## L:424 | 9 | parity &= 1; + ldv $v03, 0, 16, $a0 ## L:647 | 10 | vec16 tmp3 = load(ptrSrc, 0x10).xyzw; + sll $t1, $t1, 8 ## L:425 | 11 | parity <<= 8; + subu $t2, $t2, $t1 ## L:428 | 12 | ptrBuff1 -= parity; + ldv $v04, 0, 24, $a0 ## L:648 | 13 | vec16 tmp4 = load(ptrSrc, 0x18).xyzw; + or $t3, $zero, $t2 ## L:429 | 14 | u32 ptrWrite = ptrBuff1; + addiu $t3, $t3, 65500 ## L:644 | 15 | ptrDst -= 36; + sdv $v03, 0, 16, $t3 ## L:652 | 16 | store(tmp3.xyzw, ptrDst, 0x10); + ori $at, $zero, %lo(NORM_SCALE_W) ## L:448 | 17 | normScaleWInv.x = load(NORM_SCALE_W).w; + sdv $v01, 0, 0, $t3 ## L:650 | 18 | store(tmp1.xyzw, ptrDst, 0x00); + sdv $v04, 0, 24, $t3 ## L:653 | 19 | store(tmp4.xyzw, ptrDst, 0x18); + sdv $v02, 0, 8, $t3 ## L:651 | 20 | store(tmp2.xyzw, ptrDst, 0x08); + ldv $v03, 0, 16, $a1 ## L:647 | 21 | vec16 tmp3 = load(ptrSrc, 0x10).xyzw; + ldv $v02, 0, 8, $a1 ## L:646 | 22 | vec16 tmp2 = load(ptrSrc, 0x08).xyzw; + ldv $v01, 0, 0, $a1 ## L:645 | 23 | vec16 tmp1 = load(ptrSrc, 0x00).xyzw; + ldv $v04, 0, 24, $a1 ## L:648 | 24 | vec16 tmp4 = load(ptrSrc, 0x18).xyzw; + ori $t5, $zero, %lo(CLIPPING_PLANES) ## L:438 | 25 | u32 planePtr = CLIPPING_PLANES; + addiu $t3, $t3, 65500 ## L:644 | 26 | ptrDst -= 36; + sdv $v02, 0, 8, $t3 ## L:651 | 27 | store(tmp2.xyzw, ptrDst, 0x08); + sdv $v04, 0, 24, $t3 ## L:653 | 28 | store(tmp4.xyzw, ptrDst, 0x18); + sdv $v01, 0, 0, $t3 ## L:650 | 29 | store(tmp1.xyzw, ptrDst, 0x00); + sdv $v03, 0, 16, $t3 ## L:652 | 30 | store(tmp3.xyzw, ptrDst, 0x10); + ldv $v02, 0, 8, $a2 ## L:646 | 31 | vec16 tmp2 = load(ptrSrc, 0x08).xyzw; + ldv $v04, 0, 24, $a2 ## L:648 | 32 | vec16 tmp4 = load(ptrSrc, 0x18).xyzw; + ldv $v01, 0, 0, $a2 ## L:645 | 33 | vec16 tmp1 = load(ptrSrc, 0x00).xyzw; + ldv $v03, 0, 16, $a2 ## L:647 | 34 | vec16 tmp3 = load(ptrSrc, 0x10).xyzw; + addiu $t3, $t3, 65500 ## L:644 | 35 | ptrDst -= 36; + lbu $t7, 6($a0) ## L:443 | 36 | u8 oldClip = load(ptrVertA, 0x06); + sdv $v01, 0, 0, $t3 ## L:650 | 37 | store(tmp1.xyzw, ptrDst, 0x00); + lsv $v01, 0, 6, $at ## L:448 | 38 | normScaleWInv.x = load(NORM_SCALE_W).w; + sdv $v02, 0, 8, $t3 ## L:651 | 39 | store(tmp2.xyzw, ptrDst, 0x08); + vsubc $v02, $v00, $v30.e7 ## L:456 | ^ | vec16 uvIntMask = VZERO - 1; + ori $at, $zero, 0xFFFF ## L:450 | 40 | normScaleWInv.w = 0xFFFF; + sb $t7, %lo(20 + RSPQ_SCRATCH_MEM)($zero) ## L:444 | 41 | store(oldClip, RSPQ_SCRATCH_MEM, 20); + sdv $v04, 0, 24, $t3 ## L:653 | 42 | store(tmp4.xyzw, ptrDst, 0x18); + vor $v01, $v00, $v01.e0 ## L:449 | ^ | normScaleWInv = normScaleWInv.x; + mtc2 $at, $v01.e3 ## L:450 | 43 | normScaleWInv.w = 0xFFFF; + ori $at, $zero, 0xFFFF ## L:451 | 44 | normScaleWInv.W = 0xFFFF; + addiu $t0, $zero, 108 ## L:412 | 45 | arraySize = 108; + addiu $t6, $zero, 1 ## L:439 | 46 | s32 planeIdx = 1; + mtc2 $at, $v01.e7 ## L:451 | 47 | normScaleWInv.W = 0xFFFF; + sdv $v03, 0, 16, $t3 ## L:652 | 48 | store(tmp3.xyzw, ptrDst, 0x10); + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:457 | 49 | uvIntMask.XYZW = VZERO.xyzw; ## Barrier: 0x1 + sdv $v00, 0, 0, $at ## L:457 | 50 | uvIntMask.XYZW = VZERO.xyzw; ## Barrier: 0x1 + vor $v03, $v00, $v00 ## L:458 | ^ | vec16 uvBias = VZERO; + vmov $v03.e4, $v31.e0 ## L:459 | 51 | uvBias.X = 0x8000; + ldv $v02, 8, 0, $at ## L:457 | ^ | uvIntMask.XYZW = VZERO.xyzw; ## Barrier: 0x1 + vmov $v03.e5, $v31.e0 ## L:460 | 52 | uvBias.Y = 0x8000; LABEL_clipTriangle_0001: - xor $t1, $t1, $t2 ## L:442 | 43 | swap(ptrBuff0, ptrBuff1); - xor $t2, $t1, $t2 ## L:442 | 44 | swap(ptrBuff0, ptrBuff1); - addiu $t6, $t3, 65500 ## L:433 | 45 | u32 ptrLast = ptrWrite - 36; - ldv $v04, 0, 16, $t6 ## L:436 | 46 | vec32 lastPosUV = load(ptrLast, 0x10).xyzw; - xor $t1, $t1, $t2 ## L:442 | 47 | swap(ptrBuff0, ptrBuff1); - luv $v03, 0, 8, $t6 ## L:435 | 48 | vec16 lastColor = load_vec_u8(ptrLast, 0x08); - lbu $t7, 6($t6) ## L:438 | 49 | u8 lastClipCode = load(ptrLast, 0x06); - ldv $v05, 0, 24, $t6 ## L:436 | 50 | vec32 lastPosUV = load(ptrLast, 0x10).xyzw; - or $t3, $zero, $t2 ## L:444 | 51 | ptrWrite = ptrBuff1; - llv $v04, 8, 12, $t6 ## L:437 | 52 | lastPosUV:sint.XY = load(ptrLast, 0x0C).xy; - addu $t8, $t1, $t0 ## L:446 | 53 | u32 ptrReadEnd = ptrBuff0 + arraySize; - or $t6, $zero, $t1 ## L:445 | 54 | u32 ptrRead = ptrBuff0; - LABEL_clipTriangle_0003: - lbu $t9, 6($t6) ## L:455 | 55 | u8 clipCode = load(ptrRead, 0x06); - luv $v08, 0, 8, $t6 ## L:453 | 56 | vec16 currentColor = load_vec_u8(ptrRead, 0x08); - ldv $v07, 0, 24, $t6 ## L:451 | 57 | vec32 currentPosUV = load(ptrRead, 0x10).xyzw; - nor $k1, $zero, $t9 ## L:459 | 58 | u8 isInsideCurr = ~clipCode; - xor $k0, $t9, $t7 ## L:458 | 59 | u8 exclIntersect = clipCode ^ lastClipCode; - ldv $v06, 0, 16, $t6 ## L:451 | 60 | vec32 currentPosUV = load(ptrRead, 0x10).xyzw; - and $k0, $k0, $t5 ## L:460 | 61 | exclIntersect &= planeIdx; - and $k1, $k1, $t5 ## L:461 | 62 | isInsideCurr &= planeIdx; - beq $k0, $zero, LABEL_clipTriangle_0005 ## L:463 | 63 | if(exclIntersect) - llv $v06, 8, 12, $t6 ## L:452 | *65 | currentPosUV:sint.XY = load(ptrRead, 0x0C).xy; - lpv $v14, 0, 0, $t4 ## L:313 | 66 | vec32 planeNorm:sint = load_vec_s8(planePtr); - and $t7, $t7, $t5 ## L:465 | 67 | lastClipCode &= planeIdx; - beq $t7, $zero, LABEL_clipTriangle_0006 ## L:318 | 68 | if(newClipCode) - nop ## L:318 | *70 | if(newClipCode) - ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:320 | 71 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 - vsubc $v10, $v05, $v07.v ## L:323 | ^ | posUVDiff = posBase - pos; - sdv $v14, 0, 0, $at ## L:320 | 72 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 - vxor $v15, $v00, $v00.e0 ## L:321 | ^ | planeNorm:sfract = 0; - vsub $v09, $v04, $v06.v ## L:323 | 73 | posUVDiff = posBase - pos; - ldv $v14, 8, 0, $at ## L:320 | ^ | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 - sdv $v04, 0, 0, $at ## L:325 | 74 | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 - vor $v12, $v00, $v07 ## L:324 | ^ | vpos = pos; - sdv $v05, 0, 8, $at ## L:325 | *76 | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 - vor $v11, $v00, $v06 ## L:324 | ^ | vpos = pos; - ldv $v11, 8, 0, $at ## L:325 | 77 | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 - vmudl $v15, $v15, $v31.e7 ## L:326 | ^ | planeNorm >>= 8; - vmadm $v14, $v14, $v31.e7 ## L:326 | 78 | planeNorm >>= 8; - ldv $v12, 8, 8, $at ## L:325 | ^ | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 - vmadn $v15, $v00, $v00 ## L:326 | 79 | planeNorm >>= 8; - beq $zero, $zero, LABEL_clipTriangle_0007 ## L:328 | ^ | colorDiff = colorBase - color; - vsubc $v13, $v03, $v08.v ## L:328 | *81 | colorDiff = colorBase - color; - LABEL_clipTriangle_0006: - ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:330 | 82 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 - vor $v11, $v00, $v04 ## L:334 | ^ | vpos = posBase; - sdv $v14, 0, 0, $at ## L:330 | 83 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 - vxor $v15, $v00, $v00.e0 ## L:331 | ^ | planeNorm:sfract = 0; - vor $v12, $v00, $v05 ## L:334 | 84 | vpos = posBase; - ldv $v14, 8, 0, $at ## L:330 | ^ | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 - vsubc $v10, $v07, $v05.v ## L:333 | 85 | posUVDiff = pos - posBase; - sdv $v06, 0, 0, $at ## L:335 | ^ | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 - vsub $v09, $v06, $v04.v ## L:333 | 86 | posUVDiff = pos - posBase; - vmudl $v15, $v15, $v31.e7 ## L:336 | 87 | planeNorm >>= 8; - vmadm $v14, $v14, $v31.e7 ## L:336 | 88 | planeNorm >>= 8; - vmadn $v15, $v00, $v00 ## L:336 | 89 | planeNorm >>= 8; - sdv $v07, 0, 8, $at ## L:335 | ^ | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 - vsubc $v13, $v08, $v03.v ## L:338 | 90 | colorDiff = color - colorBase; - ldv $v11, 8, 0, $at ## L:335 | ^ | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 - ldv $v12, 8, 8, $at ## L:335 | **93 | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 + and $t7, $t4, $t6 ## L:466 | ^ | u32 planeActive = clipMask & planeIdx; + beq $t7, $zero, LABEL_clipTriangle_0003 ## L:467 | 53 | if(planeActive) + nop ## L:467 | 54 | if(planeActive) + vmudl $v05, $v00, $v31.e7 ## L:475 | 55 | planeNorm >>= 8; + lpv $v04, 0, 0, $t5 ## L:472 | ^ | vec32 planeNorm:sint = load_vec_s8(planePtr); + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:473 | 56 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 + or $t8, $zero, $t3 ## L:478 | 57 | u32 ptrLast = ptrWrite; + llv $v08, 8, 12, $t8 ## L:482 | 58 | lastPosUV:sfract.XY = load(ptrLast, 0x0C).xy; + sdv $v04, 0, 0, $at ## L:473 | 59 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 + ldv $v04, 8, 0, $at ## L:473 | 60 | planeNorm:sint.XYZW = planeNorm:sint.xyzw; ## Barrier: 0x1 + ldv $v07, 0, 16, $t8 ## L:481 | 61 | vec32 lastPosUV = load(ptrLast, 0x10).xyzw; + ldv $v08, 0, 24, $t8 ## L:481 | 62 | vec32 lastPosUV = load(ptrLast, 0x10).xyzw; + luv $v06, 0, 8, $t8 ## L:480 | *64 | vec16 lastColor = load_vec_u8(ptrLast, 0x08); + vmadm $v04, $v04, $v31.e7 ## L:475 | ^ | planeNorm >>= 8; + vmadn $v05, $v00, $v00 ## L:475 | 65 | planeNorm >>= 8; + lbu $t9, 6($t8) ## L:485 | ^ | u8 lastClipCode = load(ptrLast, 0x06); + xor $t4, $t4, $t6 ## L:469 | 66 | clipMask ^= planeIdx; + vxor $v08, $v08, $v03.v ## L:484 | ^ | lastPosUV:sfract ^= uvBias; + xori $t2, $t2, 256 ## L:489 | 67 | ptrBuff1 ^= 0x100; + or $t3, $zero, $t2 ## L:491 | 68 | ptrWrite = ptrBuff1; + vand $v07, $v07, $v02.v ## L:483 | ^ | lastPosUV:sint &= uvIntMask; + vmudl $v05, $v05, $v01.v ## L:476 | 69 | planeNorm *= normScaleWInv:ufract; + xori $t8, $t2, 256 ## L:492 | ^ | u32 ptrRead = ptrBuff1 ^ 0x100; + subu $k0, $t8, $t0 ## L:493 | 70 | u32 ptrReadEnd = ptrRead - arraySize; + vmadm $v04, $v04, $v01.v ## L:476 | ^ | planeNorm *= normScaleWInv:ufract; + vmadn $v05, $v00, $v00 ## L:476 | 71 | planeNorm *= normScaleWInv:ufract; + LABEL_clipTriangle_0004: + addiu $t8, $t8, 65500 ## L:498 | ^ | ptrRead -= 36; + llv $v10, 8, 12, $t8 ## L:500 | 72 | currentPosUV:sfract.XY = load(ptrRead, 0x0C).xy; + ldv $v09, 0, 16, $t8 ## L:499 | 73 | vec32 currentPosUV = load(ptrRead, 0x10).xyzw; + lbu $k1, 6($t8) ## L:505 | 74 | u8 clipCode = load(ptrRead, 0x06); + ldv $v10, 0, 24, $t8 ## L:499 | 75 | vec32 currentPosUV = load(ptrRead, 0x10).xyzw; + luv $v11, 0, 8, $t8 ## L:503 | 76 | vec16 currentColor = load_vec_u8(ptrRead, 0x08); + xor $sp, $k1, $t9 ## L:508 | 77 | u8 exclIntersect = clipCode ^ lastClipCode; + and $sp, $sp, $t6 ## L:510 | 78 | exclIntersect &= planeIdx; + vand $v09, $v09, $v02.v ## L:501 | ^ | currentPosUV:sint &= uvIntMask; + nor $fp, $zero, $k1 ## L:509 | 79 | u8 isInsideCurr = ~clipCode; + vxor $v10, $v10, $v03.v ## L:502 | ^ | currentPosUV:sfract ^= uvBias; + beq $sp, $zero, LABEL_clipTriangle_0006 ## L:513 | 80 | if(exclIntersect) + and $fp, $fp, $t6 ## L:511 | 81 | isInsideCurr &= planeIdx; + and $t9, $t9, $t6 ## L:515 | 82 | lastClipCode &= planeIdx; + beq $t9, $zero, LABEL_clipTriangle_0007 ## L:340 | 83 | if(newClipCode) + nop ## L:340 | 84 | if(newClipCode) + vor $v15, $v00, $v10 ## L:343 | 85 | vpos = pos; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:344 | ^ | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 + sdv $v07, 0, 0, $at ## L:344 | 86 | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 + vor $v14, $v00, $v09 ## L:343 | ^ | vpos = pos; + vsubc $v13, $v08, $v10.v ## L:342 | 87 | posUVDiff = posBase - pos; + sdv $v08, 0, 8, $at ## L:344 | ^ | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 + ldv $v14, 8, 0, $at ## L:344 | 88 | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 + vsub $v12, $v07, $v09.v ## L:342 | ^ | posUVDiff = posBase - pos; + ldv $v15, 8, 8, $at ## L:344 | 89 | vpos.XYZW = posBase.xyzw; ## Barrier: 0x1 + beq $zero, $zero, LABEL_clipTriangle_0008 ## L:345 | 90 | colorDiff = colorBase - color; + vsubc $v16, $v06, $v11.v ## L:345 | *92 | colorDiff = colorBase - color; LABEL_clipTriangle_0007: - vmudl $v15, $v15, $v01.v ## L:341 | ^ | planeNorm *= normScaleWInv:ufract; - vmadm $v14, $v14, $v01.v ## L:341 | 94 | planeNorm *= normScaleWInv:ufract; - vmadn $v15, $v00, $v00 ## L:341 | 95 | planeNorm *= normScaleWInv:ufract; - vmudl $v29, $v12, $v15.v ## L:212 | ***99 | res = a * b; - vmadm $v29, $v11, $v15.v ## L:212 | 100 | res = a * b; - vmadn $v17, $v12, $v14.v ## L:212 | 101 | res = a * b; - vmadh $v16, $v11, $v14.v ## L:212 | 102 | res = a * b; - vaddc $v17, $v17, $v17.q1 ## L:213 | **105 | res += res.yywwYYWW; - vadd $v16, $v16, $v16.q1 ## L:213 | 106 | res += res.yywwYYWW; - vaddc $v17, $v17, $v17.h2 ## L:214 | **109 | res += res.zzzzZZZZ; - vadd $v16, $v16, $v16.h2 ## L:214 | 110 | res += res.zzzzZZZZ; - vsubc $v19, $v17, $v17.e4 ## L:344 | **113 | vec32 fac = dot - dot.X; - vsub $v18, $v16, $v16.e4 ## L:344 | 114 | vec32 fac = dot - dot.X; - vrcph $v18.e0, $v18.e0 ## L:346 | ***118 | fac.x = invert_half(fac).x; - vrcpl $v19.e0, $v19.e0 ## L:346 | 119 | fac.x = invert_half(fac).x; - vrcph $v18.e0, $v00.e0 ## L:346 | 120 | fac.x = invert_half(fac).x; - vaddc $v19, $v19, $v19.v ## L:347 | **123 | fac += fac; - vadd $v18, $v18, $v18.v ## L:347 | 124 | fac += fac; - vmudl $v29, $v19, $v17.e0 ## L:348 | **127 | fac *= dot.x; - vmadm $v29, $v18, $v17.e0 ## L:348 | 128 | fac *= dot.x; - vmadn $v19, $v19, $v16.e0 ## L:348 | 129 | fac *= dot.x; - vmadh $v18, $v18, $v16.e0 ## L:348 | 130 | fac *= dot.x; - mfc2 $sp, $v18.e0 ## L:350 | ***134 | s16 facX = fac:sint.x; - beq $sp, $zero, LABEL_clipTriangle_0008 ## L:351 | **137 | if(facX != 0) { - nop ## L:351 | *139 | if(facX != 0) { - vlt $v29, $v18, $v30.e7 ## L:355 | 140 | fac:ufract = fac:sint < 1 ? fac:ufract : normScaleWInv:ufract.w; - vmrg $v19, $v19, $v01.e3 ## L:355 | 141 | fac:ufract = fac:sint < 1 ? fac:ufract : normScaleWInv:ufract.w; - vge $v29, $v18, $v00.e0 ## L:356 | 142 | fac:ufract = fac:sint >= 0 ? fac:ufract : VZERO; - vmrg $v19, $v19, $v00 ## L:356 | **145 | fac:ufract = fac:sint >= 0 ? fac:ufract : VZERO; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:349 | 1 | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 + vsubc $v13, $v10, $v08.v ## L:347 | ^ | posUVDiff = pos - posBase; + vor $v14, $v00, $v07 ## L:348 | 2 | vpos = posBase; + sdv $v09, 0, 0, $at ## L:349 | ^ | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 + vsub $v12, $v09, $v07.v ## L:347 | 3 | posUVDiff = pos - posBase; + sdv $v10, 0, 8, $at ## L:349 | ^ | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 + vor $v15, $v00, $v08 ## L:348 | 4 | vpos = posBase; + ldv $v14, 8, 0, $at ## L:349 | ^ | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 + ldv $v15, 8, 8, $at ## L:349 | 5 | vpos.XYZW = pos.xyzw; ## Barrier: 0x1 + vsubc $v16, $v11, $v06.v ## L:350 | ^ | colorDiff = color - colorBase; LABEL_clipTriangle_0008: - beq $t7, $zero, LABEL_clipTriangle_0009 ## L:361 | ^ | if(newClipCode) { - vmudm $v13, $v13, $v19.e0 ## L:359 | ****150 | colorDiff:sfract *= fac:sfract.x; - vmudl $v17, $v10, $v19.e0 ## L:363 | 151 | dot = posUVDiff * fac:ufract.x; - vmadm $v16, $v09, $v19.e0 ## L:363 | 152 | dot = posUVDiff * fac:ufract.x; - vmadn $v17, $v00, $v00 ## L:363 | 153 | dot = posUVDiff * fac:ufract.x; - vmadn $v05, $v07, $v30.e7 ## L:364 | 154 | resPosUV = pos +* 1; - vmadh $v04, $v06, $v30.e7 ## L:364 | 155 | resPosUV = pos +* 1; - beq $zero, $zero, LABEL_clipTriangle_000A ## L:365 | ^ | resColor:uint = color + colorDiff; - vaddc $v03, $v08, $v13.v ## L:365 | *157 | resColor:uint = color + colorDiff; + vmudl $v17, $v15, $v05.v ## L:232 | ***************************************************************************************93 | res = a * b; + vmadm $v17, $v14, $v05.v ## L:232 | 94 | res = a * b; + vmadn $v18, $v15, $v04.v ## L:232 | 95 | res = a * b; + vmadh $v17, $v14, $v04.v ## L:232 | 96 | res = a * b; + vaddc $v18, $v18, $v18.q1 ## L:233 | **99 | res += res.yywwYYWW; + vadd $v17, $v17, $v17.q1 ## L:233 | 100 | res += res.yywwYYWW; + vaddc $v18, $v18, $v18.h2 ## L:234 | **103 | res += res.zzzzZZZZ; + vadd $v17, $v17, $v17.h2 ## L:234 | 104 | res += res.zzzzZZZZ; + vsubc $v20, $v18, $v18.e4 ## L:354 | **107 | vec32 fac = dot - dot.X; + vsub $v19, $v17, $v17.e4 ## L:354 | 108 | vec32 fac = dot - dot.X; + vrcph $v19.e0, $v19.e0 ## L:356 | ***112 | fac.x = invert_half(fac).x; + vrcpl $v20.e0, $v20.e0 ## L:356 | 113 | fac.x = invert_half(fac).x; + vrcph $v19.e0, $v00.e0 ## L:356 | 114 | fac.x = invert_half(fac).x; + vaddc $v20, $v20, $v20.v ## L:357 | **117 | fac += fac; + vadd $v19, $v19, $v19.v ## L:357 | 118 | fac += fac; + vmudl $v29, $v20, $v18.e0 ## L:358 | **121 | fac *= dot.x; + vmadm $v29, $v19, $v18.e0 ## L:358 | 122 | fac *= dot.x; + vmadn $v20, $v20, $v17.e0 ## L:358 | 123 | fac *= dot.x; + vmadh $v19, $v19, $v17.e0 ## L:358 | 124 | fac *= dot.x; + mfc2 $s0, $v19.e0 ## L:360 | ***128 | s16 facX = fac:sint.x; + beq $s0, $zero, LABEL_clipTriangle_0009 ## L:361 | **131 | if(facX != 0) { + nop ## L:361 | 132 | if(facX != 0) { + vlt $v29, $v19, $v30.e7 ## L:365 | 133 | fac:ufract = fac:sint < 1 ? fac:ufract : normScaleWInv:ufract.w; + vmrg $v20, $v20, $v01.e3 ## L:365 | 134 | fac:ufract = fac:sint < 1 ? fac:ufract : normScaleWInv:ufract.w; + vge $v29, $v19, $v00.e0 ## L:366 | 135 | fac:ufract = fac:sint >= 0 ? fac:ufract : VZERO; + vmrg $v20, $v20, $v00 ## L:366 | **138 | fac:ufract = fac:sint >= 0 ? fac:ufract : VZERO; LABEL_clipTriangle_0009: - vmudl $v17, $v10, $v19.e0 ## L:367 | 158 | dot = posUVDiff * fac:ufract.x; - vmadm $v16, $v09, $v19.e0 ## L:367 | 159 | dot = posUVDiff * fac:ufract.x; - vmadn $v17, $v00, $v00 ## L:367 | 160 | dot = posUVDiff * fac:ufract.x; - vmadn $v05, $v05, $v30.e7 ## L:368 | 161 | resPosUV = posBase +* 1; - vmadh $v04, $v04, $v30.e7 ## L:368 | 162 | resPosUV = posBase +* 1; - vaddc $v03, $v03, $v13.v ## L:369 | 163 | resColor:uint = colorBase + colorDiff; + beq $t9, $zero, LABEL_clipTriangle_000A ## L:371 | ^ | if(newClipCode) { + vmudm $v16, $v16, $v20.e0 ## L:369 | ***142 | colorDiff:sfract *= fac:sfract.x; + vmudl $v18, $v13, $v20.e0 ## L:373 | 143 | dot = posUVDiff * fac:ufract.x; + vmadm $v17, $v12, $v20.e0 ## L:373 | 144 | dot = posUVDiff * fac:ufract.x; + vmadn $v18, $v00, $v00 ## L:373 | 145 | dot = posUVDiff * fac:ufract.x; + vmadn $v08, $v10, $v30.e7 ## L:374 | 146 | resPosUV = pos +* 1; + vmadh $v07, $v09, $v30.e7 ## L:374 | 147 | resPosUV = pos +* 1; + beq $zero, $zero, LABEL_clipTriangle_000B ## L:375 | ^ | resColor:uint = color + colorDiff; + vaddc $v06, $v11, $v16.v ## L:375 | *149 | resColor:uint = color + colorDiff; LABEL_clipTriangle_000A: - vmudl $v10, $v05, $v01.v ## L:373 | *165 | vec32 clipBase = resPosUV * normScaleWInv:ufract; - vmadm $v09, $v04, $v01.v ## L:373 | 166 | vec32 clipBase = resPosUV * normScaleWInv:ufract; - vmadn $v10, $v00, $v00 ## L:373 | 167 | vec32 clipBase = resPosUV * normScaleWInv:ufract; - sdv $v04, 0, 16, $t3 ## L:563 | ^ | store(lastPosUV.xyzw, ptrWrite, 0x10); - vmudm $v12, $v02, $v05.h3 ## L:374 | 168 | vec32 clipPlaneW = guardBandScale * resPosUV.wwwwWWWW; - vmadh $v11, $v02, $v04.h3 ## L:374 | 169 | vec32 clipPlaneW = guardBandScale * resPosUV.wwwwWWWW; - vmadn $v12, $v00, $v00 ## L:374 | 170 | vec32 clipPlaneW = guardBandScale * resPosUV.wwwwWWWW; - suv $v03, 0, 8, $t3 ## L:559 | ^ | @Barrier("uv") store_vec_u8(lastColor, ptrWrite, 0x08); ## Barrier: 0x2 - vch $v29, $v09, $v11.e3 ## L:376 | **173 | newClipCode = clip(clipBase, clipPlaneW.w); - vcl $v29, $v10, $v12.e3 ## L:376 | 174 | newClipCode = clip(clipBase, clipPlaneW.w); - slv $v04, 8, 12, $t3 ## L:560 | ^ | @Barrier("uv") store(lastPosUV:sint.XY, ptrWrite, 0x0C); ## Barrier: 0x2 - cfc2 $t7, $vcc ## L:376 | 175 | newClipCode = clip(clipBase, clipPlaneW.w); - sdv $v05, 0, 24, $t3 ## L:563 | 176 | store(lastPosUV.xyzw, ptrWrite, 0x10); - andi $t7, $t7, 775 ## L:236 | *178 | res = clipCode & 0b0000'0011'0000'0111; - srl $sp, $t7, 5 ## L:237 | 179 | u32 tmp = res >> 5; - or $t7, $t7, $sp ## L:238 | 180 | res |= tmp; - sb $t7, 6($t3) ## L:562 | 181 | store(lastClipCode:u8, ptrWrite, 0x06); - addiu $t3, $t3, 36 ## L:564 | 182 | ptrWrite += 36; - LABEL_clipTriangle_0005: - vor $v03, $v00, $v08 ## L:476 | ^ | lastColor = currentColor; - vor $v05, $v00, $v07 ## L:474 | 183 | lastPosUV = currentPosUV; - or $t7, $zero, $t9 ## L:475 | ^ | lastClipCode = clipCode; - beq $k1, $zero, LABEL_clipTriangle_000B ## L:478 | 184 | if(isInsideCurr) { - vor $v04, $v00, $v06 ## L:474 | *186 | lastPosUV = currentPosUV; - suv $v03, 0, 8, $t3 ## L:559 | 187 | @Barrier("uv") store_vec_u8(lastColor, ptrWrite, 0x08); ## Barrier: 0x2 - sb $t7, 6($t3) ## L:562 | 188 | store(lastClipCode:u8, ptrWrite, 0x06); - sdv $v05, 0, 24, $t3 ## L:563 | 189 | store(lastPosUV.xyzw, ptrWrite, 0x10); - slv $v04, 8, 12, $t3 ## L:560 | 190 | @Barrier("uv") store(lastPosUV:sint.XY, ptrWrite, 0x0C); ## Barrier: 0x2 - sdv $v04, 0, 16, $t3 ## L:563 | 191 | store(lastPosUV.xyzw, ptrWrite, 0x10); - addiu $t3, $t3, 36 ## L:564 | 192 | ptrWrite += 36; + vmudl $v18, $v13, $v20.e0 ## L:377 | 1 | dot = posUVDiff * fac:ufract.x; + vmadm $v17, $v12, $v20.e0 ## L:377 | 2 | dot = posUVDiff * fac:ufract.x; + vmadn $v18, $v00, $v00 ## L:377 | 3 | dot = posUVDiff * fac:ufract.x; + vmadn $v08, $v08, $v30.e7 ## L:378 | 4 | resPosUV = posBase +* 1; + vmadh $v07, $v07, $v30.e7 ## L:378 | 5 | resPosUV = posBase +* 1; + vaddc $v06, $v06, $v16.v ## L:379 | 6 | resColor:uint = colorBase + colorDiff; LABEL_clipTriangle_000B: - addiu $t6, $t6, 36 ## L:482 | 193 | ptrRead += 36; - bne $t6, $t8, LABEL_clipTriangle_0003 ## L:482 | 194 | ptrRead += 36; - LABEL_clipTriangle_0004: - subu $t0, $t3, $t2 ## L:487 | 197 | arraySize = ptrWrite - ptrBuff1; - beq $t0, $zero, CLIP_RETURN ## L:489 | 198 | if(arraySize == 0)goto CLIP_RETURN; - sll $t5, $t5, 1 ## L:486 | *200 | planeIdx <<= 1; - addiu $at, $zero, 32 ## L:491 | 201 | planePtr += 0x04; - bne $t5, $at, LABEL_clipTriangle_0001 ## L:491 | 202 | planePtr += 0x04; - addiu $t4, $t4, 4 ## L:491 | *204 | planePtr += 0x04; - CLIP_END: - ori $s6, $zero, %lo(CLIP_BUFFER_RESULT) ## L:496 | 205 | u32<$s6> ptrVertIn = CLIP_BUFFER_RESULT; - addu $s5, $s6, $t0 ## L:497 | 206 | u32<$s5> ptrVertInEnd = ptrVertIn + arraySize; - bgezal $zero, triToScreenSpace ## L:502 | 207 | @Relative triToScreenSpace(ptrVertIn); ## Args: $s6 - addiu $s5, $s5, 65464 ## L:498 | *209 | ptrVertInEnd -= 72; - bgezal $zero, triToScreenSpace ## L:504 | 210 | @Relative triToScreenSpace(ptrVertIn); ## Args: $s6 - addiu $s6, $s6, 72 ## L:503 | *212 | ptrVertIn += 72; + beq $t4, $zero, LABEL_clipTriangle_000C ## L:384 | ***********************************************************************************************************************************************150 | if(remainingPlanes) + nop ## L:384 | 151 | if(remainingPlanes) + vmudl $v13, $v08, $v01.v ## L:387 | 152 | vec32 clipBase = resPosUV * normScaleWInv:ufract; + vmadm $v12, $v07, $v01.v ## L:387 | 153 | vec32 clipBase = resPosUV * normScaleWInv:ufract; + vmadn $v13, $v00, $v00 ## L:387 | 154 | vec32 clipBase = resPosUV * normScaleWInv:ufract; + vmov $v12.e2, $v12.e3 ## L:389 | **157 | clipBase.z = clipBase.w; + vmov $v13.e2, $v13.e3 ## L:389 | 158 | clipBase.z = clipBase.w; + vch $v29, $v12, $v07.e3 ## L:390 | **161 | newClipCode = clip(clipBase, resPosUV.w); + vcl $v29, $v13, $v08.e3 ## L:390 | 162 | newClipCode = clip(clipBase, resPosUV.w); + cfc2 $t9, $vcc ## L:390 | 163 | newClipCode = clip(clipBase, resPosUV.w); + andi $t9, $t9, 771 ## L:257 | **166 | res = clipCode & 0b0000'0011'0000'0011; + srl $s0, $t9, 5 ## L:258 | 167 | u32 tmp = res >> 5; + or $t9, $t9, $s0 ## L:259 | 168 | res |= tmp; + LABEL_clipTriangle_000C: + vxor $v12, $v08, $v03.v ## L:669 | ^ | vec16 stOut = lastPosUV:sfract ^ uvBias; + addiu $t3, $t3, 65500 ## L:667 | 169 | ptrWrite -= 36; + sb $t9, 6($t3) ## L:672 | 170 | store(lastClipCode:u8, ptrWrite, 0x06); + sdv $v08, 0, 24, $t3 ## L:673 | 171 | store(lastPosUV.xyzw, ptrWrite, 0x10); + sdv $v07, 0, 16, $t3 ## L:673 | 172 | store(lastPosUV.xyzw, ptrWrite, 0x10); + suv $v06, 0, 8, $t3 ## L:668 | 173 | @Barrier("uv") store_vec_u8(lastColor, ptrWrite, 0x08); ## Barrier: 0x2 + slv $v12, 8, 12, $t3 ## L:670 | 174 | @Barrier("uv") store(stOut.XY, ptrWrite, 0x0C); ## Barrier: 0x2 + LABEL_clipTriangle_0006: + vor $v08, $v00, $v10 ## L:524 | ^ | lastPosUV = currentPosUV; + vor $v07, $v00, $v09 ## L:524 | 175 | lastPosUV = currentPosUV; + or $t9, $zero, $k1 ## L:525 | ^ | lastClipCode = clipCode; + beq $fp, $zero, LABEL_clipTriangle_000D ## L:528 | 176 | if(isInsideCurr) { + vor $v06, $v00, $v11 ## L:526 | 177 | lastColor = currentColor; + addiu $t3, $t3, 65500 ## L:667 | 178 | ptrWrite -= 36; + vxor $v12, $v08, $v03.v ## L:669 | ^ | vec16 stOut = lastPosUV:sfract ^ uvBias; + sb $t9, 6($t3) ## L:672 | 179 | store(lastClipCode:u8, ptrWrite, 0x06); + sdv $v07, 0, 16, $t3 ## L:673 | 180 | store(lastPosUV.xyzw, ptrWrite, 0x10); + suv $v06, 0, 8, $t3 ## L:668 | 181 | @Barrier("uv") store_vec_u8(lastColor, ptrWrite, 0x08); ## Barrier: 0x2 + sdv $v08, 0, 24, $t3 ## L:673 | 182 | store(lastPosUV.xyzw, ptrWrite, 0x10); + slv $v12, 8, 12, $t3 ## L:670 | 183 | @Barrier("uv") store(stOut.XY, ptrWrite, 0x0C); ## Barrier: 0x2 LABEL_clipTriangle_000D: - bgezal $zero, triToScreenSpace ## L:502 | 212 | @Relative triToScreenSpace(ptrVertIn); ## Args: $s6 - addiu $s6, $s6, 72 ## L:501 | *214 | ptrVertIn += 72; - or $a1, $zero, $s6 ## L:505 | 215 | ptrVertB = ptrVertIn; - ori $a0, $zero, %lo(CLIP_BUFFER_RESULT) ## L:504 | 217 | ptrVertA = CLIP_BUFFER_RESULT; - jal RDPQ_Triangle_Send_Async ## L:510 | 218 | RDPQ_Triangle_Send_Async(ptrVertA, ptrVertB, ptrVertC, cullDest, faceCull); ## Args: $a0, $a1, $a2, $sp, $v0 - addiu $a2, $s6, 36 ## L:506 | *220 | ptrVertC = ptrVertIn + 36; - j RDPQ_Triangle_Send_End ## L:511 | 221 | RDPQ_Triangle_Send_End(); - ori $ra, $zero, %lo(RDPQ_Triangle_Clip) + bne $t8, $k0, LABEL_clipTriangle_0004 ## L:673 | 184 | store(lastPosUV.xyzw, ptrWrite, 0x10); + nop ## L:673 | 185 | store(lastPosUV.xyzw, ptrWrite, 0x10); + LABEL_clipTriangle_0005: + subu $t0, $t2, $t3 ## L:534 | 186 | arraySize = ptrBuff1 - ptrWrite; + beq $t0, $zero, CLIP_RETURN ## L:535 | 187 | if(arraySize == 0)goto CLIP_RETURN; + nop ## L:535 | 188 | if(arraySize == 0)goto CLIP_RETURN; + LABEL_clipTriangle_0003: + sll $t6, $t6, 1 ## L:538 | 189 | planeIdx <<= 1; + addiu $at, $zero, 32 ## L:539 | 190 | planePtr += 0x04; + bne $t6, $at, LABEL_clipTriangle_0001 ## L:539 | 191 | planePtr += 0x04; + addiu $t5, $t5, 4 ## L:539 | 192 | planePtr += 0x04; + CLIP_END: + or $t7, $zero, $t3 ## L:547 | 193 | u32 ptrConvA = ptrWrite; + LABEL_clipTriangle_000F: + addiu $t9, $t7, 36 ## L:552 | 194 | u32 ptrConvB = ptrConvA + 36; + bne $t9, $t2, LABEL_clipTriangle_0011 ## L:553 | 195 | if(ptrConvB == ptrBuff1) { + lhu $t8, %lo(RSPQ_SCRATCH_MEM + 20) ## L:551 | 196 | u16 oldClipFlag = load(RSPQ_SCRATCH_MEM, 20); + or $t9, $zero, $t7 ## L:554 | 197 | ptrConvB = ptrConvA; + LABEL_clipTriangle_0011: + ldv $v09, 8, 24, $t9 ## L:568 | 198 | posClip.XYZW = load(ptrConvB, 0x10).xyzw; + ldv $v08, 0, 16, $t7 ## L:567 | 199 | vec32 posClip = load(ptrConvA, 0x10).xyzw; + ldv $v08, 8, 16, $t9 ## L:568 | 200 | posClip.XYZW = load(ptrConvB, 0x10).xyzw; + ldv $v09, 0, 24, $t7 ## L:567 | 201 | vec32 posClip = load(ptrConvA, 0x10).xyzw; + ori $at, $zero, %lo(SCREEN_SCALE) ## L:557 | 202 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v04, 8, 0, $at ## L:557 | 203 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v05, 8, 8, $at ## L:557 | 204 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + vrcph $v10.e3, $v08.e3 ## L:571 | ^ | invWRaw.w = invert_half(posClip).w; + ldv $v05, 0, 8, $at ## L:557 | 205 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + vrcpl $v11.e3, $v09.e3 ## L:571 | ^ | invWRaw.w = invert_half(posClip).w; + ldv $v04, 0, 0, $at ## L:557 | 206 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + vrcph $v10.e3, $v08.e7 ## L:572 | ^ | invWRaw.W = invert_half(posClip).W; + ori $at, $zero, %lo(SCREEN_OFFSET) ## L:558 | 207 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + vrcpl $v11.e7, $v09.e7 ## L:572 | ^ | invWRaw.W = invert_half(posClip).W; + ldv $v06, 0, 0, $at ## L:558 | 208 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + vrcph $v10.e7, $v00.e7 ## L:572 | ^ | invWRaw.W = invert_half(posClip).W; + ldv $v06, 8, 0, $at ## L:558 | 209 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ori $at, $zero, %lo(NORM_SCALE_W) ## L:559 | *211 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + vmudl $v13, $v09, $v11.h3 ## L:576 | ^ | invW:sfract = posClip * invWRaw.wwwwWWWW; + vmadm $v13, $v08, $v11.h3 ## L:576 | 212 | invW:sfract = posClip * invWRaw.wwwwWWWW; + ldv $v07, 0, 0, $at ## L:559 | ^ | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + vmadn $v13, $v09, $v10.h3 ## L:576 | 213 | invW:sfract = posClip * invWRaw.wwwwWWWW; + ldv $v07, 8, 0, $at ## L:559 | ^ | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + vsubc $v14, $v07, $v13.h3 ## L:577 | ***217 | vec16 nrD = normScaleW:ufract - invW:ufract.wwwwWWWW; + andi $t8, $t8, 57344 ## L:564 | ^ | oldClipFlag = oldClipFlag & ((0b111'00000) << 8); + ori $t8, $t8, 255 ## L:565 | 218 | oldClipFlag |= 0xFF; + vaddc $v13, $v11, $v11.v ## L:578 | ^ | invW = invWRaw + invWRaw; + vadd $v12, $v10, $v10.v ## L:578 | 219 | invW = invWRaw + invWRaw; + vmudl $v13, $v13, $v14.h2 ## L:579 | **222 | invW *= nrD:ufract.zzzzZZZZ; + vmadm $v12, $v12, $v14.h2 ## L:579 | 223 | invW *= nrD:ufract.zzzzZZZZ; + vmadn $v13, $v00, $v00 ## L:579 | 224 | invW *= nrD:ufract.zzzzZZZZ; + ssv $v13, 6, 34, $t7 ## L:582 | ***228 | store(invW.w, ptrConvA, 0x20); + vmudl $v29, $v09, $v13.h3 ## L:586 | ^ | invW = posClip * invW.wwwwWWWW; + ssv $v13, 14, 34, $t9 ## L:583 | 229 | store(invW.W, ptrConvB, 0x20); + vmadm $v29, $v08, $v13.h3 ## L:586 | ^ | invW = posClip * invW.wwwwWWWW; + ssv $v12, 14, 32, $t9 ## L:583 | 230 | store(invW.W, ptrConvB, 0x20); + vmadn $v13, $v09, $v12.h3 ## L:586 | ^ | invW = posClip * invW.wwwwWWWW; + ssv $v12, 6, 32, $t7 ## L:582 | 231 | store(invW.w, ptrConvA, 0x20); + vmadh $v12, $v08, $v12.h3 ## L:586 | ^ | invW = posClip * invW.wwwwWWWW; + addiu $t7, $t7, 72 ## L:599 | 232 | ptrConvA += 72; + sh $t8, -66($t7) ## L:593 | *234 | store(oldClipFlag, ptrConvA, 0x06); + vmudl $v08, $v13, $v05.v ## L:587 | ^ | posClip = invW * screenSize; + sltu $at, $t7, $t2 ## L:599 | 235 | ptrConvA += 72; + vmadm $v08, $v12, $v05.v ## L:587 | ^ | posClip = invW * screenSize; + vmadn $v09, $v13, $v04.v ## L:587 | 236 | posClip = invW * screenSize; + vmadh $v08, $v12, $v04.v ## L:587 | 237 | posClip = invW * screenSize; + sh $t8, 6($t9) ## L:597 | ^ | store(oldClipFlag, ptrConvB, 0x06); + vmadh $v08, $v06, $v30.e7 ## L:588 | 238 | posClip:sint = screenOffset:sint +* 1; + ssv $v08, 12, 4, $t9 ## L:596 | ***242 | store(posClip:sint.Z, ptrConvB, 0x04); + slv $v08, 0, -72, $t7 ## L:591 | 243 | store(posClip:sint.xy, ptrConvA, 0x00); + ssv $v08, 4, -68, $t7 ## L:592 | 244 | store(posClip:sint.z, ptrConvA, 0x04); + bne $at, $zero, LABEL_clipTriangle_000F ## L:599 | 245 | ptrConvA += 72; + slv $v08, 8, 0, $t9 ## L:595 | 246 | store(posClip:sint.XY, ptrConvB, 0x00); + LABEL_clipTriangle_0010: + addiu $s4, $t2, 65500 ## L:605 | 247 | u32<$s4> ptrVert0 = ptrBuff1 - 36; + addiu $s0, $t0, 65391 ## L:608 | 248 | s32<$s0> fanWait = arraySize - 145; + or $s6, $zero, $s4 ## L:606 | 249 | u32<$s6> ptrVertIn = ptrVert0; + addiu $s5, $t3, 36 ## L:607 | 250 | u32<$s5> ptrVertInEnd = ptrWrite + 36; + LABEL_clipTriangle_0012: + addiu $s6, $s6, 65500 ## L:612 | 251 | ptrVertIn -= 36; + addiu $a2, $s6, 65500 ## L:616 | 252 | ptrVertC = ptrVertIn - 36; + or $a0, $zero, $s4 ## L:614 | 253 | ptrVertA = ptrVert0; + jal RDPQ_Triangle_Send_Async ## L:619 | 254 | RDPQ_Triangle_Send_Async(ptrVertA, ptrVertB, ptrVertC, faceCull); ## Args: $a0, $a1, $a2, $v0 + or $a1, $zero, $s6 ## L:615 | 255 | ptrVertB = ptrVertIn; + bgez $s0, RDPQ_Triangle_Send_End ## L:620 | 256 | if(fanWait >= 0) { + ori $ra, $zero, RDPQ_Triangle_Clip ## L:559 | 257 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; RDPQ_Triangle_Clip: - bne $s6, $s5, LABEL_clipTriangle_000D ## L:519 | 224 | RDPQ_Triangle_Clip: + bne $s6, $s5, LABEL_clipTriangle_0012 ## L:623 | 258 | RDPQ_Triangle_Clip: + nop ## L:623 | 259 | RDPQ_Triangle_Clip: CLIP_RETURN: - lhu $at, %lo(CLIP_RA + 0) ## L:280 | 227 | u16 tmp = load(CLIP_RA); - j $at ## L:283 | **230 | goto tmp; - lh $s4, %lo(RSPQ_SCRATCH_MEM + 18) ## L:282 | *232 | s16<$s4> oldDMEM = load(RSPQ_SCRATCH_MEM, 18); -triToScreenSpace: - ori $at, $zero, %lo(SCREEN_SCALE_OFFSET) ## L:574 | ^ | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzw; - ldv $v01, 0, 0, $at ## L:574 | 2 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzw; - ldv $v07, 0, 16, $s6 ## L:589 | 3 | vec32 posClip = load(ptr, 0x10).xyzw; - vmudl $v02, $v00, $v31.e7 ## L:576 | ^ | screenSize >>= 4; - ldv $v08, 0, 24, $s6 ## L:589 | 4 | vec32 posClip = load(ptr, 0x10).xyzw; - lhu $t0, %lo(RSPQ_SCRATCH_MEM + 20) ## L:582 | 5 | u16<$t0> oldClipFlag = load(RSPQ_SCRATCH_MEM, 20); - ldv $v04, 0, 8, $at ## L:586 | 6 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzw; - vmadm $v01, $v01, $v31.e7 ## L:576 | ^ | screenSize >>= 4; - vmadn $v02, $v00, $v00 ## L:576 | 7 | screenSize >>= 4; - vrcph $v05.e3, $v07.e3 ## L:590 | 8 | invW.w = invert_half(posClip).w; - vrcpl $v06.e3, $v08.e3 ## L:590 | 9 | invW.w = invert_half(posClip).w; - vrcph $v05.e3, $v00.e3 ## L:590 | 10 | invW.w = invert_half(posClip).w; - vxor $v03, $v00, $v30.e7 ## L:578 | 11 | vec16 vecOne = 1; - vmudl $v29, $v08, $v06.e3 ## L:593 | *13 | posClip *= invW.w; - vmadm $v29, $v07, $v06.e3 ## L:593 | 14 | posClip *= invW.w; - vmadn $v08, $v08, $v05.e3 ## L:593 | 15 | posClip *= invW.w; - vmadh $v07, $v07, $v05.e3 ## L:593 | 16 | posClip *= invW.w; - vmudl $v29, $v08, $v02.v ## L:594 | **19 | posClip *= screenSize; - vmadm $v29, $v07, $v02.v ## L:594 | 20 | posClip *= screenSize; - andi $t0, $t0, 57344 ## L:583 | ^ | oldClipFlag = oldClipFlag & ((0b111'00000) << 8); - vmadn $v08, $v08, $v01.v ## L:594 | 21 | posClip *= screenSize; - ssv $v06, 6, 34, $s6 ## L:591 | ^ | store(invW.w, ptr, 0x20); - ori $t0, $t0, 255 ## L:584 | 22 | oldClipFlag |= 0xFF; - vmadh $v07, $v07, $v01.v ## L:594 | ^ | posClip *= screenSize; - ssv $v05, 6, 32, $s6 ## L:591 | 23 | store(invW.w, ptr, 0x20); - vmadh $v07, $v04, $v30.e7 ## L:596 | ^ | posClip:sint = screenOffset:sint +* 1; - sdv $v07, 0, 0, $s6 ## L:598 | ***27 | @Barrier("cc") store(posClip:sint.xyzw, ptr, 0x00); ## Barrier: 0x1 - sh $t0, 6($s6) ## L:599 | 28 | @Barrier("cc") store(oldClipFlag, ptr, 0x06); ## Barrier: 0x1 - jr $ra ## L:602 | 29 | } - addiu $s6, $s6, 65500 ## L:601 | *31 | ptr -= 36; -T3DCmd_TriDraw_End: + lhu $t7, %lo(CLIP_RA + 0) ## L:631 | 260 | u16 tmp = load(CLIP_RA); + j $t7 ## L:634 | **263 | goto tmp; + lh $s4, %lo(RSPQ_SCRATCH_MEM + 18) ## L:633 | *265 | s16<$s4> oldDMEM = load(RSPQ_SCRATCH_MEM, 18); OVERLAY_CODE_END: #define zero $0 diff --git a/src/t3d/rsp/rsp_tinypx.S b/src/t3d/rsp/rsp_tinypx.S index 89edbfd9..ce5201bb 100644 --- a/src/t3d/rsp/rsp_tinypx.S +++ b/src/t3d/rsp/rsp_tinypx.S @@ -3,10 +3,17 @@ #define RDP_CMD_DEPTH 0x2E #define RDP_CMD_RECT 0x36 #define RDP_CMD_TEX_RECT 0x24 -#define PARTICLE_INPUT_SIZE 16 +#define RDP_CMD_TEX_RECT_FLIP 0x25 +#define PARTICLE_INPUT_SIZE_S8 16 +#define PARTICLE_INPUT_SIZE_S16 24 #define PARTICLE_MAX_COUNT 344 #define RDP_FLUSH_SIZE 528 +#define RDP_TEX_FLUSH_SIZE 480 #define RDP_POS_MASK 0b1111'1111'1111 +#define LOOP_16BIT 1 +#define MATRIX_TEMP_MUL PARTICLE_BUFF +#define MATRIX_MV RDP_BUFF +#define MATRIX_SIZE 0x40 #include #include #include @@ -98,8 +105,10 @@ MATRIX_PROJ: .ds.b 64 .align 3 MATRIX_MVP: .ds.b 64 - .align 4 - SCREEN_SCALE_OFFSET: .half 0, 0, 0, 0, 0, 0, 16383, 255 + .align 3 + SCREEN_SCALE: .half 0, 0, 0, 0, 0, 0, 0, 0 + .align 1 + SCREEN_OFFSET: .half 0, 0, 16383, 255 .align 3 NORM_SCALE_W: .half 65535, 65535, 65535, 0 .align 2 @@ -127,839 +136,844 @@ OVERLAY_CODE_START: TPXCmd_SyncT3D: - ori $t0, $zero, 127 - or $t2, $zero, $zero - or $s0, $zero, $a0 - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - ori $s4, $zero, %lo(MATRIX_PROJ) - ori $t0, $zero, 63 - addiu $a0, $a0, 128 - or $s0, $zero, $a0 - or $t2, $zero, $zero - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - ori $s4, $zero, %lo(RDP_BUFF) - ori $t0, $zero, 63 - addiu $t2, $zero, -32768 - lw $s0, %lo(MATRIX_STACK_PTR + 0) - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - ori $s4, $zero, %lo(RDP_BUFF) - ori $t0, $zero, 15 - sh $a2, %lo(6 + NORM_SCALE_W)($zero) - ori $s4, $zero, %lo(SCREEN_SCALE_OFFSET) - or $s0, $zero, $a1 - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - addiu $t2, $zero, 12 - j RSPQ_Loop - nop + ## hot-path cycles: 25 + or $s0, $zero, $a0 ## L:818 | ^ | dma_in_async(MATRIX_PROJ, rdramMatrix, 128); + ori $s4, $zero, %lo(MATRIX_PROJ) ## L:818 | 2 | dma_in_async(MATRIX_PROJ, rdramMatrix, 128); + ori $t0, $zero, 127 ## L:818 | 3 | dma_in_async(MATRIX_PROJ, rdramMatrix, 128); + jal DMAExec ## L:818 | 4 | dma_in_async(MATRIX_PROJ, rdramMatrix, 128); ## Args: $t0, $t1, $s0, $s4, $t2 + or $t2, $zero, $zero ## L:818 | 5 | dma_in_async(MATRIX_PROJ, rdramMatrix, 128); + addiu $a0, $a0, 128 ## L:820 | 6 | rdramMatrix += 128; + or $t2, $zero, $zero ## L:821 | 7 | dma_in_async(RDP_BUFF, rdramMatrix, 64); + ori $t0, $zero, 63 ## L:821 | 8 | dma_in_async(RDP_BUFF, rdramMatrix, 64); + ori $s4, $zero, %lo(RDP_BUFF) ## L:821 | 9 | dma_in_async(RDP_BUFF, rdramMatrix, 64); + jal DMAExec ## L:821 | 10 | dma_in_async(RDP_BUFF, rdramMatrix, 64); ## Args: $t0, $t1, $s0, $s4, $t2 + or $s0, $zero, $a0 ## L:821 | 11 | dma_in_async(RDP_BUFF, rdramMatrix, 64); + ori $t0, $zero, 63 ## L:823 | 12 | dma_out_async(RDP_BUFF, addrRDRAM, 64); + addiu $t2, $zero, -32768 ## L:823 | 13 | dma_out_async(RDP_BUFF, addrRDRAM, 64); + ori $s4, $zero, %lo(RDP_BUFF) ## L:823 | 14 | dma_out_async(RDP_BUFF, addrRDRAM, 64); + jal DMAExec ## L:823 | 15 | dma_out_async(RDP_BUFF, addrRDRAM, 64); ## Args: $t0, $t1, $s0, $s4, $t2 + lw $s0, %lo(MATRIX_STACK_PTR + 0) ## L:822 | 16 | u32<$s0> addrRDRAM = load(MATRIX_STACK_PTR); + or $s0, $zero, $a1 ## L:829 | 17 | dma_in(SCREEN_SCALE, rdramScreen, 24); + addiu $t2, $zero, 12 ## L:829 | 18 | dma_in(SCREEN_SCALE, rdramScreen, 24); + sh $a2, %lo(6 + NORM_SCALE_W)($zero) ## L:825 | 19 | store(wNorm, NORM_SCALE_W, 6); + ori $s4, $zero, %lo(SCREEN_SCALE) ## L:829 | 20 | dma_in(SCREEN_SCALE, rdramScreen, 24); + jal DMAExec ## L:829 | 21 | dma_in(SCREEN_SCALE, rdramScreen, 24); ## Args: $t0, $t1, $s0, $s4, $t2 + ori $t0, $zero, 23 ## L:829 | 22 | dma_in(SCREEN_SCALE, rdramScreen, 24); + j RSPQ_Loop ## L:830 | 23 | + nop ## L:830 | *25 | TPXCmd_DrawColor: - or $s0, $zero, $a1 ## L:850 | ^ | dma_in_async(dmaDmem, rdramAddr, dmaSize); - andi $t0, $a0, 65535 ## L:834 | 2 | u32<$t0> dmaSize = dataSize & 0xFFFF; - ori $s4, $zero, %lo(PARTICLE_BUFF) ## L:833 | 3 | u16<$s4> dmaDmem = PARTICLE_BUFF; - addu $s7, $s4, $t0 ## L:849 | 4 | u32 ptrInEnd = dmaDmem + dmaSize; - addiu $t0, $t0, -1 ## L:850 | 5 | dma_in_async(dmaDmem, rdramAddr, dmaSize); - jal DMAExec ## L:850 | 6 | dma_in_async(dmaDmem, rdramAddr, dmaSize); ## Args: $t0, $t1, $s0, $s4, $t2 - or $t2, $zero, $zero ## L:850 | *8 | dma_in_async(dmaDmem, rdramAddr, dmaSize); - vmudl $v20, $v00, $v31.e7 ## L:865 | 9 | screenSize >>= 4; - lw $s2, %lo(RDPQ_SCISSOR_RECT + 4) ## L:1213 | ^ | u32 extMax = load(RDPQ_SCISSOR_RECT, 4); - lw $s1, %lo(RDPQ_SCISSOR_RECT + 0) ## L:1214 | 10 | u32 extMin = load(RDPQ_SCISSOR_RECT, 0); - ori $at, $zero, %lo(MATRIX_MVP) ## L:858 | 11 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v21, 0, 48, $at ## L:861 | 12 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - mtc2 $s2, $v15.e5 ## L:1218 | 13 | screenMax.y = extMax; screenMax.Y = extMax; - ldv $v23, 0, 32, $at ## L:860 | 14 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ldv $v28, 0, 8, $at ## L:858 | 15 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v22, 0, 56, $at ## L:861 | 16 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - ldv $v26, 0, 24, $at ## L:859 | 17 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ori $s3, $zero, %lo(RDP_BUFF) ## L:855 | 18 | u16<$s3> dmaDmemEnd = RDP_BUFF; - ldv $v25, 0, 16, $at ## L:859 | 19 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v25, 8, 16, $at ## L:859 | 20 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v24, 0, 40, $at ## L:860 | 21 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ldv $v21, 8, 48, $at ## L:861 | 22 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - ldv $v26, 8, 24, $at ## L:859 | 23 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v28, 8, 8, $at ## L:858 | 24 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v27, 0, 0, $at ## L:858 | 25 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v24, 8, 40, $at ## L:860 | 26 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ldv $v23, 8, 32, $at ## L:860 | 27 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ldv $v27, 8, 0, $at ## L:858 | 28 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v22, 8, 56, $at ## L:861 | 29 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - ori $at, $zero, %lo(SCREEN_SCALE_OFFSET) ## L:863 | 30 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ldv $v18, 0, 8, $at ## L:867 | 31 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - mtc2 $s1, $v16.e5 ## L:1222 | 32 | screenMin.y = extMin; screenMin.Y = extMin; - ldv $v18, 8, 8, $at ## L:867 | 33 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - srl $t4, $s2, 12 ## L:1216 | 34 | temp1 = extMax >> 12; - ldv $v19, 0, 0, $at ## L:863 | 35 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - mtc2 $s1, $v16.e1 ## L:1222 | 36 | screenMin.y = extMin; screenMin.Y = extMin; - ldv $v19, 8, 0, $at ## L:863 | 37 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ori $at, $zero, %lo(NORM_SCALE_W) ## L:868 | 38 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - addiu $s5, $s3, 528 ## L:856 | 39 | u16 dmaDmemFlush = dmaDmemEnd + 528; - mtc2 $s2, $v15.e1 ## L:1218 | 40 | screenMax.y = extMax; screenMax.Y = extMax; - ori $s2, $zero, %lo(RDP_BUFF) ## L:881 | 41 | u16 buffRdp = RDP_BUFF; - ldv $v17, 0, 0, $at ## L:868 | 42 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - mtc2 $t4, $v15.e4 ## L:1217 | 43 | screenMax.x = temp1; screenMax.X = temp1; - ldv $v17, 8, 0, $at ## L:868 | 44 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - lui $t7, 0x3A00 ## L:883 | 45 | cmdRdpColor = 0x3A00'0000; - addiu $at, $zero, 4095 ## L:1212 | 46 | screenMax.w = 0b1111'1111'1111; - mtc2 $at, $v15.e3 ## L:1212 | 47 | screenMax.w = 0b1111'1111'1111; - mtc2 $t4, $v15.e0 ## L:1217 | 48 | screenMax.x = temp1; screenMax.X = temp1; - ori $at, $zero, %lo(PARTICLE_SCALE) ## L:875 | 49 | globalPartSize.xy = load(PARTICLE_SCALE).xy; - addiu $a0, $zero, 46 ## L:884 | 50 | cmdRdpDepth = 0x2E; - srl $t4, $s1, 12 ## L:1220 | 51 | temp1 = extMin >> 12; - vmadm $v19, $v19, $v31.e7 ## L:865 | ^ | screenSize >>= 4; - vmadn $v20, $v00, $v00 ## L:865 | 52 | screenSize >>= 4; - mtc2 $t4, $v16.e0 ## L:1221 | ^ | screenMin.x = temp1; screenMin.X = temp1; - mtc2 $t4, $v16.e4 ## L:1221 | 53 | screenMin.x = temp1; screenMin.X = temp1; - vand $v15, $v15, $v15.e3 ## L:1224 | ^ | screenMax &= screenMax.w; - llv $v13, 0, 0, $at ## L:875 | 54 | globalPartSize.xy = load(PARTICLE_SCALE).xy; - llv $v13, 8, 0, $at ## L:876 | 55 | globalPartSize.XY = load(PARTICLE_SCALE).xy; - addiu $s1, $s5, 24 ## L:882 | 56 | u16 buffRdpEnd = dmaDmemFlush + 24; - or $s6, $zero, $s4 ## L:852 | 57 | u32 ptrIn = dmaDmem; - ori $s4, $zero, %lo(RDP_BUFF) ## L:854 | 58 | dmaDmem = RDP_BUFF; - vand $v16, $v16, $v15.e3 ## L:1225 | ^ | screenMin &= screenMax.w; + ## hot-path cycles: 186 + andi $t0, $a0, 65535 ## L:835 | ^ | u32<$t0> dmaSize = dataSize & 0xFFFF; + ori $s4, $zero, %lo(PARTICLE_BUFF) ## L:834 | 2 | u16<$s4> dmaDmem = PARTICLE_BUFF; + or $s0, $zero, $a1 ## L:851 | 3 | dma_in_async(dmaDmem, rdramAddr, dmaSize); + addu $s7, $s4, $t0 ## L:850 | 4 | u32 ptrInEnd = dmaDmem + dmaSize; + addiu $t0, $t0, -1 ## L:851 | 5 | dma_in_async(dmaDmem, rdramAddr, dmaSize); + jal DMAExec ## L:851 | 6 | dma_in_async(dmaDmem, rdramAddr, dmaSize); ## Args: $t0, $t1, $s0, $s4, $t2 + or $t2, $zero, $zero ## L:851 | 7 | dma_in_async(dmaDmem, rdramAddr, dmaSize); + ori $at, $zero, %lo(MATRIX_MVP) ## L:859 | 8 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + or $s6, $zero, $s4 ## L:853 | 9 | u32 ptrIn = dmaDmem; + lw $s2, %lo(RDPQ_SCISSOR_RECT + 4) ## L:1210 | 10 | u32 extMax = load(RDPQ_SCISSOR_RECT, 4); + ldv $v26, 0, 24, $at ## L:860 | 11 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + ldv $v24, 8, 40, $at ## L:861 | 12 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ldv $v26, 8, 24, $at ## L:860 | 13 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + srl $t4, $s2, 12 ## L:1213 | 14 | temp1 = extMax >> 12; + ldv $v27, 8, 0, $at ## L:859 | 15 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + lw $s1, %lo(RDPQ_SCISSOR_RECT + 0) ## L:1211 | 16 | u32 extMin = load(RDPQ_SCISSOR_RECT, 0); + ori $s3, $zero, %lo(RDP_BUFF) ## L:856 | 17 | u16<$s3> dmaDmemEnd = RDP_BUFF; + ldv $v28, 0, 8, $at ## L:859 | 18 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ldv $v21, 8, 48, $at ## L:862 | 19 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + ldv $v22, 8, 56, $at ## L:862 | 20 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + ldv $v28, 8, 8, $at ## L:859 | 21 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ldv $v23, 8, 32, $at ## L:861 | 22 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ldv $v25, 8, 16, $at ## L:860 | 23 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + ldv $v21, 0, 48, $at ## L:862 | 24 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + ldv $v27, 0, 0, $at ## L:859 | 25 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ldv $v25, 0, 16, $at ## L:860 | 26 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + ldv $v24, 0, 40, $at ## L:861 | 27 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ldv $v23, 0, 32, $at ## L:861 | 28 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ori $s4, $zero, %lo(RDP_BUFF) ## L:855 | 29 | dmaDmem = RDP_BUFF; + ldv $v22, 0, 56, $at ## L:862 | 30 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + mtc2 $t4, $v15.e4 ## L:1214 | 31 | screenMax.x = temp1; screenMax.X = temp1; + ori $at, $zero, %lo(SCREEN_SCALE) ## L:864 | 32 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v20, 8, 8, $at ## L:864 | 33 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + mtc2 $t4, $v15.e0 ## L:1214 | 34 | screenMax.x = temp1; screenMax.X = temp1; + ldv $v19, 0, 0, $at ## L:864 | 35 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v20, 0, 8, $at ## L:864 | 36 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + addiu $a0, $zero, 46 ## L:883 | 37 | cmdRdpDepth = 0x2E; + ldv $v19, 8, 0, $at ## L:864 | 38 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + mtc2 $s1, $v16.e1 ## L:1219 | 39 | screenMin.y = extMin; screenMin.Y = extMin; + ori $at, $zero, %lo(SCREEN_OFFSET) ## L:866 | 40 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ldv $v18, 8, 0, $at ## L:866 | 41 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + addiu $s5, $s3, 528 ## L:857 | 42 | u16 dmaDmemFlush = dmaDmemEnd + 528; + ldv $v18, 0, 0, $at ## L:866 | 43 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + mtc2 $s1, $v16.e5 ## L:1219 | 44 | screenMin.y = extMin; screenMin.Y = extMin; + ori $at, $zero, %lo(NORM_SCALE_W) ## L:867 | 45 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + ldv $v17, 8, 0, $at ## L:867 | 46 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + ldv $v17, 0, 0, $at ## L:867 | 47 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + srl $t4, $s1, 12 ## L:1217 | 48 | temp1 = extMin >> 12; + addiu $at, $zero, 4095 ## L:1209 | 49 | screenMax.w = 0b1111'1111'1111; + mtc2 $at, $v15.e3 ## L:1209 | 50 | screenMax.w = 0b1111'1111'1111; + mtc2 $t4, $v16.e0 ## L:1218 | 51 | screenMin.x = temp1; screenMin.X = temp1; + ori $at, $zero, %lo(PARTICLE_SCALE) ## L:874 | 52 | globalPartSize.xy = load(PARTICLE_SCALE).xy; + addiu $s1, $s5, 24 ## L:881 | 53 | u16 buffRdpEnd = dmaDmemFlush + 24; + mtc2 $s2, $v15.e1 ## L:1215 | 54 | screenMax.y = extMax; screenMax.Y = extMax; + mtc2 $s2, $v15.e5 ## L:1215 | 55 | screenMax.y = extMax; screenMax.Y = extMax; + lui $t7, 0x3A00 ## L:882 | 56 | cmdRdpColor = 0x3A00'0000; + llv $v13, 8, 0, $at ## L:875 | 57 | globalPartSize.XY = load(PARTICLE_SCALE).xy; + mtc2 $t4, $v16.e4 ## L:1218 | 58 | screenMin.x = temp1; screenMin.X = temp1; + ori $s2, $zero, %lo(RDP_BUFF) ## L:880 | 59 | u16 buffRdp = RDP_BUFF; + llv $v13, 0, 0, $at ## L:874 | 60 | globalPartSize.xy = load(PARTICLE_SCALE).xy; + vand $v15, $v15, $v15.e3 ## L:1221 | ^ | screenMax &= screenMax.w; + vand $v16, $v16, $v15.e3 ## L:1222 | ***64 | screenMin &= screenMax.w; LABEL_TPXCmd_DrawColor_0001: - sh $zero, 14($s2) ## L:888 | 59 | store(ZERO:u16, buffRdp, 0x0E); - sw $t7, 0($s2) ## L:886 | 60 | store(cmdRdpColor, buffRdp, 0); - sb $a0, 8($s2) ## L:887 | 61 | store(cmdRdpDepth, buffRdp, 8); - addiu $s2, $s2, 24 ## L:889 | 62 | buffRdp += 24; - bne $s2, $s1, LABEL_TPXCmd_DrawColor_0001 ## L:889 | 63 | buffRdp += 24; - nop ## L:889 | *65 | buffRdp += 24; + sb $a0, 8($s2) ## L:886 | ^ | store(cmdRdpDepth, buffRdp, 8); + addiu $s2, $s2, 24 ## L:888 | 65 | buffRdp += 24; + sw $t7, -24($s2) ## L:885 | 66 | store(cmdRdpColor, buffRdp, 0); + bne $s2, $s1, LABEL_TPXCmd_DrawColor_0001 ## L:888 | 67 | buffRdp += 24; + sh $zero, -10($s2) ## L:887 | 68 | store(ZERO:u16, buffRdp, 0x0E); LABEL_TPXCmd_DrawColor_0002: - jal DMAWaitIdle ## L:893 | 66 | dma_await(); - nop ## L:893 | *68 | dma_await(); - bgez $a1, LABEL_TPXCmd_DrawColor_0003 ## L:900 | 69 | if(rdramAddr < 0) { - vxor $v10, $v00, $v30.e7 ## L:897 | *71 | const vec16 vecOne = 1; - lqv $v09, 0, 0, $s6 ## L:466 | 72 | vec16 posStart = load(ptrIn, 0x00); - vmulf $v14, $v13, $v09.h3 ## L:467 | ***76 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - vmudn $v12, $v28, $v09.h0 ## L:93 | 77 | out = mat0 * vec.xxxxXXXX; - vmadh $v11, $v27, $v09.h0 ## L:93 | 78 | out = mat0 * vec.xxxxXXXX; - vmadn $v12, $v26, $v09.h1 ## L:94 | 79 | out = mat1 +* vec.yyyyYYYY; - vmadh $v11, $v25, $v09.h1 ## L:94 | 80 | out = mat1 +* vec.yyyyYYYY; - vmadn $v12, $v24, $v09.h2 ## L:95 | 81 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v11, $v23, $v09.h2 ## L:95 | 82 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v12, $v22, $v30.e7 ## L:96 | 83 | out = mat3 +* 1; - vmadh $v11, $v21, $v30.e7 ## L:96 | 84 | out = mat3 +* 1; - vch $v29, $v11, $v11.h3 ## L:475 | ***88 | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v12, $v12.h3 ## L:475 | 89 | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:475 | 90 | temp1 = clip(posClip, posClip.wwwwWWWW); + jal DMAWaitIdle ## L:892 | 69 | dma_await(); + nop ## L:892 | 70 | dma_await(); + bgez $a1, LABEL_TPXCmd_DrawColor_0003 ## L:899 | 71 | if(rdramAddr < 0) { + vxor $v10, $v00, $v30.e7 ## L:896 | 72 | const vec16 vecOne = 1; + lqv $v09, 0, 0, $s6 ## L:467 | 73 | vec16 posStart = load(ptrIn, 0x00); + vmulf $v14, $v13, $v09.h3 ## L:468 | ***77 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + vmudn $v12, $v28, $v09.h0 ## L:94 | 78 | out = mat0 * vec.xxxxXXXX; + vmadh $v11, $v27, $v09.h0 ## L:94 | 79 | out = mat0 * vec.xxxxXXXX; + vmadn $v12, $v26, $v09.h1 ## L:95 | 80 | out = mat1 +* vec.yyyyYYYY; + vmadh $v11, $v25, $v09.h1 ## L:95 | 81 | out = mat1 +* vec.yyyyYYYY; + vmadn $v12, $v24, $v09.h2 ## L:96 | 82 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v11, $v23, $v09.h2 ## L:96 | 83 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v12, $v22, $v30.e7 ## L:97 | 84 | out = mat3 +* 1; + vmadh $v11, $v21, $v30.e7 ## L:97 | 85 | out = mat3 +* 1; + vch $v29, $v11, $v11.h3 ## L:476 | ***89 | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v12, $v12.h3 ## L:476 | 90 | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:476 | 91 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawColor_0005: - vmudl $v12, $v12, $v17.v ## L:486 | ^ | posClip *= normScaleW:ufract; - vmadm $v11, $v11, $v17.v ## L:486 | 91 | posClip *= normScaleW:ufract; - ldv $v03, 0, 16, $s6 ## L:531 | ^ | vec16 color = load(ptrIn, 16).xyzw; - vmadn $v12, $v00, $v00 ## L:486 | 92 | posClip *= normScaleW:ufract; - vrcph $v07.e3, $v11.e3 ## L:488 | **95 | invW.w = invert_half(posClip).w; - andi $t1, $t4, 1028 ## L:482 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; - vrcpl $v08.e3, $v12.e3 ## L:488 | 96 | invW.w = invert_half(posClip).w; - addiu $t2, $zero, 54 ## L:535 | ^ | cmdRdpRect = 0x36; - ori $at, $zero, %lo(BASE_SIZE) ## L:492 | 97 | posClip:sint.w = load(BASE_SIZE).x; - vrcph $v07.e3, $v11.e7 ## L:489 | ^ | invW.W = invert_half(posClip).W; - vrcpl $v08.e7, $v12.e7 ## L:489 | 98 | invW.W = invert_half(posClip).W; - vmov $v12.e3, $v00.e0 ## L:494 | 99 | posClip:sfract.w = 0; - vmov $v12.e7, $v00.e0 ## L:495 | 100 | posClip:sfract.W = 0; - lsv $v11, 6, 0, $at ## L:492 | ^ | posClip:sint.w = load(BASE_SIZE).x; - lsv $v11, 14, 0, $at ## L:493 | 101 | posClip:sint.W = load(BASE_SIZE).x; - vrcph $v07.e7, $v00.e7 ## L:489 | ^ | invW.W = invert_half(posClip).W; - andi $t5, $t4, 16448 ## L:483 | **104 | clipB = temp1 & 0b0100'0000'0100'0000; - vmudl $v29, $v12, $v08.h3 ## L:498 | ^ | posClip *= invW.wwwwWWWW; - vmadm $v29, $v11, $v08.h3 ## L:498 | 105 | posClip *= invW.wwwwWWWW; - vmadn $v12, $v12, $v07.h3 ## L:498 | 106 | posClip *= invW.wwwwWWWW; - vmadh $v11, $v11, $v07.h3 ## L:498 | 107 | posClip *= invW.wwwwWWWW; - slv $v03, 0, 4, $s3 ## L:543 | ^ | store(color.xy, dmaDmemEnd, 4); - vmulf $v14, $v14, $v11.h3 ## L:502 | ***111 | localPartSize:sfract *= posClip:sint.wwwwWWWW; - vmudl $v29, $v12, $v20.v ## L:505 | 112 | vec32 posScreen = posClip * screenSize; - vmadm $v29, $v11, $v20.v ## L:505 | 113 | vec32 posScreen = posClip * screenSize; - vmadn $v08, $v12, $v19.v ## L:505 | 114 | vec32 posScreen = posClip * screenSize; - vmadh $v07, $v11, $v19.v ## L:505 | 115 | vec32 posScreen = posClip * screenSize; - vmadh $v06, $v18, $v10.v ## L:506 | 116 | vec16 posCenter = screenOffset:sint +* vecOne; - vmadh $v05, $v10, $v14.v ## L:509 | 117 | vec16 posEnd = vecOne +* localPartSize:sint; - vsubc $v09, $v06, $v14.v ## L:510 | **120 | posStart = posCenter - localPartSize:sint; - vlt $v05, $v05, $v15 ## L:513 | 121 | posEnd = min(posEnd, screenMax); - addiu $at, $zero, 3 ## L:567 | ^ | if(clipA == 0b0000'0011) { - ssv $v06, 4, 12, $s3 ## L:547 | **124 | store(posCenter.z, dmaDmemEnd, 0x04, 8); - vge $v09, $v09, $v16 ## L:514 | ^ | posStart = max(posStart, screenMin); - mfc2 $fp, $v05.e1 ## L:1191 | 125 | outA = pos.y; - mfc2 $sp, $v05.e5 ## L:1197 | 126 | outB = pos.Y; - andi $fp, $fp, 4095 ## L:1192 | *128 | outA &= 0b1111'1111'1111; - mfc2 $s2, $v09.e1 ## L:1191 | 129 | outA = pos.y; - mfc2 $k1, $v09.e0 ## L:1193 | 130 | u32 tmp = pos.x; - andi $sp, $sp, 4095 ## L:1198 | 131 | outB &= 0b1111'1111'1111; - andi $s2, $s2, 4095 ## L:1192 | 132 | outA &= 0b1111'1111'1111; - mfc2 $s1, $v09.e5 ## L:1197 | 133 | outB = pos.Y; - vlt $v04, $v09, $v05 ## L:520 | ^ | vec16 extend = posStart < posEnd; - sll $k1, $k1, 12 ## L:1194 | 134 | tmp <<= 12; - or $s2, $s2, $k1 ## L:1195 | 135 | outA |= tmp; - andi $s1, $s1, 4095 ## L:1198 | 136 | outB &= 0b1111'1111'1111; - mfc2 $k1, $v09.e4 ## L:1199 | 137 | tmp = pos.X; - sw $s2, 4 + 16($s3) ## L:551 | 138 | store(posA, dmaDmemEnd, 0x04, 16); - ldv $v09, 0, 24, $s6 ## L:558 | 139 | posStart.xyzw = load(ptrIn, 24).xyzw; - sll $k1, $k1, 12 ## L:1200 | 140 | tmp <<= 12; - or $s1, $s1, $k1 ## L:1201 | 141 | outB |= tmp; - mfc2 $k1, $v05.e0 ## L:1193 | 142 | u32 tmp = pos.x; - cfc2 $t4, $vcc ## L:521 | 143 | temp1 = get_vcc(); - ldv $v09, 8, 32, $s6 ## L:559 | 144 | posStart.XYZW = load(ptrIn, 24).XYZW; - sll $k1, $k1, 12 ## L:1194 | 145 | tmp <<= 12; - or $fp, $fp, $k1 ## L:1195 | 146 | outA |= tmp; - sw $fp, 0 + 16($s3) ## L:552 | 147 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - andi $a2, $t4, 3 ## L:523 | 148 | temp0 = temp1 & 0b0000'0011; - mfc2 $k1, $v05.e4 ## L:1199 | 149 | tmp = pos.X; - or $t1, $t1, $a2 ## L:524 | 150 | clipA |= temp0; - andi $a2, $t4, 48 ## L:526 | 151 | temp0 = temp1 & 0b0011'0000; - vmulf $v14, $v13, $v09.h3 ## L:560 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - sll $k1, $k1, 12 ## L:1200 | 152 | tmp <<= 12; - sb $t2, 0 + 16($s3) ## L:553 | 153 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - or $t5, $t5, $a2 ## L:527 | 154 | clipB |= temp0; - bne $t1, $at, LABEL_TPXCmd_DrawColor_0007 ## L:567 | 155 | if(clipA == 0b0000'0011) { - or $sp, $sp, $k1 ## L:1201 | *157 | outB |= tmp; - addiu $s3, $s3, 24 ## L:568 | 158 | dmaDmemEnd += 24; + vmudl $v12, $v12, $v17.v ## L:487 | ^ | posClip *= normScaleW:ufract; + addiu $t2, $zero, 54 ## L:536 | 92 | cmdRdpRect = 0x36; + vmadm $v11, $v11, $v17.v ## L:487 | ^ | posClip *= normScaleW:ufract; + vmadn $v12, $v00, $v00 ## L:487 | 93 | posClip *= normScaleW:ufract; + vrcph $v07.e3, $v11.e3 ## L:489 | **96 | invW.w = invert_half(posClip).w; + ori $at, $zero, %lo(BASE_SIZE) ## L:493 | ^ | posClip:sint.w = load(BASE_SIZE).x; + vrcpl $v08.e3, $v12.e3 ## L:489 | 97 | invW.w = invert_half(posClip).w; + vrcph $v07.e3, $v11.e7 ## L:490 | 98 | invW.W = invert_half(posClip).W; + lsv $v11, 6, 0, $at ## L:493 | ^ | posClip:sint.w = load(BASE_SIZE).x; + vrcpl $v08.e7, $v12.e7 ## L:490 | 99 | invW.W = invert_half(posClip).W; + vmov $v12.e7, $v00.e0 ## L:496 | 100 | posClip:sfract.W = 0; + vmov $v12.e3, $v00.e0 ## L:495 | 101 | posClip:sfract.w = 0; + vrcph $v07.e7, $v00.e7 ## L:490 | 102 | invW.W = invert_half(posClip).W; + lsv $v11, 14, 0, $at ## L:494 | ^ | posClip:sint.W = load(BASE_SIZE).x; + vmudl $v29, $v12, $v08.h3 ## L:499 | **105 | posClip *= invW.wwwwWWWW; + vmadm $v29, $v11, $v08.h3 ## L:499 | 106 | posClip *= invW.wwwwWWWW; + vmadn $v12, $v12, $v07.h3 ## L:499 | 107 | posClip *= invW.wwwwWWWW; + vmadh $v11, $v11, $v07.h3 ## L:499 | 108 | posClip *= invW.wwwwWWWW; + vmulf $v14, $v14, $v11.h3 ## L:503 | ***112 | localPartSize:sfract *= posClip:sint.wwwwWWWW; + vmudl $v29, $v12, $v20.v ## L:506 | 113 | vec32 posScreen = posClip * screenSize; + vmadm $v29, $v11, $v20.v ## L:506 | 114 | vec32 posScreen = posClip * screenSize; + vmadn $v08, $v12, $v19.v ## L:506 | 115 | vec32 posScreen = posClip * screenSize; + addiu $at, $zero, 3 ## L:568 | ^ | if(clipA == 0b0000'0011) { + ldv $v03, 0, 16, $s6 ## L:532 | 116 | vec16 color = load(ptrIn, 16).xyzw; + vmadh $v07, $v11, $v19.v ## L:506 | ^ | vec32 posScreen = posClip * screenSize; + vmadh $v06, $v18, $v10.v ## L:507 | 117 | vec16 posCenter = screenOffset:sint +* vecOne; + andi $t1, $t4, 1028 ## L:483 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; + andi $t5, $t4, 16448 ## L:484 | 118 | clipB = temp1 & 0b0100'0000'0100'0000; + vmadh $v05, $v10, $v14.v ## L:510 | ^ | vec16 posEnd = vecOne +* localPartSize:sint; + vsubc $v09, $v06, $v14.v ## L:511 | **121 | posStart = posCenter - localPartSize:sint; + ssv $v06, 4, 12, $s3 ## L:548 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); + slv $v03, 0, 4, $s3 ## L:544 | 122 | store(color.xy, dmaDmemEnd, 4); + vlt $v05, $v05, $v15 ## L:514 | ^ | posEnd = min(posEnd, screenMax); + mfc2 $sp, $v05.e5 ## L:1194 | ***126 | outB = pos.Y; + vge $v09, $v09, $v16 ## L:515 | ^ | posStart = max(posStart, screenMin); + mfc2 $fp, $v05.e1 ## L:1188 | 127 | outA = pos.y; + andi $sp, $sp, 4095 ## L:1195 | *129 | outB &= 0b1111'1111'1111; + mfc2 $s2, $v09.e1 ## L:1188 | 130 | outA = pos.y; + mfc2 $k1, $v09.e0 ## L:1190 | 131 | u32 tmp = pos.x; + andi $fp, $fp, 4095 ## L:1189 | 132 | outA &= 0b1111'1111'1111; + andi $s2, $s2, 4095 ## L:1189 | 133 | outA &= 0b1111'1111'1111; + mfc2 $s1, $v09.e5 ## L:1194 | 134 | outB = pos.Y; + sll $k1, $k1, 12 ## L:1191 | 135 | tmp <<= 12; + or $s2, $s2, $k1 ## L:1192 | 136 | outA |= tmp; + mfc2 $k1, $v09.e4 ## L:1196 | 137 | tmp = pos.X; + vlt $v04, $v09, $v05 ## L:521 | ^ | vec16 extend = posStart < posEnd; + sw $s2, 4 + 16($s3) ## L:552 | 138 | store(posA, dmaDmemEnd, 0x04, 16); + andi $s1, $s1, 4095 ## L:1195 | 139 | outB &= 0b1111'1111'1111; + cfc2 $t4, $vcc ## L:522 | 140 | temp1 = get_vcc(); + sll $k1, $k1, 12 ## L:1197 | 141 | tmp <<= 12; + or $s1, $s1, $k1 ## L:1198 | 142 | outB |= tmp; + andi $a2, $t4, 3 ## L:524 | 143 | temp0 = temp1 & 0b0000'0011; + ldv $v09, 0, 24, $s6 ## L:559 | 144 | posStart.xyzw = load(ptrIn, 24).xyzw; + mfc2 $k1, $v05.e0 ## L:1190 | 145 | u32 tmp = pos.x; + or $t1, $t1, $a2 ## L:525 | 146 | clipA |= temp0; + ldv $v09, 8, 32, $s6 ## L:560 | 147 | posStart.XYZW = load(ptrIn, 24).XYZW; + sll $k1, $k1, 12 ## L:1191 | 148 | tmp <<= 12; + or $fp, $fp, $k1 ## L:1192 | 149 | outA |= tmp; + mfc2 $k1, $v05.e4 ## L:1196 | 150 | tmp = pos.X; + andi $a2, $t4, 48 ## L:527 | 151 | temp0 = temp1 & 0b0011'0000; + or $t5, $t5, $a2 ## L:528 | 152 | clipB |= temp0; + sll $k1, $k1, 12 ## L:1197 | 153 | tmp <<= 12; + vmulf $v14, $v13, $v09.h3 ## L:561 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + sw $fp, 0 + 16($s3) ## L:553 | 154 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + or $sp, $sp, $k1 ## L:1198 | 155 | outB |= tmp; + bne $t1, $at, LABEL_TPXCmd_DrawColor_0007 ## L:568 | 156 | if(clipA == 0b0000'0011) { + sb $t2, 0 + 16($s3) ## L:554 | 157 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + addiu $s3, $s3, 24 ## L:569 | 158 | dmaDmemEnd += 24; LABEL_TPXCmd_DrawColor_0007: - addiu $at, $zero, 48 ## L:578 | 159 | if(clipB == 0b0011'0000) { - bne $t5, $at, LABEL_TPXCmd_DrawColor_0008 ## L:578 | 160 | if(clipB == 0b0011'0000) { - addiu $s6, $s6, 24 ## L:572 | *162 | ptrIn += 24; - sw $s1, 4 + 16($s3) ## L:582 | 163 | store(posB, dmaDmemEnd, 0x04, 16); - ssv $v06, 12, 12, $s3 ## L:580 | 164 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); - sw $sp, 0 + 16($s3) ## L:583 | 165 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - sb $t2, 0 + 16($s3) ## L:584 | 166 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - slv $v03, 4, 4, $s3 ## L:579 | 167 | store(color.zw, dmaDmemEnd, 4); - addiu $s3, $s3, 24 ## L:586 | 168 | dmaDmemEnd += 24; + addiu $at, $zero, 48 ## L:579 | 159 | if(clipB == 0b0011'0000) { + bne $t5, $at, LABEL_TPXCmd_DrawColor_0008 ## L:579 | 160 | if(clipB == 0b0011'0000) { + addiu $s6, $s6, 24 ## L:573 | 161 | ptrIn += 24; + sw $sp, 0 + 16($s3) ## L:584 | 162 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + sb $t2, 0 + 16($s3) ## L:585 | 163 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + slv $v03, 4, 4, $s3 ## L:580 | 164 | store(color.zw, dmaDmemEnd, 4); + sw $s1, 4 + 16($s3) ## L:583 | 165 | store(posB, dmaDmemEnd, 0x04, 16); + addiu $s3, $s3, 24 ## L:587 | 166 | dmaDmemEnd += 24; + ssv $v06, 12, -12, $s3 ## L:581 | 167 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); LABEL_TPXCmd_DrawColor_0008: - vmudn $v12, $v28, $v09.h0 ## L:93 | ^ | out = mat0 * vec.xxxxXXXX; - sltu $at, $s3, $s5 ## L:593 | 169 | if(dmaDmemEnd >= dmaDmemFlush) { - vmadh $v11, $v27, $v09.h0 ## L:93 | ^ | out = mat0 * vec.xxxxXXXX; - vmadn $v12, $v26, $v09.h1 ## L:94 | 170 | out = mat1 +* vec.yyyyYYYY; - vmadh $v11, $v25, $v09.h1 ## L:94 | 171 | out = mat1 +* vec.yyyyYYYY; - vmadn $v12, $v24, $v09.h2 ## L:95 | 172 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v11, $v23, $v09.h2 ## L:95 | 173 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v12, $v22, $v30.e7 ## L:96 | 174 | out = mat3 +* 1; - bne $at, $zero, LABEL_TPXCmd_DrawColor_0009 ## L:593 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { - vmadh $v11, $v21, $v30.e7 ## L:96 | *176 | out = mat3 +* 1; - jal RDPQ_Send ## L:594 | 177 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 - nop ## L:594 | *179 | RDPQ_Send(dmaDmem, dmaDmemEnd); - or $s3, $zero, $s4 ## L:595 | 180 | dmaDmemEnd = dmaDmem; + vmudn $v12, $v28, $v09.h0 ## L:94 | ^ | out = mat0 * vec.xxxxXXXX; + vmadh $v11, $v27, $v09.h0 ## L:94 | 168 | out = mat0 * vec.xxxxXXXX; + vmadn $v12, $v26, $v09.h1 ## L:95 | 169 | out = mat1 +* vec.yyyyYYYY; + vmadh $v11, $v25, $v09.h1 ## L:95 | 170 | out = mat1 +* vec.yyyyYYYY; + vmadn $v12, $v24, $v09.h2 ## L:96 | 171 | out = mat2 +* vec.zzzzZZZZ; + sltu $at, $s3, $s5 ## L:594 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v11, $v23, $v09.h2 ## L:96 | 172 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v12, $v22, $v30.e7 ## L:97 | 173 | out = mat3 +* 1; + bne $at, $zero, LABEL_TPXCmd_DrawColor_0009 ## L:594 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v11, $v21, $v30.e7 ## L:97 | 174 | out = mat3 +* 1; + jal RDPQ_Send ## L:595 | 175 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 + nop ## L:595 | 176 | RDPQ_Send(dmaDmem, dmaDmemEnd); + or $s3, $zero, $s4 ## L:596 | *178 | dmaDmemEnd = dmaDmem; LABEL_TPXCmd_DrawColor_0009: - vch $v29, $v11, $v11.h3 ## L:598 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v12, $v12.h3 ## L:598 | 181 | temp1 = clip(posClip, posClip.wwwwWWWW); - bne $s6, $s7, LABEL_TPXCmd_DrawColor_0005 ## L:598 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:598 | *183 | temp1 = clip(posClip, posClip.wwwwWWWW); + vch $v29, $v11, $v11.h3 ## L:599 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v12, $v12.h3 ## L:599 | 179 | temp1 = clip(posClip, posClip.wwwwWWWW); + bne $s6, $s7, LABEL_TPXCmd_DrawColor_0005 ## L:599 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:599 | 180 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawColor_0006: - beq $zero, $zero, LABEL_TPXCmd_DrawColor_0004 ## L:598 | 184 | temp1 = clip(posClip, posClip.wwwwWWWW); - nop ## L:598 | *186 | temp1 = clip(posClip, posClip.wwwwWWWW); + beq $zero, $zero, LABEL_TPXCmd_DrawColor_0004 ## L:599 | 181 | temp1 = clip(posClip, posClip.wwwwWWWW); + nop ## L:599 | *183 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawColor_0003: - lpv $v09, 0, 0, $s6 ## L:116 | 187 | vec16 posStart = load_vec_s8(ptrIn, 0x00); - vmulf $v14, $v13, $v09.h3 ## L:117 | ***191 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - vmudm $v09, $v09, $v31.e7 ## L:118 | 192 | posStart >>= 8; - vmudn $v12, $v28, $v09.h0 ## L:93 | ***196 | out = mat0 * vec.xxxxXXXX; - vmadh $v11, $v27, $v09.h0 ## L:93 | 197 | out = mat0 * vec.xxxxXXXX; - vmadn $v12, $v26, $v09.h1 ## L:94 | 198 | out = mat1 +* vec.yyyyYYYY; - vmadh $v11, $v25, $v09.h1 ## L:94 | 199 | out = mat1 +* vec.yyyyYYYY; - vmadn $v12, $v24, $v09.h2 ## L:95 | 200 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v11, $v23, $v09.h2 ## L:95 | 201 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v12, $v22, $v30.e7 ## L:96 | 202 | out = mat3 +* 1; - vmadh $v11, $v21, $v30.e7 ## L:96 | 203 | out = mat3 +* 1; - vch $v29, $v11, $v11.h3 ## L:122 | ***207 | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v12, $v12.h3 ## L:122 | 208 | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:122 | 209 | temp1 = clip(posClip, posClip.wwwwWWWW); + lpv $v09, 0, 0, $s6 ## L:117 | 1 | vec16 posStart = load_vec_s8(ptrIn, 0x00); + vmulf $v14, $v13, $v09.h3 ## L:118 | ***5 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + vmudm $v09, $v09, $v31.e7 ## L:119 | 6 | posStart >>= 8; + vmudn $v12, $v28, $v09.h0 ## L:94 | ***10 | out = mat0 * vec.xxxxXXXX; + vmadh $v11, $v27, $v09.h0 ## L:94 | 11 | out = mat0 * vec.xxxxXXXX; + vmadn $v12, $v26, $v09.h1 ## L:95 | 12 | out = mat1 +* vec.yyyyYYYY; + vmadh $v11, $v25, $v09.h1 ## L:95 | 13 | out = mat1 +* vec.yyyyYYYY; + vmadn $v12, $v24, $v09.h2 ## L:96 | 14 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v11, $v23, $v09.h2 ## L:96 | 15 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v12, $v22, $v30.e7 ## L:97 | 16 | out = mat3 +* 1; + vmadh $v11, $v21, $v30.e7 ## L:97 | 17 | out = mat3 +* 1; + vch $v29, $v11, $v11.h3 ## L:123 | ***21 | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v12, $v12.h3 ## L:123 | 22 | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:123 | 23 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawColor_000A: - vmudl $v12, $v12, $v17.v ## L:133 | ^ | posClip *= normScaleW:ufract; - vmadm $v11, $v11, $v17.v ## L:133 | 210 | posClip *= normScaleW:ufract; - vmadn $v12, $v00, $v00 ## L:133 | 211 | posClip *= normScaleW:ufract; - ldv $v03, 0, 8, $s6 ## L:180 | ^ | vec16 color = load(ptrIn, 8).xyzw; - andi $t1, $t4, 1028 ## L:129 | 212 | clipA = temp1 & 0b0000'0100'0000'0100; - addiu $t2, $zero, 54 ## L:182 | *214 | cmdRdpRect = 0x36; - vrcph $v07.e3, $v11.e3 ## L:135 | ^ | invW.w = invert_half(posClip).w; - vrcpl $v08.e3, $v12.e3 ## L:135 | 215 | invW.w = invert_half(posClip).w; - vrcph $v07.e3, $v11.e7 ## L:136 | 216 | invW.W = invert_half(posClip).W; - ori $at, $zero, %lo(BASE_SIZE) ## L:139 | ^ | posClip:sint.w = load(BASE_SIZE).x; - vrcpl $v08.e7, $v12.e7 ## L:136 | 217 | invW.W = invert_half(posClip).W; - lsv $v11, 6, 0, $at ## L:139 | ^ | posClip:sint.w = load(BASE_SIZE).x; - vmov $v12.e3, $v00.e0 ## L:141 | 218 | posClip:sfract.w = 0; - lsv $v11, 14, 0, $at ## L:140 | ^ | posClip:sint.W = load(BASE_SIZE).x; - addiu $at, $zero, 3 ## L:214 | 219 | if(clipA == 0b0000'0011) { - vmov $v12.e7, $v00.e0 ## L:142 | ^ | posClip:sfract.W = 0; - vrcph $v07.e7, $v00.e7 ## L:136 | 220 | invW.W = invert_half(posClip).W; - vmudl $v29, $v12, $v08.h3 ## L:145 | **223 | posClip *= invW.wwwwWWWW; - vmadm $v29, $v11, $v08.h3 ## L:145 | 224 | posClip *= invW.wwwwWWWW; - vmadn $v12, $v12, $v07.h3 ## L:145 | 225 | posClip *= invW.wwwwWWWW; - vmadh $v11, $v11, $v07.h3 ## L:145 | 226 | posClip *= invW.wwwwWWWW; - vmulf $v14, $v14, $v11.h3 ## L:149 | ***230 | localPartSize:sfract *= posClip:sint.wwwwWWWW; - andi $t5, $t4, 16448 ## L:130 | ^ | clipB = temp1 & 0b0100'0000'0100'0000; - vmudl $v29, $v12, $v20.v ## L:152 | 231 | vec32 posScreen = posClip * screenSize; - slv $v03, 0, 4, $s3 ## L:190 | ^ | store(color.xy, dmaDmemEnd, 4); - vmadm $v29, $v11, $v20.v ## L:152 | 232 | vec32 posScreen = posClip * screenSize; - vmadn $v08, $v12, $v19.v ## L:152 | 233 | vec32 posScreen = posClip * screenSize; - vmadh $v07, $v11, $v19.v ## L:152 | 234 | vec32 posScreen = posClip * screenSize; - vmadh $v06, $v18, $v10.v ## L:153 | 235 | vec16 posCenter = screenOffset:sint +* vecOne; - vmadh $v05, $v10, $v14.v ## L:156 | 236 | vec16 posEnd = vecOne +* localPartSize:sint; - vsubc $v09, $v06, $v14.v ## L:157 | **239 | posStart = posCenter - localPartSize:sint; - vlt $v05, $v05, $v15 ## L:160 | 240 | posEnd = min(posEnd, screenMax); - vge $v09, $v09, $v16 ## L:161 | **243 | posStart = max(posStart, screenMin); - ssv $v06, 4, 12, $s3 ## L:194 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); - mfc2 $fp, $v05.e1 ## L:1191 | 244 | outA = pos.y; - mfc2 $sp, $v05.e5 ## L:1197 | 245 | outB = pos.Y; - andi $fp, $fp, 4095 ## L:1192 | *247 | outA &= 0b1111'1111'1111; - mfc2 $k1, $v09.e0 ## L:1193 | 248 | u32 tmp = pos.x; - mfc2 $s2, $v09.e1 ## L:1191 | 249 | outA = pos.y; - andi $sp, $sp, 4095 ## L:1198 | 250 | outB &= 0b1111'1111'1111; - vlt $v04, $v09, $v05 ## L:167 | ^ | vec16 extend = posStart < posEnd; - sll $k1, $k1, 12 ## L:1194 | 251 | tmp <<= 12; - mfc2 $s1, $v09.e5 ## L:1197 | 252 | outB = pos.Y; - andi $s2, $s2, 4095 ## L:1192 | 253 | outA &= 0b1111'1111'1111; - or $s2, $s2, $k1 ## L:1195 | 254 | outA |= tmp; - mfc2 $k1, $v09.e4 ## L:1199 | 255 | tmp = pos.X; - cfc2 $t4, $vcc ## L:168 | 256 | temp1 = get_vcc(); - lpv $v09, 0, 16, $s6 ## L:209 | 257 | posStart = load_vec_s8(ptrIn, 16); - sll $k1, $k1, 12 ## L:1200 | 258 | tmp <<= 12; - andi $s1, $s1, 4095 ## L:1198 | 259 | outB &= 0b1111'1111'1111; - andi $a2, $t4, 3 ## L:170 | 260 | temp0 = temp1 & 0b0000'0011; - or $s1, $s1, $k1 ## L:1201 | 261 | outB |= tmp; - mfc2 $k1, $v05.e0 ## L:1193 | 262 | u32 tmp = pos.x; - vmulf $v14, $v13, $v09.h3 ## L:210 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - vmudm $v09, $v09, $v31.e7 ## L:211 | 263 | posStart >>= 8; - or $t1, $t1, $a2 ## L:171 | ^ | clipA |= temp0; - andi $a2, $t4, 48 ## L:173 | 264 | temp0 = temp1 & 0b0011'0000; - sll $k1, $k1, 12 ## L:1194 | 265 | tmp <<= 12; - or $fp, $fp, $k1 ## L:1195 | 266 | outA |= tmp; - mfc2 $k1, $v05.e4 ## L:1199 | 267 | tmp = pos.X; - sw $s2, 4 + 16($s3) ## L:198 | 268 | store(posA, dmaDmemEnd, 0x04, 16); - or $t5, $t5, $a2 ## L:174 | 269 | clipB |= temp0; - sw $fp, 0 + 16($s3) ## L:199 | 270 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - sb $t2, 0 + 16($s3) ## L:200 | 271 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - sll $k1, $k1, 12 ## L:1200 | 272 | tmp <<= 12; - bne $t1, $at, LABEL_TPXCmd_DrawColor_000C ## L:214 | 273 | if(clipA == 0b0000'0011) { - or $sp, $sp, $k1 ## L:1201 | *275 | outB |= tmp; - addiu $s3, $s3, 24 ## L:215 | 276 | dmaDmemEnd += 24; + vmudl $v12, $v12, $v17.v ## L:134 | ^ | posClip *= normScaleW:ufract; + ldv $v03, 0, 8, $s6 ## L:181 | 24 | vec16 color = load(ptrIn, 8).xyzw; + vmadm $v11, $v11, $v17.v ## L:134 | ^ | posClip *= normScaleW:ufract; + ori $at, $zero, %lo(BASE_SIZE) ## L:140 | 25 | posClip:sint.w = load(BASE_SIZE).x; + vmadn $v12, $v00, $v00 ## L:134 | ^ | posClip *= normScaleW:ufract; + vrcph $v07.e3, $v11.e3 ## L:136 | **28 | invW.w = invert_half(posClip).w; + addiu $t2, $zero, 54 ## L:183 | ^ | cmdRdpRect = 0x36; + vrcpl $v08.e3, $v12.e3 ## L:136 | 29 | invW.w = invert_half(posClip).w; + vrcph $v07.e3, $v11.e7 ## L:137 | 30 | invW.W = invert_half(posClip).W; + vrcpl $v08.e7, $v12.e7 ## L:137 | 31 | invW.W = invert_half(posClip).W; + lsv $v11, 14, 0, $at ## L:141 | ^ | posClip:sint.W = load(BASE_SIZE).x; + lsv $v11, 6, 0, $at ## L:140 | 32 | posClip:sint.w = load(BASE_SIZE).x; + vmov $v12.e3, $v00.e0 ## L:142 | ^ | posClip:sfract.w = 0; + addiu $at, $zero, 3 ## L:215 | 33 | if(clipA == 0b0000'0011) { + vmov $v12.e7, $v00.e0 ## L:143 | ^ | posClip:sfract.W = 0; + vrcph $v07.e7, $v00.e7 ## L:137 | 34 | invW.W = invert_half(posClip).W; + vmudl $v29, $v12, $v08.h3 ## L:146 | **37 | posClip *= invW.wwwwWWWW; + vmadm $v29, $v11, $v08.h3 ## L:146 | 38 | posClip *= invW.wwwwWWWW; + vmadn $v12, $v12, $v07.h3 ## L:146 | 39 | posClip *= invW.wwwwWWWW; + vmadh $v11, $v11, $v07.h3 ## L:146 | 40 | posClip *= invW.wwwwWWWW; + vmulf $v14, $v14, $v11.h3 ## L:150 | ***44 | localPartSize:sfract *= posClip:sint.wwwwWWWW; + vmudl $v29, $v12, $v20.v ## L:153 | 45 | vec32 posScreen = posClip * screenSize; + vmadm $v29, $v11, $v20.v ## L:153 | 46 | vec32 posScreen = posClip * screenSize; + vmadn $v08, $v12, $v19.v ## L:153 | 47 | vec32 posScreen = posClip * screenSize; + vmadh $v07, $v11, $v19.v ## L:153 | 48 | vec32 posScreen = posClip * screenSize; + vmadh $v06, $v18, $v10.v ## L:154 | 49 | vec16 posCenter = screenOffset:sint +* vecOne; + vmadh $v05, $v10, $v14.v ## L:157 | 50 | vec16 posEnd = vecOne +* localPartSize:sint; + andi $t1, $t4, 1028 ## L:130 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; + andi $t5, $t4, 16448 ## L:131 | **53 | clipB = temp1 & 0b0100'0000'0100'0000; + vsubc $v09, $v06, $v14.v ## L:158 | ^ | posStart = posCenter - localPartSize:sint; + vlt $v05, $v05, $v15 ## L:161 | 54 | posEnd = min(posEnd, screenMax); + slv $v03, 0, 4, $s3 ## L:191 | ^ | store(color.xy, dmaDmemEnd, 4); + vge $v09, $v09, $v16 ## L:162 | **57 | posStart = max(posStart, screenMin); + ssv $v06, 4, 12, $s3 ## L:195 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); + mfc2 $fp, $v05.e1 ## L:1188 | 58 | outA = pos.y; + mfc2 $sp, $v05.e5 ## L:1194 | 59 | outB = pos.Y; + andi $fp, $fp, 4095 ## L:1189 | *61 | outA &= 0b1111'1111'1111; + mfc2 $s2, $v09.e1 ## L:1188 | 62 | outA = pos.y; + mfc2 $k1, $v09.e0 ## L:1190 | 63 | u32 tmp = pos.x; + andi $sp, $sp, 4095 ## L:1195 | 64 | outB &= 0b1111'1111'1111; + andi $s2, $s2, 4095 ## L:1189 | 65 | outA &= 0b1111'1111'1111; + vlt $v04, $v09, $v05 ## L:168 | ^ | vec16 extend = posStart < posEnd; + mfc2 $s1, $v09.e5 ## L:1194 | 66 | outB = pos.Y; + sll $k1, $k1, 12 ## L:1191 | 67 | tmp <<= 12; + or $s2, $s2, $k1 ## L:1192 | 68 | outA |= tmp; + mfc2 $k1, $v09.e4 ## L:1196 | 69 | tmp = pos.X; + cfc2 $t4, $vcc ## L:169 | 70 | temp1 = get_vcc(); + andi $s1, $s1, 4095 ## L:1195 | 71 | outB &= 0b1111'1111'1111; + sll $k1, $k1, 12 ## L:1197 | 72 | tmp <<= 12; + andi $a2, $t4, 3 ## L:171 | 73 | temp0 = temp1 & 0b0000'0011; + or $s1, $s1, $k1 ## L:1198 | 74 | outB |= tmp; + mfc2 $k1, $v05.e0 ## L:1190 | 75 | u32 tmp = pos.x; + lpv $v09, 0, 16, $s6 ## L:210 | 76 | posStart = load_vec_s8(ptrIn, 16); + or $t1, $t1, $a2 ## L:172 | 77 | clipA |= temp0; + sll $k1, $k1, 12 ## L:1191 | 78 | tmp <<= 12; + or $fp, $fp, $k1 ## L:1192 | 79 | outA |= tmp; + mfc2 $k1, $v05.e4 ## L:1196 | 80 | tmp = pos.X; + sw $fp, 0 + 16($s3) ## L:200 | 81 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + andi $a2, $t4, 48 ## L:174 | 82 | temp0 = temp1 & 0b0011'0000; + sw $s2, 4 + 16($s3) ## L:199 | 83 | store(posA, dmaDmemEnd, 0x04, 16); + sll $k1, $k1, 12 ## L:1197 | 84 | tmp <<= 12; + vmulf $v14, $v13, $v09.h3 ## L:211 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + or $sp, $sp, $k1 ## L:1198 | 85 | outB |= tmp; + vmudm $v09, $v09, $v31.e7 ## L:212 | ^ | posStart >>= 8; + or $t5, $t5, $a2 ## L:175 | 86 | clipB |= temp0; + bne $t1, $at, LABEL_TPXCmd_DrawColor_000C ## L:215 | 87 | if(clipA == 0b0000'0011) { + sb $t2, 0 + 16($s3) ## L:201 | *89 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + addiu $s3, $s3, 24 ## L:216 | 90 | dmaDmemEnd += 24; LABEL_TPXCmd_DrawColor_000C: - addiu $at, $zero, 48 ## L:225 | 277 | if(clipB == 0b0011'0000) { - bne $t5, $at, LABEL_TPXCmd_DrawColor_000D ## L:225 | 278 | if(clipB == 0b0011'0000) { - addiu $s6, $s6, 16 ## L:221 | *280 | ptrIn += 16; - ssv $v06, 12, 12, $s3 ## L:227 | 281 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); - slv $v03, 4, 4, $s3 ## L:226 | 282 | store(color.zw, dmaDmemEnd, 4); - sw $sp, 0 + 16($s3) ## L:230 | 283 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - sw $s1, 4 + 16($s3) ## L:229 | 284 | store(posB, dmaDmemEnd, 0x04, 16); - sb $t2, 0 + 16($s3) ## L:231 | 285 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - addiu $s3, $s3, 24 ## L:233 | 286 | dmaDmemEnd += 24; + addiu $at, $zero, 48 ## L:226 | 91 | if(clipB == 0b0011'0000) { + bne $t5, $at, LABEL_TPXCmd_DrawColor_000D ## L:226 | 92 | if(clipB == 0b0011'0000) { + addiu $s6, $s6, 16 ## L:222 | *94 | ptrIn += 16; + sw $sp, 0 + 16($s3) ## L:231 | 95 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + sb $t2, 0 + 16($s3) ## L:232 | 96 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + sw $s1, 4 + 16($s3) ## L:230 | 97 | store(posB, dmaDmemEnd, 0x04, 16); + slv $v03, 4, 4, $s3 ## L:227 | 98 | store(color.zw, dmaDmemEnd, 4); + ssv $v06, 12, 12, $s3 ## L:228 | 99 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); + addiu $s3, $s3, 24 ## L:234 | 100 | dmaDmemEnd += 24; LABEL_TPXCmd_DrawColor_000D: - vmudn $v12, $v28, $v09.h0 ## L:93 | ^ | out = mat0 * vec.xxxxXXXX; - vmadh $v11, $v27, $v09.h0 ## L:93 | 287 | out = mat0 * vec.xxxxXXXX; - vmadn $v12, $v26, $v09.h1 ## L:94 | 288 | out = mat1 +* vec.yyyyYYYY; - vmadh $v11, $v25, $v09.h1 ## L:94 | 289 | out = mat1 +* vec.yyyyYYYY; - sltu $at, $s3, $s5 ## L:240 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { - vmadn $v12, $v24, $v09.h2 ## L:95 | 290 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v11, $v23, $v09.h2 ## L:95 | 291 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v12, $v22, $v30.e7 ## L:96 | 292 | out = mat3 +* 1; - bne $at, $zero, LABEL_TPXCmd_DrawColor_000E ## L:240 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { - vmadh $v11, $v21, $v30.e7 ## L:96 | *294 | out = mat3 +* 1; - jal RDPQ_Send ## L:241 | 295 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 - nop ## L:241 | *297 | RDPQ_Send(dmaDmem, dmaDmemEnd); - or $s3, $zero, $s4 ## L:242 | 298 | dmaDmemEnd = dmaDmem; + vmudn $v12, $v28, $v09.h0 ## L:94 | ^ | out = mat0 * vec.xxxxXXXX; + sltu $at, $s3, $s5 ## L:241 | 101 | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v11, $v27, $v09.h0 ## L:94 | ^ | out = mat0 * vec.xxxxXXXX; + vmadn $v12, $v26, $v09.h1 ## L:95 | 102 | out = mat1 +* vec.yyyyYYYY; + vmadh $v11, $v25, $v09.h1 ## L:95 | 103 | out = mat1 +* vec.yyyyYYYY; + vmadn $v12, $v24, $v09.h2 ## L:96 | 104 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v11, $v23, $v09.h2 ## L:96 | 105 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v12, $v22, $v30.e7 ## L:97 | 106 | out = mat3 +* 1; + bne $at, $zero, LABEL_TPXCmd_DrawColor_000E ## L:241 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v11, $v21, $v30.e7 ## L:97 | *108 | out = mat3 +* 1; + jal RDPQ_Send ## L:242 | 109 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 + nop ## L:242 | *111 | RDPQ_Send(dmaDmem, dmaDmemEnd); + or $s3, $zero, $s4 ## L:243 | 112 | dmaDmemEnd = dmaDmem; LABEL_TPXCmd_DrawColor_000E: - vch $v29, $v11, $v11.h3 ## L:245 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v12, $v12.h3 ## L:245 | 299 | temp1 = clip(posClip, posClip.wwwwWWWW); - bne $s6, $s7, LABEL_TPXCmd_DrawColor_000A ## L:245 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:245 | *301 | temp1 = clip(posClip, posClip.wwwwWWWW); + vch $v29, $v11, $v11.h3 ## L:246 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v12, $v12.h3 ## L:246 | 113 | temp1 = clip(posClip, posClip.wwwwWWWW); + bne $s6, $s7, LABEL_TPXCmd_DrawColor_000A ## L:246 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:246 | *115 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawColor_0004: - j RDPQ_Send ## L:908 | 302 | goto RDPQ_Send; - ori $ra, $zero, %lo(RSPQ_Loop) ## L:907 | 303 | RA = RSPQ_Loop; + j RDPQ_Send ## L:907 | ********************************************************************184 | goto RDPQ_Send; + ori $ra, $zero, %lo(RSPQ_Loop) ## L:906 | *186 | RA = RSPQ_Loop; mulMat4Mat4: - ldv $v01, 0, 0, $s3 - ldv $v10, 0, 8, $s4 - ldv $v02, 0, 8, $s3 - ldv $v09, 0, 0, $s4 - ldv $v02, 8, 8, $s3 - ldv $v10, 8, 24, $s4 - ldv $v01, 8, 0, $s3 - ldv $v09, 8, 16, $s4 - ldv $v03, 0, 16, $s3 - ldv $v05, 0, 32, $s3 - vmudl $v29, $v02, $v10.h0 - ldv $v04, 0, 24, $s3 - ldv $v06, 0, 40, $s3 - ldv $v06, 8, 40, $s3 - ldv $v04, 8, 24, $s3 - vmadm $v29, $v01, $v10.h0 - ldv $v03, 8, 16, $s3 - vmadn $v14, $v02, $v09.h0 - ldv $v07, 0, 48, $s3 - ldv $v08, 0, 56, $s3 - vmadh $v13, $v01, $v09.h0 - vmadl $v29, $v04, $v10.h1 - ldv $v05, 8, 32, $s3 - vmadm $v29, $v03, $v10.h1 - ldv $v11, 0, 32, $s4 - ldv $v12, 0, 40, $s4 - vmadn $v14, $v04, $v09.h1 - vmadh $v13, $v03, $v09.h1 - ldv $v08, 8, 56, $s3 - vmadl $v29, $v06, $v10.h2 - ldv $v12, 8, 56, $s4 - ldv $v07, 8, 48, $s3 - vmadm $v29, $v05, $v10.h2 - vmadn $v14, $v06, $v09.h2 - ldv $v11, 8, 48, $s4 - vmadh $v13, $v05, $v09.h2 - vmadl $v29, $v08, $v10.h3 - vmadm $v29, $v07, $v10.h3 - vmadn $v10, $v08, $v09.h3 - vmadh $v09, $v07, $v09.h3 - vmudl $v29, $v02, $v12.h0 - vmadm $v29, $v01, $v12.h0 - vmadn $v14, $v02, $v11.h0 - vmadh $v13, $v01, $v11.h0 - vmadl $v29, $v04, $v12.h1 - vmadm $v29, $v03, $v12.h1 - sdv $v09, 0, 0, $s2 - vmadn $v14, $v04, $v11.h1 - vmadh $v13, $v03, $v11.h1 - vmadl $v29, $v06, $v12.h2 - sdv $v10, 8, 24, $s2 - sdv $v09, 8, 16, $s2 - vmadm $v29, $v05, $v12.h2 - vmadn $v14, $v06, $v11.h2 - vmadh $v13, $v05, $v11.h2 - vmadl $v29, $v08, $v12.h3 - vmadm $v29, $v07, $v12.h3 - vmadn $v12, $v08, $v11.h3 - vmadh $v11, $v07, $v11.h3 - sdv $v10, 0, 8, $s2 - sdv $v12, 0, 40, $s2 - sdv $v11, 0, 32, $s2 - sdv $v12, 8, 56, $s2 - jr $ra - sdv $v11, 8, 48, $s2 + ## hot-path cycles: 50 + ldv $v02, 0, 8, $s3 ## L:932 | ^ | vec32 matL0 = load(addrMatL, 0x00).xyzwxyzw; + ldv $v10, 8, 24, $s4 ## L:940 | 2 | matR01.XYZW = load(addrMatR, 0x10).xyzw; + ldv $v01, 8, 0, $s3 ## L:932 | 3 | vec32 matL0 = load(addrMatL, 0x00).xyzwxyzw; + ldv $v09, 8, 16, $s4 ## L:940 | 4 | matR01.XYZW = load(addrMatR, 0x10).xyzw; + ldv $v10, 0, 8, $s4 ## L:939 | 5 | matR01.xyzw = load(addrMatR, 0x00).xyzw; + ldv $v02, 8, 8, $s3 ## L:932 | 6 | vec32 matL0 = load(addrMatL, 0x00).xyzwxyzw; + ldv $v01, 0, 0, $s3 ## L:932 | 7 | vec32 matL0 = load(addrMatL, 0x00).xyzwxyzw; + ldv $v09, 0, 0, $s4 ## L:939 | 8 | matR01.xyzw = load(addrMatR, 0x00).xyzw; + ldv $v04, 0, 24, $s3 ## L:933 | 9 | vec32 matL1 = load(addrMatL, 0x10).xyzwxyzw; + ldv $v03, 8, 16, $s3 ## L:933 | 10 | vec32 matL1 = load(addrMatL, 0x10).xyzwxyzw; + vmudl $v29, $v02, $v10.h0 ## L:945 | ^ | tmp = matL0 * matR01.xxxxXXXX; + vmadm $v29, $v01, $v10.h0 ## L:945 | 11 | tmp = matL0 * matR01.xxxxXXXX; + ldv $v04, 8, 24, $s3 ## L:933 | ^ | vec32 matL1 = load(addrMatL, 0x10).xyzwxyzw; + vmadn $v14, $v02, $v09.h0 ## L:945 | 12 | tmp = matL0 * matR01.xxxxXXXX; + ldv $v03, 0, 16, $s3 ## L:933 | ^ | vec32 matL1 = load(addrMatL, 0x10).xyzwxyzw; + ldv $v06, 8, 40, $s3 ## L:934 | 13 | vec32 matL2 = load(addrMatL, 0x20).xyzwxyzw; + ldv $v06, 0, 40, $s3 ## L:934 | 14 | vec32 matL2 = load(addrMatL, 0x20).xyzwxyzw; + vmadh $v13, $v01, $v09.h0 ## L:945 | ^ | tmp = matL0 * matR01.xxxxXXXX; + vmadl $v29, $v04, $v10.h1 ## L:946 | 15 | tmp = matL1 +* matR01.yyyyYYYY; + ldv $v05, 0, 32, $s3 ## L:934 | ^ | vec32 matL2 = load(addrMatL, 0x20).xyzwxyzw; + vmadm $v29, $v03, $v10.h1 ## L:946 | 16 | tmp = matL1 +* matR01.yyyyYYYY; + ldv $v05, 8, 32, $s3 ## L:934 | ^ | vec32 matL2 = load(addrMatL, 0x20).xyzwxyzw; + vmadn $v14, $v04, $v09.h1 ## L:946 | 17 | tmp = matL1 +* matR01.yyyyYYYY; + ldv $v08, 0, 56, $s3 ## L:935 | ^ | vec32 matL3 = load(addrMatL, 0x30).xyzwxyzw; + ldv $v08, 8, 56, $s3 ## L:935 | 18 | vec32 matL3 = load(addrMatL, 0x30).xyzwxyzw; + vmadh $v13, $v03, $v09.h1 ## L:946 | ^ | tmp = matL1 +* matR01.yyyyYYYY; + ldv $v07, 0, 48, $s3 ## L:935 | 19 | vec32 matL3 = load(addrMatL, 0x30).xyzwxyzw; + vmadl $v29, $v06, $v10.h2 ## L:947 | ^ | tmp = matL2 +* matR01.zzzzZZZZ; + vmadm $v29, $v05, $v10.h2 ## L:947 | 20 | tmp = matL2 +* matR01.zzzzZZZZ; + ldv $v07, 8, 48, $s3 ## L:935 | ^ | vec32 matL3 = load(addrMatL, 0x30).xyzwxyzw; + vmadn $v14, $v06, $v09.h2 ## L:947 | 21 | tmp = matL2 +* matR01.zzzzZZZZ; + ldv $v11, 8, 48, $s4 ## L:942 | ^ | matR23.XYZW = load(addrMatR, 0x30).xyzw; + vmadh $v13, $v05, $v09.h2 ## L:947 | 22 | tmp = matL2 +* matR01.zzzzZZZZ; + ldv $v12, 8, 56, $s4 ## L:942 | ^ | matR23.XYZW = load(addrMatR, 0x30).xyzw; + vmadl $v29, $v08, $v10.h3 ## L:948 | 23 | matR01 = matL3 +* matR01.wwwwWWWW; + ldv $v12, 0, 40, $s4 ## L:941 | ^ | matR23.xyzw = load(addrMatR, 0x20).xyzw; + vmadm $v29, $v07, $v10.h3 ## L:948 | 24 | matR01 = matL3 +* matR01.wwwwWWWW; + ldv $v11, 0, 32, $s4 ## L:941 | ^ | matR23.xyzw = load(addrMatR, 0x20).xyzw; + vmadn $v10, $v08, $v09.h3 ## L:948 | 25 | matR01 = matL3 +* matR01.wwwwWWWW; + vmadh $v09, $v07, $v09.h3 ## L:948 | 26 | matR01 = matL3 +* matR01.wwwwWWWW; + vmudl $v29, $v02, $v12.h0 ## L:950 | 27 | tmp = matL0 * matR23.xxxxXXXX; + vmadm $v29, $v01, $v12.h0 ## L:950 | 28 | tmp = matL0 * matR23.xxxxXXXX; + vmadn $v14, $v02, $v11.h0 ## L:950 | 29 | tmp = matL0 * matR23.xxxxXXXX; + vmadh $v13, $v01, $v11.h0 ## L:950 | 30 | tmp = matL0 * matR23.xxxxXXXX; + vmadl $v29, $v04, $v12.h1 ## L:951 | 31 | tmp = matL1 +* matR23.yyyyYYYY; + vmadm $v29, $v03, $v12.h1 ## L:951 | 32 | tmp = matL1 +* matR23.yyyyYYYY; + sdv $v10, 8, 24, $s2 ## L:956 | ^ | store(matR01.XYZW, addrOut, 0x10); + vmadn $v14, $v04, $v11.h1 ## L:951 | 33 | tmp = matL1 +* matR23.yyyyYYYY; + vmadh $v13, $v03, $v11.h1 ## L:951 | 34 | tmp = matL1 +* matR23.yyyyYYYY; + vmadl $v29, $v06, $v12.h2 ## L:952 | 35 | tmp = matL2 +* matR23.zzzzZZZZ; + vmadm $v29, $v05, $v12.h2 ## L:952 | 36 | tmp = matL2 +* matR23.zzzzZZZZ; + vmadn $v14, $v06, $v11.h2 ## L:952 | 37 | tmp = matL2 +* matR23.zzzzZZZZ; + vmadh $v13, $v05, $v11.h2 ## L:952 | 38 | tmp = matL2 +* matR23.zzzzZZZZ; + sdv $v09, 0, 0, $s2 ## L:955 | ^ | store(matR01.xyzw, addrOut, 0x00); + vmadl $v29, $v08, $v12.h3 ## L:953 | 39 | matR23 = matL3 +* matR23.wwwwWWWW; + vmadm $v29, $v07, $v12.h3 ## L:953 | 40 | matR23 = matL3 +* matR23.wwwwWWWW; + vmadn $v12, $v08, $v11.h3 ## L:953 | 41 | matR23 = matL3 +* matR23.wwwwWWWW; + sdv $v10, 0, 8, $s2 ## L:955 | ^ | store(matR01.xyzw, addrOut, 0x00); + sdv $v09, 8, 16, $s2 ## L:956 | 42 | store(matR01.XYZW, addrOut, 0x10); + vmadh $v11, $v07, $v11.h3 ## L:953 | ^ | matR23 = matL3 +* matR23.wwwwWWWW; + sdv $v12, 8, 56, $s2 ## L:958 | **45 | store(matR23.XYZW, addrOut, 0x30); + sdv $v11, 0, 32, $s2 ## L:957 | 46 | store(matR23.xyzw, addrOut, 0x20); + sdv $v12, 0, 40, $s2 ## L:957 | 47 | store(matR23.xyzw, addrOut, 0x20); + jr $ra ## L:959 | 48 | } + sdv $v11, 8, 48, $s2 ## L:958 | *50 | store(matR23.XYZW, addrOut, 0x30); T3DCmd_MatrixStack: - andi $s7, $a0, 1 - andi $s6, $a0, 2 - lh $a0, %lo(RSPQ_DMEM_BUFFER -7)($gp) - lw $s5, %lo(MATRIX_STACK_PTR + 0) - addu $s5, $s5, $a0 - bne $s6, $zero, RSPQ_Loop - sw $s5, %lo(MATRIX_STACK_PTR)($zero) - bgez $a0, LABEL_T3DCmd_MatrixStack_0009 - ori $s4, $zero, %lo(RDP_BUFF) - or $a1, $zero, $s5 - LABEL_T3DCmd_MatrixStack_0009: - lui $at, 0xFF - ori $t0, $zero, 63 - ori $at, $at, 0xFFFF - addiu $t2, $zero, 12 - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - and $s0, $a1, $at - beq $s7, $zero, LABEL_T3DCmd_MatrixStack_000A - nop - ori $t0, $zero, 63 - ori $s4, $zero, %lo(PARTICLE_BUFF) - addiu $s0, $s5, 65472 - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - addiu $t2, $zero, 12 - ori $s4, $zero, %lo(RDP_BUFF) - ori $s3, $zero, %lo(PARTICLE_BUFF) - jal mulMat4Mat4 ## Args: $s2, $s3, $s4 - ori $s2, $zero, %lo(RDP_BUFF) - LABEL_T3DCmd_MatrixStack_000A: - ori $t0, $zero, 63 - addiu $t2, $zero, -32756 - jal DMAExec ## Args: $t0, $t1, $s0, $s4, $t2 - or $s0, $zero, $s5 - ori $s2, $zero, %lo(MATRIX_MVP) - ori $s4, $zero, %lo(RDP_BUFF) - jal mulMat4Mat4 ## Args: $s2, $s3, $s4 - ori $s3, $zero, %lo(MATRIX_PROJ) - j RSPQ_Loop + ## hot-path cycles: 40 + andi $s7, $a0, 1 ## L:1005 | ^ | u16 doMultiply = stackAdvance & 0b01; + andi $s6, $a0, 2 ## L:1006 | 2 | u16 onlyStackMove = stackAdvance & 0b10; + lh $a0, %lo(RSPQ_DMEM_BUFFER -7)($gp) ## L:1008 | 3 | stackAdvance:s16 = load_arg(1); + lw $s5, %lo(MATRIX_STACK_PTR + 0) ## L:1010 | 4 | s32 stackPtr = load(MATRIX_STACK_PTR); + addu $s5, $s5, $a0 ## L:1011 | **7 | stackPtr += stackAdvance; + bne $s6, $zero, RSPQ_Loop ## L:1015 | 8 | if(onlyStackMove)exit; + sw $s5, %lo(MATRIX_STACK_PTR)($zero) ## L:1012 | 9 | store(stackPtr, MATRIX_STACK_PTR); + bgez $a0, LABEL_T3DCmd_MatrixStack_0010 ## L:1020 | 10 | if(stackAdvance < 0)addressMat = stackPtr; + ori $s4, $zero, %lo(RDP_BUFF) ## L:1016 | 11 | dmaDest = RDP_BUFF; + or $a1, $zero, $s5 ## L:1020 | 12 | if(stackAdvance < 0)addressMat = stackPtr; + LABEL_T3DCmd_MatrixStack_0010: + lui $at, 0xFF ## L:1021 | 13 | u32<$s0> addrRDRAM = addressMat & 0xFFFFFF; + ori $at, $at, 0xFFFF ## L:1021 | 14 | u32<$s0> addrRDRAM = addressMat & 0xFFFFFF; + and $s0, $a1, $at ## L:1021 | 15 | u32<$s0> addrRDRAM = addressMat & 0xFFFFFF; + addiu $t2, $zero, 12 ## L:1023 | 16 | dma_in(dmaDest, addrRDRAM, 0x40); + jal DMAExec ## L:1023 | 17 | dma_in(dmaDest, addrRDRAM, 0x40); ## Args: $t0, $t1, $s0, $s4, $t2 + ori $t0, $zero, 63 ## L:1023 | 18 | dma_in(dmaDest, addrRDRAM, 0x40); + beq $s7, $zero, LABEL_T3DCmd_MatrixStack_0011 ## L:1030 | 19 | if(doMultiply) { + nop ## L:1030 | 20 | if(doMultiply) { + addiu $t2, $zero, 12 ## L:1034 | 21 | dma_in(dmaDest, addrRDRAM, 0x40); + ori $s4, $zero, %lo(PARTICLE_BUFF) ## L:1032 | 22 | dmaDest = PARTICLE_BUFF; + ori $t0, $zero, 63 ## L:1034 | 23 | dma_in(dmaDest, addrRDRAM, 0x40); + jal DMAExec ## L:1034 | 24 | dma_in(dmaDest, addrRDRAM, 0x40); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $s0, $s5, 65472 ## L:1033 | 25 | addrRDRAM = stackPtr - 0x40; + ori $s4, $zero, %lo(RDP_BUFF) ## L:1039 | 26 | dmaDest = RDP_BUFF; + ori $s3, $zero, %lo(PARTICLE_BUFF) ## L:1038 | 27 | u32<$s3> mulLeft = PARTICLE_BUFF; + jal mulMat4Mat4 ## L:1040 | 28 | mulMat4Mat4(mulDest, mulLeft, dmaDest); ## Args: $s2, $s3, $s4 + ori $s2, $zero, %lo(RDP_BUFF) ## L:1037 | 29 | u32<$s2> mulDest = RDP_BUFF; + LABEL_T3DCmd_MatrixStack_0011: + ori $t0, $zero, 63 ## L:1045 | 30 | dma_out(dmaDest, addrRDRAM, 0x40); + addiu $t2, $zero, -32756 ## L:1045 | 31 | dma_out(dmaDest, addrRDRAM, 0x40); + jal DMAExec ## L:1045 | 32 | dma_out(dmaDest, addrRDRAM, 0x40); ## Args: $t0, $t1, $s0, $s4, $t2 + or $s0, $zero, $s5 ## L:1044 | 33 | addrRDRAM = stackPtr; + ori $s2, $zero, %lo(MATRIX_MVP) ## L:1049 | 34 | u32<$s2> mulDest = MATRIX_MVP; + ori $s3, $zero, %lo(MATRIX_PROJ) ## L:1053 | 35 | u32<$s3> mulLeft = MATRIX_PROJ; + jal mulMat4Mat4 ## L:1063 | 36 | mulMat4Mat4(mulDest, mulLeft, mulRight); ## Args: $s2, $s3, $s4 + ori $s4, $zero, %lo(RDP_BUFF) ## L:1062 | 37 | u32<$s4> mulRight = RDP_BUFF; + j RSPQ_Loop ## L:1064 | 38 | } + nop ## L:1064 | *40 | } TPXCmd_SetDMEM: - andi $s7, $a0, 32768 - bne $s7, $zero, RSPQ_Loop - sh $a1, ($a0) - j RSPQ_Loop - sw $a1, ($a0) + ## hot-path cycles: 6 + andi $s7, $a0, 32768 ## L:1069 | ^ | u32 is16bit = addrDMEM & 0x8000; + bne $s7, $zero, RSPQ_Loop ## L:1072 | 2 | if(is16bit)goto RSPQ_Loop; + sh $a1, ($a0) ## L:1070 | 3 | store(value:u16, addrDMEM); + j RSPQ_Loop ## L:1075 | 4 | } + sw $a1, ($a0) ## L:1074 | *6 | store(value:u32, addrDMEM); TPXCmd_DrawTextured: - andi $t0, $a0, 65535 ## L:1081 | ^ | u32<$t0> dmaSize = dataSize & 0xFFFF; - ori $s4, $zero, %lo(PARTICLE_BUFF) ## L:1080 | 2 | u16<$s4> dmaDmem = PARTICLE_BUFF; - or $t2, $zero, $zero ## L:1097 | 3 | dma_in_async(dmaDmem, rdramAddr, dmaSize); - or $s0, $zero, $a1 ## L:1097 | 4 | dma_in_async(dmaDmem, rdramAddr, dmaSize); - addu $s7, $s4, $t0 ## L:1096 | 5 | u32 ptrInEnd = dmaDmem + dmaSize; + ## hot-path cycles: 246 + or $s0, $zero, $a1 ## L:1097 | ^ | dma_in_async(dmaDmem, rdramAddr, dmaSize); + andi $t0, $a0, 65535 ## L:1081 | 2 | u32<$t0> dmaSize = dataSize & 0xFFFF; + ori $s4, $zero, %lo(PARTICLE_BUFF) ## L:1080 | 3 | u16<$s4> dmaDmem = PARTICLE_BUFF; + addu $s7, $s4, $t0 ## L:1096 | 4 | u32 ptrInEnd = dmaDmem + dmaSize; + addiu $t0, $t0, -1 ## L:1097 | 5 | dma_in_async(dmaDmem, rdramAddr, dmaSize); jal DMAExec ## L:1097 | 6 | dma_in_async(dmaDmem, rdramAddr, dmaSize); ## Args: $t0, $t1, $s0, $s4, $t2 - addiu $t0, $t0, -1 ## L:1097 | *8 | dma_in_async(dmaDmem, rdramAddr, dmaSize); - vmudl $v20, $v00, $v31.e7 ## L:1112 | 9 | screenSize >>= 4; - ori $at, $zero, %lo(MATRIX_MVP) ## L:1105 | ^ | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v22, 0, 56, $at ## L:1108 | 10 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - lw $s2, %lo(RDPQ_SCISSOR_RECT + 4) ## L:1212 | 11 | u32 extMax = load(RDPQ_SCISSOR_RECT, 4); - ldv $v23, 0, 32, $at ## L:1107 | 12 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ldv $v25, 0, 16, $at ## L:1106 | 13 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v24, 0, 40, $at ## L:1107 | 14 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + or $t2, $zero, $zero ## L:1097 | 7 | dma_in_async(dmaDmem, rdramAddr, dmaSize); + ori $at, $zero, %lo(MATRIX_MVP) ## L:1105 | 8 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ldv $v22, 8, 56, $at ## L:1108 | 9 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + ldv $v26, 0, 24, $at ## L:1106 | 10 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + lw $s2, %lo(RDPQ_SCISSOR_RECT + 4) ## L:1210 | 11 | u32 extMax = load(RDPQ_SCISSOR_RECT, 4); + ldv $v27, 8, 0, $at ## L:1105 | 12 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + lw $s1, %lo(RDPQ_SCISSOR_RECT + 0) ## L:1211 | 13 | u32 extMin = load(RDPQ_SCISSOR_RECT, 0); + ldv $v24, 8, 40, $at ## L:1107 | 14 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; ldv $v21, 0, 48, $at ## L:1108 | 15 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - ldv $v25, 8, 16, $at ## L:1106 | 16 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v27, 0, 0, $at ## L:1105 | 17 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v26, 0, 24, $at ## L:1106 | 18 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v27, 8, 0, $at ## L:1105 | 19 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v22, 8, 56, $at ## L:1108 | 20 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - ldv $v26, 8, 24, $at ## L:1106 | 21 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; - ldv $v28, 0, 8, $at ## L:1105 | 22 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v23, 8, 32, $at ## L:1107 | 23 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ldv $v28, 8, 8, $at ## L:1105 | 24 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; - ldv $v21, 8, 48, $at ## L:1108 | 25 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - ldv $v24, 8, 40, $at ## L:1107 | 26 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; - ori $at, $zero, %lo(SCREEN_SCALE_OFFSET) ## L:1110 | 27 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ldv $v19, 0, 0, $at ## L:1110 | 28 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - mtc2 $s2, $v15.e5 ## L:1217 | 29 | screenMax.y = extMax; screenMax.Y = extMax; - ldv $v18, 0, 8, $at ## L:1114 | 30 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - ldv $v19, 8, 0, $at ## L:1110 | 31 | vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - ldv $v18, 8, 8, $at ## L:1114 | 32 | vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; - srl $t4, $s2, 12 ## L:1215 | 33 | temp1 = extMax >> 12; - lw $s1, %lo(RDPQ_SCISSOR_RECT + 0) ## L:1213 | 34 | u32 extMin = load(RDPQ_SCISSOR_RECT, 0); - mtc2 $s2, $v15.e1 ## L:1217 | 35 | screenMax.y = extMax; screenMax.Y = extMax; - ori $at, $zero, %lo(NORM_SCALE_W) ## L:1115 | 36 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - ldv $v17, 0, 0, $at ## L:1115 | 37 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - mtc2 $s1, $v16.e5 ## L:1221 | 38 | screenMin.y = extMin; screenMin.Y = extMin; - lui $t7, 0x3A00 ## L:1130 | 39 | cmdRdpColor = 0x3A00'0000; - ori $s3, $zero, %lo(RDP_BUFF) ## L:1102 | 40 | u16<$s3> dmaDmemEnd = RDP_BUFF; - mtc2 $t4, $v15.e0 ## L:1216 | 41 | screenMax.x = temp1; screenMax.X = temp1; - ldv $v17, 8, 0, $at ## L:1115 | 42 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; - addiu $s5, $s3, 480 ## L:1103 | 43 | u16 dmaDmemFlush = dmaDmemEnd + 480; - or $s6, $zero, $s4 ## L:1099 | 44 | u32 ptrIn = dmaDmem; - addiu $at, $zero, 4095 ## L:1211 | 45 | screenMax.w = 0b1111'1111'1111; - mtc2 $t4, $v15.e4 ## L:1216 | 46 | screenMax.x = temp1; screenMax.X = temp1; - mtc2 $s1, $v16.e1 ## L:1221 | 47 | screenMin.y = extMin; screenMin.Y = extMin; - addiu $a0, $zero, 46 ## L:1131 | 48 | cmdRdpDepth = 0x2E; - srl $t4, $s1, 12 ## L:1219 | 49 | temp1 = extMin >> 12; - mtc2 $at, $v15.e3 ## L:1211 | 50 | screenMax.w = 0b1111'1111'1111; - mtc2 $t4, $v16.e4 ## L:1220 | 51 | screenMin.x = temp1; screenMin.X = temp1; - ori $at, $zero, %lo(PARTICLE_SCALE) ## L:1122 | 52 | globalPartSize.xy = load(PARTICLE_SCALE).xy; - vmadm $v19, $v19, $v31.e7 ## L:1112 | ^ | screenSize >>= 4; - addiu $s1, $s5, 32 ## L:1129 | 53 | u16 buffRdpEnd = dmaDmemFlush + 32; - vmadn $v20, $v00, $v00 ## L:1112 | ^ | screenSize >>= 4; - vand $v15, $v15, $v15.e3 ## L:1223 | 54 | screenMax &= screenMax.w; - mtc2 $t4, $v16.e0 ## L:1220 | ^ | screenMin.x = temp1; screenMin.X = temp1; - llv $v13, 0, 0, $at ## L:1122 | 55 | globalPartSize.xy = load(PARTICLE_SCALE).xy; - llv $v13, 8, 0, $at ## L:1123 | 56 | globalPartSize.XY = load(PARTICLE_SCALE).xy; - ori $s2, $zero, %lo(RDP_BUFF) ## L:1128 | 57 | u16 buffRdp = RDP_BUFF; - ori $s4, $zero, %lo(RDP_BUFF) ## L:1101 | 58 | dmaDmem = RDP_BUFF; - vand $v16, $v16, $v15.e3 ## L:1224 | ^ | screenMin &= screenMax.w; + ldv $v22, 0, 56, $at ## L:1108 | 16 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + ldv $v24, 0, 40, $at ## L:1107 | 17 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ldv $v28, 0, 8, $at ## L:1105 | 18 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ldv $v23, 0, 32, $at ## L:1107 | 19 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ldv $v21, 8, 48, $at ## L:1108 | 20 | vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; + ldv $v25, 0, 16, $at ## L:1106 | 21 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + ldv $v28, 8, 8, $at ## L:1105 | 22 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ldv $v26, 8, 24, $at ## L:1106 | 23 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + ldv $v27, 0, 0, $at ## L:1105 | 24 | vec32 mat0 = load(MATRIX_MVP, 0x00).xyzwxyzw; + ori $s3, $zero, %lo(RDP_BUFF) ## L:1102 | 25 | u16<$s3> dmaDmemEnd = RDP_BUFF; + ldv $v23, 8, 32, $at ## L:1107 | 26 | vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; + ldv $v25, 8, 16, $at ## L:1106 | 27 | vec32 mat1 = load(MATRIX_MVP, 0x10).xyzwxyzw; + ori $at, $zero, %lo(SCREEN_SCALE) ## L:1110 | 28 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v19, 0, 0, $at ## L:1110 | 29 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v20, 8, 8, $at ## L:1110 | 30 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v20, 0, 8, $at ## L:1110 | 31 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ldv $v19, 8, 0, $at ## L:1110 | 32 | vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; + ori $at, $zero, %lo(SCREEN_OFFSET) ## L:1112 | 33 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ldv $v18, 8, 0, $at ## L:1112 | 34 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ldv $v18, 0, 0, $at ## L:1112 | 35 | vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; + ori $at, $zero, %lo(NORM_SCALE_W) ## L:1113 | 36 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + ldv $v17, 8, 0, $at ## L:1113 | 37 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + addiu $s5, $s3, 480 ## L:1103 | 38 | u16 dmaDmemFlush = dmaDmemEnd + 480; + ldv $v17, 0, 0, $at ## L:1113 | 39 | vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; + mtc2 $s2, $v15.e5 ## L:1215 | 40 | screenMax.y = extMax; screenMax.Y = extMax; + srl $t4, $s2, 12 ## L:1213 | 41 | temp1 = extMax >> 12; + addiu $at, $zero, 4095 ## L:1209 | 42 | screenMax.w = 0b1111'1111'1111; + mtc2 $t4, $v15.e0 ## L:1214 | 43 | screenMax.x = temp1; screenMax.X = temp1; + mtc2 $t4, $v15.e4 ## L:1214 | 44 | screenMax.x = temp1; screenMax.X = temp1; + addiu $a0, $zero, 46 ## L:1129 | 45 | cmdRdpDepth = 0x2E; + srl $t4, $s1, 12 ## L:1217 | 46 | temp1 = extMin >> 12; + lui $t7, 0x3A00 ## L:1128 | 47 | cmdRdpColor = 0x3A00'0000; + or $s6, $zero, $s4 ## L:1099 | 48 | u32 ptrIn = dmaDmem; + mtc2 $at, $v15.e3 ## L:1209 | 49 | screenMax.w = 0b1111'1111'1111; + mtc2 $s2, $v15.e1 ## L:1215 | 50 | screenMax.y = extMax; screenMax.Y = extMax; + ori $at, $zero, %lo(PARTICLE_SCALE) ## L:1120 | 51 | globalPartSize.xy = load(PARTICLE_SCALE).xy; + llv $v13, 0, 0, $at ## L:1120 | 52 | globalPartSize.xy = load(PARTICLE_SCALE).xy; + mtc2 $t4, $v16.e0 ## L:1218 | 53 | screenMin.x = temp1; screenMin.X = temp1; + ori $s2, $zero, %lo(RDP_BUFF) ## L:1126 | 54 | u16 buffRdp = RDP_BUFF; + vand $v15, $v15, $v15.e3 ## L:1221 | ^ | screenMax &= screenMax.w; + ori $s4, $zero, %lo(RDP_BUFF) ## L:1101 | 55 | dmaDmem = RDP_BUFF; + mtc2 $s1, $v16.e5 ## L:1219 | 56 | screenMin.y = extMin; screenMin.Y = extMin; + mtc2 $s1, $v16.e1 ## L:1219 | 57 | screenMin.y = extMin; screenMin.Y = extMin; + addiu $s1, $s5, 32 ## L:1127 | 58 | u16 buffRdpEnd = dmaDmemFlush + 32; + llv $v13, 8, 0, $at ## L:1121 | 59 | globalPartSize.XY = load(PARTICLE_SCALE).xy; + mtc2 $t4, $v16.e4 ## L:1218 | 60 | screenMin.x = temp1; screenMin.X = temp1; + vand $v16, $v16, $v15.e3 ## L:1222 | ***64 | screenMin &= screenMax.w; LABEL_TPXCmd_DrawTextured_0013: - sh $zero, 14($s2) ## L:1135 | 59 | store(ZERO:u16, buffRdp, 0x0E); - sw $t7, 0($s2) ## L:1133 | 60 | store(cmdRdpColor, buffRdp, 0); - sb $a0, 8($s2) ## L:1134 | 61 | store(cmdRdpDepth, buffRdp, 8); - addiu $s2, $s2, 32 ## L:1136 | 62 | buffRdp += 32; - bne $s2, $s1, LABEL_TPXCmd_DrawTextured_0013 ## L:1136 | 63 | buffRdp += 32; - nop ## L:1136 | *65 | buffRdp += 32; + addiu $s2, $s2, 32 ## L:1134 | ^ | buffRdp += 32; + sh $zero, -18($s2) ## L:1133 | 65 | store(ZERO:u16, buffRdp, 0x0E); + sb $a0, -24($s2) ## L:1132 | 66 | store(cmdRdpDepth, buffRdp, 8); + bne $s2, $s1, LABEL_TPXCmd_DrawTextured_0013 ## L:1134 | 67 | buffRdp += 32; + sw $t7, -32($s2) ## L:1131 | 68 | store(cmdRdpColor, buffRdp, 0); LABEL_TPXCmd_DrawTextured_0014: - lhu $s1, %lo(TILE_COUNT + 0) ## L:1147 | 66 | u16 tiles = load(TILE_COUNT); - vxor $v12, $v00, $v00.e0 ## L:1143 | ^ | vec16 texMirrorMask = 0; - addu $fp, $s1, $s1 ## L:1148 | **69 | u16 tilesEnd = tiles + tiles; - vmov $v12.e5, $v30.e7 ## L:1150 | ^ | texMirrorMask.Y = 1; - mtc2 $fp, $v12.e3 ## L:1153 | 70 | texMirrorMask.w = tilesEnd; - mtc2 $s1, $v12.e2 ## L:1152 | 71 | texMirrorMask.z = tiles; - vmov $v12.e1, $v30.e7 ## L:1151 | 72 | texMirrorMask.y = 1; - vmov $v12.e7, $v31.e7 ## L:1158 | 73 | texMirrorMask.W = 0x100; - addiu $fp, $fp, 65535 ## L:1155 | ^ | tilesEnd -= 1; - mtc2 $fp, $v12.e4 ## L:1157 | 74 | texMirrorMask.X = tilesEnd; - mtc2 $fp, $v12.e0 ## L:1156 | 75 | texMirrorMask.x = tilesEnd; - vxor $v11, $v00, $v00.e0 ## L:1144 | ^ | vec16 texMirrorCompare = 0; - vmudn $v12, $v12, $v12.e7 ## L:1159 | ***79 | texMirrorMask = texMirrorMask * texMirrorMask.W; - vsubc $v29, $v12, $v30.e7 ## L:1161 | ***83 | VTEMP = texMirrorMask - 1; - lh $s2, %lo(TEX_OFFSET + 0) ## L:1141 | ^ | s16 texOffset = load(TEX_OFFSET); - vmov $v12.e3, $v29.e3 ## L:1162 | ***87 | texMirrorMask.w = VTEMP.w; - jal DMAWaitIdle ## L:1166 | ^ | dma_await(); - vor $v11, $v00, $v29.e2 ## L:1163 | *89 | texMirrorCompare = VTEMP.z; - bgez $a1, LABEL_TPXCmd_DrawTextured_0015 ## L:1171 | 90 | if(rdramAddr < 0) { - nop ## L:1171 | *92 | if(rdramAddr < 0) { - vxor $v07, $v00, $v30.e7 ## L:614 | 93 | const vec16 vecOne = 1; - lqv $v08, 0, 0, $s6 ## L:606 | ^ | vec16 posStart = load(ptrIn, 0x00); - vmulf $v14, $v13, $v08.h3 ## L:607 | ***97 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - vmudn $v10, $v28, $v08.h0 ## L:92 | 98 | out = mat0 * vec.xxxxXXXX; - vmadh $v09, $v27, $v08.h0 ## L:92 | 99 | out = mat0 * vec.xxxxXXXX; - vmadn $v10, $v26, $v08.h1 ## L:93 | 100 | out = mat1 +* vec.yyyyYYYY; - vmadh $v09, $v25, $v08.h1 ## L:93 | 101 | out = mat1 +* vec.yyyyYYYY; - vmadn $v10, $v24, $v08.h2 ## L:94 | 102 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v09, $v23, $v08.h2 ## L:94 | 103 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v10, $v22, $v30.e7 ## L:95 | 104 | out = mat3 +* 1; - vmadh $v09, $v21, $v30.e7 ## L:95 | 105 | out = mat3 +* 1; - vch $v29, $v09, $v09.h3 ## L:619 | ***109 | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v10, $v10.h3 ## L:619 | 110 | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:619 | 111 | temp1 = clip(posClip, posClip.wwwwWWWW); + lhu $s1, %lo(TILE_COUNT + 0) ## L:1145 | 69 | u16 tiles = load(TILE_COUNT); + vxor $v12, $v00, $v00.e0 ## L:1141 | ^ | vec16 texMirrorMask = 0; + addu $fp, $s1, $s1 ## L:1146 | **72 | u16 tilesEnd = tiles + tiles; + vmov $v12.e7, $v31.e7 ## L:1156 | ^ | texMirrorMask.W = 0x100; + mtc2 $s1, $v12.e2 ## L:1150 | 73 | texMirrorMask.z = tiles; + mtc2 $fp, $v12.e3 ## L:1151 | 74 | texMirrorMask.w = tilesEnd; + vmov $v12.e1, $v30.e7 ## L:1149 | 75 | texMirrorMask.y = 1; + addiu $fp, $fp, 65535 ## L:1153 | ^ | tilesEnd -= 1; + vmov $v12.e5, $v30.e7 ## L:1148 | 76 | texMirrorMask.Y = 1; + mtc2 $fp, $v12.e4 ## L:1155 | 77 | texMirrorMask.X = tilesEnd; + vxor $v11, $v00, $v00.e0 ## L:1142 | ^ | vec16 texMirrorCompare = 0; + mtc2 $fp, $v12.e0 ## L:1154 | 78 | texMirrorMask.x = tilesEnd; + vmudn $v12, $v12, $v12.e7 ## L:1157 | ***82 | texMirrorMask = texMirrorMask * texMirrorMask.W; + vsubc $v29, $v12, $v30.e7 ## L:1159 | ***86 | VTEMP = texMirrorMask - 1; + lh $s2, %lo(TEX_OFFSET + 0) ## L:1139 | ^ | s16 texOffset = load(TEX_OFFSET); + vmov $v12.e3, $v29.e3 ## L:1160 | ***90 | texMirrorMask.w = VTEMP.w; + jal DMAWaitIdle ## L:1164 | ^ | dma_await(); + vor $v11, $v00, $v29.e2 ## L:1161 | 91 | texMirrorCompare = VTEMP.z; + bgez $a1, LABEL_TPXCmd_DrawTextured_0015 ## L:1169 | 92 | if(rdramAddr < 0) { + nop ## L:1169 | 93 | if(rdramAddr < 0) { + lqv $v08, 0, 0, $s6 ## L:608 | 94 | vec16 posStart = load(ptrIn, 0x00); + vxor $v07, $v00, $v30.e7 ## L:616 | ^ | const vec16 vecOne = 1; + vmulf $v14, $v13, $v08.h3 ## L:609 | ***98 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + vmudn $v10, $v28, $v08.h0 ## L:94 | 99 | out = mat0 * vec.xxxxXXXX; + vmadh $v09, $v27, $v08.h0 ## L:94 | 100 | out = mat0 * vec.xxxxXXXX; + vmadn $v10, $v26, $v08.h1 ## L:95 | 101 | out = mat1 +* vec.yyyyYYYY; + vmadh $v09, $v25, $v08.h1 ## L:95 | 102 | out = mat1 +* vec.yyyyYYYY; + vmadn $v10, $v24, $v08.h2 ## L:96 | 103 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v09, $v23, $v08.h2 ## L:96 | 104 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v10, $v22, $v30.e7 ## L:97 | 105 | out = mat3 +* 1; + vmadh $v09, $v21, $v30.e7 ## L:97 | 106 | out = mat3 +* 1; + vch $v29, $v09, $v09.h3 ## L:621 | ***110 | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v10, $v10.h3 ## L:621 | 111 | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:621 | 112 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawTextured_0017: - vmudl $v10, $v10, $v17.v ## L:630 | ^ | posClip *= normScaleW:ufract; - lb $a2, 7($s6) ## L:674 | 112 | temp0:s8 = load(ptrIn, 7); - vmadm $v09, $v09, $v17.v ## L:630 | ^ | posClip *= normScaleW:ufract; - vmadn $v10, $v00, $v00 ## L:630 | 113 | posClip *= normScaleW:ufract; - ori $at, $zero, %lo(BASE_SIZE) ## L:636 | ^ | posClip:sint.w = load(BASE_SIZE).x; - vrcph $v05.e3, $v09.e3 ## L:632 | **116 | invW.w = invert_half(posClip).w; - andi $t1, $t4, 1028 ## L:626 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; - andi $t5, $t4, 16448 ## L:627 | 117 | clipB = temp1 & 0b0100'0000'0100'0000; - vrcpl $v06.e3, $v10.e3 ## L:632 | ^ | invW.w = invert_half(posClip).w; - lb $t4, 15($s6) ## L:675 | 118 | temp1:s8 = load(ptrIn, 15); - vrcph $v05.e3, $v09.e7 ## L:633 | ^ | invW.W = invert_half(posClip).W; - addiu $t2, $zero, 36 ## L:737 | 119 | cmdRdpRect = 0x24; - vrcpl $v06.e7, $v10.e7 ## L:633 | ^ | invW.W = invert_half(posClip).W; - vmov $v10.e7, $v00.e0 ## L:639 | 120 | posClip:sfract.W = 0; - lsv $v09, 6, 0, $at ## L:636 | ^ | posClip:sint.w = load(BASE_SIZE).x; - lsv $v09, 14, 0, $at ## L:637 | 121 | posClip:sint.W = load(BASE_SIZE).x; - vmov $v10.e3, $v00.e0 ## L:638 | ^ | posClip:sfract.w = 0; - addu $t4, $t4, $s2 ## L:681 | 122 | temp1 += texOffset; temp1 <<= 3; - sll $t4, $t4, 3 ## L:681 | 123 | temp1 += texOffset; temp1 <<= 3; - vrcph $v05.e7, $v00.e7 ## L:633 | ^ | invW.W = invert_half(posClip).W; - addu $a2, $a2, $s2 ## L:680 | *125 | temp0 += texOffset; temp0 <<= 3; - vmudl $v29, $v10, $v06.h3 ## L:642 | ^ | posClip *= invW.wwwwWWWW; - sll $a2, $a2, 3 ## L:680 | 126 | temp0 += texOffset; temp0 <<= 3; - vmadm $v29, $v09, $v06.h3 ## L:642 | ^ | posClip *= invW.wwwwWWWW; - addiu $at, $zero, 3 ## L:771 | 127 | if(clipA == 0b0000'0011) { - vmadn $v10, $v10, $v05.h3 ## L:642 | ^ | posClip *= invW.wwwwWWWW; - vmadh $v09, $v09, $v05.h3 ## L:642 | 128 | posClip *= invW.wwwwWWWW; - vmulf $v14, $v14, $v09.h3 ## L:645 | ***132 | localPartSize:sfract *= posClip:sint.wwwwWWWW; - vmudl $v29, $v10, $v20.v ## L:648 | 133 | vec32 posScreen = posClip * screenSize; - vmadm $v29, $v09, $v20.v ## L:648 | 134 | vec32 posScreen = posClip * screenSize; - vmadn $v04, $v10, $v19.v ## L:648 | 135 | vec32 posScreen = posClip * screenSize; - vmadh $v03, $v09, $v19.v ## L:648 | 136 | vec32 posScreen = posClip * screenSize; - vmadh $v02, $v18, $v07.v ## L:649 | 137 | vec16 posCenter = screenOffset:sint +* vecOne; - vmadh $v04, $v07, $v14.v ## L:654 | 138 | vec16 posEnd = vecOne +* localPartSize:sint; - vsubc $v08, $v02, $v14.v ## L:655 | **141 | posStart = posCenter - localPartSize:sint; - vmudn $v14, $v14, $v30.e6 ## L:659 | 142 | localPartSize *= 2; - vrcp $v06.e0, $v14.e0 ## L:660 | ***146 | invW.x = invert_half(localPartSize).x; - vrcph $v05.e0, $v14.e0 ## L:660 | 147 | invW.x = invert_half(localPartSize).x; - vrcp $v06.e1, $v14.e1 ## L:661 | 148 | invW.y = invert_half(localPartSize).y; - vrcph $v05.e1, $v14.e1 ## L:661 | 149 | invW.y = invert_half(localPartSize).y; - vrcp $v06.e4, $v14.e4 ## L:662 | 150 | invW.X = invert_half(localPartSize).X; - vrcph $v05.e4, $v14.e4 ## L:662 | 151 | invW.X = invert_half(localPartSize).X; - vrcp $v06.e5, $v14.e5 ## L:663 | 152 | invW.Y = invert_half(localPartSize).Y; - vrcph $v05.e5, $v14.e5 ## L:663 | 153 | invW.Y = invert_half(localPartSize).Y; - vmudh $v01, $v08, $v05.v ## L:668 | ***157 | vec16 uvStart = posStart * invW:sint; - vor $v03, $v00, $v05 ## L:664 | 158 | vec16 uvDelta = invW:sint; - vmudm $v01, $v01, $v31.e6 ## L:669 | **161 | uvStart >>= 7; - vxor $v05, $v00, $v00.e0 ## L:694 | 162 | vec16 texOffsetTotal = 0; - vlt $v01, $v01, $v00.e0 ## L:670 | **165 | uvStart = uvStart < 0; - mtc2 $a2, $v05.e0 ## L:695 | ^ | texOffsetTotal.x = temp0:s16; - mtc2 $t4, $v05.e4 ## L:696 | 166 | texOffsetTotal.X = temp1:s16; - slv $v03, 0, 28, $s3 ## L:758 | **169 | store(uvDelta.xy, dmaDmemEnd, 0x0C, 16); - vsubc $v06, $v00, $v01.v ## L:692 | ^ | vec16 uvStartNeg = VZERO - uvStart; - vand $v05, $v05, $v12.e3 ## L:697 | 170 | texOffsetTotal &= texMirrorMask.w; - vge $v29, $v11, $v05.h0 ## L:700 | ***174 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; - vmrg $v01, $v06, $v01 ## L:700 | 175 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; - vlt $v04, $v04, $v15 ## L:703 | 176 | posEnd = min(posEnd, screenMax); - ssv $v02, 4, 12, $s3 ## L:749 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); - vge $v08, $v08, $v16 ## L:704 | 177 | posStart = max(posStart, screenMin); - vaddc $v01, $v01, $v05.v ## L:706 | **180 | uvStart += texOffsetTotal; - mfc2 $k1, $v04.e5 ## L:1196 | ^ | outB = pos.Y; - mfc2 $s1, $v08.e1 ## L:1190 | 181 | outA = pos.y; - mfc2 $fp, $v08.e5 ## L:1196 | **184 | outB = pos.Y; - vsubc $v06, $v12, $v01.v ## L:711 | ^ | uvStartNeg = texMirrorMask - uvStart; - mfc2 $k0, $v08.e0 ## L:1192 | 185 | u32 tmp = pos.x; - andi $s1, $s1, 4095 ## L:1191 | 186 | outA &= 0b1111'1111'1111; - andi $k1, $k1, 4095 ## L:1197 | 187 | outB &= 0b1111'1111'1111; - sll $k0, $k0, 12 ## L:1193 | 188 | tmp <<= 12; - or $s1, $s1, $k0 ## L:1194 | 189 | outA |= tmp; - mfc2 $k0, $v08.e4 ## L:1198 | 190 | tmp = pos.X; - vaddc $v06, $v06, $v12.e2 ## L:712 | ^ | uvStartNeg += texMirrorMask.z; - mfc2 $sp, $v04.e1 ## L:1190 | 191 | outA = pos.y; - andi $fp, $fp, 4095 ## L:1197 | 192 | outB &= 0b1111'1111'1111; - sll $k0, $k0, 12 ## L:1199 | 193 | tmp <<= 12; - or $fp, $fp, $k0 ## L:1200 | 194 | outB |= tmp; - mfc2 $k0, $v04.e0 ## L:1192 | 195 | u32 tmp = pos.x; - sw $s1, 4 + 16($s3) ## L:754 | 196 | store(posA, dmaDmemEnd, 0x04, 16); - vge $v29, $v11, $v05.h0 ## L:714 | ^ | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; - andi $sp, $sp, 4095 ## L:1191 | 197 | outA &= 0b1111'1111'1111; - vmrg $v01, $v01, $v06 ## L:714 | ^ | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; - sll $k0, $k0, 12 ## L:1193 | 198 | tmp <<= 12; - or $sp, $sp, $k0 ## L:1194 | 199 | outA |= tmp; - sw $sp, 0 + 16($s3) ## L:755 | 200 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - mfc2 $k0, $v04.e4 ## L:1198 | 201 | tmp = pos.X; - sb $t2, 0 + 16($s3) ## L:756 | 202 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - vlt $v06, $v08, $v04 ## L:721 | ^ | vec16 extend = posStart < posEnd; - ldv $v08, 0, 24, $s6 ## L:762 | 203 | posStart.xyzw = load(ptrIn, 24).xyzw; - cfc2 $t4, $vcc ## L:722 | 204 | temp1 = get_vcc(); - ldv $v05, 0, 16, $s6 ## L:732 | 205 | vec16 color = load(ptrIn, 16).xyzw; - sll $k0, $k0, 12 ## L:1199 | 206 | tmp <<= 12; - ldv $v08, 8, 32, $s6 ## L:763 | 207 | posStart.XYZW = load(ptrIn, 24).XYZW; - slv $v01, 0, 24, $s3 ## L:757 | 208 | store(uvStart.xy, dmaDmemEnd, 0x08, 16); - andi $a2, $t4, 3 ## L:724 | 209 | temp0 = temp1 & 0b0000'0011; - or $k1, $k1, $k0 ## L:1200 | 210 | outB |= tmp; - or $t1, $t1, $a2 ## L:725 | 211 | clipA |= temp0; - slv $v05, 0, 4, $s3 ## L:745 | 212 | store(color.xy, dmaDmemEnd, 4); - vmulf $v14, $v13, $v08.h3 ## L:764 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - andi $a2, $t4, 48 ## L:727 | 213 | temp0 = temp1 & 0b0011'0000; - bne $t1, $at, LABEL_TPXCmd_DrawTextured_0019 ## L:771 | 214 | if(clipA == 0b0000'0011) { - or $t5, $t5, $a2 ## L:728 | *216 | clipB |= temp0; - addiu $s3, $s3, 32 ## L:772 | 217 | dmaDmemEnd += 32; + vmudl $v10, $v10, $v17.v ## L:632 | ^ | posClip *= normScaleW:ufract; + vmadm $v09, $v09, $v17.v ## L:632 | 113 | posClip *= normScaleW:ufract; + lb $a2, 7($s6) ## L:676 | ^ | temp0:s8 = load(ptrIn, 7); + vmadn $v10, $v00, $v00 ## L:632 | 114 | posClip *= normScaleW:ufract; + ori $at, $zero, %lo(BASE_SIZE) ## L:638 | ^ | posClip:sint.w = load(BASE_SIZE).x; + vrcph $v05.e3, $v09.e3 ## L:634 | **117 | invW.w = invert_half(posClip).w; + andi $t1, $t4, 1028 ## L:628 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; + vrcpl $v06.e3, $v10.e3 ## L:634 | 118 | invW.w = invert_half(posClip).w; + andi $t5, $t4, 16448 ## L:629 | ^ | clipB = temp1 & 0b0100'0000'0100'0000; + vrcph $v05.e3, $v09.e7 ## L:635 | 119 | invW.W = invert_half(posClip).W; + lsv $v09, 14, 0, $at ## L:639 | ^ | posClip:sint.W = load(BASE_SIZE).x; + vrcpl $v06.e7, $v10.e7 ## L:635 | 120 | invW.W = invert_half(posClip).W; + vmov $v10.e3, $v00.e0 ## L:640 | 121 | posClip:sfract.w = 0; + vmov $v10.e7, $v00.e0 ## L:641 | 122 | posClip:sfract.W = 0; + lsv $v09, 6, 0, $at ## L:638 | ^ | posClip:sint.w = load(BASE_SIZE).x; + vrcph $v05.e7, $v00.e7 ## L:635 | 123 | invW.W = invert_half(posClip).W; + lb $t4, 15($s6) ## L:677 | ^ | temp1:s8 = load(ptrIn, 15); + vmudl $v29, $v10, $v06.h3 ## L:644 | **126 | posClip *= invW.wwwwWWWW; + vmadm $v29, $v09, $v06.h3 ## L:644 | 127 | posClip *= invW.wwwwWWWW; + vmadn $v10, $v10, $v05.h3 ## L:644 | 128 | posClip *= invW.wwwwWWWW; + vmadh $v09, $v09, $v05.h3 ## L:644 | 129 | posClip *= invW.wwwwWWWW; + vmulf $v14, $v14, $v09.h3 ## L:647 | ***133 | localPartSize:sfract *= posClip:sint.wwwwWWWW; + vmudl $v29, $v10, $v20.v ## L:650 | 134 | vec32 posScreen = posClip * screenSize; + vmadm $v29, $v09, $v20.v ## L:650 | 135 | vec32 posScreen = posClip * screenSize; + vmadn $v04, $v10, $v19.v ## L:650 | 136 | vec32 posScreen = posClip * screenSize; + vmadh $v03, $v09, $v19.v ## L:650 | 137 | vec32 posScreen = posClip * screenSize; + addu $t4, $t4, $s2 ## L:683 | ^ | temp1 += texOffset; temp1 <<= 3; + sll $t4, $t4, 3 ## L:683 | 138 | temp1 += texOffset; temp1 <<= 3; + vmadh $v02, $v18, $v07.v ## L:651 | ^ | vec16 posCenter = screenOffset:sint +* vecOne; + vmadh $v04, $v07, $v14.v ## L:656 | 139 | vec16 posEnd = vecOne +* localPartSize:sint; + vsubc $v08, $v02, $v14.v ## L:657 | **142 | posStart = posCenter - localPartSize:sint; + vmudn $v14, $v14, $v30.e6 ## L:661 | 143 | localPartSize *= 2; + vrcp $v06.e0, $v14.e0 ## L:662 | ***147 | invW.x = invert_half(localPartSize).x; + vrcph $v05.e0, $v14.e0 ## L:662 | 148 | invW.x = invert_half(localPartSize).x; + vrcp $v06.e1, $v14.e1 ## L:663 | 149 | invW.y = invert_half(localPartSize).y; + vrcph $v05.e1, $v14.e1 ## L:663 | 150 | invW.y = invert_half(localPartSize).y; + vrcp $v06.e4, $v14.e4 ## L:664 | 151 | invW.X = invert_half(localPartSize).X; + vrcph $v05.e4, $v14.e4 ## L:664 | 152 | invW.X = invert_half(localPartSize).X; + vrcp $v06.e5, $v14.e5 ## L:665 | 153 | invW.Y = invert_half(localPartSize).Y; + ssv $v02, 4, 12, $s3 ## L:751 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); + vrcph $v05.e5, $v14.e5 ## L:665 | 154 | invW.Y = invert_half(localPartSize).Y; + addu $a2, $a2, $s2 ## L:682 | ^ | temp0 += texOffset; temp0 <<= 3; + vmudh $v01, $v08, $v05.v ## L:670 | ***158 | vec16 uvStart = posStart * invW:sint; + vor $v03, $v00, $v05 ## L:666 | 159 | vec16 uvDelta = invW:sint; + sll $a2, $a2, 3 ## L:682 | ^ | temp0 += texOffset; temp0 <<= 3; + vxor $v05, $v00, $v00.e0 ## L:696 | 160 | vec16 texOffsetTotal = 0; + vmudm $v01, $v01, $v31.e6 ## L:671 | *162 | uvStart >>= 7; + mtc2 $t4, $v05.e4 ## L:698 | ^ | texOffsetTotal.X = temp1:s16; + mtc2 $a2, $v05.e0 ## L:697 | ***166 | texOffsetTotal.x = temp0:s16; + vlt $v01, $v01, $v00.e0 ## L:672 | ^ | uvStart = uvStart < 0; + vsubc $v06, $v00, $v01.v ## L:694 | ***170 | vec16 uvStartNeg = VZERO - uvStart; + slv $v03, 0, 28, $s3 ## L:760 | ^ | store(uvDelta.xy, dmaDmemEnd, 0x0C, 16); + vand $v05, $v05, $v12.e3 ## L:699 | 171 | texOffsetTotal &= texMirrorMask.w; + vge $v29, $v11, $v05.h0 ## L:702 | ***175 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; + vmrg $v01, $v06, $v01 ## L:702 | 176 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; + vlt $v04, $v04, $v15 ## L:705 | 177 | posEnd = min(posEnd, screenMax); + addiu $t2, $zero, 36 ## L:739 | ^ | cmdRdpRect = 0x24; + addiu $at, $zero, 3 ## L:773 | 178 | if(clipA == 0b0000'0011) { + vge $v08, $v08, $v16 ## L:706 | ^ | posStart = max(posStart, screenMin); + mfc2 $sp, $v04.e1 ## L:1188 | **181 | outA = pos.y; + vaddc $v01, $v01, $v05.v ## L:708 | ^ | uvStart += texOffsetTotal; + mfc2 $s1, $v08.e1 ## L:1188 | 182 | outA = pos.y; + andi $sp, $sp, 4095 ## L:1189 | *184 | outA &= 0b1111'1111'1111; + mfc2 $k0, $v08.e0 ## L:1190 | 185 | u32 tmp = pos.x; + vsubc $v06, $v12, $v01.v ## L:713 | ^ | uvStartNeg = texMirrorMask - uvStart; + mfc2 $fp, $v08.e5 ## L:1194 | 186 | outB = pos.Y; + andi $s1, $s1, 4095 ## L:1189 | 187 | outA &= 0b1111'1111'1111; + sll $k0, $k0, 12 ## L:1191 | 188 | tmp <<= 12; + or $s1, $s1, $k0 ## L:1192 | 189 | outA |= tmp; + vaddc $v06, $v06, $v12.e2 ## L:714 | ^ | uvStartNeg += texMirrorMask.z; + vge $v29, $v11, $v05.h0 ## L:716 | 190 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; + mfc2 $k0, $v08.e4 ## L:1196 | ^ | tmp = pos.X; + ldv $v05, 0, 16, $s6 ## L:734 | 191 | vec16 color = load(ptrIn, 16).xyzw; + andi $fp, $fp, 4095 ## L:1195 | 192 | outB &= 0b1111'1111'1111; + sll $k0, $k0, 12 ## L:1197 | 193 | tmp <<= 12; + vmrg $v01, $v01, $v06 ## L:716 | ^ | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; + vlt $v06, $v08, $v04 ## L:723 | 194 | vec16 extend = posStart < posEnd; + or $fp, $fp, $k0 ## L:1198 | ^ | outB |= tmp; + sw $s1, 4 + 16($s3) ## L:756 | 195 | store(posA, dmaDmemEnd, 0x04, 16); + mfc2 $k0, $v04.e0 ## L:1190 | 196 | u32 tmp = pos.x; + mfc2 $k1, $v04.e5 ## L:1194 | 197 | outB = pos.Y; + ldv $v08, 8, 32, $s6 ## L:765 | 198 | posStart.XYZW = load(ptrIn, 24).XYZW; + ldv $v08, 0, 24, $s6 ## L:764 | 199 | posStart.xyzw = load(ptrIn, 24).xyzw; + sll $k0, $k0, 12 ## L:1191 | 200 | tmp <<= 12; + or $sp, $sp, $k0 ## L:1192 | 201 | outA |= tmp; + mfc2 $k0, $v04.e4 ## L:1196 | 202 | tmp = pos.X; + sw $sp, 0 + 16($s3) ## L:757 | 203 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + andi $k1, $k1, 4095 ## L:1195 | 204 | outB &= 0b1111'1111'1111; + vmulf $v14, $v13, $v08.h3 ## L:766 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + sll $k0, $k0, 12 ## L:1197 | 205 | tmp <<= 12; + sb $t2, 0 + 16($s3) ## L:758 | 206 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + cfc2 $t4, $vcc ## L:724 | 207 | temp1 = get_vcc(); + slv $v05, 0, 4, $s3 ## L:747 | 208 | store(color.xy, dmaDmemEnd, 4); + or $k1, $k1, $k0 ## L:1198 | 209 | outB |= tmp; + slv $v01, 0, 24, $s3 ## L:759 | 210 | store(uvStart.xy, dmaDmemEnd, 0x08, 16); + andi $a2, $t4, 3 ## L:726 | 211 | temp0 = temp1 & 0b0000'0011; + or $t1, $t1, $a2 ## L:727 | 212 | clipA |= temp0; + andi $a2, $t4, 48 ## L:729 | 213 | temp0 = temp1 & 0b0011'0000; + bne $t1, $at, LABEL_TPXCmd_DrawTextured_0019 ## L:773 | 214 | if(clipA == 0b0000'0011) { + or $t5, $t5, $a2 ## L:730 | 215 | clipB |= temp0; + addiu $s3, $s3, 32 ## L:774 | 216 | dmaDmemEnd += 32; LABEL_TPXCmd_DrawTextured_0019: - addiu $at, $zero, 48 ## L:782 | 218 | if(clipB == 0b0011'0000) { - bne $t5, $at, LABEL_TPXCmd_DrawTextured_001A ## L:782 | 219 | if(clipB == 0b0011'0000) { - addiu $s6, $s6, 24 ## L:776 | *221 | ptrIn += 24; - sw $k1, 0 + 16($s3) ## L:787 | 222 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - sb $t2, 0 + 16($s3) ## L:788 | 223 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - ssv $v02, 12, 12, $s3 ## L:784 | 224 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); - slv $v01, 8, 24, $s3 ## L:790 | 225 | store(uvStart.XY, dmaDmemEnd, 0x08, 16); - slv $v05, 4, 4, $s3 ## L:783 | 226 | store(color.zw, dmaDmemEnd, 4); - sw $fp, 4 + 16($s3) ## L:786 | 227 | store(posB, dmaDmemEnd, 0x04, 16); - slv $v03, 8, 28, $s3 ## L:791 | 228 | store(uvDelta.XY, dmaDmemEnd, 0x0C, 16); - addiu $s3, $s3, 32 ## L:793 | 229 | dmaDmemEnd += 32; + addiu $at, $zero, 48 ## L:784 | 217 | if(clipB == 0b0011'0000) { + bne $t5, $at, LABEL_TPXCmd_DrawTextured_001A ## L:784 | 218 | if(clipB == 0b0011'0000) { + addiu $s6, $s6, 24 ## L:778 | 219 | ptrIn += 24; + slv $v01, 8, 24, $s3 ## L:792 | 220 | store(uvStart.XY, dmaDmemEnd, 0x08, 16); + slv $v05, 4, 4, $s3 ## L:785 | 221 | store(color.zw, dmaDmemEnd, 4); + sw $k1, 0 + 16($s3) ## L:789 | 222 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + sw $fp, 4 + 16($s3) ## L:788 | 223 | store(posB, dmaDmemEnd, 0x04, 16); + ssv $v02, 12, 12, $s3 ## L:786 | 224 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); + sb $t2, 0 + 16($s3) ## L:790 | 225 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + addiu $s3, $s3, 32 ## L:795 | 226 | dmaDmemEnd += 32; + slv $v03, 8, -4, $s3 ## L:793 | 227 | store(uvDelta.XY, dmaDmemEnd, 0x0C, 16); LABEL_TPXCmd_DrawTextured_001A: - vmudn $v10, $v28, $v08.h0 ## L:92 | ^ | out = mat0 * vec.xxxxXXXX; - vmadh $v09, $v27, $v08.h0 ## L:92 | 230 | out = mat0 * vec.xxxxXXXX; - vmadn $v10, $v26, $v08.h1 ## L:93 | 231 | out = mat1 +* vec.yyyyYYYY; - vmadh $v09, $v25, $v08.h1 ## L:93 | 232 | out = mat1 +* vec.yyyyYYYY; - vmadn $v10, $v24, $v08.h2 ## L:94 | 233 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v09, $v23, $v08.h2 ## L:94 | 234 | out = mat2 +* vec.zzzzZZZZ; - sltu $at, $s3, $s5 ## L:800 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { - vmadn $v10, $v22, $v30.e7 ## L:95 | 235 | out = mat3 +* 1; - bne $at, $zero, LABEL_TPXCmd_DrawTextured_001B ## L:800 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { - vmadh $v09, $v21, $v30.e7 ## L:95 | *237 | out = mat3 +* 1; - jal RDPQ_Send ## L:801 | 238 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 - nop ## L:801 | *240 | RDPQ_Send(dmaDmem, dmaDmemEnd); - or $s3, $zero, $s4 ## L:802 | 241 | dmaDmemEnd = dmaDmem; + vmudn $v10, $v28, $v08.h0 ## L:94 | ^ | out = mat0 * vec.xxxxXXXX; + vmadh $v09, $v27, $v08.h0 ## L:94 | 228 | out = mat0 * vec.xxxxXXXX; + vmadn $v10, $v26, $v08.h1 ## L:95 | 229 | out = mat1 +* vec.yyyyYYYY; + vmadh $v09, $v25, $v08.h1 ## L:95 | 230 | out = mat1 +* vec.yyyyYYYY; + vmadn $v10, $v24, $v08.h2 ## L:96 | 231 | out = mat2 +* vec.zzzzZZZZ; + sltu $at, $s3, $s5 ## L:802 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v09, $v23, $v08.h2 ## L:96 | 232 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v10, $v22, $v30.e7 ## L:97 | 233 | out = mat3 +* 1; + bne $at, $zero, LABEL_TPXCmd_DrawTextured_001B ## L:802 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v09, $v21, $v30.e7 ## L:97 | 234 | out = mat3 +* 1; + jal RDPQ_Send ## L:803 | 235 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 + nop ## L:803 | 236 | RDPQ_Send(dmaDmem, dmaDmemEnd); + or $s3, $zero, $s4 ## L:804 | *238 | dmaDmemEnd = dmaDmem; LABEL_TPXCmd_DrawTextured_001B: - vch $v29, $v09, $v09.h3 ## L:805 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v10, $v10.h3 ## L:805 | 242 | temp1 = clip(posClip, posClip.wwwwWWWW); - bne $s6, $s7, LABEL_TPXCmd_DrawTextured_0017 ## L:805 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:805 | *244 | temp1 = clip(posClip, posClip.wwwwWWWW); + vch $v29, $v09, $v09.h3 ## L:807 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v10, $v10.h3 ## L:807 | 239 | temp1 = clip(posClip, posClip.wwwwWWWW); + bne $s6, $s7, LABEL_TPXCmd_DrawTextured_0017 ## L:807 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:807 | 240 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawTextured_0018: - beq $zero, $zero, LABEL_TPXCmd_DrawTextured_0016 ## L:805 | 245 | temp1 = clip(posClip, posClip.wwwwWWWW); - nop ## L:805 | *247 | temp1 = clip(posClip, posClip.wwwwWWWW); + beq $zero, $zero, LABEL_TPXCmd_DrawTextured_0016 ## L:807 | 241 | temp1 = clip(posClip, posClip.wwwwWWWW); + nop ## L:807 | *243 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawTextured_0015: - vxor $v07, $v00, $v30.e7 ## L:261 | 248 | const vec16 vecOne = 1; - lpv $v08, 0, 0, $s6 ## L:256 | ^ | vec16 posStart = load_vec_s8(ptrIn, 0x00); - vmulf $v14, $v13, $v08.h3 ## L:257 | ***252 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - vmudm $v08, $v08, $v31.e7 ## L:258 | 253 | posStart >>= 8; - vmudn $v10, $v28, $v08.h0 ## L:92 | ***257 | out = mat0 * vec.xxxxXXXX; - vmadh $v09, $v27, $v08.h0 ## L:92 | 258 | out = mat0 * vec.xxxxXXXX; - vmadn $v10, $v26, $v08.h1 ## L:93 | 259 | out = mat1 +* vec.yyyyYYYY; - vmadh $v09, $v25, $v08.h1 ## L:93 | 260 | out = mat1 +* vec.yyyyYYYY; - vmadn $v10, $v24, $v08.h2 ## L:94 | 261 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v09, $v23, $v08.h2 ## L:94 | 262 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v10, $v22, $v30.e7 ## L:95 | 263 | out = mat3 +* 1; - vmadh $v09, $v21, $v30.e7 ## L:95 | 264 | out = mat3 +* 1; - vch $v29, $v09, $v09.h3 ## L:266 | ***268 | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v10, $v10.h3 ## L:266 | 269 | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:266 | 270 | temp1 = clip(posClip, posClip.wwwwWWWW); + lpv $v08, 0, 0, $s6 ## L:258 | 1 | vec16 posStart = load_vec_s8(ptrIn, 0x00); + vxor $v07, $v00, $v30.e7 ## L:263 | ^ | const vec16 vecOne = 1; + vmulf $v14, $v13, $v08.h3 ## L:259 | ***5 | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + vmudm $v08, $v08, $v31.e7 ## L:260 | 6 | posStart >>= 8; + vmudn $v10, $v28, $v08.h0 ## L:94 | ***10 | out = mat0 * vec.xxxxXXXX; + vmadh $v09, $v27, $v08.h0 ## L:94 | 11 | out = mat0 * vec.xxxxXXXX; + vmadn $v10, $v26, $v08.h1 ## L:95 | 12 | out = mat1 +* vec.yyyyYYYY; + vmadh $v09, $v25, $v08.h1 ## L:95 | 13 | out = mat1 +* vec.yyyyYYYY; + vmadn $v10, $v24, $v08.h2 ## L:96 | 14 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v09, $v23, $v08.h2 ## L:96 | 15 | out = mat2 +* vec.zzzzZZZZ; + vmadn $v10, $v22, $v30.e7 ## L:97 | 16 | out = mat3 +* 1; + vmadh $v09, $v21, $v30.e7 ## L:97 | 17 | out = mat3 +* 1; + vch $v29, $v09, $v09.h3 ## L:268 | ***21 | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v10, $v10.h3 ## L:268 | 22 | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:268 | 23 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawTextured_001C: - vmudl $v10, $v10, $v17.v ## L:277 | ^ | posClip *= normScaleW:ufract; - lb $a2, 11($s6) ## L:324 | 271 | temp0:s8 = load(ptrIn, 0x0B); - vmadm $v09, $v09, $v17.v ## L:277 | ^ | posClip *= normScaleW:ufract; - vmadn $v10, $v00, $v00 ## L:277 | 272 | posClip *= normScaleW:ufract; - ori $at, $zero, %lo(BASE_SIZE) ## L:283 | ^ | posClip:sint.w = load(BASE_SIZE).x; - vrcph $v05.e3, $v09.e3 ## L:279 | **275 | invW.w = invert_half(posClip).w; - andi $t5, $t4, 16448 ## L:274 | ^ | clipB = temp1 & 0b0100'0000'0100'0000; - vrcpl $v06.e3, $v10.e3 ## L:279 | 276 | invW.w = invert_half(posClip).w; - andi $t1, $t4, 1028 ## L:273 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; - lb $t4, 15($s6) ## L:325 | 277 | temp1:s8 = load(ptrIn, 0x0F); - vrcph $v05.e3, $v09.e7 ## L:280 | ^ | invW.W = invert_half(posClip).W; - vrcpl $v06.e7, $v10.e7 ## L:280 | 278 | invW.W = invert_half(posClip).W; - vmov $v10.e3, $v00.e0 ## L:285 | 279 | posClip:sfract.w = 0; - lsv $v09, 6, 0, $at ## L:283 | ^ | posClip:sint.w = load(BASE_SIZE).x; - lsv $v09, 14, 0, $at ## L:284 | 280 | posClip:sint.W = load(BASE_SIZE).x; - vmov $v10.e7, $v00.e0 ## L:286 | ^ | posClip:sfract.W = 0; - vrcph $v05.e7, $v00.e7 ## L:280 | 281 | invW.W = invert_half(posClip).W; - vmudl $v29, $v10, $v06.h3 ## L:289 | **284 | posClip *= invW.wwwwWWWW; - addu $a2, $a2, $s2 ## L:327 | ^ | temp0 += texOffset; temp0 <<= 3; - vmadm $v29, $v09, $v06.h3 ## L:289 | 285 | posClip *= invW.wwwwWWWW; - vmadn $v10, $v10, $v05.h3 ## L:289 | 286 | posClip *= invW.wwwwWWWW; - vmadh $v09, $v09, $v05.h3 ## L:289 | 287 | posClip *= invW.wwwwWWWW; - vmulf $v14, $v14, $v09.h3 ## L:292 | ***291 | localPartSize:sfract *= posClip:sint.wwwwWWWW; - vmudl $v29, $v10, $v20.v ## L:295 | 292 | vec32 posScreen = posClip * screenSize; - vmadm $v29, $v09, $v20.v ## L:295 | 293 | vec32 posScreen = posClip * screenSize; - vmadn $v04, $v10, $v19.v ## L:295 | 294 | vec32 posScreen = posClip * screenSize; - vmadh $v03, $v09, $v19.v ## L:295 | 295 | vec32 posScreen = posClip * screenSize; - vmadh $v02, $v18, $v07.v ## L:296 | 296 | vec16 posCenter = screenOffset:sint +* vecOne; - vmadh $v04, $v07, $v14.v ## L:301 | 297 | vec16 posEnd = vecOne +* localPartSize:sint; - vsubc $v08, $v02, $v14.v ## L:302 | **300 | posStart = posCenter - localPartSize:sint; - vmudn $v14, $v14, $v30.e6 ## L:306 | 301 | localPartSize *= 2; - vrcp $v06.e0, $v14.e0 ## L:307 | ***305 | invW.x = invert_half(localPartSize).x; - vrcph $v05.e0, $v14.e0 ## L:307 | 306 | invW.x = invert_half(localPartSize).x; - vrcp $v06.e1, $v14.e1 ## L:308 | 307 | invW.y = invert_half(localPartSize).y; - vrcph $v05.e1, $v14.e1 ## L:308 | 308 | invW.y = invert_half(localPartSize).y; - vrcp $v06.e4, $v14.e4 ## L:309 | 309 | invW.X = invert_half(localPartSize).X; - addu $t4, $t4, $s2 ## L:328 | ^ | temp1 += texOffset; temp1 <<= 3; - vrcph $v05.e4, $v14.e4 ## L:309 | 310 | invW.X = invert_half(localPartSize).X; - ssv $v02, 4, 12, $s3 ## L:396 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); - vrcp $v06.e5, $v14.e5 ## L:310 | 311 | invW.Y = invert_half(localPartSize).Y; - vrcph $v05.e5, $v14.e5 ## L:310 | 312 | invW.Y = invert_half(localPartSize).Y; - vmudh $v01, $v08, $v05.v ## L:315 | ***316 | vec16 uvStart = posStart * invW:sint; - sll $t4, $t4, 3 ## L:328 | ^ | temp1 += texOffset; temp1 <<= 3; - vor $v03, $v00, $v05 ## L:311 | 317 | vec16 uvDelta = invW:sint; - vxor $v05, $v00, $v00.e0 ## L:341 | 318 | vec16 texOffsetTotal = 0; - sll $a2, $a2, 3 ## L:327 | ^ | temp0 += texOffset; temp0 <<= 3; - vmudm $v01, $v01, $v31.e6 ## L:316 | *320 | uvStart >>= 7; - mtc2 $a2, $v05.e0 ## L:342 | ^ | texOffsetTotal.x = temp0:s16; - mtc2 $t4, $v05.e4 ## L:343 | ***324 | texOffsetTotal.X = temp1:s16; - vlt $v01, $v01, $v00.e0 ## L:317 | ^ | uvStart = uvStart < 0; - vsubc $v06, $v00, $v01.v ## L:339 | ***328 | vec16 uvStartNeg = VZERO - uvStart; - vand $v05, $v05, $v12.e3 ## L:344 | 329 | texOffsetTotal &= texMirrorMask.w; - vge $v29, $v11, $v05.h0 ## L:347 | ***333 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; - vmrg $v01, $v06, $v01 ## L:347 | 334 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; - vlt $v04, $v04, $v15 ## L:350 | 335 | posEnd = min(posEnd, screenMax); - slv $v03, 0, 28, $s3 ## L:405 | ^ | store(uvDelta.xy, dmaDmemEnd, 0x0C, 16); - addiu $t2, $zero, 36 ## L:384 | 336 | cmdRdpRect = 0x24; - vge $v08, $v08, $v16 ## L:351 | ^ | posStart = max(posStart, screenMin); - vaddc $v01, $v01, $v05.v ## L:353 | *338 | uvStart += texOffsetTotal; - addiu $at, $zero, 3 ## L:418 | ^ | if(clipA == 0b0000'0011) { - mfc2 $k1, $v04.e5 ## L:1196 | 339 | outB = pos.Y; - mfc2 $k0, $v08.e0 ## L:1192 | 340 | u32 tmp = pos.x; - andi $k1, $k1, 4095 ## L:1197 | *342 | outB &= 0b1111'1111'1111; - vsubc $v06, $v12, $v01.v ## L:358 | ^ | uvStartNeg = texMirrorMask - uvStart; - mfc2 $s1, $v08.e1 ## L:1190 | 343 | outA = pos.y; - mfc2 $fp, $v08.e5 ## L:1196 | 344 | outB = pos.Y; - sll $k0, $k0, 12 ## L:1193 | 345 | tmp <<= 12; - andi $s1, $s1, 4095 ## L:1191 | 346 | outA &= 0b1111'1111'1111; - vaddc $v06, $v06, $v12.e2 ## L:359 | ^ | uvStartNeg += texMirrorMask.z; - andi $fp, $fp, 4095 ## L:1197 | 347 | outB &= 0b1111'1111'1111; - or $s1, $s1, $k0 ## L:1194 | 348 | outA |= tmp; - sw $s1, 4 + 16($s3) ## L:401 | 349 | store(posA, dmaDmemEnd, 0x04, 16); - vge $v29, $v11, $v05.h0 ## L:361 | ^ | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; - mfc2 $k0, $v08.e4 ## L:1198 | 350 | tmp = pos.X; - vmrg $v01, $v01, $v06 ## L:361 | ^ | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; - mfc2 $sp, $v04.e1 ## L:1190 | 351 | outA = pos.y; - ldv $v05, 0, 8, $s6 ## L:381 | 352 | vec16 color = load(ptrIn, 8).xyzw; - sll $k0, $k0, 12 ## L:1199 | 353 | tmp <<= 12; - vlt $v06, $v08, $v04 ## L:368 | ^ | vec16 extend = posStart < posEnd; - or $fp, $fp, $k0 ## L:1200 | 354 | outB |= tmp; - cfc2 $t4, $vcc ## L:369 | 355 | temp1 = get_vcc(); - mfc2 $k0, $v04.e0 ## L:1192 | 356 | u32 tmp = pos.x; - lpv $v08, 0, 16, $s6 ## L:413 | 357 | posStart = load_vec_s8(ptrIn, 16); - andi $sp, $sp, 4095 ## L:1191 | 358 | outA &= 0b1111'1111'1111; - sll $k0, $k0, 12 ## L:1193 | 359 | tmp <<= 12; - or $sp, $sp, $k0 ## L:1194 | 360 | outA |= tmp; - slv $v05, 0, 4, $s3 ## L:392 | 361 | store(color.xy, dmaDmemEnd, 4); - mfc2 $k0, $v04.e4 ## L:1198 | 362 | tmp = pos.X; - andi $a2, $t4, 3 ## L:371 | 363 | temp0 = temp1 & 0b0000'0011; - or $t1, $t1, $a2 ## L:372 | 364 | clipA |= temp0; - vmulf $v14, $v13, $v08.h3 ## L:414 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; - slv $v01, 0, 24, $s3 ## L:404 | 365 | store(uvStart.xy, dmaDmemEnd, 0x08, 16); - andi $a2, $t4, 48 ## L:374 | 366 | temp0 = temp1 & 0b0011'0000; - sll $k0, $k0, 12 ## L:1199 | 367 | tmp <<= 12; - or $k1, $k1, $k0 ## L:1200 | 368 | outB |= tmp; - sw $sp, 0 + 16($s3) ## L:402 | 369 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - or $t5, $t5, $a2 ## L:375 | 370 | clipB |= temp0; - vmudm $v08, $v08, $v31.e7 ## L:415 | ^ | posStart >>= 8; - bne $t1, $at, LABEL_TPXCmd_DrawTextured_001E ## L:418 | 371 | if(clipA == 0b0000'0011) { - sb $t2, 0 + 16($s3) ## L:403 | *373 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - addiu $s3, $s3, 32 ## L:419 | 374 | dmaDmemEnd += 32; + vmudl $v10, $v10, $v17.v ## L:279 | ^ | posClip *= normScaleW:ufract; + vmadm $v09, $v09, $v17.v ## L:279 | 24 | posClip *= normScaleW:ufract; + lb $a2, 11($s6) ## L:326 | ^ | temp0:s8 = load(ptrIn, 0x0B); + ori $at, $zero, %lo(BASE_SIZE) ## L:285 | 25 | posClip:sint.w = load(BASE_SIZE).x; + vmadn $v10, $v00, $v00 ## L:279 | ^ | posClip *= normScaleW:ufract; + addiu $t2, $zero, 36 ## L:386 | **28 | cmdRdpRect = 0x24; + vrcph $v05.e3, $v09.e3 ## L:281 | ^ | invW.w = invert_half(posClip).w; + vrcpl $v06.e3, $v10.e3 ## L:281 | 29 | invW.w = invert_half(posClip).w; + vrcph $v05.e3, $v09.e7 ## L:282 | 30 | invW.W = invert_half(posClip).W; + lsv $v09, 14, 0, $at ## L:286 | ^ | posClip:sint.W = load(BASE_SIZE).x; + andi $t5, $t4, 16448 ## L:276 | 31 | clipB = temp1 & 0b0100'0000'0100'0000; + vrcpl $v06.e7, $v10.e7 ## L:282 | ^ | invW.W = invert_half(posClip).W; + vmov $v10.e7, $v00.e0 ## L:288 | 32 | posClip:sfract.W = 0; + vmov $v10.e3, $v00.e0 ## L:287 | 33 | posClip:sfract.w = 0; + lsv $v09, 6, 0, $at ## L:285 | ^ | posClip:sint.w = load(BASE_SIZE).x; + vrcph $v05.e7, $v00.e7 ## L:282 | 34 | invW.W = invert_half(posClip).W; + vmudl $v29, $v10, $v06.h3 ## L:291 | **37 | posClip *= invW.wwwwWWWW; + vmadm $v29, $v09, $v06.h3 ## L:291 | 38 | posClip *= invW.wwwwWWWW; + vmadn $v10, $v10, $v05.h3 ## L:291 | 39 | posClip *= invW.wwwwWWWW; + vmadh $v09, $v09, $v05.h3 ## L:291 | 40 | posClip *= invW.wwwwWWWW; + vmulf $v14, $v14, $v09.h3 ## L:294 | ***44 | localPartSize:sfract *= posClip:sint.wwwwWWWW; + vmudl $v29, $v10, $v20.v ## L:297 | 45 | vec32 posScreen = posClip * screenSize; + vmadm $v29, $v09, $v20.v ## L:297 | 46 | vec32 posScreen = posClip * screenSize; + andi $t1, $t4, 1028 ## L:275 | ^ | clipA = temp1 & 0b0000'0100'0000'0100; + vmadn $v04, $v10, $v19.v ## L:297 | 47 | vec32 posScreen = posClip * screenSize; + vmadh $v03, $v09, $v19.v ## L:297 | 48 | vec32 posScreen = posClip * screenSize; + lb $t4, 15($s6) ## L:327 | ^ | temp1:s8 = load(ptrIn, 0x0F); + vmadh $v02, $v18, $v07.v ## L:298 | 49 | vec16 posCenter = screenOffset:sint +* vecOne; + vmadh $v04, $v07, $v14.v ## L:303 | *51 | vec16 posEnd = vecOne +* localPartSize:sint; + addu $t4, $t4, $s2 ## L:330 | ^ | temp1 += texOffset; temp1 <<= 3; + vsubc $v08, $v02, $v14.v ## L:304 | *53 | posStart = posCenter - localPartSize:sint; + vmudn $v14, $v14, $v30.e6 ## L:308 | 54 | localPartSize *= 2; + vrcp $v06.e0, $v14.e0 ## L:309 | ***58 | invW.x = invert_half(localPartSize).x; + vrcph $v05.e0, $v14.e0 ## L:309 | 59 | invW.x = invert_half(localPartSize).x; + vrcp $v06.e1, $v14.e1 ## L:310 | 60 | invW.y = invert_half(localPartSize).y; + vrcph $v05.e1, $v14.e1 ## L:310 | 61 | invW.y = invert_half(localPartSize).y; + vrcp $v06.e4, $v14.e4 ## L:311 | 62 | invW.X = invert_half(localPartSize).X; + vrcph $v05.e4, $v14.e4 ## L:311 | 63 | invW.X = invert_half(localPartSize).X; + vrcp $v06.e5, $v14.e5 ## L:312 | 64 | invW.Y = invert_half(localPartSize).Y; + vrcph $v05.e5, $v14.e5 ## L:312 | 65 | invW.Y = invert_half(localPartSize).Y; + addu $a2, $a2, $s2 ## L:329 | ^ | temp0 += texOffset; temp0 <<= 3; + sll $a2, $a2, 3 ## L:329 | ***69 | temp0 += texOffset; temp0 <<= 3; + vmudh $v01, $v08, $v05.v ## L:317 | ^ | vec16 uvStart = posStart * invW:sint; + vor $v03, $v00, $v05 ## L:313 | 70 | vec16 uvDelta = invW:sint; + sll $t4, $t4, 3 ## L:330 | ^ | temp1 += texOffset; temp1 <<= 3; + vxor $v05, $v00, $v00.e0 ## L:343 | 71 | vec16 texOffsetTotal = 0; + vmudm $v01, $v01, $v31.e6 ## L:318 | *73 | uvStart >>= 7; + mtc2 $t4, $v05.e4 ## L:345 | ^ | texOffsetTotal.X = temp1:s16; + vlt $v01, $v01, $v00.e0 ## L:319 | ***77 | uvStart = uvStart < 0; + mtc2 $a2, $v05.e0 ## L:344 | ^ | texOffsetTotal.x = temp0:s16; + vsubc $v06, $v00, $v01.v ## L:341 | ***81 | vec16 uvStartNeg = VZERO - uvStart; + vand $v05, $v05, $v12.e3 ## L:346 | 82 | texOffsetTotal &= texMirrorMask.w; + slv $v03, 0, 28, $s3 ## L:407 | ^ | store(uvDelta.xy, dmaDmemEnd, 0x0C, 16); + vge $v29, $v11, $v05.h0 ## L:349 | ***86 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; + vmrg $v01, $v06, $v01 ## L:349 | 87 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStartNeg : uvStart; + vlt $v04, $v04, $v15 ## L:352 | 88 | posEnd = min(posEnd, screenMax); + addiu $at, $zero, 3 ## L:420 | ^ | if(clipA == 0b0000'0011) { + vge $v08, $v08, $v16 ## L:353 | 89 | posStart = max(posStart, screenMin); + vaddc $v01, $v01, $v05.v ## L:355 | *91 | uvStart += texOffsetTotal; + ssv $v02, 4, 12, $s3 ## L:398 | ^ | store(posCenter.z, dmaDmemEnd, 0x04, 8); + mfc2 $sp, $v04.e1 ## L:1188 | 92 | outA = pos.y; + mfc2 $fp, $v08.e5 ## L:1194 | 93 | outB = pos.Y; + andi $sp, $sp, 4095 ## L:1189 | *95 | outA &= 0b1111'1111'1111; + vsubc $v06, $v12, $v01.v ## L:360 | ^ | uvStartNeg = texMirrorMask - uvStart; + mfc2 $k0, $v08.e0 ## L:1190 | 96 | u32 tmp = pos.x; + mfc2 $s1, $v08.e1 ## L:1188 | 97 | outA = pos.y; + andi $fp, $fp, 4095 ## L:1195 | 98 | outB &= 0b1111'1111'1111; + sll $k0, $k0, 12 ## L:1191 | 99 | tmp <<= 12; + vaddc $v06, $v06, $v12.e2 ## L:361 | ^ | uvStartNeg += texMirrorMask.z; + vge $v29, $v11, $v05.h0 ## L:363 | 100 | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; + andi $s1, $s1, 4095 ## L:1189 | ^ | outA &= 0b1111'1111'1111; + or $s1, $s1, $k0 ## L:1192 | 101 | outA |= tmp; + mfc2 $k0, $v08.e4 ## L:1196 | 102 | tmp = pos.X; + mfc2 $k1, $v04.e5 ## L:1194 | 103 | outB = pos.Y; + ldv $v05, 0, 8, $s6 ## L:383 | 104 | vec16 color = load(ptrIn, 8).xyzw; + sll $k0, $k0, 12 ## L:1197 | 105 | tmp <<= 12; + andi $k1, $k1, 4095 ## L:1195 | 106 | outB &= 0b1111'1111'1111; + vmrg $v01, $v01, $v06 ## L:363 | ^ | uvStart = texMirrorCompare >= texOffsetTotal.xxxxXXXX ? uvStart : uvStartNeg; + or $fp, $fp, $k0 ## L:1198 | 107 | outB |= tmp; + slv $v05, 0, 4, $s3 ## L:394 | 108 | store(color.xy, dmaDmemEnd, 4); + vlt $v06, $v08, $v04 ## L:370 | ^ | vec16 extend = posStart < posEnd; + mfc2 $k0, $v04.e0 ## L:1190 | 109 | u32 tmp = pos.x; + cfc2 $t4, $vcc ## L:371 | 110 | temp1 = get_vcc(); + lpv $v08, 0, 16, $s6 ## L:415 | 111 | posStart = load_vec_s8(ptrIn, 16); + sll $k0, $k0, 12 ## L:1191 | 112 | tmp <<= 12; + andi $a2, $t4, 3 ## L:373 | 113 | temp0 = temp1 & 0b0000'0011; + or $sp, $sp, $k0 ## L:1192 | 114 | outA |= tmp; + sw $sp, 0 + 16($s3) ## L:404 | 115 | @Barrier("pos-cmd") store(posEndA, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + slv $v01, 0, 24, $s3 ## L:406 | 116 | store(uvStart.xy, dmaDmemEnd, 0x08, 16); + mfc2 $k0, $v04.e4 ## L:1196 | 117 | tmp = pos.X; + sb $t2, 0 + 16($s3) ## L:405 | 118 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + or $t1, $t1, $a2 ## L:374 | 119 | clipA |= temp0; + sw $s1, 4 + 16($s3) ## L:403 | 120 | store(posA, dmaDmemEnd, 0x04, 16); + vmulf $v14, $v13, $v08.h3 ## L:416 | ^ | localPartSize = globalPartSize:sfract * posStart:sfract.wwwwWWWW; + andi $a2, $t4, 48 ## L:376 | 121 | temp0 = temp1 & 0b0011'0000; + or $t5, $t5, $a2 ## L:377 | 122 | clipB |= temp0; + sll $k0, $k0, 12 ## L:1197 | 123 | tmp <<= 12; + vmudm $v08, $v08, $v31.e7 ## L:417 | ^ | posStart >>= 8; + bne $t1, $at, LABEL_TPXCmd_DrawTextured_001E ## L:420 | 124 | if(clipA == 0b0000'0011) { + or $k1, $k1, $k0 ## L:1198 | *126 | outB |= tmp; + addiu $s3, $s3, 32 ## L:421 | 127 | dmaDmemEnd += 32; LABEL_TPXCmd_DrawTextured_001E: - addiu $at, $zero, 48 ## L:429 | 375 | if(clipB == 0b0011'0000) { - bne $t5, $at, LABEL_TPXCmd_DrawTextured_001F ## L:429 | 376 | if(clipB == 0b0011'0000) { - addiu $s6, $s6, 16 ## L:425 | *378 | ptrIn += 16; - sw $k1, 0 + 16($s3) ## L:434 | 379 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - slv $v01, 8, 24, $s3 ## L:437 | 380 | store(uvStart.XY, dmaDmemEnd, 0x08, 16); - slv $v05, 4, 4, $s3 ## L:430 | 381 | store(color.zw, dmaDmemEnd, 4); - ssv $v02, 12, 12, $s3 ## L:431 | 382 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); - sw $fp, 4 + 16($s3) ## L:433 | 383 | store(posB, dmaDmemEnd, 0x04, 16); - slv $v03, 8, 28, $s3 ## L:438 | 384 | store(uvDelta.XY, dmaDmemEnd, 0x0C, 16); - sb $t2, 0 + 16($s3) ## L:435 | 385 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 - addiu $s3, $s3, 32 ## L:440 | 386 | dmaDmemEnd += 32; + addiu $at, $zero, 48 ## L:431 | 128 | if(clipB == 0b0011'0000) { + bne $t5, $at, LABEL_TPXCmd_DrawTextured_001F ## L:431 | 129 | if(clipB == 0b0011'0000) { + addiu $s6, $s6, 16 ## L:427 | *131 | ptrIn += 16; + sw $k1, 0 + 16($s3) ## L:436 | 132 | @Barrier("pos-cmd") store(posEndB, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + sw $fp, 4 + 16($s3) ## L:435 | 133 | store(posB, dmaDmemEnd, 0x04, 16); + slv $v03, 8, 28, $s3 ## L:440 | 134 | store(uvDelta.XY, dmaDmemEnd, 0x0C, 16); + sb $t2, 0 + 16($s3) ## L:437 | 135 | @Barrier("pos-cmd") store(cmdRdpRect, dmaDmemEnd, 0x00, 16); ## Barrier: 0x1 + slv $v01, 8, 24, $s3 ## L:439 | 136 | store(uvStart.XY, dmaDmemEnd, 0x08, 16); + ssv $v02, 12, 12, $s3 ## L:433 | 137 | store(posCenter.Z, dmaDmemEnd, 0x04, 8); + addiu $s3, $s3, 32 ## L:442 | 138 | dmaDmemEnd += 32; + slv $v05, 4, -28, $s3 ## L:432 | 139 | store(color.zw, dmaDmemEnd, 4); LABEL_TPXCmd_DrawTextured_001F: - vmudn $v10, $v28, $v08.h0 ## L:92 | ^ | out = mat0 * vec.xxxxXXXX; - sltu $at, $s3, $s5 ## L:447 | 387 | if(dmaDmemEnd >= dmaDmemFlush) { - vmadh $v09, $v27, $v08.h0 ## L:92 | ^ | out = mat0 * vec.xxxxXXXX; - vmadn $v10, $v26, $v08.h1 ## L:93 | 388 | out = mat1 +* vec.yyyyYYYY; - vmadh $v09, $v25, $v08.h1 ## L:93 | 389 | out = mat1 +* vec.yyyyYYYY; - vmadn $v10, $v24, $v08.h2 ## L:94 | 390 | out = mat2 +* vec.zzzzZZZZ; - vmadh $v09, $v23, $v08.h2 ## L:94 | 391 | out = mat2 +* vec.zzzzZZZZ; - vmadn $v10, $v22, $v30.e7 ## L:95 | 392 | out = mat3 +* 1; - bne $at, $zero, LABEL_TPXCmd_DrawTextured_0020 ## L:447 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { - vmadh $v09, $v21, $v30.e7 ## L:95 | *394 | out = mat3 +* 1; - jal RDPQ_Send ## L:448 | 395 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 - nop ## L:448 | *397 | RDPQ_Send(dmaDmem, dmaDmemEnd); - or $s3, $zero, $s4 ## L:449 | 398 | dmaDmemEnd = dmaDmem; + vmudn $v10, $v28, $v08.h0 ## L:94 | ^ | out = mat0 * vec.xxxxXXXX; + vmadh $v09, $v27, $v08.h0 ## L:94 | 140 | out = mat0 * vec.xxxxXXXX; + vmadn $v10, $v26, $v08.h1 ## L:95 | 141 | out = mat1 +* vec.yyyyYYYY; + vmadh $v09, $v25, $v08.h1 ## L:95 | 142 | out = mat1 +* vec.yyyyYYYY; + vmadn $v10, $v24, $v08.h2 ## L:96 | 143 | out = mat2 +* vec.zzzzZZZZ; + vmadh $v09, $v23, $v08.h2 ## L:96 | 144 | out = mat2 +* vec.zzzzZZZZ; + sltu $at, $s3, $s5 ## L:449 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadn $v10, $v22, $v30.e7 ## L:97 | 145 | out = mat3 +* 1; + bne $at, $zero, LABEL_TPXCmd_DrawTextured_0020 ## L:449 | ^ | if(dmaDmemEnd >= dmaDmemFlush) { + vmadh $v09, $v21, $v30.e7 ## L:97 | *147 | out = mat3 +* 1; + jal RDPQ_Send ## L:450 | 148 | RDPQ_Send(dmaDmem, dmaDmemEnd); ## Args: $s4, $s3 + nop ## L:450 | *150 | RDPQ_Send(dmaDmem, dmaDmemEnd); + or $s3, $zero, $s4 ## L:451 | 151 | dmaDmemEnd = dmaDmem; LABEL_TPXCmd_DrawTextured_0020: - vch $v29, $v09, $v09.h3 ## L:452 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - vcl $v29, $v10, $v10.h3 ## L:452 | 399 | temp1 = clip(posClip, posClip.wwwwWWWW); - bne $s6, $s7, LABEL_TPXCmd_DrawTextured_001C ## L:452 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); - cfc2 $t4, $vcc ## L:452 | *401 | temp1 = clip(posClip, posClip.wwwwWWWW); + vch $v29, $v09, $v09.h3 ## L:454 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + vcl $v29, $v10, $v10.h3 ## L:454 | 152 | temp1 = clip(posClip, posClip.wwwwWWWW); + bne $s6, $s7, LABEL_TPXCmd_DrawTextured_001C ## L:454 | ^ | temp1 = clip(posClip, posClip.wwwwWWWW); + cfc2 $t4, $vcc ## L:454 | *154 | temp1 = clip(posClip, posClip.wwwwWWWW); LABEL_TPXCmd_DrawTextured_0016: - j RDPQ_Send ## L:1179 | 402 | goto RDPQ_Send; - ori $ra, $zero, %lo(RSPQ_Loop) ## L:1178 | *404 | RA = RSPQ_Loop; + j RDPQ_Send ## L:1177 | *****************************************************************************************244 | goto RDPQ_Send; + ori $ra, $zero, %lo(RSPQ_Loop) ## L:1176 | *246 | RA = RSPQ_Loop; OVERLAY_CODE_END: @@ -996,4 +1010,4 @@ OVERLAY_CODE_END: #define ra $31 .set at -.set macro +.set macro \ No newline at end of file diff --git a/src/t3d/rsp/rsp_tinypx.rspl b/src/t3d/rsp/rsp_tinypx.rspl index 0e8f787e..c21eeb1c 100644 --- a/src/t3d/rsp/rsp_tinypx.rspl +++ b/src/t3d/rsp/rsp_tinypx.rspl @@ -44,9 +44,11 @@ state alignas(8) vec16 MATRIX_PROJ[4]; // projection matrix alignas(8) vec16 MATRIX_MVP[4]; // view * model * projection - vec16 SCREEN_SCALE_OFFSET = { - 0, 0, 0, 0, // screen size scale (.xyzw) - 0, 0, 0x3FFF, 0x00FF // screen size offset (.XYZW), W is used for a fake clipping-code in 'triToScreenSpace' + // s16.16 screen-size scale + offset, DMA'd as one 24-byte block from the t3d state + // (must stay adjacent and 8-aligned, layout mirrors rsp_tiny3d.rspl) + alignas(8) s16 SCREEN_SCALE[8] = {0}; + s16 SCREEN_OFFSET[4] = { + 0, 0, 0x3FFF, 0x00FF }; alignas(8) s16 NORM_SCALE_W[4] = { @@ -91,7 +93,7 @@ command<0> TPXCmd_SyncT3D(u32 rdramMatrix, u32 rdramScreen, u16 wNorm) // get screen-size, this must happen after the matrix load // since the MV matrix will spill into the screen-size offset - dma_in(SCREEN_SCALE_OFFSET, rdramScreen); + dma_in(SCREEN_SCALE, rdramScreen, 24); // SCREEN_SCALE + SCREEN_OFFSET } command<1> TPXCmd_DrawColor(s16 dataSize, s32 rdramAddr) @@ -126,11 +128,9 @@ command<1> TPXCmd_DrawColor(s16 dataSize, s32 rdramAddr) vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - screenSize:sfract = 0; - screenSize >>= 8; + vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; // s16.16 - vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; + vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; vec16 screenMin, screenMax; @@ -223,11 +223,9 @@ command<4> TPXCmd_DrawTextured(s16 dataSize, s32 rdramAddr) vec32 mat2 = load(MATRIX_MVP, 0x20).xyzwxyzw; vec32 mat3 = load(MATRIX_MVP, 0x30).xyzwxyzw; - vec32 screenSize:sint = load(SCREEN_SCALE_OFFSET).xyzwxyzw; - screenSize:sfract = 0; - screenSize >>= 8; + vec32 screenSize = load(SCREEN_SCALE).xyzwxyzw; // s16.16 - vec16 screenOffset = load(SCREEN_SCALE_OFFSET, 0x08).xyzwxyzw; + vec16 screenOffset = load(SCREEN_OFFSET).xyzwxyzw; vec16 normScaleW = load(NORM_SCALE_W).xyzwxyzw; vec16 screenMin, screenMax; diff --git a/src/t3d/rsp/rspq_triangle.rspl b/src/t3d/rsp/rspq_triangle.rspl index 1843a264..f3831c66 100644 --- a/src/t3d/rsp/rspq_triangle.rspl +++ b/src/t3d/rsp/rspq_triangle.rspl @@ -97,45 +97,38 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vall3.w = vtx3; vall3.xy = load(vtx3, VTX_ATTR_XY).xy; - // Create a vector for negative pow2 constants - vec16<$v27> vmconst = VZERO - VSHIFT; - u16<$t3> clip1 = load(vtx1, VTX_ATTR_CLIPFLAGS); u16<$t4> clip2 = load(vtx2, VTX_ATTR_CLIPFLAGS); u16<$t5> clip3 = load(vtx3, VTX_ATTR_CLIPFLAGS); + // only the first key needs to be a full broadcast, the others are read via + // element-select on the compare's second operand vec16<$v06> vy1 = vall1.y; - vec16<$v07> vy2 = vall2.y; - vec16<$v08> vy3 = vall3.y; - - // Create a vector of ones. - // Do it with an addition (vaddc) so that we also clear - // VCO to make sure the first max()/vge does - // the right thing if vy1==vy2 - vec16<$v12> vk1 = VZERO + 1; + vec16<$v07> vy2; clip1 |= clip2; clip1 |= clip3; undef clip2, clip3; - // Do a sort-of-three (min, mid, max), using vyN as key of the sort, - // and vallN as values to sort. We compare the keys with min/max, - // and then use select (vmrg) to apply the swap. + // Do a sort-of-three (min, mid, max), using the Y values as key of the sort, + // and vallN as values to sort. One compare (vlt, VCC = a < b) per round is enough: + // select(a, b) picks the min, select(b, a) with the same VCC picks the max. + // On equal keys VCC is 0, so min = b and max = a (same as the vge/vlt pair before). u32<$t0> did_swap_0; u32<$t1> did_swap_1; vec16<$v09> vytmp1; - vec16<$v10> vytmp2; vec16<$v04> valltmp1; vec16<$v05> valltmp2; - vytmp1 = max(vy1, vy2); - valltmp1 = select(vall1, vall2); - vy1 = min(vy1, vy2); + vytmp1 = max(vy1, vall2.y); // broadcast max key, needed as first operand in round 3 + vy1 = min(vy1, vall2.y); + valltmp1 = select(vall2, vall1); vall1 = select(vall1, vall2); did_swap_0 = get_vcc(); - vec16<$v28> vhmlupp; - vhmlupp ^= vhmlupp; + // Zeroed with an addition (vaddc) so that VCO is cleared as well, which the + // first sort compare (vlt) relies on when vy1==vy2 + vec16<$v28> vhmlupp = VZERO + VZERO; u16<$s7> buffOffset = load(RDPQ_TRI_BUFF_OFFSET); @@ -145,9 +138,8 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u if(rejCodes != 0xFF)goto JrRa; undef rejCodes; - vytmp2 = max(vy1, vy3); - valltmp2 = select(vall1, vall3); - vy1 = min(vy1, vy3); + vy1 = min(vy1, vall3.y); + valltmp2 = select(vall3, vall1); vall1 = select(vall1, vall3); did_swap_1 = get_vcc(); @@ -159,13 +151,12 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u // instead so the two lifetimes cannot collide. u32<$t2> tileIdx = clip1 >> 13; - vy3 = max(vytmp1, vytmp2); - vall3 = select(valltmp1, valltmp2); - vy2 = min(vytmp1, vytmp2); + vy2 = min(vytmp1, valltmp2.y); + vall3 = select(valltmp2, valltmp1); vall2 = select(valltmp1, valltmp2); u32<$t5> did_swap_2 = get_vcc(); - undef vytmp1, vytmp2; + undef vytmp1; u32<$t4> clipCodes = clip1 & 0x1F00; u16<$s3> outPtr = buffOffset + CLIP_BUFFER_TMP; @@ -197,6 +188,9 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vx12F.x = vall1.x; vx12F.z = vall2.x; + // YL (max Y) is stored straight from the sorted vertex, there is no separate key for it + @Barrier("tri-out") store(vall3.y, outPtr, 2); + did_swap_0 &= 1; u32<$t1> cullFlip = cull ^ did_swap_0; undef did_swap_0; @@ -205,14 +199,13 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u // Prepare -MY for the crossprod VTEMP = VZERO - vm.y; - // FY.e4 = Y1 (s15.16) + // FY.e4 = Y1 (s15.16), only the fraction is needed (see below) vec16<$v26> vfyF = vy1 << 14; - vec16<$v25> vfyI = vy1 >> 2; + vec16<$v25> vfyI; buffOffset ^= RDP_CMD_MAX_SIZE; @Barrier("tri-out") store(vy2.x, outPtr, 4); - @Barrier("tri-out") store(vy3.x, outPtr, 2); - undef vy1, vy2, vy3; + undef vy1, vy2; // Cross product for the winding order (and 1/NZ later): // NZ = MX*HY - MY*HX @@ -238,9 +231,11 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u u32<$t4> color_dmem = outPtr + 0x20; // FY.e0 = floorf(y1) - y1 - // this is always a negative fraction, so fy_i is always 0xFFFF (or fy_i=fy_f=0) + // this is always a negative fraction, so fy_i is always 0xFFFF (or fy_i=fy_f=0): + // the vsubc sets VCO when the fraction is non-zero, and 'x - x - VCO' yields exactly + // that -1/0 for any x, so no integer part has to be computed (was 'vy1 >> 2' before) vfyF = VZERO - vfyF; - vfyI:sint = vfyI - vfyI; + vfyI:sint = vfyF - vfyF; vec16<$v08> vwF; vec16<$v07> vwI; @@ -307,10 +302,6 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vec16<$v21> vslopeF; vec16<$v20> vslopeI; - // vslopem2 = X/2 * (-4) = -2*X - vec16<$v01> vslopem2F = vslopeF:ufract * vmconst:sint.Y; - vec16<$v02> vslopem2I = vslopeI:sint +* vmconst:sint.Y; - // Calculate the minimum W (between e0 and e2) VTEMP = vwF - vwF.z; vwI = min(vwI, vwI.z); @@ -322,10 +313,13 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vec16<$v14> vinvwI; vinvwF.Z = load(vtx3, VTX_ATTR_INVWf).x; - // NR: R*(X/2) + // NR step: t = n * y0 with y0 the vrcp half-reciprocal, so t ~ 0.5. + // Only the fraction of t is needed: d = 1 - t is then (0x10000 - tF) as a 0.16 + // fraction, and the refined value is y1 = 4*y0 * d (= 2 * (2*y0) * (1 - t)). + // Same result as the former (-2*X) * (R*X/2 - 1) form with fewer ops and no + // -1/-4 constants (vk1/vmconst). undef vm, vl; vec16<$v03> vtmpF; - vec16<$v04> vtmpI; asm_op("vmudl", vtmpF, vslopeF, vhml.yywwYYWW); asm_op("vmadm", vtmpF, vslopeI, vhml.yywwYYWW); vinvwF.X = load(vtx1, VTX_ATTR_INVWf).x; @@ -335,16 +329,18 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u u32<$t5> tex_dmem = triCmd & 0x400; tex_dmem >>= 4; - vtmpF = vslopeF:ufract +* vhmlupp:sint; - vtmpI = vslopeI:sint +* vhmlupp:sint; + vtmpF = vslopeF:ufract +* vhmlupp:sint; // tF (fraction of t) undef vhmlupp; - // NR: R*X/2 - 1 u32<$t0> negMY = vhml.w; u32<$t1> negHX = vhml.x; - vtmpF = vk1:ufract +* vmconst:sint.W; - vtmpI = vk1:sint +* vmconst:sint.W; - undef vk1; + + // d = 1 - t (0x10000 - tF, t is never 0 here) + vtmpF = VZERO - vtmpF; + + // 4*y0 (the vrcp result is the half reciprocal) + vslopeF = vslopeF:ufract * VSHIFT:sint.Y; + vslopeI = vslopeI:sint +* VSHIFT:sint.Y; // Calculate the minimum W (between e0 and e4) // Now vwI/vwF.e0 contains the minimum W @@ -356,16 +352,13 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vinvwI.Z = load(vtx3, VTX_ATTR_INVWi).x; vinvwI.X = load(vtx1, VTX_ATTR_INVWi).x; - // NR: -2*X * (R*X/2 - 1) - // = 2*X * (1 - R*X/2) - // = X * (2 - R*X) + // y1 = 4*y0 * d vec16<$v19> vnzF; vec16<$v18> vnzI; - asm_op("vmudl", VTEMP, vtmpF, vslopem2F); - asm_op("vmadm", VTEMP, vtmpI, vslopem2F); - vnzF = vtmpF:ufract +* vslopem2I:sint; - vnzI = vtmpI:sint +* vslopem2I:sint; - undef vtmpF, vtmpI, vslopem2F, vslopem2I; + asm_op("vmudl", VTEMP, vslopeF, vtmpF); + vnzI = vslopeI:sint +* vtmpF:ufract; + vnzF = get_acc_low(); + undef vtmpF; u32<$t6> z_dmem = triCmd & 0x200; z_dmem >>= 3; @@ -395,6 +388,10 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u asm_op("vmudl", VTEMP, vinvwF, vwF.x); asm_op("vmadm", VTEMP, vinvwI, vwF.x); vinvwF = vinvwF:ufract +* vwI:sint.x; + + vinvwF:ufract -= 1; + vinvwF >>= 1; + undef vwI, vwF; // Load the S/T coordinates @@ -423,12 +420,6 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vhml.x = negHX; undef negMY, negHX; - // Subtract INVW by 1. This workarounds an overflow when INVW is exactly 1.0. - vinvwF -= 1; - - // Prepare the VCC for the select() later (to merge the tex coords into the attributes) - set_vcc(0xCF); - // vattr now contains only RGBA, loaded via luv. Shift them back to raw bytes. vattr1 >>>= 7; vattr2 >>>= 7; @@ -439,9 +430,13 @@ function RDPQ_Triangle_Send_Async(u32<$a0> vtx1, u32<$a1> vtx2, u32<$a2> vtx3, u vattr2.W = load(vtx2, VTX_ATTR_Z).x; vattr3.W = load(vtx3, VTX_ATTR_Z).x; - // Divide vinvwF by 2. This is needed because it is going to be used - // in a vmulf which expects a 0.15 number. - vinvwF >>>= 1; + // clamp negative depth (no near plane), other lanes are unaffected + vattr1 = vattr1 >= 0; + vattr2 = vattr2 >= 0; + vattr3 = vattr3 >= 0; + + // Prepare the VCC for the select() later (to merge the tex coords into the attributes) + set_vcc(0xCF); // vx12 = X1 -- X2 -- -- -- -- -- // slope = HX/HY -- MX/MY -- LX/LY -- -- -- diff --git a/src/t3d/rsp/rspq_triangle_rspl.inc b/src/t3d/rsp/rspq_triangle_rspl.inc index 93388fb3..2cc46aea 100644 --- a/src/t3d/rsp/rspq_triangle_rspl.inc +++ b/src/t3d/rsp/rspq_triangle_rspl.inc @@ -73,293 +73,286 @@ T3DCmd_TriDraw: srl $a2, $a1, 16 ## L:68 | 2 | u32<$a2> vert2 = vert1 >> 16; RDPQ_Triangle_Send_Async: ## hot-path cycles: 142 - llv $v01, 0, 0, $a0 ## L:95 | ^ | vall1.xy = load(vtx1, 0x00).xy; - mtc2 $a0, $v01.e3 ## L:93 | 2 | vall1.w = vtx1; - llv $v02, 0, 0, $a1 ## L:96 | 3 | vall2.xy = load(vtx2, 0x00).xy; - vsubc $v27, $v00, $v30.v ## L:101 | ^ | vec16<$v27> vmconst = VZERO - VSHIFT; - llv $v03, 0, 0, $a2 ## L:98 | 4 | vall3.xy = load(vtx3, 0x00).xy; - vaddc $v12, $v00, $v30.e7 ## L:115 | ^ | vec16<$v12> vk1 = VZERO + 1; - lhu $t4, 6($a1) ## L:104 | 5 | u16<$t4> clip2 = load(vtx2, 0x06); - addiu $at, $zero, 255 ## L:145 | 6 | if(rejCodes != 0xFF)goto JrRa; - vor $v06, $v00, $v01.e1 ## L:107 | ^ | vec16<$v06> vy1 = vall1.y; - vor $v07, $v00, $v02.e1 ## L:108 | 7 | vec16<$v07> vy2 = vall2.y; - lhu $t3, 6($a0) ## L:103 | ^ | u16<$t3> clip1 = load(vtx1, 0x06); - mtc2 $a1, $v02.e3 ## L:94 | 8 | vall2.w = vtx2; - vor $v08, $v00, $v03.e1 ## L:109 | ^ | vec16<$v08> vy3 = vall3.y; - lhu $t5, 6($a2) ## L:105 | 9 | u16<$t5> clip3 = load(vtx3, 0x06); - lhu $s7, %lo(RDPQ_TRI_BUFF_OFFSET + 0) ## L:140 | 10 | u16<$s7> buffOffset = load(RDPQ_TRI_BUFF_OFFSET); - or $t3, $t3, $t4 ## L:117 | 11 | clip1 |= clip2; - vge $v09, $v06, $v07 ## L:131 | ^ | vytmp1 = max(vy1, vy2); - vmrg $v04, $v01, $v02 ## L:132 | 12 | valltmp1 = select(vall1, vall2); - or $t3, $t3, $t5 ## L:118 | ^ | clip1 |= clip3; - vlt $v06, $v06, $v07 ## L:133 | 13 | vy1 = min(vy1, vy2); - mtc2 $a2, $v03.e3 ## L:97 | ^ | vall3.w = vtx3; - vmrg $v01, $v01, $v02 ## L:134 | 14 | vall1 = select(vall1, vall2); - andi $t6, $t3, 255 ## L:144 | ^ | u32<$t6> rejCodes = clip1 & 0xFF; - vxor $v28, $v28, $v28.v ## L:138 | 15 | vhmlupp ^= vhmlupp; - bne $t6, $at, JrRa ## L:145 | ^ | if(rejCodes != 0xFF)goto JrRa; - cfc2 $t0, $vcc ## L:135 | 16 | did_swap_0 = get_vcc(); - vge $v10, $v06, $v08 ## L:148 | 17 | vytmp2 = max(vy1, vy3); - vmrg $v05, $v01, $v03 ## L:149 | 18 | valltmp2 = select(vall1, vall3); - addiu $s3, $s7, %lo(CLIP_BUFFER_TMP) ## L:171 | ^ | u16<$s3> outPtr = buffOffset + CLIP_BUFFER_TMP; - srl $t2, $t3, 13 ## L:160 | 19 | u32<$t2> tileIdx = clip1 >> 13; - vlt $v06, $v06, $v08 ## L:150 | ^ | vy1 = min(vy1, vy3); - cfc2 $t1, $vcc ## L:152 | 20 | did_swap_1 = get_vcc(); - vmrg $v01, $v01, $v03 ## L:151 | ^ | vall1 = select(vall1, vall3); - vge $v08, $v09, $v10 ## L:162 | 21 | vy3 = max(vytmp1, vytmp2); - andi $t4, $t3, 7936 ## L:170 | ^ | u32<$t4> clipCodes = clip1 & 0x1F00; - lw $a3, %lo(TRI_COMMAND + 0) ## L:154 | 22 | u32<$a3> triCmd = load(TRI_COMMAND); - vmrg $v03, $v04, $v05 ## L:163 | ^ | vall3 = select(valltmp1, valltmp2); - vlt $v07, $v09, $v10 ## L:164 | 23 | vy2 = min(vytmp1, vytmp2); - ssv $v06, 0, 6, $s3 ## L:172 | ^ | @Barrier("tri-out") store(vy1.x, outPtr, 6); ## Barrier: 0x1 - vmrg $v02, $v04, $v05 ## L:165 | 24 | vall2 = select(valltmp1, valltmp2); - bne $t4, $zero, RDPQ_Triangle_Clip ## L:176 | ^ | if(clipCodes != 0)goto RDPQ_Triangle_Clip; - cfc2 $t5, $vcc ## L:166 | 25 | u32<$t5> did_swap_2 = get_vcc(); - vmov $v23.e0, $v01.e0 ## L:197 | 26 | vx12F.x = vall1.x; - mfc2 $a2, $v03.e3 ## L:193 | ^ | vtx3 = vall3.w; - xor $t0, $t0, $t1 ## L:179 | 27 | did_swap_0 ^= did_swap_1; - xor $t0, $t0, $t5 ## L:180 | 28 | did_swap_0 ^= did_swap_2; - vsubc $v05, $v02, $v01.v ## L:187 | ^ | vec16<$v05> vm = vall2 - vall1; - vsubc $v24, $v03, $v01.v ## L:185 | 29 | vec16<$v24> vhml = vall3 - vall1; - ssv $v07, 0, 4, $s3 ## L:213 | ^ | @Barrier("tri-out") store(vy2.x, outPtr, 4); ## Barrier: 0x1 - ssv $v08, 0, 2, $s3 ## L:214 | 30 | @Barrier("tri-out") store(vy3.x, outPtr, 2); ## Barrier: 0x1 - vsubc $v04, $v03, $v02.v ## L:188 | ^ | vec16<$v04> vl = vall3 - vall2; - mfc2 $a1, $v02.e3 ## L:192 | 31 | vtx2 = vall2.w; - vmudn $v26, $v06, $v31.e1 ## L:209 | ^ | vec16<$v26> vfyF = vy1 << 14; - vsubc $v29, $v00, $v05.e1 ## L:206 | 32 | VTEMP = VZERO - vm.y; - slv $v05, 0, 8, $s3 ## L:232 | ^ | @Barrier("tri-oA", before) @Barrier("tri-out") store(vm.xy, outPtr, 8); ## Barrier: 0x1 - andi $t0, $t0, 1 ## L:200 | 33 | did_swap_0 &= 1; - vmudm $v25, $v06, $v31.e1 ## L:210 | ^ | vec16<$v25> vfyI = vy1 >> 2; - vmov $v23.e2, $v02.e0 ## L:198 | 34 | vx12F.z = vall2.x; - mfc2 $a0, $v01.e3 ## L:191 | ^ | vtx1 = vall1.w; - vmudh $v19, $v05, $v24.e1 ## L:221 | 35 | vnzF = vm:sint * vhml:sint.y; - slv $v04, 0, 12, $s3 ## L:233 | ^ | @Barrier("tri-oA", before) @Barrier("tri-out") store(vl.xy, outPtr, 12); ## Barrier: 0x1 - vmadh $v19, $v24, $v29.v ## L:222 | 36 | vnzF = vhml:sint +* VTEMP:sint; - xor $t1, $v0, $t0 ## L:201 | ^ | u32<$t1> cullFlip = cull ^ did_swap_0; - ldv $v24, 4, 8, $s3 ## L:234 | 37 | @Barrier("tri-oA", after) @Barrier("tri-oA2", before) vhml.z = load(outPtr, 8).xyzw; - vsar $v18, COP2_ACC_HI ## L:223 | ^ | vnzI = get_acc_high(); - vsar $v19, COP2_ACC_MD ## L:224 | 38 | vnzF = get_acc_mid(); - lsv $v08, 4, 30, $a1 ## L:248 | ^ | vwF.z = load(vtx2, 0x1E).x; - vsubc $v26, $v00, $v26.v ## L:242 | 39 | vfyF = VZERO - vfyF; - xori $s7, $s7, 176 ## L:211 | ^ | buffOffset ^= 176; - vsub $v25, $v25, $v25.v ## L:243 | 40 | vfyI:sint = vfyI - vfyI; - lsv $v08, 8, 30, $a2 ## L:249 | ^ | vwF.X = load(vtx3, 0x1E).x; - mfc2 $t0, $v18.e0 ## L:252 | 41 | s32<$t0> nzSign = vnzI.x; - vrcph $v20.e7, $v18.e0 ## L:264 | ^ | vslope.W = invert_half(vnz).x; - addiu $t4, $s3, 32 ## L:238 | 42 | u32<$t4> color_dmem = outPtr + 0x20; - vrcpl $v21.e7, $v19.e0 ## L:264 | ^ | vslope.W = invert_half(vnz).x; - vrcph $v20.e7, $v00.e0 ## L:264 | 43 | vslope.W = invert_half(vnz).x; - lsv $v08, 0, 30, $a0 ## L:247 | ^ | vwF.x = load(vtx1, 0x1E).x; - vrcp $v21.e0, $v24.e1 ## L:268 | 44 | vslope.x = invert_half(vhml).y; - TAG_CullFlipA: slt $t0, $t0, $zero ## L:269 | ^ | @Tag("CullFlipA") asm_op("slt", nzSign, nzSign, ZERO); - beq $t0, $t1, JrRa ## L:270 | 45 | if(nzSign == cullFlip)goto JrRa; - vrcph $v20.e0, $v24.e1 ## L:268 | 46 | vslope.x = invert_half(vhml).y; - lsv $v15, 8, 34, $a0 ## L:331 | 47 | vinvwF.X = load(vtx1, 0x22).x; - vrcp $v21.e2, $v05.e1 ## L:285 | ^ | vslope.z = invert_half(vm).y; - lsv $v07, 0, 22, $a0 ## L:289 | 48 | vwI.x = load(vtx1, 0x16).x; - vrcph $v20.e2, $v05.e1 ## L:285 | ^ | vslope.z = invert_half(vm).y; - vrcp $v21.e4, $v04.e1 ## L:287 | 49 | vslope.X = invert_half(vl).y; - lsv $v14, 8, 32, $a0 ## L:357 | ^ | vinvwI.X = load(vtx1, 0x20).x; - lsv $v07, 4, 22, $a1 ## L:290 | 50 | vwI.z = load(vtx2, 0x16).x; - vrcph $v20.e4, $v04.e1 ## L:287 | ^ | vslope.X = invert_half(vl).y; - lsv $v07, 8, 22, $a2 ## L:291 | 51 | vwI.X = load(vtx3, 0x16).x; - vmov $v28.e7, $v18.e0 ## L:282 | ^ | vhmlupp.W = vnzI.x; - lsv $v14, 10, 32, $a1 ## L:355 | 52 | vinvwI.Y = load(vtx2, 0x20).x; - vmov $v24.e7, $v19.e0 ## L:281 | ^ | vhml.W = vnzF.x; - vmudn $v01, $v21, $v27.e5 ## L:311 | 53 | vec16<$v01> vslopem2F = vslopeF:ufract * vmconst:sint.Y; - lsv $v15, 10, 34, $a1 ## L:332 | ^ | vinvwF.Y = load(vtx2, 0x22).x; - llv $v06, 8, 12, $a2 ## L:406 | 54 | vtex3.XY = load(vtx3, 0x0C).xy; - vmadh $v02, $v20, $v27.e5 ## L:312 | ^ | vec16<$v02> vslopem2I = vslopeI:sint +* vmconst:sint.Y; - lsv $v15, 12, 34, $a2 ## L:323 | 55 | vinvwF.Z = load(vtx3, 0x22).x; - vsubc $v29, $v08, $v08.e2 ## L:315 | ^ | VTEMP = vwF - vwF.z; - vlt $v07, $v07, $v07.e2 ## L:316 | 56 | vwI = min(vwI, vwI.z); - luv $v09, 0, 8, $a0 ## L:302 | ^ | vec16<$v09> vattr1 = load_vec_u8(vtx1, 0x08); - lsv $v14, 12, 32, $a2 ## L:356 | 57 | vinvwI.Z = load(vtx3, 0x20).x; - vmrg $v08, $v08, $v08.e2 ## L:318 | ^ | vwF = select(vwF, vwF.z); - TAG_CullFlipB: xori $t0, $t0, 1 ## L:298 | 58 | @Tag("CullFlipB") nzSign ^= 1; - vmudl $v03, $v21, $v24.q1 ## L:329 | ^ | asm_op("vmudl", vtmpF, vslopeF, vhml.yywwYYWW); - sll $t0, $t0, 7 ## L:299 | 59 | nzSign <<= 7; - vmadm $v03, $v20, $v24.q1 ## L:330 | ^ | asm_op("vmadm", vtmpF, vslopeI, vhml.yywwYYWW); - or $a3, $a3, $t0 ## L:317 | 60 | triCmd |= nzSign; - vmadn $v03, $v21, $v28.v ## L:338 | ^ | vtmpF = vslopeF:ufract +* vhmlupp:sint; - mfc2 $t1, $v24.e0 ## L:344 | 61 | u32<$t1> negHX = vhml.x; - vmadh $v04, $v20, $v28.v ## L:339 | ^ | vtmpI = vslopeI:sint +* vhmlupp:sint; - vmadn $v03, $v12, $v27.e7 ## L:345 | 62 | vtmpF = vk1:ufract +* vmconst:sint.W; - andi $t6, $a3, 512 ## L:370 | ^ | u32<$t6> z_dmem = triCmd & 0x200; - vmadh $v04, $v12, $v27.e7 ## L:346 | 63 | vtmpI = vk1:sint +* vmconst:sint.W; - andi $t5, $a3, 1024 ## L:335 | ^ | u32<$t5> tex_dmem = triCmd & 0x400; - vsubc $v29, $v08, $v08.e4 ## L:351 | 64 | VTEMP = vwF - vwF.X; - mfc2 $t0, $v24.e3 ## L:343 | ^ | u32<$t0> negMY = vhml.w; - vlt $v07, $v07, $v07.e4 ## L:352 | 65 | vwI = min(vwI, vwI.X); - subu $t1, $zero, $t1 ## L:421 | ^ | negHX = ZERO - negHX; - vmrg $v08, $v08, $v08.e4 ## L:353 | 66 | vwF = select(vwF, vwF.X); - luv $v11, 0, 8, $a2 ## L:301 | ^ | vec16<$v11> vattr3 = load_vec_u8(vtx3, 0x08); - vmudl $v29, $v03, $v01 ## L:364 | 67 | asm_op("vmudl", VTEMP, vtmpF, vslopem2F); - addiu $at, $zero, 207 ## L:430 | ^ | set_vcc(0xCF); - luv $v10, 0, 8, $a1 ## L:303 | 68 | vec16<$v10> vattr2 = load_vec_u8(vtx2, 0x08); - vmadm $v29, $v04, $v01 ## L:365 | ^ | asm_op("vmadm", VTEMP, vtmpI, vslopem2F); - vmadn $v19, $v03, $v02.v ## L:366 | 69 | vnzF = vtmpF:ufract +* vslopem2I:sint; - srl $t5, $t5, 4 ## L:336 | ^ | tex_dmem >>= 4; - or $a3, $a3, $t2 ## L:377 | 70 | triCmd |= tileIdx; - vmadh $v18, $v04, $v02.v ## L:367 | ^ | vnzI = vtmpI:sint +* vslopem2I:sint; - vmudl $v29, $v15, $v08.e0 ## L:395 | 71 | asm_op("vmudl", VTEMP, vinvwF, vwF.x); - ctc2 $at, $vcc ## L:430 | ^ | set_vcc(0xCF); - vmadm $v29, $v14, $v08.e0 ## L:396 | 72 | asm_op("vmadm", VTEMP, vinvwI, vwF.x); - llv $v03, 8, 12, $a1 ## L:405 | ^ | vtex2.XY = load(vtx2, 0x0C).xy; - vmadn $v15, $v15, $v07.e0 ## L:397 | 73 | vinvwF = vinvwF:ufract +* vwI:sint.x; - llv $v04, 8, 12, $a0 ## L:404 | ^ | vtex1.XY = load(vtx1, 0x0C).xy; - vmudn $v29, $v19, $v24.v ## L:414 | 74 | VTEMP = vnzF:ufract * vhml:sint; - addu $t5, $t5, $t4 ## L:372 | ^ | tex_dmem += color_dmem; - subu $t0, $zero, $t0 ## L:420 | 75 | negMY = ZERO - negMY; - vmadh $v29, $v18, $v24.v ## L:415 | ^ | VTEMP = vnzI:sint +* vhml:sint; - sh $a3, 0($s3) ## L:379 | 76 | @Barrier("tri-out") store(triCmd:u16, outPtr, 0); ## Barrier: 0x1 - vsar $v20, COP2_ACC_HI ## L:417 | ^ | vslopeI = get_acc_high(); - vsar $v21, COP2_ACC_MD ## L:416 | 77 | vslopeF = get_acc_mid(); - mtc2 $t1, $v24.e0 ## L:423 | ^ | vhml.x = negHX; - mtc2 $t0, $v24.e3 ## L:422 | 78 | vhml.w = negMY; - vsubc $v15, $v15, $v30.e7 ## L:427 | ^ | vinvwF -= 1; - lbu $t0, %lo(RDPQ_SYNCFULL_ONGOING + 0) ## L:477 | 79 | u8<$t0> syncFull = load(RDPQ_SYNCFULL_ONGOING); - vmudl $v09, $v09, $v31.e6 ## L:433 | ^ | vattr1 >>>= 7; - lsv $v09, 14, 4, $a0 ## L:438 | 80 | vattr1.W = load(vtx1, 0x04).x; - vmudl $v11, $v11, $v31.e6 ## L:435 | ^ | vattr3 >>>= 7; - srl $t6, $t6, 3 ## L:371 | 81 | z_dmem >>= 3; - vmudl $v10, $v10, $v31.e6 ## L:434 | ^ | vattr2 >>>= 7; - vmudl $v15, $v15, $v31.e0 ## L:444 | 82 | vinvwF >>>= 1; - lsv $v11, 14, 4, $a2 ## L:440 | ^ | vattr3.W = load(vtx3, 0x04).x; - vmudl $v29, $v21, $v26.e4 ## L:454 | 83 | vec32<$v16> vedges = vslope * vfy.X; - mfc0 $t1, COP0_DMA_BUSY ## L:458 | ^ | u32<$t1> dmaBusy = get_dma_busy(); - vmadm $v29, $v20, $v26.e4 ## L:454 | 84 | vec32<$v16> vedges = vslope * vfy.X; - andi $t3, $a3, 256 ## L:456 | ^ | u32<$t3> prim_size = triCmd & 0x100; - vmadn $v17, $v21, $v25.e4 ## L:454 | 85 | vec32<$v16> vedges = vslope * vfy.X; - lsv $v10, 14, 4, $a1 ## L:439 | ^ | vattr2.W = load(vtx2, 0x04).x; - vmadh $v16, $v20, $v25.e4 ## L:454 | 86 | vec32<$v16> vedges = vslope * vfy.X; - sdv $v15, 8, 16, $s3 ## L:461 | ^ | @Barrier("tri-oB", before) @Barrier("tri-out") store(vinvwF.XYZW, outPtr, 16); ## Barrier: 0x1 - vmulf $v03, $v03, $v15.h1 ## L:468 | 87 | vtex2:sfract *= vinvwF.yyyyYYYY; - lsv $v11, 12, 20, $s3 ## L:464 | ^ | @Barrier("tri-oB", after) @Barrier("tri-oB2", before) vattr3.Z = load(outPtr, 20).x; - lsv $v10, 12, 18, $s3 ## L:463 | 88 | @Barrier("tri-oB", after) @Barrier("tri-oB2", before) vattr2.Z = load(outPtr, 18).x; - vmulf $v06, $v06, $v15.h2 ## L:469 | ^ | vtex3:sfract *= vinvwF.zzzzZZZZ; - vmulf $v04, $v04, $v15.h0 ## L:467 | 89 | vtex1:sfract *= vinvwF.xxxxXXXX; - lsv $v09, 12, 16, $s3 ## L:462 | ^ | @Barrier("tri-oB", after) @Barrier("tri-oB2", before) vattr1.Z = load(outPtr, 16).x; - vmudm $v22, $v23, $v31.e1 ## L:474 | 90 | vec16<$v22> vx12I = vx12F >> 2; - bne $t1, $zero, LABEL_RDPQ_Triangle_Send_Async_0006## L:479 | ^ | @Unlikely if(dmaBusy != 0) - vmudn $v23, $v23, $v31.e1 ## L:475 | 91 | vx12F <<= 14; + mtc2 $a0, $v01.e3 ## L:93 | ^ | vall1.w = vtx1; + mtc2 $a1, $v02.e3 ## L:94 | 2 | vall2.w = vtx2; + llv $v01, 0, 0, $a0 ## L:95 | 3 | vall1.xy = load(vtx1, 0x00).xy; + lhu $t3, 6($a0) ## L:100 | 4 | u16<$t3> clip1 = load(vtx1, 0x06); + lhu $s7, %lo(RDPQ_TRI_BUFF_OFFSET + 0) ## L:133 | 5 | u16<$s7> buffOffset = load(RDPQ_TRI_BUFF_OFFSET); + lhu $t4, 6($a1) ## L:101 | 6 | u16<$t4> clip2 = load(vtx2, 0x06); + llv $v02, 0, 0, $a1 ## L:96 | 7 | vall2.xy = load(vtx2, 0x00).xy; + vor $v06, $v00, $v01.e1 ## L:106 | ^ | vec16<$v06> vy1 = vall1.y; + addiu $at, $zero, 255 ## L:138 | 8 | if(rejCodes != 0xFF)goto JrRa; + lhu $t5, 6($a2) ## L:102 | 9 | u16<$t5> clip3 = load(vtx3, 0x06); + mtc2 $a2, $v03.e3 ## L:97 | 10 | vall3.w = vtx3; + or $t3, $t3, $t4 ## L:109 | 11 | clip1 |= clip2; + vge $v09, $v06, $v02.e1 ## L:123 | ^ | vytmp1 = max(vy1, vall2.y); + llv $v03, 0, 0, $a2 ## L:98 | 12 | vall3.xy = load(vtx3, 0x00).xy; + vlt $v06, $v06, $v02.e1 ## L:124 | ^ | vy1 = min(vy1, vall2.y); + or $t3, $t3, $t5 ## L:110 | 13 | clip1 |= clip3; + vmrg $v04, $v02, $v01 ## L:125 | ^ | valltmp1 = select(vall2, vall1); + vmrg $v01, $v01, $v02 ## L:126 | 14 | vall1 = select(vall1, vall2); + andi $t6, $t3, 255 ## L:137 | ^ | u32<$t6> rejCodes = clip1 & 0xFF; + vaddc $v28, $v00, $v00.v ## L:131 | 15 | vec16<$v28> vhmlupp = VZERO + VZERO; + bne $t6, $at, JrRa ## L:138 | ^ | if(rejCodes != 0xFF)goto JrRa; + cfc2 $t0, $vcc ## L:127 | 16 | did_swap_0 = get_vcc(); + vlt $v06, $v06, $v03.e1 ## L:141 | 17 | vy1 = min(vy1, vall3.y); + andi $t4, $t3, 7936 ## L:161 | ^ | u32<$t4> clipCodes = clip1 & 0x1F00; + vmrg $v05, $v03, $v01 ## L:142 | 18 | valltmp2 = select(vall3, vall1); + vmrg $v01, $v01, $v03 ## L:143 | 19 | vall1 = select(vall1, vall3); + addiu $s3, $s7, %lo(CLIP_BUFFER_TMP) ## L:162 | ^ | u16<$s3> outPtr = buffOffset + CLIP_BUFFER_TMP; + cfc2 $t1, $vcc ## L:144 | 20 | did_swap_1 = get_vcc(); + ssv $v06, 0, 6, $s3 ## L:163 | 21 | @Barrier("tri-out") store(vy1.x, outPtr, 6); ## Barrier: 0x1 + lw $a3, %lo(TRI_COMMAND + 0) ## L:146 | 22 | u32<$a3> triCmd = load(TRI_COMMAND); + vlt $v07, $v09, $v05.e1 ## L:154 | ^ | vy2 = min(vytmp1, valltmp2.y); + cfc2 $t5, $vcc ## L:157 | 23 | u32<$t5> did_swap_2 = get_vcc(); + vmrg $v03, $v05, $v04 ## L:155 | ^ | vall3 = select(valltmp2, valltmp1); + vmrg $v02, $v04, $v05 ## L:156 | 24 | vall2 = select(valltmp1, valltmp2); + bne $t4, $zero, RDPQ_Triangle_Clip ## L:167 | ^ | if(clipCodes != 0)goto RDPQ_Triangle_Clip; + srl $t2, $t3, 13 ## L:152 | 25 | u32<$t2> tileIdx = clip1 >> 13; + xor $t0, $t0, $t1 ## L:170 | 26 | did_swap_0 ^= did_swap_1; + vmov $v23.e0, $v01.e0 ## L:188 | ^ | vx12F.x = vall1.x; + mfc2 $a2, $v03.e3 ## L:184 | 27 | vtx3 = vall3.w; + mfc2 $a0, $v01.e3 ## L:182 | 28 | vtx1 = vall1.w; + vsubc $v05, $v02, $v01.v ## L:178 | ^ | vec16<$v05> vm = vall2 - vall1; + vsubc $v24, $v03, $v01.v ## L:176 | 29 | vec16<$v24> vhml = vall3 - vall1; + xor $t0, $t0, $t5 ## L:171 | ^ | did_swap_0 ^= did_swap_2; + andi $t0, $t0, 1 ## L:194 | 30 | did_swap_0 &= 1; + vmudn $v26, $v06, $v31.e1 ## L:203 | ^ | vec16<$v26> vfyF = vy1 << 14; + mfc2 $a1, $v02.e3 ## L:183 | 31 | vtx2 = vall2.w; + xor $t1, $v0, $t0 ## L:195 | 32 | u32<$t1> cullFlip = cull ^ did_swap_0; + vsubc $v29, $v00, $v05.e1 ## L:200 | ^ | VTEMP = VZERO - vm.y; + vsubc $v04, $v03, $v02.v ## L:179 | 33 | vec16<$v04> vl = vall3 - vall2; + lsv $v08, 0, 30, $a0 ## L:242 | ^ | vwF.x = load(vtx1, 0x1E).x; + vsubc $v26, $v00, $v26.v ## L:237 | 34 | vfyF = VZERO - vfyF; + ssv $v03, 2, 2, $s3 ## L:192 | ^ | @Barrier("tri-out") store(vall3.y, outPtr, 2); ## Barrier: 0x1 + vmudh $v19, $v05, $v24.e1 ## L:214 | 35 | vnzF = vm:sint * vhml:sint.y; + xori $s7, $s7, 176 ## L:205 | ^ | buffOffset ^= 176; + vmadh $v19, $v24, $v29.v ## L:215 | 36 | vnzF = vhml:sint +* VTEMP:sint; + ssv $v07, 0, 4, $s3 ## L:207 | ^ | @Barrier("tri-out") store(vy2.x, outPtr, 4); ## Barrier: 0x1 + vsar $v18, COP2_ACC_HI ## L:216 | 37 | vnzI = get_acc_high(); + slv $v05, 0, 8, $s3 ## L:225 | ^ | @Barrier("tri-oA", before) @Barrier("tri-out") store(vm.xy, outPtr, 8); ## Barrier: 0x1 + addiu $t4, $s3, 32 ## L:231 | 38 | u32<$t4> color_dmem = outPtr + 0x20; + vsar $v19, COP2_ACC_MD ## L:217 | ^ | vnzF = get_acc_mid(); + vmov $v23.e2, $v02.e0 ## L:189 | 39 | vx12F.z = vall2.x; + slv $v04, 0, 12, $s3 ## L:226 | ^ | @Barrier("tri-oA", before) @Barrier("tri-out") store(vl.xy, outPtr, 12); ## Barrier: 0x1 + ldv $v24, 4, 8, $s3 ## L:227 | 40 | @Barrier("tri-oA", after) @Barrier("tri-oA2", before) vhml.z = load(outPtr, 8).xyzw; + vsub $v25, $v26, $v26.v ## L:238 | ^ | vfyI:sint = vfyF - vfyF; + vrcph $v20.e7, $v18.e0 ## L:259 | 41 | vslope.W = invert_half(vnz).x; + mfc2 $t0, $v18.e0 ## L:247 | ^ | s32<$t0> nzSign = vnzI.x; + vrcpl $v21.e7, $v19.e0 ## L:259 | 42 | vslope.W = invert_half(vnz).x; + lsv $v08, 4, 30, $a1 ## L:243 | ^ | vwF.z = load(vtx2, 0x1E).x; + lsv $v08, 8, 30, $a2 ## L:244 | 43 | vwF.X = load(vtx3, 0x1E).x; + vrcph $v20.e7, $v00.e0 ## L:259 | ^ | vslope.W = invert_half(vnz).x; + vrcp $v21.e0, $v24.e1 ## L:263 | 44 | vslope.x = invert_half(vhml).y; + TAG_CullFlipA: slt $t0, $t0, $zero ## L:264 | ^ | @Tag("CullFlipA") asm_op("slt", nzSign, nzSign, ZERO); + beq $t0, $t1, JrRa ## L:265 | 45 | if(nzSign == cullFlip)goto JrRa; + vrcph $v20.e0, $v24.e1 ## L:263 | 46 | vslope.x = invert_half(vhml).y; + vrcp $v21.e2, $v05.e1 ## L:280 | 47 | vslope.z = invert_half(vm).y; + TAG_CullFlipB: xori $t0, $t0, 1 ## L:293 | ^ | @Tag("CullFlipB") nzSign ^= 1; + lsv $v07, 8, 22, $a2 ## L:286 | 48 | vwI.X = load(vtx3, 0x16).x; + vmov $v28.e7, $v18.e0 ## L:277 | ^ | vhmlupp.W = vnzI.x; + vmov $v24.e7, $v19.e0 ## L:276 | 49 | vhml.W = vnzF.x; + lsv $v07, 0, 22, $a0 ## L:284 | ^ | vwI.x = load(vtx1, 0x16).x; + lsv $v07, 4, 22, $a1 ## L:285 | 50 | vwI.z = load(vtx2, 0x16).x; + vrcph $v20.e2, $v05.e1 ## L:280 | ^ | vslope.z = invert_half(vm).y; + vrcp $v21.e4, $v04.e1 ## L:282 | 51 | vslope.X = invert_half(vl).y; + luv $v09, 0, 8, $a0 ## L:297 | ^ | vec16<$v09> vattr1 = load_vec_u8(vtx1, 0x08); + vrcph $v20.e4, $v04.e1 ## L:282 | 52 | vslope.X = invert_half(vl).y; + lsv $v15, 10, 34, $a1 ## L:326 | ^ | vinvwF.Y = load(vtx2, 0x22).x; + vsubc $v29, $v08, $v08.e2 ## L:306 | 53 | VTEMP = vwF - vwF.z; + llv $v04, 8, 12, $a0 ## L:401 | ^ | vtex1.XY = load(vtx1, 0x0C).xy; + vlt $v07, $v07, $v07.e2 ## L:307 | 54 | vwI = min(vwI, vwI.z); + sll $t0, $t0, 7 ## L:294 | ^ | nzSign <<= 7; + lsv $v15, 12, 34, $a2 ## L:314 | 55 | vinvwF.Z = load(vtx3, 0x22).x; + vmrg $v08, $v08, $v08.e2 ## L:309 | ^ | vwF = select(vwF, vwF.z); + lsv $v15, 8, 34, $a0 ## L:325 | 56 | vinvwF.X = load(vtx1, 0x22).x; + vmudl $v03, $v21, $v24.q1 ## L:323 | ^ | asm_op("vmudl", vtmpF, vslopeF, vhml.yywwYYWW); + or $a3, $a3, $t0 ## L:308 | 57 | triCmd |= nzSign; + vmadm $v03, $v20, $v24.q1 ## L:324 | ^ | asm_op("vmadm", vtmpF, vslopeI, vhml.yywwYYWW); + andi $t5, $a3, 1024 ## L:329 | 58 | u32<$t5> tex_dmem = triCmd & 0x400; + vmadn $v03, $v21, $v28.v ## L:332 | ^ | vtmpF = vslopeF:ufract +* vhmlupp:sint; + vmudl $v09, $v09, $v31.e6 ## L:424 | 59 | vattr1 >>>= 7; + mfc2 $t0, $v24.e3 ## L:335 | ^ | u32<$t0> negMY = vhml.w; + lsv $v14, 8, 32, $a0 ## L:353 | 60 | vinvwI.X = load(vtx1, 0x20).x; + vmudn $v21, $v21, $v30.e5 ## L:342 | ^ | vslopeF = vslopeF:ufract * VSHIFT:sint.Y; + vmadh $v20, $v20, $v30.e5 ## L:343 | 61 | vslopeI = vslopeI:sint +* VSHIFT:sint.Y; + lsv $v14, 12, 32, $a2 ## L:352 | ^ | vinvwI.Z = load(vtx3, 0x20).x; + vsubc $v03, $v00, $v03.v ## L:339 | 62 | vtmpF = VZERO - vtmpF; + lsv $v14, 10, 32, $a1 ## L:351 | ^ | vinvwI.Y = load(vtx2, 0x20).x; + subu $t0, $zero, $t0 ## L:417 | 63 | negMY = ZERO - negMY; + vsubc $v29, $v08, $v08.e4 ## L:347 | ^ | VTEMP = vwF - vwF.X; + vlt $v07, $v07, $v07.e4 ## L:348 | 64 | vwI = min(vwI, vwI.X); + andi $t6, $a3, 512 ## L:363 | ^ | u32<$t6> z_dmem = triCmd & 0x200; + vmrg $v08, $v08, $v08.e4 ## L:349 | 65 | vwF = select(vwF, vwF.X); + lsv $v09, 14, 4, $a0 ## L:429 | ^ | vattr1.W = load(vtx1, 0x04).x; + mfc2 $t1, $v24.e0 ## L:336 | 66 | u32<$t1> negHX = vhml.x; + vmudl $v29, $v21, $v03 ## L:358 | ^ | asm_op("vmudl", VTEMP, vslopeF, vtmpF); + vmadm $v18, $v20, $v03.v ## L:359 | 67 | vnzI = vslopeI:sint +* vtmpF:ufract; + srl $t5, $t5, 4 ## L:330 | ^ | tex_dmem >>= 4; + llv $v03, 8, 12, $a1 ## L:402 | 68 | vtex2.XY = load(vtx2, 0x0C).xy; + vsar $v19, COP2_ACC_LO ## L:360 | ^ | vnzF = get_acc_low(); + vmudl $v29, $v15, $v08.e0 ## L:388 | 69 | asm_op("vmudl", VTEMP, vinvwF, vwF.x); + luv $v10, 0, 8, $a1 ## L:298 | ^ | vec16<$v10> vattr2 = load_vec_u8(vtx2, 0x08); + vmadm $v29, $v14, $v08.e0 ## L:389 | 70 | asm_op("vmadm", VTEMP, vinvwI, vwF.x); + llv $v06, 8, 12, $a2 ## L:403 | ^ | vtex3.XY = load(vtx3, 0x0C).xy; + subu $t1, $zero, $t1 ## L:418 | 71 | negHX = ZERO - negHX; + vmadn $v15, $v15, $v07.e0 ## L:390 | ^ | vinvwF = vinvwF:ufract +* vwI:sint.x; + luv $v11, 0, 8, $a2 ## L:296 | 72 | vec16<$v11> vattr3 = load_vec_u8(vtx3, 0x08); + vmudn $v29, $v19, $v24.v ## L:411 | ^ | VTEMP = vnzF:ufract * vhml:sint; + vmadh $v29, $v18, $v24.v ## L:412 | 73 | VTEMP = vnzI:sint +* vhml:sint; + mtc2 $t0, $v24.e3 ## L:419 | ^ | vhml.w = negMY; + vsar $v20, COP2_ACC_HI ## L:414 | 74 | vslopeI = get_acc_high(); + or $a3, $a3, $t2 ## L:370 | ^ | triCmd |= tileIdx; + lbu $t0, %lo(RDPQ_SYNCFULL_ONGOING + 0) ## L:471 | 75 | u8<$t0> syncFull = load(RDPQ_SYNCFULL_ONGOING); + vsar $v21, COP2_ACC_MD ## L:413 | ^ | vslopeF = get_acc_mid(); + vsubc $v15, $v15, $v30.e7 ## L:392 | 76 | vinvwF:ufract -= 1; + mtc2 $t1, $v24.e0 ## L:420 | ^ | vhml.x = negHX; + vmudl $v11, $v11, $v31.e6 ## L:426 | 77 | vattr3 >>>= 7; + andi $t3, $a3, 256 ## L:450 | ^ | u32<$t3> prim_size = triCmd & 0x100; + vmudl $v10, $v10, $v31.e6 ## L:425 | 78 | vattr2 >>>= 7; + lsv $v11, 14, 4, $a2 ## L:431 | ^ | vattr3.W = load(vtx3, 0x04).x; + vmudm $v22, $v23, $v31.e1 ## L:468 | 79 | vec16<$v22> vx12I = vx12F >> 2; + lsv $v10, 14, 4, $a1 ## L:430 | ^ | vattr2.W = load(vtx2, 0x04).x; + vmudm $v15, $v15, $v31.e0 ## L:393 | 80 | vinvwF >>= 1; + addiu $at, $zero, 207 ## L:438 | ^ | set_vcc(0xCF); + vmudn $v23, $v23, $v31.e1 ## L:469 | 81 | vx12F <<= 14; + addu $t5, $t5, $t4 ## L:365 | ^ | tex_dmem += color_dmem; + vge $v09, $v09, $v00.e0 ## L:433 | 82 | vattr1 = vattr1 >= 0; + sh $a3, 0($s3) ## L:372 | ^ | @Barrier("tri-out") store(triCmd:u16, outPtr, 0); ## Barrier: 0x1 + srl $t6, $t6, 3 ## L:364 | 83 | z_dmem >>= 3; + vge $v10, $v10, $v00.e0 ## L:434 | ^ | vattr2 = vattr2 >= 0; + sdv $v15, 8, 16, $s3 ## L:455 | 84 | @Barrier("tri-oB", before) @Barrier("tri-out") store(vinvwF.XYZW, outPtr, 16); ## Barrier: 0x1 + vge $v11, $v11, $v00.e0 ## L:435 | ^ | vattr3 = vattr3 >= 0; + mfc0 $t1, COP0_DMA_BUSY ## L:452 | 85 | u32<$t1> dmaBusy = get_dma_busy(); + vmudl $v16, $v21, $v26.e4 ## L:448 | ^ | vec32<$v16> vedges = vslope * vfy.X; + vmadm $v16, $v20, $v26.e4 ## L:448 | 86 | vec32<$v16> vedges = vslope * vfy.X; + ctc2 $at, $vcc ## L:438 | ^ | set_vcc(0xCF); + vmadn $v17, $v21, $v25.e4 ## L:448 | 87 | vec32<$v16> vedges = vslope * vfy.X; + lsv $v09, 12, 16, $s3 ## L:456 | ^ | @Barrier("tri-oB", after) @Barrier("tri-oB2", before) vattr1.Z = load(outPtr, 16).x; + lsv $v11, 12, 20, $s3 ## L:458 | 88 | @Barrier("tri-oB", after) @Barrier("tri-oB2", before) vattr3.Z = load(outPtr, 20).x; + vmadh $v16, $v20, $v25.e4 ## L:448 | ^ | vec32<$v16> vedges = vslope * vfy.X; + vmulf $v04, $v04, $v15.h0 ## L:461 | 89 | vtex1:sfract *= vinvwF.xxxxXXXX; + lsv $v10, 12, 18, $s3 ## L:457 | ^ | @Barrier("tri-oB", after) @Barrier("tri-oB2", before) vattr2.Z = load(outPtr, 18).x; + vmulf $v03, $v03, $v15.h1 ## L:462 | 90 | vtex2:sfract *= vinvwF.yyyyYYYY; + bne $t1, $zero, LABEL_RDPQ_Triangle_Send_Async_0006## L:473 | ^ | @Unlikely if(dmaBusy != 0) + vmulf $v06, $v06, $v15.h2 ## L:463 | 91 | vtex3:sfract *= vinvwF.zzzzZZZZ; LABEL_RDPQ_Triangle_Send_Async_0005: - vmrg $v11, $v11, $v06 ## L:502 | 92 | vattr3 = select(vattr3, vtex3); - ssv $v20, 8, 12, $s3 ## L:508 | ^ | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vslope:sint.X, outPtr, 12); ## Barrier: 0x1 - lw $a0, %lo(RDPQ_CURRENT + 0) ## L:513 | 93 | u32<$a0> rdramCur = load(RDPQ_CURRENT); - vmrg $v09, $v09, $v04 ## L:500 | ^ | vattr1 = select(vattr1, vtex1); - vmrg $v10, $v10, $v03 ## L:501 | 94 | vattr2 = select(vattr2, vtex2); - addu $t6, $t6, $t5 ## L:495 | ^ | z_dmem += tex_dmem; - vaddc $v17, $v17, $v23.e0 ## L:518 | 95 | vedges += vx12.x; - srl $t3, $t3, 4 ## L:496 | ^ | prim_size >>= 4; - vadd $v16, $v16, $v22.e0 ## L:518 | 96 | vedges += vx12.x; - ssv $v22, 4, 8, $s3 ## L:509 | ^ | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vx12I.z, outPtr, 8); ## Barrier: 0x1 - bne $t0, $zero, LABEL_RDPQ_Triangle_Send_Async_0008## L:526 | 97 | if(syncFull == 0) { - ssv $v21, 8, 14, $s3 ## L:510 | 98 | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vslope:ufract.X, outPtr, 14); ## Barrier: 0x1 - mtc0 $a0, COP0_DP_END ## L:527 | 99 | set_rdp_end(rdramCur); + ssv $v20, 8, 12, $s3 ## L:502 | 92 | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vslope:sint.X, outPtr, 12); ## Barrier: 0x1 + ssv $v22, 4, 8, $s3 ## L:503 | 93 | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vx12I.z, outPtr, 8); ## Barrier: 0x1 + vmrg $v09, $v09, $v04 ## L:494 | ^ | vattr1 = select(vattr1, vtex1); + srl $t3, $t3, 4 ## L:490 | 94 | prim_size >>= 4; + vmrg $v10, $v10, $v03 ## L:495 | ^ | vattr2 = select(vattr2, vtex2); + lw $a0, %lo(RDPQ_CURRENT + 0) ## L:507 | 95 | u32<$a0> rdramCur = load(RDPQ_CURRENT); + vmrg $v11, $v11, $v06 ## L:496 | ^ | vattr3 = select(vattr3, vtex3); + ssv $v21, 8, 14, $s3 ## L:504 | 96 | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vslope:ufract.X, outPtr, 14); ## Barrier: 0x1 + vaddc $v17, $v17, $v23.e0 ## L:512 | ^ | vedges += vx12.x; + vadd $v16, $v16, $v22.e0 ## L:512 | 97 | vedges += vx12.x; + bne $t0, $zero, LABEL_RDPQ_Triangle_Send_Async_0008## L:520 | ^ | if(syncFull == 0) { + addu $t6, $t6, $t5 ## L:489 | 98 | z_dmem += tex_dmem; + mtc0 $a0, COP0_DP_END ## L:521 | 99 | set_rdp_end(rdramCur); LABEL_RDPQ_Triangle_Send_Async_0008: - vsubc $v29, $v00, $v00 ## L:539 | ^ | clear_vcc(); - ssv $v23, 4, 10, $s3 ## L:535 | 100 | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vx12F.z, outPtr, 10); ## Barrier: 0x1 - vsub $v12, $v10, $v09.v ## L:549 | ^ | vec16<$v12> vma:sint = vattr2 - vattr1; - vsub $v13, $v11, $v09.v ## L:550 | 101 | vec16<$v13> vha:sint = vattr3 - vattr1; - addu $t3, $t3, $t6 ## L:603 | ^ | prim_size += z_dmem; - ssv $v20, 4, 28, $s3 ## L:571 | 102 | @Barrier("tri-out") store(vslope:sint.z, outPtr, 28); ## Barrier: 0x1 - vmudn $v19, $v19, $v30.e5 ## L:557 | ^ | vnz = vnz * 4; - ssv $v21, 4, 30, $s3 ## L:572 | 103 | @Barrier("tri-out") store(vslope:ufract.z, outPtr, 30); ## Barrier: 0x1 - vmadh $v18, $v18, $v30.e5 ## L:557 | ^ | vnz = vnz * 4; - vmudh $v29, $v12, $v24.e1 ## L:564 | 104 | VTEMP = vma:sint * vhml:sint.y; - sh $s7, %lo(RDPQ_TRI_BUFF_OFFSET)($zero) ## L:608 | ^ | store(buffOffset, RDPQ_TRI_BUFF_OFFSET); - vmadh $v29, $v13, $v24.e3 ## L:565 | 105 | VTEMP = vha:sint +* vhml:sint.w; - ssv $v16, 4, 24, $s3 ## L:574 | ^ | @Barrier("tri-out") store(vedges:sint.z, outPtr, 24); ## Barrier: 0x1 - vsar $v03, COP2_ACC_HI ## L:567 | 106 | vdxI = get_acc_high(); - ssv $v17, 4, 26, $s3 ## L:575 | ^ | @Barrier("tri-out") store(vedges:ufract.z, outPtr, 26); ## Barrier: 0x1 - vsar $v04, COP2_ACC_MD ## L:566 | 107 | vdxF = get_acc_mid(); - ssv $v16, 0, 16, $s3 ## L:576 | ^ | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vedges:sint.x, outPtr, 16); ## Barrier: 0x1 - ssv $v17, 0, 18, $s3 ## L:577 | 108 | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vedges:ufract.x, outPtr, 18); ## Barrier: 0x1 - vmudh $v29, $v13, $v24.e2 ## L:583 | ^ | VTEMP = vha:sint * vhml:sint.z; - vmadh $v29, $v12, $v24.e0 ## L:584 | 109 | VTEMP = vma:sint +* vhml:sint.x; - ssv $v20, 0, 20, $s3 ## L:591 | ^ | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vslope:sint.x, outPtr, 20); ## Barrier: 0x1 - lw $a2, %lo(RDPQ_SENTINEL + 0) ## L:559 | 110 | u32<$a2> rdramSentinel = load(RDPQ_SENTINEL); - vsar $v08, COP2_ACC_MD ## L:585 | ^ | vdyF = get_acc_mid(); - vsar $v07, COP2_ACC_HI ## L:586 | 111 | vdyI = get_acc_high(); - ssv $v21, 0, 22, $s3 ## L:592 | ^ | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vslope:ufract.x, outPtr, 22); ## Barrier: 0x1 - vmudl $v29, $v04, $v19.e7 ## L:597 | 112 | vdx *= vnz.W; - subu $t3, $t3, $s3 ## L:604 | ^ | prim_size -= outPtr; - vmadm $v29, $v03, $v19.e7 ## L:597 | 113 | vdx *= vnz.W; - mtc0 $s3, COP0_DMA_SPADDR ## L:594 | ^ | @Barrier("tri-out") set_dma_addr_rsp(outPtr); ## Barrier: 0x1 - mtc0 $a0, COP0_DMA_RAMADDR ## L:606 | 114 | @Barrier("tri-out") set_dma_addr_rdram(rdramCur); ## Barrier: 0x1 - vmadn $v04, $v04, $v18.e7 ## L:597 | ^ | vdx *= vnz.W; - addu $a0, $a0, $t3 ## L:612 | 115 | rdramCur += prim_size; - vmadh $v03, $v03, $v18.e7 ## L:597 | ^ | vdx *= vnz.W; - vmudl $v29, $v08, $v19.e7 ## L:599 | 116 | vdy *= vnz.W; - sltu $at, $a2, $a0 ## L:634 | ^ | @Unlikely if(rdramSentinel < rdramCur) - vmadm $v29, $v07, $v19.e7 ## L:599 | 117 | vdy *= vnz.W; - addu $s3, $s3, $t3 ## L:605 | ^ | outPtr += prim_size; - sdv $v04, 0, 24, $t4 ## L:615 | 118 | @Barrier("tri-out") store(vdx:ufract.xyzw, color_dmem, 0x18); ## Barrier: 0x1 - vmadn $v08, $v08, $v18.e7 ## L:599 | ^ | vdy *= vnz.W; - vmadh $v07, $v07, $v18.e7 ## L:599 | 119 | vdy *= vnz.W; - sdv $v04, 8, 24, $t5 ## L:616 | ^ | @Barrier("tri-out") store(vdx:ufract.XYZW, tex_dmem, 0x18); ## Barrier: 0x1 - vmadl $v29, $v04, $v21.e0 ## L:621 | 120 | vec32<$v05> vde = vdx +* vslope.x; - sdv $v03, 0, 8, $t4 ## L:617 | ^ | @Barrier("tri-out") store(vdx:sint.xyzw, color_dmem, 0x08); ## Barrier: 0x1 - vmadm $v29, $v03, $v21.e0 ## L:621 | 121 | vec32<$v05> vde = vdx +* vslope.x; - sdv $v03, 8, 8, $t5 ## L:618 | ^ | @Barrier("tri-out") store(vdx:sint.XYZW, tex_dmem, 0x08); ## Barrier: 0x1 - vmadn $v06, $v04, $v20.e0 ## L:621 | 122 | vec32<$v05> vde = vdx +* vslope.x; - sdv $v08, 0, 56, $t4 ## L:625 | ^ | @Barrier("tri-out") store(vdy:ufract.xyzw, color_dmem, 0x38); ## Barrier: 0x1 - vmadh $v05, $v03, $v20.e0 ## L:621 | 123 | vec32<$v05> vde = vdx +* vslope.x; - bne $at, $zero, LABEL_RDPQ_Triangle_Send_Async_0009## L:634 | ^ | @Unlikely if(rdramSentinel < rdramCur) - sdv $v08, 8, 56, $t5 ## L:628 | 124 | @Barrier("tri-out") store(vdy:ufract.XYZW, tex_dmem, 0x38); ## Barrier: 0x1 + vsubc $v29, $v00, $v00 ## L:533 | ^ | clear_vcc(); + vsub $v12, $v10, $v09.v ## L:543 | 100 | vec16<$v12> vma:sint = vattr2 - vattr1; + ssv $v23, 4, 10, $s3 ## L:529 | ^ | @Barrier("tri-oA2", after) @Barrier("tri-out") store(vx12F.z, outPtr, 10); ## Barrier: 0x1 + addu $t3, $t3, $t6 ## L:597 | 101 | prim_size += z_dmem; + vsub $v13, $v11, $v09.v ## L:544 | ^ | vec16<$v13> vha:sint = vattr3 - vattr1; + vmudn $v19, $v19, $v30.e5 ## L:551 | 102 | vnz = vnz * 4; + ssv $v20, 4, 28, $s3 ## L:565 | ^ | @Barrier("tri-out") store(vslope:sint.z, outPtr, 28); ## Barrier: 0x1 + ssv $v21, 4, 30, $s3 ## L:566 | 103 | @Barrier("tri-out") store(vslope:ufract.z, outPtr, 30); ## Barrier: 0x1 + vmadh $v18, $v18, $v30.e5 ## L:551 | ^ | vnz = vnz * 4; + ssv $v16, 4, 24, $s3 ## L:568 | 104 | @Barrier("tri-out") store(vedges:sint.z, outPtr, 24); ## Barrier: 0x1 + vmudh $v29, $v12, $v24.e1 ## L:558 | ^ | VTEMP = vma:sint * vhml:sint.y; + vmadh $v29, $v13, $v24.e3 ## L:559 | 105 | VTEMP = vha:sint +* vhml:sint.w; + ssv $v17, 4, 26, $s3 ## L:569 | ^ | @Barrier("tri-out") store(vedges:ufract.z, outPtr, 26); ## Barrier: 0x1 + ssv $v16, 0, 16, $s3 ## L:570 | 106 | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vedges:sint.x, outPtr, 16); ## Barrier: 0x1 + vsar $v03, COP2_ACC_HI ## L:561 | ^ | vdxI = get_acc_high(); + ssv $v17, 0, 18, $s3 ## L:571 | 107 | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vedges:ufract.x, outPtr, 18); ## Barrier: 0x1 + vsar $v04, COP2_ACC_MD ## L:560 | ^ | vdxF = get_acc_mid(); + lw $a2, %lo(RDPQ_SENTINEL + 0) ## L:553 | 108 | u32<$a2> rdramSentinel = load(RDPQ_SENTINEL); + vmudh $v29, $v13, $v24.e2 ## L:577 | ^ | VTEMP = vha:sint * vhml:sint.z; + ssv $v20, 0, 20, $s3 ## L:585 | 109 | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vslope:sint.x, outPtr, 20); ## Barrier: 0x1 + vmadh $v29, $v12, $v24.e0 ## L:578 | ^ | VTEMP = vma:sint +* vhml:sint.x; + subu $t3, $t3, $s3 ## L:598 | 110 | prim_size -= outPtr; + vsar $v08, COP2_ACC_MD ## L:579 | ^ | vdyF = get_acc_mid(); + ssv $v21, 0, 22, $s3 ## L:586 | 111 | @Barrier("tri-oB2", after) @Barrier("tri-out") store(vslope:ufract.x, outPtr, 22); ## Barrier: 0x1 + vsar $v07, COP2_ACC_HI ## L:580 | ^ | vdyI = get_acc_high(); + vmudl $v29, $v04, $v19.e7 ## L:591 | 112 | vdx *= vnz.W; + mtc0 $s3, COP0_DMA_SPADDR ## L:588 | ^ | @Barrier("tri-out") set_dma_addr_rsp(outPtr); ## Barrier: 0x1 + vmadm $v29, $v03, $v19.e7 ## L:591 | 113 | vdx *= vnz.W; + mtc0 $a0, COP0_DMA_RAMADDR ## L:600 | ^ | @Barrier("tri-out") set_dma_addr_rdram(rdramCur); ## Barrier: 0x1 + vmadn $v04, $v04, $v18.e7 ## L:591 | 114 | vdx *= vnz.W; + addu $a0, $a0, $t3 ## L:606 | ^ | rdramCur += prim_size; + addu $s3, $s3, $t3 ## L:599 | 115 | outPtr += prim_size; + vmadh $v03, $v03, $v18.e7 ## L:591 | ^ | vdx *= vnz.W; + sh $s7, %lo(RDPQ_TRI_BUFF_OFFSET)($zero) ## L:602 | 116 | store(buffOffset, RDPQ_TRI_BUFF_OFFSET); + vmudl $v29, $v08, $v19.e7 ## L:593 | ^ | vdy *= vnz.W; + vmadm $v29, $v07, $v19.e7 ## L:593 | 117 | vdy *= vnz.W; + sltu $at, $a2, $a0 ## L:628 | ^ | @Unlikely if(rdramSentinel < rdramCur) + vmadn $v08, $v08, $v18.e7 ## L:593 | 118 | vdy *= vnz.W; + sdv $v04, 0, 24, $t4 ## L:609 | ^ | @Barrier("tri-out") store(vdx:ufract.xyzw, color_dmem, 0x18); ## Barrier: 0x1 + vmadh $v07, $v07, $v18.e7 ## L:593 | 119 | vdy *= vnz.W; + sdv $v04, 8, 24, $t5 ## L:610 | ^ | @Barrier("tri-out") store(vdx:ufract.XYZW, tex_dmem, 0x18); ## Barrier: 0x1 + vmadl $v05, $v04, $v21.e0 ## L:615 | 120 | vec32<$v05> vde = vdx +* vslope.x; + sdv $v03, 0, 8, $t4 ## L:611 | ^ | @Barrier("tri-out") store(vdx:sint.xyzw, color_dmem, 0x08); ## Barrier: 0x1 + sdv $v03, 8, 8, $t5 ## L:612 | 121 | @Barrier("tri-out") store(vdx:sint.XYZW, tex_dmem, 0x08); ## Barrier: 0x1 + vmadm $v05, $v03, $v21.e0 ## L:615 | ^ | vec32<$v05> vde = vdx +* vslope.x; + vmadn $v06, $v04, $v20.e0 ## L:615 | 122 | vec32<$v05> vde = vdx +* vslope.x; + sdv $v08, 0, 56, $t4 ## L:619 | ^ | @Barrier("tri-out") store(vdy:ufract.xyzw, color_dmem, 0x38); ## Barrier: 0x1 + vmadh $v05, $v03, $v20.e0 ## L:615 | 123 | vec32<$v05> vde = vdx +* vslope.x; + bne $at, $zero, LABEL_RDPQ_Triangle_Send_Async_0009## L:628 | ^ | @Unlikely if(rdramSentinel < rdramCur) + sdv $v08, 8, 56, $t5 ## L:622 | 124 | @Barrier("tri-out") store(vdy:ufract.XYZW, tex_dmem, 0x38); ## Barrier: 0x1 LABEL_RDPQ_Triangle_Send_Async_000A: - vmudh $v29, $v09, $v30.e7 ## L:665 | 125 | VTEMP = vattr1:sint * 1; - sdv $v07, 0, 40, $t4 ## L:669 | ^ | @Barrier("tri-out") store(vdy:sint.xyzw, color_dmem, 0x28); ## Barrier: 0x1 - sdv $v07, 8, 40, $t5 ## L:670 | 126 | @Barrier("tri-out") store(vdy:sint.XYZW, tex_dmem, 0x28); ## Barrier: 0x1 - vmadl $v29, $v06, $v26.e4 ## L:666 | ^ | vec32<$v01> vfinal = vde +* vfy.X; - vmadm $v29, $v05, $v26.e4 ## L:666 | 127 | vec32<$v01> vfinal = vde +* vfy.X; - sdv $v06, 0, 48, $t4 ## L:672 | ^ | @Barrier("tri-out") store(vde:ufract.xyzw, color_dmem, 0x30); ## Barrier: 0x1 - vmadn $v02, $v06, $v25.e4 ## L:666 | 128 | vec32<$v01> vfinal = vde +* vfy.X; - sdv $v06, 8, 48, $t5 ## L:673 | ^ | @Barrier("tri-out") store(vde:ufract.XYZW, tex_dmem, 0x30); ## Barrier: 0x1 - sdv $v05, 0, 32, $t4 ## L:674 | 129 | @Barrier("tri-out") store(vde:sint.xyzw, color_dmem, 0x20); ## Barrier: 0x1 - vmadh $v01, $v05, $v25.e4 ## L:666 | ^ | vec32<$v01> vfinal = vde +* vfy.X; - sw $a0, %lo(RDPQ_CURRENT)($zero) ## L:678 | 130 | store(rdramCur, RDPQ_CURRENT); - vmov $v10.e3, $v04.e7 ## L:702 | ^ | vzout.w = vdxF.W; - vmov $v06.e6, $v05.e7 ## L:699 | 131 | vdeF.Z = vdeI.W; - sdv $v05, 8, 32, $t5 ## L:675 | ^ | @Barrier("tri-out") store(vde:sint.XYZW, tex_dmem, 0x20); ## Barrier: 0x1 - sdv $v02, 0, 16, $t4 ## L:706 | 132 | @Barrier("tri-out") store(vfinalF.xyzw, color_dmem, 0x10); ## Barrier: 0x1 - vmov $v08.e6, $v07.e7 ## L:698 | ^ | vdyF.Z = vdyI.W; - sdv $v02, 8, 16, $t5 ## L:707 | 133 | @Barrier("tri-out") store(vfinalF.XYZW, tex_dmem, 0x10); ## Barrier: 0x1 - vmov $v10.e2, $v03.e7 ## L:703 | ^ | vzout.z = vdxI.W; - sdv $v01, 0, 0, $t4 ## L:708 | 134 | @Barrier("tri-out") store(vfinalI.xyzw, color_dmem, 0x00); ## Barrier: 0x1 - vmov $v10.e1, $v02.e7 ## L:700 | ^ | vzout.y = vfinalF.W; - sdv $v01, 8, 0, $t5 ## L:709 | 135 | @Barrier("tri-out") store(vfinalI.XYZW, tex_dmem, 0x00); ## Barrier: 0x1 - vmov $v10.e0, $v01.e7 ## L:701 | ^ | vzout.x = vfinalI.W; - slv $v06, 12, 8, $t6 ## L:712 | 136 | @Barrier("tri-out") store(vdeF.ZW, z_dmem, 0x08); ## Barrier: 0x1 - slv $v08, 12, 12, $t6 ## L:713 | 137 | @Barrier("tri-out") store(vdyF.ZW, z_dmem, 0x0C); ## Barrier: 0x1 - addiu $t3, $t3, 65535 ## L:714 | 138 | prim_size -= 1; - sdv $v10, 0, 0, $t6 ## L:715 | 139 | @Barrier("tri-out") store(vzout.xyzw, z_dmem, 0x00); ## Barrier: 0x1 - jr $ra ## L:727 | 140 | } - mtc0 $t3, COP0_DMA_WRITE ## L:726 | *142 | @Barrier("tri-out", after) set_dma_write(prim_size); + sdv $v07, 0, 40, $t4 ## L:663 | 125 | @Barrier("tri-out") store(vdy:sint.xyzw, color_dmem, 0x28); ## Barrier: 0x1 + vmudh $v29, $v09, $v30.e7 ## L:659 | ^ | VTEMP = vattr1:sint * 1; + sdv $v07, 8, 40, $t5 ## L:664 | 126 | @Barrier("tri-out") store(vdy:sint.XYZW, tex_dmem, 0x28); ## Barrier: 0x1 + vmadl $v01, $v06, $v26.e4 ## L:660 | ^ | vec32<$v01> vfinal = vde +* vfy.X; + vmadm $v01, $v05, $v26.e4 ## L:660 | 127 | vec32<$v01> vfinal = vde +* vfy.X; + sw $a0, %lo(RDPQ_CURRENT)($zero) ## L:672 | ^ | store(rdramCur, RDPQ_CURRENT); + vmadn $v02, $v06, $v25.e4 ## L:660 | 128 | vec32<$v01> vfinal = vde +* vfy.X; + addiu $t3, $t3, 65535 ## L:708 | ^ | prim_size -= 1; + vmadh $v01, $v05, $v25.e4 ## L:660 | 129 | vec32<$v01> vfinal = vde +* vfy.X; + sdv $v06, 0, 48, $t4 ## L:666 | ^ | @Barrier("tri-out") store(vde:ufract.xyzw, color_dmem, 0x30); ## Barrier: 0x1 + sdv $v06, 8, 48, $t5 ## L:667 | 130 | @Barrier("tri-out") store(vde:ufract.XYZW, tex_dmem, 0x30); ## Barrier: 0x1 + vmov $v10.e3, $v04.e7 ## L:696 | ^ | vzout.w = vdxF.W; + sdv $v05, 0, 32, $t4 ## L:668 | 131 | @Barrier("tri-out") store(vde:sint.xyzw, color_dmem, 0x20); ## Barrier: 0x1 + vmov $v06.e6, $v05.e7 ## L:693 | ^ | vdeF.Z = vdeI.W; + sdv $v05, 8, 32, $t5 ## L:669 | 132 | @Barrier("tri-out") store(vde:sint.XYZW, tex_dmem, 0x20); ## Barrier: 0x1 + vmov $v10.e1, $v02.e7 ## L:694 | ^ | vzout.y = vfinalF.W; + vmov $v10.e2, $v03.e7 ## L:697 | 133 | vzout.z = vdxI.W; + sdv $v02, 0, 16, $t4 ## L:700 | ^ | @Barrier("tri-out") store(vfinalF.xyzw, color_dmem, 0x10); ## Barrier: 0x1 + sdv $v02, 8, 16, $t5 ## L:701 | 134 | @Barrier("tri-out") store(vfinalF.XYZW, tex_dmem, 0x10); ## Barrier: 0x1 + vmov $v08.e6, $v07.e7 ## L:692 | ^ | vdyF.Z = vdyI.W; + sdv $v01, 0, 0, $t4 ## L:702 | 135 | @Barrier("tri-out") store(vfinalI.xyzw, color_dmem, 0x00); ## Barrier: 0x1 + vmov $v10.e0, $v01.e7 ## L:695 | ^ | vzout.x = vfinalI.W; + sdv $v01, 8, 0, $t5 ## L:703 | 136 | @Barrier("tri-out") store(vfinalI.XYZW, tex_dmem, 0x00); ## Barrier: 0x1 + slv $v06, 12, 8, $t6 ## L:706 | 137 | @Barrier("tri-out") store(vdeF.ZW, z_dmem, 0x08); ## Barrier: 0x1 + slv $v08, 12, 12, $t6 ## L:707 | 138 | @Barrier("tri-out") store(vdyF.ZW, z_dmem, 0x0C); ## Barrier: 0x1 + sdv $v10, 0, 0, $t6 ## L:709 | 139 | @Barrier("tri-out") store(vzout.xyzw, z_dmem, 0x00); ## Barrier: 0x1 + jr $ra ## L:721 | 140 | } + mtc0 $t3, COP0_DMA_WRITE ## L:720 | *142 | @Barrier("tri-out", after) set_dma_write(prim_size); LABEL_RDPQ_Triangle_Send_Async_0006: - mfc0 $t1, COP0_DMA_BUSY ## L:487 | 1 | dmaBusy = get_dma_busy(); - bne $t1, $zero, LABEL_RDPQ_Triangle_Send_Async_0006## L:487 | **4 | dmaBusy = get_dma_busy(); - nop ## L:431 | *6 | + mfc0 $t1, COP0_DMA_BUSY ## L:481 | 1 | dmaBusy = get_dma_busy(); + bne $t1, $zero, LABEL_RDPQ_Triangle_Send_Async_0006## L:481 | **4 | dmaBusy = get_dma_busy(); + nop ## L:481 | *6 | dmaBusy = get_dma_busy(); LABEL_RDPQ_Triangle_Send_Async_0007: - j LABEL_RDPQ_Triangle_Send_Async_0005 ## L:487 | 7 | dmaBusy = get_dma_busy(); - nop ## L:431 | *9 | + j LABEL_RDPQ_Triangle_Send_Async_0005 ## L:481 | 7 | dmaBusy = get_dma_busy(); + nop ## L:481 | *9 | dmaBusy = get_dma_busy(); LABEL_RDPQ_Triangle_Send_Async_0009: - lw $a0, %lo(RDPQ_DYNAMIC_BUFFERS + 4) ## L:637 | 10 | rdramCur = load(RDPQ_DYNAMIC_BUFFERS, 4); - or $a3, $zero, $ra ## L:636 | 11 | u32<$a3> savedRA = RA; - lw $t1, %lo(RDPQ_DYNAMIC_BUFFERS + 0) ## L:638 | 12 | u32<$t1> otherBuff = load(RDPQ_DYNAMIC_BUFFERS, 0); - sb $t3, 0($t4) ## L:648 | 13 | @Barrier("cb-stash") store(prim_size:u8, color_dmem, 0x00); ## Barrier: 0x2 - or $a1, $zero, $a0 ## L:651 | 14 | u32<$a1> rdramCurCopy = rdramCur; - lui $at, 0x01 ## L:650 | 15 | rdramSentinel = rdramCur + 65536; - sw $a0, %lo(0 + RDPQ_DYNAMIC_BUFFERS)($zero) ## L:639 | 16 | store(rdramCur, RDPQ_DYNAMIC_BUFFERS, 0); - addu $a2, $a0, $at ## L:650 | 17 | rdramSentinel = rdramCur + 65536; - jal RSPQCmd_RdpSetBuffer ## L:652 | 18 | RSPQCmd_RdpSetBuffer(rdramCur, rdramCurCopy, rdramSentinel); ## Args: $a0, $a1, $a2 - sw $t1, %lo(4 + RDPQ_DYNAMIC_BUFFERS)($zero) ## L:640 | *20 | store(otherBuff, RDPQ_DYNAMIC_BUFFERS, 4); - or $ra, $zero, $a3 ## L:660 | 21 | RA = savedRA; - lbu $t3, 0($t4) ## L:658 | 22 | @Barrier("cb-stash") prim_size:u8 = load(color_dmem, 0x00); ## Barrier: 0x2 - mtc0 $a0, COP0_DMA_RAMADDR ## L:657 | 23 | @Barrier("tri-out") set_dma_addr_rdram(rdramCur); ## Barrier: 0x1 - j LABEL_RDPQ_Triangle_Send_Async_000A ## L:660 | 24 | RA = savedRA; - addu $a0, $a0, $t3 ## L:659 | *26 | rdramCur += prim_size; + lw $a0, %lo(RDPQ_DYNAMIC_BUFFERS + 4) ## L:631 | 10 | rdramCur = load(RDPQ_DYNAMIC_BUFFERS, 4); + sb $t3, 0($t4) ## L:642 | 11 | @Barrier("cb-stash") store(prim_size:u8, color_dmem, 0x00); ## Barrier: 0x2 + lw $t1, %lo(RDPQ_DYNAMIC_BUFFERS + 0) ## L:632 | 12 | u32<$t1> otherBuff = load(RDPQ_DYNAMIC_BUFFERS, 0); + sw $a0, %lo(0 + RDPQ_DYNAMIC_BUFFERS)($zero) ## L:633 | 13 | store(rdramCur, RDPQ_DYNAMIC_BUFFERS, 0); + lui $at, 0x01 ## L:644 | 14 | rdramSentinel = rdramCur + 65536; + sw $t1, %lo(4 + RDPQ_DYNAMIC_BUFFERS)($zero) ## L:634 | 15 | store(otherBuff, RDPQ_DYNAMIC_BUFFERS, 4); + or $a3, $zero, $ra ## L:630 | 16 | u32<$a3> savedRA = RA; + or $a1, $zero, $a0 ## L:645 | 17 | u32<$a1> rdramCurCopy = rdramCur; + jal RSPQCmd_RdpSetBuffer ## L:646 | 18 | RSPQCmd_RdpSetBuffer(rdramCur, rdramCurCopy, rdramSentinel); ## Args: $a0, $a1, $a2 + addu $a2, $a0, $at ## L:644 | *20 | rdramSentinel = rdramCur + 65536; + or $ra, $zero, $a3 ## L:654 | 21 | RA = savedRA; + lbu $t3, 0($t4) ## L:652 | 22 | @Barrier("cb-stash") prim_size:u8 = load(color_dmem, 0x00); ## Barrier: 0x2 + mtc0 $a0, COP0_DMA_RAMADDR ## L:651 | 23 | @Barrier("tri-out") set_dma_addr_rdram(rdramCur); ## Barrier: 0x1 + j LABEL_RDPQ_Triangle_Send_Async_000A ## L:654 | 24 | RA = savedRA; + addu $a0, $a0, $t3 ## L:653 | *26 | rdramCur += prim_size; RDPQ_Triangle_Send_End: ## hot-path cycles: 11 LABEL_RDPQ_Triangle_Send_End_000B: diff --git a/src/t3d/rsp/vertexFX.rspl b/src/t3d/rsp/vertexFX.rspl index 7d725930..a171abf1 100644 --- a/src/t3d/rsp/vertexFX.rspl +++ b/src/t3d/rsp/vertexFX.rspl @@ -4,21 +4,10 @@ macro VertexFX_End() { goto LOOP_START; } -function VertexFX_None( - u32<$s4> prt3d, u32<$s7> ptr3dEnd, vec16<$v03> uv, - u32<$s6> ptrBuffA, u32<$s5> ptrBuffB -) { - store(uv.xy, ptrBuffA, VTX_ATTR_ST); - store(uv.zw, ptrBuffB, VTX_ATTR_ST); - - // to avoid a double-jump, check the loop-end here directly - VertexFX_End(); -} - function VertexFX_Spherical( u32<$s4> prt3d, u32<$s7> ptr3dEnd, vec16<$v04> uvOffsetFactor, vec16<$v05> posClipInt, vec16<$v12> screenOffset, - vec16<$v09> uvGenArgs, vec16<$v02> normal, vec16<$v03> uv, + vec16<$v09> uvGenArgs, vec16<$v11> normal, vec16<$v03> uv, u32<$s6> ptrBuffA, u32<$s5> ptrBuffB ) { @@ -50,11 +39,7 @@ function VertexFX_CelShadeColor( color = max(color, color.zzzzZZZZ); uv.x = color.x; uv.z = color.X; - - store(uv.xy, ptrBuffA, VTX_ATTR_ST); - store(uv.zw, ptrBuffB, VTX_ATTR_ST); - - VertexFX_End(); + goto VertexFX_None; } function VertexFX_CelShadeAlpha( @@ -65,17 +50,14 @@ function VertexFX_CelShadeAlpha( { uv.x = color.w; uv.z = color.W; - - store(uv.xy, ptrBuffA, VTX_ATTR_ST); - store(uv.zw, ptrBuffB, VTX_ATTR_ST); - - VertexFX_End(); + + goto VertexFX_None; } function VertexFX_Outline( u32<$s4> prt3d, u32<$s7> ptr3dEnd, vec16<$v04> uvOffsetFactor, vec16<$v05> posClipInt, vec16<$v12> screenOffset, - vec16<$v09> uvGenArgs, vec16<$v02> normal, vec16<$v03> uv, + vec16<$v09> uvGenArgs, vec16<$v11> normal, vec16<$v03> uv, u32<$s6> ptrBuffA, u32<$s5> ptrBuffB ) { diff --git a/src/t3d/t3d.c b/src/t3d/t3d.c index 689d4067..9ada7e18 100644 --- a/src/t3d/t3d.c +++ b/src/t3d/t3d.c @@ -28,8 +28,10 @@ static_assert(RSP_T3D_CODE_RSPQCmd_RdpAppendBuffer < RSP_T3D_CODE_CLIPPING_CODE_ static_assert(RSP_T3D_CODE_CLIPPING_CODE_TARGET % 8 == 0, "Clipping code must be aligned to 8 bytes!"); static_assert(RSP_T3D_CODE_CLIPPING_CODE_TARGET == RSP_T3D_CODE_CLIP_clipTriangle, "Clipping code and target must have the same address"); +static_assert((RSP_T3D_BSS_CLIP_BUFFER_TMP ^ RSP_T3D_BSS_CLIP_BUFFER_RESULT) == 0x100, "Clip buffers must differ only in bit 8 (CLIP_BUFFER_XOR)"); +static_assert(RSP_T3D_BSS_CLIP_BUFFER_TMP + 2 * 176 <= RSP_T3D_BSS_CLIP_BUFFER_RESULT + 7 * 36 - 4 * 36, "Second RDP slot must not reach a 4-vertex clip polygon"); + // @TODO: this could be handled to allow either alignment, but it is simpler to force this for now -static_assert((RSP_T3D_CODE_TAG_LightMul & 0x0FFF) % 8 == 0, "Light-Mul must be aligned to 8 bytes!"); // the cull-flip patches sit inside the triangle code, which must never be swapped out by the clipping overlay static_assert(RSP_T3D_CODE_TAG_CullFlipA < RSP_T3D_CODE_CLIPPING_CODE_TARGET, "Cull-Flip-A must come before the clipping code!"); @@ -50,7 +52,7 @@ static T3DViewport *currentViewport = NULL; static T3DMat4FP *matrixStack = NULL; static uint32_t clipCodeAddrOrg = 0; // 'CLIP_CODE_ORG_ADDR' in ucode -static uint64_t orgInstrLightMul = 0; // backup of the lighting mul. instruction + the one after +static uint64_t orgInstrLightMul = 0; // backup of the 8-byte pair containing the lighting mul. instruction static uint64_t orgInstrCullFlipA = 0; // backup static uint64_t orgInstrCullFlipB = 0; // backup @@ -68,7 +70,7 @@ void t3d_init(T3DInitParams params) *stackPtr = (uint32_t)UncachedAddr(matrixStack); uint16_t *uvGenFunc = (uint16_t*)((char*)state + ((RSP_T3D_VERTEX_FX_FUNC - RSP_T3D_STATE_MEM_START) & 0xFFFF)); - *uvGenFunc = RSP_T3D_CODE_VertexFX_None & 0xFFF; + *uvGenFunc = RSP_T3D_CODE_LOOP_TRAIL & 0xFFF; clipCodeAddrOrg = (uint32_t)PhysicalAddr(rsp_tiny3d.code + (RSP_T3D_CODE_CLIPPING_CODE_TARGET & 0xFFF)); @@ -80,8 +82,7 @@ void t3d_init(T3DInitParams params) clipAddrPtr[1] = clipCodeAddrOrg; *clipSizePtr = RSP_T3D_CODE_CLIP_OVERLAY_CODE_END - RSP_T3D_CODE_CLIP_clipTriangle + 7; - uint32_t imemAddrMul = (RSP_T3D_CODE_TAG_LightMul & 0x0FFF); - orgInstrLightMul = *(uint64_t*)(rsp_tiny3d.code + imemAddrMul); + orgInstrLightMul = *(uint64_t*)(rsp_tiny3d.code + (RSP_T3D_CODE_TAG_LightMul & 0x0FF8)); orgInstrCullFlipA = *(uint64_t*)(rsp_tiny3d.code + (RSP_T3D_CODE_TAG_CullFlipA & 0x0FF8)); orgInstrCullFlipB = *(uint64_t*)(rsp_tiny3d.code + (RSP_T3D_CODE_TAG_CullFlipB & 0x0FF8)); @@ -185,7 +186,13 @@ void t3d_vert_load(const T3DVertPacked *vertices, uint32_t offset, uint32_t coun // calculate where to start the DMA, this may overlap the buffer of transformed vertices // we have to place it so that racing the input data is possible - uint32_t tmpBufferEnd = (RSP_T3D_BSS_CLIP_BUFFER_RESULT & 0xFFFF) + 6*16; + constexpr uint32_t tmpBufferEnd = ( + ((RSP_T3D_BSS_TEMP_STATE_MEM_END & 0xFFFF) & ~0xF) // align to 16 bytes + - 32 // leave space for temp data usage + ); + + static_assert((RSP_T3D_STATE_MEM_END & 0xFFFF) <= tmpBufferEnd, "Vertex buffer overlaps temporary buffer!"); + uint16_t offsetDest = tmpBufferEnd - inputSize; offsetDest = (offsetDest & ~0xF); // make sure it's aligned to 16 bytes, must be aligned backwards @@ -358,7 +365,7 @@ void t3d_state_set_drawflags(enum T3DDrawFlags drawFlags) } void t3d_state_set_depth_offset(int16_t offset) { - t3d_dmem_set_u16((RSP_T3D_SCREEN_SCALE_OFFSET & 0xFFF) + 12, 0x3FFF + offset); + t3d_dmem_set_u16((RSP_T3D_SCREEN_OFFSET & 0xFFF) + 4, 0x3FFF + offset); } void t3d_state_set_alpha_to_tile(bool enable) { @@ -370,7 +377,7 @@ void t3d_state_set_alpha_to_tile(bool enable) { void t3d_state_set_vertex_fx(enum T3DVertexFX func, int16_t arg0, int16_t arg1) { - uint16_t rspFunc = RSP_T3D_CODE_VertexFX_None & 0xFFF; + uint16_t rspFunc = RSP_T3D_CODE_LOOP_TRAIL & 0xFFF; switch (func) { case T3D_VERTEX_FX_NONE: arg0 = 0; @@ -420,7 +427,7 @@ void t3d_state_set_lighting_mode(enum T3DLightingMode mode) const uint32_t OPCODE_VMULF = 0b000'000; const uint32_t OPCODE_VADD = 0b010'000; const uint32_t OPCODE_VOR = 0b101'010; - uint32_t instruction = (uint32_t)(orgInstrLightMul >> 32); + uint32_t instruction = t3d_imem_org_instr(RSP_T3D_CODE_TAG_LightMul, orgInstrLightMul); instruction &= ~0x3F; switch(mode) { case T3D_LIGHTING_MODE_MUL: @@ -435,18 +442,10 @@ void t3d_state_set_lighting_mode(enum T3DLightingMode mode) break; } - uint64_t newOpcodes = ((uint64_t)instruction << 32) | - (uint32_t)orgInstrLightMul; - uint32_t imemAddrMul = (RSP_T3D_CODE_TAG_LightMul & 0x0FFF); - // Now enqueue a DMA back to RDRAM to patch the ucode, one the next ucode switch this would be used. // Note that we can't patch it CPU side, as the RSP runs in parallel and we would patch too early. // This also handles the case where this is embedded in a block or queue. - t3d_imem_patch( - rsp_tiny3d.code + imemAddrMul, - (uint32_t)(newOpcodes >> 32), - (uint32_t)(newOpcodes & 0xFFFF'FFFF) - ); + t3d_imem_patch_instr(RSP_T3D_CODE_TAG_LightMul, orgInstrLightMul, instruction); } void t3d_state_set_cull_invert(bool invert) @@ -551,31 +550,44 @@ void t3d_tri_draw_strip_and_sync(int16_t* indexBuff, int count) } void t3d_fog_set_range(float near, float far) { - uint32_t dmemAddr = RSP_T3D_FOG_SCALE_OFFSET & 0xFFF; + uint32_t addrScale = RSP_T3D_SCREEN_SCALE & 0xFFF; + uint32_t addrOffset = RSP_T3D_SCREEN_OFFSET & 0xFFF; if(near == 0.0f && far == 0.0f) { - t3d_dmem_set_u32(dmemAddr + 0, 0); // offset - t3d_dmem_set_u16(dmemAddr + 6, 0); // scale + t3d_dmem_set_u16(addrScale + 6, 0); // slope int + t3d_dmem_set_u16(addrScale + 14, 0); // slope fract + t3d_dmem_set_u16(addrOffset + 6, 0x80FF); // offset: alpha 255 everywhere return; } + assertf(currentViewport, "t3d_fog_set_range needs a viewport to be attached!"); - // prevent diff by zero and weird values - float diff = far - near; + const T3DMat4 *proj = ¤tViewport->matProj; + float a = -proj->m[2][2]; + float b = proj->m[3][2]; + float zNear = a * near + b; + float zFar = a * far + b; + + // prevent div by zero and weird values + float diff = zFar - zNear; if(fabsf(diff) < 1.5f) { - diff = 1.5f; + diff = diff < 0 ? -1.5f : 1.5f; + } + // the offset must fit s16: it grows with zNear/(zFar-zNear), so bands that start far away + // and are very thin get widened to the smallest representable width (keeps 'near' in place) + float minDiff = (255.0f * fabsf(zNear) + 127.5f) / 65280.0f; + if(fabsf(diff) < minDiff) { + diff = diff < 0 ? -minDiff : minDiff; } - // @TODO: refactor in the ucode (right now it's offset and then scale) - float scale = 16384.0f / diff; - float offset = -near * 2.0f; - - scale = fm_floorf(scale); - scale = CLAMP(scale, -32768.0f, 32767.0f); - - uint16_t fogMul16 = (int16_t)scale & 0xFFFF; - int32_t fogOffset32 = T3D_F32_TO_FIXED(offset); + float slope = -255.0f / diff; // per clip-z unit + // the ucode multiplies the integer part of the clip-space Z by the slope directly + // (SCREEN_SCALE + 6/14), so there is no half-unit fraction left to compensate for + float offset = -32513.0f + zNear * 255.0f / diff; + offset = CLAMP(offset, -32768.0f, 32767.0f); - t3d_dmem_set_u32(dmemAddr + 0, fogOffset32); // offset - t3d_dmem_set_u16(dmemAddr + 6, fogMul16); // scale + int32_t slopeFx = (int32_t)roundf(slope * 0x10000); + t3d_dmem_set_u16(addrScale + 6, ((uint32_t)slopeFx >> 16) & 0xFFFF); // slope int + t3d_dmem_set_u16(addrScale + 14, (uint32_t)slopeFx & 0xFFFF); // slope fract + t3d_dmem_set_u16(addrOffset + 6, (uint32_t)(int16_t)roundf(offset) & 0xFFFF); } void t3d_viewport_attach(T3DViewport *viewport) { @@ -593,15 +605,28 @@ void t3d_viewport_attach(T3DViewport *viewport) { viewport->offset[1] + viewport->size[1] ); - uint16_t normWScale = (uint16_t)roundf(0xFFFF * currentViewport->_normScaleW); + uint16_t normWScale = (uint16_t)roundf(0xFFFF * fminf(currentViewport->_normScaleW, 1.0f)); float normWScaleFloat = (float)normWScale * (1.0f / 0xFFFF); - float screenShiftFactor = 256.0f; // compensates the shift in the ucode - float screenFactorX = (float)viewport->size[0] * normWScaleFloat * 4.0f * screenShiftFactor; - float screenFactorY = (float)viewport->size[1] * normWScaleFloat * 4.0f * -screenShiftFactor; - - int32_t screenScaleX = (int32_t)ceilf(screenFactorX); - int32_t screenScaleY = (int32_t)ceilf(screenFactorY); + + // clip-space x/y are divided by the guard-band factor in the ucode (NORM_SCALE_W lanes x/y) + // so the clip-code test can use W as its bound, undo it here. + int32_t guardBand = viewport->guardBandScale & 0xF; + if(guardBand < 1)guardBand = 1; + // the screen scale absorbs the factor and its integer part must stay in s16 + int32_t guardMax = 32767 / (4 * (viewport->size[0] > viewport->size[1] ? viewport->size[0] : viewport->size[1])); + if(guardBand > guardMax)guardBand = guardMax < 1 ? 1 : guardMax; + uint16_t invGuard = (guardBand == 1) ? 0xFFFF : (uint16_t)(0x10000 / guardBand); + t3d_dmem_set_u32((RSP_T3D_NORM_SCALE_W & 0xFFF), ((uint32_t)invGuard << 16) | invGuard); + + // halved (2 instead of 4): the ucode's NR-refined 1/W is the full reciprocal, + // twice the raw vrcp half-reciprocal + float guardF = (float)guardBand; + float screenFactorX = (float)viewport->size[0] * normWScaleFloat * 4.0f * guardF; + float screenFactorY = (float)viewport->size[1] * normWScaleFloat * -4.0f * guardF; + + int32_t screenScaleX = (int32_t)roundf(screenFactorX * 0x10000); + int32_t screenScaleY = (int32_t)roundf(screenFactorY * 0x10000); // Set screen size, internally the 3D-scene renders to the correct size, but at [0,0] // calc. both scale and offset to move/scale it into our scissor region @@ -609,19 +634,22 @@ void t3d_viewport_attach(T3DViewport *viewport) { int32_t screenOffsetY = (int32_t)(viewport->offset[1]*2) + viewport->size[1]; int32_t screenOffset = (screenOffsetX << 17) | (screenOffsetY << 1); - int32_t screenScale = (screenScaleX << 16) | ((uint16_t)(screenScaleY) & 0xFFFF); + int32_t screenScale = (screenScaleX & 0xFFFF0000) | (((uint32_t)screenScaleY >> 16) & 0xFFFF); // int parts + uint32_t screenScaleFrac = ((uint32_t)(screenScaleX & 0xFFFF) << 16) | (uint32_t)(screenScaleY & 0xFFFF); - uint32_t depthScale = (uint32_t)roundf(0xFFFF * normWScaleFloat * screenShiftFactor * 0.5f); - if(depthScale > 0x7FFF)depthScale = 0x7FFF; + // normWScaleFloat <= 1, so this always fits u15.16 + // normWScaleFloat <= 1, so this always fits u15.16 + // (0.25: halved like the x/y scales for the NR full reciprocal) + uint32_t depthScaleFx = (uint32_t)roundf(0xFFFF * normWScaleFloat * 0.5f * 0x10000); - uint32_t depthAndWScale = (depthScale << 16) | normWScale; + uint32_t depthAndWScale = (depthScaleFx & 0xFFFF0000) | normWScale; // z int + w-normalize /*debugf("Screen: %04X %04X | Depth: %08X W-scale: %04X\n", (screenScaleX & 0xFFFF), (screenScaleY & 0xFFFF), depthScale, normWScale );*/ - int32_t guardBandScale = viewport->guardBandScale & 0xF; + int32_t guardBandScale = guardBand; // uv-gen offset, used to skew normals based on distance to the screen center. // This can fake uvgen shifting based on the viewing angle. @@ -630,7 +658,8 @@ void t3d_viewport_attach(T3DViewport *viewport) { guardBandScale |= invScreenSize; rspq_write(T3D_RSP_ID, T3D_CMD_SCREEN_SIZE, - guardBandScale, screenOffset, screenScale, depthAndWScale + guardBandScale, screenOffset, screenScale, depthAndWScale, + screenScaleFrac, (depthScaleFx & 0xFFFF) << 16 // fraction words of the s16.16 scales ); if(viewport->_matFP) diff --git a/src/t3d/t3d.h b/src/t3d/t3d.h index 84dcdbbd..1e6bea65 100644 --- a/src/t3d/t3d.h +++ b/src/t3d/t3d.h @@ -532,11 +532,12 @@ void t3d_light_set_exposure(float exposure); /** * Sets the range of the fog. + * Linear ramp from near to far in world-space. * To disable fog, use 't3d_fog_disable' or set 'near' and 'far' to 0. * Note: in order for fog itself to work, make sure to setup the needed RSPQ commands. * - * @param near start of the fog effect - * @param far end of the fog effect + * @param near distance where the fog starts + * @param far distance where the fog reaches the fog color */ void t3d_fog_set_range(float near, float far); diff --git a/src/t3d/t3dmath.c b/src/t3d/t3dmath.c index b0ab0f76..9817fe1c 100644 --- a/src/t3d/t3dmath.c +++ b/src/t3d/t3dmath.c @@ -150,7 +150,7 @@ void t3d_mat4_perspective(T3DMat4 *mat, float fov, float aspect, float near, flo *mat = (T3DMat4){0}; mat->m[0][0] = 1.0f / (aspect * tanHalfFov); mat->m[1][1] = 1.0f / tanHalfFov; - mat->m[2][2] = far / (near - far); + mat->m[2][2] = (far + near) / (near - far); mat->m[2][3] = -1.0f; mat->m[3][2] = -2.0f * (far * near) / (far - near); } diff --git a/src/t3d/tpx.c b/src/t3d/tpx.c index 5be33537..62d722c5 100644 --- a/src/t3d/tpx.c +++ b/src/t3d/tpx.c @@ -56,10 +56,15 @@ void tpx_state_from_t3d() { T3DViewport *vp = t3d_viewport_get(); assertf(vp, "No Viewport attached"); - uint16_t normWScale = (uint16_t)roundf(0xFFFF * vp->_normScaleW); + uint16_t normWScale = (uint16_t)roundf(0xFFFF * fminf(vp->_normScaleW, 1.0f)); + + int32_t guardBand = vp->guardBandScale & 0xF; + if(guardBand < 1)guardBand = 1; + uint16_t invGuard = (guardBand == 1) ? 0xFFFF : (uint16_t)(0x10000 / guardBand); + tpx_dmem_set_u32(RSP_TPX_NORM_SCALE_W, ((uint32_t)invGuard << 16) | invGuard); uint32_t addrMatrix = (uint32_t)rsp_tiny3d.data + (RSP_T3D_MATRIX_PROJ & 0xFFFF); - uint32_t addrScreen = (uint32_t)rsp_tiny3d.data + (RSP_T3D_SCREEN_SCALE_OFFSET & 0xFFFF); + uint32_t addrScreen = (uint32_t)rsp_tiny3d.data + (RSP_T3D_SCREEN_SCALE & 0xFFFF); rspq_write(TPX_RSP_ID, TPX_CMD_SYNC_T3D, addrMatrix & 0x00FFFFFF, addrScreen & 0x00FFFFFF, diff --git a/tests/depth.sh b/tests/depth.sh new file mode 100755 index 00000000..5b90c3fd --- /dev/null +++ b/tests/depth.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Depth precision regression test, requires ares-64 test runner + node. +# +# Usage: tests/depth.sh [--update] [preset ...] +# --update accept the current result as the new golden +# preset one or more preset numbers (default: 0 2) +# 0 = near 10 / far 12800 (default-sized) +# 2 = near 10 / far 150 (near-field) +# +# Runs the SWEEP scene of examples/98_depthtest for each preset (tests/depth.test.js), +# stores the z-buffer code of all 2000 sweep samples in tests/depth/.actual.txt +# and compares it against the golden tests/depth/.txt (tests/depth_compare.js): +# the metrics are always printed side by side, any metric getting worse fails, +# a changed sample vector with equal-or-better metrics is reported as CHANGED. + +set -u +cd "$(dirname "$0")/.." + +ARES_TEST=${ARES_TEST:-ares-test} +ROM=examples/98_depthtest/t3d_98_depthtest.z64 +DIR=tests/depth + +declare -A NAMES=([0]=near10_far12800 [1]=near10_far1000 [2]=near10_far150 [3]=near1_far100) + +update="" +selected=() +for arg in "$@"; do + case "$arg" in + --update) update="--update" ;; + *) selected+=("$arg") ;; + esac +done +[[ ${#selected[@]} -eq 0 ]] && selected=(0 2) + +if [[ ! -f "$ROM" ]]; then + echo "FAIL depth (ROM not built: $ROM)" + exit 1 +fi + +mkdir -p "$DIR" +rm -f "$DIR"/*.actual.txt +pass=0 fail=0 + +for p in "${selected[@]}"; do + name=${NAMES[$p]:-} + if [[ -z "$name" ]]; then + echo "FAIL preset $p (unknown)" + fail=$((fail + 1)) + continue + fi + actual="$DIR/$name.actual.txt" + golden="$DIR/$name.txt" + echo "== depth preset $p ($name)" + if ! out=$("$ARES_TEST" tests/depth.test.js "$ROM" "$p" --timeout 900 2>&1); then + echo "FAIL $name (capture)" + sed 's/^/ | /' <<<"$out" | tail -20 + fail=$((fail + 1)) + continue + fi + grep -q '^WARNING' <<<"$out" && grep '^WARNING' <<<"$out" | sed 's/^/ /' + sed -n '/^DEPTH-BEGIN$/,/^DEPTH-END$/p' <<<"$out" | sed '1d;$d' >"$actual" + if node tests/depth_compare.js "$golden" "$actual" $update; then + echo "PASS $name" + pass=$((pass + 1)) + else + echo "FAIL $name" + fail=$((fail + 1)) + fi +done + +echo "----" +echo "pass=$pass fail=$fail" +[[ $fail -eq 0 ]] || exit 1 diff --git a/tests/depth.test.js b/tests/depth.test.js new file mode 100644 index 00000000..63255ff1 --- /dev/null +++ b/tests/depth.test.js @@ -0,0 +1,89 @@ +// Depth regression capture for 98_depthtest (see tests/depth.sh). +// +// Usage: ares-test tests/depth.test.js +// +// Runs only the SWEEP scene of the depth test ROM for one near/far preset: +// a view-aligned quad is moved through 2000 log-spaced distances and the +// stored z-buffer code (18-bit decoded, ares.depthBuffer) is read for every +// step. The result is printed as a text block between "DEPTH-BEGIN" and +// "DEPTH-END", one "step w z" line per sample, which tests/depth_compare.js +// turns into metrics and compares against tests/depth/*.txt. +// +// A screen-aligned quad only exercises the vertex side of the ucode (W +// normalisation, reciprocal, Z multiply, fraction handling), which is exactly +// the part an optimisation can silently degrade, so this is the complete +// per-vertex depth behaviour for the preset in a few KB. + +const [rom, presetArg] = ares.args; +if (!rom) throw new Error("usage: depth.test.js "); +const PRESET = parseInt(presetArg || "0", 10); + +const W = 320, H = 240; +const PRESET_COUNT = 4, STEPS = 2000; +const RX = 128, RY = 104, RW = 64, RH = 32; // centre region of the quad + +ares.setRenderer("angrylion"); +ares.loadRom(rom); +ares.resume(); +if (!ares.waitLog("DT ready", 60)) throw new Error("ROM did not boot:\n" + ares.log()); + +const p1 = ares.controller(1); +const cur = { scene: 0, sub: 0, step: 0, preset: 0 }; +const marker = (s) => `DT scene=${s.scene} sub=${s.sub} step=${s.step} `; + +function pressUntil(btn, expect) { + ares.clearLog(); + p1.hold(btn); + const ok = ares.waitLog(marker(expect), 20); + p1.release(btn); + ares.waitVI(); ares.waitVI(); + if (!ok) throw new Error(`button ${btn}: ROM never reached ${JSON.stringify(expect)}\n` + ares.log().slice(-800)); + Object.assign(cur, expect); +} +while (cur.preset !== PRESET) pressUntil("R", { ...cur, preset: (cur.preset + 1) % PRESET_COUNT }); + +function parseLine(line) { + const o = {}; + for (const tok of line.slice(3).split(" ")) { + const eq = tok.indexOf("="); + if (eq > 0) o[tok.slice(0, eq)] = tok.slice(eq + 1); + } + return o; +} + +const samples = []; +let info = null; +ares.onLog((line) => { + if (!line.startsWith("DT scene=")) return; + const st = parseLine(line); + if (+st.scene !== 0 || +st.sub !== 0) return; + const step = +st.step; + if (samples.length && samples[samples.length - 1].step === step) return; + info = info || { near: +st.near, far: +st.far }; + const z = new Uint32Array(ares.depthBuffer(W, H, { x: RX, y: RY, width: RW, height: RH }).data); + const counts = new Map(); + for (const v of z) counts.set(v, (counts.get(v) || 0) + 1); + let mode = 0, modeN = 0; + for (const [v, n] of counts) if (n > modeN) { mode = v; modeN = n; } + samples.push({ step, w: st.w, z: mode, spread: z.length - modeN }); +}); + +ares.clearLog(); +if (!ares.waitLog(marker(cur), 20)) throw new Error("sweep: no first frame"); +p1.hold("Start"); // auto-advance one step per frame +if (!ares.waitLog("step=1 ", 20)) throw new Error("sweep: auto-advance did not start"); +p1.release("Start"); +if (!ares.waitLog(`step=${STEPS - 1} `, 900)) throw new Error("sweep: did not reach the last step"); +ares.waitVI(); ares.waitVI(); + +if (ares.log().includes("RSP CRASH") || ares.log().includes("CPU exception")) throw new Error("ROM crashed:\n" + ares.log()); +samples.sort((a, b) => a.step - b.step); +if (samples.length !== STEPS) throw new Error(`sweep: captured ${samples.length} of ${STEPS} steps`); +const nonUniform = samples.filter((s) => s.spread > 0).length; +if (nonUniform) console.log(`WARNING: ${nonUniform} samples had non-uniform depth across the flat quad`); + +console.log("DEPTH-BEGIN"); +console.log(`# rom=${rom.split("/").pop()} preset=${PRESET} near=${info.near} far=${info.far} steps=${STEPS}`); +console.log("# step w z18"); +for (const s of samples) console.log(`${s.step} ${s.w} ${s.z}`); +console.log("DEPTH-END"); diff --git a/tests/depth/.gitignore b/tests/depth/.gitignore new file mode 100644 index 00000000..bdc49b10 --- /dev/null +++ b/tests/depth/.gitignore @@ -0,0 +1 @@ +*.actual.txt diff --git a/tests/depth/near10_far12800.txt b/tests/depth/near10_far12800.txt new file mode 100644 index 00000000..b1da38e2 --- /dev/null +++ b/tests/depth/near10_far12800.txt @@ -0,0 +1,2002 @@ +# rom=t3d_98_depthtest.z64 preset=0 near=10 far=12800 steps=2000 +# step w z18 +0 10.5 12480 +1 10.53734 12928 +2 10.57481 13376 +3 10.61241 14976 +4 10.65015 15424 +5 10.68802 15872 +6 10.72603 17472 +7 10.76417 17920 +8 10.80245 19456 +9 10.84086 19904 +10 10.87941 20352 +11 10.9181 21824 +12 10.95692 22336 +13 10.99588 22784 +14 11.03498 24256 +15 11.07422 24704 +16 11.1136 26112 +17 11.15312 26560 +18 11.19278 27072 +19 11.23258 28480 +20 11.27253 28928 +21 11.31261 30272 +22 11.35284 30784 +23 11.39321 31232 +24 11.43372 32576 +25 11.47438 33024 +26 11.51518 34368 +27 11.55613 34816 +28 11.59722 35264 +29 11.63846 36608 +30 11.67985 37056 +31 11.72138 38336 +32 11.76306 38784 +33 11.80489 40064 +34 11.84687 40512 +35 11.889 40960 +36 11.93127 42176 +37 11.9737 42688 +38 12.01628 43840 +39 12.05901 44352 +40 12.10189 45504 +41 12.14493 45952 +42 12.18811 46464 +43 12.23145 47616 +44 12.27495 48064 +45 12.3186 49216 +46 12.3624 49664 +47 12.40636 50816 +48 12.45048 51264 +49 12.49475 51712 +50 12.53918 52864 +51 12.58377 53312 +52 12.62852 54400 +53 12.67343 54848 +54 12.71849 55936 +55 12.76372 56384 +56 12.80911 57472 +57 12.85466 57920 +58 12.90037 58944 +59 12.94624 59392 +60 12.99228 59904 +61 13.03848 60864 +62 13.08484 61376 +63 13.13137 62336 +64 13.17806 62848 +65 13.22493 63808 +66 13.27195 64256 +67 13.31915 65216 +68 13.36651 65728 +69 13.41404 66688 +70 13.46174 67136 +71 13.50961 68096 +72 13.55765 68544 +73 13.60586 69440 +74 13.65424 69952 +75 13.7028 70848 +76 13.75152 71296 +77 13.80042 72192 +78 13.8495 72640 +79 13.89875 73152 +80 13.94817 74048 +81 13.99777 74496 +82 14.04754 75392 +83 14.0975 75840 +84 14.14763 76672 +85 14.19794 77184 +86 14.24842 78016 +87 14.29909 78464 +88 14.34994 79296 +89 14.40097 80128 +90 14.45218 80576 +91 14.50357 81408 +92 14.55514 81856 +93 14.6069 82688 +94 14.65884 83136 +95 14.71097 83968 +96 14.76328 84416 +97 14.81578 85184 +98 14.86846 85632 +99 14.92133 86400 +100 14.97439 86912 +101 15.02764 87680 +102 15.08108 88128 +103 15.13471 88896 +104 15.18852 89344 +105 15.24253 90048 +106 15.29674 90560 +107 15.35113 91264 +108 15.40572 92032 +109 15.4605 92480 +110 15.51548 93184 +111 15.57065 93632 +112 15.62602 94336 +113 15.68158 94848 +114 15.73735 95488 +115 15.79331 96000 +116 15.84947 96704 +117 15.90583 97344 +118 15.96239 97856 +119 16.01915 98496 +120 16.07612 98944 +121 16.13328 99648 +122 16.19065 100096 +123 16.24823 100736 +124 16.306 101376 +125 16.36399 101888 +126 16.42218 102528 +127 16.48057 102976 +128 16.53918 103616 +129 16.59799 104064 +130 16.65701 104704 +131 16.71625 105344 +132 16.77569 105792 +133 16.83534 106432 +134 16.89521 106880 +135 16.95529 107520 +136 17.01558 108096 +137 17.07609 108544 +138 17.13681 109184 +139 17.19775 109632 +140 17.2589 110208 +141 17.32027 110784 +142 17.38186 111296 +143 17.44367 111872 +144 17.5057 112448 +145 17.56795 112896 +146 17.63042 113472 +147 17.69312 113920 +148 17.75603 114496 +149 17.81917 115072 +150 17.88254 115520 +151 17.94613 116096 +152 18.00994 116608 +153 18.07398 117120 +154 18.13826 117632 +155 18.20275 118208 +156 18.26748 118656 +157 18.33244 119168 +158 18.39763 119680 +159 18.46305 120192 +160 18.52871 120704 +161 18.59459 121152 +162 18.66072 121664 +163 18.72707 122176 +164 18.79367 122688 +165 18.8605 123200 +166 18.92756 123712 +167 18.99487 124160 +168 19.06241 124672 +169 19.1302 125184 +170 19.19823 125632 +171 19.26649 126144 +172 19.335 126592 +173 19.40376 127104 +174 19.47276 127552 +175 19.542 128064 +176 19.61149 128512 +177 19.68123 129024 +178 19.75122 129472 +179 19.82145 129920 +180 19.89194 130432 +181 19.96267 130880 +182 20.03366 131360 +183 20.1049 131840 +184 20.17639 132288 +185 20.24814 132768 +186 20.32014 133216 +187 20.3924 133696 +188 20.46491 134144 +189 20.53768 134592 +190 20.61072 135040 +191 20.68401 135520 +192 20.75756 135936 +193 20.83137 136384 +194 20.90545 136832 +195 20.97979 137312 +196 21.05439 137728 +197 21.12926 138176 +198 21.2044 138592 +199 21.2798 139072 +200 21.35547 139488 +201 21.4314 139936 +202 21.50761 140352 +203 21.5841 140800 +204 21.66085 141248 +205 21.73787 141664 +206 21.81517 142080 +207 21.89275 142528 +208 21.9706 142944 +209 22.04872 143360 +210 22.12713 143776 +211 22.20581 144192 +212 22.28477 144640 +213 22.36402 145056 +214 22.44354 145472 +215 22.52335 145856 +216 22.60345 146272 +217 22.68382 146720 +218 22.76449 147136 +219 22.84544 147520 +220 22.92667 147904 +221 23.0082 148320 +222 23.09002 148768 +223 23.17212 149152 +224 23.25452 149536 +225 23.33722 149952 +226 23.4202 150336 +227 23.50348 150720 +228 23.58706 151168 +229 23.67093 151552 +230 23.75511 151936 +231 23.83958 152320 +232 23.92435 152672 +233 24.00943 153056 +234 24.0948 153536 +235 24.18049 153888 +236 24.26647 154272 +237 24.35276 154656 +238 24.43936 155008 +239 24.52626 155392 +240 24.61348 155744 +241 24.701 156128 +242 24.78884 156576 +243 24.87699 156960 +244 24.96545 157312 +245 25.05423 157664 +246 25.14332 158016 +247 25.23273 158400 +248 25.32245 158752 +249 25.4125 159104 +250 25.50287 159456 +251 25.59356 159936 +252 25.68456 160288 +253 25.7759 160640 +254 25.86756 160992 +255 25.95954 161344 +256 26.05185 161696 +257 26.14449 162016 +258 26.23746 162368 +259 26.33076 162720 +260 26.42439 163072 +261 26.51835 163424 +262 26.61265 163744 +263 26.70729 164096 +264 26.80226 164448 +265 26.89757 164896 +266 26.99321 165248 +267 27.0892 165600 +268 27.18553 165920 +269 27.2822 166272 +270 27.37921 166592 +271 27.47657 166944 +272 27.57428 167264 +273 27.67233 167616 +274 27.77073 167936 +275 27.86949 168288 +276 27.96859 168608 +277 28.06805 168960 +278 28.16786 169280 +279 28.26802 169600 +280 28.36854 169952 +281 28.46942 170272 +282 28.57065 170592 +283 28.67225 170912 +284 28.77421 171264 +285 28.87652 171584 +286 28.97921 171904 +287 29.08226 172224 +288 29.18568 172544 +289 29.28946 172864 +290 29.39361 173216 +291 29.49813 173536 +292 29.60303 173696 +293 29.7083 174016 +294 29.81394 174336 +295 29.91996 174656 +296 30.02635 174976 +297 30.13312 175296 +298 30.24028 175616 +299 30.34781 175936 +300 30.45573 176256 +301 30.56403 176576 +302 30.67271 176896 +303 30.78178 177216 +304 30.89124 177536 +305 31.00109 177696 +306 31.11133 178016 +307 31.22196 178336 +308 31.33298 178656 +309 31.4444 178944 +310 31.55622 179264 +311 31.66843 179584 +312 31.78104 179904 +313 31.89405 180224 +314 32.00747 180384 +315 32.12129 180672 +316 32.23551 180992 +317 32.35014 181312 +318 32.46518 181600 +319 32.58062 181920 +320 32.69647 182240 +321 32.81274 182400 +322 32.92942 182688 +323 33.04652 183008 +324 33.16403 183328 +325 33.28196 183616 +326 33.40031 183776 +327 33.51908 184096 +328 33.63828 184384 +329 33.75789 184704 +330 33.87793 184992 +331 33.9984 185312 +332 34.1193 185472 +333 34.24063 185760 +334 34.36238 186080 +335 34.48457 186368 +336 34.6072 186528 +337 34.73027 186848 +338 34.85376 187136 +339 34.9777 187456 +340 35.10208 187584 +341 35.22691 187904 +342 35.35217 188192 +343 35.47788 188512 +344 35.60404 188640 +345 35.73064 188960 +346 35.8577 189248 +347 35.98521 189568 +348 36.11317 189696 +349 36.24159 190016 +350 36.37047 190304 +351 36.4998 190624 +352 36.62959 190752 +353 36.75984 191040 +354 36.89056 191360 +355 37.02174 191488 +356 37.15339 191808 +357 37.28551 192096 +358 37.41809 192224 +359 37.55116 192544 +360 37.68468 192832 +361 37.81869 192992 +362 37.95317 193280 +363 38.08813 193600 +364 38.22357 193728 +365 38.35949 194016 +366 38.4959 194336 +367 38.63279 194464 +368 38.77016 194784 +369 38.90803 194912 +370 39.04639 195200 +371 39.18523 195520 +372 39.32457 195648 +373 39.46441 195936 +374 39.60475 196096 +375 39.74558 196384 +376 39.88691 196704 +377 40.02875 196832 +378 40.17109 197136 +379 40.31394 197280 +380 40.45729 197584 +381 40.60116 197712 +382 40.74554 198016 +383 40.89043 198320 +384 41.03583 198464 +385 41.18175 198752 +386 41.32819 198896 +387 41.47516 199200 +388 41.62264 199344 +389 41.77065 199632 +390 41.91918 199776 +391 42.06825 200080 +392 42.21784 200224 +393 42.36797 200528 +394 42.51862 200656 +395 42.66982 200960 +396 42.82156 201104 +397 42.97383 201408 +398 43.12664 201536 +399 43.27999 201840 +400 43.4339 201984 +401 43.58835 202288 +402 43.74335 202432 +403 43.8989 202736 +404 44.055 202864 +405 44.21166 203008 +406 44.36887 203312 +407 44.52665 203456 +408 44.68498 203760 +409 44.84388 203904 +410 45.00335 204048 +411 45.16338 204352 +412 45.32398 204480 +413 45.48515 204784 +414 45.64689 204928 +415 45.80921 205072 +416 45.97211 205376 +417 46.13558 205520 +418 46.29964 205824 +419 46.46428 205968 +420 46.62951 206112 +421 46.79532 206416 +422 46.96172 206560 +423 47.12872 206704 +424 47.2963 207008 +425 47.46449 207168 +426 47.63327 207312 +427 47.80265 207456 +428 47.97264 207760 +429 48.14323 207904 +430 48.31442 208048 +431 48.48623 208352 +432 48.65864 208512 +433 48.83167 208656 +434 49.00531 208800 +435 49.17958 209104 +436 49.35445 209264 +437 49.52996 209408 +438 49.70609 209552 +439 49.88284 209872 +440 50.06022 210016 +441 50.23823 210176 +442 50.41688 210320 +443 50.59616 210624 +444 50.77608 210784 +445 50.95664 210928 +446 51.13784 211088 +447 51.31968 211248 +448 51.50217 211392 +449 51.68531 211712 +450 51.8691 211856 +451 52.05355 212016 +452 52.23865 212176 +453 52.42441 212320 +454 52.61083 212480 +455 52.79791 212800 +456 52.98566 212944 +457 53.17407 213104 +458 53.36316 213264 +459 53.55292 213424 +460 53.74335 213584 +461 53.93446 213744 +462 54.12625 213904 +463 54.31872 214064 +464 54.51188 214224 +465 54.70572 214384 +466 54.90025 214544 +467 55.09547 214864 +468 55.29139 215024 +469 55.48801 215184 +470 55.68532 215344 +471 55.88334 215504 +472 56.08205 215680 +473 56.28148 215840 +474 56.48162 216000 +475 56.68246 216176 +476 56.88403 216336 +477 57.0863 216496 +478 57.28931 216672 +479 57.49302 216832 +480 57.69746 217008 +481 57.90263 217024 +482 58.10853 217200 +483 58.31517 217360 +484 58.52253 217536 +485 58.73064 217712 +486 58.93948 217872 +487 59.14907 218048 +488 59.3594 218224 +489 59.57048 218400 +490 59.78231 218560 +491 59.9949 218736 +492 60.20824 218768 +493 60.42233 218944 +494 60.6372 219120 +495 60.85282 219296 +496 61.06921 219472 +497 61.28637 219648 +498 61.5043 219680 +499 61.72301 219856 +500 61.9425 220032 +501 62.16275 220224 +502 62.38381 220400 +503 62.60565 220432 +504 62.82827 220608 +505 63.05169 220800 +506 63.27589 220976 +507 63.5009 221024 +508 63.72672 221200 +509 63.95331 221376 +510 64.18073 221568 +511 64.40896 221616 +512 64.63799 221792 +513 64.86785 221984 +514 65.09851 222160 +515 65.33 222208 +516 65.5623 222400 +517 65.79545 222592 +518 66.02943 222640 +519 66.26421 222832 +520 66.49986 223024 +521 66.73632 223072 +522 66.97363 223264 +523 67.21179 223312 +524 67.45079 223504 +525 67.69064 223696 +526 67.93136 223760 +527 68.17291 223952 +528 68.41534 224000 +529 68.65862 224192 +530 68.90276 224256 +531 69.14779 224448 +532 69.39367 224656 +533 69.64043 224720 +534 69.88807 224912 +535 70.13659 224976 +536 70.386 225168 +537 70.63628 225232 +538 70.88747 225440 +539 71.13953 225504 +540 71.39251 225712 +541 71.64639 225776 +542 71.90115 225840 +543 72.15683 226048 +544 72.41343 226112 +545 72.67091 226320 +546 72.92934 226400 +547 73.18866 226608 +548 73.44893 226672 +549 73.71011 226752 +550 73.97221 226960 +551 74.23526 227040 +552 74.49924 227248 +553 74.76415 227328 +554 75.03002 227408 +555 75.29681 227616 +556 75.56458 227696 +557 75.83327 227776 +558 76.10294 227856 +559 76.37357 228080 +560 76.64513 228160 +561 76.91769 228240 +562 77.19119 228464 +563 77.46569 228544 +564 77.74117 228640 +565 78.0176 228720 +566 78.29504 228944 +567 78.57346 229024 +568 78.85285 229120 +569 79.13326 229216 +570 79.41464 229312 +571 79.69704 229536 +572 79.98045 229632 +573 80.26485 229728 +574 80.55028 229824 +575 80.8367 229928 +576 81.12416 230024 +577 81.41264 230128 +578 81.70213 230224 +579 81.99267 230448 +580 82.28422 230552 +581 82.57683 230656 +582 82.87048 230760 +583 83.16515 230864 +584 83.46089 230976 +585 83.75766 231080 +586 84.0555 231192 +587 84.35441 231296 +588 84.65437 231408 +589 84.95541 231520 +590 85.25751 231632 +591 85.56067 231744 +592 85.86493 231856 +593 86.17025 231968 +594 86.47668 232088 +595 86.78419 232200 +596 87.09278 232320 +597 87.40248 232320 +598 87.71327 232440 +599 88.02519 232560 +600 88.33821 232680 +601 88.65233 232800 +602 88.96758 232920 +603 89.28394 233048 +604 89.60144 233056 +605 89.92006 233184 +606 90.2398 233304 +607 90.5607 233432 +608 90.88272 233560 +609 91.2059 233576 +610 91.53024 233704 +611 91.85571 233832 +612 92.18235 233968 +613 92.51015 233984 +614 92.83911 234120 +615 93.16924 234248 +616 93.50054 234280 +617 93.83304 234408 +618 94.16671 234544 +619 94.50155 234576 +620 94.8376 234712 +621 95.17484 234848 +622 95.51328 234880 +623 95.85293 235024 +624 96.19376 235160 +625 96.53583 235192 +626 96.8791 235336 +627 97.22362 235376 +628 97.56934 235520 +629 97.91628 235560 +630 98.26447 235704 +631 98.61391 235744 +632 98.96456 235896 +633 99.31649 235936 +634 99.66964 236088 +635 100.0241 236128 +636 100.3798 236280 +637 100.7367 236328 +638 101.0949 236480 +639 101.4544 236528 +640 101.8152 236584 +641 102.1772 236736 +642 102.5406 236792 +643 102.9052 236848 +644 103.2711 237000 +645 103.6384 237056 +646 104.0069 237120 +647 104.3767 237272 +648 104.7479 237336 +649 105.1204 237392 +650 105.4942 237560 +651 105.8693 237624 +652 106.2458 237688 +653 106.6236 237752 +654 107.0028 237816 +655 107.3832 237984 +656 107.7651 238048 +657 108.1483 238120 +658 108.5329 238192 +659 108.9188 238264 +660 109.3061 238336 +661 109.6948 238512 +662 110.0849 238584 +663 110.4763 238664 +664 110.8692 238736 +665 111.2634 238816 +666 111.6591 238896 +667 112.0561 238976 +668 112.4546 239056 +669 112.8545 239136 +670 113.2558 239224 +671 113.6585 239304 +672 114.0627 239392 +673 114.4683 239480 +674 114.8754 239568 +675 115.2838 239656 +676 115.6938 239744 +677 116.1052 239744 +678 116.5181 239832 +679 116.9324 239928 +680 117.3482 240024 +681 117.7655 240120 +682 118.1843 240216 +683 118.6045 240216 +684 119.0263 240320 +685 119.4495 240416 +686 119.8743 240512 +687 120.3006 240528 +688 120.7283 240632 +689 121.1577 240736 +690 121.5885 240840 +691 122.0209 240856 +692 122.4548 240960 +693 122.8902 241064 +694 123.3272 241080 +695 123.7658 241192 +696 124.2058 241216 +697 124.6475 241328 +698 125.0908 241440 +699 125.5356 241464 +700 125.982 241584 +701 126.43 241608 +702 126.8796 241728 +703 127.3307 241760 +704 127.7835 241872 +705 128.2379 241912 +706 128.6939 242032 +707 129.1516 242064 +708 129.6108 242104 +709 130.0717 242224 +710 130.5343 242264 +711 130.9984 242392 +712 131.4642 242432 +713 131.9317 242472 +714 132.4009 242520 +715 132.8717 242648 +716 133.3442 242696 +717 133.8183 242744 +718 134.2942 242880 +719 134.7717 242928 +720 135.251 242976 +721 135.7319 243032 +722 136.2146 243088 +723 136.699 243224 +724 137.1851 243280 +725 137.6729 243336 +726 138.1624 243392 +727 138.6537 243456 +728 139.1468 243512 +729 139.6416 243576 +730 140.1382 243640 +731 140.6365 243712 +732 141.1366 243776 +733 141.6385 243840 +734 142.1421 243912 +735 142.6476 243976 +736 143.1548 244048 +737 143.6639 244120 +738 144.1748 244192 +739 144.6874 244272 +740 145.2019 244264 +741 145.7183 244344 +742 146.2364 244424 +743 146.7565 244496 +744 147.2783 244584 +745 147.802 244584 +746 148.3276 244664 +747 148.8551 244752 +748 149.3844 244832 +749 149.9156 244848 +750 150.4487 244936 +751 150.9837 245016 +752 151.5206 245032 +753 152.0594 245128 +754 152.6001 245144 +755 153.1427 245232 +756 153.6873 245328 +757 154.2338 245352 +758 154.7823 245440 +759 155.3327 245472 +760 155.885 245568 +761 156.4393 245592 +762 156.9956 245696 +763 157.5539 245720 +764 158.1142 245752 +765 158.6764 245856 +766 159.2407 245888 +767 159.8069 245920 +768 160.3752 246024 +769 160.9455 246064 +770 161.5178 246104 +771 162.0921 246216 +772 162.6685 246256 +773 163.247 246296 +774 163.8275 246336 +775 164.41 246384 +776 164.9947 246496 +777 165.5814 246544 +778 166.1702 246592 +779 166.7611 246640 +780 167.3541 246696 +781 167.9492 246744 +782 168.5464 246800 +783 169.1458 246848 +784 169.7473 246912 +785 170.3508 246968 +786 170.9566 247024 +787 171.5646 247088 +788 172.1746 247144 +789 172.7869 247208 +790 173.4013 247208 +791 174.0179 247272 +792 174.6367 247336 +793 175.2577 247400 +794 175.8809 247472 +795 176.5063 247472 +796 177.134 247544 +797 177.7639 247616 +798 178.396 247688 +799 179.0304 247696 +800 179.667 247776 +801 180.3059 247784 +802 180.9471 247864 +803 181.5905 247944 +804 182.2362 247960 +805 182.8843 248040 +806 183.5346 248064 +807 184.1872 248144 +808 184.8422 248168 +809 185.4995 248256 +810 186.1591 248280 +811 186.8211 248304 +812 187.4854 248392 +813 188.1521 248424 +814 188.8212 248448 +815 189.4926 248544 +816 190.1664 248576 +817 190.8427 248616 +818 191.5213 248648 +819 192.2024 248688 +820 192.8858 248784 +821 193.5717 248824 +822 194.2601 248864 +823 194.9509 248904 +824 195.6441 248952 +825 196.3398 248992 +826 197.0379 249040 +827 197.7386 249088 +828 198.4418 249136 +829 199.1474 249184 +830 199.8556 249240 +831 200.5663 249296 +832 201.2795 249344 +833 201.9952 249400 +834 202.7135 249400 +835 203.4344 249456 +836 204.1577 249512 +837 204.8837 249576 +838 205.6123 249584 +839 206.3434 249640 +840 207.0772 249704 +841 207.8135 249712 +842 208.5525 249784 +843 209.2942 249856 +844 210.0384 249864 +845 210.7853 249936 +846 211.5348 249952 +847 212.287 250024 +848 213.0419 250040 +849 213.7995 250120 +850 214.5598 250136 +851 215.3227 250160 +852 216.0884 250240 +853 216.8568 250264 +854 217.6279 250296 +855 218.4018 250320 +856 219.1785 250408 +857 219.9578 250440 +858 220.74 250472 +859 221.5249 250504 +860 222.3127 250536 +861 223.1033 250576 +862 223.8966 250664 +863 224.6928 250704 +864 225.4917 250744 +865 226.2936 250792 +866 227.0983 250832 +867 227.9058 250824 +868 228.7163 250872 +869 229.5296 250920 +870 230.3457 250968 +871 231.1649 251016 +872 231.9869 251064 +873 232.8118 251072 +874 233.6397 251128 +875 234.4705 251184 +876 235.3043 251184 +877 236.141 251240 +878 236.9807 251304 +879 237.8235 251312 +880 238.6691 251376 +881 239.5178 251384 +882 240.3695 251456 +883 241.2243 251472 +884 242.0821 251536 +885 242.9429 251552 +886 243.8068 251576 +887 244.6738 251648 +888 245.5438 251664 +889 246.417 251696 +890 247.2932 251768 +891 248.1726 251792 +892 249.0551 251824 +893 249.9407 251856 +894 250.8295 251888 +895 251.7214 251920 +896 252.6166 251960 +897 253.5149 251992 +898 254.4163 252032 +899 255.3211 252064 +900 256.2289 252104 +901 257.1401 252152 +902 258.0545 252192 +903 258.9721 252232 +904 259.893 252280 +905 260.8172 252280 +906 261.7446 252328 +907 262.6754 252384 +908 263.6094 252384 +909 264.5468 252440 +910 265.4876 252488 +911 266.4316 252504 +912 267.3791 252552 +913 268.3298 252568 +914 269.284 252632 +915 270.2416 252640 +916 271.2026 252664 +917 272.167 252728 +918 273.1347 252744 +919 274.106 252768 +920 275.0807 252832 +921 276.0589 252856 +922 277.0406 252880 +923 278.0257 252912 +924 279.0144 252936 +925 280.0066 252968 +926 281.0022 252992 +927 282.0015 253032 +928 283.0043 253064 +929 284.0106 253104 +930 285.0206 253136 +931 286.0341 253176 +932 287.0512 253216 +933 288.072 253256 +934 289.0963 253296 +935 290.1243 253304 +936 291.156 253344 +937 292.1913 253392 +938 293.2304 253400 +939 294.2731 253448 +940 295.3195 253456 +941 296.3697 253512 +942 297.4236 253520 +943 298.4812 253576 +944 299.5425 253592 +945 300.6077 253608 +946 301.6766 253664 +947 302.7495 253688 +948 303.826 253704 +949 304.9064 253728 +950 305.9907 253792 +951 307.0788 253816 +952 308.1707 253848 +953 309.2666 253880 +954 310.3663 253904 +955 311.4699 253936 +956 312.5775 253968 +957 313.689 254008 +958 314.8045 254000 +959 315.9239 254040 +960 317.0474 254072 +961 318.1748 254112 +962 319.3062 254120 +963 320.4417 254160 +964 321.5811 254208 +965 322.7246 254208 +966 323.8723 254264 +967 325.0239 254264 +968 326.1797 254320 +969 327.3396 254336 +970 328.5036 254352 +971 329.6718 254400 +972 330.844 254424 +973 332.0205 254440 +974 333.2012 254456 +975 334.386 254520 +976 335.5751 254544 +977 336.7684 254568 +978 337.9659 254592 +979 339.1677 254624 +980 340.3738 254648 +981 341.5842 254680 +982 342.7988 254712 +983 344.0178 254712 +984 345.2411 254752 +985 346.4688 254784 +986 347.7008 254784 +987 348.9372 254824 +988 350.178 254864 +989 351.4233 254872 +990 352.6729 254920 +991 353.927 254928 +992 355.1855 254976 +993 356.4486 254992 +994 357.7161 255008 +995 358.9881 255056 +996 360.2647 255072 +997 361.5458 255096 +998 362.8314 255112 +999 364.1216 255136 +1000 365.4165 255160 +1001 366.7158 255184 +1002 368.0198 255208 +1003 369.3286 255240 +1004 370.6419 255264 +1005 371.9599 255296 +1006 373.2827 255336 +1007 374.6099 255328 +1008 375.942 255368 +1009 377.2789 255408 +1010 378.6205 255408 +1011 379.9669 255448 +1012 381.3179 255456 +1013 382.6739 255504 +1014 384.0347 255512 +1015 385.4004 255528 +1016 386.7708 255568 +1017 388.1461 255584 +1018 389.5264 255608 +1019 390.9115 255624 +1020 392.3016 255648 +1021 393.6967 255704 +1022 395.0965 255720 +1023 396.5015 255712 +1024 397.9115 255744 +1025 399.3264 255768 +1026 400.7465 255800 +1027 402.1714 255832 +1028 403.6016 255832 +1029 405.0367 255864 +1030 406.4771 255904 +1031 407.9225 255912 +1032 409.373 255944 +1033 410.8287 255960 +1034 412.2897 256000 +1035 413.7558 256008 +1036 415.2271 256024 +1037 416.7035 256032 +1038 418.1853 256080 +1039 419.6724 256104 +1040 421.1648 256120 +1041 422.6625 256144 +1042 424.1653 256168 +1043 425.6736 256192 +1044 427.1874 256216 +1045 428.7065 256216 +1046 430.231 256240 +1047 431.7609 256272 +1048 433.2961 256304 +1049 434.8369 256312 +1050 436.3832 256344 +1051 437.935 256352 +1052 439.4924 256392 +1053 441.055 256400 +1054 442.6234 256416 +1055 444.1974 256448 +1056 445.777 256464 +1057 447.3622 256480 +1058 448.9529 256504 +1059 450.5493 256520 +1060 452.1516 256544 +1061 453.7594 256568 +1062 455.373 256592 +1063 456.9922 256616 +1064 458.6172 256616 +1065 460.2481 256640 +1066 461.8848 256672 +1067 463.5273 256680 +1068 465.1754 256712 +1069 466.8296 256720 +1070 468.4897 256752 +1071 470.1556 256768 +1072 471.8275 256776 +1073 473.5052 256792 +1074 475.189 256832 +1075 476.8787 256856 +1076 478.5746 256872 +1077 480.2764 256888 +1078 481.9841 256912 +1079 483.6981 256928 +1080 485.4181 256928 +1081 487.1443 256960 +1082 488.8766 256984 +1083 490.6149 256984 +1084 492.3595 257024 +1085 494.1104 257024 +1086 495.8675 257056 +1087 497.6308 257072 +1088 499.4004 257080 +1089 501.1761 257120 +1090 502.9583 257128 +1091 504.7468 257144 +1092 506.5417 257160 +1093 508.343 257184 +1094 510.1505 257200 +1095 511.9646 257224 +1096 513.7852 257248 +1097 515.6122 257248 +1098 517.4458 257272 +1099 519.2856 257304 +1100 521.1323 257304 +1101 522.9854 257336 +1102 524.8452 257344 +1103 526.7115 257352 +1104 528.5844 257392 +1105 530.464 257400 +1106 532.3503 257416 +1107 534.2434 257432 +1108 536.1432 257448 +1109 538.0496 257464 +1110 539.9629 257488 +1111 541.8831 257512 +1112 543.81 257512 +1113 545.7438 257536 +1114 547.6843 257560 +1115 549.6319 257568 +1116 551.5864 257600 +1117 553.5479 257600 +1118 555.5163 257616 +1119 557.4915 257648 +1120 559.474 257656 +1121 561.4635 257672 +1122 563.4601 257688 +1123 565.4638 257704 +1124 567.4744 257728 +1125 569.4923 257744 +1126 571.5175 257744 +1127 573.5499 257768 +1128 575.5894 257792 +1129 577.636 257800 +1130 579.6901 257824 +1131 581.7515 257832 +1132 583.8203 257840 +1133 585.8964 257880 +1134 587.9798 257888 +1135 590.0704 257904 +1136 592.1688 257912 +1137 594.2745 257928 +1138 596.3878 257952 +1139 598.5086 257952 +1140 600.6367 257976 +1141 602.7726 257992 +1142 604.9161 258000 +1143 607.0672 258024 +1144 609.226 258032 +1145 611.3922 258056 +1146 613.5663 258072 +1147 615.7482 258080 +1148 617.9378 258096 +1149 620.1352 258104 +1150 622.3401 258128 +1151 624.5532 258144 +1152 626.7742 258160 +1153 629.0031 258160 +1154 631.2398 258184 +1155 633.4843 258208 +1156 635.7369 258216 +1157 637.9977 258240 +1158 640.2664 258248 +1159 642.5433 258256 +1160 644.8279 258272 +1161 647.1209 258280 +1162 649.4221 258296 +1163 651.7315 258312 +1164 654.0491 258328 +1165 656.3746 258352 +1166 658.7088 258352 +1167 661.0511 258376 +1168 663.4019 258376 +1169 665.761 258400 +1170 668.1282 258408 +1171 670.5041 258424 +1172 672.8884 258448 +1173 675.2812 258464 +1174 677.6826 258480 +1175 680.0925 258496 +1176 682.5107 258488 +1177 684.9377 258512 +1178 687.3734 258528 +1179 689.8177 258528 +1180 692.2707 258552 +1181 694.7322 258560 +1182 697.2026 258568 +1183 699.6819 258600 +1184 702.17 258608 +1185 704.667 258624 +1186 707.1726 258632 +1187 709.6873 258656 +1188 712.211 258648 +1189 714.7437 258672 +1190 717.2853 258688 +1191 719.8357 258696 +1192 722.3954 258720 +1193 724.9644 258720 +1194 727.5424 258736 +1195 730.1296 258744 +1196 732.7256 258752 +1197 735.3312 258768 +1198 737.946 258784 +1199 740.5703 258800 +1200 743.2037 258800 +1201 745.8464 258824 +1202 748.4987 258840 +1203 751.1603 258848 +1204 753.8315 258856 +1205 756.5121 258864 +1206 759.202 258880 +1207 761.9017 258888 +1208 764.6111 258904 +1209 767.3301 258920 +1210 770.0588 258936 +1211 772.7969 258952 +1212 775.545 258952 +1213 778.3029 258960 +1214 781.0705 258984 +1215 783.8481 258992 +1216 786.6351 259000 +1217 789.4324 259016 +1218 792.2397 259032 +1219 795.0569 259040 +1220 797.8842 259056 +1221 800.7216 259056 +1222 803.5686 259080 +1223 806.4261 259088 +1224 809.2938 259104 +1225 812.1717 259112 +1226 815.0599 259120 +1227 817.9579 259136 +1228 820.8666 259144 +1229 823.7857 259160 +1230 826.7151 259160 +1231 829.6549 259176 +1232 832.6049 259184 +1233 835.5657 259200 +1234 838.537 259208 +1235 841.5189 259216 +1236 844.5113 259224 +1237 847.5141 259240 +1238 850.5279 259256 +1239 853.5525 259264 +1240 856.5877 259280 +1241 859.6339 259280 +1242 862.6903 259304 +1243 865.7581 259312 +1244 868.8368 259320 +1245 871.9264 259328 +1246 875.027 259336 +1247 878.1383 259352 +1248 881.261 259360 +1249 884.3948 259376 +1250 887.5397 259384 +1251 890.6959 259400 +1252 893.8629 259408 +1253 897.0415 259416 +1254 900.2314 259424 +1255 903.4327 259432 +1256 906.6453 259448 +1257 909.8691 259456 +1258 913.1046 259456 +1259 916.3516 259472 +1260 919.6102 259480 +1261 922.8804 259504 +1262 926.1622 259512 +1263 929.4553 259512 +1264 932.7605 259528 +1265 936.0775 259544 +1266 939.4062 259544 +1267 942.7468 259552 +1268 946.0988 259576 +1269 949.4632 259576 +1270 952.8396 259584 +1271 956.2278 259592 +1272 959.6283 259600 +1273 963.0404 259616 +1274 966.465 259624 +1275 969.9018 259632 +1276 973.3508 259648 +1277 976.8121 259648 +1278 980.2853 259664 +1279 983.7712 259672 +1280 987.2696 259688 +1281 990.7803 259696 +1282 994.3036 259696 +1283 997.839 259712 +1284 1001.387 259720 +1285 1004.948 259728 +1286 1008.522 259736 +1287 1012.108 259744 +1288 1015.707 259752 +1289 1019.319 259760 +1290 1022.944 259776 +1291 1026.581 259784 +1292 1030.232 259792 +1293 1033.895 259808 +1294 1037.572 259808 +1295 1041.261 259824 +1296 1044.964 259824 +1297 1048.68 259840 +1298 1052.409 259840 +1299 1056.151 259856 +1300 1059.907 259856 +1301 1063.676 259872 +1302 1067.458 259880 +1303 1071.254 259888 +1304 1075.063 259896 +1305 1078.886 259912 +1306 1082.723 259912 +1307 1086.573 259928 +1308 1090.437 259928 +1309 1094.314 259936 +1310 1098.206 259944 +1311 1102.111 259952 +1312 1106.03 259960 +1313 1109.963 259976 +1314 1113.91 259976 +1315 1117.871 259992 +1316 1121.846 260000 +1317 1125.835 260008 +1318 1129.839 260016 +1319 1133.856 260024 +1320 1137.888 260040 +1321 1141.935 260040 +1322 1145.996 260056 +1323 1150.071 260056 +1324 1154.16 260064 +1325 1158.264 260072 +1326 1162.383 260088 +1327 1166.517 260088 +1328 1170.665 260096 +1329 1174.827 260104 +1330 1179.005 260104 +1331 1183.198 260128 +1332 1187.405 260120 +1333 1191.628 260128 +1334 1195.865 260144 +1335 1200.117 260144 +1336 1204.385 260160 +1337 1208.668 260168 +1338 1212.966 260176 +1339 1217.279 260184 +1340 1221.607 260184 +1341 1225.951 260200 +1342 1230.311 260200 +1343 1234.686 260216 +1344 1239.077 260224 +1345 1243.482 260232 +1346 1247.904 260232 +1347 1252.342 260240 +1348 1256.795 260256 +1349 1261.264 260256 +1350 1265.749 260264 +1351 1270.25 260272 +1352 1274.767 260280 +1353 1279.3 260280 +1354 1283.85 260296 +1355 1288.414 260296 +1356 1292.996 260312 +1357 1297.594 260320 +1358 1302.208 260320 +1359 1306.839 260328 +1360 1311.486 260336 +1361 1316.15 260344 +1362 1320.83 260352 +1363 1325.527 260352 +1364 1330.24 260360 +1365 1334.97 260376 +1366 1339.718 260376 +1367 1344.482 260392 +1368 1349.263 260392 +1369 1354.061 260400 +1370 1358.875 260408 +1371 1363.707 260408 +1372 1368.557 260424 +1373 1373.423 260424 +1374 1378.307 260432 +1375 1383.208 260440 +1376 1388.127 260440 +1377 1393.063 260456 +1378 1398.017 260456 +1379 1402.989 260472 +1380 1407.977 260472 +1381 1412.984 260480 +1382 1418.008 260488 +1383 1423.051 260496 +1384 1428.111 260496 +1385 1433.189 260512 +1386 1438.286 260520 +1387 1443.4 260512 +1388 1448.533 260520 +1389 1453.684 260536 +1390 1458.854 260536 +1391 1464.041 260544 +1392 1469.247 260552 +1393 1474.472 260560 +1394 1479.715 260560 +1395 1484.977 260576 +1396 1490.257 260576 +1397 1495.556 260584 +1398 1500.875 260592 +1399 1506.212 260592 +1400 1511.568 260600 +1401 1516.943 260608 +1402 1522.337 260616 +1403 1527.75 260616 +1404 1533.183 260624 +1405 1538.635 260632 +1406 1544.106 260632 +1407 1549.597 260648 +1408 1555.107 260648 +1409 1560.637 260656 +1410 1566.187 260664 +1411 1571.756 260672 +1412 1577.345 260672 +1413 1582.954 260680 +1414 1588.583 260688 +1415 1594.232 260688 +1416 1599.901 260696 +1417 1605.59 260704 +1418 1611.3 260712 +1419 1617.03 260712 +1420 1622.78 260720 +1421 1628.55 260720 +1422 1634.341 260728 +1423 1640.153 260736 +1424 1645.986 260744 +1425 1651.839 260744 +1426 1657.712 260752 +1427 1663.607 260752 +1428 1669.523 260760 +1429 1675.46 260768 +1430 1681.418 260768 +1431 1687.397 260784 +1432 1693.397 260792 +1433 1699.418 260792 +1434 1705.462 260800 +1435 1711.526 260800 +1436 1717.613 260808 +1437 1723.72 260808 +1438 1729.849 260824 +1439 1736.001 260816 +1440 1742.174 260832 +1441 1748.37 260840 +1442 1754.586 260840 +1443 1760.825 260848 +1444 1767.087 260848 +1445 1773.371 260856 +1446 1779.677 260864 +1447 1786.005 260864 +1448 1792.356 260872 +1449 1798.73 260872 +1450 1805.126 260880 +1451 1811.545 260888 +1452 1817.986 260896 +1453 1824.451 260896 +1454 1830.939 260904 +1455 1837.45 260904 +1456 1843.984 260912 +1457 1850.541 260920 +1458 1857.121 260920 +1459 1863.725 260928 +1460 1870.353 260928 +1461 1877.004 260936 +1462 1883.678 260944 +1463 1890.376 260952 +1464 1897.099 260960 +1465 1903.845 260952 +1466 1910.615 260960 +1467 1917.408 260960 +1468 1924.227 260968 +1469 1931.069 260976 +1470 1937.937 260984 +1471 1944.828 260984 +1472 1951.743 260992 +1473 1958.684 261000 +1474 1965.649 261000 +1475 1972.639 261008 +1476 1979.653 261008 +1477 1986.693 261016 +1478 1993.757 261016 +1479 2000.847 261024 +1480 2007.962 261032 +1481 2015.102 261032 +1482 2022.268 261040 +1483 2029.459 261040 +1484 2036.676 261048 +1485 2043.918 261048 +1486 2051.187 261056 +1487 2058.481 261064 +1488 2065.8 261072 +1489 2073.146 261072 +1490 2080.518 261072 +1491 2087.917 261072 +1492 2095.341 261080 +1493 2102.792 261088 +1494 2110.269 261096 +1495 2117.773 261096 +1496 2125.304 261096 +1497 2132.862 261104 +1498 2140.446 261112 +1499 2148.057 261112 +1500 2155.696 261120 +1501 2163.362 261120 +1502 2171.055 261128 +1503 2178.774 261128 +1504 2186.522 261136 +1505 2194.297 261144 +1506 2202.1 261136 +1507 2209.931 261144 +1508 2217.789 261152 +1509 2225.675 261160 +1510 2233.59 261160 +1511 2241.533 261160 +1512 2249.504 261168 +1513 2257.502 261168 +1514 2265.53 261176 +1515 2273.586 261184 +1516 2281.671 261184 +1517 2289.785 261192 +1518 2297.928 261192 +1519 2306.098 261200 +1520 2314.299 261200 +1521 2322.529 261208 +1522 2330.788 261208 +1523 2339.076 261216 +1524 2347.393 261216 +1525 2355.74 261224 +1526 2364.118 261224 +1527 2372.524 261232 +1528 2380.961 261232 +1529 2389.427 261232 +1530 2397.924 261240 +1531 2406.451 261248 +1532 2415.009 261248 +1533 2423.596 261256 +1534 2432.214 261256 +1535 2440.863 261256 +1536 2449.543 261264 +1537 2458.253 261272 +1538 2466.995 261272 +1539 2475.767 261272 +1540 2484.571 261280 +1541 2493.406 261280 +1542 2502.273 261288 +1543 2511.171 261288 +1544 2520.1 261296 +1545 2529.062 261296 +1546 2538.055 261304 +1547 2547.08 261304 +1548 2556.138 261304 +1549 2565.227 261312 +1550 2574.349 261312 +1551 2583.503 261320 +1552 2592.69 261320 +1553 2601.91 261320 +1554 2611.162 261328 +1555 2620.447 261336 +1556 2629.765 261336 +1557 2639.117 261336 +1558 2648.502 261344 +1559 2657.92 261344 +1560 2667.371 261352 +1561 2676.856 261352 +1562 2686.375 261360 +1563 2695.928 261360 +1564 2705.515 261360 +1565 2715.134 261368 +1566 2724.79 261376 +1567 2734.479 261376 +1568 2744.203 261376 +1569 2753.961 261384 +1570 2763.754 261384 +1571 2773.582 261392 +1572 2783.445 261392 +1573 2793.343 261392 +1574 2803.276 261400 +1575 2813.243 261400 +1576 2823.247 261400 +1577 2833.287 261408 +1578 2843.362 261408 +1579 2853.474 261416 +1580 2863.62 261416 +1581 2873.803 261416 +1582 2884.022 261424 +1583 2894.278 261432 +1584 2904.57 261432 +1585 2914.897 261432 +1586 2925.263 261440 +1587 2935.666 261440 +1588 2946.105 261440 +1589 2956.582 261448 +1590 2967.094 261448 +1591 2977.645 261456 +1592 2988.234 261456 +1593 2998.86 261464 +1594 3009.524 261456 +1595 3020.225 261464 +1596 3030.965 261464 +1597 3041.743 261472 +1598 3052.56 261472 +1599 3063.415 261472 +1600 3074.309 261480 +1601 3085.24 261480 +1602 3096.211 261480 +1603 3107.221 261488 +1604 3118.271 261496 +1605 3129.36 261496 +1606 3140.486 261496 +1607 3151.654 261496 +1608 3162.862 261504 +1609 3174.109 261504 +1610 3185.396 261512 +1611 3196.722 261512 +1612 3208.09 261520 +1613 3219.498 261520 +1614 3230.947 261520 +1615 3242.436 261520 +1616 3253.965 261528 +1617 3265.536 261528 +1618 3277.149 261536 +1619 3288.802 261536 +1620 3300.498 261544 +1621 3312.233 261544 +1622 3324.011 261544 +1623 3335.832 261544 +1624 3347.694 261552 +1625 3359.599 261552 +1626 3371.544 261552 +1627 3383.534 261560 +1628 3395.566 261560 +1629 3407.64 261568 +1630 3419.758 261568 +1631 3431.918 261568 +1632 3444.122 261568 +1633 3456.369 261576 +1634 3468.66 261576 +1635 3480.995 261584 +1636 3493.372 261584 +1637 3505.794 261584 +1638 3518.261 261584 +1639 3530.772 261592 +1640 3543.328 261592 +1641 3555.927 261592 +1642 3568.572 261600 +1643 3581.262 261600 +1644 3593.997 261608 +1645 3606.778 261608 +1646 3619.604 261608 +1647 3632.474 261608 +1648 3645.391 261616 +1649 3658.354 261616 +1650 3671.363 261616 +1651 3684.419 261624 +1652 3697.519 261624 +1653 3710.667 261632 +1654 3723.863 261624 +1655 3737.105 261624 +1656 3750.395 261632 +1657 3763.729 261632 +1658 3777.114 261632 +1659 3790.545 261640 +1660 3804.025 261640 +1661 3817.552 261648 +1662 3831.126 261648 +1663 3844.75 261648 +1664 3858.422 261648 +1665 3872.142 261656 +1666 3885.912 261656 +1667 3899.729 261656 +1668 3913.596 261664 +1669 3927.513 261664 +1670 3941.48 261672 +1671 3955.496 261672 +1672 3969.56 261672 +1673 3983.676 261672 +1674 3997.842 261672 +1675 4012.059 261680 +1676 4026.326 261680 +1677 4040.642 261680 +1678 4055.011 261680 +1679 4069.431 261688 +1680 4083.902 261688 +1681 4098.424 261688 +1682 4112.997 261696 +1683 4127.623 261696 +1684 4142.301 261696 +1685 4157.031 261704 +1686 4171.814 261704 +1687 4186.649 261704 +1688 4201.535 261704 +1689 4216.476 261712 +1690 4231.47 261712 +1691 4246.518 261712 +1692 4261.618 261712 +1693 4276.771 261720 +1694 4291.979 261720 +1695 4307.242 261720 +1696 4322.559 261728 +1697 4337.93 261728 +1698 4353.354 261728 +1699 4368.835 261728 +1700 4384.37 261736 +1701 4399.961 261736 +1702 4415.608 261736 +1703 4431.308 261736 +1704 4447.066 261744 +1705 4462.88 261744 +1706 4478.75 261744 +1707 4494.677 261752 +1708 4510.659 261752 +1709 4526.699 261760 +1710 4542.796 261752 +1711 4558.95 261752 +1712 4575.162 261760 +1713 4591.43 261760 +1714 4607.757 261760 +1715 4624.143 261760 +1716 4640.586 261768 +1717 4657.088 261768 +1718 4673.647 261768 +1719 4690.267 261768 +1720 4706.946 261776 +1721 4723.684 261776 +1722 4740.482 261784 +1723 4757.337 261784 +1724 4774.255 261784 +1725 4791.232 261784 +1726 4808.27 261784 +1727 4825.369 261784 +1728 4842.525 261792 +1729 4859.746 261792 +1730 4877.027 261792 +1731 4894.37 261800 +1732 4911.775 261800 +1733 4929.242 261800 +1734 4946.768 261808 +1735 4964.359 261800 +1736 4982.013 261800 +1737 4999.729 261808 +1738 5017.508 261808 +1739 5035.349 261816 +1740 5053.254 261816 +1741 5071.224 261816 +1742 5089.257 261816 +1743 5107.355 261816 +1744 5125.515 261816 +1745 5143.742 261824 +1746 5162.033 261824 +1747 5180.39 261824 +1748 5198.811 261824 +1749 5217.296 261832 +1750 5235.849 261832 +1751 5254.468 261832 +1752 5273.154 261840 +1753 5291.905 261832 +1754 5310.721 261840 +1755 5329.606 261840 +1756 5348.559 261840 +1757 5367.578 261840 +1758 5386.666 261848 +1759 5405.819 261848 +1760 5425.042 261848 +1761 5444.334 261848 +1762 5463.695 261848 +1763 5483.123 261848 +1764 5502.62 261856 +1765 5522.188 261856 +1766 5541.824 261856 +1767 5561.531 261856 +1768 5581.308 261856 +1769 5601.153 261864 +1770 5621.072 261864 +1771 5641.06 261864 +1772 5661.12 261864 +1773 5681.251 261864 +1774 5701.455 261872 +1775 5721.727 261872 +1776 5742.073 261880 +1777 5762.492 261880 +1778 5782.984 261880 +1779 5803.549 261880 +1780 5824.184 261880 +1781 5844.895 261880 +1782 5865.68 261880 +1783 5886.538 261880 +1784 5907.472 261888 +1785 5928.476 261888 +1786 5949.558 261888 +1787 5970.715 261888 +1788 5991.947 261896 +1789 6013.255 261896 +1790 6034.636 261896 +1791 6056.096 261904 +1792 6077.631 261904 +1793 6099.243 261904 +1794 6120.933 261904 +1795 6142.696 261904 +1796 6164.54 261904 +1797 6186.462 261904 +1798 6208.461 261912 +1799 6230.539 261912 +1800 6252.692 261912 +1801 6274.927 261912 +1802 6297.241 261912 +1803 6319.634 261912 +1804 6342.107 261912 +1805 6364.657 261920 +1806 6387.29 261920 +1807 6410.004 261920 +1808 6432.798 261920 +1809 6455.673 261920 +1810 6478.627 261928 +1811 6501.666 261928 +1812 6524.786 261928 +1813 6547.989 261928 +1814 6571.273 261936 +1815 6594.642 261936 +1816 6618.09 261936 +1817 6641.624 261936 +1818 6665.242 261936 +1819 6688.944 261936 +1820 6712.73 261936 +1821 6736.598 261944 +1822 6760.554 261944 +1823 6784.595 261944 +1824 6808.721 261944 +1825 6832.933 261944 +1826 6857.229 261944 +1827 6881.613 261952 +1828 6906.084 261952 +1829 6930.643 261952 +1830 6955.289 261952 +1831 6980.019 261960 +1832 7004.841 261952 +1833 7029.75 261952 +1834 7054.748 261960 +1835 7079.835 261960 +1836 7105.009 261960 +1837 7130.274 261960 +1838 7155.629 261968 +1839 7181.076 261968 +1840 7206.612 261968 +1841 7232.236 261968 +1842 7257.955 261976 +1843 7283.764 261976 +1844 7309.666 261976 +1845 7335.659 261976 +1846 7361.742 261976 +1847 7387.921 261976 +1848 7414.193 261976 +1849 7440.558 261976 +1850 7467.016 261976 +1851 7493.566 261984 +1852 7520.214 261976 +1853 7546.957 261984 +1854 7573.794 261984 +1855 7600.727 261984 +1856 7627.755 261984 +1857 7654.877 261984 +1858 7682.098 261992 +1859 7709.416 261984 +1860 7736.831 261992 +1861 7764.344 261992 +1862 7791.95 261992 +1863 7819.66 261992 +1864 7847.466 261992 +1865 7875.373 262000 +1866 7903.378 262000 +1867 7931.479 262000 +1868 7959.684 262000 +1869 7987.989 262000 +1870 8016.395 262000 +1871 8044.901 262000 +1872 8073.506 262008 +1873 8102.216 262008 +1874 8131.027 262008 +1875 8159.942 262008 +1876 8188.959 262008 +1877 8218.076 262016 +1878 8247.3 262016 +1879 8276.628 262016 +1880 8306.061 262016 +1881 8335.597 262016 +1882 8365.234 262016 +1883 8394.982 262016 +1884 8424.835 262016 +1885 8454.794 262024 +1886 8484.86 262016 +1887 8515.029 262024 +1888 8545.31 262016 +1889 8575.697 262024 +1890 8606.192 262024 +1891 8636.796 262024 +1892 8667.505 262024 +1893 8698.328 262032 +1894 8729.26 262032 +1895 8760.301 262032 +1896 8791.453 262032 +1897 8822.712 262032 +1898 8854.087 262032 +1899 8885.572 262040 +1900 8917.169 262040 +1901 8948.88 262040 +1902 8980.702 262032 +1903 9012.634 262040 +1904 9044.684 262040 +1905 9076.847 262040 +1906 9109.124 262048 +1907 9141.517 262040 +1908 9174.021 262048 +1909 9206.645 262048 +1910 9239.384 262048 +1911 9272.239 262040 +1912 9305.212 262048 +1913 9338.298 262048 +1914 9371.505 262048 +1915 9404.831 262048 +1916 9438.274 262048 +1917 9471.838 262056 +1918 9505.516 262056 +1919 9539.318 262056 +1920 9573.24 262056 +1921 9607.283 262056 +1922 9641.447 262056 +1923 9675.729 262056 +1924 9710.137 262056 +1925 9744.666 262064 +1926 9779.319 262064 +1927 9814.095 262064 +1928 9848.99 262064 +1929 9884.014 262064 +1930 9919.161 262064 +1931 9954.435 262064 +1932 9989.833 262064 +1933 10025.35 262072 +1934 10061 262072 +1935 10096.78 262072 +1936 10132.69 262072 +1937 10168.72 262072 +1938 10204.88 262072 +1939 10241.16 262080 +1940 10277.58 262072 +1941 10314.13 262072 +1942 10350.81 262072 +1943 10387.61 262080 +1944 10424.55 262072 +1945 10461.62 262072 +1946 10498.82 262080 +1947 10536.16 262080 +1948 10573.62 262080 +1949 10611.22 262080 +1950 10648.95 262088 +1951 10686.82 262088 +1952 10724.82 262088 +1953 10762.96 262088 +1954 10801.23 262088 +1955 10839.64 262088 +1956 10878.19 262088 +1957 10916.87 262096 +1958 10955.69 262088 +1959 10994.65 262096 +1960 11033.74 262088 +1961 11072.98 262088 +1962 11112.36 262096 +1963 11151.87 262096 +1964 11191.52 262088 +1965 11231.32 262096 +1966 11271.26 262096 +1967 11311.34 262096 +1968 11351.57 262096 +1969 11391.93 262096 +1970 11432.44 262104 +1971 11473.09 262104 +1972 11513.89 262104 +1973 11554.84 262096 +1974 11595.92 262096 +1975 11637.16 262104 +1976 11678.54 262104 +1977 11720.07 262104 +1978 11761.75 262104 +1979 11803.57 262112 +1980 11845.54 262104 +1981 11887.66 262104 +1982 11929.94 262112 +1983 11972.36 262104 +1984 12014.93 262112 +1985 12057.65 262112 +1986 12100.53 262120 +1987 12143.56 262120 +1988 12186.75 262112 +1989 12230.08 262112 +1990 12273.57 262112 +1991 12317.21 262112 +1992 12361.01 262112 +1993 12404.97 262120 +1994 12449.08 262112 +1995 12493.35 262120 +1996 12537.77 262120 +1997 12582.36 262120 +1998 12627.1 262120 +1999 12672 262120 diff --git a/tests/depth/near10_far150.txt b/tests/depth/near10_far150.txt new file mode 100644 index 00000000..dd7b033d --- /dev/null +++ b/tests/depth/near10_far150.txt @@ -0,0 +1,2002 @@ +# rom=t3d_98_depthtest.z64 preset=2 near=10 far=150 steps=2000 +# step w z18 +0 10.5 13312 +1 10.51393 13696 +2 10.52787 14016 +3 10.54183 14400 +4 10.55581 14720 +5 10.56981 15104 +6 10.58383 15424 +7 10.59786 15808 +8 10.61191 16128 +9 10.62599 16512 +10 10.64008 16832 +11 10.65419 17216 +12 10.66832 17536 +13 10.68247 17920 +14 10.69663 18240 +15 10.71082 18624 +16 10.72502 18944 +17 10.73925 19264 +18 10.75349 19648 +19 10.76775 19968 +20 10.78203 20352 +21 10.79633 20672 +22 10.81064 20992 +23 10.82498 21376 +24 10.83934 21696 +25 10.85371 22080 +26 10.8681 22400 +27 10.88252 22720 +28 10.89695 23104 +29 10.9114 23424 +30 10.92587 23744 +31 10.94036 24128 +32 10.95487 24448 +33 10.96939 24768 +34 10.98394 25088 +35 10.99851 25472 +36 11.01309 25792 +37 11.0277 26112 +38 11.04232 26496 +39 11.05697 26816 +40 11.07163 27136 +41 11.08631 27456 +42 11.10102 27840 +43 11.11574 28160 +44 11.13048 28480 +45 11.14524 28800 +46 11.16002 29184 +47 11.17482 29504 +48 11.18964 29824 +49 11.20448 30144 +50 11.21934 30464 +51 11.23421 30784 +52 11.24911 31168 +53 11.26403 31488 +54 11.27897 31808 +55 11.29393 32128 +56 11.3089 32448 +57 11.3239 32768 +58 11.33892 33152 +59 11.35395 33472 +60 11.36901 33792 +61 11.38409 34112 +62 11.39918 34432 +63 11.4143 34752 +64 11.42944 35072 +65 11.4446 35392 +66 11.45977 35712 +67 11.47497 36032 +68 11.49019 36352 +69 11.50543 36672 +70 11.52068 37056 +71 11.53596 37376 +72 11.55126 37696 +73 11.56658 38016 +74 11.58192 38336 +75 11.59728 38656 +76 11.61266 38976 +77 11.62806 39296 +78 11.64348 39616 +79 11.65892 39936 +80 11.67438 40256 +81 11.68986 40576 +82 11.70536 40896 +83 11.72089 41216 +84 11.73643 41536 +85 11.752 41856 +86 11.76758 42112 +87 11.78319 42432 +88 11.79881 42752 +89 11.81446 43072 +90 11.83013 43392 +91 11.84582 43712 +92 11.86152 44032 +93 11.87725 44352 +94 11.89301 44672 +95 11.90878 44992 +96 11.92457 45312 +97 11.94038 45632 +98 11.95622 45888 +99 11.97207 46208 +100 11.98795 46528 +101 12.00385 46848 +102 12.01977 47168 +103 12.03571 47488 +104 12.05167 47744 +105 12.06765 48064 +106 12.08365 48384 +107 12.09968 48704 +108 12.11572 49024 +109 12.13179 49280 +110 12.14788 49600 +111 12.16399 49920 +112 12.18012 50240 +113 12.19627 50560 +114 12.21245 50816 +115 12.22864 51136 +116 12.24486 51456 +117 12.2611 51776 +118 12.27736 52032 +119 12.29364 52352 +120 12.30994 52672 +121 12.32627 52992 +122 12.34262 53248 +123 12.35898 53568 +124 12.37537 53888 +125 12.39178 54144 +126 12.40822 54464 +127 12.42467 54784 +128 12.44115 55040 +129 12.45765 55360 +130 12.47417 55680 +131 12.49071 55936 +132 12.50728 56256 +133 12.52386 56576 +134 12.54047 56832 +135 12.5571 57152 +136 12.57376 57472 +137 12.59043 57728 +138 12.60713 58048 +139 12.62384 58304 +140 12.64059 58624 +141 12.65735 58944 +142 12.67414 59200 +143 12.69094 59520 +144 12.70777 59776 +145 12.72462 60096 +146 12.7415 60416 +147 12.7584 60672 +148 12.77532 60992 +149 12.79226 61248 +150 12.80922 61568 +151 12.82621 61824 +152 12.84322 62144 +153 12.86025 62400 +154 12.87731 62720 +155 12.89438 62976 +156 12.91148 63296 +157 12.92861 63552 +158 12.94575 63872 +159 12.96292 64128 +160 12.98011 64448 +161 12.99732 64704 +162 13.01456 65024 +163 13.03182 65280 +164 13.0491 65600 +165 13.0664 65856 +166 13.08373 66176 +167 13.10108 66432 +168 13.11846 66752 +169 13.13585 67008 +170 13.15327 67264 +171 13.17072 67584 +172 13.18818 67840 +173 13.20567 68160 +174 13.22319 68416 +175 13.24072 68736 +176 13.25828 68992 +177 13.27586 69248 +178 13.29347 69568 +179 13.3111 69824 +180 13.32875 70080 +181 13.34643 70400 +182 13.36413 70656 +183 13.38185 70912 +184 13.3996 71232 +185 13.41737 71488 +186 13.43516 71744 +187 13.45297 72064 +188 13.47082 72320 +189 13.48868 72576 +190 13.50657 72896 +191 13.52448 73152 +192 13.54241 73408 +193 13.56037 73728 +194 13.57836 73984 +195 13.59636 74240 +196 13.6144 74496 +197 13.63245 74816 +198 13.65053 75072 +199 13.66863 75328 +200 13.68676 75648 +201 13.70491 75904 +202 13.72308 76160 +203 13.74128 76416 +204 13.7595 76672 +205 13.77775 76992 +206 13.79602 77248 +207 13.81432 77504 +208 13.83264 77760 +209 13.85098 78016 +210 13.86935 78336 +211 13.88774 78592 +212 13.90616 78848 +213 13.9246 79104 +214 13.94307 79360 +215 13.96156 79680 +216 13.98007 79936 +217 13.99861 80192 +218 14.01718 80448 +219 14.03577 80704 +220 14.05438 80960 +221 14.07302 81216 +222 14.09168 81536 +223 14.11037 81792 +224 14.12908 82048 +225 14.14782 82304 +226 14.16658 82560 +227 14.18537 82816 +228 14.20418 83072 +229 14.22302 83328 +230 14.24188 83584 +231 14.26077 83904 +232 14.27968 84160 +233 14.29861 84416 +234 14.31758 84672 +235 14.33656 84928 +236 14.35558 85184 +237 14.37461 85440 +238 14.39368 85696 +239 14.41276 85952 +240 14.43188 86208 +241 14.45102 86464 +242 14.47018 86720 +243 14.48937 86976 +244 14.50858 87232 +245 14.52783 87488 +246 14.54709 87744 +247 14.56638 88000 +248 14.5857 88256 +249 14.60504 88512 +250 14.62441 88768 +251 14.6438 89024 +252 14.66323 89280 +253 14.68267 89536 +254 14.70214 89792 +255 14.72164 90048 +256 14.74116 90304 +257 14.76071 90560 +258 14.78029 90816 +259 14.79989 91072 +260 14.81951 91328 +261 14.83917 91584 +262 14.85885 91776 +263 14.87855 92032 +264 14.89828 92288 +265 14.91804 92544 +266 14.93782 92800 +267 14.95763 93056 +268 14.97747 93312 +269 14.99733 93568 +270 15.01722 93824 +271 15.03713 94016 +272 15.05708 94272 +273 15.07704 94528 +274 15.09704 94784 +275 15.11706 95040 +276 15.13711 95296 +277 15.15718 95552 +278 15.17728 95744 +279 15.19741 96000 +280 15.21756 96256 +281 15.23774 96512 +282 15.25795 96768 +283 15.27818 96960 +284 15.29844 97216 +285 15.31873 97472 +286 15.33905 97728 +287 15.35939 97984 +288 15.37976 98176 +289 15.40016 98432 +290 15.42058 98688 +291 15.44103 98944 +292 15.4615 99200 +293 15.48201 99392 +294 15.50254 99648 +295 15.5231 99904 +296 15.54368 100160 +297 15.5643 100352 +298 15.58494 100608 +299 15.60561 100864 +300 15.6263 101056 +301 15.64703 101312 +302 15.66778 101568 +303 15.68855 101824 +304 15.70936 102016 +305 15.73019 102272 +306 15.75105 102528 +307 15.77194 102720 +308 15.79286 102976 +309 15.8138 103232 +310 15.83477 103424 +311 15.85577 103680 +312 15.8768 103936 +313 15.89785 104128 +314 15.91894 104384 +315 15.94005 104640 +316 15.96118 104832 +317 15.98235 105088 +318 16.00355 105344 +319 16.02477 105536 +320 16.04602 105792 +321 16.0673 106048 +322 16.08861 106240 +323 16.10994 106496 +324 16.13131 106688 +325 16.1527 106944 +326 16.17412 107200 +327 16.19557 107392 +328 16.21705 107648 +329 16.23855 107840 +330 16.26009 108096 +331 16.28165 108352 +332 16.30324 108544 +333 16.32487 108800 +334 16.34651 108992 +335 16.36819 109248 +336 16.3899 109440 +337 16.41163 109696 +338 16.4334 109888 +339 16.45519 110144 +340 16.47701 110336 +341 16.49886 110592 +342 16.52074 110848 +343 16.54265 111040 +344 16.56459 111296 +345 16.58656 111488 +346 16.60855 111744 +347 16.63058 111936 +348 16.65263 112192 +349 16.67472 112384 +350 16.69683 112640 +351 16.71897 112832 +352 16.74114 113024 +353 16.76335 113280 +354 16.78558 113472 +355 16.80784 113728 +356 16.83013 113920 +357 16.85245 114176 +358 16.87479 114368 +359 16.89717 114624 +360 16.91958 114816 +361 16.94202 115072 +362 16.96449 115264 +363 16.98698 115456 +364 17.00951 115712 +365 17.03207 115904 +366 17.05466 116160 +367 17.07727 116352 +368 17.09992 116608 +369 17.1226 116800 +370 17.1453 116992 +371 17.16804 117248 +372 17.19081 117440 +373 17.2136 117632 +374 17.23643 117888 +375 17.25929 118080 +376 17.28218 118336 +377 17.3051 118528 +378 17.32805 118720 +379 17.35103 118976 +380 17.37404 119168 +381 17.39708 119360 +382 17.42015 119616 +383 17.44325 119808 +384 17.46638 120000 +385 17.48954 120256 +386 17.51274 120448 +387 17.53596 120640 +388 17.55922 120896 +389 17.5825 121088 +390 17.60582 121280 +391 17.62917 121536 +392 17.65255 121728 +393 17.67596 121920 +394 17.6994 122112 +395 17.72287 122368 +396 17.74637 122560 +397 17.76991 122752 +398 17.79347 123008 +399 17.81707 123200 +400 17.8407 123392 +401 17.86436 123584 +402 17.88805 123840 +403 17.91177 124032 +404 17.93552 124224 +405 17.95931 124416 +406 17.98313 124672 +407 18.00698 124864 +408 18.03086 125056 +409 18.05477 125248 +410 18.07871 125440 +411 18.10268 125696 +412 18.12669 125888 +413 18.15073 126080 +414 18.1748 126272 +415 18.1989 126464 +416 18.22304 126720 +417 18.2472 126912 +418 18.2714 127104 +419 18.29563 127296 +420 18.31989 127488 +421 18.34419 127744 +422 18.36852 127936 +423 18.39288 128128 +424 18.41727 128320 +425 18.44169 128512 +426 18.46615 128704 +427 18.49064 128960 +428 18.51516 129152 +429 18.53971 129344 +430 18.5643 129536 +431 18.58892 129728 +432 18.61357 129920 +433 18.63825 130112 +434 18.66297 130304 +435 18.68772 130560 +436 18.7125 130752 +437 18.73732 130944 +438 18.76217 131136 +439 18.78705 131328 +440 18.81196 131552 +441 18.83691 131744 +442 18.86189 131936 +443 18.8869 132128 +444 18.91195 132320 +445 18.93703 132512 +446 18.96214 132736 +447 18.98729 132928 +448 19.01247 133120 +449 19.03768 133312 +450 19.06293 133504 +451 19.08821 133696 +452 19.11353 133888 +453 19.13887 134080 +454 19.16425 134272 +455 19.18967 134464 +456 19.21512 134688 +457 19.2406 134880 +458 19.26611 135072 +459 19.29166 135264 +460 19.31725 135456 +461 19.34286 135648 +462 19.36852 135840 +463 19.3942 136032 +464 19.41992 136224 +465 19.44567 136416 +466 19.47146 136608 +467 19.49728 136800 +468 19.52314 136992 +469 19.54903 137184 +470 19.57496 137376 +471 19.60092 137536 +472 19.62691 137728 +473 19.65294 137920 +474 19.679 138112 +475 19.7051 138304 +476 19.73123 138496 +477 19.75739 138688 +478 19.7836 138880 +479 19.80983 139072 +480 19.8361 139264 +481 19.86241 139424 +482 19.88875 139616 +483 19.91512 139808 +484 19.94154 140000 +485 19.96798 140192 +486 19.99446 140384 +487 20.02098 140544 +488 20.04753 140736 +489 20.07411 140928 +490 20.10073 141120 +491 20.12739 141312 +492 20.15408 141472 +493 20.18081 141664 +494 20.20757 141856 +495 20.23437 142048 +496 20.2612 142208 +497 20.28807 142400 +498 20.31498 142592 +499 20.34192 142784 +500 20.3689 142944 +501 20.39591 143136 +502 20.42296 143328 +503 20.45004 143488 +504 20.47716 143680 +505 20.50431 143872 +506 20.53151 144032 +507 20.55873 144224 +508 20.586 144416 +509 20.6133 144576 +510 20.64063 144768 +511 20.66801 144960 +512 20.69542 145120 +513 20.72286 145312 +514 20.75034 145472 +515 20.77786 145664 +516 20.80541 145856 +517 20.83301 146016 +518 20.86063 146208 +519 20.8883 146368 +520 20.916 146560 +521 20.94374 146752 +522 20.97151 146912 +523 20.99932 147104 +524 21.02717 147264 +525 21.05506 147456 +526 21.08298 147616 +527 21.11094 147808 +528 21.13893 147968 +529 21.16697 148160 +530 21.19504 148320 +531 21.22314 148512 +532 21.25129 148672 +533 21.27947 148864 +534 21.30769 149024 +535 21.33595 149216 +536 21.36424 149376 +537 21.39257 149536 +538 21.42095 149728 +539 21.44935 149888 +540 21.4778 150080 +541 21.50628 150240 +542 21.5348 150432 +543 21.56336 150592 +544 21.59196 150752 +545 21.62059 150944 +546 21.64926 151104 +547 21.67797 151264 +548 21.70672 151456 +549 21.73551 151616 +550 21.76433 151808 +551 21.79319 151968 +552 21.82209 152128 +553 21.85103 152320 +554 21.88001 152480 +555 21.90903 152640 +556 21.93808 152800 +557 21.96717 152992 +558 21.99631 153152 +559 22.02548 153312 +560 22.05469 153504 +561 22.08393 153664 +562 22.11322 153824 +563 22.14254 153984 +564 22.17191 154176 +565 22.20131 154336 +566 22.23075 154496 +567 22.26024 154656 +568 22.28976 154848 +569 22.31932 155008 +570 22.34892 155168 +571 22.37855 155328 +572 22.40823 155488 +573 22.43794 155680 +574 22.4677 155840 +575 22.4975 156000 +576 22.52733 156160 +577 22.55721 156320 +578 22.58712 156480 +579 22.61707 156672 +580 22.64707 156832 +581 22.6771 156992 +582 22.70718 157152 +583 22.73729 157312 +584 22.76744 157472 +585 22.79763 157632 +586 22.82787 157792 +587 22.85814 157984 +588 22.88845 158144 +589 22.91881 158304 +590 22.9492 158464 +591 22.97964 158624 +592 23.01011 158784 +593 23.04062 158944 +594 23.07118 159104 +595 23.10178 159264 +596 23.13241 159424 +597 23.16309 159584 +598 23.19381 159744 +599 23.22456 159904 +600 23.25536 160064 +601 23.2862 160224 +602 23.31709 160384 +603 23.348 160544 +604 23.37897 160704 +605 23.40997 160864 +606 23.44102 161024 +607 23.47211 161184 +608 23.50323 161344 +609 23.5344 161504 +610 23.56561 161664 +611 23.59686 161824 +612 23.62815 161984 +613 23.65949 162144 +614 23.69086 162304 +615 23.72228 162432 +616 23.75374 162592 +617 23.78524 162752 +618 23.81679 162912 +619 23.84837 163072 +620 23.88 163232 +621 23.91166 163392 +622 23.94337 163552 +623 23.97513 163680 +624 24.00692 163840 +625 24.03876 164000 +626 24.07064 164160 +627 24.10256 164320 +628 24.13452 164480 +629 24.16653 164608 +630 24.19858 164768 +631 24.23067 164928 +632 24.2628 165088 +633 24.29498 165248 +634 24.32719 165376 +635 24.35946 165536 +636 24.39176 165696 +637 24.42411 165856 +638 24.4565 165984 +639 24.48893 166144 +640 24.52141 166304 +641 24.55393 166464 +642 24.58649 166592 +643 24.61909 166752 +644 24.65174 166912 +645 24.68443 167072 +646 24.71717 167200 +647 24.74995 167360 +648 24.78277 167520 +649 24.81564 167648 +650 24.84855 167808 +651 24.8815 167968 +652 24.91449 168096 +653 24.94753 168256 +654 24.98062 168416 +655 25.01375 168544 +656 25.04692 168704 +657 25.08013 168864 +658 25.11339 168992 +659 25.1467 169152 +660 25.18004 169312 +661 25.21344 169440 +662 25.24687 169600 +663 25.28036 169728 +664 25.31388 169888 +665 25.34745 170048 +666 25.38107 170176 +667 25.41472 170336 +668 25.44843 170464 +669 25.48218 170624 +670 25.51597 170784 +671 25.54981 170912 +672 25.58369 171072 +673 25.61762 171200 +674 25.65159 171360 +675 25.68561 171488 +676 25.71967 171648 +677 25.75378 171776 +678 25.78793 171936 +679 25.82213 172064 +680 25.85637 172224 +681 25.89067 172352 +682 25.925 172512 +683 25.95938 172640 +684 25.9938 172800 +685 26.02828 172928 +686 26.06279 173088 +687 26.09736 173216 +688 26.13197 173376 +689 26.16662 173504 +690 26.20132 173632 +691 26.23607 173792 +692 26.27086 173920 +693 26.3057 174080 +694 26.34059 174208 +695 26.37552 174368 +696 26.4105 174496 +697 26.44552 174624 +698 26.48059 174784 +699 26.51571 174912 +700 26.55087 175072 +701 26.58608 175200 +702 26.62134 175328 +703 26.65664 175488 +704 26.69199 175616 +705 26.72739 175744 +706 26.76283 175904 +707 26.79833 176032 +708 26.83386 176160 +709 26.86945 176320 +710 26.90508 176448 +711 26.94076 176576 +712 26.97649 176736 +713 27.01226 176864 +714 27.04809 176992 +715 27.08396 177152 +716 27.11987 177280 +717 27.15584 177408 +718 27.19185 177536 +719 27.22791 177696 +720 27.26402 177824 +721 27.30017 177952 +722 27.33638 178112 +723 27.37263 178240 +724 27.40893 178368 +725 27.44528 178496 +726 27.48168 178656 +727 27.51812 178784 +728 27.55462 178912 +729 27.59116 179040 +730 27.62775 179168 +731 27.66438 179328 +732 27.70107 179456 +733 27.73781 179584 +734 27.77459 179712 +735 27.81142 179840 +736 27.8483 180000 +737 27.88524 180128 +738 27.92222 180256 +739 27.95925 180384 +740 27.99632 180512 +741 28.03345 180640 +742 28.07063 180800 +743 28.10785 180928 +744 28.14513 181056 +745 28.18245 181184 +746 28.21983 181312 +747 28.25725 181440 +748 28.29473 181568 +749 28.33225 181696 +750 28.36982 181856 +751 28.40744 181984 +752 28.44511 182112 +753 28.48284 182240 +754 28.52061 182368 +755 28.55843 182496 +756 28.59631 182624 +757 28.63423 182752 +758 28.6722 182880 +759 28.71023 183008 +760 28.7483 183136 +761 28.78642 183264 +762 28.8246 183392 +763 28.86282 183520 +764 28.9011 183648 +765 28.93943 183776 +766 28.9778 183904 +767 29.01623 184032 +768 29.05471 184160 +769 29.09325 184288 +770 29.13183 184416 +771 29.17046 184544 +772 29.20914 184672 +773 29.24788 184800 +774 29.28667 184928 +775 29.3255 185056 +776 29.36439 185184 +777 29.40333 185312 +778 29.44233 185440 +779 29.48137 185568 +780 29.52047 185696 +781 29.55962 185824 +782 29.59882 185952 +783 29.63807 186080 +784 29.67738 186208 +785 29.71673 186336 +786 29.75614 186464 +787 29.7956 186592 +788 29.83512 186720 +789 29.87468 186816 +790 29.9143 186944 +791 29.95397 187072 +792 29.99369 187200 +793 30.03347 187328 +794 30.0733 187456 +795 30.11318 187584 +796 30.15311 187680 +797 30.1931 187808 +798 30.23314 187936 +799 30.27324 188064 +800 30.31338 188192 +801 30.35358 188320 +802 30.39384 188448 +803 30.43414 188544 +804 30.4745 188672 +805 30.51492 188800 +806 30.55538 188928 +807 30.5959 189056 +808 30.63648 189152 +809 30.67711 189280 +810 30.71779 189408 +811 30.75852 189536 +812 30.79932 189664 +813 30.84016 189760 +814 30.88106 189888 +815 30.92201 190016 +816 30.96302 190144 +817 31.00408 190240 +818 31.0452 190368 +819 31.08637 190496 +820 31.12759 190624 +821 31.16887 190720 +822 31.21021 190848 +823 31.2516 190976 +824 31.29304 191104 +825 31.33454 191200 +826 31.37609 191328 +827 31.4177 191456 +828 31.45937 191552 +829 31.50109 191680 +830 31.54286 191808 +831 31.58469 191904 +832 31.62658 192032 +833 31.66852 192160 +834 31.71052 192256 +835 31.75257 192384 +836 31.79468 192512 +837 31.83684 192608 +838 31.87906 192736 +839 31.92134 192864 +840 31.96367 192960 +841 32.00606 193088 +842 32.0485 193216 +843 32.09101 193312 +844 32.13356 193440 +845 32.17618 193536 +846 32.21885 193664 +847 32.26157 193792 +848 32.30436 193888 +849 32.34719 194016 +850 32.39009 194112 +851 32.43305 194240 +852 32.47606 194368 +853 32.51913 194464 +854 32.56225 194592 +855 32.60543 194688 +856 32.64867 194816 +857 32.69197 194944 +858 32.73532 195040 +859 32.77874 195168 +860 32.82221 195264 +861 32.86574 195392 +862 32.90932 195488 +863 32.95296 195616 +864 32.99666 195712 +865 33.04042 195840 +866 33.08424 195936 +867 33.12811 196064 +868 33.17205 196160 +869 33.21604 196288 +870 33.26009 196384 +871 33.30419 196512 +872 33.34836 196624 +873 33.39258 196736 +874 33.43687 196848 +875 33.48121 196960 +876 33.52561 197072 +877 33.57007 197184 +878 33.61459 197296 +879 33.65917 197408 +880 33.7038 197520 +881 33.7485 197632 +882 33.79325 197744 +883 33.83807 197840 +884 33.88295 197952 +885 33.92788 198064 +886 33.97287 198176 +887 34.01793 198288 +888 34.06303 198400 +889 34.10821 198512 +890 34.15344 198608 +891 34.19873 198720 +892 34.24409 198832 +893 34.2895 198944 +894 34.33498 199040 +895 34.3805 199152 +896 34.4261 199264 +897 34.47176 199376 +898 34.51747 199488 +899 34.56324 199584 +900 34.60908 199696 +901 34.65498 199808 +902 34.70094 199904 +903 34.74695 200016 +904 34.79303 200128 +905 34.83917 200224 +906 34.88537 200336 +907 34.93164 200448 +908 34.97796 200560 +909 35.02435 200656 +910 35.0708 200768 +911 35.1173 200864 +912 35.16388 200976 +913 35.21051 201088 +914 35.2572 201184 +915 35.30396 201296 +916 35.35078 201392 +917 35.39766 201504 +918 35.4446 201600 +919 35.4916 201712 +920 35.53867 201824 +921 35.5858 201920 +922 35.63299 202032 +923 35.68024 202128 +924 35.72756 202240 +925 35.77494 202336 +926 35.82238 202448 +927 35.86989 202544 +928 35.91746 202656 +929 35.96509 202752 +930 36.01279 202864 +931 36.06055 202960 +932 36.10837 203072 +933 36.15625 203168 +934 36.2042 203264 +935 36.25221 203376 +936 36.30029 203472 +937 36.34843 203584 +938 36.39663 203680 +939 36.4449 203776 +940 36.49323 203888 +941 36.54162 203984 +942 36.59008 204080 +943 36.63861 204192 +944 36.68719 204288 +945 36.73585 204400 +946 36.78456 204496 +947 36.83335 204592 +948 36.88219 204704 +949 36.93111 204800 +950 36.98008 204896 +951 37.02913 205008 +952 37.07823 205104 +953 37.1274 205200 +954 37.17663 205296 +955 37.22594 205408 +956 37.27531 205504 +957 37.32474 205600 +958 37.37424 205696 +959 37.4238 205792 +960 37.47343 205904 +961 37.52312 206000 +962 37.57288 206096 +963 37.62271 206192 +964 37.6726 206288 +965 37.72256 206400 +966 37.77259 206496 +967 37.82268 206592 +968 37.87284 206688 +969 37.92307 206784 +970 37.97336 206880 +971 38.02372 206976 +972 38.07414 207088 +973 38.12463 207184 +974 38.17519 207280 +975 38.22581 207376 +976 38.27651 207472 +977 38.32727 207568 +978 38.3781 207664 +979 38.42899 207760 +980 38.47995 207856 +981 38.53099 207952 +982 38.58208 208048 +983 38.63325 208144 +984 38.68448 208240 +985 38.73578 208336 +986 38.78715 208432 +987 38.83859 208528 +988 38.89009 208624 +989 38.94167 208720 +990 38.99331 208816 +991 39.04502 208912 +992 39.0968 209008 +993 39.14865 209104 +994 39.20057 209200 +995 39.25255 209296 +996 39.30461 209392 +997 39.35673 209488 +998 39.40892 209584 +999 39.46119 209680 +1000 39.51352 209776 +1001 39.56591 209856 +1002 39.61839 209952 +1003 39.67093 210048 +1004 39.72354 210144 +1005 39.77622 210240 +1006 39.82897 210336 +1007 39.88178 210416 +1008 39.93467 210512 +1009 39.98763 210608 +1010 40.04066 210704 +1011 40.09377 210800 +1012 40.14693 210896 +1013 40.20017 210976 +1014 40.25348 211072 +1015 40.30687 211168 +1016 40.36032 211264 +1017 40.41384 211360 +1018 40.46744 211440 +1019 40.5211 211536 +1020 40.57484 211632 +1021 40.62865 211712 +1022 40.68252 211808 +1023 40.73648 211904 +1024 40.7905 212000 +1025 40.8446 212080 +1026 40.89877 212176 +1027 40.953 212272 +1028 41.00731 212352 +1029 41.06169 212448 +1030 41.11614 212544 +1031 41.17067 212624 +1032 41.22527 212720 +1033 41.27994 212816 +1034 41.33468 212896 +1035 41.3895 212992 +1036 41.44439 213088 +1037 41.49934 213168 +1038 41.55438 213264 +1039 41.60949 213344 +1040 41.66467 213440 +1041 41.71992 213520 +1042 41.77525 213616 +1043 41.83065 213712 +1044 41.88612 213792 +1045 41.94167 213888 +1046 41.9973 213968 +1047 42.05299 214064 +1048 42.10875 214144 +1049 42.16459 214240 +1050 42.22051 214320 +1051 42.2765 214416 +1052 42.33257 214496 +1053 42.38871 214592 +1054 42.44492 214672 +1055 42.50121 214768 +1056 42.55757 214848 +1057 42.61401 214944 +1058 42.67052 215024 +1059 42.7271 215120 +1060 42.78377 215200 +1061 42.84051 215296 +1062 42.89732 215376 +1063 42.95421 215456 +1064 43.01117 215552 +1065 43.06821 215632 +1066 43.12533 215728 +1067 43.18252 215808 +1068 43.23978 215888 +1069 43.29712 215984 +1070 43.35454 216064 +1071 43.41204 216144 +1072 43.46961 216240 +1073 43.52725 216320 +1074 43.58498 216416 +1075 43.64278 216496 +1076 43.70066 216576 +1077 43.75861 216656 +1078 43.81664 216752 +1079 43.87475 216832 +1080 43.93293 216912 +1081 43.9912 217008 +1082 44.04953 217088 +1083 44.10794 217168 +1084 44.16644 217264 +1085 44.22501 217344 +1086 44.28366 217424 +1087 44.34239 217504 +1088 44.4012 217600 +1089 44.46007 217680 +1090 44.51904 217760 +1091 44.57808 217840 +1092 44.6372 217936 +1093 44.69639 218016 +1094 44.75566 218096 +1095 44.81501 218176 +1096 44.87445 218256 +1097 44.93396 218352 +1098 44.99355 218432 +1099 45.05321 218512 +1100 45.11296 218592 +1101 45.17279 218672 +1102 45.23269 218752 +1103 45.29268 218832 +1104 45.35274 218912 +1105 45.41288 219008 +1106 45.47311 219088 +1107 45.53342 219168 +1108 45.5938 219248 +1109 45.65426 219328 +1110 45.7148 219408 +1111 45.77543 219488 +1112 45.83614 219568 +1113 45.89693 219648 +1114 45.95778 219728 +1115 46.01873 219808 +1116 46.07976 219888 +1117 46.14087 219984 +1118 46.20206 220064 +1119 46.26333 220144 +1120 46.32468 220224 +1121 46.38611 220304 +1122 46.44763 220384 +1123 46.50923 220464 +1124 46.5709 220544 +1125 46.63266 220624 +1126 46.69451 220704 +1127 46.75643 220784 +1128 46.81844 220864 +1129 46.88052 220928 +1130 46.94269 221008 +1131 47.00495 221088 +1132 47.06728 221184 +1133 47.1297 221248 +1134 47.19221 221328 +1135 47.25478 221408 +1136 47.31745 221488 +1137 47.3802 221568 +1138 47.44304 221648 +1139 47.50596 221728 +1140 47.56895 221808 +1141 47.63203 221888 +1142 47.69521 221968 +1143 47.75845 222032 +1144 47.82179 222112 +1145 47.8852 222192 +1146 47.94871 222272 +1147 48.01229 222352 +1148 48.07597 222432 +1149 48.13972 222512 +1150 48.20356 222576 +1151 48.26749 222656 +1152 48.3315 222736 +1153 48.39559 222816 +1154 48.45977 222896 +1155 48.52403 222960 +1156 48.58839 223040 +1157 48.65282 223120 +1158 48.71735 223200 +1159 48.78195 223280 +1160 48.84663 223344 +1161 48.91142 223424 +1162 48.97628 223504 +1163 49.04123 223584 +1164 49.10627 223648 +1165 49.17139 223728 +1166 49.2366 223808 +1167 49.30189 223872 +1168 49.36728 223952 +1169 49.43275 224032 +1170 49.49829 224112 +1171 49.56394 224176 +1172 49.62967 224256 +1173 49.69549 224336 +1174 49.76139 224400 +1175 49.82738 224480 +1176 49.89346 224560 +1177 49.95963 224624 +1178 50.02588 224704 +1179 50.09222 224784 +1180 50.15865 224848 +1181 50.22517 224928 +1182 50.29177 225008 +1183 50.35847 225072 +1184 50.42525 225152 +1185 50.49213 225216 +1186 50.55908 225296 +1187 50.62613 225376 +1188 50.69327 225440 +1189 50.76049 225520 +1190 50.82781 225584 +1191 50.89521 225664 +1192 50.9627 225744 +1193 51.03029 225808 +1194 51.09797 225888 +1195 51.16573 225952 +1196 51.23358 226032 +1197 51.30153 226096 +1198 51.36956 226176 +1199 51.43768 226240 +1200 51.5059 226320 +1201 51.5742 226384 +1202 51.64259 226464 +1203 51.71108 226528 +1204 51.77966 226608 +1205 51.84833 226672 +1206 51.91708 226752 +1207 51.98593 226816 +1208 52.05488 226896 +1209 52.12391 226960 +1210 52.19304 227040 +1211 52.26224 227104 +1212 52.33155 227184 +1213 52.40096 227248 +1214 52.47044 227328 +1215 52.54004 227392 +1216 52.6097 227456 +1217 52.67947 227536 +1218 52.74933 227600 +1219 52.81929 227680 +1220 52.88933 227744 +1221 52.95947 227808 +1222 53.0297 227888 +1223 53.10003 227952 +1224 53.17045 228016 +1225 53.24096 228096 +1226 53.31157 228160 +1227 53.38226 228240 +1228 53.45305 228304 +1229 53.52394 228368 +1230 53.59492 228448 +1231 53.666 228512 +1232 53.73716 228576 +1233 53.80843 228656 +1234 53.87979 228720 +1235 53.95124 228784 +1236 54.02279 228864 +1237 54.09443 228928 +1238 54.16616 228992 +1239 54.238 229072 +1240 54.30993 229136 +1241 54.38195 229200 +1242 54.45406 229264 +1243 54.52628 229344 +1244 54.59859 229408 +1245 54.671 229480 +1246 54.7435 229544 +1247 54.81609 229616 +1248 54.88879 229680 +1249 54.96158 229752 +1250 55.03447 229816 +1251 55.10746 229888 +1252 55.18053 229952 +1253 55.2537 230024 +1254 55.32698 230088 +1255 55.40036 230152 +1256 55.47383 230224 +1257 55.54739 230288 +1258 55.62105 230352 +1259 55.69482 230424 +1260 55.76868 230488 +1261 55.84264 230560 +1262 55.91669 230624 +1263 55.99084 230688 +1264 56.06509 230760 +1265 56.13945 230824 +1266 56.2139 230888 +1267 56.28845 230960 +1268 56.36308 231016 +1269 56.43783 231088 +1270 56.51268 231152 +1271 56.58762 231216 +1272 56.66267 231288 +1273 56.73781 231352 +1274 56.81305 231416 +1275 56.8884 231480 +1276 56.96384 231544 +1277 57.03939 231608 +1278 57.11502 231672 +1279 57.19076 231744 +1280 57.26661 231808 +1281 57.34256 231872 +1282 57.4186 231936 +1283 57.49474 232000 +1284 57.57099 232064 +1285 57.64734 232128 +1286 57.72379 232192 +1287 57.80034 232264 +1288 57.87698 232328 +1289 57.95374 232384 +1290 58.03059 232448 +1291 58.10756 232520 +1292 58.18462 232584 +1293 58.26177 232640 +1294 58.33904 232712 +1295 58.4164 232768 +1296 58.49387 232840 +1297 58.57145 232896 +1298 58.64911 232960 +1299 58.72689 233024 +1300 58.80478 233088 +1301 58.88276 233152 +1302 58.96085 233216 +1303 59.03904 233280 +1304 59.11733 233336 +1305 59.19573 233408 +1306 59.27423 233464 +1307 59.35284 233536 +1308 59.43155 233592 +1309 59.51036 233656 +1310 59.58928 233720 +1311 59.66831 233776 +1312 59.74744 233840 +1313 59.82668 233904 +1314 59.90601 233968 +1315 59.98545 234024 +1316 60.065 234096 +1317 60.14466 234152 +1318 60.22442 234216 +1319 60.30428 234280 +1320 60.38425 234336 +1321 60.46433 234400 +1322 60.54452 234464 +1323 60.62481 234528 +1324 60.7052 234584 +1325 60.78571 234648 +1326 60.86632 234704 +1327 60.94704 234768 +1328 61.02787 234832 +1329 61.1088 234888 +1330 61.18983 234952 +1331 61.27098 235016 +1332 61.35223 235072 +1333 61.4336 235128 +1334 61.51507 235192 +1335 61.59665 235256 +1336 61.67833 235312 +1337 61.76013 235376 +1338 61.84203 235432 +1339 61.92404 235496 +1340 62.00616 235560 +1341 62.08839 235616 +1342 62.17073 235680 +1343 62.25318 235736 +1344 62.33574 235800 +1345 62.4184 235856 +1346 62.50117 235912 +1347 62.58406 235976 +1348 62.66706 236032 +1349 62.75017 236096 +1350 62.83337 236152 +1351 62.9167 236208 +1352 63.00014 236272 +1353 63.08369 236328 +1354 63.16735 236384 +1355 63.25111 236448 +1356 63.335 236504 +1357 63.41899 236560 +1358 63.50309 236624 +1359 63.58731 236680 +1360 63.67163 236736 +1361 63.75607 236800 +1362 63.84062 236856 +1363 63.92529 236912 +1364 64.01006 236976 +1365 64.09493 237032 +1366 64.17994 237088 +1367 64.26505 237144 +1368 64.35028 237208 +1369 64.43562 237264 +1370 64.52106 237320 +1371 64.60663 237376 +1372 64.69231 237440 +1373 64.7781 237496 +1374 64.86401 237552 +1375 64.95002 237608 +1376 65.03616 237664 +1377 65.12241 237720 +1378 65.20877 237784 +1379 65.29525 237840 +1380 65.38183 237896 +1381 65.46854 237952 +1382 65.55536 238008 +1383 65.6423 238064 +1384 65.72935 238120 +1385 65.81651 238176 +1386 65.90379 238232 +1387 65.9912 238296 +1388 66.07871 238352 +1389 66.16634 238400 +1390 66.25409 238456 +1391 66.34195 238512 +1392 66.42992 238576 +1393 66.51803 238624 +1394 66.60624 238680 +1395 66.69457 238736 +1396 66.78301 238792 +1397 66.87157 238848 +1398 66.96026 238904 +1399 67.04906 238968 +1400 67.13799 239016 +1401 67.22701 239072 +1402 67.31616 239128 +1403 67.40543 239184 +1404 67.49483 239240 +1405 67.58434 239296 +1406 67.67395 239352 +1407 67.7637 239400 +1408 67.85357 239456 +1409 67.94356 239512 +1410 68.03365 239568 +1411 68.12387 239624 +1412 68.21422 239680 +1413 68.30468 239728 +1414 68.39526 239792 +1415 68.48597 239840 +1416 68.57678 239896 +1417 68.66772 239952 +1418 68.75879 240008 +1419 68.84998 240056 +1420 68.94128 240112 +1421 69.0327 240168 +1422 69.12425 240216 +1423 69.21593 240272 +1424 69.30772 240328 +1425 69.39963 240376 +1426 69.49165 240432 +1427 69.58382 240488 +1428 69.67609 240544 +1429 69.7685 240592 +1430 69.86102 240648 +1431 69.95367 240696 +1432 70.04643 240752 +1433 70.13932 240808 +1434 70.23235 240864 +1435 70.32549 240912 +1436 70.41875 240968 +1437 70.51212 241024 +1438 70.60564 241072 +1439 70.69927 241128 +1440 70.79303 241176 +1441 70.88692 241232 +1442 70.98091 241280 +1443 71.07504 241336 +1444 71.1693 241384 +1445 71.26369 241440 +1446 71.35819 241496 +1447 71.45282 241544 +1448 71.54758 241592 +1449 71.64246 241648 +1450 71.73747 241704 +1451 71.83261 241752 +1452 71.92786 241808 +1453 72.02325 241856 +1454 72.11877 241904 +1455 72.21441 241960 +1456 72.31017 242008 +1457 72.40606 242056 +1458 72.50208 242112 +1459 72.59824 242168 +1460 72.69451 242216 +1461 72.79092 242272 +1462 72.88744 242320 +1463 72.9841 242368 +1464 73.08089 242416 +1465 73.17781 242472 +1466 73.27486 242520 +1467 73.37202 242576 +1468 73.46932 242624 +1469 73.56676 242672 +1470 73.66432 242720 +1471 73.76201 242776 +1472 73.85983 242824 +1473 73.95777 242872 +1474 74.05585 242928 +1475 74.15407 242976 +1476 74.2524 243024 +1477 74.35088 243072 +1478 74.44947 243128 +1479 74.5482 243176 +1480 74.64706 243224 +1481 74.74606 243272 +1482 74.84519 243328 +1483 74.94444 243376 +1484 75.04382 243424 +1485 75.14334 243472 +1486 75.243 243528 +1487 75.34278 243576 +1488 75.44269 243624 +1489 75.54274 243672 +1490 75.64293 243720 +1491 75.74324 243768 +1492 75.84369 243816 +1493 75.94426 243872 +1494 76.04498 243920 +1495 76.14582 243968 +1496 76.2468 244016 +1497 76.34792 244064 +1498 76.44916 244112 +1499 76.55054 244160 +1500 76.65206 244208 +1501 76.75372 244256 +1502 76.85551 244312 +1503 76.95742 244352 +1504 77.05948 244400 +1505 77.16167 244456 +1506 77.26401 244504 +1507 77.36647 244544 +1508 77.46906 244592 +1509 77.5718 244640 +1510 77.67467 244696 +1511 77.77768 244744 +1512 77.88083 244784 +1513 77.9841 244840 +1514 78.08752 244880 +1515 78.19109 244928 +1516 78.29477 244976 +1517 78.39861 245024 +1518 78.50258 245072 +1519 78.60667 245120 +1520 78.71092 245168 +1521 78.8153 245216 +1522 78.91983 245264 +1523 79.02449 245304 +1524 79.12928 245360 +1525 79.23421 245400 +1526 79.33929 245448 +1527 79.44451 245496 +1528 79.54987 245544 +1529 79.65536 245592 +1530 79.76099 245640 +1531 79.86677 245688 +1532 79.97269 245728 +1533 80.07875 245784 +1534 80.18493 245824 +1535 80.29127 245872 +1536 80.39775 245920 +1537 80.50437 245960 +1538 80.61114 246008 +1539 80.71803 246056 +1540 80.82507 246104 +1541 80.93227 246152 +1542 81.0396 246192 +1543 81.14706 246240 +1544 81.25467 246288 +1545 81.36243 246328 +1546 81.47033 246376 +1547 81.57837 246424 +1548 81.68655 246464 +1549 81.79488 246512 +1550 81.90335 246560 +1551 82.01197 246608 +1552 82.12073 246648 +1553 82.22964 246696 +1554 82.33868 246736 +1555 82.44787 246784 +1556 82.55721 246832 +1557 82.66669 246872 +1558 82.77633 246920 +1559 82.8861 246968 +1560 82.99601 247016 +1561 83.10608 247056 +1562 83.21629 247104 +1563 83.32665 247144 +1564 83.43716 247192 +1565 83.5478 247232 +1566 83.6586 247280 +1567 83.76954 247320 +1568 83.88064 247360 +1569 83.99188 247416 +1570 84.10325 247456 +1571 84.21479 247504 +1572 84.32647 247544 +1573 84.4383 247584 +1574 84.55029 247632 +1575 84.6624 247672 +1576 84.77468 247720 +1577 84.8871 247760 +1578 84.99968 247808 +1579 85.1124 247856 +1580 85.22527 247896 +1581 85.33829 247936 +1582 85.45146 247984 +1583 85.56478 248024 +1584 85.67825 248072 +1585 85.79187 248112 +1586 85.90565 248160 +1587 86.01957 248200 +1588 86.13364 248240 +1589 86.24788 248288 +1590 86.36224 248328 +1591 86.47678 248376 +1592 86.59145 248416 +1593 86.70629 248456 +1594 86.82129 248504 +1595 86.93641 248544 +1596 87.0517 248584 +1597 87.16714 248632 +1598 87.28275 248672 +1599 87.3985 248712 +1600 87.5144 248760 +1601 87.63046 248800 +1602 87.74666 248840 +1603 87.86303 248888 +1604 87.97955 248928 +1605 88.09622 248968 +1606 88.21304 249016 +1607 88.33003 249056 +1608 88.44717 249096 +1609 88.56447 249136 +1610 88.68192 249184 +1611 88.79952 249224 +1612 88.91728 249264 +1613 89.0352 249304 +1614 89.15328 249344 +1615 89.27151 249384 +1616 89.38989 249432 +1617 89.50843 249472 +1618 89.62714 249512 +1619 89.746 249552 +1620 89.86501 249600 +1621 89.98418 249632 +1622 90.10352 249680 +1623 90.22301 249720 +1624 90.34266 249760 +1625 90.46247 249808 +1626 90.58243 249840 +1627 90.70255 249888 +1628 90.82285 249928 +1629 90.94328 249968 +1630 91.0639 250008 +1631 91.18465 250048 +1632 91.30558 250088 +1633 91.42666 250128 +1634 91.5479 250168 +1635 91.66932 250208 +1636 91.79088 250256 +1637 91.9126 250288 +1638 92.0345 250336 +1639 92.15656 250368 +1640 92.27877 250416 +1641 92.40113 250456 +1642 92.52367 250496 +1643 92.64638 250536 +1644 92.76924 250576 +1645 92.89227 250616 +1646 93.01546 250656 +1647 93.1388 250696 +1648 93.26232 250736 +1649 93.386 250776 +1650 93.50985 250816 +1651 93.63386 250848 +1652 93.75801 250896 +1653 93.88236 250936 +1654 94.00686 250968 +1655 94.13153 251016 +1656 94.25637 251056 +1657 94.38135 251088 +1658 94.50652 251128 +1659 94.63185 251168 +1660 94.75735 251208 +1661 94.88302 251248 +1662 95.00883 251288 +1663 95.13483 251328 +1664 95.26099 251368 +1665 95.38734 251408 +1666 95.51383 251448 +1667 95.64049 251488 +1668 95.76732 251520 +1669 95.89432 251560 +1670 96.02149 251600 +1671 96.14883 251640 +1672 96.27633 251680 +1673 96.40401 251712 +1674 96.53185 251752 +1675 96.65988 251792 +1676 96.78806 251832 +1677 96.9164 251872 +1678 97.04494 251904 +1679 97.17364 251952 +1680 97.3025 251984 +1681 97.43155 252024 +1682 97.56074 252064 +1683 97.69012 252096 +1684 97.81968 252136 +1685 97.94941 252176 +1686 98.07931 252216 +1687 98.20937 252248 +1688 98.33961 252288 +1689 98.47002 252328 +1690 98.60061 252368 +1691 98.73137 252400 +1692 98.8623 252440 +1693 98.99339 252480 +1694 99.12468 252520 +1695 99.25614 252552 +1696 99.38777 252592 +1697 99.51958 252624 +1698 99.65154 252664 +1699 99.7837 252704 +1700 99.91602 252736 +1701 100.0485 252776 +1702 100.1812 252816 +1703 100.3141 252848 +1704 100.4471 252888 +1705 100.5803 252920 +1706 100.7137 252968 +1707 100.8472 253000 +1708 100.981 253040 +1709 101.1149 253072 +1710 101.249 253112 +1711 101.3833 253152 +1712 101.5177 253184 +1713 101.6523 253224 +1714 101.7871 253256 +1715 101.9221 253296 +1716 102.0573 253336 +1717 102.1926 253368 +1718 102.3282 253408 +1719 102.4639 253440 +1720 102.5997 253480 +1721 102.7358 253504 +1722 102.8721 253544 +1723 103.0085 253584 +1724 103.1451 253616 +1725 103.2819 253656 +1726 103.4188 253688 +1727 103.556 253728 +1728 103.6933 253760 +1729 103.8308 253800 +1730 103.9685 253832 +1731 104.1064 253872 +1732 104.2445 253912 +1733 104.3827 253944 +1734 104.5211 253976 +1735 104.6597 254008 +1736 104.7985 254056 +1737 104.9375 254080 +1738 105.0767 254120 +1739 105.216 254160 +1740 105.3555 254192 +1741 105.4953 254232 +1742 105.6352 254264 +1743 105.7753 254296 +1744 105.9155 254336 +1745 106.056 254368 +1746 106.1966 254400 +1747 106.3375 254432 +1748 106.4785 254472 +1749 106.6197 254504 +1750 106.7611 254544 +1751 106.9027 254576 +1752 107.0444 254616 +1753 107.1864 254648 +1754 107.3285 254680 +1755 107.4709 254712 +1756 107.6134 254752 +1757 107.7561 254784 +1758 107.899 254816 +1759 108.0421 254856 +1760 108.1854 254888 +1761 108.3288 254920 +1762 108.4725 254960 +1763 108.6164 254992 +1764 108.7604 255024 +1765 108.9046 255064 +1766 109.049 255096 +1767 109.1937 255128 +1768 109.3385 255168 +1769 109.4835 255200 +1770 109.6286 255232 +1771 109.774 255264 +1772 109.9196 255296 +1773 110.0654 255336 +1774 110.2114 255368 +1775 110.3575 255400 +1776 110.5039 255432 +1777 110.6504 255464 +1778 110.7971 255504 +1779 110.9441 255536 +1780 111.0912 255568 +1781 111.2385 255600 +1782 111.386 255632 +1783 111.5338 255672 +1784 111.6817 255696 +1785 111.8298 255736 +1786 111.9781 255768 +1787 112.1266 255800 +1788 112.2753 255832 +1789 112.4242 255864 +1790 112.5732 255896 +1791 112.7225 255936 +1792 112.872 255960 +1793 113.0217 256000 +1794 113.1716 256032 +1795 113.3217 256064 +1796 113.472 256096 +1797 113.6224 256136 +1798 113.7731 256168 +1799 113.924 256200 +1800 114.0751 256232 +1801 114.2263 256256 +1802 114.3778 256296 +1803 114.5295 256320 +1804 114.6814 256360 +1805 114.8335 256392 +1806 114.9858 256424 +1807 115.1383 256456 +1808 115.291 256488 +1809 115.4439 256520 +1810 115.5969 256552 +1811 115.7502 256584 +1812 115.9037 256616 +1813 116.0575 256648 +1814 116.2114 256680 +1815 116.3655 256712 +1816 116.5198 256744 +1817 116.6743 256776 +1818 116.829 256808 +1819 116.984 256840 +1820 117.1391 256872 +1821 117.2944 256904 +1822 117.45 256936 +1823 117.6058 256968 +1824 117.7617 257000 +1825 117.9179 257032 +1826 118.0742 257064 +1827 118.2308 257096 +1828 118.3876 257120 +1829 118.5446 257152 +1830 118.7019 257192 +1831 118.8593 257224 +1832 119.0169 257256 +1833 119.1747 257280 +1834 119.3328 257312 +1835 119.491 257344 +1836 119.6495 257376 +1837 119.8081 257408 +1838 119.967 257440 +1839 120.1261 257472 +1840 120.2854 257496 +1841 120.4449 257528 +1842 120.6047 257560 +1843 120.7646 257592 +1844 120.9248 257624 +1845 121.0851 257656 +1846 121.2457 257680 +1847 121.4065 257720 +1848 121.5675 257744 +1849 121.7287 257776 +1850 121.8901 257808 +1851 122.0518 257832 +1852 122.2136 257864 +1853 122.3757 257896 +1854 122.538 257928 +1855 122.7005 257960 +1856 122.8632 257992 +1857 123.0262 258024 +1858 123.1893 258048 +1859 123.3527 258080 +1860 123.5163 258112 +1861 123.6801 258144 +1862 123.8441 258176 +1863 124.0083 258200 +1864 124.1728 258232 +1865 124.3375 258264 +1866 124.5023 258288 +1867 124.6674 258320 +1868 124.8328 258352 +1869 124.9983 258376 +1870 125.1641 258408 +1871 125.3301 258440 +1872 125.4963 258472 +1873 125.6627 258496 +1874 125.8293 258528 +1875 125.9962 258560 +1876 126.1633 258592 +1877 126.3306 258616 +1878 126.4982 258640 +1879 126.6659 258672 +1880 126.8339 258704 +1881 127.0021 258736 +1882 127.1705 258768 +1883 127.3392 258792 +1884 127.508 258824 +1885 127.6771 258848 +1886 127.8464 258880 +1887 128.016 258904 +1888 128.1857 258944 +1889 128.3557 258968 +1890 128.526 259000 +1891 128.6964 259024 +1892 128.8671 259048 +1893 129.038 259080 +1894 129.2091 259112 +1895 129.3804 259144 +1896 129.552 259168 +1897 129.7238 259200 +1898 129.8959 259224 +1899 130.0681 259256 +1900 130.2406 259288 +1901 130.4133 259312 +1902 130.5863 259344 +1903 130.7594 259368 +1904 130.9328 259392 +1905 131.1065 259424 +1906 131.2804 259456 +1907 131.4545 259480 +1908 131.6288 259512 +1909 131.8033 259536 +1910 131.9781 259568 +1911 132.1532 259600 +1912 132.3284 259624 +1913 132.5039 259656 +1914 132.6796 259680 +1915 132.8556 259712 +1916 133.0318 259736 +1917 133.2082 259760 +1918 133.3848 259792 +1919 133.5617 259816 +1920 133.7388 259848 +1921 133.9162 259872 +1922 134.0938 259904 +1923 134.2716 259936 +1924 134.4497 259960 +1925 134.628 259992 +1926 134.8065 260016 +1927 134.9853 260040 +1928 135.1643 260072 +1929 135.3435 260096 +1930 135.523 260120 +1931 135.7028 260152 +1932 135.8827 260176 +1933 136.0629 260208 +1934 136.2433 260232 +1935 136.424 260256 +1936 136.605 260288 +1937 136.7861 260312 +1938 136.9675 260344 +1939 137.1491 260368 +1940 137.331 260392 +1941 137.5132 260424 +1942 137.6955 260456 +1943 137.8781 260472 +1944 138.061 260504 +1945 138.244 260528 +1946 138.4274 260560 +1947 138.611 260584 +1948 138.7948 260616 +1949 138.9788 260640 +1950 139.1631 260664 +1951 139.3477 260696 +1952 139.5325 260720 +1953 139.7175 260744 +1954 139.9028 260776 +1955 140.0883 260800 +1956 140.2741 260824 +1957 140.4602 260856 +1958 140.6464 260880 +1959 140.8329 260904 +1960 141.0197 260936 +1961 141.2067 260952 +1962 141.394 260984 +1963 141.5815 261008 +1964 141.7692 261040 +1965 141.9572 261064 +1966 142.1455 261088 +1967 142.334 261112 +1968 142.5228 261144 +1969 142.7118 261168 +1970 142.901 261192 +1971 143.0905 261224 +1972 143.2803 261240 +1973 143.4703 261280 +1974 143.6606 261296 +1975 143.8511 261320 +1976 144.0419 261352 +1977 144.2329 261376 +1978 144.4242 261400 +1979 144.6157 261424 +1980 144.8074 261456 +1981 144.9995 261480 +1982 145.1918 261504 +1983 145.3843 261528 +1984 145.5771 261560 +1985 145.7702 261584 +1986 145.9635 261608 +1987 146.1571 261632 +1988 146.3509 261656 +1989 146.545 261680 +1990 146.7393 261704 +1991 146.9339 261736 +1992 147.1288 261760 +1993 147.3239 261792 +1994 147.5193 261808 +1995 147.7149 261832 +1996 147.9108 261864 +1997 148.1069 261880 +1998 148.3033 261912 +1999 148.5 261936 diff --git a/tests/depth_compare.js b/tests/depth_compare.js new file mode 100755 index 00000000..e3ec50d3 --- /dev/null +++ b/tests/depth_compare.js @@ -0,0 +1,146 @@ +#!/usr/bin/env node +// Depth regression metrics + comparison (see tests/depth.sh). +// +// Usage: node tests/depth_compare.js [--update] +// +// Both files are the "step w z18" blocks written by tests/depth.test.js. +// The metrics below are computed for both and printed side by side, always. +// Any metric that got worse fails the test, no tolerance. A different sample +// vector with equal-or-better metrics is reported as CHANGED (still a pass); +// --update overwrites the golden with the actual file. +// +// Metrics (all derived from the 2000 sweep samples + near/far): +// codes distinct stored z-buffer codes (more = finer) +// err rms rms |Z - ideal| in Z units (ideal = exact mapping, pushed +// err max max |Z - ideal| through the RDP z-buffer format) +// bias mean (Z - ideal), Z units (sign of the systematic error) +// inv samples whose Z is smaller than a nearer sample's Z +// inv reach worst distance (world units) such a wrong-order pair spans +// amb p99 99th percentile / max of the ambiguity span: at a sample, how +// amb max far back + forward another sample sits whose Z is not sorted +// strictly against it (equal or inverted), in world units + +const fs = require("fs"); +const [goldenPath, actualPath, ...flags] = process.argv.slice(2); +if (!goldenPath || !actualPath) { console.error("usage: depth_compare.js [--update]"); process.exit(2); } +const update = flags.includes("--update"); + +function parse(path) { + const meta = {}, samples = []; + for (const line of fs.readFileSync(path, "utf8").split("\n")) { + if (!line.trim()) continue; + if (line[0] === "#") { + for (const tok of line.slice(1).trim().split(/\s+/)) { const eq = tok.indexOf("="); if (eq > 0) meta[tok.slice(0, eq)] = tok.slice(eq + 1); } + continue; + } + const [step, w, z] = line.trim().split(/\s+/); + samples.push({ step: +step, w: +w, z: +z }); + } + samples.sort((a, b) => a.w - b.w); + return { meta, samples, near: +meta.near, far: +meta.far }; +} + +// ---- reference: exact perspective mapping -> RDP z-buffer format roundtrip (angrylion) ---- +const idealZ = (w, near, far) => { const zndc = ((far + near) * w - 2 * far * near) / ((far - near) * w); return (zndc + 1) * 0.5 * 32767; }; +const Z_DEC = [[6, 0x00000], [5, 0x20000], [4, 0x30000], [3, 0x38000], [2, 0x3C000], [1, 0x3E000], [0, 0x3F000], [0, 0x3F800]]; +function rdpRoundtrip(zUnits) { + const z16 = Math.floor(zUnits * 65536); + let sz = (z16 >> 10) & 0x3fffff; + sz = sz >> 3; + sz = Math.max(0, Math.min(0x3FFFF, sz)); + const key = (sz >> 11) & 0x7F; let m, e; + if (key <= 0x3F) { m = (sz >> 4) & 0x1FFC; e = 0; } else if (key <= 0x5F) { m = (sz >> 3) & 0x1FFC; e = 1; } + else if (key <= 0x6F) { m = (sz >> 2) & 0x1FFC; e = 2; } else if (key <= 0x77) { m = (sz >> 1) & 0x1FFC; e = 3; } + else if (key <= 0x7B) { m = sz & 0x1FFC; e = 4; } else if (key <= 0x7D) { m = (sz << 1) & 0x1FFC; e = 5; } + else if (key === 0x7E) { m = (sz << 2) & 0x1FFC; e = 6; } else { m = (sz << 2) & 0x1FFC; e = 7; } + return (((m >> 2) << Z_DEC[e][0]) + Z_DEC[e][1]) & 0x3ffff; +} + +function metrics(d) { + const sm = d.samples, n = sm.length; + const codes = new Set(sm.map((s) => s.z)).size; + let sq = 0, mx = 0, sum = 0; + for (const s of sm) { + const e = (s.z - rdpRoundtrip(idealZ(s.w, d.near, d.far))) / 8; + sq += e * e; mx = Math.max(mx, Math.abs(e)); sum += e; + } + let inv = 0, invReach = 0; + const amb = []; + for (let i = 0; i < n; i++) { + let jf = i, jb = i, jInv = -1; + for (let j = n - 1; j > i; j--) if (sm[j].z <= sm[i].z) { jf = j; break; } + for (let j = n - 1; j > i; j--) if (sm[j].z < sm[i].z) { jInv = j; break; } + for (let j = 0; j < i; j++) if (sm[j].z >= sm[i].z) { jb = j; break; } + if (i > 0 && sm[i - 1].z > sm[i].z) inv++; + if (jInv >= 0) invReach = Math.max(invReach, sm[jInv].w - sm[i].w); + amb.push((sm[jf].w - sm[i].w) + (sm[i].w - sm[jb].w)); + } + amb.sort((a, b) => a - b); + return { + codes, errRms: Math.sqrt(sq / n), errMax: mx, bias: sum / n, + inv, invReach, ambP99: amb[Math.floor(0.99 * (n - 1))], ambMax: amb[n - 1], + }; +} + +// name, label, unit, better = sign of (actual - golden) that is an improvement (+1 higher is better, -1 lower is better) +const TABLE = [ + ["codes", "codes", "", +1, (v) => String(v)], + ["errRms", "err rms", "Z units", -1, (v) => v.toFixed(3)], + ["errMax", "err max", "Z units", -1, (v) => v.toFixed(3)], + ["bias", "bias", "Z units", 0, (v) => v.toFixed(3)], + ["inv", "inversions", "", -1, (v) => String(v)], + ["invReach", "inv reach", "world", -1, (v) => v.toFixed(3)], + ["ambP99", "amb p99", "world", -1, (v) => v.toFixed(3)], + ["ambMax", "amb max", "world", -1, (v) => v.toFixed(3)], +]; + +const actual = parse(actualPath); +if (actual.samples.length === 0) { console.log("no samples in " + actualPath); process.exit(1); } +const golden = fs.existsSync(goldenPath) ? parse(goldenPath) : null; + +const mA = metrics(actual), mG = golden ? metrics(golden) : null; +const pad = (s, n) => String(s).padStart(n); +console.log(` near=${actual.near} far=${actual.far} samples=${actual.samples.length}` + (golden ? "" : " (no golden yet)")); +console.log(" " + "metric".padEnd(12) + pad("golden", 12) + pad("actual", 12) + pad("delta", 12) + " unit"); +let worse = 0, better = 0; +for (const [key, label, unit, sign, f] of TABLE) { + const a = mA[key], g = mG ? mG[key] : null; + let tag = ""; + if (mG) { + const d = a - g; + if (sign !== 0 && d !== 0) { if (Math.sign(d) === sign) { better++; tag = " better"; } else { worse++; tag = " WORSE"; } } + else if (sign === 0 && Math.abs(a) > Math.abs(g)) tag = " (larger)"; + } + console.log(" " + label.padEnd(12) + pad(mG ? f(g) : "-", 12) + pad(f(a), 12) + pad(mG ? (a - g === 0 ? "0" : f(a - g)) : "-", 12) + " " + unit + tag); +} + +let status; +if (!golden) { + status = "CREATED"; +} else { + if (golden.near !== actual.near || golden.far !== actual.far || golden.samples.length !== actual.samples.length) { + console.log(` golden setup differs (near/far/steps), re-record with --update`); + process.exit(1); + } + let diff = 0, first = -1, wDiff = 0; + for (let i = 0; i < actual.samples.length; i++) { + const a = actual.samples[i], g = golden.samples[i]; + if (a.z !== g.z) { diff++; if (first < 0) first = i; } + if (a.w !== g.w) wDiff++; + } + if (wDiff) console.log(` NOTE: sweep distances differ from the golden for ${wDiff} samples (scene setup changed?)`); + if (diff) { + const a = actual.samples[first], g = golden.samples[first]; + console.log(` samples differ: ${diff} of ${actual.samples.length}, first at step ${a.step} (w=${a.w}: golden Z ${g.z / 8}, actual Z ${a.z / 8})`); + } + diff += wDiff; + status = worse ? "FAIL" : diff ? "CHANGED" : "SAME"; +} +console.log(` result: ${status}` + (worse ? ` (${worse} metric(s) worse)` : better ? ` (${better} metric(s) better)` : "") + + (status === "CHANGED" ? " -> accept with --update" : "")); + +if (update || !golden) { + fs.copyFileSync(actualPath, goldenPath); + console.log(` ${golden ? "updated" : "created"} golden ${goldenPath}`); +} +process.exit(worse ? 1 : 0); diff --git a/tests/perf.sh b/tests/perf.sh new file mode 100755 index 00000000..2cf14cfe --- /dev/null +++ b/tests/perf.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# RSP performance tests, requires the ares-64 test runner. +# +# Usage: tests/perf.sh [example ...] +# example one or more example names (e.g. 99_testscene); default: every +# tests/perf/*.json +# +# Each tests/perf/.json holds the frame counts and the baseline times: +# { "framesWarmup": 40, "framesProfile": 30, "data": {"tiny3d/Tri Strip": 3583.76, ...} } +# The ROM is implied by the file name: examples//t3d_.z64 +# +# Exits non-zero if any command is slower than its baseline. To update a baseline, +# copy the "perfMap:" line printed at the end into the "data" object of that JSON. + +set -u +cd "$(dirname "$0")/.." + +ARES_TEST=${ARES_TEST:-ares-test} +PERF_DIR=tests/perf + +selected=("$@") +if [[ ${#selected[@]} -eq 0 ]]; then + shopt -s nullglob + for f in "$PERF_DIR"/*.json; do selected+=("$(basename "$f" .json)"); done + shopt -u nullglob + if [[ ${#selected[@]} -eq 0 ]]; then + echo "no baselines found in $PERF_DIR" + exit 1 + fi +fi + +pass=0 fail=0 + +for name in "${selected[@]}"; do + json="$PERF_DIR/$name.json" + rom="examples/$name/t3d_$name.z64" + + if [[ ! -f "$json" ]]; then + echo "FAIL $name (no baseline: $json)" + fail=$((fail + 1)) + continue + fi + if [[ ! -f "$rom" ]]; then + echo "FAIL $name (ROM not built: $rom)" + fail=$((fail + 1)) + continue + fi + + # the whole JSON goes to the test script, it reads the frame counts and the baseline + cfg=$(cat "$json") + + # the example Makefiles do not track the library, a stale ROM would measure old ucode + if [[ -f build/libt3d.a && build/libt3d.a -nt "$rom" ]]; then + echo "WARN $name: $rom is older than build/libt3d.a, rebuild it (make -C examples/$name)" + fi + + echo "=== $name ($rom)" + if out=$("$ARES_TEST" tests/perf.test.js "$rom" "$cfg" 2>&1); then + sed 's/^/ /' <<<"$out" + echo "PASS $name" + pass=$((pass + 1)) + else + sed 's/^/ /' <<<"$out" + echo "FAIL $name" + fail=$((fail + 1)) + fi +done + +echo "----" +echo "pass=$pass fail=$fail" +[[ $fail -eq 0 ]] || exit 1 diff --git a/tests/perf.test.js b/tests/perf.test.js new file mode 100644 index 00000000..9a43d4bd --- /dev/null +++ b/tests/perf.test.js @@ -0,0 +1,115 @@ +// RSP performance test for a single example (invoked by tests/perf.sh). +// +// Usage: ares-test tests/perf.test.js +// config contents of tests/perf/.json: +// { "framesWarmup": n, "framesProfile": n, "data": {"tiny3d/": usPerFrame, ...} } +// +// Boots the ROM, profiles the RSP over a fixed number of game frames and prints the +// per-command time, a grouped summary, and the comparison against the baseline. +// Exits non-zero if any command got slower than the baseline (beyond TOLERANCE_US). + +const [rom, configArg] = ares.args; +if (!rom || !configArg) throw new Error("usage: perf.test.js "); + +const cfg = JSON.parse(configArg); +const framesWarmup = cfg.framesWarmup; +const frames = cfg.framesProfile; +const lastPerf = cfg.data ?? {}; +if (!(framesWarmup >= 0) || !(frames > 0)) { + throw new Error("config needs framesWarmup >= 0 and framesProfile > 0"); +} + +const TOLERANCE_US = 0.0025; // ignore differences below this (us/frame) +const RSP_MHZ = 62.5; + +ares.setRenderer("angrylion"); +ares.loadRom(rom); +ares.resume(); +ares.waitFrames(framesWarmup); + +ares.waitRspCommand("Screen Size"); +ares.rspProfileStart(); +ares.waitRspCommand("Screen Size", frames); +const t = ares.rspProfile(); + +if (ares.log().includes("RSP CRASH") || ares.log().includes("CPU exception")) { + throw new Error("ROM crashed:\n" + ares.log()); +} + +const usPerFrame = (c) => c / frames / RSP_MHZ; // 62.5 MHz -> us per game frame + +console.log(""); +console.log("RSP profile over " + frames + " game frames (lostRows: " + t.lostRows + ")"); +console.log("total: " + Math.round(t.totalCycles) + " cycles = " + + usPerFrame(t.totalCycles).toFixed(2) + " us/frame (commands " + + usPerFrame(t.commandCycles).toFixed(2) + ", rspq overhead " + + usPerFrame(t.overheadCycles).toFixed(2) + ")"); +console.log(""); +console.log("command".padEnd(30) + "count".padStart(8) + "avg cyc".padStart(10) + + "cyc/frame".padStart(12) + "us/frame".padStart(10) + "share".padStart(8)); + +const perfMap = {}; +for (const r of t.rows) { + if (r.overlay !== "tiny3d") continue; + const name = r.overhead ? "rspq: " + r.overheadType : r.overlay + "/" + r.name; + const usPF = usPerFrame(r.cycles); + perfMap[name] = usPF; + console.log(name.padEnd(30) + + String(r.count).padStart(8) + + r.avg.toFixed(1).padStart(10) + + String(Math.round(r.cycles / frames)).padStart(12) + + usPF.toFixed(2).padStart(10) + + ((r.cycles / t.totalCycles) * 100).toFixed(1).padStart(7) + "%"); +} + +// grouped summary for the vertex/triangle refactor work +const GROUPS = [ + { label: "triangles (Draw+Strip+Seq)", names: ["Tri Draw", "Tri Strip", "Tri Seq"] }, + { label: "vertices (Vert Load)", names: ["Vert Load"] }, +]; +console.log(""); +console.log("group".padEnd(30) + "count".padStart(8) + "avg cyc".padStart(10) + + "cyc/frame".padStart(12) + "us/frame".padStart(10) + "share".padStart(8)); +for (const g of GROUPS) { + let count = 0, cycles = 0; + for (const r of t.rows) { + if (!r.overhead && r.overlay === "tiny3d" && g.names.includes(r.name)) { + count += r.count; cycles += r.cycles; + } + } + console.log(g.label.padEnd(30) + + String(count).padStart(8) + + (count ? (cycles / count) : 0).toFixed(1).padStart(10) + + String(Math.round(cycles / frames)).padStart(12) + + usPerFrame(cycles).toFixed(1).padStart(10) + + ((cycles / t.totalCycles) * 100).toFixed(1).padStart(7) + "%"); +} + +console.log("========================================="); + +// compare against the baseline and report what got better/worse +let foundWorse = false, strBetter = "", strWorse = "", strNew = ""; +for (const [name, usPF] of Object.entries(perfMap)) { + const last = lastPerf[name]; + if (last === undefined) { + strNew += name + " " + usPF.toFixed(4) + " us/frame\n"; + continue; + } + if (Math.abs(usPF - last) < TOLERANCE_US) continue; + const perc = ((usPF / last - 1) * 100).toFixed(1); + const line = name + " " + usPF.toFixed(4) + " us/frame (was " + last.toFixed(4) + ", " + + (usPF > last ? "+" : "") + perc + "%)\n"; + if (usPF > last) { strWorse += line; foundWorse = true; } else strBetter += line; +} +for (const name of Object.keys(lastPerf)) { + if (perfMap[name] === undefined) strNew += name + " GONE (was " + lastPerf[name].toFixed(4) + " us/frame)\n"; +} + +if (strNew) console.log("New/removed:\n" + strNew); +if (strBetter) console.log("Better:\n" + strBetter); +if (strWorse) console.log("Worse:\n" + strWorse); +if (!foundWorse) console.log("Performance OK"); +console.log("========================================="); +//console.log("perfMap: " + JSON.stringify(perfMap)); // paste into tests/perf/.json to update + +if (foundWorse) ares.exit(1); diff --git a/tests/perf/15_pointlight.json b/tests/perf/15_pointlight.json new file mode 100644 index 00000000..8b3c6294 --- /dev/null +++ b/tests/perf/15_pointlight.json @@ -0,0 +1,5 @@ +{ + "framesWarmup": 2, + "framesProfile": 20, + "data": {"tiny3d/Vert Load":14574.276800000001,"tiny3d/Tri Strip":2850.2376,"tiny3d/Tri Seq":89.48639999999999,"tiny3d/Matrix Stack":56.656,"tiny3d/Tri Draw":40.552800000000005,"tiny3d/Set Word":8.3256,"tiny3d/Draw Flags":2.9184,"tiny3d/Light Set":2.0911999999999997,"tiny3d/Fog State":2.0216,"tiny3d/Proj Set":0.912,"tiny3d/Screen Size":0.4648} +} diff --git a/tests/perf/97_cliptest.json b/tests/perf/97_cliptest.json new file mode 100644 index 00000000..b072d6ad --- /dev/null +++ b/tests/perf/97_cliptest.json @@ -0,0 +1,5 @@ +{ + "framesWarmup": 20, + "framesProfile": 20, + "data": {"tiny3d/Tri Draw":224.7584,"tiny3d/Vert Load":28.208,"tiny3d/Matrix Stack":17.5608,"tiny3d/Tri Sync":3.1512,"tiny3d/Set Word":1.632,"tiny3d/Proj Set":0.96,"tiny3d/Light Set":0.72,"tiny3d/Screen Size":0.48,"tiny3d/Draw Flags":0.384,"tiny3d/Fog State":0.304} +} diff --git a/tests/perf/99_testscene.json b/tests/perf/99_testscene.json new file mode 100644 index 00000000..cdbca5e0 --- /dev/null +++ b/tests/perf/99_testscene.json @@ -0,0 +1,5 @@ +{ + "framesWarmup": 40, + "framesProfile": 30, + "data": {"tiny3d/Tri Strip":3569.856,"tiny3d/Vert Load":2453.152,"tiny3d/Tri Seq":965.504,"tiny3d/Tri Draw":49.392,"tiny3d/Matrix Stack":17.552,"tiny3d/Set Word":1.632,"tiny3d/Proj Set":0.96,"tiny3d/Light Set":0.72,"tiny3d/Fog State":0.608,"tiny3d/Screen Size":0.48,"tiny3d/Draw Flags":0.384} +} diff --git a/tests/rsp.sh b/tests/rsp.sh new file mode 100755 index 00000000..d6e8638f --- /dev/null +++ b/tests/rsp.sh @@ -0,0 +1,5 @@ +set -u + +cd "$(dirname "$0")/rsp" +npm i +npm test \ No newline at end of file diff --git a/tests/rsp/elf.mjs b/tests/rsp/elf.mjs new file mode 100644 index 00000000..3736ae96 --- /dev/null +++ b/tests/rsp/elf.mjs @@ -0,0 +1,48 @@ +// Minimal ELF32 big-endian reader for the RSP ucode ELFs (rsp.ld layout): +// section bytes by name (.text -> IMEM, .data -> DMEM) and the symbol table. +import {readFileSync} from 'node:fs'; + +/** + * @param {string} path + * @returns {{sections: Object, symbols: Object, bytes: (name: string) => Uint8Array}} + * symbols hold the full link address (e.g. 0xA4001280); mask with 0x1FFF for the RSP address + */ +export function parseElf(path) { + const buf = readFileSync(path); + const dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); + const u16 = (o) => dv.getUint16(o, false); + const u32 = (o) => dv.getUint32(o, false); + if (u32(0) !== 0x7F454C46) throw new Error('not an ELF file: ' + path); + + const shoff = u32(0x20), shentsize = u16(0x2E), shnum = u16(0x30), shstrndx = u16(0x32); + const sh = (i) => { + const o = shoff + i * shentsize; + return {name: u32(o), type: u32(o + 4), addr: u32(o + 12), offset: u32(o + 16), + size: u32(o + 20), link: u32(o + 24), entsize: u32(o + 36)}; + }; + const cstr = (base, off) => { + let e = base + off; while (buf[e] !== 0) e++; + return buf.toString('latin1', base + off, e); + }; + const strtab = sh(shstrndx).offset; + const sections = {}; + const list = []; + for (let i = 0; i < shnum; i++) { const s = sh(i); s.strName = cstr(strtab, s.name); sections[s.strName] = s; list.push(s); } + + const symbols = {}; + const symtab = sections['.symtab']; + if (symtab) { + const names = list[symtab.link].offset; + for (let o = symtab.offset; o < symtab.offset + symtab.size; o += 16) { + const name = cstr(names, u32(o)); + if (name) symbols[name] = u32(o + 4); + } + } + const bytes = (name) => { + const s = sections[name]; + if (!s || s.type === 8 /*NOBITS*/) return new Uint8Array(0); + return new Uint8Array(buf.buffer, buf.byteOffset + s.offset, s.size); + }; + return {sections, symbols, bytes}; +} + diff --git a/tests/rsp/golden.test.mjs b/tests/rsp/golden.test.mjs new file mode 100644 index 00000000..e76be8f6 --- /dev/null +++ b/tests/rsp/golden.test.mjs @@ -0,0 +1,117 @@ +// Golden-byte tests: exact output of the triangle code and the vertex loop for a fixed +// set of inputs. Recorded once, every later change must reproduce them byte for byte +// (or consciously re-record with UPDATE_GOLDEN=1 and explain the diff in the commit). +import {test, before} from 'node:test'; +import assert from 'node:assert/strict'; +import {Ucode, TRI_SIZE, writeScreenVertex, writePackedVertexPair, writeMatrixFP, setViewport, checkGolden, hex, vertLoadInputDest} from './harness.mjs'; + +let u; +before(async () => { u = await Ucode.load(); }); + +// --------------------------------------------------------------------------- +// RDPQ_Triangle_Send_Async +// --------------------------------------------------------------------------- +const CMD = {shadeTexZ: 0xCF00, shade: 0xCC00, shadeZ: 0xCD00, texZ: 0xCB00, tex: 0xCA00, flat: 0xC800}; +const v = (x, y, w, o = {}) => ({x, y, w, z: o.z ?? 0x2000, rgba: o.rgba ?? 0x80C040FF, s: o.s ?? 0, t: o.t ?? 0, clip: o.clip ?? 0, reject: o.reject ?? 0xFF}); + +const TRI_CASES = [ + {name: 'basic', verts: [v(10, 10, 2, {z: 0x1000, rgba: 0xFF0000FF}), v(100, 20, 4, {z: 0x3000, rgba: 0x00FF00FF, s: 32}), v(50, 90, 8, {z: 0x5000, rgba: 0x0000FFFF, t: 32})]}, + {name: 'fractional_positions', verts: [v(10.25, 10.75, 2.5), v(100.5, 20.25, 4.25, {s: 17.5, t: 3.25}), v(50.75, 90.5, 8.75, {s: 1.25, t: 40})]}, + {name: 'reversed_winding', verts: [v(10, 10, 2), v(50, 90, 8, {t: 32}), v(100, 20, 4, {s: 32})]}, + {name: 'unsorted_input', verts: [v(50, 90, 8, {rgba: 0x0000FFFF}), v(10, 10, 2, {rgba: 0xFF0000FF}), v(100, 20, 4, {rgba: 0x00FF00FF})]}, + {name: 'flat_top', verts: [v(10, 10, 3), v(120, 10, 3), v(60, 80, 5)]}, + {name: 'flat_bottom', verts: [v(60, 5, 5), v(10, 80, 3), v(120, 80, 3)]}, + {name: 'all_same_y', verts: [v(10, 40, 3), v(60, 40, 3), v(120, 40, 3)]}, + {name: 'zero_area_vertical', verts: [v(40, 10, 3), v(40, 50, 3), v(40, 90, 3)]}, + {name: 'sliver', verts: [v(10, 10, 3), v(11, 200, 3), v(10.25, 100, 3)]}, + {name: 'guard_band_extent', verts: [v(-600, -450, 1.5), v(950, -300, 6), v(300, 700, 2.25, {s: 500, t: -300})]}, + {name: 'negative_coords', verts: [v(-30, -20, 2), v(-5, -60, 2.5), v(-80, -70, 3)]}, + {name: 'w_close_to_one', verts: [v(20, 20, 1.0), v(200, 30, 1.0001), v(90, 200, 1.5)]}, + {name: 'w_large', verts: [v(20, 20, 3000), v(200, 30, 4500.5), v(90, 200, 12000)]}, + {name: 'w_not_power_of_two', verts: [v(20, 20, 3.7), v(200, 30, 5.3), v(90, 200, 9.9)]}, + {name: 'colour_extremes', verts: [v(20, 20, 2, {rgba: 0x00000000}), v(200, 30, 2, {rgba: 0xFFFFFFFF}), v(90, 200, 2, {rgba: 0xFF00FF00})]}, + {name: 'st_saturation', verts: [v(20, 20, 2, {s: -1000, t: 1000}), v(200, 30, 2, {s: 1023, t: -1023}), v(90, 200, 2, {s: 0.5, t: 0.03125})]}, + {name: 'depth_extremes', verts: [v(20, 20, 2, {z: 0}), v(200, 30, 2, {z: 0x7FFF}), v(90, 200, 2, {z: 0x4000})]}, + {name: 'tile_3', verts: [v(10, 10, 2, {clip: 3 << 5}), v(100, 20, 4, {clip: 3 << 5}), v(50, 90, 8, {clip: 3 << 5})]}, + {name: 'cmd_shade_only', cmd: CMD.shade, verts: [v(10, 10, 2, {rgba: 0xFF0000FF}), v(100, 20, 4, {rgba: 0x00FF00FF}), v(50, 90, 8, {rgba: 0x0000FFFF})]}, + {name: 'cmd_shade_z', cmd: CMD.shadeZ, verts: [v(10, 10, 2, {z: 0x100}), v(100, 20, 4, {z: 0x3000}), v(50, 90, 8, {z: 0x7000})]}, + {name: 'cmd_tex_z', cmd: CMD.texZ, verts: [v(10, 10, 2), v(100, 20, 4, {s: 32}), v(50, 90, 8, {t: 32})]}, + {name: 'cmd_tex_only', cmd: CMD.tex, verts: [v(10, 10, 2), v(100, 20, 4, {s: 32}), v(50, 90, 8, {t: 32})]}, + {name: 'cmd_flat', cmd: CMD.flat, verts: [v(10, 10, 2), v(100, 20, 4), v(50, 90, 8)]}, + {name: 'buffer_offset_176', buffOffset: 176, verts: [v(10, 10, 2), v(100, 20, 4), v(50, 90, 8)]}, + {name: 'cull_front_ccw', cull: 0, verts: [v(10, 10, 2), v(100, 20, 4), v(50, 90, 8)]}, + {name: 'cull_back_ccw', cull: 1, verts: [v(10, 10, 2), v(100, 20, 4), v(50, 90, 8)]}, + {name: 'cull_front_cw', cull: 0, verts: [v(10, 10, 2), v(50, 90, 8), v(100, 20, 4)]}, + {name: 'cull_back_cw', cull: 1, verts: [v(10, 10, 2), v(50, 90, 8), v(100, 20, 4)]}, + {name: 'rejected', verts: [v(10, 10, 2, {reject: 0xFB}), v(100, 20, 4, {reject: 0xFB}), v(50, 90, 8, {reject: 0xFB})]}, + {name: 'clip_handoff', verts: [v(10, 10, 2, {clip: 0x10}), v(100, 20, 4), v(50, 90, 8)]}, +]; + +test('triangle golden bytes', () => { + const results = []; + for (const c of TRI_CASES) { + u.reset(); + const VB = u.sym.VERT_BUFFER, OUT = u.sym.CLIP_BUFFER_TMP + (c.buffOffset ?? 0); + u.w32(u.sym.TRI_COMMAND, c.cmd ?? CMD.shadeTexZ); + u.w16(u.sym.RDPQ_TRI_BUFF_OFFSET, c.buffOffset ?? 0); + u.w32(u.sym.RDPQ_CURRENT, 0x00100000); + u.w32(u.sym.RDPQ_SENTINEL, 0x00200000); + u.w8(u.sym.RDPQ_SYNCFULL_ONGOING, 0); + for (let i = 0; i < 176 * 2; i++) u.w8(u.sym.CLIP_BUFFER_TMP + i, 0xEE); + c.verts.forEach((vv, i) => writeScreenVertex(u, VB + i * TRI_SIZE, vv)); + const res = u.call('RDPQ_Triangle_Send_Async', + {$a0: VB, $a1: VB + TRI_SIZE, $a2: VB + 2 * TRI_SIZE, $v0: c.cull ?? 2}, ['RDPQ_Triangle_Clip']); + results.push({ + name: c.name, + end: res.pc === u.sym.RDPQ_Triangle_Clip ? 'clip' : res.returned ? 'return' : `pc=${res.pc.toString(16)}`, + rdramAdvance: u.r32(u.sym.RDPQ_CURRENT) - 0x00100000, + s3: u.gpr('$s3'), s7: u.gpr('$s7'), + bytes: hex(u.bytes(OUT, 176)), + }); + } + checkGolden('triangle', results); +}); + +// --------------------------------------------------------------------------- +// T3DCmd_VertLoad +// --------------------------------------------------------------------------- +const S = 1 / 64; +const PERSPECTIVE = [[S, 0, 0, 0], [0, S, 0, 0], [0, 0, S, S], [0, 0, 0, 1]]; // w = 1 + z/64 +const ROTATED = [[0.0123, 0.0071, -0.0032, 0.0011], [-0.0064, 0.0142, 0.0018, -0.0007], + [0.0027, -0.0045, 0.0151, 0.0161], [0.35, -0.2, 0.9, 1.0]]; // all lanes engaged +const p = (pos, o = {}) => ({pos, norm: o.norm ?? [0, 0, 1], rgba: o.rgba ?? 0xFFFFFFFF, st: o.st ?? [0, 0]}); + +const VERT_CASES = [ + {name: 'perspective_inside', mvp: PERSPECTIVE, pairs: [[p([16, -24, 64], {rgba: 0x102030FF, st: [10, 20]}), p([-40, 32, 128], {rgba: 0x80FF40C0, st: [-5.5, 33.25]})]]}, + {name: 'rotated_matrix', mvp: ROTATED, guardBand: 3, pairs: [ + [p([100, 200, -300], {norm: [1, 0, 0], rgba: 0xC08040FF, st: [64, 64]}), p([-250, 75, 500], {norm: [0, 0.7, 0.7], st: [0.03125, 1023]})], + [p([3000, -2500, 1200], {norm: [-1, 0, 0]}), p([-3000, 3000, 900])]]}, + {name: 'guard_band_and_clip', mvp: PERSPECTIVE, guardBand: 2, pairs: [ + [p([0, 0, 0]), p([96, 0, 0])], // inside | outside screen, inside guard band + [p([192, 0, 0]), p([-192, -192, 0])], // outside guard band | two planes + [p([0, 64, 0]), p([0, -64, 0])], // exactly on the top / bottom edge + [p([0, 0, -64]), p([0, 0, -70])]]}, // w = 0 | w < 0 (behind the camera) + {name: 'depth_range', mvp: PERSPECTIVE, pairs: [[p([0, 0, -32]), p([0, 0, 32])], [p([0, 0, 100]), p([0, 0, 2000])]]}, + {name: 'colours_and_uvs', mvp: PERSPECTIVE, pairs: [[p([8, 8, 0], {rgba: 0x00000000, st: [-1024, 1023.96875]}), p([-8, -8, 0], {rgba: 0xFFFFFFFF, st: [512.5, -0.03125]})]]}, +]; + +test('vertex loop golden bytes', () => { + const results = []; + for (const c of VERT_CASES) { + u.reset(); + setViewport(u, {width: 320, height: 240, guardBand: c.guardBand ?? 2}); + writeMatrixFP(u, u.sym.MATRIX_MVP, c.mvp); + const RD = 0x00100000, VB = u.sym.VERT_BUFFER; + c.pairs.forEach((pr, i) => writePackedVertexPair(u, RD + i * 32, pr[0], pr[1])); + const inputSize = c.pairs.length * 32; + const dest = vertLoadInputDest(u, inputSize); + for (let i = 0; i < c.pairs.length * 2 * TRI_SIZE; i++) u.w8(VB + i, 0xEE); + const res = u.command('T3DCmd_VertLoad', [inputSize, RD, (dest << 16) | VB]); + results.push({ + name: c.name, + end: res.pc === u.sym.RSPQ_Loop ? 'loop' : `pc=${res.pc.toString(16)}`, + verts: Array.from({length: c.pairs.length * 2}, (_, i) => hex(u.bytes(VB + i * TRI_SIZE, TRI_SIZE))), + }); + } + checkGolden('vertload', results); +}); diff --git a/tests/rsp/golden/sort.json b/tests/rsp/golden/sort.json new file mode 100644 index 00000000..ed09cddd --- /dev/null +++ b/tests/rsp/golden/sort.json @@ -0,0 +1,812 @@ +[ + { + "name": "distinct_012_cull2", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_012_cull0", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_012_cull1", + "drawn": false, + "bytes": "eeee0169005200280168002aff380117eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "distinct_021_cull2", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_021_cull0", + "drawn": false, + "bytes": "eeee0169005200280168002aff380117eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "distinct_021_cull1", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_102_cull2", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_102_cull0", + "drawn": false, + "bytes": "eeee0169005200280168002aff380117eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "distinct_102_cull1", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_120_cull2", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_120_cull0", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_120_cull1", + "drawn": false, + "bytes": "eeee0169005200280168002aff380117eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "distinct_201_cull2", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_201_cull0", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_201_cull1", + "drawn": false, + "bytes": "eeee0169005200280168002aff380117eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "distinct_210_cull2", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "distinct_210_cull0", + "drawn": false, + "bytes": "eeee0169005200280168002aff380117eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "distinct_210_cull1", + "drawn": true, + "bytes": "cf8001690052002800640000ffff487b000a000000007f9a000a00000008925800ff0000000000fffffd0003ffff0000000000000000000062a6021c9b3c0000fffcffff00030000fffefffe00030000d28bffff2d730000202e80245fad000000a000a03fff10000007ffffffb2004700000000000000007d05bca7535b5a2000000002ff6600ccfffc0002ff8d00a87f998130e12a291ac413a2c2988a98781000000000475a2000cc291a00a89878" + }, + { + "name": "tie_top_012_cull2", + "drawn": true, + "bytes": "cf00016800280028000a00000000800000640000ffff5ffe0064000000000000000000ff000000fffffd00020000000000000000000000002aa9d556000000000000fffc00030000fffefffe000300000005cff8300100003aa9955430010000032000501fff30000007ffffffa4005b00000000000000001c751c71fa2005e0fff80003ffcc0066fffc0002ff93009f7fed8003cd6865e5f1c5f1c8e9064a4830000000005b05e0006665e5009f4a48" + }, + { + "name": "tie_top_012_cull0", + "drawn": true, + "bytes": "cf00016800280028000a00000000800000640000ffff5ffe0064000000000000000000ff000000fffffd00020000000000000000000000002aa9d556000000000000fffc00030000fffefffe000300000005cff8300100003aa9955430010000032000501fff30000007ffffffa4005b00000000000000001c751c71fa2005e0fff80003ffcc0066fffc0002ff93009f7fed8003cd6865e5f1c5f1c8e9064a4830000000005b05e0006665e5009f4a48" + }, + { + "name": "tie_top_012_cull1", + "drawn": false, + "bytes": "eeee016800280028fe98000000a00140eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_top_021_cull2", + "drawn": true, + "bytes": "cf00016800280028000a00000000800000640000ffff5ffe0064000000000000000000ff000000fffffd00020000000000000000000000002aa9d556000000000000fffc00030000fffefffe000300000005cff8300100003aa9955430010000032000501fff30000007ffffffa4005b00000000000000001c751c71fa2005e0fff80003ffcc0066fffc0002ff93009f7fed8003cd6865e5f1c5f1c8e9064a4830000000005b05e0006665e5009f4a48" + }, + { + "name": "tie_top_021_cull0", + "drawn": false, + "bytes": "eeee016800280028fe98000000a00140eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_top_021_cull1", + "drawn": true, + "bytes": "cf00016800280028000a00000000800000640000ffff5ffe0064000000000000000000ff000000fffffd00020000000000000000000000002aa9d556000000000000fffc00030000fffefffe000300000005cff8300100003aa9955430010000032000501fff30000007ffffffa4005b00000000000000001c751c71fa2005e0fff80003ffcc0066fffc0002ff93009f7fed8003cd6865e5f1c5f1c8e9064a4830000000005b05e0006665e5009f4a48" + }, + { + "name": "tie_top_102_cull2", + "drawn": true, + "bytes": "cf8001680028002800640000ffff5ffe000a000000008000000a00000000000000ff0000000000fffffd00020000000000000000000000002aa9d55600000000fffcffff00030000fffefffe00030000cffdffff300100003aa995543001000000a000a03fff10000007ffffffa4005b00000000000000001c751c71fa2005e000000002ff6600ccfffc0002ff93009f7fff80006616cd38f1c5f1c8e9064a4810000000005b05e000cccd38009f4a48" + }, + { + "name": "tie_top_102_cull0", + "drawn": false, + "bytes": "eeee01680028002801680000ff380140eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_top_102_cull1", + "drawn": true, + "bytes": "cf8001680028002800640000ffff5ffe000a000000008000000a00000000000000ff0000000000fffffd00020000000000000000000000002aa9d55600000000fffcffff00030000fffefffe00030000cffdffff300100003aa995543001000000a000a03fff10000007ffffffa4005b00000000000000001c751c71fa2005e000000002ff6600ccfffc0002ff93009f7fff80006616cd38f1c5f1c8e9064a4810000000005b05e000cccd38009f4a48" + }, + { + "name": "tie_top_120_cull2", + "drawn": true, + "bytes": "cf8001680028002800640000ffff5ffe000a000000008000000a00000000000000ff0000000000fffffd00020000000000000000000000002aa9d55600000000fffcffff00030000fffefffe00030000cffdffff300100003aa995543001000000a000a03fff10000007ffffffa4005b00000000000000001c751c71fa2005e000000002ff6600ccfffc0002ff93009f7fff80006616cd38f1c5f1c8e9064a4810000000005b05e000cccd38009f4a48" + }, + { + "name": "tie_top_120_cull0", + "drawn": true, + "bytes": "cf8001680028002800640000ffff5ffe000a000000008000000a00000000000000ff0000000000fffffd00020000000000000000000000002aa9d55600000000fffcffff00030000fffefffe00030000cffdffff300100003aa995543001000000a000a03fff10000007ffffffa4005b00000000000000001c751c71fa2005e000000002ff6600ccfffc0002ff93009f7fff80006616cd38f1c5f1c8e9064a4810000000005b05e000cccd38009f4a48" + }, + { + "name": "tie_top_120_cull1", + "drawn": false, + "bytes": "eeee01680028002801680000ff380140eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_top_201_cull2", + "drawn": true, + "bytes": "cf00016800280028000a00000000800000640000ffff5ffe0064000000000000000000ff000000fffffd00020000000000000000000000002aa9d556000000000000fffc00030000fffefffe000300000005cff8300100003aa9955430010000032000501fff30000007ffffffa4005b00000000000000001c751c71fa2005e0fff80003ffcc0066fffc0002ff93009f7fed8003cd6865e5f1c5f1c8e9064a4830000000005b05e0006665e5009f4a48" + }, + { + "name": "tie_top_201_cull0", + "drawn": true, + "bytes": "cf00016800280028000a00000000800000640000ffff5ffe0064000000000000000000ff000000fffffd00020000000000000000000000002aa9d556000000000000fffc00030000fffefffe000300000005cff8300100003aa9955430010000032000501fff30000007ffffffa4005b00000000000000001c751c71fa2005e0fff80003ffcc0066fffc0002ff93009f7fed8003cd6865e5f1c5f1c8e9064a4830000000005b05e0006665e5009f4a48" + }, + { + "name": "tie_top_201_cull1", + "drawn": false, + "bytes": "eeee016800280028fe98000000a00140eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_top_210_cull2", + "drawn": true, + "bytes": "cf8001680028002800640000ffff5ffe000a000000008000000a00000000000000ff0000000000fffffd00020000000000000000000000002aa9d55600000000fffcffff00030000fffefffe00030000cffdffff300100003aa995543001000000a000a03fff10000007ffffffa4005b00000000000000001c751c71fa2005e000000002ff6600ccfffc0002ff93009f7fff80006616cd38f1c5f1c8e9064a4810000000005b05e000cccd38009f4a48" + }, + { + "name": "tie_top_210_cull0", + "drawn": false, + "bytes": "eeee01680028002801680000ff380140eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_top_210_cull1", + "drawn": true, + "bytes": "cf8001680028002800640000ffff5ffe000a000000008000000a00000000000000ff0000000000fffffd00020000000000000000000000002aa9d55600000000fffcffff00030000fffefffe00030000cffdffff300100003aa995543001000000a000a03fff10000007ffffffa4005b00000000000000001c751c71fa2005e000000002ff6600ccfffc0002ff93009f7fff80006616cd38f1c5f1c8e9064a4810000000005b05e000cccd38009f4a48" + }, + { + "name": "tie_bottom_012_cull2", + "drawn": true, + "bytes": "cf000168016800280032000000000000000a000000012001000a00000000800000ff0000000000ff00000005fffa00000000000000000000000019a4e65b0000fffc0003ffff0000fffcfffd00050000cff9300afff90000cff9732dbcd8000000a000a03fff1000000c00070051ff5c000000000000000000193342ec3027a000080007ff990066fffafffeff3d011e001c0015991566987ff4e6646f0ebaa810000000ff5c27a000666698011ebaa8" + }, + { + "name": "tie_bottom_012_cull0", + "drawn": true, + "bytes": "cf000168016800280032000000000000000a000000012001000a00000000800000ff0000000000ff00000005fffa00000000000000000000000019a4e65b0000fffc0003ffff0000fffcfffd00050000cff9300afff90000cff9732dbcd8000000a000a03fff1000000c00070051ff5c000000000000000000193342ec3027a000080007ff990066fffafffeff3d011e001c0015991566987ff4e6646f0ebaa810000000ff5c27a000666698011ebaa8" + }, + { + "name": "tie_bottom_012_cull1", + "drawn": false, + "bytes": "eeee01680168002800a0014000c80000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_bottom_021_cull2", + "drawn": true, + "bytes": "cf800168016800280064000000000000000a000000008000000a00000001200100ff0000000000ff00000005fffa000000000000000000000000199fe6600000fffcffff00030000fffcfffd00050000cffcffff30030000cffc7330bcd3000000a000a03fff1000000c00070051ff5c0000000000000000000d333bebe0284000000002ff6600ccfffafffeff3d011e7fff800265bccdb07ff9e6656fccb99010000000ff5c284000cccdb0011eb990" + }, + { + "name": "tie_bottom_021_cull0", + "drawn": false, + "bytes": "eeee01680168002801680140ff380000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_bottom_021_cull1", + "drawn": true, + "bytes": "cf800168016800280064000000000000000a000000008000000a00000001200100ff0000000000ff00000005fffa000000000000000000000000199fe6600000fffcffff00030000fffcfffd00050000cffcffff30030000cffc7330bcd3000000a000a03fff1000000c00070051ff5c0000000000000000000d333bebe0284000000002ff6600ccfffafffeff3d011e7fff800265bccdb07ff9e6656fccb99010000000ff5c284000cccdb0011eb990" + }, + { + "name": "tie_bottom_102_cull2", + "drawn": true, + "bytes": "cf000168016800280032000000000000000a000000012001000a00000000800000ff0000000000ff00000005fffa00000000000000000000000019a4e65b0000fffc0003ffff0000fffcfffd00050000cff9300afff90000cff9732dbcd8000000a000a03fff1000000c00070051ff5c000000000000000000193342ec3027a000080007ff990066fffafffeff3d011e001c0015991566987ff4e6646f0ebaa810000000ff5c27a000666698011ebaa8" + }, + { + "name": "tie_bottom_102_cull0", + "drawn": false, + "bytes": "eeee01680168002800a0014000c80000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_bottom_102_cull1", + "drawn": true, + "bytes": "cf000168016800280032000000000000000a000000012001000a00000000800000ff0000000000ff00000005fffa00000000000000000000000019a4e65b0000fffc0003ffff0000fffcfffd00050000cff9300afff90000cff9732dbcd8000000a000a03fff1000000c00070051ff5c000000000000000000193342ec3027a000080007ff990066fffafffeff3d011e001c0015991566987ff4e6646f0ebaa810000000ff5c27a000666698011ebaa8" + }, + { + "name": "tie_bottom_120_cull2", + "drawn": true, + "bytes": "cf000168016800280032000000000000000a000000012001000a00000000800000ff0000000000ff00000005fffa00000000000000000000000019a4e65b0000fffc0003ffff0000fffcfffd00050000cff9300afff90000cff9732dbcd8000000a000a03fff1000000c00070051ff5c000000000000000000193342ec3027a000080007ff990066fffafffeff3d011e001c0015991566987ff4e6646f0ebaa810000000ff5c27a000666698011ebaa8" + }, + { + "name": "tie_bottom_120_cull0", + "drawn": true, + "bytes": "cf000168016800280032000000000000000a000000012001000a00000000800000ff0000000000ff00000005fffa00000000000000000000000019a4e65b0000fffc0003ffff0000fffcfffd00050000cff9300afff90000cff9732dbcd8000000a000a03fff1000000c00070051ff5c000000000000000000193342ec3027a000080007ff990066fffafffeff3d011e001c0015991566987ff4e6646f0ebaa810000000ff5c27a000666698011ebaa8" + }, + { + "name": "tie_bottom_120_cull1", + "drawn": false, + "bytes": "eeee01680168002800a0014000c80000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_bottom_201_cull2", + "drawn": true, + "bytes": "cf800168016800280064000000000000000a000000008000000a00000001200100ff0000000000ff00000005fffa000000000000000000000000199fe6600000fffcffff00030000fffcfffd00050000cffcffff30030000cffc7330bcd3000000a000a03fff1000000c00070051ff5c0000000000000000000d333bebe0284000000002ff6600ccfffafffeff3d011e7fff800265bccdb07ff9e6656fccb99010000000ff5c284000cccdb0011eb990" + }, + { + "name": "tie_bottom_201_cull0", + "drawn": true, + "bytes": "cf800168016800280064000000000000000a000000008000000a00000001200100ff0000000000ff00000005fffa000000000000000000000000199fe6600000fffcffff00030000fffcfffd00050000cffcffff30030000cffc7330bcd3000000a000a03fff1000000c00070051ff5c0000000000000000000d333bebe0284000000002ff6600ccfffafffeff3d011e7fff800265bccdb07ff9e6656fccb99010000000ff5c284000cccdb0011eb990" + }, + { + "name": "tie_bottom_201_cull1", + "drawn": false, + "bytes": "eeee01680168002801680140ff380000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_bottom_210_cull2", + "drawn": true, + "bytes": "cf800168016800280064000000000000000a000000008000000a00000001200100ff0000000000ff00000005fffa000000000000000000000000199fe6600000fffcffff00030000fffcfffd00050000cffcffff30030000cffc7330bcd3000000a000a03fff1000000c00070051ff5c0000000000000000000d333bebe0284000000002ff6600ccfffafffeff3d011e7fff800265bccdb07ff9e6656fccb99010000000ff5c284000cccdb0011eb990" + }, + { + "name": "tie_bottom_210_cull0", + "drawn": false, + "bytes": "eeee01680168002801680140ff380000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_bottom_210_cull1", + "drawn": true, + "bytes": "cf800168016800280064000000000000000a000000008000000a00000001200100ff0000000000ff00000005fffa000000000000000000000000199fe6600000fffcffff00030000fffcfffd00050000cffcffff30030000cffc7330bcd3000000a000a03fff1000000c00070051ff5c0000000000000000000d333bebe0284000000002ff6600ccfffafffeff3d011e7fff800265bccdb07ff9e6656fccb99010000000ff5c284000cccdb0011eb990" + }, + { + "name": "tie_outer_012_cull2", + "drawn": true, + "bytes": "cf0000c800280028000a000000024003003200000001400200320000000000000000000000ff00fffff900000006000000000000000000009ffb000060040000ffff0006fff9000000070006fff10000fff16004a0060000f8056004a7f5000000c800280fff50000001fffcfecc019900000000000000000000fffdcbf09ac0000f00080066ff33000d000c01e6fd33000bffff644935d3c009c00967c431305000000001999ac0ff3335d3fd333130" + }, + { + "name": "tie_outer_012_cull0", + "drawn": false, + "bytes": "eeee00c800280028ff600000016800a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_outer_012_cull1", + "drawn": true, + "bytes": "cf0000c800280028000a000000024003003200000001400200320000000000000000000000ff00fffff900000006000000000000000000009ffb000060040000ffff0006fff9000000070006fff10000fff16004a0060000f8056004a7f5000000c800280fff50000001fffcfecc019900000000000000000000fffdcbf09ac0000f00080066ff33000d000c01e6fd33000bffff644935d3c009c00967c431305000000001999ac0ff3335d3fd333130" + }, + { + "name": "tie_outer_021_cull2", + "drawn": true, + "bytes": "cf0000c800280028000a000000024003003200000001400200320000000000000000000000ff00fffff900000006000000000000000000009ffb000060040000ffff0006fff9000000070006fff10000fff16004a0060000f8056004a7f5000000c800280fff50000001fffcfecc019900000000000000000000fffdcbf09ac0000f00080066ff33000d000c01e6fd33000bffff644935d3c009c00967c431305000000001999ac0ff3335d3fd333130" + }, + { + "name": "tie_outer_021_cull0", + "drawn": true, + "bytes": "cf0000c800280028000a000000024003003200000001400200320000000000000000000000ff00fffff900000006000000000000000000009ffb000060040000ffff0006fff9000000070006fff10000fff16004a0060000f8056004a7f5000000c800280fff50000001fffcfecc019900000000000000000000fffdcbf09ac0000f00080066ff33000d000c01e6fd33000bffff644935d3c009c00967c431305000000001999ac0ff3335d3fd333130" + }, + { + "name": "tie_outer_021_cull1", + "drawn": false, + "bytes": "eeee00c800280028ff600000016800a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_outer_102_cull2", + "drawn": true, + "bytes": "cf0000c800280028000a000000024003003200000001400200320000000000000000000000ff00fffff900000006000000000000000000009ffb000060040000ffff0006fff9000000070006fff10000fff16004a0060000f8056004a7f5000000c800280fff50000001fffcfecc019900000000000000000000fffdcbf09ac0000f00080066ff33000d000c01e6fd33000bffff644935d3c009c00967c431305000000001999ac0ff3335d3fd333130" + }, + { + "name": "tie_outer_102_cull0", + "drawn": true, + "bytes": "cf0000c800280028000a000000024003003200000001400200320000000000000000000000ff00fffff900000006000000000000000000009ffb000060040000ffff0006fff9000000070006fff10000fff16004a0060000f8056004a7f5000000c800280fff50000001fffcfecc019900000000000000000000fffdcbf09ac0000f00080066ff33000d000c01e6fd33000bffff644935d3c009c00967c431305000000001999ac0ff3335d3fd333130" + }, + { + "name": "tie_outer_102_cull1", + "drawn": false, + "bytes": "eeee00c800280028ff600000016800a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_outer_120_cull2", + "drawn": true, + "bytes": "cf8000c8002800280032000000014002000a000000024003000a00000000000000ff0000000000fffff900000006000000000000000000009ff30000600c0000fff900060000000000070006fff100009fde600c00120000f80f600ca7e4000000a000a03fff10000001fffcfecc019900000000000000000001fffaca889ca000100006ff3300cc000d000c01e6fd33001e00012e16d31cc019c01869fe2de81000000001999ca000ccd31cfd332de8" + }, + { + "name": "tie_outer_120_cull0", + "drawn": false, + "bytes": "eeee00c80028002800a0000000c800a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_outer_120_cull1", + "drawn": true, + "bytes": "cf8000c8002800280032000000014002000a000000024003000a00000000000000ff0000000000fffff900000006000000000000000000009ff30000600c0000fff900060000000000070006fff100009fde600c00120000f80f600ca7e4000000a000a03fff10000001fffcfecc019900000000000000000001fffaca889ca000100006ff3300cc000d000c01e6fd33001e00012e16d31cc019c01869fe2de81000000001999ca000ccd31cfd332de8" + }, + { + "name": "tie_outer_201_cull2", + "drawn": true, + "bytes": "cf8000c8002800280032000000014002000a000000024003000a00000000000000ff0000000000fffff900000006000000000000000000009ff30000600c0000fff900060000000000070006fff100009fde600c00120000f80f600ca7e4000000a000a03fff10000001fffcfecc019900000000000000000001fffaca889ca000100006ff3300cc000d000c01e6fd33001e00012e16d31cc019c01869fe2de81000000001999ca000ccd31cfd332de8" + }, + { + "name": "tie_outer_201_cull0", + "drawn": false, + "bytes": "eeee00c80028002800a0000000c800a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_outer_201_cull1", + "drawn": true, + "bytes": "cf8000c8002800280032000000014002000a000000024003000a00000000000000ff0000000000fffff900000006000000000000000000009ff30000600c0000fff900060000000000070006fff100009fde600c00120000f80f600ca7e4000000a000a03fff10000001fffcfecc019900000000000000000001fffaca889ca000100006ff3300cc000d000c01e6fd33001e00012e16d31cc019c01869fe2de81000000001999ca000ccd31cfd332de8" + }, + { + "name": "tie_outer_210_cull2", + "drawn": true, + "bytes": "cf8000c8002800280032000000014002000a000000024003000a00000000000000ff0000000000fffff900000006000000000000000000009ff30000600c0000fff900060000000000070006fff100009fde600c00120000f80f600ca7e4000000a000a03fff10000001fffcfecc019900000000000000000001fffaca889ca000100006ff3300cc000d000c01e6fd33001e00012e16d31cc019c01869fe2de81000000001999ca000ccd31cfd332de8" + }, + { + "name": "tie_outer_210_cull0", + "drawn": true, + "bytes": "cf8000c8002800280032000000014002000a000000024003000a00000000000000ff0000000000fffff900000006000000000000000000009ff30000600c0000fff900060000000000070006fff100009fde600c00120000f80f600ca7e4000000a000a03fff10000001fffcfecc019900000000000000000001fffaca889ca000100006ff3300cc000d000c01e6fd33001e00012e16d31cc019c01869fe2de81000000001999ca000ccd31cfd332de8" + }, + { + "name": "tie_outer_210_cull1", + "drawn": false, + "bytes": "eeee00c80028002800a0000000c800a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_012_cull2", + "drawn": true, + "bytes": "cf8000a000a000a00064000000000000003200000000000000320000000000000000000000ff00ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c800a00fff5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "all_equal_012_cull0", + "drawn": false, + "bytes": "eeee00a000a000a000c80000fe980000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_012_cull1", + "drawn": true, + "bytes": "cf8000a000a000a00064000000000000003200000000000000320000000000000000000000ff00ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c800a00fff5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "all_equal_021_cull2", + "drawn": true, + "bytes": "cf8000a000a000a0003200000000000000640000000000000064000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032001401fff3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "all_equal_021_cull0", + "drawn": false, + "bytes": "eeee00a000a000a0ff380000ff600000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_021_cull1", + "drawn": true, + "bytes": "cf8000a000a000a0003200000000000000640000000000000064000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032001401fff3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "all_equal_102_cull2", + "drawn": true, + "bytes": "cf8000a000a000a0000a000000000000003200000000000000320000000000000000000000ff00ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c800a00fff5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "all_equal_102_cull0", + "drawn": false, + "bytes": "eeee00a000a000a0ff60000001680000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_102_cull1", + "drawn": true, + "bytes": "cf8000a000a000a0000a000000000000003200000000000000320000000000000000000000ff00ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c800a00fff5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "all_equal_120_cull2", + "drawn": true, + "bytes": "cf8000a000a000a00032000000000000000a000000000000000a00000000000000ff0000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a002803fff1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "all_equal_120_cull0", + "drawn": false, + "bytes": "eeee00a000a000a000a0000000c80000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_120_cull1", + "drawn": true, + "bytes": "cf8000a000a000a00032000000000000000a000000000000000a00000000000000ff0000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a002803fff1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "all_equal_201_cull2", + "drawn": true, + "bytes": "cf8000a000a000a0000a00000000000000640000000000000064000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032001401fff3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "all_equal_201_cull0", + "drawn": false, + "bytes": "eeee00a000a000a0fe98000000a00000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_201_cull1", + "drawn": true, + "bytes": "cf8000a000a000a0000a00000000000000640000000000000064000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032001401fff3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "all_equal_210_cull2", + "drawn": true, + "bytes": "cf8000a000a000a00064000000000000000a000000000000000a00000000000000ff0000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a002803fff1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "all_equal_210_cull0", + "drawn": false, + "bytes": "eeee00a000a000a001680000ff380000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "all_equal_210_cull1", + "drawn": true, + "bytes": "cf8000a000a000a00064000000000000000a000000000000000a00000000000000ff0000000000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a002803fff1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "tie_frac_012_cull2", + "drawn": true, + "bytes": "cf00016800290029000a00000000806700642820ffff5f7e0064000000000000ffff00ffffff00fffffd000200000000ffffcca7335a00002aa3d55c000000000000fffc00030000fffefffe000300000004cd6432960000393a942e3296000003210051200b2fe60007ffffffa4005be18920e4d70e51bf1c8316bff96c0693fff80003ffcc0066fffc0002ff93009f79dc7c6da3c7b902ef4bea2e9172cb582fe651bf005b06930066b902009fcb58" + }, + { + "name": "tie_frac_012_cull0", + "drawn": true, + "bytes": "cf00016800290029000a00000000806700642820ffff5f7e0064000000000000ffff00ffffff00fffffd000200000000ffffcca7335a00002aa3d55c000000000000fffc00030000fffefffe000300000004cd6432960000393a942e3296000003210051200b2fe60007ffffffa4005be18920e4d70e51bf1c8316bff96c0693fff80003ffcc0066fffc0002ff93009f79dc7c6da3c7b902ef4bea2e9172cb582fe651bf005b06930066b902009fcb58" + }, + { + "name": "tie_frac_012_cull1", + "drawn": false, + "bytes": "eeee016800290029fe98000000a0013feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_frac_021_cull2", + "drawn": true, + "bytes": "cf00016800290029000a00000000806700642820ffff5f7e0064000000000000ffff00ffffff00fffffd000200000000ffffcca7335a00002aa3d55c000000000000fffc00030000fffefffe000300000004cd6432960000393a942e3296000003210051200b2fe60007ffffffa4005be18920e4d70e51bf1c8316bff96c0693fff80003ffcc0066fffc0002ff93009f79dc7c6da3c7b902ef4bea2e9172cb582fe651bf005b06930066b902009fcb58" + }, + { + "name": "tie_frac_021_cull0", + "drawn": false, + "bytes": "eeee016800290029fe98000000a0013feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_frac_021_cull1", + "drawn": true, + "bytes": "cf00016800290029000a00000000806700642820ffff5f7e0064000000000000ffff00ffffff00fffffd000200000000ffffcca7335a00002aa3d55c000000000000fffc00030000fffefffe000300000004cd6432960000393a942e3296000003210051200b2fe60007ffffffa4005be18920e4d70e51bf1c8316bff96c0693fff80003ffcc0066fffc0002ff93009f79dc7c6da3c7b902ef4bea2e9172cb582fe651bf005b06930066b902009fcb58" + }, + { + "name": "tie_frac_102_cull2", + "drawn": true, + "bytes": "cf8001680029002900640000ffff5f7e0009dfe600008067000a00000000000000ff0000ffff00fffffd000200000000cca40000335b00002aa8d55700000000fffc000000030000fffefffe00030000cd6d000032910000393d943132910000009f00a340250fcc0007ffffffa4005bdfe662b5855aa3891c7716c0fa0c05f400000002ff6500cdfffc0002ff93009f8068752bea9671d9ef51ea299230ca400fcca389005b05f400cd71d9009fca40" + }, + { + "name": "tie_frac_102_cull0", + "drawn": false, + "bytes": "eeee01680029002901680000ff38013feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_frac_102_cull1", + "drawn": true, + "bytes": "cf8001680029002900640000ffff5f7e0009dfe600008067000a00000000000000ff0000ffff00fffffd000200000000cca40000335b00002aa8d55700000000fffc000000030000fffefffe00030000cd6d000032910000393d943132910000009f00a340250fcc0007ffffffa4005bdfe662b5855aa3891c7716c0fa0c05f400000002ff6500cdfffc0002ff93009f8068752bea9671d9ef51ea299230ca400fcca389005b05f400cd71d9009fca40" + }, + { + "name": "tie_frac_120_cull2", + "drawn": true, + "bytes": "cf8001680029002900640000ffff5f7e0009dfe600008067000a00000000000000ff0000ffff00fffffd000200000000cca40000335b00002aa8d55700000000fffc000000030000fffefffe00030000cd6d000032910000393d943132910000009f00a340250fcc0007ffffffa4005bdfe662b5855aa3891c7716c0fa0c05f400000002ff6500cdfffc0002ff93009f8068752bea9671d9ef51ea299230ca400fcca389005b05f400cd71d9009fca40" + }, + { + "name": "tie_frac_120_cull0", + "drawn": true, + "bytes": "cf8001680029002900640000ffff5f7e0009dfe600008067000a00000000000000ff0000ffff00fffffd000200000000cca40000335b00002aa8d55700000000fffc000000030000fffefffe00030000cd6d000032910000393d943132910000009f00a340250fcc0007ffffffa4005bdfe662b5855aa3891c7716c0fa0c05f400000002ff6500cdfffc0002ff93009f8068752bea9671d9ef51ea299230ca400fcca389005b05f400cd71d9009fca40" + }, + { + "name": "tie_frac_120_cull1", + "drawn": false, + "bytes": "eeee01680029002901680000ff38013feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_frac_201_cull2", + "drawn": true, + "bytes": "cf00016800290029000a00000000806700642820ffff5f7e0064000000000000ffff00ffffff00fffffd000200000000ffffcca7335a00002aa3d55c000000000000fffc00030000fffefffe000300000004cd6432960000393a942e3296000003210051200b2fe60007ffffffa4005be18920e4d70e51bf1c8316bff96c0693fff80003ffcc0066fffc0002ff93009f79dc7c6da3c7b902ef4bea2e9172cb582fe651bf005b06930066b902009fcb58" + }, + { + "name": "tie_frac_201_cull0", + "drawn": true, + "bytes": "cf00016800290029000a00000000806700642820ffff5f7e0064000000000000ffff00ffffff00fffffd000200000000ffffcca7335a00002aa3d55c000000000000fffc00030000fffefffe000300000004cd6432960000393a942e3296000003210051200b2fe60007ffffffa4005be18920e4d70e51bf1c8316bff96c0693fff80003ffcc0066fffc0002ff93009f79dc7c6da3c7b902ef4bea2e9172cb582fe651bf005b06930066b902009fcb58" + }, + { + "name": "tie_frac_201_cull1", + "drawn": false, + "bytes": "eeee016800290029fe98000000a0013feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_frac_210_cull2", + "drawn": true, + "bytes": "cf8001680029002900640000ffff5f7e0009dfe600008067000a00000000000000ff0000ffff00fffffd000200000000cca40000335b00002aa8d55700000000fffc000000030000fffefffe00030000cd6d000032910000393d943132910000009f00a340250fcc0007ffffffa4005bdfe662b5855aa3891c7716c0fa0c05f400000002ff6500cdfffc0002ff93009f8068752bea9671d9ef51ea299230ca400fcca389005b05f400cd71d9009fca40" + }, + { + "name": "tie_frac_210_cull0", + "drawn": false, + "bytes": "eeee01680029002901680000ff38013feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "tie_frac_210_cull1", + "drawn": true, + "bytes": "cf8001680029002900640000ffff5f7e0009dfe600008067000a00000000000000ff0000ffff00fffffd000200000000cca40000335b00002aa8d55700000000fffc000000030000fffefffe00030000cd6d000032910000393d943132910000009f00a340250fcc0007ffffffa4005bdfe662b5855aa3891c7716c0fa0c05f400000002ff6500cdfffc0002ff93009f8068752bea9671d9ef51ea299230ca400fcca389005b05f400cd71d9009fca40" + }, + { + "name": "negative_012_cull2", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_012_cull0", + "drawn": false, + "bytes": "eeeeffb0ff10fee8012c0028ff9c00a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "negative_012_cull1", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_021_cull2", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_021_cull0", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_021_cull1", + "drawn": false, + "bytes": "eeeeffb0ff10fee8012c0028ff9c00a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "negative_102_cull2", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_102_cull0", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_102_cull1", + "drawn": false, + "bytes": "eeeeffb0ff10fee8012c0028ff9c00a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "negative_120_cull2", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_120_cull0", + "drawn": false, + "bytes": "eeeeffb0ff10fee8012c0028ff9c00a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "negative_120_cull1", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_201_cull2", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_201_cull0", + "drawn": false, + "bytes": "eeeeffb0ff10fee8012c0028ff9c00a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "negative_201_cull1", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_210_cull2", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_210_cull0", + "drawn": true, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c0000000000ff00ffffff0003fffc000000000000000000003723ec4ddc8f000000050000fffa00000005fffcfffe000019950002e6640000e27313b209d90000fcabfd152aaa5000000afffe0010ffb40000000000000000fd9e5cf3cbfc61cc00070008006dfeb8fffc000a005cff0375c88a373834522878202d466c28f0a850000000ffb461ccfeb85228ff03f0a8" + }, + { + "name": "negative_210_cull1", + "drawn": false, + "bytes": "eeeeffb0ff10fee8012c0028ff9c00a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_012_cull2", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_012_cull0", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_012_cull1", + "drawn": false, + "bytes": "eeee016800c80028000000a0000000a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_021_cull2", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_021_cull0", + "drawn": false, + "bytes": "eeee016800c80028000000a0000000a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_021_cull1", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_102_cull2", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_102_cull0", + "drawn": false, + "bytes": "eeee016800c80028000000a0000000a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_102_cull1", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_120_cull2", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_120_cull0", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_120_cull1", + "drawn": false, + "bytes": "eeee016800c80028000000a0000000a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_201_cull2", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_201_cull0", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_201_cull1", + "drawn": false, + "bytes": "eeee016800c80028000000a0000000a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_210_cull2", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_x_210_cull0", + "drawn": false, + "bytes": "eeee016800c80028000000a0000000a0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_x_210_cull1", + "drawn": true, + "bytes": "cf80016800c8002800280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80ff60c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_point_012_cull2", + "drawn": true, + "bytes": "cf8000a000a000a00028000000000000002800000000000000280000000000000000000000ff00ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "same_point_012_cull0", + "drawn": false, + "bytes": "eeee00a000a000a00000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_point_012_cull1", + "drawn": true, + "bytes": "cf8000a000a000a00028000000000000002800000000000000280000000000000000000000ff00ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "same_point_021_cull2", + "drawn": true, + "bytes": "cf8000a000a000a0002800000000000000280000000000000028000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "same_point_021_cull0", + "drawn": false, + "bytes": "eeee00a000a000a00000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_point_021_cull1", + "drawn": true, + "bytes": "cf8000a000a000a0002800000000000000280000000000000028000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "same_point_102_cull2", + "drawn": true, + "bytes": "cf8000a000a000a00028000000000000002800000000000000280000000000000000000000ff00ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "same_point_102_cull0", + "drawn": false, + "bytes": "eeee00a000a000a00000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_point_102_cull1", + "drawn": true, + "bytes": "cf8000a000a000a00028000000000000002800000000000000280000000000000000000000ff00ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0005000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000" + }, + { + "name": "same_point_120_cull2", + "drawn": true, + "bytes": "cf8000a000a000a000280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_point_120_cull0", + "drawn": false, + "bytes": "eeee00a000a000a00000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_point_120_cull1", + "drawn": true, + "bytes": "cf8000a000a000a000280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_point_201_cull2", + "drawn": true, + "bytes": "cf8000a000a000a0002800000000000000280000000000000028000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "same_point_201_cull0", + "drawn": false, + "bytes": "eeee00a000a000a00000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_point_201_cull1", + "drawn": true, + "bytes": "cf8000a000a000a0002800000000000000280000000000000028000000000000000000ff000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000" + }, + { + "name": "same_point_210_cull2", + "drawn": true, + "bytes": "cf8000a000a000a000280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + }, + { + "name": "same_point_210_cull0", + "drawn": false, + "bytes": "eeee00a000a000a00000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "same_point_210_cull1", + "drawn": true, + "bytes": "cf8000a000a000a000280000000000000028000000000000002800000000000000ff0000000000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fd80fd80c0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000" + } +] diff --git a/tests/rsp/golden/triangle.json b/tests/rsp/golden/triangle.json new file mode 100644 index 00000000..e5c36032 --- /dev/null +++ b/tests/rsp/golden/triangle.json @@ -0,0 +1,242 @@ +[ + { + "name": "basic", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8001680050002800640000ffff4923000a000000008000000a00000009000e00ff0000000000fffffd0003ffff000000000000000000005fff00009fff0000fffcffff00030000fffefffe00030000cffeffff300000001fff7fff60010000000000003fff10000003ffffffb1004800000000000000000304cfcfb198486000000001ff6600ccfffe0001ff8d00a8000099996634cd107e7eb1b28d68a8e0100000000048486000cccd1000a8a8e0" + }, + { + "name": "fractional_positions", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf80016a0051002b00648000ffff4ab30009de7e0000820200031ff400098010008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffe406d200000010000ffc10000f18f476e0f1e0000ec511b9259b6000000000002ff6d0000ffff0002ff8d000013414b6d412d0000193d3d6d121c000020000000000000000000000000000000" + }, + { + "name": "reversed_winding", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8001680050002800640000ffff4923000a000000008000000a00000009000e008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff20000003ffffffb1000000000000000000000304cfcfb198000000000001ff660000fffe0001ff8d000000009999663400007e7eb1b28d68000020000000000000000000000000000000" + }, + { + "name": "unsorted_input", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8001680050002800640000ffff4923000a000000008000000a00000009000e00ff0000000000fffffd0003ffff000000000000000000005fff00009fff0000fffcffff00030000fffefffe00030000cffeffff300000001fff7fff60010000000000003fff200000000000ffb10000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d68000020000000000000000000000000000000" + }, + { + "name": "flat_top", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf00014000280028000a00000000b6dc00780000ffff24900078000000000000008000c0004000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000200000000000000000000000000000000000000000000000000000000000017600000000000001760000000000007d090000000000007d09000020000000000000000000000000000000" + }, + { + "name": "flat_bottom", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf800140014000140078000000000000003c0000ffff5554003c00000000ccce008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002666200000000000000000000000000000000000000000000000000000000000fea2000000000000fea200000000000079dd00000000000079dd000020000000000000000000000000000000" + }, + { + "name": "all_same_y", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8000a000a000a0003c00000000000000780000000000000078000000000000008000c0004000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000" + }, + { + "name": "zero_area_vertical", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf80016800c80028002800000000000000280000000000000028000000000000008000c0004000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000" + }, + { + "name": "sliver", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf00032001900028000a4000000001eb000a000000000158000a0000000000b6008000c0004000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000" + }, + { + "name": "guard_band_extent", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf800af0fb50f8f803b60000ffff5998fda800000000c85afda80000000a5569008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff2000ffff0000fff70000000000000000000084694a28f75a00000004fffdfffb00000004fffd000100009c5a3bbd47470000fd1401b490dc000020000000000000000000000000000000" + }, + { + "name": "negative_coords", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf80ffb0ff10fee8fffb0000ffff5ffeffb0000000010001ffb000000007800c008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002aaa20000000000000100000000000000000000000000000cbfc000000000000006d000000000000005c00000000000038340000000000006c28000020000000000000000000000000000000" + }, + { + "name": "w_close_to_one", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8003200078005000c80000ffff5a59001400000000638e001400000012001d008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff20000000000000010000000000000000000000000000b78f000000000000ffe1000000000000ffe0000000000000a93c000000000000fe4c000020000000000000000000000000000000" + }, + { + "name": "w_large", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8003200078005000c80000ffff5a59001400000000638e001400000012001d008000c0004000ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0732000000000000091000000000000000000000000000071900000000000000073000000000000003a0000000000006098000000000000d101000020000000000000000000000000000000" + }, + { + "name": "w_not_power_of_two", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8003200078005000c80000ffff5a59001400000000638e001400000012001d008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff200000000000ffe700000000000000000000000000002874000000000000ffc6000000000000ffd0000000000000fe96000000000000a7b9000020000000000000000000000000000000" + }, + { + "name": "colour_extremes", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8003200078005000c80000ffff5a59001400000000638e001400000012001d0000000000000000000100010001000100000000000000005e1572ac5e1572ac0001ffff0001ffff0000ffff0000ffff6aaaffff6aaaffffe2866fd9e2866fd9000000003fff2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000" + }, + { + "name": "st_saturation", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8003200078005000c80000ffff5a59001400000000638e001400000012001d008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c1813e7f3fff200000b2ff4d000000000000000000000000bb7643e4000000000058ffa7000000000013ffec00000000ed5d1e01000000006bbb9fe50000000020000000000000000000000000000000" + }, + { + "name": "depth_extremes", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8003200078005000c80000ffff5a59001400000000638e001400000012001d008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff000000000000000000b40000000000000000000000000000e3eb000000000000005b0000000000000014000000000000058a000000000000ad100000000000b4e3eb005b058a0014ad10" + }, + { + "name": "tile_3", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8301680050002800640000ffff4923000a000000008000000a00000009000e008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff200000000000ffb10000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d68000020000000000000000000000000000000" + }, + { + "name": "cmd_shade_only", + "end": "return", + "rdramAdvance": 96, + "s3": 3680, + "s7": 176, + "bytes": "cc8001680050002800640000ffff4923000a000000008000000a00000009000e00ff0000000000fffffd0003ffff000000000000000000005fff00009fff0000fffcffff00030000fffefffe00030000cffeffff300000001fff7fff6001000020000000000000000000000000000000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d680000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "cmd_shade_z", + "end": "return", + "rdramAdvance": 112, + "s3": 3696, + "s7": 176, + "bytes": "cd8001680050002800640000ffff4923000a000000008000000a00000009000e008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000063c3e4016333a7013151b5000000000000000000000000b198c3e400000000ff66016300000000ff8d013100000000663433a7000000008d6851b5eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "cmd_tex_z", + "end": "return", + "rdramAdvance": 112, + "s3": 3696, + "s7": 176, + "bytes": "cb8001680050002800640000ffff4923000a000000008000000a00000009000e000000003fff20000003ffffffb1000000000000000000000304cfcfb198000000000001ff660000fffe0001ff8d000000009999663400007e7eb1b28d68000020000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "cmd_tex_only", + "end": "return", + "rdramAdvance": 96, + "s3": 3680, + "s7": 176, + "bytes": "ca8001680050002800640000ffff4923000a000000008000000a00000009000e000000003fff20000003ffffffb1000000000000000000000304cfcfb198000000000001ff660000fffe0001ff8d000000009999663400007e7eb1b28d68000020000000000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "cmd_flat", + "end": "return", + "rdramAdvance": 32, + "s3": 3616, + "s7": 176, + "bytes": "c88001680050002800640000ffff4923000a000000008000000a00000009000e20000000000000000000000000000000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d680000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "buffer_offset_176", + "end": "return", + "rdramAdvance": 176, + "s3": 3936, + "s7": 0, + "bytes": "cf8001680050002800640000ffff4923000a000000008000000a00000009000e008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff200000000000ffb10000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d68000020000000000000000000000000000000" + }, + { + "name": "cull_front_ccw", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8001680050002800640000ffff4923000a000000008000000a00000009000e008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff200000000000ffb10000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d68000020000000000000000000000000000000" + }, + { + "name": "cull_back_ccw", + "end": "return", + "rdramAdvance": 0, + "s3": 3584, + "s7": 176, + "bytes": "eeee01680050002801680028ff380118eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "cull_front_cw", + "end": "return", + "rdramAdvance": 0, + "s3": 3584, + "s7": 176, + "bytes": "eeee01680050002801680028ff380118eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "cull_back_cw", + "end": "return", + "rdramAdvance": 176, + "s3": 3760, + "s7": 176, + "bytes": "cf8001680050002800640000ffff4923000a000000008000000a00000009000e008000c0004000ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fff200000000000ffb10000000000000000000000000000b198000000000000ff66000000000000ff8d00000000000066340000000000008d68000020000000000000000000000000000000" + }, + { + "name": "rejected", + "end": "return", + "rdramAdvance": 0, + "s3": 0, + "s7": 0, + "bytes": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + }, + { + "name": "clip_handoff", + "end": "clip", + "rdramAdvance": 0, + "s3": 3584, + "s7": 0, + "bytes": "eeeeeeeeeeee0028eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + } +] diff --git a/tests/rsp/golden/vertload.json b/tests/rsp/golden/vertload.json new file mode 100644 index 00000000..a7ec60cb --- /dev/null +++ b/tests/rsp/golden/vertload.json @@ -0,0 +1,52 @@ +[ + { + "name": "perspective_inside", + "end": "loop", + "verts": [ + "02cf02395ffd00ff0f1f2ffe014002800000ffff000000012000d000fffffffe00003fff", + "01fa01906aa800ff7ffe3fbfff500428ffff000000010002b0004000fffefffd00002aaa" + ] + }, + { + "name": "rotated_matrix", + "end": "loop", + "verts": [ + "02d404287b8f1b86bf7f3ffe08000800ffff0001fffcfffcd48f9128686923dfffffded6", + "01f7028d7fff00bffefefefe00017fe0fffffffe0009000861d0f26e639ab8b900000ead", + "080f03564c6100effefefefe000000000012fff900040019d2b963d4e9b95e2e0000050b", + "f54afeb37fff019efefefefe00000000ffee0005001d000a3c33b1858280162100000cb0" + ] + }, + { + "name": "guard_band_and_clip", + "end": "loop", + "verts": [ + "028001e03fff00fffefefefe000000000000000000000000000000000000ffff00007fff", + "064001e03fff00effefefefe000000000000000000000000c00000000000ffff00007fff", + "0a0001e03fff08effefefefe000000000001000000000000800000000000ffff00007fff", + "faff077f3fff03fcfefefefe00000000fffefffe00000000800080000000ffff00007fff", + "028000003fff00dffefefefe000000000000000000000000000080000000ffff00007fff", + "028003bf3fff00fdfefefefe000000000000ffff00000000000080000000ffff00007fff", + "028001e0800018cffefefefe0000000000000000ffff000000000000000100007fff7ffe", + "028001e07fff1bc4fefefefe0000000000000000fffeffff00000000e801e800fffaaaab" + ] + }, + { + "name": "depth_range", + "end": "loop", + "verts": [ + "028001e0fffe00fffefefefe0000000000000000ffff00000000000080007fff00010001", + "028001e0555300fffefefefe000000000000000000000001000000007fff7ffe00005555", + "028001e0670400fffefefefe000000000000000000010002000000008ffe8ffd000031f3", + "028001e07e0100fffefefefe0000000000000000001f0020000000003fe03fdf000003f8" + ] + }, + { + "name": "colours_and_uvs", + "end": "loop", + "verts": [ + "02cf01a43fff00ff0000000080007fff0000000000000000100010000000ffff00007fff", + "022f021b3fff00fffefefefe4010ffffffffffff00000000f000f0000000ffff00007fff" + ] + } +] diff --git a/tests/rsp/harness.mjs b/tests/rsp/harness.mjs new file mode 100644 index 00000000..6b8e32c8 --- /dev/null +++ b/tests/rsp/harness.mjs @@ -0,0 +1,337 @@ +// Unit-test harness for the tiny3d RSP ucode. +// +// Runs the fully linked ucode ELF (build/rsp/rsp_tiny3d.elf) inside the rsp-wasm +// emulator (ares RSP core) and exposes helpers to call single functions/commands +// with hand-made DMEM/RDRAM contents and inspect the results. +// +// Requires the ucode to be built (`make` in the repo root) and `npm install` in this +// directory (rsp-wasm >= 1.1.0). + +import {readFileSync, writeFileSync, existsSync, mkdirSync} from 'node:fs'; +import {fileURLToPath} from 'node:url'; +import assert from 'node:assert/strict'; +import {parseElf} from './elf.mjs'; + +const REPO = fileURLToPath(new URL('../../', import.meta.url)); +// rsp-wasm npm package (>= 1.1.0 has the DMA/CTC2/jump fixes); RSP_WASM overrides the module path +const RSP_WASM = process.env.RSP_WASM ?? 'rsp-wasm'; + +export const ELF_T3D = REPO + 'build/rsp/rsp_tiny3d.elf'; + +// --------------------------------------------------------------------------- +// Emulator wrapper +// --------------------------------------------------------------------------- +export class Ucode { + /** + * @param {string} elfPath + */ + static async load(elfPath = ELF_T3D) { + const {createRSP} = await import(RSP_WASM); + const rsp = await createRSP(); + const u = new Ucode(rsp, parseElf(elfPath)); + u.reset(); + return u; + } + + constructor(rsp, elf) { + this.rsp = rsp; + this.elf = elf; + /** symbol name -> 13-bit RSP address (DMEM 0x000-0xFFF, IMEM 0x1000-0x1FFF) */ + this.sym = {}; + for (const [k, v] of Object.entries(elf.symbols)) this.sym[k] = v & 0x1FFF; + // return stub: a 'break' at the end of IMEM, used as $ra for function calls + this.RET_STUB = 0x1FF8; + } + + /** Reload text/data from the ELF and reset all registers. */ + reset() { + const {rsp} = this; + rsp.reset(); + for (let i = 0; i < 0x1000; i += 4) { rsp.IMEM.setUint32(i, 0, true); rsp.DMEM.setUint32(i, 0, true); } + this.#loadBE(rsp.IMEM, this.elf.bytes('.text')); + this.#loadBE(rsp.DMEM, this.elf.bytes('.data')); + rsp.IMEM.setUint32(this.RET_STUB & 0xFFF, 0x0000000D, true); // break + for (let r = 1; r < 32; r++) rsp.setGPR(r, 0); + for (let r = 0; r < 32; r++) rsp.setVPR(r, [0, 0, 0, 0, 0, 0, 0, 0]); + // constants rspq sets up before every command (vshift / vshift8) + rsp.setVPR('$v30', [128, 64, 32, 16, 8, 4, 2, 1]); + rsp.setVPR('$v31', [0x8000, 0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100]); + // CPU-side init (t3d_init): vertex FX function + if (this.sym.VERTEX_FX_FUNC !== undefined && this.sym.LOOP_TRAIL !== undefined) { + this.w16(this.sym.VERTEX_FX_FUNC, this.sym.LOOP_TRAIL & 0xFFF); + } + } + + #loadBE(view, bytes) { + const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + let i = 0; + for (; i + 3 < bytes.byteLength; i += 4) view.setUint32(i, dv.getUint32(i, false), true); + for (; i < bytes.byteLength; i++) this.#w8(view, i, bytes[i]); + } + #w8(view, a, v) { view.setUint8((a & ~3) | (3 - (a & 3)), v & 0xFF); } + #r8(view, a) { return view.getUint8((a & ~3) | (3 - (a & 3))); } + + // --- DMEM (big-endian view, addresses as in the ucode) --- + r8(a) { return this.#r8(this.rsp.DMEM, a & 0xFFF); } + r16(a) { return (this.r8(a) << 8) | this.r8(a + 1); } + s16(a) { return (this.r16(a) << 16) >> 16; } + r32(a) { return ((this.r16(a) << 16) | this.r16(a + 2)) >>> 0; } + s32(a) { return this.r32(a) | 0; } + w8(a, v) { this.#w8(this.rsp.DMEM, a & 0xFFF, v); } + w16(a, v) { this.w8(a, v >> 8); this.w8(a + 1, v); } + w32(a, v) { this.w16(a, v >>> 16); this.w16(a + 2, v & 0xFFFF); } + bytes(a, n) { const r = []; for (let i = 0; i < n; i++) r.push(this.r8(a + i)); return r; } + + // --- RDRAM (physical addresses, 4 MiB, wraps) --- + rdr8(a) { return this.#r8(this.rsp.RDRAM, a); } + rdr16(a) { return (this.rdr8(a) << 8) | this.rdr8(a + 1); } + rdr32(a) { return ((this.rdr16(a) << 16) | this.rdr16(a + 2)) >>> 0; } + rdw8(a, v) { this.#w8(this.rsp.RDRAM, a, v); } + rdw16(a, v) { this.rdw8(a, v >> 8); this.rdw8(a + 1, v); } + rdw32(a, v) { this.rdw16(a, v >>> 16); this.rdw16(a + 2, v & 0xFFFF); } + + // --- registers --- + gpr(name) { return this.rsp.getGPR(name); } + setGpr(name, v) { this.rsp.setGPR(name, v >>> 0); } + vpr(name) { return this.rsp.getVPR(name); } + setVpr(name, lanes) { this.rsp.setVPR(name, lanes); } + /** current PC as a 12-bit IMEM offset (the emulator drops bit 12 after jumps) */ + get pc() { return this.rsp.getPC() & 0xFFF; } + set pc(v) { this.rsp.setPC(v); } + + /** + * Run until the PC hits one of the given addresses (or the RSP halts unexpectedly). + * A 'break' is temporarily placed at every stop address so the run ends there even when + * the emulator dual-issues across it; the original instructions are restored afterwards. + * @returns {{pc:number, steps:number, cycles:number, halted:boolean}} pc = the stop that was hit + */ + runUntil(stops, maxSteps = 200000) { + const {rsp} = this; + const addrs = stops.map((s) => (typeof s === 'string' ? this.sym[s] : s) & 0xFFF); + const saved = addrs.map((a) => rsp.IMEM.getUint32(a, true)); + addrs.forEach((a) => rsp.IMEM.setUint32(a, 0x0000000D, true)); // break + rsp.fn.rsp_set_halted(0); + const c0 = rsp.getCycles(); + let steps = 0; + const set = new Set(addrs); + while (!set.has(this.pc) && !rsp.isHalted()) { + if (steps++ >= maxSteps) { + addrs.forEach((a, i) => rsp.IMEM.setUint32(a, saved[i], true)); + throw new Error(`RSP did not reach ${addrs.map((x) => x.toString(16))} within ${maxSteps} steps (pc=0x${this.pc.toString(16)})`); + } + rsp.step(); + } + addrs.forEach((a, i) => rsp.IMEM.setUint32(a, saved[i], true)); + const pc = this.pc; + const hit = addrs.find((a) => a === pc) ?? addrs.find((a) => pc - a > 0 && pc - a <= 8); + return {pc: hit === undefined ? pc : hit | 0x1000, rawPc: pc, steps, cycles: rsp.getCycles() - c0, halted: hit === undefined && rsp.isHalted()}; + } + + /** + * Call a plain function ('jr $ra' return): sets up $ra to the break stub. + * @param {string} fn symbol name + * @param {Object} regs e.g. {$a0: 0x428, $v0: 2} + * @param {(string|number)[]} extraStops additional addresses that end the run (e.g. a taken branch target) + */ + call(fn, regs = {}, extraStops = []) { + for (const [r, v] of Object.entries(regs)) this.setGpr(r, v); + this.setGpr('$ra', this.RET_STUB); + this.pc = this.sym[fn]; + const res = this.runUntil([this.RET_STUB, ...extraStops]); + res.returned = res.pc === (this.RET_STUB | 0x1000); + return res; + } + + /** + * Run an rspq command handler: args go to $a0-$a3 like rspq does (the command id byte + * in the MSB of the first word is irrelevant for the handlers), ends at RSPQ_Loop. + */ + command(fn, args = [], regs = {}, extraStops = []) { + const names = ['$a0', '$a1', '$a2', '$a3']; + args.forEach((v, i) => this.setGpr(names[i], v)); + for (const [r, v] of Object.entries(regs)) this.setGpr(r, v); + this.setGpr('$ra', this.sym.RSPQ_Loop); + this.pc = this.sym[fn]; + return this.runUntil(['RSPQ_Loop', this.RET_STUB, ...extraStops]); + } +} + +// --------------------------------------------------------------------------- +// tiny3d data formats +// --------------------------------------------------------------------------- +export const TRI_SIZE = 36; +export const VTX = {XY: 0, Z: 4, CLIP: 6, REJECT: 7, RGBA: 8, ST: 0xC, CLIPPOS_I: 0x10, W_I: 0x16, CLIPPOS_F: 0x18, W_F: 0x1E, INVW_I: 0x20, INVW_F: 0x22}; + +const clampS16 = (v) => Math.max(-32768, Math.min(32767, Math.round(v))); +export const fx = { + /** float -> [int16, frac16] (s16.16) */ + s16_16(v) { const i = Math.floor(v); return [i & 0xFFFF, Math.round((v - i) * 0x10000) & 0xFFFF]; }, + s16_16_to_float(i, f) { return ((i << 16) >> 16) + f / 0x10000; }, +}; + +/** + * Write a transformed (screen-space) vertex as the triangle code expects it. + * @param {Ucode} u + * @param {number} addr DMEM address + * @param {{x:number,y:number,z?:number,rgba?:number,s?:number,t?:number,w?:number,clip?:number,reject?:number,clipPos?:number[]}} v + * x/y in pixels (s13.2), z 0..0x7FFF, s/t in texels (s10.5), w clip-space W (float, stores W and 0.5/W), + * clip: clip-code byte, reject: rejection byte (inverted: 0xFF = not rejected) + */ +export function writeScreenVertex(u, addr, v) { + u.w16(addr + VTX.XY, clampS16(v.x * 4)); + u.w16(addr + VTX.XY + 2, clampS16(v.y * 4)); + u.w16(addr + VTX.Z, v.z ?? 0x4000); + u.w8(addr + VTX.CLIP, v.clip ?? 0); + u.w8(addr + VTX.REJECT, v.reject ?? 0xFF); + u.w32(addr + VTX.RGBA, (v.rgba ?? 0xFFFFFFFF) >>> 0); + u.w16(addr + VTX.ST, clampS16((v.s ?? 0) * 32)); + u.w16(addr + VTX.ST + 2, clampS16((v.t ?? 0) * 32)); + const w = v.w ?? 1; + const [wi, wf] = fx.s16_16(w); + const [ii, iff] = fx.s16_16(0.5 / w); // the vertex loop stores the half reciprocal (0.5/W) + const cp = v.clipPos ?? [0, 0, 0]; + for (let i = 0; i < 3; i++) { const [ci, cf] = fx.s16_16(cp[i]); u.w16(addr + VTX.CLIPPOS_I + i * 2, ci); u.w16(addr + VTX.CLIPPOS_F + i * 2, cf); } + u.w16(addr + VTX.W_I, wi); u.w16(addr + VTX.W_F, wf); + u.w16(addr + VTX.INVW_I, ii); u.w16(addr + VTX.INVW_F, iff); +} + +/** Read back a transformed vertex from DMEM (as produced by the vertex loop). */ +export function readScreenVertex(u, addr) { + const f = (o) => fx.s16_16_to_float(u.r16(addr + o), u.r16(addr + o + 8)); + return { + x: u.s16(addr + VTX.XY) / 4, y: u.s16(addr + VTX.XY + 2) / 4, + z: u.s16(addr + VTX.Z), + clip: u.r8(addr + VTX.CLIP), reject: u.r8(addr + VTX.REJECT), + rgba: u.r32(addr + VTX.RGBA), + s: u.s16(addr + VTX.ST) / 32, t: u.s16(addr + VTX.ST + 2) / 32, + clipPos: [f(VTX.CLIPPOS_I), f(VTX.CLIPPOS_I + 2), f(VTX.CLIPPOS_I + 4)], + w: f(VTX.W_I), + invW: fx.s16_16_to_float(u.r16(addr + VTX.INVW_I), u.r16(addr + VTX.INVW_F)), + }; +} + +/** + * Write a pair of input vertices (T3DVertPacked, 32 bytes) into RDRAM. + * @param {{pos:number[], norm?:number[], rgba?:number, st?:number[]}} a + */ +export function writePackedVertexPair(u, rdramAddr, a, b) { + const packNorm = (n = [0, 0, 1]) => { + const l = Math.hypot(...n) || 1; + const q = (v, bits) => Math.round((v / l) * ((1 << (bits - 1)) - 1)) & ((1 << bits) - 1); + return (q(n[0], 5) << 11) | (q(n[1], 6) << 5) | q(n[2], 5); + }; + const wr = (base, v) => { + for (let i = 0; i < 3; i++) u.rdw16(base + i * 2, clampS16(v.pos[i])); + u.rdw16(base + 6, packNorm(v.norm)); + }; + wr(rdramAddr + 0x00, a); wr(rdramAddr + 0x08, b); + u.rdw32(rdramAddr + 0x10, (a.rgba ?? 0xFFFFFFFF) >>> 0); + u.rdw32(rdramAddr + 0x14, (b.rgba ?? 0xFFFFFFFF) >>> 0); + const st = (base, v) => { const s = v.st ?? [0, 0]; u.rdw16(base, clampS16(s[0] * 32)); u.rdw16(base + 2, clampS16(s[1] * 32)); }; + st(rdramAddr + 0x18, a); st(rdramAddr + 0x1C, b); +} + +/** + * Write a 4x4 matrix (row-major float, m[row][col], applied as clip = M * pos with column + * vectors like tiny3d: row i holds the coefficients multiplied with pos[i]) into a DMEM + * vec16[4] slot in the ucode layout: per row int x,y,z,w then frac x,y,z,w. + */ +export function writeMatrixFP(u, addr, m) { + for (let r = 0; r < 4; r++) for (let c = 0; c < 4; c++) { + const [i, f] = fx.s16_16(m[r][c]); + u.w16(addr + r * 16 + c * 2, i); + u.w16(addr + r * 16 + 8 + c * 2, f); + } +} + +/** + * Same computations as t3d_viewport_attach(), then runs T3DCmd_SetScreenSize and writes + * NORM_SCALE_W like the CPU does. Returns the derived values for reference checks. + */ +export function setViewport(u, {width = 320, height = 240, offsetX = 0, offsetY = 0, guardBand = 2, normScaleW = 1.0} = {}) { + const normWScale = Math.round(0xFFFF * Math.min(normScaleW, 1.0)); + const normWScaleFloat = normWScale / 0xFFFF; + const guardMax = Math.floor(32767 / (4 * Math.max(width, height))); + guardBand = Math.max(1, Math.min(guardBand & 0xF, Math.max(1, guardMax))); + const invGuard = guardBand === 1 ? 0xFFFF : Math.floor(0x10000 / guardBand); + u.w32(u.sym.NORM_SCALE_W, ((invGuard << 16) | invGuard) >>> 0); + + const screenFactorX = width * normWScaleFloat * 4.0 * guardBand; + const screenFactorY = height * normWScaleFloat * -4.0 * guardBand; + const screenScaleX = Math.round(screenFactorX * 0x10000); + const screenScaleY = Math.round(screenFactorY * 0x10000); + const screenOffsetX = offsetX * 2 + width; + const screenOffsetY = offsetY * 2 + height; + const screenOffset = ((screenOffsetX << 17) | (screenOffsetY << 1)) >>> 0; + const screenScale = ((screenScaleX & 0xFFFF0000) | ((screenScaleY >>> 16) & 0xFFFF)) >>> 0; + const screenScaleFrac = (((screenScaleX & 0xFFFF) << 16) | (screenScaleY & 0xFFFF)) >>> 0; + const depthScaleFx = Math.round(0xFFFF * normWScaleFloat * 0.5 * 0x10000); + const depthAndWScale = ((depthScaleFx & 0xFFFF0000) | normWScale) >>> 0; + const invScreenSize = (Math.floor((1.0 / width) * 0x2A00) << 8) >>> 0; + const guardBandScale = (guardBand | invScreenSize) >>> 0; + + u.command('T3DCmd_SetScreenSize', [guardBandScale, screenOffset, screenScale, depthAndWScale], + {$t4: screenScaleFrac, $t5: (depthScaleFx & 0xFFFF) << 16}); + return {guardBand, normWScaleFloat, screenFactorX, screenFactorY, screenOffsetX, screenOffsetY, depthScaleFx}; +} + +/** Decode the RDP triangle command the triangle code wrote to DMEM. */ +export function readRdpTriangle(u, addr) { + const s32_16 = (v) => (v | 0) / 65536; + const y = (v) => ((v << 18) >> 18) / 4; + const w = (i) => u.r32(addr + i * 4); + const cmd = w(0); + const hasShade = !!(cmd & 0x04000000), hasTex = !!(cmd & 0x02000000), hasZ = !!(cmd & 0x01000000); + let off = 0x20; + const block = (n) => { const r = []; for (let i = 0; i < n; i++) r.push(u.s16(addr + off + i * 2)); off += n * 2; return r; }; + const res = { + cmd: cmd >>> 24, leftMajor: !!(cmd & 0x800000), level: (cmd >>> 19) & 7, tile: (cmd >>> 16) & 7, + yl: y(cmd), ym: y(w(1) >>> 16), yh: y(w(1)), + xl: s32_16(w(2)), dxldy: s32_16(w(3)), xh: s32_16(w(4)), dxhdy: s32_16(w(5)), xm: s32_16(w(6)), dxmdy: s32_16(w(7)), + }; + const attr = () => { + const vI = block(4), dxI = block(4), vF = block(4), dxF = block(4), deI = block(4), dyI = block(4), deF = block(4), dyF = block(4); + const c = (I, F) => I.map((v, i) => fx.s16_16_to_float(v & 0xFFFF, F[i] & 0xFFFF)); + return {v: c(vI, vF), dx: c(dxI, dxF), de: c(deI, deF), dy: c(dyI, dyF)}; + }; + if (hasShade) res.shade = attr(); + if (hasTex) res.tex = attr(); + if (hasZ) { const z = block(8); res.z = {v: fx.s16_16_to_float(z[0] & 0xFFFF, z[1] & 0xFFFF), dx: fx.s16_16_to_float(z[2] & 0xFFFF, z[3] & 0xFFFF), de: fx.s16_16_to_float(z[4] & 0xFFFF, z[5] & 0xFFFF), dy: fx.s16_16_to_float(z[6] & 0xFFFF, z[7] & 0xFFFF)}; } + res.size = off; + return res; +} + +// --------------------------------------------------------------------------- +// Golden files (tests/rsp/golden/.json) +// --------------------------------------------------------------------------- +const GOLDEN_DIR = fileURLToPath(new URL('./golden/', import.meta.url)); +export const hex = (bytes) => bytes.map((b) => b.toString(16).padStart(2, '0')).join(''); + +/** + * Compare `actual` (array of {name, ...}) with the recorded golden; records it when the + * file does not exist yet or UPDATE_GOLDEN=1 is set. + */ +export function checkGolden(name, actual) { + const file = GOLDEN_DIR + name + '.json'; + if (process.env.UPDATE_GOLDEN || !existsSync(file)) { + mkdirSync(GOLDEN_DIR, {recursive: true}); + writeFileSync(file, JSON.stringify(actual, null, 1) + '\n'); + if (!process.env.UPDATE_GOLDEN) console.log(`recorded new golden ${file}`); + return; + } + const expected = JSON.parse(readFileSync(file, 'utf8')); + assert.equal(actual.length, expected.length, `golden '${name}': case count changed, re-record with UPDATE_GOLDEN=1`); + for (let i = 0; i < expected.length; i++) { + assert.deepEqual(actual[i], expected[i], `golden '${name}' case '${expected[i].name}' differs`); + } +} + +/** + * DMEM address the vertex input is DMA'd to, same math as t3d_vert_load(): + * end of the temp state, 16-byte aligned, minus the temp data the ucode keeps after the input. + */ +export const VERT_LOAD_TEMP_PADDING = 48; +export function vertLoadInputDest(u, inputSize) { + const tmpBufferEnd = (u.sym.TEMP_STATE_MEM_END & ~0xF) - VERT_LOAD_TEMP_PADDING; + return (tmpBufferEnd - inputSize) & ~0xF; +} diff --git a/tests/rsp/package-lock.json b/tests/rsp/package-lock.json new file mode 100644 index 00000000..2e00cae2 --- /dev/null +++ b/tests/rsp/package-lock.json @@ -0,0 +1,19 @@ +{ + "name": "tiny3d-rsp-tests", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tiny3d-rsp-tests", + "dependencies": { + "rsp-wasm": "^1.1.0" + } + }, + "node_modules/rsp-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/rsp-wasm/-/rsp-wasm-1.1.0.tgz", + "integrity": "sha512-GdKrZZYkMbPRu3I+V8nLiHcawifHGSPlwhoeJ/Ygla/8QbCo6m+Tnj4bVpTwu64Uiqwwzj9KA3ShUp1DUCYOjg==", + "license": "ISC" + } + } +} diff --git a/tests/rsp/package.json b/tests/rsp/package.json new file mode 100644 index 00000000..69d5036a --- /dev/null +++ b/tests/rsp/package.json @@ -0,0 +1,11 @@ +{ + "name": "tiny3d-rsp-tests", + "private": true, + "type": "module", + "scripts": { + "test": "node --test" + }, + "dependencies": { + "rsp-wasm": "^1.1.0" + } +} diff --git a/tests/rsp/sort.test.mjs b/tests/rsp/sort.test.mjs new file mode 100644 index 00000000..437a4be7 --- /dev/null +++ b/tests/rsp/sort.test.mjs @@ -0,0 +1,81 @@ +// Sort coverage for RDPQ_Triangle_Send_Async: every input permutation, every tie position, +// with and without culling. Two layers: +// - invariants that must hold for any correct sort (permutation independence, cull parity) +// - goldens of the exact bytes per permutation (tie-breaking depends on the input order and +// the rewrite must reproduce the current choice) +import {test, before} from 'node:test'; +import assert from 'node:assert/strict'; +import {Ucode, TRI_SIZE, writeScreenVertex, checkGolden, hex} from './harness.mjs'; + +let u; +before(async () => { u = await Ucode.load(); }); + +const PERMS = [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]; +const parity = (p) => (p[0] === 0 && p[1] === 1) || (p[0] === 1 && p[1] === 2) || (p[0] === 2 && p[1] === 0) ? 0 : 1; + +function draw(verts, cull = 2) { + u.reset(); + const VB = u.sym.VERT_BUFFER, OUT = u.sym.CLIP_BUFFER_TMP; + u.w32(u.sym.TRI_COMMAND, 0xCF00); + u.w32(u.sym.RDPQ_CURRENT, 0x00100000); + u.w32(u.sym.RDPQ_SENTINEL, 0x00200000); + for (let i = 0; i < 176; i++) u.w8(OUT + i, 0xEE); + verts.forEach((v, i) => writeScreenVertex(u, VB + i * TRI_SIZE, v)); + const res = u.call('RDPQ_Triangle_Send_Async', {$a0: VB, $a1: VB + TRI_SIZE, $a2: VB + 2 * TRI_SIZE, $v0: cull}, ['RDPQ_Triangle_Clip']); + return {drawn: u.r32(u.sym.RDPQ_CURRENT) !== 0x00100000, bytes: u.bytes(OUT, 176), returned: res.returned}; +} + +const v = (x, y, w, rgba, z) => ({x, y, w, rgba, z, s: x, t: y}); +const SETS = { + distinct: [v(10, 10, 2, 0xFF0000FF, 0x1000), v(100, 20.5, 4, 0x00FF00FF, 0x3000), v(50, 90.25, 8, 0x0000FFFF, 0x5000)], + tie_top: [v(10, 10, 2, 0xFF0000FF, 0x1000), v(100, 10, 4, 0x00FF00FF, 0x3000), v(50, 90, 8, 0x0000FFFF, 0x5000)], + tie_bottom: [v(10, 10, 2, 0xFF0000FF, 0x1000), v(100, 90, 4, 0x00FF00FF, 0x3000), v(50, 90, 8, 0x0000FFFF, 0x5000)], + tie_outer: [v(10, 10, 2, 0xFF0000FF, 0x1000), v(100, 50, 4, 0x00FF00FF, 0x3000), v(50, 10, 8, 0x0000FFFF, 0x5000)], + all_equal: [v(10, 40, 2, 0xFF0000FF, 0x1000), v(100, 40, 4, 0x00FF00FF, 0x3000), v(50, 40, 8, 0x0000FFFF, 0x5000)], + tie_frac: [v(10, 10.25, 2, 0xFF0000FF, 0x1000), v(100, 10.25, 4, 0x00FF00FF, 0x3000), v(50, 90, 8, 0x0000FFFF, 0x5000)], + negative: [v(-30, -20, 2, 0xFF0000FF, 0x1000), v(-5, -60, 2.5, 0x00FF00FF, 0x3000), v(-80, -70, 3, 0x0000FFFF, 0x5000)], + same_x: [v(40, 10, 3, 0xFF0000FF, 0x1000), v(40, 50, 3, 0x00FF00FF, 0x3000), v(40, 90, 3, 0x0000FFFF, 0x5000)], + same_point: [v(40, 40, 3, 0xFF0000FF, 0x1000), v(40, 40, 3, 0x00FF00FF, 0x3000), v(40, 40, 3, 0x0000FFFF, 0x5000)], +}; +const perm = (verts, p) => p.map((i) => verts[i]); + +test('distinct Y: every input permutation gives the same primitive', () => { + const ref = draw(SETS.distinct).bytes; + for (const p of PERMS) assert.deepEqual(draw(perm(SETS.distinct, p)).bytes, ref, `perm ${p}`); +}); + +test('distinct Y: cull decision follows the permutation parity', () => { + const base = [draw(SETS.distinct, 0).drawn, draw(SETS.distinct, 1).drawn]; + assert.notEqual(base[0], base[1]); + for (const p of PERMS) { + const odd = parity(p); + assert.equal(draw(perm(SETS.distinct, p), 0).drawn, odd ? !base[0] : base[0], `perm ${p} cull front`); + assert.equal(draw(perm(SETS.distinct, p), 1).drawn, odd ? !base[1] : base[1], `perm ${p} cull back`); + assert.equal(draw(perm(SETS.distinct, p), 2).drawn, true, `perm ${p} no cull`); + } +}); + +test('ties: the sorted Y values are always ordered and every permutation terminates', () => { + for (const [name, verts] of Object.entries(SETS)) { + for (const p of PERMS) { + const r = draw(perm(verts, p)); + assert.ok(r.returned, `${name} perm ${p} did not return`); + const y = (o) => ((u.r16(u.sym.CLIP_BUFFER_TMP + o) << 18) >> 18) / 4; + const [yl, ym, yh] = [y(2), y(4), y(6)]; + assert.ok(yh <= ym && ym <= yl, `${name} perm ${p}: YH ${yh} YM ${ym} YL ${yl}`); + } + } +}); + +test('sort golden bytes: every set x permutation x cull mode', () => { + const results = []; + for (const [name, verts] of Object.entries(SETS)) { + for (const p of PERMS) { + for (const cull of [2, 0, 1]) { + const r = draw(perm(verts, p), cull); + results.push({name: `${name}_${p.join('')}_cull${cull}`, drawn: r.drawn, bytes: hex(r.bytes)}); + } + } + } + checkGolden('sort', results); +}); diff --git a/tests/rsp/triangle.test.mjs b/tests/rsp/triangle.test.mjs new file mode 100644 index 00000000..a97f2bb0 --- /dev/null +++ b/tests/rsp/triangle.test.mjs @@ -0,0 +1,124 @@ +// Unit tests for RDPQ_Triangle_Send_Async (rspq_triangle.rspl) +import {test, before, beforeEach} from 'node:test'; +import assert from 'node:assert/strict'; +import {Ucode, TRI_SIZE, writeScreenVertex, readRdpTriangle} from './harness.mjs'; + +const CULL_FRONT = 0, CULL_BACK = 1, CULL_NONE = 2; +const TRI_SHADE_TEX_Z = 0x0000CF00; // TRI_COMMAND value for shade+tex+z, tile 0 + +let u, VB, OUT; +before(async () => { u = await Ucode.load(); VB = u.sym.VERT_BUFFER; OUT = u.sym.CLIP_BUFFER_TMP; }); + +beforeEach(() => { + u.reset(); + u.w32(u.sym.TRI_COMMAND, TRI_SHADE_TEX_Z); + u.w16(u.sym.RDPQ_TRI_BUFF_OFFSET, 0); + u.w32(u.sym.RDPQ_CURRENT, 0x00100000); + u.w32(u.sym.RDPQ_SENTINEL, 0x00200000); + u.w8(u.sym.RDPQ_SYNCFULL_ONGOING, 0); + for (let i = 0; i < 176; i++) u.w8(OUT + i, 0xEE); // detect untouched output +}); + +/** writes 3 vertices and calls the triangle function */ +function drawTriangle(verts, cull = CULL_NONE) { + u.w32(u.sym.RDPQ_CURRENT, 0x00100000); + verts.forEach((v, i) => writeScreenVertex(u, VB + i * TRI_SIZE, v)); + const res = u.call('RDPQ_Triangle_Send_Async', + {$a0: VB, $a1: VB + TRI_SIZE, $a2: VB + 2 * TRI_SIZE, $v0: cull}, + ['RDPQ_Triangle_Clip']); + res.drawn = u.r32(u.sym.RDPQ_CURRENT) !== 0x00100000; // pointer advanced -> primitive emitted + res.clipped = res.pc === u.sym.RDPQ_Triangle_Clip; + return res; +} + +const V = [ + {x: 10, y: 10, z: 0x1000, rgba: 0xFF0000FF, s: 0, t: 0, w: 2}, + {x: 100, y: 20, z: 0x3000, rgba: 0x00FF00FF, s: 32, t: 0, w: 4}, + {x: 50, y: 90, z: 0x5000, rgba: 0x0000FFFF, s: 0, t: 32, w: 8}, +]; + +test('edge coefficients match the float reference', () => { + const res = drawTriangle(V); + assert.ok(res.returned && res.drawn); + const tri = readRdpTriangle(u, OUT); + assert.equal(tri.cmd, 0xCF); + assert.equal(tri.tile, 0); + assert.deepEqual([tri.yh, tri.ym, tri.yl], [10, 20, 90]); + // sorted by y: v1=(10,10) v2=(100,20) v3=(50,90) + const H = [40, 80], M = [90, 10], L = [-50, 70]; + const near = (a, b, eps = 1 / 4096) => assert.ok(Math.abs(a - b) <= eps, `${a} != ${b} (+-${eps})`); + // slopes come from a vrcp + one Newton-Raphson step: ~2^-11 relative precision + const slope = (a, b) => near(a, b, Math.abs(b) / 2048 + 1 / 8192); + slope(tri.dxhdy, H[0] / H[1]); + slope(tri.dxmdy, M[0] / M[1]); + slope(tri.dxldy, L[0] / L[1]); + near(tri.xh, 10); near(tri.xm, 10); near(tri.xl, 100); + assert.equal(tri.leftMajor, true); // NZ = MX*HY - MY*HX = 6800 > 0 + assert.equal(tri.size, 176); + assert.equal(u.gpr('$s3'), OUT + 176); // end pointer + assert.equal(u.gpr('$s7'), 176); // next buffer offset + assert.equal(u.r32(u.sym.RDPQ_CURRENT), 0x00100000 + 176); +}); + +test('shade and depth start at the top vertex and interpolate along the major edge', () => { + drawTriangle(V); + const tri = readRdpTriangle(u, OUT); + const near = (a, b, eps) => assert.ok(Math.abs(a - b) <= eps, `${a} != ${b} (+-${eps})`); + // top vertex has an integer y, so FY = 0 and the start values are the vertex attributes + assert.deepEqual(tri.shade.v.map(Math.round), [255, 0, 0, 255]); + near(tri.z.v, 0x1000, 1); + // vertex 3 lies on the H edge, 80 scanlines below: value = v + de * 80 + near(tri.shade.v[2] + tri.shade.de[2] * 80, 255, 1.5); + near(tri.shade.v[0] + tri.shade.de[0] * 80, 0, 1.5); + near(tri.z.v + tri.z.de * 80, 0x5000, 4); + // vertex 2: 10 lines down the H edge then along x to x=100 + const xOnH = 10 + tri.dxhdy * 10; + near(tri.shade.v[1] + tri.shade.de[1] * 10 + tri.shade.dx[1] * (100 - xOnH), 255, 1.5); + near(tri.z.v + tri.z.de * 10 + tri.z.dx * (100 - xOnH), 0x3000, 4); + // texture W: 0.5/W normalized to the closest vertex (W=2 -> 0.5 = 0x8000), minus 1, halved, + // and placed in the integer lane of the coefficient (RDP only needs the relative scale) + assert.equal(tri.tex.v[2], 0x3FFF); +}); + +test('tile index from the clip flags goes into the command word', () => { + drawTriangle(V.map((v, i) => ({...v, clip: 5 << 5}))); + assert.equal(readRdpTriangle(u, OUT).tile, 5); +}); + +test('backface culling: exactly one cull mode drops the triangle, flipped winding swaps it', () => { + const r = (verts, cull) => drawTriangle(verts, cull).drawn; + assert.equal(r(V, CULL_NONE), true); + const cw = [r(V, CULL_FRONT), r(V, CULL_BACK)]; + assert.deepEqual([...cw].sort(), [false, true]); + const flipped = [V[0], V[2], V[1]]; + assert.equal(r(flipped, CULL_NONE), true); + assert.equal(r(flipped, CULL_FRONT), !cw[0]); + assert.equal(r(flipped, CULL_BACK), !cw[1]); +}); + +test('vertex order does not change the output', () => { + drawTriangle(V); + const a = u.bytes(OUT, 176); + drawTriangle([V[1], V[2], V[0]]); + assert.deepEqual(u.bytes(OUT, 176), a); +}); + +test('rejection: dropped only when all three vertices are outside the same plane', () => { + // rejection bytes are stored inverted: 0xFF = inside all planes + assert.equal(drawTriangle(V.map((v) => ({...v, reject: 0xFE}))).drawn, false); + assert.equal(drawTriangle(V.map((v, i) => ({...v, reject: i === 2 ? 0xFF : 0xFE}))).drawn, true); + assert.equal(drawTriangle(V.map((v, i) => ({...v, reject: 0xFF ^ (1 << i)}))).drawn, true); +}); + +test('clipping: any clip flag hands the triangle to the clipper', () => { + for (let i = 0; i < 3; i++) { + const res = drawTriangle(V.map((v, j) => ({...v, clip: j === i ? 0x02 : 0}))); + assert.equal(res.clipped, true, `vertex ${i}`); + assert.equal(res.drawn, false); + } +}); + +test('degenerate triangle (zero area) still terminates', () => { + const res = drawTriangle([{...V[0]}, {...V[0], x: 50}, {...V[0], x: 90}]); + assert.ok(res.returned || res.clipped); +}); diff --git a/tests/rsp/vertload.test.mjs b/tests/rsp/vertload.test.mjs new file mode 100644 index 00000000..c4cc4fab --- /dev/null +++ b/tests/rsp/vertload.test.mjs @@ -0,0 +1,114 @@ +// Unit tests for T3DCmd_VertLoad (vertex transform loop in rsp_tiny3d.rspl) +import {test, before, beforeEach} from 'node:test'; +import assert from 'node:assert/strict'; +import {Ucode, TRI_SIZE, writePackedVertexPair, writeMatrixFP, setViewport, readScreenVertex, vertLoadInputDest} from './harness.mjs'; + +const RDRAM_VERTS = 0x00100000; +const W = 320, H = 240; + +let u; +before(async () => { u = await Ucode.load(); }); +beforeEach(() => { u.reset(); }); + +/** + * Loads `pairs` (arrays of two packed vertices) through T3DCmd_VertLoad like t3d_vert_load() + * does and returns the transformed vertices from VERT_BUFFER. + */ +function vertLoad(pairs) { + const inputSize = pairs.length * 32; + pairs.forEach((p, i) => writePackedVertexPair(u, RDRAM_VERTS + i * 32, p[0], p[1])); + const offsetDest = vertLoadInputDest(u, inputSize); + const offsetInput = u.sym.VERT_BUFFER; + const res = u.command('T3DCmd_VertLoad', [inputSize, RDRAM_VERTS, (offsetDest << 16) | offsetInput]); + assert.equal(res.pc, u.sym.RSPQ_Loop, 'command did not return to the rspq loop'); + const out = []; + for (let i = 0; i < pairs.length * 2; i++) out.push(readScreenVertex(u, u.sym.VERT_BUFFER + i * TRI_SIZE)); + return out; +} + +const near = (a, b, eps, msg = '') => assert.ok(Math.abs(a - b) <= eps, `${msg} ${a} != ${b} (+-${eps})`); + +// clip = M * pos, pos.w = 1. Row r of the DMEM matrix holds the coefficients of pos[r]. +const SCALE = 1 / 64; +const MVP_ORTHO = [[SCALE, 0, 0, 0], [0, SCALE, 0, 0], [0, 0, SCALE, 0], [0, 0, 0, 1]]; + +test('orthographic transform lands on the expected screen positions', () => { + const vp = setViewport(u, {width: W, height: H, guardBand: 2}); + writeMatrixFP(u, u.sym.MATRIX_MVP, MVP_ORTHO); + const verts = vertLoad([[ + {pos: [32, -48, 0], rgba: 0x102030FF, st: [10, 20]}, // ndc (0.5, -0.75, 0) + {pos: [-64, 32, 32], rgba: 0xFFFFFFFF, st: [0, 0]}, // ndc (-1, 0.5, 0.5) + ]]); + const expect = (ndc) => ({ + x: vp.screenOffsetX / 2 + ndc[0] * (W / 2), + y: vp.screenOffsetY / 2 - ndc[1] * (H / 2), + z: 0x3FFF + ndc[2] * 0x3FFF, + }); + const e0 = expect([0.5, -0.75, 0]), e1 = expect([-1, 0.5, 0.5]); + near(verts[0].x, e0.x, 0.25, 'x0'); near(verts[0].y, e0.y, 0.25, 'y0'); near(verts[0].z, e0.z, 4, 'z0'); + near(verts[1].x, e1.x, 0.25, 'x1'); near(verts[1].y, e1.y, 0.25, 'y1'); near(verts[1].z, e1.z, 4, 'z1'); + // both are inside the view: no clip / reject flags + // (vertex 1 sits exactly on the left edge, x = -w: the compare is inclusive, so it is + // flagged as rejected on that plane but not clipped; see the edge test below) + assert.equal(verts[0].clip & 0x1F, 0); assert.equal(verts[0].reject, 0xFF); + assert.equal(verts[1].clip & 0x1F, 0); + // w = 1 -> stored W and the half reciprocal 0.5/W + near(verts[0].w, 1, 1 / 4096); near(verts[0].invW, 0.5, 1 / 1024); + // clip-space position is kept for the clipper, x/y pre-divided by the guard band (2) + near(verts[0].clipPos[0], 0.5 / 2, 1 / 4096); near(verts[0].clipPos[1], -0.75 / 2, 1 / 4096); + // UVs pass through, colour is unlit (ambient white, scaled by 0x7FFF/0x8000 -> each channel may lose 1) + near(verts[0].s, 10, 1 / 32); near(verts[0].t, 20, 1 / 32); + const ch = (rgba) => [24, 16, 8, 0].map((sh) => (rgba >>> sh) & 0xFF); + ch(verts[0].rgba).forEach((c, i) => near(c, ch(0x102030FF)[i], 1, `channel ${i}`)); +}); + +test('perspective: screen position is divided by W', () => { + setViewport(u, {width: W, height: H, guardBand: 2}); + // w = 1 + z/64 -> z=64 gives w=2 + writeMatrixFP(u, u.sym.MATRIX_MVP, [[SCALE, 0, 0, 0], [0, SCALE, 0, 0], [0, 0, SCALE, SCALE], [0, 0, 0, 1]]); + const [a, b] = vertLoad([[{pos: [64, 64, 64]}, {pos: [64, 64, 0]}]]); + near(a.x, 160 + 0.5 * 160, 0.25, 'x/w'); near(a.y, 120 - 0.5 * 120, 0.25, 'y/w'); + near(b.x, 160 + 1.0 * 160, 0.25, 'x'); near(b.y, 120 - 1.0 * 120, 0.25, 'y'); + near(a.w, 2, 1 / 4096); near(a.invW, 0.25, 1 / 2048); + assert.ok(a.z > b.z, 'farther vertex has a larger depth'); +}); + +test('clip and reject codes: screen edge vs guard band', () => { + setViewport(u, {width: W, height: H, guardBand: 2}); + writeMatrixFP(u, u.sym.MATRIX_MVP, MVP_ORTHO); + const [inside, offscreen, farOut, nearSide] = vertLoad([ + [{pos: [0, 0, 0]}, {pos: [96, 0, 0]}], // ndc x = 0 | 1.5 (outside screen, inside guard band 2) + [{pos: [192, 0, 0]}, {pos: [0, 0, 0]}], // ndc x = 3 (outside guard band) + ]); + assert.equal(inside.clip & 0x1F, 0); assert.equal(inside.reject, 0xFF); + assert.equal(offscreen.clip & 0x1F, 0, 'inside the guard band must not clip'); + assert.notEqual(offscreen.reject, 0xFF, 'outside the screen must set a reject bit'); + assert.notEqual(farOut.clip & 0x1F, 0, 'outside the guard band must clip'); + assert.notEqual(farOut.reject, 0xFF); + const bits = (v) => v.toString(2).split('1').length - 1; + assert.equal(bits(0xFF ^ offscreen.reject), 1, 'one plane rejects'); + assert.equal(bits(farOut.clip & 0x1F), 1, 'one plane clips'); + assert.equal(farOut.reject, offscreen.reject, 'same plane rejects both'); + assert.equal(nearSide.reject, 0xFF); +}); + +test('a vertex exactly on a screen edge counts as outside for rejection, inside for clipping', () => { + setViewport(u, {width: W, height: H, guardBand: 2}); + writeMatrixFP(u, u.sym.MATRIX_MVP, MVP_ORTHO); + const [onEdge, justInside] = vertLoad([[{pos: [-64, 0, 0]}, {pos: [-63, 0, 0]}]]); // ndc x = -1 | -0.984 + assert.notEqual(onEdge.reject, 0xFF); + assert.equal(onEdge.clip & 0x1F, 0); + assert.equal(justInside.reject, 0xFF); +}); + +test('vertex count: every pair is transformed', () => { + setViewport(u, {width: W, height: H, guardBand: 2}); + writeMatrixFP(u, u.sym.MATRIX_MVP, MVP_ORTHO); + const pairs = []; + for (let i = 0; i < 4; i++) pairs.push([{pos: [i * 8, 0, 0]}, {pos: [-i * 8, 0, 0]}]); + const out = vertLoad(pairs); + for (let i = 0; i < 4; i++) { + near(out[i * 2].x, 160 + (i * 8 / 64) * 160, 0.25, `v${i * 2}`); + near(out[i * 2 + 1].x, 160 - (i * 8 / 64) * 160, 0.25, `v${i * 2 + 1}`); + } +}); diff --git a/tests/run.sh b/tests/snapshot.sh similarity index 98% rename from tests/run.sh rename to tests/snapshot.sh index 0db3005d..538cab0f 100755 --- a/tests/run.sh +++ b/tests/snapshot.sh @@ -41,7 +41,7 @@ declare -A TESTS=( [13_cel_shading]="t3d_13_cel_shading.z64 10" [14_outline]="t3d_14_outline.z64 10" [15_pointlight]="t3d_15_pointlight.z64 10 win=2" - [16_light_clip]="t3d_16_light_clip.z64 10" + [16_light_clip]="t3d_16_light_clip.z64 12" [17_culling]="t3d_17_culling.z64 10 crop=0,24,640,176" [18_particles]="t3d_18_particles.z64 10" [19_particles_tex]="t3d_19_particles_tex.z64 10" diff --git a/tests/snapshots/00_quad.png b/tests/snapshots/00_quad.png index 0eed0cd3..6cac4ed0 100644 --- a/tests/snapshots/00_quad.png +++ b/tests/snapshots/00_quad.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f0db12375eff6f88b08d1a4c34d4265da23957a342f6e84d5754516c22e9bc8c +oid sha256:787d2c90f902220244b4aa36668362b84d96730a687dd7459e67cadbf2b182c8 size 458451 diff --git a/tests/snapshots/01_model.png b/tests/snapshots/01_model.png index a11db7d4..f1a0aaa5 100644 --- a/tests/snapshots/01_model.png +++ b/tests/snapshots/01_model.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d8aa443c978b7a7dba409d00e05ff30063f4bf795171e88a5f6666a1f900fc3 +oid sha256:1a579f617cf5f01535ff1fb780b65fc16c6395dc8ab973783c9194439b64eae5 size 458451 diff --git a/tests/snapshots/02_lighting.png b/tests/snapshots/02_lighting.png index c56d2b5a..aa457a7d 100644 --- a/tests/snapshots/02_lighting.png +++ b/tests/snapshots/02_lighting.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6c2159fb961b853c525f98b6c6aa5330331812ce201ef2629dc55ef55f90ee51 +oid sha256:1fc3485f09ede6604530fdc16804ee235d9175f993adb5fc8ffedb67129ff47f size 458451 diff --git a/tests/snapshots/03_objects.png b/tests/snapshots/03_objects.png index d338a43e..64369b73 100644 --- a/tests/snapshots/03_objects.png +++ b/tests/snapshots/03_objects.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c8cbacfd013ef6aae06a45db22d19eb8661df40ad07efeb24709f190b9a43232 +oid sha256:1d63d808d1e11705d5445f15331b03dee5e822cd2a0876cd2979c6a07d39854e size 385263 diff --git a/tests/snapshots/04_dynamic.png b/tests/snapshots/04_dynamic.png index 40c3d79b..75472ad4 100644 --- a/tests/snapshots/04_dynamic.png +++ b/tests/snapshots/04_dynamic.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1b35dab027ff22bf99593bff1e0b92a95aac9136183a9c1fcf7ef4e50c53dc9e +oid sha256:ed00129e45119509ffc87d98137aa4b3d357443435accadbb143c7c8d291f309 size 458451 diff --git a/tests/snapshots/05_splitscreen.png b/tests/snapshots/05_splitscreen.png index e1d11e88..3fb37b66 100644 --- a/tests/snapshots/05_splitscreen.png +++ b/tests/snapshots/05_splitscreen.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b775de5b346acae7071e8555f52a9723bdf781db2058aee50a0c7153c4be38c6 +oid sha256:44e060b49970dcc1b2ff0de99536ebebc0f94622dc913cd58df8039ee9d7dfb3 size 458451 diff --git a/tests/snapshots/07_skeleton.png b/tests/snapshots/07_skeleton.png index da262491..c21f1507 100644 --- a/tests/snapshots/07_skeleton.png +++ b/tests/snapshots/07_skeleton.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b66f17753e1a55f5db2de79e4fe3e46e9756749515b131f11457cb35f41d434 +oid sha256:3172edf2f3f0949ea7aff433d62cd99884c0effa91781faca1f4fc2153f42f2e size 458451 diff --git a/tests/snapshots/08_animation.png b/tests/snapshots/08_animation.png index 9040f07e..0ed015e5 100644 --- a/tests/snapshots/08_animation.png +++ b/tests/snapshots/08_animation.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fa302d2856f5d628794394898f273fecb3c4dff54de6610e1546c76d72405c6f +oid sha256:a658db5b0ecc024bfc6cc6cea0a6067b131c178c30194a12e7eb5798485e0630 size 458451 diff --git a/tests/snapshots/10_flipbook_tex.png b/tests/snapshots/10_flipbook_tex.png index 1966fff6..ae48ee60 100644 --- a/tests/snapshots/10_flipbook_tex.png +++ b/tests/snapshots/10_flipbook_tex.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab3fd1d855d01dce77b4a990a3dff3ac863f26d49423f03739491fa8d653f8d2 +oid sha256:e3b40fed4cb99b94550e4ff04f885f4666b179014446a9e0bbc884fccff22978 size 458451 diff --git a/tests/snapshots/12_uv_gen.png b/tests/snapshots/12_uv_gen.png index 04a0154c..60025945 100644 --- a/tests/snapshots/12_uv_gen.png +++ b/tests/snapshots/12_uv_gen.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2981c51f15dd4c17540e209c142a366c9e2331e954e9bf3439eeac2f3fb9df0c +oid sha256:05c508616855bf20e52f3e6e8fadeb357a9dbf44dcecd6b8a88e5cc1dcc10e3c size 458451 diff --git a/tests/snapshots/13_cel_shading.png b/tests/snapshots/13_cel_shading.png index 4de372e8..9e12ed26 100644 --- a/tests/snapshots/13_cel_shading.png +++ b/tests/snapshots/13_cel_shading.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0c1efc0478834dad8fdbf6ececd7e9ef02b26465ffc29b1f96899881791e199f +oid sha256:8b95cd16c948cc959b1b6eb3d1892fa4b537f248e9433ed5aa310e608f6518d1 size 458451 diff --git a/tests/snapshots/14_outline.png b/tests/snapshots/14_outline.png index 25f2b949..ac7e5251 100644 --- a/tests/snapshots/14_outline.png +++ b/tests/snapshots/14_outline.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95be02b3d3671d61630a0d45b35a773010ce3c128a0e15193c2e7ca568d6420e +oid sha256:449d3663b8a544d6d928dac0bf4dde4831709ce73b40984cc58195136678cfe3 size 458451 diff --git a/tests/snapshots/15_pointlight.png b/tests/snapshots/15_pointlight.png index ad2a3e3a..a5338bfa 100644 --- a/tests/snapshots/15_pointlight.png +++ b/tests/snapshots/15_pointlight.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83c89b040ba3debf35994710915f75e171e9edbe7ffd6429449e8336cc377e8a +oid sha256:975a606092b5ca4a06c1ee14f8705000a514bdd708f20f8e386968621be07327 size 458451 diff --git a/tests/snapshots/16_light_clip.png b/tests/snapshots/16_light_clip.png index 800e74eb..242cf2b5 100644 --- a/tests/snapshots/16_light_clip.png +++ b/tests/snapshots/16_light_clip.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9ad3a9faa812597def80162c61cbe613399e6d1a59fa28410416a3d607d2510 +oid sha256:1c3536d41a6459976801a9d099b798cbafd7b556d3b330e032a63532c426dbbd size 458451 diff --git a/tests/snapshots/17_culling.png b/tests/snapshots/17_culling.png index 4ed03bc3..2987a2af 100644 --- a/tests/snapshots/17_culling.png +++ b/tests/snapshots/17_culling.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:374f0ced720ed8fcaa9214c3f73a928a4abdea6c478454a371f3c6392565df24 +oid sha256:346e5a509301388def95e3a02db0db411fa2ef5eae389f7a12af167c9b43ea9a size 339039 diff --git a/tests/snapshots/18_particles.png b/tests/snapshots/18_particles.png index 81b15b3f..0708266a 100644 --- a/tests/snapshots/18_particles.png +++ b/tests/snapshots/18_particles.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:78f3a8c0b82a3c6e2f82240b6a65309d27337493712396668bdcd66408cb9e51 +oid sha256:7f0715d291575d2146d97b2aead3ab060fbdb7534c729686a9c49045031e0f21 size 458451 diff --git a/tests/snapshots/19_particles_tex.png b/tests/snapshots/19_particles_tex.png index 5b5c4701..52532ecc 100644 --- a/tests/snapshots/19_particles_tex.png +++ b/tests/snapshots/19_particles_tex.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:982799e1445153d05a73f394208741809a5363c90355e3abf00ddc0058cb8c9d +oid sha256:63e4e13c65208dde2cc4bc42a4760ec2b8d15de0dd75d40dc46e2967c79a61fa size 458451 diff --git a/tests/snapshots/20_mipmaps.png b/tests/snapshots/20_mipmaps.png index 9f6e46c8..20bf2da6 100644 --- a/tests/snapshots/20_mipmaps.png +++ b/tests/snapshots/20_mipmaps.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4be7664a4d9e8218d53b2ea8743fb1fd682a138e8225ccb555eee5259b411d47 +oid sha256:64d5cc496d840c6f339ec88c6bfb64c5d38976a59142baae629de113b8aa5bb9 size 458451 diff --git a/tests/snapshots/21_fresnel.png b/tests/snapshots/21_fresnel.png index c02988ca..b3be7697 100644 --- a/tests/snapshots/21_fresnel.png +++ b/tests/snapshots/21_fresnel.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3822f5704c9519da63421a4bede448ff1feeca3e5885f3c40035a48d4ba0ce01 +oid sha256:93e9c6a03f0da44e000bd50e9af785c1454df5e3de1e19b8d7bb41b070b5a7fc size 458451 diff --git a/tests/snapshots/22_bigtex.png b/tests/snapshots/22_bigtex.png index 67cc4aa1..c963b133 100644 --- a/tests/snapshots/22_bigtex.png +++ b/tests/snapshots/22_bigtex.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:483db824c7dd62236ceda9cd183bfd9e93cbd7f1b05caec3ee5c1c78b135a47a +oid sha256:91de91ffb98d813427aed2b1334e8e4e36ed1cd7f0cc557c130cf1965d6fb99a size 400671 diff --git a/tests/snapshots/23_hdr.png b/tests/snapshots/23_hdr.png index ff7ebaf2..b12bf897 100644 --- a/tests/snapshots/23_hdr.png +++ b/tests/snapshots/23_hdr.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f074a6ef82f1b95eea8a1ac00ea87f93328154ff11c605a4a870acb966ed0ca8 +oid sha256:215f3a214c3cba9b823935a2ec95b99e0c738d05d68ba5eabcdbf4a84c62a94b size 458451 diff --git a/tests/snapshots/24_hdr_bloom.png b/tests/snapshots/24_hdr_bloom.png index 3854904d..691ab564 100644 --- a/tests/snapshots/24_hdr_bloom.png +++ b/tests/snapshots/24_hdr_bloom.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:faa16c448dc8ffc8156a333c48ff1ddf5b16617df209420ac0ed1ff5d1a5d56f +oid sha256:0c29532a1d0d4da91dc8670f9aedd6f3a6747da07fbe72d5f7479fbe68917d7d size 458451 diff --git a/tests/snapshots/99_testscene.png b/tests/snapshots/99_testscene.png index bb665a37..4a558c1f 100644 --- a/tests/snapshots/99_testscene.png +++ b/tests/snapshots/99_testscene.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6f52bf76c534bf150281d14e792c3d9fa95fc2df61aca2a1dd981901a907d2b +oid sha256:14496472e3832aacd2b75f2dbc146a9c778da60eafd20aa67ee632abe11f04fd size 458451 diff --git a/tools/depth_report.html b/tools/depth_report.html new file mode 100644 index 00000000..e3ef3e1a --- /dev/null +++ b/tools/depth_report.html @@ -0,0 +1,754 @@ + + + + + +Depth Bench Report + + + + + +
+

Depth Bench

+
+ + + + + + +
+
presetnone loaded
+
runsnone loaded
+ +
+ + + +
+
+
+
+

No dumps loaded

+

This page only draws data from bench dumps. Click Load dumps… (or drop the files anywhere on the page) and pick one or more .json files from examples/98_depthtest/data/. For a copy that has the data built in, run examples/98_depthtest/report.sh and open the generated report.html.

+ +
+ +
+

Stored Z vs distance SWEEP, 2000 log-spaced steps, one flat quad each

+

"w" throughout is the view-space depth of the test quad in world units (camera-space −z; for a perspective projection this equals clip-space W, which is how the ROM reports it). All runs render the very same depths, so runs can be compared sample by sample. Difference to reference: stored Z of each run minus the reference, either in integer Z units (code space: 1 unit = 1/32767 of the depth range, where the pipeline loses bits) or converted to a distance error, either in % of w or in plain world units (what a code is worth on screen: dw = dZ·w²/B, so one code is 0.003 units near the camera but ~300 units at the far plane of 10/12800), or in z-buffer codes: the Z difference divided by the format's resolution at that depth (8 Z units below Z = 16384, then 4, 2, 1, ½, ¼, ⅛ at the top), i.e. how many storable values the vertex is off by. The reference is another run, the exact analytic mapping Z = 32767·(zndc+1)/2, that mapping through the RDP's z-buffer format (s15.16 → u15.3 → 11-bit-mantissa float, as angrylion does it; the hardware floor nobody can change), or additionally with the W-norm quantisation both ucodes share (w·2/(far+near) held in s15.16 before the reciprocal; the near-field curve with its sign flip at zclip = 0, w = 2fn/(f+n)). Step to previous sample: how much the stored Z moved between neighbouring sweep steps, i.e. the quantisation grain. Fit residual: distance from a global Z = A + B/w fit; use it only for the envelope. Dots mark inversions (stored Z decreases while w increases).

+
+ + + + + +
+
+
+
+ + + + +
+ + + + diff --git a/tools/depth_report_embed.py b/tools/depth_report_embed.py new file mode 100755 index 00000000..68f2ef66 --- /dev/null +++ b/tools/depth_report_embed.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +"""Inline depth-bench dumps into tools/depth_report.html so the page is self-contained. + + tools/depth_report_embed.py out.html examples/98_depthtest/data/*.json [--fragment] + +--fragment strips the /// wrapper (for hosts that wrap the page themselves). +""" +import sys, json, re, os +args = [a for a in sys.argv[1:] if not a.startswith("--")] +fragment = "--fragment" in sys.argv +out, files = args[0], args[1:] +here = os.path.dirname(os.path.abspath(__file__)) +html = open(os.path.join(here, "depth_report.html"), encoding="utf-8").read() +dumps = [json.load(open(f, encoding="utf-8")) for f in files] +for d, f in zip(dumps, files): + d["file"] = os.path.basename(f) +blob = json.dumps(dumps, separators=(",", ":")).replace("window.DT_EMBEDDED = " + blob + ";\n