2021-10-10 20:07:03 -04:00
|
|
|
#include "SkyRenderer.h"
|
2022-06-22 23:37:46 -04:00
|
|
|
|
2021-10-10 20:07:03 -04:00
|
|
|
#include "common/log/log.h"
|
|
|
|
|
2022-06-22 23:37:46 -04:00
|
|
|
#include "game/graphics/opengl_renderer/AdgifHandler.h"
|
|
|
|
#include "game/graphics/pipelines/opengl.h"
|
|
|
|
|
|
|
|
#include "third-party/imgui/imgui.h"
|
|
|
|
|
2021-10-10 20:07:03 -04:00
|
|
|
// The sky texture system blends together sky textures from different levels and times of day
|
|
|
|
// to create the final sky texture.
|
|
|
|
|
|
|
|
// The sequence is:
|
|
|
|
// set-display-gs-state 8qw
|
|
|
|
// copy-sky-textures (between 0 and 8, usually 2.)
|
|
|
|
// copy-cloud-texture
|
|
|
|
// set alpha state
|
|
|
|
// reset display gs state
|
|
|
|
// and this happens twice: one for each level. Note that the first call to either of the copy
|
|
|
|
// functions will use "draw" mode instead of "blend"
|
|
|
|
// The results are stored in special sky textures.
|
|
|
|
|
|
|
|
// size of the sky texture is 64x96, but it's actually a 64x64 (clouds) and a 32x32 (sky)
|
|
|
|
|
2021-10-23 16:00:49 -04:00
|
|
|
SkyBlendHandler::SkyBlendHandler(const std::string& name,
|
|
|
|
BucketId my_id,
|
2022-01-20 00:22:03 -05:00
|
|
|
int level_id,
|
2021-12-30 19:38:18 -05:00
|
|
|
std::shared_ptr<SkyBlendGPU> shared_blender,
|
|
|
|
std::shared_ptr<SkyBlendCPU> shared_blender_cpu)
|
2021-11-13 20:44:17 -05:00
|
|
|
: BucketRenderer(name, my_id),
|
2021-12-30 19:38:18 -05:00
|
|
|
m_shared_gpu_blender(shared_blender),
|
|
|
|
m_shared_cpu_blender(shared_blender_cpu),
|
2021-12-04 12:33:18 -05:00
|
|
|
m_tfrag_renderer(fmt::format("tfrag-{}", name),
|
|
|
|
my_id,
|
|
|
|
{tfrag3::TFragmentTreeKind::TRANS, tfrag3::TFragmentTreeKind::LOWRES_TRANS},
|
2022-01-20 00:22:03 -05:00
|
|
|
true,
|
|
|
|
level_id) {}
|
2021-10-23 16:00:49 -04:00
|
|
|
|
|
|
|
void SkyBlendHandler::handle_sky_copies(DmaFollower& dma,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof) {
|
|
|
|
if (!m_enabled) {
|
|
|
|
while (dma.current_tag().qwc == 6) {
|
|
|
|
dma.read_and_advance();
|
|
|
|
dma.read_and_advance();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
2021-12-30 19:38:18 -05:00
|
|
|
if (render_state->use_sky_cpu) {
|
|
|
|
m_gpu_stats = m_shared_cpu_blender->do_sky_blends(dma, render_state, prof);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
m_gpu_stats = m_shared_gpu_blender->do_sky_blends(dma, render_state, prof);
|
|
|
|
}
|
2021-10-23 16:00:49 -04:00
|
|
|
}
|
2021-10-10 20:07:03 -04:00
|
|
|
}
|
|
|
|
|
2021-10-23 16:00:49 -04:00
|
|
|
void SkyBlendHandler::render(DmaFollower& dma,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof) {
|
2021-12-30 19:38:18 -05:00
|
|
|
m_gpu_stats = {};
|
2021-10-10 20:07:03 -04:00
|
|
|
// First thing should be a NEXT with two nops. this is a jump from buckets to sprite data
|
|
|
|
auto data0 = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(data0.vif1() == 0);
|
|
|
|
ASSERT(data0.vif0() == 0);
|
|
|
|
ASSERT(data0.size_bytes == 0);
|
2021-10-10 20:07:03 -04:00
|
|
|
|
|
|
|
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
|
|
|
|
// sky renderer didn't run, let's just get out of here.
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
dma.read_and_advance();
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
2021-10-10 20:07:03 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-04 12:33:18 -05:00
|
|
|
if (dma.current_tag().qwc != 8) {
|
|
|
|
auto tfrag_prof = prof.make_scoped_child("tfrag-trans");
|
|
|
|
m_tfrag_renderer.render(dma, render_state, tfrag_prof);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-10-10 20:07:03 -04:00
|
|
|
// first is the set-display-gs-state
|
|
|
|
auto set_display = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(set_display.size_bytes == 8 * 16);
|
2021-10-10 20:07:03 -04:00
|
|
|
|
|
|
|
handle_sky_copies(dma, render_state, prof);
|
|
|
|
|
|
|
|
auto reset_alpha = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(reset_alpha.size_bytes == 16 * 2);
|
2021-10-10 20:07:03 -04:00
|
|
|
|
|
|
|
auto reset_gs = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(reset_gs.size_bytes == 16 * 8);
|
2021-10-10 20:07:03 -04:00
|
|
|
|
|
|
|
auto empty = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(empty.size_bytes == 0);
|
|
|
|
ASSERT(empty.vif0() == 0);
|
|
|
|
ASSERT(empty.vif1() == 0);
|
2021-10-10 20:07:03 -04:00
|
|
|
|
2021-11-13 20:44:17 -05:00
|
|
|
if (dma.current_tag().kind != DmaTag::Kind::CALL) {
|
|
|
|
auto tfrag_prof = prof.make_scoped_child("tfrag-trans");
|
|
|
|
m_tfrag_renderer.render(dma, render_state, tfrag_prof);
|
|
|
|
} else {
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::CALL);
|
2021-11-13 20:44:17 -05:00
|
|
|
dma.read_and_advance();
|
|
|
|
dma.read_and_advance(); // cnt
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::RET);
|
2021-11-13 20:44:17 -05:00
|
|
|
dma.read_and_advance(); // ret
|
|
|
|
dma.read_and_advance(); // ret
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
2021-11-13 20:44:17 -05:00
|
|
|
}
|
2021-10-10 20:07:03 -04:00
|
|
|
}
|
|
|
|
|
2021-10-23 16:00:49 -04:00
|
|
|
void SkyBlendHandler::draw_debug_window() {
|
2021-10-10 20:07:03 -04:00
|
|
|
ImGui::Separator();
|
2021-12-30 19:38:18 -05:00
|
|
|
ImGui::Text("Draw/Blend ( sky ): %d/%d", m_gpu_stats.sky_draws, m_gpu_stats.sky_blends);
|
|
|
|
ImGui::Text("Draw/Blend (cloud): %d/%d", m_gpu_stats.cloud_draws, m_gpu_stats.cloud_blends);
|
2021-11-13 20:44:17 -05:00
|
|
|
|
|
|
|
if (ImGui::TreeNode("tfrag")) {
|
|
|
|
m_tfrag_renderer.draw_debug_window();
|
|
|
|
ImGui::TreePop();
|
|
|
|
}
|
2021-10-10 20:07:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
SkyRenderer::SkyRenderer(const std::string& name, BucketId my_id)
|
2022-02-25 23:25:49 -05:00
|
|
|
: BucketRenderer(name, my_id), m_direct_renderer("sky-direct", my_id, 100) {}
|
2021-10-10 20:07:03 -04:00
|
|
|
|
|
|
|
void SkyRenderer::render(DmaFollower& dma,
|
|
|
|
SharedRenderState* render_state,
|
|
|
|
ScopedProfilerNode& prof) {
|
|
|
|
m_direct_renderer.reset_state();
|
|
|
|
m_frame_stats = {};
|
|
|
|
// First thing should be a NEXT with two nops. this is a jump from buckets to sprite data
|
|
|
|
auto data0 = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(data0.vif1() == 0);
|
|
|
|
ASSERT(data0.vif0() == 0);
|
|
|
|
ASSERT(data0.size_bytes == 0);
|
2021-10-10 20:07:03 -04:00
|
|
|
|
|
|
|
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
|
|
|
|
// sky renderer didn't run, let's just get out of here.
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
dma.read_and_advance();
|
|
|
|
}
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
2021-10-10 20:07:03 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto setup_packet = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(setup_packet.size_bytes == 16 * 4);
|
2021-10-10 20:07:03 -04:00
|
|
|
m_direct_renderer.render_gif(setup_packet.data, setup_packet.size_bytes, render_state, prof);
|
|
|
|
|
2021-10-20 19:49:32 -04:00
|
|
|
if (dma.current_tag().qwc == 5) {
|
|
|
|
auto draw_setup_packet = dma.read_and_advance();
|
|
|
|
m_direct_renderer.render_gif(draw_setup_packet.data, draw_setup_packet.size_bytes, render_state,
|
|
|
|
prof);
|
|
|
|
// tex0: tbw = 1, th = 5, hw = 5, sky-base-block
|
|
|
|
// mmag/mmin = 1
|
|
|
|
// clamp
|
|
|
|
// drawing.
|
|
|
|
int dma_idx = 0;
|
|
|
|
while (dma.current_tag().kind == DmaTag::Kind::CNT) {
|
|
|
|
m_frame_stats.gif_packets++;
|
|
|
|
auto data = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(data.vifcode0().kind == VifCode::Kind::NOP);
|
|
|
|
ASSERT(data.vifcode1().kind == VifCode::Kind::DIRECT);
|
|
|
|
ASSERT(data.vifcode1().immediate == data.size_bytes / 16);
|
2021-10-20 19:49:32 -04:00
|
|
|
if (m_enabled) {
|
|
|
|
m_direct_renderer.render_gif(data.data, data.size_bytes, render_state, prof);
|
|
|
|
}
|
|
|
|
dma_idx++;
|
2021-10-10 20:07:03 -04:00
|
|
|
}
|
|
|
|
|
2021-10-20 19:49:32 -04:00
|
|
|
auto empty = dma.read_and_advance();
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(empty.size_bytes == 0);
|
|
|
|
ASSERT(empty.vif0() == 0);
|
|
|
|
ASSERT(empty.vif1() == 0);
|
2021-10-20 19:49:32 -04:00
|
|
|
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::CALL);
|
2021-10-20 19:49:32 -04:00
|
|
|
dma.read_and_advance();
|
|
|
|
dma.read_and_advance(); // cnt
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::RET);
|
2021-10-20 19:49:32 -04:00
|
|
|
dma.read_and_advance(); // ret
|
|
|
|
dma.read_and_advance(); // ret
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
2021-10-20 19:49:32 -04:00
|
|
|
} else {
|
|
|
|
while (dma.current_tag_offset() != render_state->next_bucket) {
|
|
|
|
auto data = dma.read_and_advance();
|
|
|
|
if (data.size_bytes && m_enabled) {
|
|
|
|
m_direct_renderer.render_vif(data.vif0(), data.vif1(), data.data, data.size_bytes,
|
|
|
|
render_state, prof);
|
|
|
|
}
|
2021-10-10 20:07:03 -04:00
|
|
|
|
2021-10-20 19:49:32 -04:00
|
|
|
if (dma.current_tag_offset() == render_state->default_regs_buffer) {
|
|
|
|
dma.read_and_advance(); // cnt
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::RET);
|
2021-10-20 19:49:32 -04:00
|
|
|
dma.read_and_advance(); // ret
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-10 20:07:03 -04:00
|
|
|
|
2021-10-20 19:49:32 -04:00
|
|
|
m_direct_renderer.flush_pending(render_state, prof);
|
2021-10-10 20:07:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void SkyRenderer::draw_debug_window() {
|
|
|
|
ImGui::Separator();
|
|
|
|
ImGui::Text("GIF packets: %d", m_frame_stats.gif_packets);
|
|
|
|
|
|
|
|
if (ImGui::TreeNode("direct")) {
|
|
|
|
m_direct_renderer.draw_debug_window();
|
|
|
|
ImGui::TreePop();
|
|
|
|
}
|
|
|
|
}
|