mirror of
https://github.com/open-goal/jak-project
synced 2026-07-08 06:30:44 -04:00
[graphics] shadow volumes (#1247)
* shadow volumes drawing * fix bugs in clipping case * add shadow * fix Q register bugs * fix bugs
This commit is contained in:
@@ -1007,6 +1007,13 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma
|
||||
|
||||
case VuInstrK::XTOP:
|
||||
return fmt::format("vu.{} = xtop();", instr.src.at(0).to_string(m_label_names));
|
||||
case VuInstrK::OPMULA:
|
||||
return fmt::format("vu.acc.opmula(vu.{}, vu.{});", instr.src.at(0).to_string(m_label_names),
|
||||
instr.src.at(1).to_string(m_label_names));
|
||||
case VuInstrK::OPMSUB:
|
||||
return fmt::format("vu.acc.opmsub(vu.{}, vu.{}, vu.{});", instr.dst->to_string(m_label_names),
|
||||
instr.src.at(0).to_string(m_label_names),
|
||||
instr.src.at(1).to_string(m_label_names));
|
||||
default:
|
||||
unk++;
|
||||
fmt::print("unknown 0 is {}\n", to_string(instr));
|
||||
|
||||
@@ -109,6 +109,7 @@ set(RUNTIME_SOURCE
|
||||
graphics/opengl_renderer/OpenGLRenderer.cpp
|
||||
graphics/opengl_renderer/Profiler.cpp
|
||||
graphics/opengl_renderer/Shader.cpp
|
||||
graphics/opengl_renderer/Shadow_PS2.cpp
|
||||
graphics/opengl_renderer/ShadowRenderer.cpp
|
||||
graphics/opengl_renderer/SkyBlendCPU.cpp
|
||||
graphics/opengl_renderer/SkyBlendGPU.cpp
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "immintrin.h"
|
||||
#include "common/math/Vector.h"
|
||||
#include <cfloat>
|
||||
|
||||
enum class Mask {
|
||||
NONE = 0,
|
||||
@@ -76,6 +77,8 @@ struct alignas(16) Vf {
|
||||
|
||||
std::string print() const { return fmt::format("{} {} {} {}", x(), y(), z(), w()); }
|
||||
|
||||
float length_xyz() const { return std::sqrt(x() * x() + y() * y() + z() * z()); }
|
||||
|
||||
std::string print_hex() const {
|
||||
return fmt::format("0x{:x} 0x{:x} 0x{:x} 0x{:x}", x_as_u32(), y_as_u32(), z_as_u32(),
|
||||
w_as_u32());
|
||||
@@ -232,6 +235,14 @@ struct alignas(16) Vf {
|
||||
}
|
||||
}
|
||||
|
||||
void mini(Mask mask, const Vf& a, const Vf& b) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
data[i] = vu_min(a[i], b[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fill(float f) {
|
||||
for (auto& x : data) {
|
||||
x = f;
|
||||
@@ -274,6 +285,32 @@ struct alignas(16) Vf {
|
||||
}
|
||||
}
|
||||
|
||||
u32 add_and_set_sf_s(Mask mask, const Vf& a, float b) {
|
||||
u32 flag = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
data[i] = a[i] + b;
|
||||
if (data[i] < 0) {
|
||||
flag = 0x2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
u32 sub_and_set_sf_s(Mask mask, const Vf& a, float b) {
|
||||
u32 flag = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
data[i] = a[i] - b;
|
||||
if (data[i] < 0) {
|
||||
flag = 0x2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
void sub(Mask mask, const Vf& a, float b) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
@@ -306,6 +343,18 @@ struct alignas(16) Vf {
|
||||
}
|
||||
}
|
||||
|
||||
void saturate_infs() {
|
||||
for (auto& val : data) {
|
||||
if (std::isinf(val)) {
|
||||
if (val > 0) {
|
||||
val = FLT_MAX;
|
||||
} else {
|
||||
val = -FLT_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mul(Mask mask, const Vf& a, float b) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
@@ -522,4 +571,16 @@ struct alignas(16) Accumulator {
|
||||
auto a = _mm_load_ps(_a.data);
|
||||
_mm_store_ps(data, _mm_mul_ps(a, b));
|
||||
}
|
||||
|
||||
void opmula(const Vf& a, const Vf& b) {
|
||||
data[0] = a.data[1] * b.data[2];
|
||||
data[1] = a.data[2] * b.data[0];
|
||||
data[2] = a.data[0] * b.data[1];
|
||||
}
|
||||
|
||||
void opmsub(Vf& dst, Vf a, Vf b) {
|
||||
dst.data[0] = data[0] - a.data[1] * b.data[2];
|
||||
dst.data[1] = data[1] - a.data[2] * b.data[0];
|
||||
dst.data[2] = data[2] - a.data[0] * b.data[1];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -682,6 +682,16 @@ void DirectRenderer::handle_ad(const u8* data,
|
||||
break;
|
||||
case GsRegisterAddress::FRAME_1:
|
||||
break;
|
||||
case GsRegisterAddress::RGBAQ:
|
||||
// shadow scissor does this?
|
||||
{
|
||||
m_prim_building.rgba_reg[0] = data[0];
|
||||
m_prim_building.rgba_reg[1] = data[1];
|
||||
m_prim_building.rgba_reg[2] = data[2];
|
||||
m_prim_building.rgba_reg[3] = data[3];
|
||||
memcpy(&m_prim_building.Q, data + 4, 4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fmt::print("Address {} is not supported\n", register_address_name(addr));
|
||||
ASSERT(false);
|
||||
|
||||
@@ -391,7 +391,7 @@ void OpenGLRenderer::setup_frame(int window_width_px,
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClearDepth(0.0);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,4 +81,5 @@ ShaderLibrary::ShaderLibrary() {
|
||||
at(ShaderId::OCEAN_TEXTURE) = {"ocean_texture"};
|
||||
at(ShaderId::OCEAN_TEXTURE_MIPMAP) = {"ocean_texture_mipmap"};
|
||||
at(ShaderId::OCEAN_COMMON) = {"ocean_common"};
|
||||
at(ShaderId::SHADOW) = {"shadow"};
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ enum class ShaderId {
|
||||
OCEAN_TEXTURE = 13,
|
||||
OCEAN_TEXTURE_MIPMAP = 14,
|
||||
OCEAN_COMMON = 15,
|
||||
SHADOW = 16,
|
||||
MAX_SHADERS
|
||||
};
|
||||
|
||||
@@ -45,7 +46,6 @@ class ShaderLibrary {
|
||||
public:
|
||||
ShaderLibrary();
|
||||
Shader& operator[](ShaderId id) { return m_shaders[(int)id]; }
|
||||
|
||||
Shader& at(ShaderId id) { return m_shaders[(int)id]; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,16 +1,426 @@
|
||||
#include "ShadowRenderer.h"
|
||||
#include "third-party/imgui/imgui.h"
|
||||
|
||||
#include <cfloat>
|
||||
|
||||
ShadowRenderer::ShadowRenderer(const std::string& name, BucketId my_id)
|
||||
: BucketRenderer(name, my_id), m_direct(name, my_id, 0x4000) {}
|
||||
: BucketRenderer(name, my_id) {
|
||||
// create OpenGL objects
|
||||
glGenBuffers(1, &m_ogl.vertex_buffer);
|
||||
|
||||
glGenBuffers(2, m_ogl.index_buffer);
|
||||
glGenVertexArrays(1, &m_ogl.vao);
|
||||
|
||||
// set up the vertex array
|
||||
glBindVertexArray(m_ogl.vao);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[i]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_INDICES * sizeof(u32), nullptr, GL_STREAM_DRAW);
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, MAX_VERTICES * sizeof(Vertex), nullptr, GL_STREAM_DRAW);
|
||||
|
||||
// xyz
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, // location 0 in the shader
|
||||
3, // 3 floats per vert
|
||||
GL_FLOAT, // floats
|
||||
GL_TRUE, // normalized, ignored,
|
||||
sizeof(Vertex), //
|
||||
(void*)offsetof(Vertex, xyz) // offset in array
|
||||
);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void ShadowRenderer::draw_debug_window() {
|
||||
m_direct.draw_debug_window();
|
||||
ImGui::Checkbox("Volume", &m_debug_draw_volume);
|
||||
ImGui::Text("Vert: %d, Front: %d, Back: %d\n", m_next_vertex, m_next_front_index,
|
||||
m_next_back_index);
|
||||
}
|
||||
|
||||
ShadowRenderer::~ShadowRenderer() {
|
||||
glDeleteBuffers(1, &m_ogl.vertex_buffer);
|
||||
glDeleteBuffers(2, m_ogl.index_buffer);
|
||||
glDeleteVertexArrays(1, &m_ogl.vao);
|
||||
}
|
||||
|
||||
void ShadowRenderer::xgkick(u16 imm) {
|
||||
u32 ind_of_fan_start = UINT32_MAX;
|
||||
bool fan_running = false;
|
||||
const u8* data = (const u8*)(m_vu_data + imm);
|
||||
|
||||
u8 rgba[4] = {1, 2, 3, 4};
|
||||
|
||||
bool eop = false;
|
||||
|
||||
u32 offset = 0;
|
||||
while (!eop) {
|
||||
GifTag tag(data + offset);
|
||||
offset += 16;
|
||||
|
||||
// unpack registers.
|
||||
// faster to do it once outside of the nloop loop.
|
||||
GifTag::RegisterDescriptor reg_desc[16];
|
||||
u32 nreg = tag.nreg();
|
||||
for (u32 i = 0; i < nreg; i++) {
|
||||
reg_desc[i] = tag.reg(i);
|
||||
}
|
||||
|
||||
auto format = tag.flg();
|
||||
if (format == GifTag::Format::PACKED) {
|
||||
if (tag.pre()) {
|
||||
GsPrim prim(tag.prim());
|
||||
ASSERT(prim.kind() == GsPrim::Kind::TRI_FAN);
|
||||
}
|
||||
for (u32 loop = 0; loop < tag.nloop(); loop++) {
|
||||
for (u32 reg = 0; reg < nreg; reg++) {
|
||||
switch (reg_desc[reg]) {
|
||||
case GifTag::RegisterDescriptor::AD: {
|
||||
u64 value;
|
||||
GsRegisterAddress addr;
|
||||
memcpy(&value, data + offset, sizeof(u64));
|
||||
memcpy(&addr, data + offset + 8, sizeof(GsRegisterAddress));
|
||||
|
||||
switch (addr) {
|
||||
case GsRegisterAddress::TEXFLUSH:
|
||||
break;
|
||||
case GsRegisterAddress::RGBAQ: {
|
||||
rgba[0] = data[0 + offset];
|
||||
rgba[1] = data[1 + offset];
|
||||
rgba[2] = data[2 + offset];
|
||||
rgba[3] = data[3 + offset];
|
||||
float Q;
|
||||
memcpy(&Q, data + offset + 4, 4);
|
||||
// fmt::print("rgba: {} {} {} {}: {}\n", rgba[0], rgba[1], rgba[2], rgba[3], Q);
|
||||
} break;
|
||||
default:
|
||||
fmt::print("Address {} is not supported\n", register_address_name(addr));
|
||||
ASSERT(false);
|
||||
}
|
||||
} break;
|
||||
case GifTag::RegisterDescriptor::ST: {
|
||||
float s, t;
|
||||
memcpy(&s, data + offset, 4);
|
||||
memcpy(&t, data + offset + 4, 4);
|
||||
// fmt::print("st: {} {}\n", s, t);
|
||||
} break;
|
||||
case GifTag::RegisterDescriptor::RGBAQ:
|
||||
for (int i = 0; i < 4; i++) {
|
||||
rgba[i] = data[offset + i * 4];
|
||||
}
|
||||
// fmt::print("rgbap: {} {} {} {}\n", rgba[0], rgba[1], rgba[2], rgba[3]);
|
||||
break;
|
||||
case GifTag::RegisterDescriptor::XYZF2:
|
||||
// handle_xyzf2_packed(data + offset, render_state, prof);
|
||||
{
|
||||
u32 x, y;
|
||||
memcpy(&x, data + offset, 4);
|
||||
memcpy(&y, data + offset + 4, 4);
|
||||
|
||||
u64 upper;
|
||||
memcpy(&upper, data + offset + 8, 8);
|
||||
u32 z = (upper >> 4) & 0xffffff;
|
||||
|
||||
x <<= 16;
|
||||
y <<= 16;
|
||||
z <<= 8;
|
||||
u32 vidx = m_next_vertex++;
|
||||
auto& v = m_vertices[vidx];
|
||||
ASSERT(m_next_vertex < MAX_VERTICES);
|
||||
v.xyz[0] = (float)x / (float)UINT32_MAX;
|
||||
v.xyz[1] = (float)y / (float)UINT32_MAX;
|
||||
v.xyz[2] = (float)z / (float)UINT32_MAX;
|
||||
|
||||
if (ind_of_fan_start == UINT32_MAX) {
|
||||
ind_of_fan_start = vidx;
|
||||
} else {
|
||||
if (fan_running) {
|
||||
// todo, actually use triangle fans in opengl...
|
||||
if (rgba[0] > 0) {
|
||||
// back
|
||||
m_back_indices[m_next_back_index++] = vidx;
|
||||
m_back_indices[m_next_back_index++] = vidx - 1;
|
||||
m_back_indices[m_next_back_index++] = ind_of_fan_start;
|
||||
} else {
|
||||
m_front_indices[m_next_front_index++] = vidx;
|
||||
m_front_indices[m_next_front_index++] = vidx - 1;
|
||||
m_front_indices[m_next_front_index++] = ind_of_fan_start;
|
||||
}
|
||||
} else {
|
||||
fan_running = true;
|
||||
}
|
||||
}
|
||||
|
||||
// fmt::print("xyzfadc: {} {} {} {} {}\n", x, y, z, f, adc);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fmt::print("Register {} is not supported in packed mode yet\n",
|
||||
reg_descriptor_name(reg_desc[reg]));
|
||||
ASSERT(false);
|
||||
}
|
||||
offset += 16; // PACKED = quadwords
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ASSERT(false); // format not packed or reglist.
|
||||
}
|
||||
|
||||
eop = tag.eop();
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowRenderer::render(DmaFollower& dma,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& /*prof*/) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
ScopedProfilerNode& prof) {
|
||||
if (!m_enabled) {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_next_vertex = 0;
|
||||
m_next_back_index = 0;
|
||||
m_next_front_index = 0;
|
||||
|
||||
// jump to bucket
|
||||
auto data0 = dma.read_and_advance();
|
||||
ASSERT(data0.vif1() == 0);
|
||||
ASSERT(data0.vif0() == 0);
|
||||
ASSERT(data0.size_bytes == 0);
|
||||
|
||||
// see if bucket is empty or not
|
||||
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
|
||||
// renderer didn't run, let's just get out of here.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// constants
|
||||
auto constants = dma.read_and_advance();
|
||||
auto v0 = constants.vifcode0();
|
||||
auto v1 = constants.vifcode1();
|
||||
ASSERT(v0.kind == VifCode::Kind::STCYCL);
|
||||
ASSERT(v0.immediate == 0x404);
|
||||
ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32);
|
||||
ASSERT(v1.immediate == Vu1Data::CONSTANTS);
|
||||
ASSERT(v1.num == 13);
|
||||
memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16);
|
||||
}
|
||||
|
||||
{
|
||||
// gif constants
|
||||
auto constants = dma.read_and_advance();
|
||||
auto v0 = constants.vifcode0();
|
||||
auto v1 = constants.vifcode1();
|
||||
ASSERT(v0.kind == VifCode::Kind::STCYCL);
|
||||
ASSERT(v0.immediate == 0x404);
|
||||
ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32);
|
||||
ASSERT(v1.immediate == Vu1Data::GIF_CONSTANTS);
|
||||
ASSERT(v1.num == 4);
|
||||
memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16);
|
||||
}
|
||||
|
||||
{
|
||||
// matrix constants
|
||||
auto constants = dma.read_and_advance();
|
||||
auto v0 = constants.vifcode0();
|
||||
auto v1 = constants.vifcode1();
|
||||
ASSERT(v0.kind == VifCode::Kind::STCYCL);
|
||||
ASSERT(v0.immediate == 0x404);
|
||||
ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32);
|
||||
ASSERT(v1.immediate == Vu1Data::MATRIX);
|
||||
ASSERT(v1.num == 4);
|
||||
memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16);
|
||||
}
|
||||
|
||||
{
|
||||
// exec 10
|
||||
auto mscal = dma.read_and_advance();
|
||||
ASSERT(mscal.vifcode1().kind == VifCode::Kind::FLUSHE);
|
||||
ASSERT(mscal.vifcode0().kind == VifCode::Kind::MSCALF);
|
||||
ASSERT(mscal.vifcode0().immediate == Vu1Code::INIT);
|
||||
run_mscal10_vu2c();
|
||||
}
|
||||
|
||||
{
|
||||
// init gs direct
|
||||
dma.read_and_advance();
|
||||
}
|
||||
|
||||
while (dma.current_tag().kind != DmaTag::Kind::CALL) {
|
||||
auto next = dma.read_and_advance();
|
||||
auto v1 = next.vifcode1();
|
||||
if (next.vifcode0().kind == VifCode::Kind::FLUSHA &&
|
||||
next.vifcode1().kind == VifCode::Kind::UNPACK_V4_32) {
|
||||
auto up = next.vifcode1();
|
||||
VifCodeUnpack unpack(up);
|
||||
ASSERT(!unpack.use_tops_flag);
|
||||
ASSERT((u32)unpack.addr_qw + up.num < 1024);
|
||||
memcpy(m_vu_data + unpack.addr_qw, next.data, up.num * 16);
|
||||
ASSERT(up.num * 16 == next.size_bytes);
|
||||
} else if (next.vifcode0().kind == VifCode::Kind::NOP &&
|
||||
next.vifcode1().kind == VifCode::Kind::UNPACK_V4_32) {
|
||||
auto up = next.vifcode1();
|
||||
VifCodeUnpack unpack(up);
|
||||
ASSERT(!unpack.use_tops_flag);
|
||||
ASSERT((u32)unpack.addr_qw + up.num < 1024);
|
||||
memcpy(m_vu_data + unpack.addr_qw, next.data, up.num * 16);
|
||||
ASSERT(up.num * 16 == next.size_bytes);
|
||||
} else if (next.vifcode0().kind == VifCode::Kind::NOP &&
|
||||
next.vifcode1().kind == VifCode::Kind::UNPACK_V4_8) {
|
||||
auto up = VifCodeUnpack(v1);
|
||||
ASSERT(!up.use_tops_flag);
|
||||
ASSERT(up.is_unsigned);
|
||||
u16 addr = up.addr_qw;
|
||||
ASSERT(addr + v1.num <= 1024);
|
||||
|
||||
u32 temp[4];
|
||||
for (u32 i = 0; i < v1.num; i++) {
|
||||
for (u32 j = 0; j < 4; j++) {
|
||||
temp[j] = next.data[4 * i + j];
|
||||
}
|
||||
memcpy(m_vu_data + addr + i, temp, 16);
|
||||
}
|
||||
|
||||
u32 offset = 4 * v1.num;
|
||||
ASSERT(offset + 16 == next.size_bytes);
|
||||
|
||||
u32 after[4];
|
||||
memcpy(&after, next.data + offset, 16);
|
||||
ASSERT(after[0] == 0);
|
||||
ASSERT(after[1] == 0);
|
||||
ASSERT(after[2] == 0);
|
||||
VifCode mscal(after[3]);
|
||||
ASSERT(mscal.kind == VifCode::Kind::MSCALF);
|
||||
run_mscal_vu2c(mscal.immediate);
|
||||
} else if (next.vifcode0().kind == VifCode::Kind::FLUSHA &&
|
||||
next.vifcode1().kind == VifCode::Kind::DIRECT) {
|
||||
dma.read_and_advance();
|
||||
dma.read_and_advance();
|
||||
dma.read_and_advance();
|
||||
|
||||
} else {
|
||||
fmt::print("{} {}\n", next.vifcode0().print(), next.vifcode1().print());
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dma.read_and_advance();
|
||||
}
|
||||
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
||||
|
||||
draw(render_state, prof);
|
||||
}
|
||||
|
||||
void ShadowRenderer::draw(SharedRenderState* render_state, ScopedProfilerNode& prof) {
|
||||
// enable stencil!
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilMask(0xFF);
|
||||
|
||||
u32 clear_vertices = m_next_vertex;
|
||||
m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.3, 0.3, 0), 0};
|
||||
m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.3, 0.7, 0), 0};
|
||||
m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.7, 0.3, 0), 0};
|
||||
m_vertices[m_next_vertex++] = Vertex{math::Vector3f(0.7, 0.7, 0), 0};
|
||||
m_front_indices[m_next_front_index++] = clear_vertices;
|
||||
m_front_indices[m_next_front_index++] = clear_vertices + 1;
|
||||
m_front_indices[m_next_front_index++] = clear_vertices + 2;
|
||||
m_front_indices[m_next_front_index++] = clear_vertices + 3;
|
||||
m_front_indices[m_next_front_index++] = clear_vertices + 2;
|
||||
m_front_indices[m_next_front_index++] = clear_vertices + 1;
|
||||
|
||||
glBindVertexArray(m_ogl.vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, m_next_vertex * sizeof(Vertex), m_vertices, GL_STREAM_DRAW);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthFunc(GL_GEQUAL);
|
||||
|
||||
render_state->shaders.at(ShaderId::SHADOW).activate();
|
||||
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"),
|
||||
0., 0.4, 0., 0.5);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[1]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_back_index * sizeof(u32), m_back_indices,
|
||||
GL_STREAM_DRAW);
|
||||
|
||||
// First pass.
|
||||
// here, we don't write depth or color.
|
||||
// but we increment stencil on depth fail.
|
||||
|
||||
glDepthMask(GL_FALSE); // no depth writes.
|
||||
if (m_debug_draw_volume) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
|
||||
} else {
|
||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color writes.
|
||||
}
|
||||
glStencilFunc(GL_ALWAYS, 0, 0); // always pass stencil
|
||||
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP); // increment on depth fail.
|
||||
glDrawElements(GL_TRIANGLES, m_next_back_index, GL_UNSIGNED_INT, nullptr);
|
||||
|
||||
if (m_debug_draw_volume) {
|
||||
glDisable(GL_BLEND);
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"),
|
||||
0., 0.0, 0., 0.5);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glDrawElements(GL_TRIANGLES, m_next_back_index, GL_UNSIGNED_INT, nullptr);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(m_next_back_index / 3);
|
||||
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"),
|
||||
0.4, 0.0, 0., 0.5);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[0]);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_front_index * sizeof(u32), m_front_indices,
|
||||
GL_STREAM_DRAW);
|
||||
// Second pass.
|
||||
// same settings, but decrement.
|
||||
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); // decrement on depth fail.
|
||||
glDrawElements(GL_TRIANGLES, (m_next_front_index - 6), GL_UNSIGNED_INT, nullptr);
|
||||
if (m_debug_draw_volume) {
|
||||
glDisable(GL_BLEND);
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"),
|
||||
0., 0.0, 0., 0.5);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
glDrawElements(GL_TRIANGLES, (m_next_front_index - 6), GL_UNSIGNED_INT, nullptr);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(m_next_front_index / 3);
|
||||
|
||||
// finally, draw shadow.
|
||||
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::SHADOW].id(), "color_uniform"),
|
||||
0.13, 0.13, 0.13, 0.5);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
// glStencilFunc(GL_GREATER, 0, 0);
|
||||
glStencilFunc(GL_NOTEQUAL, 0, 0xFF);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ONE, GL_ZERO);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)(sizeof(u32) * (m_next_front_index - 6)));
|
||||
prof.add_draw_call();
|
||||
prof.add_tri(2);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
@@ -1,14 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "game/graphics/opengl_renderer/BucketRenderer.h"
|
||||
#include "game/graphics/opengl_renderer/DirectRenderer.h"
|
||||
|
||||
#include "game/common/vu.h"
|
||||
|
||||
class ShadowRenderer : public BucketRenderer {
|
||||
public:
|
||||
ShadowRenderer(const std::string& name, BucketId my_id);
|
||||
~ShadowRenderer();
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
|
||||
private:
|
||||
DirectRenderer m_direct;
|
||||
void run_mscal_vu2c(u16 imm);
|
||||
void xgkick(u16 imm);
|
||||
void run_mscal10_vu2c();
|
||||
void handle_jalr_to_end_block(u16 val, u32& first_flag, u32& second_flag);
|
||||
void handle_bal52();
|
||||
void draw(SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
|
||||
Vf m_vu_data[1024];
|
||||
|
||||
enum Vu1Data {
|
||||
MATRIX = 0,
|
||||
CONSTANTS = 0x370,
|
||||
GIF_CONSTANTS = 0x3ac,
|
||||
};
|
||||
|
||||
enum Vu1Code {
|
||||
INIT = 10,
|
||||
};
|
||||
|
||||
void lq_buffer(Mask mask, Vf& dest, u16 addr) {
|
||||
ASSERT(addr < 1024);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
dest[i] = m_vu_data[addr].data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sq_buffer(Mask mask, const Vf& val, u16 addr) {
|
||||
ASSERT(addr < 1024);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((u64)mask & (1 << i)) {
|
||||
m_vu_data[addr].data[i] = val[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ilw_buffer(Mask mask, u16& dest, u16 addr) {
|
||||
ASSERT(addr < 1024);
|
||||
switch (mask) {
|
||||
case Mask::x:
|
||||
dest = m_vu_data[addr].x_as_u16();
|
||||
break;
|
||||
case Mask::y:
|
||||
dest = m_vu_data[addr].y_as_u16();
|
||||
break;
|
||||
case Mask::z:
|
||||
dest = m_vu_data[addr].z_as_u16();
|
||||
break;
|
||||
case Mask::w:
|
||||
dest = m_vu_data[addr].w_as_u16();
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
void isw_buffer(Mask mask, u16 src, u16 addr) {
|
||||
ASSERT(addr < 1024);
|
||||
u32 val32 = src;
|
||||
switch (mask) {
|
||||
case Mask::x:
|
||||
memcpy(&m_vu_data[addr].data[0], &val32, 4);
|
||||
break;
|
||||
case Mask::y:
|
||||
memcpy(&m_vu_data[addr].data[1], &val32, 4);
|
||||
break;
|
||||
case Mask::z:
|
||||
memcpy(&m_vu_data[addr].data[2], &val32, 4);
|
||||
break;
|
||||
case Mask::w:
|
||||
memcpy(&m_vu_data[addr].data[3], &val32, 4);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
struct Vu {
|
||||
const Vf vf00;
|
||||
Vu() : vf00(0, 0, 0, 1) {}
|
||||
|
||||
u16 vi01, vi02, vi03, vi04, vi05, vi06, vi07, vi08, vi09, vi10, vi12, vi15;
|
||||
Vf vf01, vf02, vf03, vf04, vf05, vf06, vf07, vf08, vf09, vf10, vf11, vf12, vf13, vf14, vf15,
|
||||
vf16, vf17, vf18, vf19, vf20, vf21, vf22, vf23, vf24, vf25, vf26, vf27, vf28, vf29, vf30,
|
||||
vf31;
|
||||
Accumulator acc;
|
||||
float Q;
|
||||
const u16 vi00 = 0;
|
||||
} vu;
|
||||
|
||||
struct Vertex {
|
||||
math::Vector3f xyz;
|
||||
u32 flag; // 1 if front face, 0 otherwise
|
||||
};
|
||||
static_assert(sizeof(Vertex) == 16);
|
||||
|
||||
static constexpr int MAX_VERTICES = 8192;
|
||||
static constexpr int MAX_INDICES = 8192;
|
||||
|
||||
Vertex m_vertices[MAX_VERTICES];
|
||||
u32 m_front_indices[MAX_INDICES];
|
||||
u32 m_back_indices[MAX_INDICES];
|
||||
|
||||
u32 m_next_vertex = 0;
|
||||
u32 m_next_front_index = 0;
|
||||
u32 m_next_back_index = 0;
|
||||
|
||||
struct {
|
||||
// index is front, back
|
||||
GLuint vertex_buffer, index_buffer[2], vao;
|
||||
} m_ogl;
|
||||
|
||||
bool m_debug_draw_volume = false;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
#version 430 core
|
||||
|
||||
out vec4 color;
|
||||
uniform vec4 color_uniform;
|
||||
|
||||
void main() {
|
||||
color = color_uniform;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#version 430 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
|
||||
void main() {
|
||||
// Note: position.y is multiplied by 32 instead of 16 to undo the half-height for interlacing stuff.
|
||||
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z * 2 - 1., 1.0);
|
||||
// scissoring area adjust
|
||||
gl_Position.y *= 512.0/448.0;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void exec_0(ExecutionContext* c) {
|
||||
}
|
||||
|
||||
void exec_28(ExecutionContext* c) {
|
||||
// nop | mul.xyzw vf27, vf20, Q 28
|
||||
// nop | mul.xyzw vf27, vf20, Q 28
|
||||
c->vfs[vf27].vf.mul(Mask::xyzw, c->vf_src(vf20).vf, c->Q);
|
||||
// div Q, vf13.x, vf17.x | sub.xyzw vf19, vf01, vf03 29
|
||||
c->vfs[vf19].vf.sub(Mask::xyzw, c->vf_src(vf01).vf, c->vf_src(vf03).vf); c->Q = c->vfs[vf13].vf.x() / c->vfs[vf17].vf.x();
|
||||
@@ -81,9 +81,10 @@ void exec_28(ExecutionContext* c) {
|
||||
// nop | mul.xyz vf15, vf19, vf02 35
|
||||
c->vfs[vf15].vf.mul(Mask::xyz, c->vf_src(vf19).vf, c->vf_src(vf02).vf);
|
||||
// div Q, vf14.x, vf18.x | mul.xyzw vf12, vf04, vf02 36
|
||||
float oldQ = c->Q;
|
||||
c->vfs[vf12].vf.mul(Mask::xyzw, c->vf_src(vf04).vf, c->vf_src(vf02).vf); c->Q = c->vfs[vf14].vf.x() / c->vfs[vf18].vf.x();
|
||||
// move.xyzw vf07, vf03 | mul.xyzw vf28, vf28, Q 37
|
||||
c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, c->Q); c->vfs[vf07].vf.move(Mask::xyzw, c->vf_src(vf03).vf);
|
||||
c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, oldQ); c->vfs[vf07].vf.move(Mask::xyzw, c->vf_src(vf03).vf);
|
||||
// move.xyzw vf08, vf04 | mul.xyz vf16, vf20, vf02 38
|
||||
c->vfs[vf16].vf.mul(Mask::xyz, c->vf_src(vf20).vf, c->vf_src(vf02).vf); c->vfs[vf08].vf.move(Mask::xyzw, c->vf_src(vf04).vf);
|
||||
// move.xyzw vf09, vf05 | addy.x vf11, vf11, vf11 39
|
||||
@@ -111,37 +112,51 @@ void exec_28(ExecutionContext* c) {
|
||||
// nop | addw.x vf11, vf11, vf11 50
|
||||
c->vfs[vf11].vf.add(Mask::x, c->vf_src(vf11).vf, c->vf_src(vf11).vf.w());
|
||||
// nop | mul.xyzw vf13, vf09, vf02 51
|
||||
|
||||
c->vfs[vf13].vf.mul(Mask::xyzw, c->vf_src(vf09).vf, c->vf_src(vf02).vf);
|
||||
c->vfs[vf13].vf.saturate_infs();
|
||||
|
||||
// nop | addw.x vf12, vf12, vf12 52
|
||||
c->vfs[vf12].vf.add(Mask::x, c->vf_src(vf12).vf, c->vf_src(vf12).vf.w());
|
||||
// nop | mul.xyz vf17, vf21, vf02 53
|
||||
c->vfs[vf17].vf.mul(Mask::xyz, c->vf_src(vf21).vf, c->vf_src(vf02).vf);
|
||||
// nop | mul.xyzw vf14, vf10, vf02 54
|
||||
c->vfs[vf14].vf.mul(Mask::xyzw, c->vf_src(vf10).vf, c->vf_src(vf02).vf);
|
||||
c->vfs[vf14].vf.saturate_infs();
|
||||
|
||||
// div Q, vf11.x, vf15.x | mul.xyz vf18, vf22, vf02 55
|
||||
c->vfs[vf18].vf.mul(Mask::xyz, c->vf_src(vf22).vf, c->vf_src(vf02).vf); c->Q = c->vfs[vf11].vf.x() / c->vfs[vf15].vf.x();
|
||||
// nop | addy.x vf13, vf13, vf13 56
|
||||
c->vfs[vf13].vf.add(Mask::x, c->vf_src(vf13).vf, c->vf_src(vf13).vf.y());
|
||||
|
||||
// nop | addy.x vf17, vf17, vf17 57
|
||||
c->vfs[vf17].vf.add(Mask::x, c->vf_src(vf17).vf, c->vf_src(vf17).vf.y());
|
||||
// nop | addy.x vf14, vf14, vf14 58
|
||||
c->vfs[vf14].vf.add(Mask::x, c->vf_src(vf14).vf, c->vf_src(vf14).vf.y());
|
||||
|
||||
// nop | addy.x vf18, vf18, vf18 59
|
||||
c->vfs[vf18].vf.add(Mask::x, c->vf_src(vf18).vf, c->vf_src(vf18).vf.y());
|
||||
// nop | addz.x vf13, vf13, vf13 60
|
||||
c->vfs[vf13].vf.add(Mask::x, c->vf_src(vf13).vf, c->vf_src(vf13).vf.z());
|
||||
|
||||
// nop | addz.x vf17, vf17, vf17 61
|
||||
c->vfs[vf17].vf.add(Mask::x, c->vf_src(vf17).vf, c->vf_src(vf17).vf.z());
|
||||
// div Q, vf12.x, vf16.x | addz.x vf14, vf14, vf14 62
|
||||
oldQ = c->Q;
|
||||
c->vfs[vf14].vf.add(Mask::x, c->vf_src(vf14).vf, c->vf_src(vf14).vf.z()); c->Q = c->vfs[vf12].vf.x() / c->vfs[vf16].vf.x();
|
||||
|
||||
// nop | mul.xyzw vf19, vf19, Q 63
|
||||
c->vfs[vf19].vf.mul(Mask::xyzw, c->vf_src(vf19).vf, c->Q);
|
||||
c->vfs[vf19].vf.mul(Mask::xyzw, c->vf_src(vf19).vf, oldQ);
|
||||
// move.xyzw vf28, vf21 | addz.x vf18, vf18, vf18 64
|
||||
c->vfs[vf18].vf.add(Mask::x, c->vf_src(vf18).vf, c->vf_src(vf18).vf.z()); c->vfs[vf28].vf.move(Mask::xyzw, c->vf_src(vf21).vf);
|
||||
// move.xyzw vf29, vf22 | addw.x vf13, vf13, vf13 65
|
||||
c->vfs[vf13].vf.add(Mask::x, c->vf_src(vf13).vf, c->vf_src(vf13).vf.w()); c->vfs[vf29].vf.move(Mask::xyzw, c->vf_src(vf22).vf);
|
||||
c->vfs[vf13].vf.saturate_infs();
|
||||
|
||||
// nop | addw.x vf14, vf14, vf14 :e 66
|
||||
c->vfs[vf14].vf.add(Mask::x, c->vf_src(vf14).vf, c->vf_src(vf14).vf.w());
|
||||
c->vfs[vf14].vf.saturate_infs();
|
||||
|
||||
// nop | sub.xyzw vf07, vf07, vf19 67
|
||||
c->vfs[vf07].vf.sub(Mask::xyzw, c->vf_src(vf07).vf, c->vf_src(vf19).vf);
|
||||
}
|
||||
@@ -164,9 +179,10 @@ void exec_68(ExecutionContext* c) {
|
||||
// nop | nop 75
|
||||
|
||||
// div Q, vf14.x, vf18.x | nop 76
|
||||
float oldQ = c->Q;
|
||||
c->Q = c->vfs[vf14].vf.x() / c->vfs[vf18].vf.x();
|
||||
// nop | mul.xyzw vf28, vf28, Q 77
|
||||
c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, c->Q);
|
||||
c->vfs[vf28].vf.mul(Mask::xyzw, c->vf_src(vf28).vf, oldQ);
|
||||
// nop | nop 78
|
||||
|
||||
// nop | nop 79
|
||||
@@ -174,7 +190,7 @@ void exec_68(ExecutionContext* c) {
|
||||
// nop | nop 80
|
||||
|
||||
// nop | sub.xyzw vf25, vf25, vf28 81
|
||||
c->vfs[vf25].vf.sub(Mask::xyzw, c->vf_src(vf25).vf, c->vf_src(vf28).vf);
|
||||
c->vfs[vf25].vf.sub(Mask::xyzw, c->vf_src(vf25).vf, c->vf_src(vf28).vf); // was bad
|
||||
// nop | nop 82
|
||||
|
||||
// nop | mul.xyzw vf29, vf29, Q 83
|
||||
@@ -324,6 +340,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->sqc2(vf9, 0, a2); // sqc2 vf9, 0(a2)
|
||||
|
||||
c->daddiu(a2, a2, 16); // daddiu a2, a2, 16
|
||||
// nop // sll r0, r0, 0
|
||||
bc = c->sgpr64(a0) != 0; // bne a0, r0, L101
|
||||
@@ -398,6 +415,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
c->mov128_vf_gpr(vf6, t2); // qmtc2.ni vf6, t2
|
||||
exec_28(c);// Unknown instr: vcallms 28
|
||||
|
||||
// nop // sll r0, r0, 0
|
||||
c->daddiu(a0, a0, -4); // daddiu a0, a0, -4
|
||||
c->lq(a3, 0, a2); // lq a3, 0(a2)
|
||||
@@ -430,7 +448,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->mov128_gpr_vf(a3, vf23); // qmfc2.i a3, vf23
|
||||
c->mov128_gpr_vf(a3, vf23); // qmfc2.i a3, vf23 // 39
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -438,11 +456,11 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->sq(a3, 0, v1); // sq a3, 0(v1)
|
||||
c->sq(a3, 0, v1); // sq a3, 0(v1) // 47
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->mov128_gpr_vf(a3, vf24); // qmfc2.ni a3, vf24
|
||||
c->mov128_gpr_vf(a3, vf24); // qmfc2.ni a3, vf24 // 51
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -450,7 +468,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->sq(a3, 16, v1); // sq a3, 16(v1)
|
||||
c->sq(a3, 16, v1); // sq a3, 16(v1) // 59
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -458,7 +476,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->mov128_gpr_vf(a3, vf25); // qmfc2.ni a3, vf25
|
||||
c->mov128_gpr_vf(a3, vf25); // qmfc2.ni a3, vf25 // 67
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -466,7 +484,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->sq(a3, 32, v1); // sq a3, 32(v1)
|
||||
c->sq(a3, 32, v1); // sq a3, 32(v1) // 75
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -474,7 +492,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->mov128_gpr_vf(a3, vf26); // qmfc2.ni a3, vf26
|
||||
c->mov128_gpr_vf(a3, vf26); // qmfc2.ni a3, vf26 // 83
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -482,7 +500,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
c->sq(a3, 48, v1); // sq a3, 48(v1)
|
||||
c->sq(a3, 48, v1); // sq a3, 48(v1) // 91
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -505,7 +523,6 @@ u64 execute(void* ctxt) {
|
||||
c->mov128_vf_gpr(vf6, t2); // qmtc2.ni vf6, t2
|
||||
if (bc) {goto block_3;} // branch non-likely
|
||||
|
||||
|
||||
block_4:
|
||||
exec_68(c);// Unknown instr: vcallms 68
|
||||
// nop // sll r0, r0, 0
|
||||
@@ -637,7 +654,7 @@ u64 execute(void* ctxt) {
|
||||
// nop // vnop
|
||||
c->vadd(DEST::xyzw, vf1, vf1, vf4); // vadd.xyzw vf1, vf1, vf4
|
||||
//beq r0, r0, L91 // beq r0, r0, L91
|
||||
c->sqc2(vf1, 0, a0); // sqc2 vf1, 0(a0)
|
||||
c->sqc2(vf1, 0, a0); // sqc2 vf1, 0(a0) was bad
|
||||
goto block_7; // branch always
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "game/mips2c/mips2c_table.h"
|
||||
|
||||
Reference in New Issue
Block a user