Skip to content
This repository has been archived by the owner on Sep 16, 2024. It is now read-only.

Commit

Permalink
Initial angrylion replayer stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
OFFTKP committed Aug 3, 2023
1 parent 2caac2d commit cd43b1d
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 52 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(WARNINGS
)
string(REPLACE ";" " " WARNINGS_FLAGS "${WARNINGS}")
set(CMAKE_CXX_FLAGS "-g -O2")
set(CMAKE_C_FLAGS "-g -O0")
if (APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2")
else()
Expand Down
99 changes: 83 additions & 16 deletions n64/qa/n64_angrylion_replayer.cxx
Original file line number Diff line number Diff line change
@@ -1,13 +1,74 @@
#include <n64/qa/n64_angrylion_replayer.hxx>

extern "C" {
#include "msg.h"
#include "n64video.h"
#include "vdac.h"
void rdp_cmd(uint32_t wid, const uint32_t* args);
}
#include <array>
#include <cstdint>
#include <cstdarg>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>

class AngrylionReplayerImpl
{
public:
AngrylionReplayerImpl();
~AngrylionReplayerImpl();

private:
n64video_config config_ = {};
std::vector<uint8_t> rdram_;
std::array<uint32_t*, VI_NUM_REG> vi_regs_ = {};
std::array<uint32_t*, DP_NUM_REG> dp_regs_ = {};
uint32_t mi_interrupt_ = 0;
};

std::unique_ptr<AngrylionReplayerImpl> AngrylionReplayer::impl_;
Framebuffer AngrylionReplayer::framebuffer_;

void AngrylionReplayer::Init()
{
AngrylionReplayer::impl_ = std::make_unique<AngrylionReplayerImpl>();
}

void AngrylionReplayer::RunCommand(const std::vector<uint64_t>& command)
{
std::vector<uint32_t> command32(command.size() * 2);
for (size_t i = 0; i < command.size(); ++i)
{
command32[i * 2] = static_cast<uint32_t>(command[i] >> 32);
command32[i * 2 + 1] = static_cast<uint32_t>(command[i]);
}
rdp_cmd(0, command32.data());
}

Framebuffer AngrylionReplayer::GetFramebuffer()
{
n64video_update_screen();
printf("test\n");
return framebuffer_;
}

void AngrylionReplayer::Cleanup()
{
AngrylionReplayer::impl_.reset();
}

void vdac_init(struct n64video_config*) {}

void vdac_write(struct frame_buffer* fb)
{
AngrylionReplayer::Current()->WriteFramebuffer(fb->pixels, fb->width, fb->height, fb->pitch);
AngrylionReplayer::framebuffer_.pixels.resize(fb->width * fb->height);
uint8_t* src = (uint8_t*)fb->pixels;
uint8_t* dst = (uint8_t*)AngrylionReplayer::framebuffer_.pixels.data();
for (unsigned y = 0; y < fb->height; y++, src += fb->pitch * 4, dst += fb->width * 4)
memcpy(dst, src, fb->width * sizeof(uint32_t));
printf("vdac_write: %d %d\n", fb->width, fb->height);
}

void vdac_sync(bool invalid)
Expand Down Expand Up @@ -50,34 +111,40 @@ void msg_debug(const char* err, ...)
printf(buffer);
}

AngrylionReplayer::AngrylionReplayer()
AngrylionReplayerImpl::AngrylionReplayerImpl()
{
rdram_.resize(0x800000);
for (auto& vi_reg : vi_regs_)
{
vi_reg = new uint32_t;
}
for (auto& dp_reg : dp_regs_)
{
dp_reg = new uint32_t;
}
config_.gfx.rdram = rdram_.data();
config_.gfx.rdram_size = rdram_.size();
config_.gfx.vi_reg = vi_regs_.data();
config_.gfx.dp_reg = dp_regs_.data();
config_.gfx.mi_intr_reg = &mi_interrupt_;
config_.gfx.mi_intr_cb = []() {};
config_.vi.mode = VI_MODE_NORMAL;
config_.vi.interp = VI_INTERP_LINEAR;
config_.vi.interp = VI_INTERP_NEAREST;
config_.dp.compat = DP_COMPAT_HIGH;

*vi_regs_[VI_ORIGIN] = 0xa0100000;
*vi_regs_[VI_WIDTH] = 320;
*vi_regs_[VI_STATUS] = 0x00003303;
*vi_regs_[VI_V_SYNC] = 0x20d;
*vi_regs_[VI_H_START] = 0x006c02ec;
*vi_regs_[VI_V_START] = 0x002501ff;
*vi_regs_[VI_X_SCALE] = 0x200;
*vi_regs_[VI_Y_SCALE] = 0x400;

n64video_init(&config_);
}

AngrylionReplayer::~AngrylionReplayer()
AngrylionReplayerImpl::~AngrylionReplayerImpl()
{
n64video_close();
}

AngrylionReplayer* AngrylionReplayer::Current()
{
static AngrylionReplayer replayer;
return &replayer;
}

void AngrylionReplayer::WriteFramebuffer(const void* pixels, uint32_t width, uint32_t height,
uint32_t pitch)
{
printf("WriteFramebuffer: %p %d %d %d\n", pixels, width, height, pitch);
}
44 changes: 25 additions & 19 deletions n64/qa/n64_angrylion_replayer.hxx
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
#pragma once

extern "C" {
#include "msg.h"
#include "n64video.h"
#include "vdac.h"
}
#include <array>
#include <cstdint>
#include <vector>
#include <cstdint>
#include <memory>

class AngrylionReplayer
class AngrylionReplayerImpl;
class frame_buffer;

struct Framebuffer
{
public:
AngrylionReplayer();
~AngrylionReplayer();
struct rgba
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
std::vector<rgba> pixels;
uint32_t width;
uint32_t height;
};

static AngrylionReplayer* Current();
void WriteFramebuffer(const void* pixels, uint32_t width, uint32_t height, uint32_t pitch);
struct AngrylionReplayer
{
static void Init();
static void RunCommand(const std::vector<uint64_t>& command);
static Framebuffer GetFramebuffer();
static void Cleanup();

private:
n64video_config config_ = {};
std::vector<uint8_t> rdram_;
std::array<uint32_t*, VI_NUM_REG> vi_regs_ = {};
std::array<uint32_t*, DP_NUM_REG> dp_regs_ = {};
uint32_t mi_interrupt_ = 0;
static std::unique_ptr<AngrylionReplayerImpl> impl_;
static Framebuffer framebuffer_;
};
76 changes: 62 additions & 14 deletions n64/qa/n64_rdp_qa.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.hxx"
#include <n64/qa/n64_angrylion_replayer.hxx>
#include <fstream>

using namespace hydra::N64;

Expand Down Expand Up @@ -118,26 +120,72 @@ class RDPTest : public testing::Test
VerifyFramebuffer("data/" #name ".png"); \
}

TRIANGLE_TEST(Simple_Triangle, 0x088002a801180118, 0x00d20000ffff0000, 0x006e000000000000,
0x006e000000000000);
// TRIANGLE_TEST(Simple_Triangle, 0x088002a801180118, 0x00d20000ffff0000, 0x006e000000000000,
// 0x006e000000000000);

TRIANGLE_TEST(Simple_Triangle_Flipped, 0x080002a801180118, 0x006e000000010000, 0x00d2000000000000,
0x00d2000000000000);
// TRIANGLE_TEST(Simple_Triangle_Flipped, 0x080002a801180118, 0x006e000000010000, 0x00d2000000000000,
// 0x00d2000000000000);

TRIANGLE_TEST(Simple_Triangle_Using_YM, 0x08800300016c0118, 0x00d20000ffff0000, 0x006e000000000000,
0x006e00000004c000);
// TRIANGLE_TEST(Simple_Triangle_Using_YM, 0x08800300016c0118, 0x00d20000ffff0000, 0x006e000000000000,
// 0x006e00000004c000);

TRIANGLE_TEST(Slopes_L_H_Intersect_Before_YM_YL, 0x088002a8016800f0, 0x00c80000ffff0000,
0x005a000000010000, 0x00780000ffff0000);
// TRIANGLE_TEST(Slopes_L_H_Intersect_Before_YM_YL, 0x088002a8016800f0, 0x00c80000ffff0000,
// 0x005a000000010000, 0x00780000ffff0000);

TRIANGLE_TEST(Slopes_L_M_Intersect, 0x088002a8011800a0, 0x00d20000ffff0000, 0x006e00000000e000,
0x006e00000004a000);
// TRIANGLE_TEST(Slopes_L_M_Intersect, 0x088002a8011800a0, 0x00d20000ffff0000, 0x006e00000000e000,
// 0x006e00000004a000);

TRIANGLE_TEST(Slopes_L_M_Intersect_Flipped, 0x080002a8011800a0, 0x006e000000010000,
0x00d20000ffff8000, 0x00d20000fffb4000);
// TRIANGLE_TEST(Slopes_L_M_Intersect_Flipped, 0x080002a8011800a0, 0x006e000000010000,
// 0x00d20000ffff8000, 0x00d20000fffb4000);

TRIANGLE_TEST(Same_XH_XM_XL, 0x088002bc02bc0258, 0x00e1000000000000, 0x00e10000fffe0000,
0x00e1000000000000);
// TRIANGLE_TEST(Same_XH_XM_XL, 0x088002bc02bc0258, 0x00e1000000000000, 0x00e10000fffe0000,
// 0x00e1000000000000);

TEST(RDPCompare, test)
{
AngrylionReplayer::Init();
std::vector<std::vector<uint64_t>> commands = {
{0x2d000000005003c0, },
{0x2f30000000000000, },
{0x3f18013f00100000, },
{0x37000000ffff00ff, },
{0x364fc3bc00000000, },
{0x2700000000000000, },
{0x37000000ff0000ff, },
{0x0880019000c800c8, 0x004b0000ffff0000, 0x0019000000000000, 0x0019000000000000, },
{0x2700000000000000, },
{0x3700000000ff00ff, },
{0x0880019000c800c8, 0x0096000000000000, 0x0064000000010000, 0x0064000000000000, },
{0x2700000000000000, },
{0x370000000000ffff, },
{0x08800190019000c8, 0x00e1000000000000, 0x00e10000ffff0000, 0x00e1000000000000, },
{0x2700000000000000, },
{0x37000000ffffffff, },
{0x08800190019000c8, 0x012c000000000000, 0x00fa000000000000, 0x00fa000000010000, },
{0x2700000000000000, },
{0x37000000ff0000ff, },
{0x0880032002bc0258, 0x004b0000fffe0000, 0x0019000000000000, 0x0019000000020000, },
{0x2700000000000000, },
{0x3700000000ff00ff, },
{0x0880032002580258, 0x00960000ffff8000, 0x0064000000008000, 0x0064000000000000, },
{0x2700000000000000, },
{0x370000000000ffff, },
{0x088002bc02bc0258, 0x00e1000000000000, 0x00e10000fffe0000, 0x00e1000000000000, },
{0x0880032002bc02bc, 0x00e1000000000000, 0x00af000000020000, 0x00af000000000000, },
{0x2700000000000000, },
{0x37000000ffffffff, },
{0x0880032003200258, 0x012c000000000000, 0x01130000ffff8000, 0x0113000000008000, },
{0x2900000000000000, },
};
for (const auto& command : commands)
{
AngrylionReplayer::RunCommand(command);
}
Framebuffer fb = AngrylionReplayer::GetFramebuffer();
std::ofstream file("tex.raw", std::ios::binary);
file.write(reinterpret_cast<char*>(fb.pixels.data()), fb.pixels.size() * sizeof(uint32_t));
AngrylionReplayer::Cleanup();
}

int main()
{
Expand Down
6 changes: 3 additions & 3 deletions nes/nes_ppu.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ unsigned char reverse(unsigned char b)
static struct CRT crt;
static struct NTSC_SETTINGS ntsc;
static int color = 1;
static int noise = 10;
// static int noise = 10;
static int field = 0;
static int raw = 0;
static int hue = 0;
Expand Down Expand Up @@ -90,8 +90,8 @@ namespace hydra::NES
{
ntsc.frame ^= 1;
}
crt_modulate(&crt, &ntsc);
crt_demodulate(&crt, noise);
// crt_modulate(&crt, &ntsc);
// crt_demodulate(&crt, noise);
field ^= 1;
std::swap(screen_color_data_, screen_color_data_second_);
}
Expand Down
12 changes: 12 additions & 0 deletions nes/nes_tkpwrapper.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,19 @@ namespace hydra::NES

void NES_TKPWrapper::update()
{
static int ticks = 0;
ticks++;
cpu_.Tick();
if (ticks > instrs_per_frame_)
{
auto elapsed = std::chrono::high_resolution_clock::now() - start_frame_time_;
if (elapsed < std::chrono::milliseconds(16))
{
std::this_thread::sleep_for(std::chrono::milliseconds(16) - elapsed);
}
start_frame_time_ = std::chrono::high_resolution_clock::now();
ticks = 0;
}
}

bool NES_TKPWrapper::load_file(const std::string& path)
Expand Down
2 changes: 2 additions & 0 deletions nes/nes_tkpwrapper.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ namespace hydra::NES
APU apu_{};
CPUBus cpubus_{ppu_, apu_};
CPU cpu_{cpubus_, Paused};

std::chrono::time_point<std::chrono::high_resolution_clock> start_frame_time_{};
};
} // namespace hydra::NES
2 changes: 2 additions & 0 deletions vendored/angrylion-rdp-plus/n64video/rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,12 @@ void rdp_init(uint32_t wid, uint32_t num_workers)

void rdp_invalid(uint32_t wid, const uint32_t* args)
{
printf("RDP: invalid command %08x\n", args[0]);
}

void rdp_noop(uint32_t wid, const uint32_t* args)
{
printf("RDP: invalid command %08x\n", args[0]);
}

void rdp_sync_load(uint32_t wid, const uint32_t* args)
Expand Down
4 changes: 4 additions & 0 deletions vendored/angrylion-rdp-plus/n64video/vi.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,12 +619,16 @@ void n64video_update_screen(void)
v_start = (*vi_reg_ptr[VI_V_START] >> 16) & 0x3ff;
h_start = (*vi_reg_ptr[VI_H_START] >> 16) & 0x3ff;

printf("v_start: %d, h_start: %d\n", v_start, h_start);

int32_t v_end = *vi_reg_ptr[VI_V_START] & 0x3ff;
int32_t h_end = *vi_reg_ptr[VI_H_START] & 0x3ff;

hres = h_end - h_start;
vres = (v_end - v_start) >> 1; // vertical is measured in half-lines

printf("hres: %d, vres: %d\n", hres, vres);

x_add = *vi_reg_ptr[VI_X_SCALE] & 0xfff;
x_start = (*vi_reg_ptr[VI_X_SCALE] >> 16) & 0xfff;

Expand Down

0 comments on commit cd43b1d

Please sign in to comment.