Skip to content

Commit

Permalink
use common ocean renderer for mid too (#1241)
Browse files Browse the repository at this point in the history
  • Loading branch information
water111 authored Mar 19, 2022
1 parent da00b1f commit 4445975
Show file tree
Hide file tree
Showing 13 changed files with 416 additions and 223 deletions.
11 changes: 10 additions & 1 deletion decompiler/config/jak1_ntsc_black_label/type_casts.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4010,7 +4010,16 @@
[249, "a0", "(pointer gs-reg64)"],
[251, "a0", "(pointer gs-alpha)"],
[253, "a0", "(pointer gs-reg64)"],
[[270, 273], "v1", "dma-packet"]
[[270, 273], "v1", "dma-packet"],
[[312, 316], "a0", "dma-packet"],
[[322, 325], "a0", "gs-gif-tag"],
[330, "a0", "(pointer gs-zbuf)"],
[332, "a0", "(pointer gs-reg)"],
[334, "a0", "(pointer gs-test)"],
[336, "a0", "(pointer gs-reg64)"],
[338, "a0", "(pointer gs-alpha)"],
[340, "a0", "(pointer gs-reg64)"],
[[357, 360], "v1", "dma-packet"]
],

"(event target-racing-start)": [
Expand Down
189 changes: 188 additions & 1 deletion game/graphics/opengl_renderer/ocean/CommonOceanRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ void CommonOceanRenderer::handle_near_adgif(const u8* data, u32 offset, u32 coun
}
}

void CommonOceanRenderer::flush(SharedRenderState* render_state, ScopedProfilerNode& prof) {
void CommonOceanRenderer::flush_near(SharedRenderState* render_state, ScopedProfilerNode& prof) {
glBindVertexArray(m_ogl.vao);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
glEnable(GL_PRIMITIVE_RESTART);
Expand Down Expand Up @@ -334,4 +334,191 @@ void CommonOceanRenderer::flush(SharedRenderState* render_state, ScopedProfilerN
prof.add_draw_call();
prof.add_tri(m_next_free_index[bucket]);
}
}

void CommonOceanRenderer::kick_from_mid(const u8* data) {
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.nreg() == 1) {
ASSERT(!tag.pre());
ASSERT(tag.nloop() == 5);
handle_mid_adgif(data, offset);
offset += 5 * 16;
} else {
ASSERT(tag.nreg() == 3);
ASSERT(tag.pre());
m_current_bucket = GsPrim(tag.prim()).abe() ? 1 : 0;

int count = tag.nloop();
if (GsPrim(tag.prim()).kind() == GsPrim::Kind::TRI_STRIP) {
handle_near_vertex_gif_data_strip(data, offset, tag.nloop());
} else {
handle_near_vertex_gif_data_fan(data, offset, tag.nloop());
}
offset += 3 * 16 * count;
// todo handle.
}
} else {
ASSERT(false); // format not packed or reglist.
}

eop = tag.eop();
}
}

void CommonOceanRenderer::handle_mid_adgif(const u8* data, u32 offset) {
u32 most_recent_tbp = 0;

for (u32 i = 0; i < 5; i++) {
u64 value;
GsRegisterAddress addr;
memcpy(&value, data + offset + 16 * i, sizeof(u64));
memcpy(&addr, data + offset + 16 * i + 8, sizeof(GsRegisterAddress));
switch (addr) {
case GsRegisterAddress::MIPTBP1_1:
case GsRegisterAddress::MIPTBP2_1:
// ignore this, it's just mipmapping settings
break;
case GsRegisterAddress::TEX1_1: {
GsTex1 reg(value);
ASSERT(reg.mmag());
} break;
case GsRegisterAddress::CLAMP_1: {
bool s = value & 0b001;
bool t = value & 0b100;
ASSERT(s == t);
} break;
case GsRegisterAddress::TEX0_1: {
GsTex0 reg(value);
ASSERT(reg.tfx() == GsTex0::TextureFunction::MODULATE);
most_recent_tbp = reg.tbp0();
} break;
case GsRegisterAddress::ALPHA_1: {
} break;

default:
fmt::print("reg: {}\n", register_address_name(addr));
break;
}
}

if (most_recent_tbp != 8160) {
m_envmap_tex = most_recent_tbp;
}

if (m_vertices.size() - 128 < m_next_free_vertex) {
ASSERT(false); // add more vertices.
}
}

void CommonOceanRenderer::init_for_mid() {
m_next_free_vertex = 0;
for (auto& x : m_next_free_index) {
x = 0;
}
}

void reverse_indices(u32* indices, u32 count) {
if (count) {
for (u32 a = 0, b = count - 1; a < b; a++, b--) {
std::swap(indices[a], indices[b]);
}
}
}

void CommonOceanRenderer::flush_mid(SharedRenderState* render_state, ScopedProfilerNode& prof) {
glBindVertexArray(m_ogl.vao);
glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(UINT32_MAX);
glBufferData(GL_ARRAY_BUFFER, m_next_free_vertex * sizeof(Vertex), m_vertices.data(),
GL_STREAM_DRAW);
render_state->shaders[ShaderId::OCEAN_COMMON].activate();
glUniform4f(glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_COMMON].id(), "fog_color"),
render_state->fog_color[0], render_state->fog_color[1], render_state->fog_color[2],
render_state->fog_intensity);

glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glDisable(GL_BLEND);

// note:
// there are some places where the game draws the same section of ocean twice, in this order:
// - low poly mesh with ocean texture
// - low poly mesh with envmap texture
// - high poly mesh with ocean texture (overwrites previous draw)
// - high poly mesh with envmap texture (overwrites previous draw)

// we draw all ocean textures together and all envmap textures togther. luckily, there's a trick
// we can use to get the same result.
// first, we'll draw all ocean textures. The high poly mesh is drawn second, so it wins.
// then, we'll draw all envmaps, but with two changes:
// - first, we draw it in reverse, so the high poly versions are drawn first
// - second, we'll modify the shader to set alpha = 0 of the destination. when the low poly
// version is drawn on top, it won't draw at all because of the blending mode
// (s_factor = DST_ALPHA, d_factor = 1)

// draw it in reverse
reverse_indices(m_indices[1].data(), m_next_free_index[1]);

for (int bucket = 0; bucket < 2; bucket++) {
switch (bucket) {
case 0: {
auto tex = render_state->texture_pool->lookup(8160);
if (!tex) {
tex = render_state->texture_pool->get_placeholder_texture();
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glUniform1i(
glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_COMMON].id(), "tex_T0"), 0);
glUniform1i(
glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_COMMON].id(), "bucket"), 3);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

break;
case 1:
glEnable(GL_BLEND);
auto tex = render_state->texture_pool->lookup(m_envmap_tex);
if (!tex) {
tex = render_state->texture_pool->get_placeholder_texture();
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, *tex);

glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ONE, GL_ZERO);
glBlendEquation(GL_FUNC_ADD);
glUniform1i(
glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_COMMON].id(), "bucket"), 4);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
break;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer[bucket]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_next_free_index[bucket] * sizeof(u32),
m_indices[bucket].data(), GL_STREAM_DRAW);
glDrawElements(GL_TRIANGLE_STRIP, m_next_free_index[bucket], GL_UNSIGNED_INT, nullptr);
prof.add_draw_call();
prof.add_tri(m_next_free_index[bucket]);
}
}
8 changes: 7 additions & 1 deletion game/graphics/opengl_renderer/ocean/CommonOceanRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ class CommonOceanRenderer {

void init_for_near();
void kick_from_near(const u8* data);
void flush(SharedRenderState* render_state, ScopedProfilerNode& prof);
void flush_near(SharedRenderState* render_state, ScopedProfilerNode& prof);

void init_for_mid();
void kick_from_mid(const u8* data);
void flush_mid(SharedRenderState* render_state, ScopedProfilerNode& prof);

private:
void handle_near_vertex_gif_data_fan(const u8* data, u32 offset, u32 loop);
void handle_near_vertex_gif_data_strip(const u8* data, u32 offset, u32 loop);

void handle_near_adgif(const u8* data, u32 offset, u32 count);

void handle_mid_adgif(const u8* data, u32 offset);

enum VertexBucket {
RGB_TEXTURE = 0,
ALPHA = 1,
Expand Down
27 changes: 12 additions & 15 deletions game/graphics/opengl_renderer/ocean/OceanMid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ OceanMid::OceanMid() {
vu.vf25 = Vf(1, 1, 1, 1);
}

void OceanMid::run(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct) {
void OceanMid::run(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) {
m_common_ocean_renderer.init_for_mid();
// first is setting base and offset
{
auto base_offset_tag = dma.read_and_advance();
Expand Down Expand Up @@ -97,26 +95,24 @@ void OceanMid::run(DmaFollower& dma,
memcpy(m_vu_data + addr + addr_off, temp, 16);
}
ASSERT(8 * v1.num == data.size_bytes);
// TODO
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::MSCALF) {
switch (v1.immediate) {
case 46:
run_call46_vu2c(render_state, prof, direct);
run_call46_vu2c();
break;
case 73:
run_call73_vu2c(render_state, prof, direct);
run_call73_vu2c();
break;
case 107:
run_call107_vu2c(render_state, prof, direct);
run_call107_vu2c();
break;
case 275:
run_call275_vu2c(render_state, prof, direct);
run_call275_vu2c();
break;
default:
fmt::print("unknown call1: {}\n", v1.immediate);
}
// TODO
} else if (v0.kind == VifCode::Kind::MSCALF && v1.kind == VifCode::Kind::FLUSHA) {
switch (v0.immediate) {
case 41:
Expand All @@ -129,17 +125,18 @@ void OceanMid::run(DmaFollower& dma,
fmt::print("unknown call2: {}\n", v0.immediate);
ASSERT(false);
}

// TODO
}

else {
} else {
fmt::print("{} {}\n", data.vifcode0().print(), data.vifcode1().print());
ASSERT(false);
}
}
m_common_ocean_renderer.flush_mid(render_state, prof);
}

void OceanMid::run_call0() {
run_call0_vu2c();
}

void OceanMid::xgkick(u16 addr) {
m_common_ocean_renderer.kick_from_mid((const u8*)&m_vu_data[addr]);
}
37 changes: 10 additions & 27 deletions game/graphics/opengl_renderer/ocean/OceanMid.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,31 @@
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "game/graphics/opengl_renderer/DirectRenderer.h"
#include "game/common/vu.h"
#include "game/graphics/opengl_renderer/ocean/CommonOceanRenderer.h"

class OceanMid {
public:
OceanMid();
void run(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);

private:
void run_call0();
void run_call0_vu2c();
void run_call41_vu2c();
void run_call43_vu2c();
void run_call46_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);

void run_call73_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_call107_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_call275_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void xgkick(u16 addr,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_call46_vu2c();
void run_call73_vu2c();
void run_call107_vu2c();
void run_call275_vu2c();
void xgkick(u16 addr);

void run_L26_vu2c();
void run_L32_vu2c();
void run_L38_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_L43_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_L38_vu2c();
void run_L43_vu2c();
void run_L45_vu2c();

CommonOceanRenderer m_common_ocean_renderer;
bool m_buffer_toggle = false;
static constexpr int VU1_INPUT_BUFFER_BASE = 0;
static constexpr int VU1_INPUT_BUFFER_OFFSET = 0x76;
Expand Down
2 changes: 1 addition & 1 deletion game/graphics/opengl_renderer/ocean/OceanMidAndFar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ void OceanMidAndFar::handle_ocean_mid(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (dma.current_tag_vifcode0().kind == VifCode::Kind::BASE) {
m_mid_renderer.run(dma, render_state, prof, m_direct);
m_mid_renderer.run(dma, render_state, prof);
} else {
// not drawing
return;
Expand Down
Loading

0 comments on commit 4445975

Please sign in to comment.