ParallelRDP integration
This commit is contained in:
20
external/shader.frag
vendored
Normal file
20
external/shader.frag
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#version 450
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
layout(set = 0, binding = 0) uniform sampler2D uImage;
|
||||||
|
|
||||||
|
layout(push_constant) uniform Screen {
|
||||||
|
vec2 size;
|
||||||
|
vec2 offset;
|
||||||
|
} uScreen;
|
||||||
|
|
||||||
|
layout(constant_id = 0) const float Scale = 1.0;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = (vUV - uScreen.offset) / uScreen.size;
|
||||||
|
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
||||||
|
FragColor = vec4(0, 0, 0, 1);
|
||||||
|
} else {
|
||||||
|
FragColor = Scale * textureLod(uImage, uv, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
8
external/shader.vert
vendored
Normal file
8
external/shader.vert
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#version 450
|
||||||
|
layout(location = 0) in vec2 Position;
|
||||||
|
layout(location = 0) out highp vec2 vUV;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(Position, 0.0, 1.0);
|
||||||
|
vUV = 0.5 * Position + 0.5;
|
||||||
|
}
|
||||||
@@ -24,3 +24,6 @@ using m128 = __m128i;
|
|||||||
#define KiB * 1024
|
#define KiB * 1024
|
||||||
#define MiB (KiB * 1024)
|
#define MiB (KiB * 1024)
|
||||||
#define GiB (MiB * 1024)
|
#define GiB (MiB * 1024)
|
||||||
|
|
||||||
|
#define N64_CPU_FREQ 93750000
|
||||||
|
#define N64_CYCLES_PER_FRAME (N64_CPU_FREQ / 60)
|
||||||
@@ -20,12 +20,19 @@ find_package(fmt REQUIRED)
|
|||||||
|
|
||||||
add_subdirectory(core)
|
add_subdirectory(core)
|
||||||
|
|
||||||
|
set(PARALLELRDP_INCLUDES
|
||||||
|
../../../external/parallel-rdp-standalone/vulkan
|
||||||
|
../../../external/parallel-rdp-standalone/util
|
||||||
|
../../../external/parallel-rdp-standalone/parallel-rdp
|
||||||
|
../../../external/parallel-rdp-standalone/volk
|
||||||
|
../../../external/parallel-rdp-standalone/vulkan-headers)
|
||||||
|
|
||||||
add_library(n64
|
add_library(n64
|
||||||
Core.hpp
|
Core.hpp
|
||||||
Core.cpp
|
Core.cpp
|
||||||
memory_regions.hpp
|
memory_regions.hpp
|
||||||
../BaseCore.cpp
|
../BaseCore.cpp
|
||||||
../BaseCore.hpp)
|
../BaseCore.hpp)
|
||||||
target_include_directories(n64 PRIVATE . ..)
|
target_include_directories(n64 PRIVATE . .. ../../frontend/sdl ${PARALLELRDP_INCLUDES})
|
||||||
target_include_directories(n64 PUBLIC ${mio_SOURCE_DIR}/include ${toml11_SOURCE_DIR}/include)
|
target_include_directories(n64 PUBLIC ${mio_SOURCE_DIR}/include ${toml11_SOURCE_DIR}/include)
|
||||||
target_link_libraries(n64 PRIVATE mio::mio toml11::toml11 fmt::fmt n64-core)
|
target_link_libraries(n64 PRIVATE mio::mio toml11::toml11 fmt::fmt n64-core)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <SDL2/SDL_events.h>
|
#include <SDL2/SDL_events.h>
|
||||||
|
#include <ParallelRDPWrapper.hpp>
|
||||||
|
|
||||||
namespace natsukashii::n64::core {
|
namespace natsukashii::n64::core {
|
||||||
Core::Core(const std::string& rom) {
|
Core::Core(const std::string& rom) {
|
||||||
mem.LoadROM(rom);
|
mem.LoadROM(rom);
|
||||||
|
LoadParallelRDP(mem.GetRDRAM());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Run() {
|
void Core::Run() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <BaseCore.hpp>
|
#include <BaseCore.hpp>
|
||||||
#include "n64/core/Cpu.hpp"
|
#include <n64/core/Cpu.hpp>
|
||||||
#include "n64/core/Mem.hpp"
|
#include <n64/core/Mem.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace natsukashii::n64::core {
|
namespace natsukashii::n64::core {
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ add_library(n64-core
|
|||||||
Cpu.hpp
|
Cpu.hpp
|
||||||
Cpu.cpp
|
Cpu.cpp
|
||||||
Mem.cpp
|
Mem.cpp
|
||||||
Mem.hpp RDP.cpp RDP.hpp)
|
Mem.hpp
|
||||||
|
RDP.cpp
|
||||||
|
RDP.hpp
|
||||||
|
mmio/VI.cpp
|
||||||
|
mmio/VI.hpp mmio/Interrupt.hpp mmio/MI.cpp mmio/MI.hpp mmio/Interrupt.cpp)
|
||||||
|
|
||||||
target_include_directories(n64-core PRIVATE . .. ../../)
|
target_include_directories(n64-core PRIVATE . .. ../../ mmio)
|
||||||
target_link_libraries(n64-core PUBLIC n64-cpu)
|
target_link_libraries(n64-core PUBLIC n64-cpu)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#include "Cpu.hpp"
|
#include <Cpu.hpp>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "n64/core/cpu/Registers.hpp"
|
#include <n64/core/cpu/Registers.hpp>
|
||||||
|
|
||||||
namespace natsukashii::n64::core {
|
namespace natsukashii::n64::core {
|
||||||
struct Cpu {
|
struct Cpu {
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ struct Mem {
|
|||||||
~Mem() = default;
|
~Mem() = default;
|
||||||
Mem();
|
Mem();
|
||||||
void LoadROM(const std::string&);
|
void LoadROM(const std::string&);
|
||||||
|
[[nodiscard]] auto GetRDRAM() const -> const u8* {
|
||||||
|
return rdram.data();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::vector<u8> cart, rdram, sram;
|
std::vector<u8> cart, rdram, sram;
|
||||||
u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{}, pifRam[PIF_RAM_SIZE]{};
|
u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{}, pifRam[PIF_RAM_SIZE]{};
|
||||||
|
|||||||
58
src/core/n64/core/mmio/Interrupt.cpp
Normal file
58
src/core/n64/core/mmio/Interrupt.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include <Interrupt.hpp>
|
||||||
|
#include <MI.hpp>
|
||||||
|
#include <n64/core/cpu/Registers.hpp>
|
||||||
|
|
||||||
|
namespace natsukashii::n64::core {
|
||||||
|
void InterruptRaise(MI &mi, Registers ®s, InterruptType intr) {
|
||||||
|
switch(intr) {
|
||||||
|
case InterruptType::VI:
|
||||||
|
mi.miIntr.vi = true;
|
||||||
|
break;
|
||||||
|
case InterruptType::SI:
|
||||||
|
mi.miIntr.si = true;
|
||||||
|
break;
|
||||||
|
case InterruptType::PI:
|
||||||
|
mi.miIntr.pi = true;
|
||||||
|
break;
|
||||||
|
case InterruptType::AI:
|
||||||
|
mi.miIntr.ai = true;
|
||||||
|
break;
|
||||||
|
case InterruptType::DP:
|
||||||
|
mi.miIntr.dp = true;
|
||||||
|
break;
|
||||||
|
case InterruptType::SP:
|
||||||
|
mi.miIntr.sp = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateInterrupt(mi, regs);
|
||||||
|
}
|
||||||
|
void InterruptLower(MI &mi, Registers ®s, InterruptType intr) {
|
||||||
|
switch(intr) {
|
||||||
|
case InterruptType::VI:
|
||||||
|
mi.miIntr.vi = false;
|
||||||
|
break;
|
||||||
|
case InterruptType::SI:
|
||||||
|
mi.miIntr.si = false;
|
||||||
|
break;
|
||||||
|
case InterruptType::PI:
|
||||||
|
mi.miIntr.pi = false;
|
||||||
|
break;
|
||||||
|
case InterruptType::AI:
|
||||||
|
mi.miIntr.ai = false;
|
||||||
|
break;
|
||||||
|
case InterruptType::DP:
|
||||||
|
mi.miIntr.dp = false;
|
||||||
|
break;
|
||||||
|
case InterruptType::SP:
|
||||||
|
mi.miIntr.sp = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateInterrupt(mi, regs);
|
||||||
|
}
|
||||||
|
void UpdateInterrupt(MI &mi, Registers ®s) {
|
||||||
|
bool interrupt = mi.miIntr.raw & mi.miIntrMask.raw;
|
||||||
|
regs.cop0.cause.ip2 = interrupt;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/core/n64/core/mmio/Interrupt.hpp
Normal file
16
src/core/n64/core/mmio/Interrupt.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <common.hpp>
|
||||||
|
#include <MI.hpp>
|
||||||
|
|
||||||
|
namespace natsukashii::n64::core {
|
||||||
|
|
||||||
|
struct Registers;
|
||||||
|
|
||||||
|
enum class InterruptType : u8 {
|
||||||
|
VI, SI, PI, AI, DP, SP
|
||||||
|
};
|
||||||
|
|
||||||
|
void InterruptRaise(MI &mi, Registers ®s, InterruptType intr);
|
||||||
|
void InterruptLower(MI &mi, Registers ®s, InterruptType intr);
|
||||||
|
void UpdateInterrupt(MI &mi, Registers ®s);
|
||||||
|
}
|
||||||
79
src/core/n64/core/mmio/MI.cpp
Normal file
79
src/core/n64/core/mmio/MI.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include <MI.hpp>
|
||||||
|
#include <n64/core/cpu/Registers.hpp>
|
||||||
|
#include <util.hpp>
|
||||||
|
#include <Interrupt.hpp>
|
||||||
|
|
||||||
|
#define MI_VERSION_REG 0x02020102
|
||||||
|
|
||||||
|
namespace natsukashii::n64::core {
|
||||||
|
MI::MI() {
|
||||||
|
miIntrMask.raw = 0;
|
||||||
|
miIntr.raw = 0;
|
||||||
|
miMode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 MI::Read(u32 paddr) {
|
||||||
|
switch(paddr & 0xF) {
|
||||||
|
case 0x0: return miMode & 0x3FF;
|
||||||
|
case 0x4: return MI_VERSION_REG;
|
||||||
|
case 0x8: return miIntr.raw & 0x3F;
|
||||||
|
case 0xC: return miIntrMask.raw & 0x3F;
|
||||||
|
default: util::panic("Unhandled MI[%08X] read\n", paddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MI::Write(Registers& regs, u32 paddr, u32 val) {
|
||||||
|
switch(paddr & 0xF) {
|
||||||
|
case 0x0:
|
||||||
|
miMode &= 0xFFFFFF80;
|
||||||
|
miMode |= val & 0x7F;
|
||||||
|
if (val & (1 << 7)) {
|
||||||
|
miMode &= ~(1 << 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 8)) {
|
||||||
|
miMode |= 1 << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 9)) {
|
||||||
|
miMode &= ~(1 << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 10)) {
|
||||||
|
miMode |= 1 << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 11)) {
|
||||||
|
InterruptLower(*this, regs, InterruptType::DP);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 12)) {
|
||||||
|
miMode &= ~(1 << 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << 13)) {
|
||||||
|
miMode |= 1 << 9;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x4: break;
|
||||||
|
case 0xC:
|
||||||
|
for (int bit = 0; bit < 6; bit++) {
|
||||||
|
int clearbit = bit << 1;
|
||||||
|
int setbit = (bit << 1) + 1;
|
||||||
|
|
||||||
|
if (val & (1 << clearbit)) {
|
||||||
|
miIntrMask.raw &= ~(1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val & (1 << setbit)) {
|
||||||
|
miIntrMask.raw |= 1 << bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateInterrupt(*this, regs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
util::panic("Unhandled MI[%08X] write (%08X)\n", val, paddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/core/n64/core/mmio/MI.hpp
Normal file
29
src/core/n64/core/mmio/MI.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <common.hpp>
|
||||||
|
|
||||||
|
namespace natsukashii::n64::core {
|
||||||
|
|
||||||
|
union MIIntr {
|
||||||
|
struct {
|
||||||
|
unsigned sp: 1;
|
||||||
|
unsigned si: 1;
|
||||||
|
unsigned ai: 1;
|
||||||
|
unsigned vi: 1;
|
||||||
|
unsigned pi: 1;
|
||||||
|
unsigned dp: 1;
|
||||||
|
unsigned: 26;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Registers;
|
||||||
|
|
||||||
|
struct MI {
|
||||||
|
MI();
|
||||||
|
u32 Read(u32);
|
||||||
|
void Write(Registers& regs, u32, u32);
|
||||||
|
|
||||||
|
u32 miMode;
|
||||||
|
MIIntr miIntr{}, miIntrMask{};
|
||||||
|
};
|
||||||
|
}
|
||||||
83
src/core/n64/core/mmio/VI.cpp
Normal file
83
src/core/n64/core/mmio/VI.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#include <VI.hpp>
|
||||||
|
#include <util.hpp>
|
||||||
|
#include <n64/core/cpu/Registers.hpp>
|
||||||
|
#include <MI.hpp>
|
||||||
|
#include <n64/core/mmio/Interrupt.hpp>
|
||||||
|
|
||||||
|
namespace natsukashii::n64::core {
|
||||||
|
VI::VI () {
|
||||||
|
status.raw = 0xF;
|
||||||
|
intr = 256;
|
||||||
|
origin = 0;
|
||||||
|
width = 320;
|
||||||
|
current = 0;
|
||||||
|
vsync = 0;
|
||||||
|
hsync = 0;
|
||||||
|
numHalflines = 262;
|
||||||
|
numFields = 1;
|
||||||
|
cyclesPerHalfline = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 VI::Read(u32 paddr) {
|
||||||
|
switch(paddr) {
|
||||||
|
case 0x04400000: return status.raw;
|
||||||
|
case 0x04400004: return origin;
|
||||||
|
case 0x04400008: return width;
|
||||||
|
case 0x0440000C: return intr;
|
||||||
|
case 0x04400010: return current << 1;
|
||||||
|
case 0x04400014: return burst.raw;
|
||||||
|
case 0x04400018: return vsync;
|
||||||
|
case 0x0440001C: return hsync;
|
||||||
|
case 0x04400020: return hsyncLeap.raw;
|
||||||
|
case 0x04400024: return hvideo.raw;
|
||||||
|
case 0x04400028: return vvideo.raw;
|
||||||
|
case 0x0440002C: return vburst.raw;
|
||||||
|
case 0x04400030: return xscale.raw;
|
||||||
|
case 0x04400034: return yscale.raw;
|
||||||
|
default:
|
||||||
|
util::panic("Unimplemented VI[%08X] read\n", paddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {
|
||||||
|
switch(paddr) {
|
||||||
|
case 0x04400000:
|
||||||
|
status.raw = val;
|
||||||
|
numFields = status.serrate ? 2 : 1;
|
||||||
|
break;
|
||||||
|
case 0x04400004: {
|
||||||
|
u32 masked = val & 0xFFFFFF;
|
||||||
|
if(origin != masked) {
|
||||||
|
swaps++;
|
||||||
|
}
|
||||||
|
origin = masked;
|
||||||
|
} break;
|
||||||
|
case 0x04400008: {
|
||||||
|
width = val & 0x7FF;
|
||||||
|
} break;
|
||||||
|
case 0x0440000C: {
|
||||||
|
intr = val & 0x3FF;
|
||||||
|
} break;
|
||||||
|
case 0x04400010:
|
||||||
|
InterruptLower(mi, regs, InterruptType::VI);
|
||||||
|
break;
|
||||||
|
case 0x04400014: burst.raw = val; break;
|
||||||
|
case 0x04400018: {
|
||||||
|
vsync = val & 0x3FF;
|
||||||
|
numHalflines = vsync >> 1;
|
||||||
|
cyclesPerHalfline = N64_CYCLES_PER_FRAME / numHalflines;
|
||||||
|
} break;
|
||||||
|
case 0x0440001C: {
|
||||||
|
hsync = val & 0x3FF;
|
||||||
|
} break;
|
||||||
|
case 0x04400020: hsyncLeap.raw = val; break;
|
||||||
|
case 0x04400024: hvideo.raw = val; break;
|
||||||
|
case 0x04400028: vvideo.raw = val; break;
|
||||||
|
case 0x0440002C: vburst.raw = val; break;
|
||||||
|
case 0x04400030: xscale.raw = val; break;
|
||||||
|
case 0x04400034: yscale.raw = val; break;
|
||||||
|
default:
|
||||||
|
util::panic("Unimplemented VI[%08X] write (%08X)\n", paddr, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
src/core/n64/core/mmio/VI.hpp
Normal file
83
src/core/n64/core/mmio/VI.hpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <common.hpp>
|
||||||
|
|
||||||
|
namespace natsukashii::n64::core {
|
||||||
|
union VIBurst {
|
||||||
|
struct {
|
||||||
|
unsigned hsyncW:8;
|
||||||
|
unsigned burstW:8;
|
||||||
|
unsigned vsyncW:4;
|
||||||
|
unsigned burstStart:10;
|
||||||
|
unsigned:2;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union VIHsyncLeap {
|
||||||
|
struct {
|
||||||
|
unsigned leapB:10;
|
||||||
|
unsigned:6;
|
||||||
|
unsigned leapA:10;
|
||||||
|
unsigned:6;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
union VIVideo {
|
||||||
|
struct {
|
||||||
|
unsigned end:10;
|
||||||
|
unsigned:6;
|
||||||
|
unsigned start:10;
|
||||||
|
unsigned:6;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
union VIScale {
|
||||||
|
struct {
|
||||||
|
unsigned scale:12;
|
||||||
|
unsigned:4;
|
||||||
|
unsigned offset:12;
|
||||||
|
unsigned:4;
|
||||||
|
};
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VIFormat {
|
||||||
|
blank = 0,
|
||||||
|
reserved = 1,
|
||||||
|
f5553 = 2,
|
||||||
|
f8888 = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
union VIStatus {
|
||||||
|
struct {
|
||||||
|
u8 format:2;
|
||||||
|
unsigned serrate:1;
|
||||||
|
unsigned:29;
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 raw;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MI;
|
||||||
|
struct Registers;
|
||||||
|
|
||||||
|
struct VI {
|
||||||
|
VI();
|
||||||
|
u32 Read(u32);
|
||||||
|
void Write(MI&, Registers&, u32, u32);
|
||||||
|
VIScale xscale{}, yscale{};
|
||||||
|
VIVideo hvideo{}, vvideo{};
|
||||||
|
VIHsyncLeap hsyncLeap{};
|
||||||
|
VIStatus status{};
|
||||||
|
VIBurst burst{}, vburst{};
|
||||||
|
u32 origin, width, current;
|
||||||
|
u32 vsync, hsync, intr;
|
||||||
|
u32 hstart{}, vstart{};
|
||||||
|
int swaps{};
|
||||||
|
int numHalflines;
|
||||||
|
int numFields;
|
||||||
|
int cyclesPerHalfline;
|
||||||
|
};
|
||||||
|
} // natsukashii::n64::core
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <portable_endian_bswap.h>
|
#include <portable_endian_bswap.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
namespace natsukashii::util {
|
namespace natsukashii::util {
|
||||||
enum MessageType : u8 {
|
enum MessageType : u8 {
|
||||||
@@ -133,4 +134,21 @@ inline size_t NextPow2(size_t num) {
|
|||||||
num |= num >> 16;
|
num |= num >> 16;
|
||||||
return num + 1;
|
return num + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void ReadFileBinary(const std::string& path, void* buf) {
|
||||||
|
std::ifstream file("external/vert.spv", std::ios::binary);
|
||||||
|
file.unsetf(std::ios::skipws);
|
||||||
|
if(!file.is_open()) {
|
||||||
|
util::panic("Could not load file!\n");
|
||||||
|
}
|
||||||
|
file.seekg(std::ios::end);
|
||||||
|
auto size = file.tellg();
|
||||||
|
file.seekg(std::ios::beg);
|
||||||
|
if(buf)
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
buf = calloc(size, 1);
|
||||||
|
file.read((char*)buf, size);
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <gb/Core.hpp>
|
#include <gb/Core.hpp>
|
||||||
#include <n64/Core.hpp>
|
#include <n64/Core.hpp>
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
|
#include <ParallelRDPWrapper.hpp>
|
||||||
|
|
||||||
namespace natsukashii::frontend {
|
namespace natsukashii::frontend {
|
||||||
using namespace natsukashii;
|
using namespace natsukashii;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ struct App {
|
|||||||
App(const std::string&, const std::string&);
|
App(const std::string&, const std::string&);
|
||||||
void Run();
|
void Run();
|
||||||
private:
|
private:
|
||||||
SDL_Window *window = nullptr;
|
|
||||||
SDL_Renderer *renderer = nullptr;
|
SDL_Renderer *renderer = nullptr;
|
||||||
u32 id;
|
u32 id;
|
||||||
std::unique_ptr<BaseCore> core;
|
std::unique_ptr<BaseCore> core;
|
||||||
|
|||||||
@@ -6,12 +6,11 @@
|
|||||||
#include <SDL2/SDL_vulkan.h>
|
#include <SDL2/SDL_vulkan.h>
|
||||||
#include <util.hpp>
|
#include <util.hpp>
|
||||||
|
|
||||||
using namespace Vulkan;
|
|
||||||
using namespace natsukashii;
|
using namespace natsukashii;
|
||||||
|
using namespace natsukashii::n64;
|
||||||
|
using namespace Vulkan;
|
||||||
|
using namespace RDP;
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
using RDP::CommandProcessor;
|
|
||||||
using RDP::CommandProcessorFlags;
|
|
||||||
using RDP::VIRegister;
|
|
||||||
|
|
||||||
static CommandProcessor* command_processor;
|
static CommandProcessor* command_processor;
|
||||||
static WSI* wsi;
|
static WSI* wsi;
|
||||||
@@ -19,7 +18,7 @@ static WSI* wsi;
|
|||||||
std::vector<Semaphore> acquire_semaphore;
|
std::vector<Semaphore> acquire_semaphore;
|
||||||
|
|
||||||
VkQueue GetGraphicsQueue() {
|
VkQueue GetGraphicsQueue() {
|
||||||
return wsi->get_context().get_graphics_queue();
|
return wsi->get_context().get_queue_info().queues[QUEUE_INDEX_GRAPHICS];
|
||||||
}
|
}
|
||||||
|
|
||||||
VkInstance GetVkInstance() {
|
VkInstance GetVkInstance() {
|
||||||
@@ -35,7 +34,7 @@ VkDevice GetVkDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GetVkGraphicsQueueFamily() {
|
uint32_t GetVkGraphicsQueueFamily() {
|
||||||
return wsi->get_context().get_graphics_queue_family();
|
return wsi->get_context().get_queue_info().family_indices[QUEUE_INDEX_GRAPHICS];
|
||||||
}
|
}
|
||||||
|
|
||||||
VkFormat GetVkFormat() {
|
VkFormat GetVkFormat() {
|
||||||
@@ -94,11 +93,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_surface_width() override {
|
uint32_t get_surface_width() override {
|
||||||
return N64_SCREEN_X * SCREEN_SCALE;
|
return 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_surface_height() override {
|
uint32_t get_surface_height() override {
|
||||||
return N64_SCREEN_Y * SCREEN_SCALE;
|
return 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool alive(Vulkan::WSI &wsi) override {
|
bool alive(Vulkan::WSI &wsi) override {
|
||||||
@@ -106,11 +105,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void poll_input() override {
|
void poll_input() override {
|
||||||
n64_poll_input();
|
SDL_Event e;
|
||||||
|
while(SDL_PollEvent(&e)) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void event_frame_tick(double frame, double elapsed) override {
|
void event_frame_tick(double frame, double elapsed) override {
|
||||||
n64_render_screen();
|
//n64_render_screen();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -125,22 +127,26 @@ void LoadParallelRDP(const u8* rdram) {
|
|||||||
util::panic("Failed to initialize WSI!");
|
util::panic("Failed to initialize WSI!");
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceLayout vert_layout;
|
ResourceLayout vertLayout;
|
||||||
ResourceLayout frag_layout;
|
ResourceLayout fragLayout;
|
||||||
|
|
||||||
vert_layout.input_mask = 1;
|
vertLayout.input_mask = 1;
|
||||||
vert_layout.output_mask = 1;
|
vertLayout.output_mask = 1;
|
||||||
|
|
||||||
frag_layout.input_mask = 1;
|
fragLayout.input_mask = 1;
|
||||||
frag_layout.output_mask = 1;
|
fragLayout.output_mask = 1;
|
||||||
frag_layout.spec_constant_mask = 1;
|
fragLayout.spec_constant_mask = 1;
|
||||||
frag_layout.push_constant_size = 4 * sizeof(float);
|
fragLayout.push_constant_size = 4 * sizeof(float);
|
||||||
|
|
||||||
frag_layout.sets[0].sampled_image_mask = 1;
|
fragLayout.sets[0].sampled_image_mask = 1;
|
||||||
frag_layout.sets[0].fp_mask = 1;
|
fragLayout.sets[0].fp_mask = 1;
|
||||||
frag_layout.sets[0].array_size[0] = 1;
|
fragLayout.sets[0].array_size[0] = 1;
|
||||||
|
|
||||||
fullscreen_quad_program = wsi->get_device().request_program(fullscreen_quad_vert, sizeof(fullscreen_quad_vert), fullscreen_quad_frag, sizeof(fullscreen_quad_frag), &vert_layout, &frag_layout);
|
u32* fullscreenQuadVert, *fullscreenQuadFrag;
|
||||||
|
util::ReadFileBinary("external/vert.spv", fullscreenQuadVert);
|
||||||
|
util::ReadFileBinary("external/frag.spv", fullscreenQuadFrag);
|
||||||
|
|
||||||
|
fullscreen_quad_program = wsi->get_device().request_program(fullscreenQuadVert, sizeof(fullscreenQuadVert), fullscreenQuadFrag, sizeof(fullscreenQuadFrag), &vertLayout, &fragLayout);
|
||||||
|
|
||||||
auto aligned_rdram = reinterpret_cast<uintptr_t>(rdram);
|
auto aligned_rdram = reinterpret_cast<uintptr_t>(rdram);
|
||||||
uintptr_t offset = 0;
|
uintptr_t offset = 0;
|
||||||
@@ -162,7 +168,7 @@ void LoadParallelRDP(const u8* rdram) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_fullscreen_textured_quad(Util::IntrusivePtr<Image> image, Util::IntrusivePtr<CommandBuffer> cmd) {
|
void DrawFullscreenTexturedQuad(Util::IntrusivePtr<Image> image, Util::IntrusivePtr<CommandBuffer> cmd) {
|
||||||
cmd->set_texture(0, 0, image->get_view(), Vulkan::StockSampler::LinearClamp);
|
cmd->set_texture(0, 0, image->get_view(), Vulkan::StockSampler::LinearClamp);
|
||||||
cmd->set_program(fullscreen_quad_program);
|
cmd->set_program(fullscreen_quad_program);
|
||||||
cmd->set_quad_state();
|
cmd->set_quad_state();
|
||||||
@@ -200,11 +206,11 @@ void draw_fullscreen_textured_quad(Util::IntrusivePtr<Image> image, Util::Intrus
|
|||||||
cmd->draw(3, 1);
|
cmd->draw(3, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_screen(Util::IntrusivePtr<Image> image) {
|
void UpdateScreen(Util::IntrusivePtr<Image> image) {
|
||||||
wsi->begin_frame();
|
wsi->begin_frame();
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
auto info = Vulkan::ImageCreateInfo::immutable_2d_image(N64_SCREEN_X * SCREEN_SCALE, N64_SCREEN_Y * SCREEN_SCALE, VK_FORMAT_R8G8B8A8_UNORM);
|
auto info = Vulkan::ImageCreateInfo::immutable_2d_image(800, 600, VK_FORMAT_R8G8B8A8_UNORM);
|
||||||
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
info.misc = IMAGE_MISC_MUTABLE_SRGB_BIT;
|
info.misc = IMAGE_MISC_MUTABLE_SRGB_BIT;
|
||||||
@@ -228,32 +234,28 @@ void update_screen(Util::IntrusivePtr<Image> image) {
|
|||||||
Util::IntrusivePtr<CommandBuffer> cmd = wsi->get_device().request_command_buffer();
|
Util::IntrusivePtr<CommandBuffer> cmd = wsi->get_device().request_command_buffer();
|
||||||
|
|
||||||
cmd->begin_render_pass(wsi->get_device().get_swapchain_render_pass(SwapchainRenderPass::ColorOnly));
|
cmd->begin_render_pass(wsi->get_device().get_swapchain_render_pass(SwapchainRenderPass::ColorOnly));
|
||||||
draw_fullscreen_textured_quad(image, cmd);
|
DrawFullscreenTexturedQuad(image, cmd);
|
||||||
ImGui_ImplVulkan_RenderDrawData(imgui_frame(), cmd->get_command_buffer());
|
//ImGui_ImplVulkan_RenderDrawData(imgui_frame(), cmd->get_command_buffer());
|
||||||
cmd->end_render_pass();
|
cmd->end_render_pass();
|
||||||
wsi->get_device().submit(cmd);
|
wsi->get_device().submit(cmd);
|
||||||
wsi->end_frame();
|
wsi->end_frame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_screen_parallel_rdp() {
|
void UpdateScreenParallelRdp(const n64::core::VI& vi) {
|
||||||
if (unlikely(!command_processor)) {
|
command_processor->set_vi_register(VIRegister::Control, vi.status.raw);
|
||||||
logfatal("Update screen without an initialized command processor");
|
command_processor->set_vi_register(VIRegister::Origin, vi.origin);
|
||||||
}
|
command_processor->set_vi_register(VIRegister::Width, vi.width);
|
||||||
|
command_processor->set_vi_register(VIRegister::Intr, vi.intr);
|
||||||
command_processor->set_vi_register(VIRegister::Control, n64sys.vi.status.raw);
|
command_processor->set_vi_register(VIRegister::VCurrentLine, vi.current);
|
||||||
command_processor->set_vi_register(VIRegister::Origin, n64sys.vi.vi_origin);
|
command_processor->set_vi_register(VIRegister::Timing, vi.burst.raw);
|
||||||
command_processor->set_vi_register(VIRegister::Width, n64sys.vi.vi_width);
|
command_processor->set_vi_register(VIRegister::VSync, vi.vsync);
|
||||||
command_processor->set_vi_register(VIRegister::Intr, n64sys.vi.vi_v_intr);
|
command_processor->set_vi_register(VIRegister::HSync, vi.hsync);
|
||||||
command_processor->set_vi_register(VIRegister::VCurrentLine, n64sys.vi.v_current);
|
command_processor->set_vi_register(VIRegister::Leap, vi.hsyncLeap.raw);
|
||||||
command_processor->set_vi_register(VIRegister::Timing, n64sys.vi.vi_burst.raw);
|
command_processor->set_vi_register(VIRegister::HStart, vi.hstart);
|
||||||
command_processor->set_vi_register(VIRegister::VSync, n64sys.vi.vsync);
|
command_processor->set_vi_register(VIRegister::VStart, vi.vstart);
|
||||||
command_processor->set_vi_register(VIRegister::HSync, n64sys.vi.hsync);
|
command_processor->set_vi_register(VIRegister::VBurst, vi.burst.raw);
|
||||||
command_processor->set_vi_register(VIRegister::Leap, n64sys.vi.leap);
|
command_processor->set_vi_register(VIRegister::XScale, vi.xscale.raw);
|
||||||
command_processor->set_vi_register(VIRegister::HStart, n64sys.vi.hstart.raw);
|
command_processor->set_vi_register(VIRegister::YScale, vi.yscale.raw);
|
||||||
command_processor->set_vi_register(VIRegister::VStart, n64sys.vi.vstart.raw);
|
|
||||||
command_processor->set_vi_register(VIRegister::VBurst, n64sys.vi.vburst);
|
|
||||||
command_processor->set_vi_register(VIRegister::XScale, n64sys.vi.xscale.raw);
|
|
||||||
command_processor->set_vi_register(VIRegister::YScale, n64sys.vi.yscale.raw);
|
|
||||||
|
|
||||||
RDP::ScanoutOptions opts;
|
RDP::ScanoutOptions opts;
|
||||||
opts.persist_frame_on_invalid_input = true;
|
opts.persist_frame_on_invalid_input = true;
|
||||||
@@ -265,18 +267,18 @@ void update_screen_parallel_rdp() {
|
|||||||
opts.downscale_steps = true;
|
opts.downscale_steps = true;
|
||||||
opts.crop_overscan_pixels = true;
|
opts.crop_overscan_pixels = true;
|
||||||
Util::IntrusivePtr<Image> image = command_processor->scanout(opts);
|
Util::IntrusivePtr<Image> image = command_processor->scanout(opts);
|
||||||
update_screen(image);
|
UpdateScreen(image);
|
||||||
command_processor->begin_frame_context();
|
command_processor->begin_frame_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_screen_parallel_rdp_no_game() {
|
void UpdateScreenParallelRdpNoGame() {
|
||||||
update_screen(static_cast<Util::IntrusivePtr<Image>>(nullptr));
|
UpdateScreen(static_cast<Util::IntrusivePtr<Image>>(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void parallel_rdp_enqueue_command(int command_length, word* buffer) {
|
void ParallelRdpEnqueueCommand(int command_length, u32* buffer) {
|
||||||
command_processor->enqueue_command(command_length, buffer);
|
command_processor->enqueue_command(command_length, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parallel_rdp_on_full_sync() {
|
void ParallelRdpOnFullSync() {
|
||||||
command_processor->wait_for_timeline(command_processor->signal_timeline());
|
command_processor->wait_for_timeline(command_processor->signal_timeline());
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <n64/Core.hpp>
|
#include <n64/Core.hpp>
|
||||||
#include <wsi.hpp>
|
#include <wsi.hpp>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <n64/core/mmio/VI.hpp>
|
||||||
|
|
||||||
|
static SDL_Window* window;
|
||||||
VkQueue GetGraphicsQueue();
|
VkQueue GetGraphicsQueue();
|
||||||
VkInstance GetVkInstance();
|
VkInstance GetVkInstance();
|
||||||
VkPhysicalDevice GetVkPhysicalDevice();
|
VkPhysicalDevice GetVkPhysicalDevice();
|
||||||
@@ -10,8 +13,8 @@ uint32_t GetVkGraphicsQueueFamily();
|
|||||||
VkFormat GetVkFormat();
|
VkFormat GetVkFormat();
|
||||||
VkCommandBuffer GetVkCommandBuffer();
|
VkCommandBuffer GetVkCommandBuffer();
|
||||||
void SubmitRequestedVkCommandBuffer();
|
void SubmitRequestedVkCommandBuffer();
|
||||||
void LoadParallelRdp();
|
void LoadParallelRDP(const u8* rdram);
|
||||||
void UpdateScreenParallelRdp();
|
void UpdateScreenParallelRdp(natsukashii::n64::core::VI& vi);
|
||||||
void ParallelRdpEnqueueCommand(int command_length, u32* buffer);
|
void ParallelRdpEnqueueCommand(int command_length, u32* buffer);
|
||||||
void ParallelRdpOnFullSync();
|
void ParallelRdpOnFullSync();
|
||||||
void UpdateScreenParallelRdpNoGame();
|
void UpdateScreenParallelRdpNoGame();
|
||||||
|
|||||||
Reference in New Issue
Block a user