Skip to content

Commit

Permalink
add vis data to tie/tfrag and better framelimiting/lag (#1100)
Browse files Browse the repository at this point in the history
* add vis data to tie/tfrag and better fps stuff

* better default
  • Loading branch information
water111 authored Jan 20, 2022
1 parent 751fd06 commit 4648f78
Show file tree
Hide file tree
Showing 21 changed files with 285 additions and 59 deletions.
11 changes: 6 additions & 5 deletions common/custom_data/Tfrag3Data.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace tfrag3 {

constexpr int TFRAG3_VERSION = 8;
constexpr int TFRAG3_VERSION = 9;

// These vertices should be uploaded to the GPU at load time and don't change
struct PreloadedVertex {
Expand Down Expand Up @@ -42,8 +42,8 @@ struct StripDraw {
// to do culling, the above vertex stream is grouped.
// by following the visgroups and checking the visibility, you can leave out invisible vertices.
struct VisGroup {
u32 num = 0; // number of vertex indices in this group
u32 vis_idx = 0; // the visibility group they belong to
u32 num = 0; // number of vertex indices in this group
u32 vis_idx_in_pc_bvh = 0; // the visibility group they belong to (in BVH)
};
std::vector<VisGroup> vis_groups;

Expand Down Expand Up @@ -77,8 +77,9 @@ struct InstancedStripDraw {
struct VisNode {
math::Vector<float, 4> bsphere; // the bounding sphere, in meters (4096 = 1 game meter). w = rad
u16 child_id = 0xffff; // the ID of our first child.
u8 num_kids = 0xff; // number of children. The children are consecutive in memory
u8 flags = 0; // flags. If 1, we have a DrawVisNode child, otherwise a leaf.
u16 my_id = 0xffff;
u8 num_kids = 0xff; // number of children. The children are consecutive in memory
u8 flags = 0; // flags. If 1, we have a DrawVisNode child, otherwise a leaf.
};

// The leaf nodes don't actually exist in the vector of VisNodes, but instead they are ID's used
Expand Down
36 changes: 36 additions & 0 deletions common/util/FrameLimiter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include "common/util/Timer.h"

class FrameLimiter {
public:
void run(double target_fps, bool experimental_accurate_lag, double engine_time) {
double target_seconds;
if (experimental_accurate_lag) {
target_seconds = round_to_nearest_60fps(engine_time);
} else {
target_seconds = 1.f / target_fps;
}
double remaining_time = target_seconds - m_timer.getSeconds();
while (remaining_time > 0) {
if (remaining_time > 0.003) {
std::this_thread::sleep_for(std::chrono::microseconds(int(remaining_time * 1e6 * 0.5)));
}
remaining_time = target_seconds - m_timer.getSeconds();
}

m_timer.start();
}

private:
double round_to_nearest_60fps(double current) {
double one_frame = 1.f / 60.f;
int frames_missed = (current / one_frame); // rounds down
if (frames_missed > 4) {
frames_missed = 4;
}
return (frames_missed + 1) * one_frame;
}

Timer m_timer;
};
13 changes: 7 additions & 6 deletions decompiler/level_extractor/extract_tfrag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ VisNodeTree extract_vis_data(const level_tools::DrawableTreeTfrag* tree, u16 fir
}
vis.num_kids = elt.child_count;
vis.flags = elt.flags;
vis.my_id = elt.id;
assert(vis.flags == expecting_leaves ? 0 : 1);
assert(vis.num_kids > 0);
assert(vis.num_kids <= 8);
Expand Down Expand Up @@ -2036,8 +2037,8 @@ void make_tfrag3_data(std::map<u32, std::vector<GroupedDraw>>& draws,

for (auto& strip : draw.strips) {
tfrag3::StripDraw::VisGroup vgroup;
vgroup.vis_idx = strip.tfrag_id; // associate with the tfrag for culling
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
vgroup.vis_idx_in_pc_bvh = strip.tfrag_id; // associate with the tfrag for culling
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!

tdraw.num_triangles += strip.verts.size() - 2;
for (auto& vert : strip.verts) {
Expand Down Expand Up @@ -2118,7 +2119,7 @@ void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
std::vector<tfrag3::StripDraw::VisGroup> result;
result.push_back(grps.at(0));
for (size_t i = 1; i < grps.size(); i++) {
if (grps[i].vis_idx == result.back().vis_idx) {
if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh) {
result.back().num += grps[i].num;
} else {
result.push_back(grps[i]);
Expand Down Expand Up @@ -2196,11 +2197,11 @@ void extract_tfrag(const level_tools::DrawableTreeTfrag* tree,

for (auto& draw : this_tree.draws) {
for (auto& str : draw.vis_groups) {
auto it = tfrag_parents.find(str.vis_idx);
auto it = tfrag_parents.find(str.vis_idx_in_pc_bvh);
if (it == tfrag_parents.end()) {
str.vis_idx = UINT32_MAX;
str.vis_idx_in_pc_bvh = UINT32_MAX;
} else {
str.vis_idx = it->second;
str.vis_idx_in_pc_bvh = it->second;
}
}
merge_groups(draw.vis_groups);
Expand Down
9 changes: 0 additions & 9 deletions decompiler/level_extractor/extract_tfrag.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,6 @@ struct VisNodeTree {
bool only_children = false;
};

// The final result
struct ExtractedTFragmentTree {
// TFragmentKind kind = TFragmentKind::INVALID;
VisNodeTree vis_nodes;

u16 num_tfrags = 0;
u16 tfrag_base_idx = 0;
};

// will pool textures with others already in out.
void extract_tfrag(const level_tools::DrawableTreeTfrag* tree,
const std::string& debug_name,
Expand Down
13 changes: 7 additions & 6 deletions decompiler/level_extractor/extract_tie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ void extract_vis_data(const level_tools::DrawableTreeInstanceTie* tree,
}
vis.num_kids = elt.child_count;
vis.flags = elt.flags;
vis.my_id = elt.id;
assert(vis.flags == expecting_leaves ? 0 : 1);
assert(vis.num_kids > 0);
assert(vis.num_kids <= 8);
Expand Down Expand Up @@ -2182,8 +2183,8 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,

// now we have a draw, time to add vertices
tfrag3::StripDraw::VisGroup vgroup;
vgroup.vis_idx = inst.vis_id; // associate with the instance for culling
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
vgroup.vis_idx_in_pc_bvh = inst.vis_id; // associate with the instance for culling
vgroup.num = strip.verts.size() + 1; // one for the primitive restart!
draw_to_add_to->num_triangles += strip.verts.size() - 2;
for (auto& vert : strip.verts) {
tfrag3::PreloadedVertex vtx;
Expand Down Expand Up @@ -2247,7 +2248,7 @@ void merge_groups(std::vector<tfrag3::StripDraw::VisGroup>& grps) {
std::vector<tfrag3::StripDraw::VisGroup> result;
result.push_back(grps.at(0));
for (size_t i = 1; i < grps.size(); i++) {
if (grps[i].vis_idx == result.back().vis_idx) {
if (grps[i].vis_idx_in_pc_bvh == result.back().vis_idx_in_pc_bvh) {
result.back().num += grps[i].num;
} else {
result.push_back(grps[i]);
Expand Down Expand Up @@ -2329,11 +2330,11 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
// remap vis indices and merge
for (auto& draw : this_tree.static_draws) {
for (auto& str : draw.vis_groups) {
auto it = instance_parents.find(str.vis_idx);
auto it = instance_parents.find(str.vis_idx_in_pc_bvh);
if (it == instance_parents.end()) {
str.vis_idx = UINT32_MAX;
str.vis_idx_in_pc_bvh = UINT32_MAX;
} else {
str.vis_idx = it->second;
str.vis_idx_in_pc_bvh = it->second;
}
}
merge_groups(draw.vis_groups);
Expand Down
7 changes: 7 additions & 0 deletions game/graphics/opengl_renderer/BucketRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,11 @@ void SkipRenderer::render(DmaFollower& dma,
while (dma.current_tag_offset() != render_state->next_bucket) {
dma.read_and_advance();
}
}

void SharedRenderState::reset() {
has_camera_planes = false;
for (auto& x : occlusion_vis) {
x.valid = false;
}
}
8 changes: 8 additions & 0 deletions game/graphics/opengl_renderer/BucketRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ enum class BucketId {
MAX_BUCKETS = 69
};

struct LevelVis {
bool valid = false;
u8 data[2048];
};

/*!
* The main renderer will contain a single SharedRenderState that's passed to all bucket renderers.
* This allows bucket renders to share textures and shaders.
Expand All @@ -63,8 +68,11 @@ struct SharedRenderState {
bool dump_playback = false;

bool use_sky_cpu = true;
bool use_occlusion_culling = true;

void reset();
bool has_camera_planes = false;
LevelVis occlusion_vis[2];
math::Vector4f camera_planes[4];
};

Expand Down
24 changes: 14 additions & 10 deletions game/graphics/opengl_renderer/OpenGLRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,29 @@ void OpenGLRenderer::init_bucket_renderers() {
init_bucket_renderer<SkyRenderer>("sky", BucketId::SKY_DRAW);

init_bucket_renderer<TextureUploadHandler>("tfrag-tex-0", BucketId::TFRAG_TEX_LEVEL0);
init_bucket_renderer<TFragment>("tfrag-0", BucketId::TFRAG_LEVEL0, normal_tfrags, false);
init_bucket_renderer<Tie3>("tie-0", BucketId::TIE_LEVEL0);
init_bucket_renderer<TFragment>("tfrag-0", BucketId::TFRAG_LEVEL0, normal_tfrags, false, 0);
init_bucket_renderer<Tie3>("tie-0", BucketId::TIE_LEVEL0, 0);
init_bucket_renderer<TextureUploadHandler>("tfrag-tex-1", BucketId::TFRAG_TEX_LEVEL1);
init_bucket_renderer<TFragment>("tfrag-1", BucketId::TFRAG_LEVEL1, normal_tfrags, false);
init_bucket_renderer<Tie3>("tie-1", BucketId::TIE_LEVEL1);
init_bucket_renderer<TFragment>("tfrag-1", BucketId::TFRAG_LEVEL1, normal_tfrags, false, 1);
init_bucket_renderer<Tie3>("tie-1", BucketId::TIE_LEVEL1, 1);
init_bucket_renderer<TextureUploadHandler>("shrub-tex-0", BucketId::SHRUB_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("shrub-tex-1", BucketId::SHRUB_TEX_LEVEL1);
init_bucket_renderer<TextureUploadHandler>("alpha-tex-0", BucketId::ALPHA_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("alpha-tex-1", BucketId::ALPHA_TEX_LEVEL1);
auto sky_gpu_blender = std::make_shared<SkyBlendGPU>();
auto sky_cpu_blender = std::make_shared<SkyBlendCPU>();
init_bucket_renderer<SkyBlendHandler>("sky-blend-and-tfrag-trans-0",
BucketId::TFRAG_TRANS0_AND_SKY_BLEND_LEVEL0,
BucketId::TFRAG_TRANS0_AND_SKY_BLEND_LEVEL0, 0,
sky_gpu_blender, sky_cpu_blender);
init_bucket_renderer<TFragment>("tfrag-dirt-0", BucketId::TFRAG_DIRT_LEVEL0, dirt_tfrags, false);
init_bucket_renderer<TFragment>("tfrag-ice-0", BucketId::TFRAG_ICE_LEVEL0, ice_tfrags, false);
init_bucket_renderer<TFragment>("tfrag-dirt-0", BucketId::TFRAG_DIRT_LEVEL0, dirt_tfrags, false,
0);
init_bucket_renderer<TFragment>("tfrag-ice-0", BucketId::TFRAG_ICE_LEVEL0, ice_tfrags, false, 0);
init_bucket_renderer<SkyBlendHandler>("sky-blend-and-tfrag-trans-1",
BucketId::TFRAG_TRANS1_AND_SKY_BLEND_LEVEL1,
BucketId::TFRAG_TRANS1_AND_SKY_BLEND_LEVEL1, 1,
sky_gpu_blender, sky_cpu_blender);
init_bucket_renderer<TFragment>("tfrag-dirt-1", BucketId::TFRAG_DIRT_LEVEL1, dirt_tfrags, false);
init_bucket_renderer<TFragment>("tfrag-ice-1", BucketId::TFRAG_ICE_LEVEL1, ice_tfrags, false);
init_bucket_renderer<TFragment>("tfrag-dirt-1", BucketId::TFRAG_DIRT_LEVEL1, dirt_tfrags, false,
1);
init_bucket_renderer<TFragment>("tfrag-ice-1", BucketId::TFRAG_ICE_LEVEL1, ice_tfrags, false, 1);
init_bucket_renderer<TextureUploadHandler>("pris-tex-0", BucketId::PRIS_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("pris-tex-1", BucketId::PRIS_TEX_LEVEL1);
init_bucket_renderer<TextureUploadHandler>("water-tex-0", BucketId::WATER_TEX_LEVEL0);
Expand All @@ -117,6 +119,7 @@ void OpenGLRenderer::init_bucket_renderers() {
*/
void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
m_profiler.clear();
m_render_state.reset();
m_render_state.dump_playback = settings.playing_from_dump;
m_render_state.ee_main_memory = settings.playing_from_dump ? nullptr : g_ee_main_mem;
m_render_state.offset_of_s7 = offset_of_s7();
Expand Down Expand Up @@ -173,6 +176,7 @@ void OpenGLRenderer::draw_renderer_selection_window() {
ImGui::Begin("Renderer Debug");

ImGui::Checkbox("Sky CPU", &m_render_state.use_sky_cpu);
ImGui::Checkbox("Occlusion Cull", &m_render_state.use_occlusion_culling);

for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
auto renderer = m_bucket_renderers[i].get();
Expand Down
4 changes: 3 additions & 1 deletion game/graphics/opengl_renderer/SkyRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

SkyBlendHandler::SkyBlendHandler(const std::string& name,
BucketId my_id,
int level_id,
std::shared_ptr<SkyBlendGPU> shared_blender,
std::shared_ptr<SkyBlendCPU> shared_blender_cpu)
: BucketRenderer(name, my_id),
Expand All @@ -29,7 +30,8 @@ SkyBlendHandler::SkyBlendHandler(const std::string& name,
m_tfrag_renderer(fmt::format("tfrag-{}", name),
my_id,
{tfrag3::TFragmentTreeKind::TRANS, tfrag3::TFragmentTreeKind::LOWRES_TRANS},
true) {}
true,
level_id) {}

void SkyBlendHandler::handle_sky_copies(DmaFollower& dma,
SharedRenderState* render_state,
Expand Down
1 change: 1 addition & 0 deletions game/graphics/opengl_renderer/SkyRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class SkyBlendHandler : public BucketRenderer {
public:
SkyBlendHandler(const std::string& name,
BucketId my_id,
int level_id,
std::shared_ptr<SkyBlendGPU> shared_gpu_blender,
std::shared_ptr<SkyBlendCPU> shared_cpu_blender);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
Expand Down
23 changes: 21 additions & 2 deletions game/graphics/opengl_renderer/debug_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@
#include "third-party/imgui/imgui.h"

void FrameTimeRecorder::finish_frame() {
m_frame_times[m_idx++] = m_timer.getMs();
m_frame_times[m_idx++] = m_compute_timer.getMs();
if (m_idx == SIZE) {
m_idx = 0;
}
}

void FrameTimeRecorder::start_frame() {
m_timer.start();
m_compute_timer.start();
float frame_time = m_fps_timer.getSeconds();
m_last_frame_time = (0.9 * m_last_frame_time) + (0.1 * frame_time);
m_fps_timer.start();
}

void FrameTimeRecorder::draw_window(const DmaStats& dma_stats) {
Expand Down Expand Up @@ -52,6 +55,8 @@ void FrameTimeRecorder::draw_window(const DmaStats& dma_stats) {
} else {
ImGui::Text("worst: %.1f", worst);
}
ImGui::SameLine();
ImGui::Text("fps-avg: %.1f", 1.f / m_last_frame_time);

ImGui::Separator();
ImGui::PlotLines(
Expand Down Expand Up @@ -105,6 +110,20 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
ImGui::InputText("Dump", m_dump_save_name, 12);
ImGui::EndMenu();
}

if (ImGui::BeginMenu("Frame Rate")) {
ImGui::MenuItem("Enable V-Sync", nullptr, &m_vsync);
ImGui::MenuItem("Disable V-Sync", nullptr, &m_nosync);
ImGui::Separator();
ImGui::Checkbox("Framelimiter", &framelimiter);
ImGui::InputFloat("Target FPS", &m_target_fps_text);
if (ImGui::MenuItem("Apply")) {
target_fps = m_target_fps_text;
}
ImGui::Separator();
ImGui::Checkbox("Accurate Lag Mode", &experimental_accurate_lag);
ImGui::EndMenu();
}
}
ImGui::EndMainMenuBar();

Expand Down
27 changes: 26 additions & 1 deletion game/graphics/opengl_renderer/debug_gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ class FrameTimeRecorder {

private:
float m_frame_times[SIZE] = {0};
float m_last_frame_time = 0;
int m_idx = 0;
Timer m_timer;
Timer m_compute_timer;
Timer m_fps_timer;
bool m_open = true;

bool m_play = true;
Expand Down Expand Up @@ -59,6 +61,26 @@ class OpenGlDebugGui {
return false;
}

bool get_nosync_flag() {
if (m_nosync) {
m_nosync = false;
return true;
}
return false;
}

bool get_vsync_flag() {
if (m_vsync) {
m_vsync = false;
return true;
}
return false;
}

bool framelimiter = false;
float target_fps = 60.f;
bool experimental_accurate_lag = false;

private:
FrameTimeRecorder m_frame_timer;
bool m_draw_frame_time = false;
Expand All @@ -70,4 +92,7 @@ class OpenGlDebugGui {
bool m_want_screenshot = false;
char m_dump_save_name[256] = "dump.bin";
char m_screenshot_save_name[256] = "screenshot.png";
bool m_vsync = false;
bool m_nosync = false;
float m_target_fps_text = 60.0;
};
Loading

0 comments on commit 4648f78

Please sign in to comment.