mirror of
https://github.com/open-goal/jak-project
synced 2026-05-25 23:35:33 -04:00
[graphics] small improvements (#1351)
* faster texture upload lookup * fix debug menu * cleanup * one more
This commit is contained in:
@@ -114,7 +114,9 @@ jobs:
|
||||
run: |
|
||||
mkdir -p ./ci-artifacts/out
|
||||
./.github/scripts/releases/extract_build_linux.sh ./ci-artifacts/out ./
|
||||
tar -czf ./ci-artifacts/linux.tar.gz -C ./ci-artifacts .
|
||||
pushd ci-artifacts
|
||||
tar czf linux.tar.gz ./out
|
||||
popd
|
||||
|
||||
- name: Upload Assets and Potential Publish Release
|
||||
if: github.repository == 'open-goal/jak-project' && startsWith(github.ref, 'refs/tags/') && matrix.compiler == 'clang'
|
||||
|
||||
@@ -120,6 +120,7 @@ set(RUNTIME_SOURCE
|
||||
graphics/opengl_renderer/Sprite3.cpp
|
||||
graphics/opengl_renderer/SpriteRenderer.cpp
|
||||
graphics/opengl_renderer/TextureUploadHandler.cpp
|
||||
graphics/texture/jak1_tpage_dir.cpp
|
||||
graphics/texture/TextureConverter.cpp
|
||||
graphics/texture/TexturePool.cpp
|
||||
graphics/pipelines/opengl.cpp
|
||||
|
||||
@@ -37,12 +37,10 @@ struct SharedRenderState {
|
||||
bool use_sky_cpu = true;
|
||||
bool use_occlusion_culling = true;
|
||||
bool enable_merc_xgkick = true;
|
||||
bool enable_generic_xgkick = true;
|
||||
bool use_direct2 = true;
|
||||
math::Vector<u8, 4> fog_color;
|
||||
float fog_intensity = 1.f;
|
||||
bool no_multidraw = true;
|
||||
bool render_collision_mesh = true;
|
||||
|
||||
void reset();
|
||||
bool has_pc_data = false;
|
||||
|
||||
@@ -24,8 +24,9 @@ void EyeRenderer::init_textures(TexturePool& texture_pool) {
|
||||
in.gpu_texture = gl_tex;
|
||||
in.w = 32;
|
||||
in.h = 32;
|
||||
in.page_name = "PC-EYES";
|
||||
in.name = fmt::format("{}-eye-cpu-{}", lr ? "left" : "right", pair_idx);
|
||||
in.debug_page_name = "PC-EYES";
|
||||
in.debug_name = fmt::format("{}-eye-cpu-{}", lr ? "left" : "right", pair_idx);
|
||||
in.id = texture_pool.allocate_pc_port_texture();
|
||||
auto* gpu_tex = texture_pool.give_texture_and_load_to_vram(in, tbp);
|
||||
m_cpu_eye_textures[tidx] = {gl_tex, gpu_tex, tbp};
|
||||
}
|
||||
@@ -37,8 +38,9 @@ void EyeRenderer::init_textures(TexturePool& texture_pool) {
|
||||
in.gpu_texture = m_gpu_eye_textures[tidx].fb.texture();
|
||||
in.w = 32;
|
||||
in.h = 32;
|
||||
in.page_name = "PC-EYES";
|
||||
in.name = fmt::format("{}-eye-gpu-{}", lr ? "left" : "right", pair_idx);
|
||||
in.debug_page_name = "PC-EYES";
|
||||
in.debug_name = fmt::format("{}-eye-gpu-{}", lr ? "left" : "right", pair_idx);
|
||||
in.id = texture_pool.allocate_pc_port_texture();
|
||||
m_gpu_eye_textures[tidx].gpu_tex = texture_pool.give_texture_and_load_to_vram(in, tbp);
|
||||
m_gpu_eye_textures[tidx].tbp = tbp;
|
||||
}
|
||||
|
||||
@@ -192,13 +192,13 @@ u64 Loader::add_texture(TexturePool& pool, const tfrag3::Texture& tex, bool is_c
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, aniso);
|
||||
if (tex.load_to_pool) {
|
||||
TextureInput in;
|
||||
in.page_name = tex.debug_tpage_name;
|
||||
in.name = tex.debug_name;
|
||||
in.debug_page_name = tex.debug_tpage_name;
|
||||
in.debug_name = tex.debug_name;
|
||||
in.w = tex.w;
|
||||
in.h = tex.h;
|
||||
in.gpu_texture = gl_tex;
|
||||
in.common = is_common;
|
||||
in.combo_id = tex.combo_id;
|
||||
in.id = PcTextureId::from_combo_id(tex.combo_id);
|
||||
in.src_data = (const u8*)tex.data.data();
|
||||
pool.give_texture(in);
|
||||
}
|
||||
@@ -632,7 +632,8 @@ void Loader::update(TexturePool& texture_pool) {
|
||||
for (size_t i = 0; i < lev.second.data.level->textures.size(); i++) {
|
||||
auto& tex = lev.second.data.level->textures[i];
|
||||
if (tex.load_to_pool) {
|
||||
texture_pool.unload_texture(tex.debug_name, lev.second.data.textures.at(i));
|
||||
texture_pool.unload_texture(PcTextureId::from_combo_id(tex.combo_id),
|
||||
lev.second.data.textures.at(i));
|
||||
}
|
||||
}
|
||||
lk.unlock();
|
||||
|
||||
@@ -110,7 +110,7 @@ void OpenGLRenderer::init_bucket_renderers() {
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL0);
|
||||
// 11 : GMERC_TFRAG_TEX_LEVEL0
|
||||
init_bucket_renderer<Generic2>("l0-tfrag-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL0);
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL0, 1500000, 10000, 10000, 800);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 1 tfrag texture
|
||||
@@ -130,7 +130,7 @@ void OpenGLRenderer::init_bucket_renderers() {
|
||||
BucketId::MERC_TFRAG_TEX_LEVEL1);
|
||||
// 18 : GMERC_TFRAG_TEX_LEVEL1
|
||||
init_bucket_renderer<Generic2>("l1-tfrag-generic", BucketCategory::GENERIC,
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL1);
|
||||
BucketId::GENERIC_TFRAG_TEX_LEVEL1, 1500000, 10000, 10000, 800);
|
||||
|
||||
//-----------------------
|
||||
// LEVEL 0 shrub texture
|
||||
@@ -366,12 +366,10 @@ void OpenGLRenderer::draw_renderer_selection_window() {
|
||||
ImGui::Begin("Renderer Debug");
|
||||
|
||||
ImGui::Checkbox("Use old single-draw", &m_render_state.no_multidraw);
|
||||
ImGui::Checkbox("Render collision mesh", &m_render_state.render_collision_mesh);
|
||||
ImGui::SliderFloat("Fog Adjust", &m_render_state.fog_intensity, 0, 10);
|
||||
ImGui::Checkbox("Sky CPU", &m_render_state.use_sky_cpu);
|
||||
ImGui::Checkbox("Occlusion Cull", &m_render_state.use_occlusion_culling);
|
||||
ImGui::Checkbox("Merc XGKICK", &m_render_state.enable_merc_xgkick);
|
||||
ImGui::Checkbox("Generic XGKICK", &m_render_state.enable_generic_xgkick);
|
||||
ImGui::Checkbox("Blackout Loads", &m_enable_fast_blackout_loads);
|
||||
ImGui::Checkbox("Direct 2", &m_render_state.use_direct2);
|
||||
|
||||
@@ -458,7 +456,7 @@ void OpenGLRenderer::dispatch_buckets(DmaFollower dma, ScopedProfilerNode& prof)
|
||||
m_category_times[(int)m_bucket_categories[bucket_id]] += bucket_prof.get_elapsed_time();
|
||||
|
||||
// hack to draw the collision mesh in the middle the drawing
|
||||
if (bucket_id == (int)BucketId::ALPHA_TEX_LEVEL0 - 1 && m_render_state.render_collision_mesh &&
|
||||
if (bucket_id == (int)BucketId::ALPHA_TEX_LEVEL0 - 1 &&
|
||||
Gfx::g_global_settings.collision_enable) {
|
||||
auto p = prof.make_scoped_child("collision-draw");
|
||||
m_collide_renderer.render(&m_render_state, p);
|
||||
|
||||
@@ -194,7 +194,8 @@ void SkyBlendCPU::init_textures(TexturePool& tex_pool) {
|
||||
in.gpu_texture = m_textures[i].gl;
|
||||
in.w = m_sizes[i];
|
||||
in.h = m_sizes[i];
|
||||
in.name = fmt::format("PC-SKY-CPU-{}", i);
|
||||
in.debug_name = fmt::format("PC-SKY-CPU-{}", i);
|
||||
in.id = tex_pool.allocate_pc_port_texture();
|
||||
u32 tbp = SKY_TEXTURE_VRAM_ADDRS[i];
|
||||
m_textures[i].tex = tex_pool.give_texture_and_load_to_vram(in, tbp);
|
||||
m_textures[i].tbp = tbp;
|
||||
|
||||
@@ -65,7 +65,8 @@ void SkyBlendGPU::init_textures(TexturePool& tex_pool) {
|
||||
in.gpu_texture = m_textures[i];
|
||||
in.w = m_sizes[i];
|
||||
in.h = in.w;
|
||||
in.name = fmt::format("PC-SKY-GPU-{}", i);
|
||||
in.debug_name = fmt::format("PC-SKY-GPU-{}", i);
|
||||
in.id = tex_pool.allocate_pc_port_texture();
|
||||
u32 tbp = SKY_TEXTURE_VRAM_ADDRS[i];
|
||||
m_tex_info[i] = {tex_pool.give_texture_and_load_to_vram(in, tbp), tbp};
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ void TextureUploadHandler::render(DmaFollower& dma,
|
||||
// note: these uploads may have texture that we need for eye rendering.
|
||||
flush_uploads(uploads, render_state);
|
||||
render_state->eye_renderer->handle_eye_dma2(dma, render_state, prof);
|
||||
uploads.clear();
|
||||
}
|
||||
|
||||
auto data = dma.read_and_advance();
|
||||
|
||||
@@ -123,8 +123,10 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Reboot in Debug Mode")) {
|
||||
want_reboot_in_debug = true;
|
||||
if (ImGui::BeginMenu("Debug Mode")) {
|
||||
if (ImGui::MenuItem("Reboot now!")) {
|
||||
want_reboot_in_debug = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,9 @@ void OceanTexture::init_textures(TexturePool& pool) {
|
||||
in.gpu_texture = m_result_texture.texture();
|
||||
in.w = TEX0_SIZE;
|
||||
in.h = TEX0_SIZE;
|
||||
in.page_name = "PC-OCEAN";
|
||||
in.name = fmt::format("pc-ocean-mip-{}", m_generate_mipmaps);
|
||||
in.debug_page_name = "PC-OCEAN";
|
||||
in.debug_name = fmt::format("pc-ocean-mip-{}", m_generate_mipmaps);
|
||||
in.id = pool.allocate_pc_port_texture();
|
||||
m_tex0_gpu = pool.give_texture_and_load_to_vram(in, OCEAN_TEX_TBP);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "common/log/log.h"
|
||||
#include "game/graphics/pipelines/opengl.h"
|
||||
#include "common/util/Assert.h"
|
||||
#include "game/graphics/texture/jak1_tpage_dir.h"
|
||||
|
||||
namespace {
|
||||
const char empty_string[] = "";
|
||||
@@ -49,41 +50,33 @@ u64 upload_to_gpu(const u8* data, u16 w, u16 h) {
|
||||
}
|
||||
|
||||
GpuTexture* TexturePool::give_texture(const TextureInput& in) {
|
||||
const auto& it = m_loaded_textures.find(in.name);
|
||||
if (it == m_loaded_textures.end()) {
|
||||
// const auto& it = m_loaded_textures.find(in.name);
|
||||
const auto existing = m_loaded_textures.lookup_or_insert(in.id);
|
||||
if (!existing.second) {
|
||||
// nothing references this texture yet.
|
||||
GpuTexture gtex;
|
||||
gtex.page_name = in.page_name;
|
||||
gtex.name = in.name;
|
||||
gtex.w = in.w;
|
||||
gtex.h = in.h;
|
||||
gtex.is_common = in.common;
|
||||
gtex.gpu_textures = {{in.gpu_texture, in.src_data}};
|
||||
gtex.combo_id = in.combo_id;
|
||||
gtex.is_placeholder = false;
|
||||
|
||||
return &m_loaded_textures.insert({in.name, gtex}).first->second;
|
||||
existing.first->tex_id = in.id;
|
||||
existing.first->w = in.w;
|
||||
existing.first->h = in.h;
|
||||
existing.first->is_common = in.common;
|
||||
existing.first->gpu_textures = {{in.gpu_texture, in.src_data}};
|
||||
existing.first->is_placeholder = false;
|
||||
*m_id_to_name.lookup_or_insert(in.id).first =
|
||||
fmt::format("{}/{}", in.debug_page_name, in.debug_name);
|
||||
return existing.first;
|
||||
} else {
|
||||
if (!it->second.is_placeholder) {
|
||||
fmt::print(
|
||||
"[tex2] loader providing {}, but we already have an entry for it {} common? {} mine "
|
||||
"{}x{} 0x{:x} new {}x{} 0x{:x}.\n",
|
||||
in.name, it->second.name, it->second.is_common, in.w, in.h, in.combo_id, it->second.w,
|
||||
it->second.h, it->second.combo_id);
|
||||
ASSERT(!it->second.gpu_textures.empty());
|
||||
if (!existing.first->is_placeholder) {
|
||||
// two sources for texture. this is fine.
|
||||
ASSERT(!existing.first->gpu_textures.empty());
|
||||
} else {
|
||||
ASSERT(it->second.gpu_textures.empty());
|
||||
ASSERT(existing.first->gpu_textures.empty());
|
||||
}
|
||||
it->second.is_placeholder = false;
|
||||
it->second.page_name = in.page_name;
|
||||
it->second.name = in.name;
|
||||
it->second.w = in.w;
|
||||
it->second.h = in.h;
|
||||
it->second.gpu_textures.push_back({in.gpu_texture, in.src_data});
|
||||
it->second.is_common = in.common;
|
||||
it->second.combo_id = in.combo_id;
|
||||
refresh_links(it->second);
|
||||
return &it->second;
|
||||
existing.first->is_placeholder = false;
|
||||
existing.first->w = in.w;
|
||||
existing.first->h = in.h;
|
||||
existing.first->gpu_textures.push_back({in.gpu_texture, in.src_data});
|
||||
existing.first->is_common = in.common;
|
||||
refresh_links(*existing.first);
|
||||
return existing.first;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,25 +126,27 @@ void TexturePool::refresh_links(GpuTexture& texture) {
|
||||
}
|
||||
}
|
||||
|
||||
void TexturePool::unload_texture(const std::string& name, u64 id) {
|
||||
auto& tex = m_loaded_textures.at(name);
|
||||
if (tex.is_common) {
|
||||
void TexturePool::unload_texture(PcTextureId tex_id, u64 gpu_id) {
|
||||
auto* tex = m_loaded_textures.lookup_existing(tex_id);
|
||||
ASSERT(tex);
|
||||
if (tex->is_common) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
if (tex.is_placeholder) {
|
||||
fmt::print("trying to unload something that was already placholdered: {} {}\n", name,
|
||||
tex.gpu_textures.size());
|
||||
if (tex->is_placeholder) {
|
||||
fmt::print("trying to unload something that was already placholdered: {} {}\n",
|
||||
get_debug_texture_name(tex_id), tex->gpu_textures.size());
|
||||
}
|
||||
ASSERT(!tex.is_placeholder);
|
||||
auto it = std::find_if(tex.gpu_textures.begin(), tex.gpu_textures.end(),
|
||||
[&](const auto& a) { return a.gl == id; });
|
||||
ASSERT(it != tex.gpu_textures.end());
|
||||
tex.gpu_textures.erase(it);
|
||||
if (tex.gpu_textures.empty()) {
|
||||
tex.is_placeholder = true;
|
||||
ASSERT(!tex->is_placeholder);
|
||||
auto it = std::find_if(tex->gpu_textures.begin(), tex->gpu_textures.end(),
|
||||
[&](const auto& a) { return a.gl == gpu_id; });
|
||||
ASSERT(it != tex->gpu_textures.end());
|
||||
|
||||
tex->gpu_textures.erase(it);
|
||||
if (tex->gpu_textures.empty()) {
|
||||
tex->is_placeholder = true;
|
||||
}
|
||||
refresh_links(tex);
|
||||
refresh_links(*tex);
|
||||
}
|
||||
|
||||
void GpuTexture::remove_slot(u32 slot) {
|
||||
@@ -208,19 +203,26 @@ void TexturePool::handle_upload_now(const u8* tpage, int mode, const u8* memory_
|
||||
// each texture may have multiple mip levels.
|
||||
for (int mip_idx = 0; mip_idx < tex.num_mips; mip_idx++) {
|
||||
if (has_segment[tex.segment_of_mip(mip_idx)]) {
|
||||
auto name = std::string(goal_string(texture_page.name_ptr, memory_base)) +
|
||||
goal_string(tex.name_ptr, memory_base);
|
||||
PcTextureId current_id(texture_page.id, tex_idx);
|
||||
if (!m_id_to_name.lookup_existing(current_id)) {
|
||||
auto name = std::string(goal_string(texture_page.name_ptr, memory_base)) +
|
||||
goal_string(tex.name_ptr, memory_base);
|
||||
*m_id_to_name.lookup_or_insert(current_id).first = name;
|
||||
m_name_to_id[name] = current_id;
|
||||
}
|
||||
|
||||
auto& slot = m_textures[tex.dest[mip_idx]];
|
||||
|
||||
if (slot.source) {
|
||||
if (slot.source->name == name) {
|
||||
if (slot.source->tex_id == current_id) {
|
||||
// we already have it, no need to do anything
|
||||
} else {
|
||||
slot.source->remove_slot(tex.dest[mip_idx]);
|
||||
slot.source = get_gpu_texture_for_slot(name, tex.dest[mip_idx]);
|
||||
slot.source = get_gpu_texture_for_slot(current_id, tex.dest[mip_idx]);
|
||||
ASSERT(slot.gpu_texture != (u64)-1);
|
||||
}
|
||||
} else {
|
||||
slot.source = get_gpu_texture_for_slot(name, tex.dest[mip_idx]);
|
||||
slot.source = get_gpu_texture_for_slot(current_id, tex.dest[mip_idx]);
|
||||
ASSERT(slot.gpu_texture != (u64)-1);
|
||||
}
|
||||
}
|
||||
@@ -246,18 +248,19 @@ void TexturePool::relocate(u32 destination, u32 source, u32 format) {
|
||||
}
|
||||
}
|
||||
|
||||
GpuTexture* TexturePool::get_gpu_texture_for_slot(const std::string& name, u32 slot) {
|
||||
auto it = m_loaded_textures.find(name);
|
||||
if (it == m_loaded_textures.end()) {
|
||||
GpuTexture placeholder;
|
||||
placeholder.name = name;
|
||||
GpuTexture* TexturePool::get_gpu_texture_for_slot(PcTextureId id, u32 slot) {
|
||||
auto it = m_loaded_textures.lookup_or_insert(id);
|
||||
if (!it.second) {
|
||||
GpuTexture& placeholder = *it.first;
|
||||
placeholder.tex_id = id;
|
||||
placeholder.is_placeholder = true;
|
||||
placeholder.slots.push_back(slot);
|
||||
auto r = m_loaded_textures.insert({name, placeholder});
|
||||
|
||||
// auto r = m_loaded_textures.insert({name, placeholder});
|
||||
m_textures[slot].gpu_texture = m_placeholder_texture_id;
|
||||
return &r.first->second;
|
||||
return it.first;
|
||||
} else {
|
||||
auto result = &it->second;
|
||||
auto result = it.first;
|
||||
result->add_slot(slot);
|
||||
m_textures[slot].gpu_texture =
|
||||
result->is_placeholder ? m_placeholder_texture_id : result->gpu_textures.at(0).gl;
|
||||
@@ -276,7 +279,8 @@ std::optional<u64> TexturePool::lookup_mt4hh(u32 location) {
|
||||
return {};
|
||||
}
|
||||
|
||||
TexturePool::TexturePool() {
|
||||
TexturePool::TexturePool()
|
||||
: m_loaded_textures(get_jak1_tpage_dir()), m_id_to_name(get_jak1_tpage_dir()) {
|
||||
m_placeholder_data.resize(16 * 16);
|
||||
u32 c0 = 0xa0303030;
|
||||
u32 c1 = 0xa0e0e0e0;
|
||||
@@ -301,14 +305,17 @@ void TexturePool::draw_debug_window() {
|
||||
auto& record = m_textures[i];
|
||||
total_textures++;
|
||||
if (record.source) {
|
||||
if (std::regex_search(record.source->name, regex)) {
|
||||
if (std::regex_search(get_debug_texture_name(record.source->tex_id), regex)) {
|
||||
ImGui::PushID(id++);
|
||||
draw_debug_for_tex(record.source->name, record.source, i);
|
||||
draw_debug_for_tex(get_debug_texture_name(record.source->tex_id), record.source, i);
|
||||
ImGui::PopID();
|
||||
total_displayed_textures++;
|
||||
}
|
||||
total_vram_bytes +=
|
||||
record.source->w * record.source->h * 4; // todo, if we support other formats
|
||||
if (!record.source->gpu_textures.empty()) {
|
||||
total_vram_bytes +=
|
||||
record.source->w * record.source->h * 4; // todo, if we support other formats
|
||||
}
|
||||
|
||||
total_uploaded_textures++;
|
||||
}
|
||||
}
|
||||
@@ -328,7 +335,7 @@ void TexturePool::draw_debug_for_tex(const std::string& name, GpuTexture* tex, u
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8, 0.8, 0.3, 1.0));
|
||||
}
|
||||
if (ImGui::TreeNode(fmt::format("{} {}", name, slot).c_str())) {
|
||||
ImGui::Text("P: %s sz: %d x %d", tex->page_name.c_str(), tex->w, tex->h);
|
||||
ImGui::Text("P: %s sz: %d x %d", get_debug_texture_name(tex->tex_id).c_str(), tex->w, tex->h);
|
||||
if (!tex->is_placeholder) {
|
||||
ImGui::Image((void*)tex->gpu_textures.at(0).gl, ImVec2(tex->w, tex->h));
|
||||
} else {
|
||||
@@ -339,4 +346,18 @@ void TexturePool::draw_debug_for_tex(const std::string& name, GpuTexture* tex, u
|
||||
ImGui::Separator();
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
PcTextureId TexturePool::allocate_pc_port_texture() {
|
||||
ASSERT(m_next_pc_texture_to_allocate < EXTRA_PC_PORT_TEXTURE_COUNT);
|
||||
return PcTextureId(get_jak1_tpage_dir().size() - 1, m_next_pc_texture_to_allocate++);
|
||||
}
|
||||
|
||||
std::string TexturePool::get_debug_texture_name(PcTextureId id) {
|
||||
auto it = m_id_to_name.lookup_existing(id);
|
||||
if (it) {
|
||||
return *it;
|
||||
} else {
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "game/graphics/texture/TextureConverter.h"
|
||||
#include "common/util/Serializer.h"
|
||||
#include "common/util/SmallVector.h"
|
||||
|
||||
// verify all texture lookups.
|
||||
// will make texture lookups slower and likely caused dropped frames when loading
|
||||
@@ -67,6 +68,71 @@ constexpr int SKY_TEXTURE_VRAM_ADDRS[2] = {8064, 8096};
|
||||
* The game will inform us when it uploads to VRAM
|
||||
*/
|
||||
|
||||
struct PcTextureId {
|
||||
u16 page = -1;
|
||||
u16 tex = -1;
|
||||
|
||||
PcTextureId(u16 p, u16 t) : page(p), tex(t) {}
|
||||
PcTextureId() = default;
|
||||
|
||||
static PcTextureId from_combo_id(u32 val) { return PcTextureId(val >> 16, val & 0xffff); }
|
||||
|
||||
bool operator==(const PcTextureId& other) const { return page == other.page && tex == other.tex; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TextureMap {
|
||||
public:
|
||||
TextureMap(const std::vector<u32>& tpage_dir) {
|
||||
u32 off = 0;
|
||||
for (auto& x : tpage_dir) {
|
||||
m_dir.push_back(off);
|
||||
off += x;
|
||||
}
|
||||
m_data.resize(off);
|
||||
}
|
||||
|
||||
T* lookup_existing(PcTextureId id) {
|
||||
auto& elt = m_data[m_dir[id.page] + id.tex];
|
||||
if (elt.present) {
|
||||
return &elt.val;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
T& at(PcTextureId id) {
|
||||
auto& elt = m_data[m_dir[id.page] + id.tex];
|
||||
if (elt.present) {
|
||||
return elt.val;
|
||||
}
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
std::pair<T*, bool> lookup_or_insert(PcTextureId id) {
|
||||
auto& elt = m_data[m_dir[id.page] + id.tex];
|
||||
if (elt.present) {
|
||||
return std::make_pair(&elt.val, true);
|
||||
} else {
|
||||
elt.present = true;
|
||||
return std::make_pair(&elt.val, false);
|
||||
}
|
||||
}
|
||||
|
||||
void erase(PcTextureId id) {
|
||||
auto& elt = m_data[m_dir[id.page] + id.tex];
|
||||
elt.present = false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<u32> m_dir;
|
||||
struct Element {
|
||||
T val;
|
||||
bool present = false;
|
||||
};
|
||||
std::vector<Element> m_data;
|
||||
};
|
||||
|
||||
/*!
|
||||
* The lowest level reference to texture data.
|
||||
*/
|
||||
@@ -80,8 +146,9 @@ struct TextureData {
|
||||
* It's possible for there to be 0 instances of the texture loaded yet.
|
||||
*/
|
||||
struct GpuTexture {
|
||||
std::string page_name;
|
||||
std::string name;
|
||||
GpuTexture(PcTextureId id) : tex_id(id) {}
|
||||
GpuTexture() = default;
|
||||
PcTextureId tex_id;
|
||||
|
||||
// all the currently loaded copies of this texture
|
||||
std::vector<TextureData> gpu_textures;
|
||||
@@ -92,9 +159,6 @@ struct GpuTexture {
|
||||
// the vram address that contain this texture, stored in mt4hh format
|
||||
std::vector<u32> mt4hh_slots;
|
||||
|
||||
// our "combo id", containing the tpage and texture ID
|
||||
u32 combo_id = -1;
|
||||
|
||||
// texture dimensions
|
||||
u16 w, h;
|
||||
|
||||
@@ -137,11 +201,13 @@ struct TextureVRAMReference {
|
||||
* A texture provided by the loader.
|
||||
*/
|
||||
struct TextureInput {
|
||||
std::string page_name;
|
||||
std::string name;
|
||||
std::string debug_page_name;
|
||||
std::string debug_name;
|
||||
|
||||
PcTextureId id;
|
||||
|
||||
u64 gpu_texture = -1;
|
||||
bool common = false;
|
||||
u32 combo_id = -1;
|
||||
const u8* src_data;
|
||||
u16 w, h;
|
||||
};
|
||||
@@ -236,7 +302,7 @@ class TexturePool {
|
||||
void handle_upload_now(const u8* tpage, int mode, const u8* memory_base, u32 s7_ptr);
|
||||
GpuTexture* give_texture(const TextureInput& in);
|
||||
GpuTexture* give_texture_and_load_to_vram(const TextureInput& in, u32 vram_slot);
|
||||
void unload_texture(const std::string& name, u64 id);
|
||||
void unload_texture(PcTextureId tex_id, u64 gpu_id);
|
||||
|
||||
/*!
|
||||
* Look up an OpenGL texture by vram address. Return std::nullopt if the game hasn't loaded
|
||||
@@ -284,10 +350,13 @@ class TexturePool {
|
||||
void move_existing_to_vram(GpuTexture* tex, u32 slot_addr);
|
||||
|
||||
std::mutex& mutex() { return m_mutex; }
|
||||
PcTextureId allocate_pc_port_texture();
|
||||
|
||||
std::string get_debug_texture_name(PcTextureId id);
|
||||
|
||||
private:
|
||||
void refresh_links(GpuTexture& texture);
|
||||
GpuTexture* get_gpu_texture_for_slot(const std::string& name, u32 slot);
|
||||
GpuTexture* get_gpu_texture_for_slot(PcTextureId id, u32 slot);
|
||||
|
||||
char m_regex_input[256] = "";
|
||||
std::array<TextureVRAMReference, 1024 * 1024 * 4 / 256> m_textures;
|
||||
@@ -300,7 +369,14 @@ class TexturePool {
|
||||
std::vector<u32> m_placeholder_data;
|
||||
u64 m_placeholder_texture_id = 0;
|
||||
|
||||
std::unordered_map<std::string, GpuTexture> m_loaded_textures;
|
||||
TextureMap<GpuTexture> m_loaded_textures;
|
||||
|
||||
// we maintain a mapping of all textures/ids we've seen so far.
|
||||
// this is only used for debug.
|
||||
TextureMap<std::string> m_id_to_name;
|
||||
std::unordered_map<std::string, PcTextureId> m_name_to_id;
|
||||
|
||||
u32 m_next_pc_texture_to_allocate = 0;
|
||||
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "jak1_tpage_dir.h"
|
||||
namespace {
|
||||
|
||||
std::vector<u32> tpage_dir = {
|
||||
0x0, 0x2, 0x37, 0x1, 0x1, 0x10, 0x2, 0x4, 0x3, 0x2, 0x1, 0x5, 0x7, 0x8, 0x1, 0x1, 0x1, 0xb, 0xe,
|
||||
0x8, 0x1, 0x6, 0x4, 0x6, 0x3, 0x3, 0x6, 0x6, 0x4, 0x4, 0x4, 0xd, 0x1, 0x4, 0x9, 0xc, 0x1, 0x1,
|
||||
0x6, 0x3, 0x2, 0x14, 0x1, 0x1, 0x2, 0x2, 0x34, 0x34, 0x4, 0x15, 0x1, 0x1, 0x1, 0x8, 0x6, 0xb,
|
||||
0xb, 0x7, 0x17, 0x1, 0x7, 0x20, 0xd, 0xa, 0x1, 0x1, 0xb, 0x11, 0x2, 0x9, 0xb, 0xa, 0xe, 0x1,
|
||||
0x6, 0x6, 0x1, 0x2, 0x2, 0x33, 0x33, 0xd, 0x2, 0x9, 0x4, 0x68, 0x1, 0x9, 0x1, 0x2, 0x1, 0x5,
|
||||
0x9, 0x7, 0x14, 0xa, 0x1, 0x1, 0x1, 0x2, 0x10, 0x4, 0x2, 0x17, 0x2, 0x1, 0x13, 0x6, 0x1, 0x1,
|
||||
0x1, 0x2, 0x1, 0x16, 0x1, 0x5, 0x1, 0xe, 0x3, 0x2, 0x1, 0x9, 0x15, 0x3, 0x1, 0x2, 0x40, 0x6,
|
||||
0xb, 0x9, 0x2, 0x8, 0xf, 0x2, 0x2, 0x7, 0x11, 0x5, 0x7, 0x13, 0x9, 0x1, 0x1, 0x1, 0x8, 0x1, 0x1,
|
||||
0x1, 0x1, 0x1, 0x2, 0x2, 0x9, 0x2, 0xb, 0x5, 0x1, 0xa, 0x15, 0x2e, 0x4, 0x22, 0xb, 0x2e, 0x1e,
|
||||
0x6, 0x4, 0x6, 0x3, 0x3, 0x6, 0x6, 0x2, 0x19, 0x5, 0x5, 0x8, 0x37, 0x15, 0x2, 0x1, 0x1, 0x4,
|
||||
0x4, 0x8, 0x9, 0x9, 0x9, 0x9, 0x8, 0x6, 0x1e, 0x7, 0x1, 0x5, 0x9, 0x72, 0xc, 0x5, 0x16, 0x5,
|
||||
0x4, 0x1, 0x6, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1, 0x1c, 0xa3, 0x47, 0x1b, 0xc9, 0xa, 0x1, 0x16, 0x1,
|
||||
0x4, 0x4, 0x4, 0x4, 0x4, 0xd, 0x4, 0xc, 0x2d, 0x4, 0x1, 0x1, 0xf, 0x2, 0x2, 0x10, 0x3, 0x3, 0x1,
|
||||
0x1, 0x1, 0x1, 0x1, 0x4, 0x4, 0x9, 0x9, 0x5, 0x6, 0xa, 0x4, 0x1, 0x5, 0x4, 0x9, 0x2, 0x1, 0x4,
|
||||
0x2, 0x2, 0x3, 0x12, 0xa, 0x8, 0x4, 0x5, 0x1, 0x1, 0x6, 0x6, 0x7, 0xf, 0x1d, 0x4, 0x4, 0x93,
|
||||
0x1, 0x2, 0x15, 0x1, 0xc, 0x1, 0xb, 0x1, 0x5, 0x1e, 0x1, 0x3c, 0x10, 0x5, 0x4, 0x5, 0x3, 0xb,
|
||||
0x4, 0x8, 0x4, 0x4, 0x9, 0x6, 0x3, 0x1d, 0x2e, 0x1, 0x3, 0x15, 0xb, 0x1, 0x1, 0x1, 0x2, 0x1,
|
||||
0x1, 0x1, 0x1, 0x9, 0x8, 0x1a, 0x5, 0xe, 0x1, 0x1e, 0xc, 0x57, 0x71, 0x1, 0x4, 0x8, 0x5, 0x15,
|
||||
0x7, 0xa, 0x1f, 0xc, 0x6, 0x12, 0x1, 0x2, 0x9, 0x4c, 0xa, 0xc9, 0x1, 0x8, 0x8, 0x1b, 0x8, 0x1d,
|
||||
0x15, 0x1, 0x19, 0x97, 0x6c, 0xd, 0x3, 0x4, 0x4, 0x2, 0x2, 0x3d, 0xa, 0x36, 0x4, 0x8, 0x21,
|
||||
0x15, 0x1, 0x1, 0x2, 0x6, 0x2, 0xb, 0x6, 0xb, 0xc, 0x5, 0x4, 0x15, 0x14, 0x1, 0x21, 0x5, 0x6,
|
||||
0xb, 0x1, 0x1b, 0x57, 0x1e, 0x2, 0xc, 0x16, 0x9, 0x5, 0x9, 0x1, 0x1, 0x2f, 0x1a, 0x9, 0x80,
|
||||
0x19, 0x97, 0xd, 0x26, 0x8, 0xb, 0x8, 0x1, 0x6, 0x4, 0x1, 0x2, 0x1c, 0x9, 0x13, 0xe, 0x8, 0x1,
|
||||
0x1, 0x8, 0x4, 0x6, 0x1, 0xd, 0x6, 0x1c, 0x8, 0x1, 0x1d, 0x1, 0x3, 0x4, 0x2, 0x2, 0x1, 0x1,
|
||||
0x12, 0x3d, 0x13, 0x5, 0x1, 0x25, 0x1, 0x1, 0xb, 0xa, 0x1, 0xe, 0x1, 0xb, 0xa, 0xb, 0x1, 0x38,
|
||||
0x5, 0x8, 0x1, 0x2, 0x51, 0xc, 0x2, 0x1, 0x5, 0x2, 0x7a, 0x5, 0x5, 0x1, 0x1, 0x2, 0x1, 0x1, 0x7,
|
||||
0xe, 0xd, 0x2, 0x4, 0x1, 0x1, 0xc, 0x5, 0x3, 0x1, 0x2, 0x24, 0x15, 0x24, 0x8, 0x11, 0x1, 0x1,
|
||||
0x1, 0x5, 0x1, 0x1, 0x8, 0x2, 0x2, 0x1, 0x1, 0xb, 0xa, 0xa, 0x5, 0x1, 0x1d, 0x4, 0x6, 0x2, 0x4,
|
||||
0x9, 0x15, 0x4, 0x4, 0x1, 0x6, 0x2, 0x5c, 0x70, 0x9, 0x1, 0xc, 0x74, 0x5, 0x2, 0x7, 0x2, 0x4,
|
||||
0x2, 0x5, 0x19, 0x1, 0x71, 0x4, 0x8, 0x6, 0x2, 0x2, 0x2, 0x11, 0x11, 0x2, 0x6, 0x5, 0xa, 0x2,
|
||||
0x1, 0x2, 0x4, 0xf, 0x3b, 0x2, 0x5, 0x5, 0x4, 0x5, 0x4, 0xf, 0xd, 0x2, 0x2, 0x2, 0x7, 0x3f, 0xc,
|
||||
0x9, 0x3a, 0xa, 0x15, 0x14, 0x4, 0x4, 0x1, 0xa, 0x9, 0x8, 0x1, 0x7, 0x5b, 0x9, 0x13, 0x1c, 0x18,
|
||||
0x5, 0x5, 0x6, 0x18, 0x4, 0x8, 0x14, 0x3a, 0x13, 0x1, 0x43, 0x4, 0x3, 0x17, 0x1, 0x16, 0x15,
|
||||
0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8a, 0x1, 0x4, 0x1, 0x1, 0x8, 0x1, 0x1, 0x1, 0x1, 0x9, 0x6, 0x6,
|
||||
0x1, 0x13, 0xa, 0x10, 0x5, 0x3, 0x6, 0x6, 0x3, 0x3, 0x4, 0xf, 0x13, 0xb, 0x3, 0x1, 0x1, 0x3,
|
||||
0x3, 0x3, 0x14, 0x13, 0x6, 0x15, 0xa, 0x1, 0x5, 0x4, 0x1, 0x2, 0x5, 0x2, 0xd, 0x9, 0xf, 0x5d,
|
||||
0x9, 0x47, 0xd, 0x6, 0x5, 0x5d, 0xa, 0x47, 0x15, 0x42, 0x9, 0x6, 0x3, 0x5, 0x2, 0xe, 0xd, 0x11,
|
||||
0x4, 0x5, 0x2, 0x1, 0x15, 0x1, 0x1, 0x4, 0x2, 0x13, 0xf, 0x11, 0x11, 0x2, 0xa, 0x9, 0x5, 0x5,
|
||||
0x7, 0x5, 0x4, 0x3, 0x4, 0x13, 0x5, 0xb, 0x1, 0x12, 0x12, 0x4, 0x13, 0x1, 0x1, 0x1, 0x1, 0xc,
|
||||
0x11, 0x9, 0x5b, 0xa, 0x13, 0xd, 0xa, 0x8, 0x1, 0x1, 0x2, 0x9, 0x6, 0x1, 0x1, 0x1, 0x2, 0x1,
|
||||
0x1, 0xa, 0x9, 0x2, 0xf, 0x1, 0x8, 0x3, 0x9, 0x3, 0x1, 0x9, 0x6, 0x6, 0x5, 0x2, 0x5, 0x2, 0x5,
|
||||
0x3, 0x1, 0x57, 0x3, 0x1, 0x1, 0x7, 0x3, 0x1, 0x9, 0x7, 0x3, 0x3, 0x3, 0xb1, 0x2, 0x1, 0x12,
|
||||
0x2b, 0x3, 0x1, 0x3, 0x2, 0x4, 0x1, 0x2, 0x5, 0x6, 0xd, 0x1, 0x1, 0x1, 0x2, 0x2, 0x6, 0x5, 0x2,
|
||||
0x2, 0x2, 0x10, 0x1, 0x1, 0x24, 0x1, 0x1, 0x1, 0x1, 0x6, 0x4, 0x7, 0x21, 0x2, 0x9, 0xa, 0xa,
|
||||
0x16, 0xb, 0x34, 0x5, 0x3, 0x10, 0x1, 0x1, 0x2e, 0x13, 0x2, 0x13, 0x1, 0x1, 0x1, 0x25, 0x13,
|
||||
0x4, 0x47, 0x8, 0x7, 0x4, 0x35, 0x1, 0xb, 0x19, 0x2, 0x2, 0x8, 0x8, 0x7, 0x10, 0xd, 0x6, 0x6,
|
||||
0xa, 0x3, 0x6a, 0x13, 0x18, 0x12, 0x3, 0x57, 0x1d, 0x1, 0xb, 0x5, 0x4, 0x7, 0x1, 0x1, 0x2, 0x2,
|
||||
0x2, 0x7, 0x15, 0x2f, 0x1, 0x2, 0xb, 0x4, 0x4, 0x3, 0x5, 0xb, 0xa, 0x9, 0x1, 0x4, 0x5, 0x3, 0x3,
|
||||
0x3, 0xb, 0x1b, 0x32, 0x9, 0x4, 0x4, 0x1, 0x1, 0x15, 0x1d, 0x13, 0x12, 0x6, 0xe, 0x4, 0x2, 0x7,
|
||||
0x2, 0xc, 0x6, 0x2, 0x5, 0x3, 0x3, 0x9, 0x7, 0xe, 0x9, 0x2, 0x1, 0x3, 0x5, 0x3, 0x3, 0x4, 0x4,
|
||||
0x3, 0x6, 0x5, 0x5, 0x19, 0x6, 0x3, 0x1, 0x11, 0x12, 0x84, 0x1c, 0x19, 0xa3, 0x2e, 0xe, 0x13,
|
||||
0x47, 0x1, 0x1, 0xc, 0x2, 0x1, 0x5, 0x4, 0x5, 0x4, 0x8, 0x7, 0x7, 0x5, 0x5, 0x3, 0xa, 0x5, 0x3,
|
||||
0x5, 0x4, 0x1, 0x6, 0x4, 0x4, 0x1, 0xe, 0x7, 0x2, 0x15, 0x2, 0x2, 0x14, 0x1, 0xc, 0xa, 0x5d,
|
||||
0x4, 0x3, 0x2, 0xa, 0x5d, 0x19, 0x1, 0x2, 0x1, 0x1, 0xa, 0x14, 0x1, 0x12, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x17, 0x1, 0x1, 0x13, 0x2, 0x2, 0x1, 0x3, 0x1a, 0x5, 0x15, 0x1, 0x5, 0x1, 0x1a, 0x2,
|
||||
0x1, 0xc, 0x6, 0x1, 0x1, 0x1, 0x1, 0x7, 0x7, 0x7, 0xc, 0xd, 0xd, 0x10, 0x1b, 0x1, 0x1, 0x1, 0x1,
|
||||
0x1, 0x1, 0x5, 0x2, 0x4d, 0x2b, 0x8, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0xe, 0xb, 0xa, 0x1,
|
||||
0xb, 0x1, 0xb, 0xa, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x1, 0x1, 0x15, 0x11, 0x1, 0x8,
|
||||
0x1, 0x5, 0x1, 0x1, 0x5, 0x4, 0x4, 0x5, 0xb, 0x6, 0x7, 0x2, 0x1, 0x1, 0x2, 0x1, 0x19, 0x19, 0x2,
|
||||
0x2, 0x2, 0x6, 0x8, 0x3, 0x3, 0x4, 0x8, 0x8, 0x3, 0x1, 0x1a, 0xe, 0x3, 0x1, 0xf, 0x1, 0x9, 0x4,
|
||||
0xc, 0x5, 0x5, 0x6, 0x1, 0x3b, 0x16, 0x8, 0x7, 0x2, 0x5, 0x32, 0xd, 0x2, 0x55, 0xe, 0x3, 0x14,
|
||||
0x3, 0x9, 0x9, 0x3, 0x2, 0x12, 0x12, 0x8, 0x14, 0x13, 0x12, 0x12, 0x9, 0xa, 0x39, 0xf, 0x7, 0x6,
|
||||
0x2, 0x1, 0x5, 0x9, 0x9, 0x9, 0x1, 0x9, 0xe, 0x18, 0x1, 0x3, 0x9, 0x3, 0x9, 0x1, 0x4, 0x2, 0x4,
|
||||
0x4, 0x2, 0x9, 0x9, 0x9, 0x3, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x16, 0x5, 0x2,
|
||||
0x2, 0x3, 0x1, 0x9, 0x3, 0x3f, 0x28, 0x9, 0x26, 0x9, 0xa, 0x65, 0x39, 0xc, 0x15, 0x9, 0x1, 0x2,
|
||||
0x7, 0xb, 0xc, 0xb, 0xb, 0x2e, 0x4, 0x1e, 0x15, 0x1, 0x2, 0x1, 0x1, 0x2, 0x3, 0x2, 0x2, 0xb,
|
||||
0x9, 0x1, 0x4, 0x4, 0x65, 0x16, 0x8f, 0x1, 0x10, 0xf, 0xf, 0x7, 0x9, 0x41, 0x9, 0xb, 0xb, 0xe,
|
||||
0x12, 0x20, 0x2, 0x2, 0x2, 0x2, 0x2, 0x9, 0x15, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
|
||||
0x1, 0x1, 0x1, 0xa, 0xd, 0xd, 0x9, 0x1, 0x1, 0xd, 0x68, 0x17, 0x94, 0x1, 0xf, 0x1, 0x1, 0x1,
|
||||
0xd, 0x79, 0x17, 0x94, 0xd, 0xf, 0x10, 0x16, 0xf, 0x13, 0xd, 0xc, 0x10, 0xb, 0x8, 0x4, 0x2, 0x2,
|
||||
0x1, 0xb, 0x4, 0x9, 0x61, 0x1, 0x2, 0x7, 0xb, 0xb, 0xf, 0xa, 0x1d, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
|
||||
0x2, 0x2, 0x10, 0x4, 0x5, 0x1, 0x9, 0x9, 0x1, 0x9, 0x3, 0x3f, 0x13, 0x9, 0x41, 0xa, 0x20, 0x9,
|
||||
0x3f, 0xc, 0x3a, 0x9, 0xa, 0x63, 0x39, 0x1, 0xb, 0xb, 0x1, 0xa, 0x6, 0x1, 0x4, 0x4, 0x4, 0x18,
|
||||
0xa, 0x39, 0x10, 0x19, 0x7, 0x8, 0x9, 0x53, 0x6, 0x2b, 0x1, 0x2, 0x1, 0x2, 0x5, 0x3, 0x1, 0x1,
|
||||
0x2, 0xd, 0x9, 0x2, 0x1, 0x17, 0x3, 0x1, 0xc, 0xf, 0x10, 0x16, 0x1, 0xd, 0x9, 0x4, 0x7, 0xd,
|
||||
0xb, 0xd, 0xc, 0xc, 0x1a, 0x2, 0xc, 0x15, 0x2, 0x2, 0xd, 0x1, 0x1, 0xa, 0x8, 0x8, 0xa, 0xa, 0xa,
|
||||
0x8, 0x7, 0xd, 0x9, 0x2, 0x3, 0xf, 0xb, 0xf, 0xf, 0x1, 0xd, 0xa, 0x14, 0x11, 0x16, 0x12, 0x1,
|
||||
0x7, 0x1, 0x2, 0x2, 0x1, 0x9, 0x9, 0x2, 0x2, 0x3, 0x9, 0x61, 0x5, 0xb1, 0x12, 0x2a, 0x4a, 0x6,
|
||||
0x2, 0x6, 0x13, 0x13, 0x1, 0x2f, 0xb, 0x12, 0x9, 0x3e, 0x4, 0x28, 0x2, 0x1, 0x4, 0x5, 0x3, 0x3,
|
||||
0x4, 0x1, 0xf, 0x19, 0x10, 0x1, 0x1, 0x1, 0x1, 0x1, 0x9, 0x17, 0x27, 0x3, 0x9, 0x7, 0x3, 0x27,
|
||||
0x2, 0x1, 0x5, 0x6, 0xe, 0x8, 0x8, 0x1, 0x8, 0x9, 0x3, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1a, 0x1,
|
||||
0x10, 0x3, 0x9, 0x1, 0x9, 0x9, 0x9, 0x9, 0x3, 0x3, 0x3, 0x19, 0x9, 0x3a, 0x3, 0x1, 0x5, 0x11,
|
||||
0xa, 0xa, 0x1, 0x11, 0x1, 0x1, 0x1, 0x4, 0x4, 0x4, 0x6, 0x9, 0x9, 0x2, 0x3, 0xa, 0xf, 0x8, 0x6,
|
||||
0x7, 0xb, 0x9, 0xa, 0x5, 0xa, 0x5, 0x9, 0x6, 0x9, 0x4, 0x1, 0x3, 0x3, 0x4, 0x4, 0x3, 0x3, 0xa,
|
||||
0x11, 0x9, 0xe, 0x11, 0xe, 0x8, 0x7, 0x8, 0x7, 0x8, 0x4, 0x5, 0x6, 0x5, 0xa, 0x5, 0xe, 0xd, 0x5,
|
||||
0xe, 0xd, 0x5, 0x5, 0x5, 0x6, 0x5, 0x6, 0xf, 0x8, 0x8, 0x7, 0x6, 0x8, 0x3, 0x1, 0x5, 0x1, 0x1,
|
||||
0x4, 0x4, 0x1, 0x1, 0x9, 0x2, 0xd, 0x7, 0xc, 0xc, 0xa, 0x6, 0x4, 0x1, 0x1, 0x3, 0x2, 0x9, 0x4,
|
||||
0x2, 0x2, 0x4, 0x4, 0x1, 0x4, 0x2, 0x21, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2,
|
||||
0x3,
|
||||
// Pc port texture page:
|
||||
EXTRA_PC_PORT_TEXTURE_COUNT};
|
||||
}
|
||||
|
||||
const std::vector<u32> get_jak1_tpage_dir() {
|
||||
return tpage_dir;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
||||
const std::vector<u32> get_jak1_tpage_dir();
|
||||
constexpr u32 EXTRA_PC_PORT_TEXTURE_COUNT = 50;
|
||||
@@ -344,12 +344,12 @@ void pc_game_load_open_file(FILE* fd) {
|
||||
mc_print("closing save file..");
|
||||
if (fclose(fd) == 0) {
|
||||
// cb_closedload //
|
||||
p2++;
|
||||
// added : check if aux bank exists
|
||||
auto new_bankname = file_util::get_user_memcard_dir() / filename[op.param2 * 2 + 4 + p2];
|
||||
bool aux_exists = std::filesystem::exists(new_bankname);
|
||||
if (p2 < 2 && aux_exists) {
|
||||
if (p2 < 1 && std::filesystem::exists(file_util::get_user_memcard_dir() /
|
||||
filename[op.param2 * 2 + 4 + p2 + 1])) {
|
||||
p2++;
|
||||
mc_print("reading next save bank {}", filename[op.param2 * 2 + 4 + p2]);
|
||||
auto new_bankname = file_util::get_user_memcard_dir() / filename[op.param2 * 2 + 4 + p2];
|
||||
auto new_fd = fopen(new_bankname.string().c_str(), "rb");
|
||||
pc_game_load_open_file(new_fd);
|
||||
} else {
|
||||
@@ -365,7 +365,7 @@ void pc_game_load_open_file(FILE* fd) {
|
||||
(McHeader*)(op.data_ptr.c() + BANK_TOTAL_SIZE + sizeof(McHeader) + BANK_SIZE);
|
||||
static_assert(BANK_TOTAL_SIZE * 2 == 0x21000, "save layout");
|
||||
ok[0] = true;
|
||||
ok[1] = aux_exists;
|
||||
ok[1] = p2 == 1;
|
||||
|
||||
for (int idx = 0; idx < 2; idx++) {
|
||||
u32 expected_save_count = headers[idx]->save_count;
|
||||
|
||||
Reference in New Issue
Block a user