From 06301d73fc996591f3bd6a0ac3c844f99b154339 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Thu, 6 Jun 2019 19:37:17 +0200 Subject: [PATCH] new memory handling --- config.cpp | 9 ++++- control.cpp | 8 ++++ graph.cpp | 2 +- hud.cpp | 8 +++- hyper.h | 7 ++++ savemem.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++ sound.cpp | 43 ++++++++++++++++++-- system.cpp | 1 + 8 files changed, 185 insertions(+), 6 deletions(-) diff --git a/config.cpp b/config.cpp index 46eae9ab..96212999 100644 --- a/config.cpp +++ b/config.cpp @@ -942,8 +942,11 @@ void configureOther() { #endif dialog::addBoolItem_action(XLAT("skip the start menu"), vid.skipstart, 'm'); + + dialog::addItem(XLAT("memory configuration"), 'y'); + dialog::add_action_push(show_memory_menu); - dialog::addBoolItem_action(XLAT("forget faraway cells"), memory_saving_mode, 'y'); + // dialog::addBoolItem_action(XLAT("forget faraway cells"), memory_saving_mode, 'y'); #if CAP_AUDIO if(CAP_AUDIO) { @@ -1289,6 +1292,7 @@ void show3D() { dialog::addSelItem(XLAT("Eye level"), fts(vid.eye), 'E'); dialog::addSelItem(XLAT("Ground level below the plane"), fts(vid.depth), 'g'); + if(GDIM == 2) dialog::addSelItem(XLAT("Projection at the ground level"), fts(vid.alpha), 'p'); @@ -2039,6 +2043,9 @@ int read_config_args() { else if(argis("-msm")) { PHASEFROM(2); memory_saving_mode = true; } + else if(argis("-mrsv")) { + PHASEFROM(2); shift(); reserve_limit = argi(); apply_memory_reserve(); + } else if(argis("-yca")) { PHASEFROM(2); shift_arg_formula(vid.yshift); diff --git a/control.cpp b/control.cpp index 4cfadc4e..686a8b06 100644 --- a/control.cpp +++ b/control.cpp @@ -108,6 +108,8 @@ void movepckeydir(int d) { DEBB(DF_GRAPH, ("movepckeydir\n")); // EUCLIDEAN + if(protect_memory()) return; + movedir md = vectodir(move_destination_vec(d)); if(!canmove) movepcto(md), remission(); else movepcto(md); @@ -152,6 +154,9 @@ void calcMousedest() { void mousemovement() { if(DIM == 3) return; + + if(protect_memory()) return; + calcMousedest(); if(!canmove) movepcto(mousedest), remission(); else movepcto(mousedest); lmouseover = NULL; @@ -468,6 +473,8 @@ void handleKeyNormal(int sym, int uni) { } if(sym == SDLK_F1) gotoHelp(help); + + if(sym == PSEUDOKEY_MEMORY) pushScreen(show_memory_menu); } bool need_mouseh = false; @@ -619,6 +626,7 @@ void mainloopiter() { #if CAP_SDLAUDIO if(audio) handlemusic(); #endif + apply_memory_reserve(); SDL_Event ev; DEBB(DF_GRAPH, ("polling for events\n")); diff --git a/graph.cpp b/graph.cpp index 058d5c5f..e915e39d 100644 --- a/graph.cpp +++ b/graph.cpp @@ -4826,7 +4826,7 @@ void draw_ceiling(cell *c, const transmatrix& V, int fd, color_t& fcol, color_t& color_t wcol2 = gradient(0, wcol, 0, .8, 1); placeSidewall(c, i, SIDE_SKY, V, darkena(wcol2, fd, 0xFF)); } - sky->sky.emplace_back(c, V, 0); + if(!euclid) sky->sky.emplace_back(c, V, 0); return; } diff --git a/hud.cpp b/hud.cpp index 52e2799c..993a3c6a 100644 --- a/hud.cpp +++ b/hud.cpp @@ -651,7 +651,13 @@ void drawStats() { } string vers = VER; if(!nofps) vers += XLAT(" fps: ") + its(calcfps()); - if(displayButtonS(4, vid.yres - 4 - vid.fsize/2, vers, 0x202020, 0, vid.fsize/2)) { + + if(reserve_limit && reserve_count < reserve_limit) { + vers += " " + its(reserve_count) + "/" + its(reserve_limit) + " MB"; + if(displayButtonS(4, vid.yres - 4 - vid.fsize/2, vers, 0xFF2020, 0, vid.fsize/2)) + getcstat = PSEUDOKEY_MEMORY, instat = true; + } + else if(displayButtonS(4, vid.yres - 4 - vid.fsize/2, vers, 0x202020, 0, vid.fsize/2)) { mouseovers = XLAT("frames per second"), getcstat = SDLK_F1, instat = true, diff --git a/hyper.h b/hyper.h index 5f0328d3..09093043 100644 --- a/hyper.h +++ b/hyper.h @@ -5526,4 +5526,11 @@ namespace dual { void raise_error(); bool invalid_matrix(const transmatrix T); +extern bool show_memory_warning; +extern bool ignored_memory_warning; +extern int reserve_count, reserve_limit; +void apply_memory_reserve(); +void show_memory_menu(); +static const int PSEUDOKEY_MEMORY = 16397; + } \ No newline at end of file diff --git a/savemem.cpp b/savemem.cpp index c83e229f..6131a1bd 100644 --- a/savemem.cpp +++ b/savemem.cpp @@ -5,6 +5,9 @@ namespace hr { bool memory_saving_mode = true; +bool show_memory_warning = true; +bool ignored_memory_warning; + static const int LIM = 150; heptagon *last_cleared; @@ -170,4 +173,114 @@ void set_if_removed(cell*& c, cell *val) { if(is_cell_removed(c)) c = val; } +typedef array reserve_block; + +int reserve_count = 0; +int reserve_limit = 128; + +const int max_reserve = 4096; +array reserve; + +std::new_handler default_handler; + +purehookset hooks_clear_cache; + +void reserve_handler() { + if(reserve_count) { + reserve_count--; + delete reserve[reserve_count]; + } + if(reserve_count < 32) callhooks(hooks_clear_cache); + if(!reserve_count) std::set_new_handler(default_handler); + } + +void apply_memory_reserve() { + if(reserve_count > 0) std::set_new_handler(default_handler); + if(reserve_limit > max_reserve) reserve_limit = max_reserve; + if(reserve_limit < 0) reserve_limit = 0; + while(reserve_count > reserve_limit) { reserve_count--; delete reserve[reserve_count]; } + try { + while(reserve_count < reserve_limit) { + reserve[reserve_count] = new reserve_block; + /* only if successful */ + reserve_count++; + } + } + catch(std::bad_alloc&) {} + default_handler = std::get_new_handler(); + if(reserve_count > 0) std::set_new_handler(reserve_handler); + } + +void memory_for_lib() { + if(reserve_count) { reserve_count--; delete reserve[reserve_count]; } + } + +void show_memory_menu() { + gamescreen(0); + dialog::init(XLAT("memory")); + + dialog::addHelp(XLAT( + "HyperRogue takes place in a world that is larger than anything Euclidean. " + "Unfortunately, in some cases running it on an Euclidean computer might be " + "a problem -- the computer could simply run out of memory. Some lands (such as the Ocean or the Brown Islands) " + "may use up memory very fast!\n\n" + )); + + if(sizeof(void*) <= 4) + dialog::addHelp(XLAT( + "You are playing a 32-bit HyperRogue executable, which can only use 4GB of memory.\n\n")); + + dialog::addHelp(XLAT( + "Although you are extremely unlikely to return to a place you have already been to, " + "the game never forgets these areas, unless you start a new game, use an Orb of " + "Safety (found in Land of Eternal Motion and the Prairie), or activate the memory " + "saving mode, which tries to intelligently predict which cells you will never find " + "again and can be safely forgotten.\n\n") + ); + + if(cheater) dialog::addSelItem(XLAT("cells in memory"), its(cellcount) + "+" + its(heptacount), 0); + + dialog::addBoolItem(XLAT("memory saving mode"), memory_saving_mode, 'f'); + dialog::add_action([] { memory_saving_mode = !memory_saving_mode; if(memory_saving_mode) save_memory(), apply_memory_reserve(); }); + + dialog::addBoolItem_action(XLAT("show memory warnings"), show_memory_warning, 'w'); + + if(reserve_limit > 0 && reserve_count < reserve_limit) { + dialog::addItem(XLAT("just let me find Orb of Safety or finish the game"), 'l'); + dialog::add_action([] { ignored_memory_warning = true; popScreen(); }); + } + + dialog::addSelItem("memory reserve", its(reserve_count) + "/" + its(reserve_limit) + " MB", 'r'); + dialog::add_action([] { + dialog::editNumber(reserve_limit, 0, max_reserve, 16, 128, XLAT("memory reserve"), + XLAT("When to show a memory warning.") + ); + dialog::bound_low(0); + dialog::bound_up(max_reserve); + dialog::reaction = apply_memory_reserve; + }); + + dialog::addItem("clear caches", 'c'); + dialog::add_action([] { callhooks(hooks_clear_cache); }); + + dialog::addBack(); + dialog::display(); + } + +bool protect_memory() { + if(reserve_limit && reserve_count < reserve_limit && !ignored_memory_warning) { + pushScreen(show_memory_menu); + return true; + } + if(reserve_limit && reserve_count < 8) { + pushScreen(show_memory_menu); + return true; + } + return false; + } + +bool memory_issues() { + return reserve_limit && reserve_count < 16; + } + } diff --git a/sound.cpp b/sound.cpp index b5261cae..c9ea93e4 100644 --- a/sound.cpp +++ b/sound.cpp @@ -80,10 +80,17 @@ void handlemusic() { if(callhandlers(false, hooks_music, id)) return; if(outoffocus) id = eLand(0); if(musfname[id] == "LAST") id = cid; - if(!loaded[id]) { + if(!loaded[id] && !memory_issues()) { loaded[id] = true; - // printf("loading (%d)> %s\n", id, musfname[id].c_str()); + // printf("loading (%d)> %s\n", id, musfname[id].c_str()); + // reuse music if(musfname[id] != "") { + for(int i=0; i currently_played; + for(int ch=0; ch<16; ch++) currently_played.insert(Mix_GetChunk(ch)); + set to_free; + for(auto& p: chunks) + if(p.second) { + if(currently_played.count(p.second)) { + println(hlog, p.first, ": currently played"); + } + else { + Mix_FreeChunk(p.second); + to_free.insert(p.first); + println(hlog, p.first, ": freed"); + } + } + for(auto& s: to_free) chunks.erase(s); + } + #else void resetmusic() {} #endif @@ -231,7 +268,7 @@ int read_sound_args() { return 0; } -auto ah_sound = addHook(hooks_args, 0, read_sound_args); +auto ah_sound = addHook(hooks_args, 0, read_sound_args) + addHook(hooks_clear_cache, 0, reuse_music_memory); #endif diff --git a/system.cpp b/system.cpp index 09222f8c..599ca87b 100644 --- a/system.cpp +++ b/system.cpp @@ -1313,6 +1313,7 @@ void start_game() { restart: game_active = true; gamegen_failure = false; + ignored_memory_warning = false; check_cgi(); cgi.require_basics(); initcells();