mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
217 lines
7.4 KiB
C++
217 lines
7.4 KiB
C++
#include "SkyRenderer.h"
|
|
|
|
#include "game/graphics/opengl_renderer/AdgifHandler.h"
|
|
#include "game/graphics/pipelines/opengl.h"
|
|
|
|
#include "third-party/imgui/imgui.h"
|
|
|
|
// 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)
|
|
|
|
SkyBlendHandler::SkyBlendHandler(const std::string& name,
|
|
int my_id,
|
|
int level_id,
|
|
std::shared_ptr<SkyBlendGPU> shared_blender,
|
|
std::shared_ptr<SkyBlendCPU> shared_blender_cpu,
|
|
const std::vector<GLuint>* anim_slots)
|
|
: BucketRenderer(name, my_id),
|
|
m_shared_gpu_blender(shared_blender),
|
|
m_shared_cpu_blender(shared_blender_cpu),
|
|
m_tfrag_renderer(fmt::format("tfrag-{}", name),
|
|
my_id,
|
|
{tfrag3::TFragmentTreeKind::TRANS, tfrag3::TFragmentTreeKind::LOWRES_TRANS},
|
|
true,
|
|
level_id,
|
|
anim_slots) {}
|
|
|
|
void SkyBlendHandler::init_shaders(ShaderLibrary& shaders) {
|
|
m_tfrag_renderer.init_shaders(shaders);
|
|
}
|
|
|
|
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 {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SkyBlendHandler::render(DmaFollower& dma,
|
|
SharedRenderState* render_state,
|
|
ScopedProfilerNode& prof) {
|
|
m_gpu_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();
|
|
ASSERT(data0.vif1() == 0);
|
|
ASSERT(data0.vif0() == 0);
|
|
ASSERT(data0.size_bytes == 0);
|
|
|
|
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();
|
|
}
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// first is the set-display-gs-state
|
|
auto set_display = dma.read_and_advance();
|
|
ASSERT(set_display.size_bytes == 8 * 16);
|
|
|
|
handle_sky_copies(dma, render_state, prof);
|
|
|
|
auto reset_alpha = dma.read_and_advance();
|
|
ASSERT(reset_alpha.size_bytes == 16 * 2);
|
|
|
|
auto reset_gs = dma.read_and_advance();
|
|
ASSERT(reset_gs.size_bytes == 16 * 8);
|
|
|
|
auto empty = dma.read_and_advance();
|
|
ASSERT(empty.size_bytes == 0);
|
|
ASSERT(empty.vif0() == 0);
|
|
ASSERT(empty.vif1() == 0);
|
|
|
|
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 {
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::CALL);
|
|
dma.read_and_advance();
|
|
dma.read_and_advance(); // cnt
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::RET);
|
|
dma.read_and_advance(); // ret
|
|
dma.read_and_advance(); // ret
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
|
}
|
|
}
|
|
|
|
void SkyBlendHandler::draw_debug_window() {
|
|
ImGui::Separator();
|
|
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);
|
|
|
|
if (ImGui::TreeNode("tfrag")) {
|
|
m_tfrag_renderer.draw_debug_window();
|
|
ImGui::TreePop();
|
|
}
|
|
}
|
|
|
|
SkyRenderer::SkyRenderer(const std::string& name, int my_id)
|
|
: BucketRenderer(name, my_id), m_direct_renderer("sky-direct", my_id, 100) {}
|
|
|
|
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();
|
|
ASSERT(data0.vif1() == 0);
|
|
ASSERT(data0.vif0() == 0);
|
|
ASSERT(data0.size_bytes == 0);
|
|
|
|
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();
|
|
}
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
|
return;
|
|
}
|
|
|
|
auto setup_packet = dma.read_and_advance();
|
|
ASSERT(setup_packet.size_bytes == 16 * 4);
|
|
m_direct_renderer.render_gif(setup_packet.data, setup_packet.size_bytes, render_state, prof);
|
|
|
|
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.
|
|
[[maybe_unused]] int dma_idx = 0;
|
|
while (dma.current_tag().kind == DmaTag::Kind::CNT) {
|
|
m_frame_stats.gif_packets++;
|
|
auto data = dma.read_and_advance();
|
|
ASSERT(data.vifcode0().kind == VifCode::Kind::NOP);
|
|
ASSERT(data.vifcode1().kind == VifCode::Kind::DIRECT);
|
|
ASSERT(data.vifcode1().immediate == data.size_bytes / 16);
|
|
if (m_enabled) {
|
|
m_direct_renderer.render_gif(data.data, data.size_bytes, render_state, prof);
|
|
}
|
|
dma_idx++;
|
|
}
|
|
|
|
auto empty = dma.read_and_advance();
|
|
ASSERT(empty.size_bytes == 0);
|
|
ASSERT(empty.vif0() == 0);
|
|
ASSERT(empty.vif1() == 0);
|
|
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::CALL);
|
|
dma.read_and_advance();
|
|
dma.read_and_advance(); // cnt
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::RET);
|
|
dma.read_and_advance(); // ret
|
|
dma.read_and_advance(); // ret
|
|
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
|
|
} 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);
|
|
}
|
|
|
|
if (dma.current_tag_offset() == render_state->default_regs_buffer) {
|
|
dma.read_and_advance(); // cnt
|
|
ASSERT(dma.current_tag().kind == DmaTag::Kind::RET);
|
|
dma.read_and_advance(); // ret
|
|
}
|
|
}
|
|
}
|
|
|
|
m_direct_renderer.flush_pending(render_state, prof);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|