[graphics] small improvements (#1351)

* faster texture upload lookup

* fix debug menu

* cleanup

* one more
This commit is contained in:
water111
2022-05-02 21:26:17 -04:00
committed by GitHub
parent 4d634cf50d
commit e8911758f0
16 changed files with 316 additions and 102 deletions
+3 -1
View File
@@ -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'
+1
View File
@@ -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;
}
+5 -4
View File
@@ -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();
+4 -2
View File
@@ -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);
}
+85 -64
View File
@@ -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 "???";
}
}
+87 -11
View File
@@ -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;
};
+102
View File
@@ -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;
}
+7
View File
@@ -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;
+5 -5
View File
@@ -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;