Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions code/graphics/2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "graphics/util/UniformBufferManager.h"
#include "graphics/shadows.h"
#include "io/mouse.h"
#include "model/modelrender.h"
#include "libs/jansson.h"
#include "options/Option.h"
#include "osapi/osapi.h"
Expand Down Expand Up @@ -2925,6 +2926,8 @@ void gr_flip(bool execute_scripting)
}
}

model_process_cached_ui_render_instances();

gr_reset_immediate_buffer();

// Do per frame operations on the matrix state
Expand Down
28 changes: 9 additions & 19 deletions code/menuui/techmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "lighting/lighting.h"
#include "localization/localize.h"
#include "menuui/techmenu.h"
#include "model/modelrender.h"
#include "missionui/missionscreencommon.h"
#include "parse/parselo.h"
#include "playerman/player.h"
Expand Down Expand Up @@ -213,7 +214,6 @@ static const char *Text_lines[MAX_TEXT_LINES];
static int Cur_entry = -1; // this is the current entry selected, using entry indexing
static int Cur_entry_index = -1; // this is the current entry selected, using master list indexing
static int Techroom_modelnum = -1;
static int Techroom_model_instance = -1;
static float Techroom_ship_rot;
static UI_BUTTON List_buttons[LIST_BUTTONS_MAX]; // buttons for each line of text in list

Expand Down Expand Up @@ -332,12 +332,6 @@ void techroom_select_new_entry()

Techroom_modelnum = model_load(sip, true);

if (Techroom_model_instance >= 0) {
model_delete_instance(Techroom_model_instance);
}
Techroom_model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, Techroom_modelnum);

model_set_up_techroom_instance(sip, Techroom_model_instance);

Current_list->at(Cur_entry).model_num = Techroom_modelnum;

Expand All @@ -348,10 +342,6 @@ void techroom_select_new_entry()
} else {
Techroom_modelnum = -1;

if (Techroom_model_instance >= 0) {
model_delete_instance(Techroom_model_instance);
Techroom_model_instance = -1;
}

Trackball_mode = 0;

Expand Down Expand Up @@ -393,11 +383,6 @@ void techroom_select_new_entry()
if (Techroom_modelnum >= 0) {
weaponLoaded = true;

if (Techroom_model_instance >= 0) {
model_delete_instance(Techroom_model_instance);
}
Techroom_model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, Techroom_modelnum);

// If this ends up being needed for weapon models, a weapon version
// of this method will need to be created. Should only be necessary
// if weapon models start having animations or other advanced model
Expand Down Expand Up @@ -611,6 +596,12 @@ void techroom_ships_render(float frametime)
model_clear_instance(Techroom_modelnum);
render_info.set_detail_level_lock(0);

int model_instance = -1;
model_get_cached_ui_render_instance(Techroom_modelnum, &model_instance);
if (Tab == SHIPS_DATA_TAB) {
model_set_up_techroom_instance(&Ship_info[Cur_entry_index], model_instance);
}

if(shadow_maybe_start_frame(Shadow_disable_overrides.disable_techroom))
{
gr_reset_clip();
Expand All @@ -620,7 +611,7 @@ void techroom_ships_render(float frametime)
shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -closeup_pos.xyz.z + pm->rad, -closeup_pos.xyz.z + pm->rad + 200.0f, -closeup_pos.xyz.z + pm->rad + 2000.0f, -closeup_pos.xyz.z + pm->rad + 10000.0f);
render_info.set_flags(MR_NO_TEXTURING | MR_NO_LIGHTING | MR_AUTOCENTER);

model_render_immediate(&render_info, Techroom_modelnum, Techroom_model_instance, &Techroom_ship_orient, &vmd_zero_vector);
model_render_immediate(&render_info, Techroom_modelnum, model_instance, &Techroom_ship_orient, &vmd_zero_vector);
shadows_end_render();

gr_set_clip(Tech_ship_display_coords[gr_screen.res][SHIP_X_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_Y_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_W_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_H_COORD], GR_RESIZE_MENU);
Expand All @@ -636,7 +627,7 @@ void techroom_ships_render(float frametime)

render_info.set_flags(render_flags);

model_render_immediate(&render_info, Techroom_modelnum, Techroom_model_instance, &Techroom_ship_orient, &vmd_zero_vector);
model_render_immediate(&render_info, Techroom_modelnum, model_instance, &Techroom_ship_orient, &vmd_zero_vector);

Glowpoint_use_depth_buffer = true;

Expand Down Expand Up @@ -1314,7 +1305,6 @@ void techroom_lists_reset()

model_free_all();
Techroom_modelnum = -1;
Techroom_model_instance = -1;

// This can be cleared immediately because there are no anims or bitmaps associated.
Ship_list.clear();
Expand Down
14 changes: 9 additions & 5 deletions code/missionui/missionscreencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "missionui/missionshipchoice.h"
#include "missionui/missionweaponchoice.h"
#include "mod_table/mod_table.h"
#include "model/modelrender.h"
#include "network/multi.h"
#include "network/multi_endgame.h"
#include "network/multimsgs.h"
Expand Down Expand Up @@ -1651,9 +1652,14 @@ void draw_model_icon(int model_id, uint64_t flags, float closeup_zoom, int x, in

Glowpoint_override = true;
model_clear_instance(model_id);
int model_instance = -1;
model_get_cached_ui_render_instance(model_id, &model_instance);
if (sip != nullptr) {
model_set_up_techroom_instance(sip, model_instance);
}

render_info.set_flags(flags);
model_render_immediate(&render_info, model_id, &object_orient, &vmd_zero_vector);
model_render_immediate(&render_info, model_id, model_instance, &object_orient, &vmd_zero_vector);
Glowpoint_override = false;

gr_end_view_matrix();
Expand All @@ -1669,7 +1675,8 @@ void draw_model_rotating(model_render_params *render_info, int ship_class, int m
if (model_id < 0)
return;

int model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, model_id);
int model_instance = -1;
model_get_cached_ui_render_instance(model_id, &model_instance);
if (!(flags & MR_IS_MISSILE) && SCP_vector_inbounds(Ship_info, ship_class)) {
model_set_up_techroom_instance(&Ship_info[ship_class], model_instance);
}
Expand Down Expand Up @@ -1953,9 +1960,6 @@ void draw_model_rotating(model_render_params *render_info, int ship_class, int m
}

shadow_end_frame();
if (model_instance >= 0) {
model_delete_instance(model_instance);
}
}

/**
Expand Down
11 changes: 4 additions & 7 deletions code/missionui/missionweaponchoice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "missionui/missionshipchoice.h"
#include "missionui/missionweaponchoice.h"
#include "model/model.h"
#include "model/modelrender.h"
#include "mod_table/mod_table.h"
#include "network/multi.h"
#include "network/multi_pmsg.h"
Expand Down Expand Up @@ -823,10 +824,9 @@ void draw_3d_overhead_view(int model_num,
Glowpoint_use_depth_buffer = false;

model_clear_instance(model_num);
int model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, model_num);
if (model_instance >= 0) {
model_set_up_techroom_instance(sip, model_instance);
}
int model_instance = -1;
model_get_cached_ui_render_instance(model_num, &model_instance);
model_set_up_techroom_instance(sip, model_instance);
polymodel* pm = model_get(model_num);

if (sip->replacement_textures.size() > 0) {
Expand Down Expand Up @@ -868,9 +868,6 @@ void draw_3d_overhead_view(int model_num,
batching_render_all();

shadow_end_frame();
if (model_instance >= 0) {
model_delete_instance(model_instance);
}

// NOW render the lines for weapons
gr_reset_clip();
Expand Down
112 changes: 106 additions & 6 deletions code/model/modelrender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "nebula/neb.h"
#include "particle/particle.h"
#include "prop/prop.h"
#include "parse/encrypt.h"
#include "render/3dinternal.h"
#include "render/batching.h"
#include "ship/ship.h"
Expand All @@ -35,6 +36,7 @@
#include "weapon/weapon.h"

#include <algorithm>
#include <unordered_map>

extern int Model_texturing;
extern int Model_polys;
Expand All @@ -50,6 +52,108 @@ extern void interp_generate_arc_segment(SCP_vector<vec3d> &arc_segment_points, c

int model_render_determine_elapsed_time(int objnum, uint64_t flags);

SCP_unordered_map<cached_ui_render_instance_key, cached_ui_render_instance_entry, cached_ui_render_instance_key_hash>
Cached_ui_render_instance_cache;
UI_TIMESTAMP Ui_render_instance_cache_last_processed_timestamp = UI_TIMESTAMP::invalid();
constexpr int UI_RENDER_INSTANCE_CACHE_UNUSED_MS_GRACE = 100;

size_t model_hash_subsystem_name_list_for_cache(const SCP_vector<SCP_string>& subsystem_names)
{
if (subsystem_names.empty()) {
return 0;
}

SCP_vector<SCP_string> normalized_names;
normalized_names.reserve(subsystem_names.size());

for (const auto& name : subsystem_names) {
auto normalized = name;
SCP_tolower(normalized);
normalized_names.push_back(std::move(normalized));
}

std::sort(normalized_names.begin(), normalized_names.end());

size_t seed = 0;

boost::hash_combine(seed, static_cast<uint32_t>(normalized_names.size()));
for (const auto& name : normalized_names) {
boost::hash_combine(seed, hash_fnv1a(name));
}

return seed;
}

// Returns TriStateBool::TRUE_ if a new instance was created, TriStateBool::FALSE_ if an existing instance was returned,
// or TriStateBool::UNKNOWN_ if there was an error (and model_instance_out will be set to -1 in this case)
TriStateBool model_get_cached_ui_render_instance(int model_num, int* model_instance_out, size_t instance_data_hash)
{
Assertion(model_instance_out != nullptr, "model_instance_out must not be null!");
if (model_instance_out == nullptr) {
return TriStateBool::UNKNOWN_;
}

cached_ui_render_instance_key key;
key.model_num = model_num;
key.state_instance_id = gameseq_get_state_instance_id();
key.instance_data_hash = instance_data_hash;

auto& entry = Cached_ui_render_instance_cache[key];

auto created_new = false;

if (entry.model_instance < 0) {
entry.model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, model_num);
if (entry.model_instance < 0) {
Warning(LOCATION, "Failed to create cached UI render model instance for model id %d.", model_num);
Cached_ui_render_instance_cache.erase(key);
*model_instance_out = -1;
return TriStateBool::UNKNOWN_;
}
created_new = true;
}

entry.last_used_timestamp = ui_timestamp();
*model_instance_out = entry.model_instance;
return created_new ? TriStateBool::TRUE_ : TriStateBool::FALSE_;
}

void model_process_cached_ui_render_instances()
{
const auto now = ui_timestamp();

if (Ui_render_instance_cache_last_processed_timestamp.isValid() &&
ui_timestamp_get_delta(Ui_render_instance_cache_last_processed_timestamp, now) == 0) {
return;
}

Ui_render_instance_cache_last_processed_timestamp = now;

for (auto it = Cached_ui_render_instance_cache.begin(); it != Cached_ui_render_instance_cache.end();) {
if (it->second.model_instance < 0 || !it->second.last_used_timestamp.isValid() ||
ui_timestamp_get_delta(it->second.last_used_timestamp, now) > UI_RENDER_INSTANCE_CACHE_UNUSED_MS_GRACE) {
if (it->second.model_instance >= 0) {
model_delete_instance(it->second.model_instance);
}
it = Cached_ui_render_instance_cache.erase(it);
} else {
++it;
}
}
}

void model_clear_cached_ui_render_instances()
{
for (auto& instance : Cached_ui_render_instance_cache) {
if (instance.second.model_instance >= 0) {
model_delete_instance(instance.second.model_instance);
}
}

Cached_ui_render_instance_cache.clear();
Ui_render_instance_cache_last_processed_timestamp = UI_TIMESTAMP::invalid();
}

model_batch_buffer TransformBufferHandler;

model_render_params::model_render_params() :
Expand Down Expand Up @@ -3220,9 +3324,9 @@ bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int

int model_instance = -1;

// Create an instance for ships that can be used to clear out destroyed subobjects from rendering
// Get a cached UI render instance for ships so repeated UI/Lua renders avoid per-call allocation churn
if (model_type == TECH_SHIP) {
model_instance = model_create_instance(model_objnum_special::OBJNUM_NONE, model_num);
model_get_cached_ui_render_instance(model_num, &model_instance);
model_set_up_techroom_instance(&Ship_info[class_idx], model_instance);
}

Expand Down Expand Up @@ -3252,9 +3356,5 @@ bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int
g3_end_frame();
gr_reset_clip();

// Now that we've rendered the frame we can remove the instance if one was created for ships
if (model_type == TECH_SHIP)
model_delete_instance(model_instance);

return true;
}
35 changes: 35 additions & 0 deletions code/model/modelrender.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "model/model.h"
#include "mission/missionparse.h"
#include "graphics/util/UniformBuffer.h"
#include "utils/boost/hash_combine.h"

extern SCP_vector<light> Lights;
extern int Num_lights;
Expand Down Expand Up @@ -159,6 +160,35 @@ class model_render_params
float get_alpha_mult() const;
};

struct cached_ui_render_instance_key {
int model_num;
int state_instance_id;
size_t instance_data_hash;

bool operator==(const cached_ui_render_instance_key& other) const
{
return model_num == other.model_num && state_instance_id == other.state_instance_id &&
instance_data_hash == other.instance_data_hash;
}
};

struct cached_ui_render_instance_key_hash {
size_t operator()(const cached_ui_render_instance_key& key) const
{
size_t seed = 0;

boost::hash_combine(seed, key.model_num);
boost::hash_combine(seed, key.state_instance_id);
boost::hash_combine(seed, key.instance_data_hash);
return seed;
}
};

struct cached_ui_render_instance_entry {
int model_instance = -1;
UI_TIMESTAMP last_used_timestamp = UI_TIMESTAMP::invalid();
};

struct arc_effect
{
matrix4 transform;
Expand Down Expand Up @@ -319,6 +349,11 @@ void model_render_insignias(const insignia_draw_data* insignia);
void model_render_set_wireframe_color(const color* clr);
bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string& pof_filename = "", float closeup_zoom = 0, const vec3d* closeup_pos = &vmd_zero_vector, const SCP_string& tcolor = "");

size_t model_hash_subsystem_name_list_for_cache(const SCP_vector<SCP_string>& subsystem_names);
TriStateBool model_get_cached_ui_render_instance(int model_num, int* model_instance_out, size_t instance_data_hash = 0);
void model_clear_cached_ui_render_instances();
void model_process_cached_ui_render_instances();

float convert_distance_and_diameter_to_pixel_size(float distance, float diameter, float field_of_view, int screen_width);

float model_render_get_diameter_clamped_to_min_pixel_size(const vec3d* pos, float diameter, float min_pixel_size);
Expand Down
Loading