From 44e64a6a1256c308284b2d96f580d048016224b5 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 11 Jan 2022 17:20:48 +0100 Subject: [PATCH] - backend update from GZDoom. * GC fix * better sound range check * UE model loader license change. --- source/common/audio/sound/s_sound.cpp | 2 +- source/common/models/models_ue1.cpp | 28 ++++---- source/common/objects/dobject.cpp | 3 - source/common/objects/dobjgc.cpp | 94 ++++++++++++++++++--------- source/common/objects/dobjgc.h | 21 +++--- source/common/rendering/v_video.cpp | 1 - source/common/statusbar/base_sbar.cpp | 2 +- source/core/mainloop.cpp | 13 ---- 8 files changed, 92 insertions(+), 72 deletions(-) diff --git a/source/common/audio/sound/s_sound.cpp b/source/common/audio/sound/s_sound.cpp index 74393dfdd..cdd0361c5 100644 --- a/source/common/audio/sound/s_sound.cpp +++ b/source/common/audio/sound/s_sound.cpp @@ -388,7 +388,7 @@ FSoundChan *SoundEngine::StartSound(int type, const void *source, FVector3 pos, vel; FRolloffInfo *rolloff; - if (sound_id <= 0 || volume <= 0 || nosfx || !SoundEnabled() || blockNewSounds) + if (sound_id <= 0 || volume <= 0 || nosfx || !SoundEnabled() || blockNewSounds || (unsigned)sound_id >= S_sfx.Size()) return NULL; // prevent crashes. diff --git a/source/common/models/models_ue1.cpp b/source/common/models/models_ue1.cpp index 68be56e61..c7ffe88a9 100644 --- a/source/common/models/models_ue1.cpp +++ b/source/common/models/models_ue1.cpp @@ -1,21 +1,25 @@ // //--------------------------------------------------------------------------- // -// Copyright(C) 2018 Marisa Kirisame -// All rights reserved. +// Copyright (c) 2018-2022 Marisa Kirisame, UnSX Team // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. // -// You should have received a copy of the GNU Lesser General Public License -// along with this program. If not, see http://www.gnu.org/licenses/ +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. // //-------------------------------------------------------------------------- // diff --git a/source/common/objects/dobject.cpp b/source/common/objects/dobject.cpp index 34e2f4cc7..2ed8279da 100644 --- a/source/common/objects/dobject.cpp +++ b/source/common/objects/dobject.cpp @@ -229,7 +229,6 @@ DObject::DObject () ObjNext = GC::Root; GCNext = nullptr; GC::Root = this; - GC::AllocCount++; } DObject::DObject (PClass *inClass) @@ -239,7 +238,6 @@ DObject::DObject (PClass *inClass) ObjNext = GC::Root; GCNext = nullptr; GC::Root = this; - GC::AllocCount++; } //========================================================================== @@ -277,7 +275,6 @@ DObject::~DObject () void DObject::Release() { - if (GC::AllocCount > 0) GC::AllocCount--; DObject **probe; // Unlink this object from the GC list. diff --git a/source/common/objects/dobjgc.cpp b/source/common/objects/dobjgc.cpp index 91cfafaef..e407d3d77 100644 --- a/source/common/objects/dobjgc.cpp +++ b/source/common/objects/dobjgc.cpp @@ -3,7 +3,7 @@ ** The garbage collector. Based largely on Lua's. ** **--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit +** Copyright 2008-2022 Marisa Heit ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -82,13 +82,19 @@ ** infinity, where each step performs a full collection.) You can also ** change this value dynamically. */ -#define DEFAULT_GCMUL 400 // GC runs 'quadruple the speed' of memory allocation +#define DEFAULT_GCMUL 200 // GC runs 'double the speed' of memory allocation -// Number of sectors to mark for each step. +// Minimum step size +#define GCSTEPSIZE (sizeof(DObject) * 16) -#define GCSTEPSIZE 1024u +// Maximum number of elements to sweep in a single step #define GCSWEEPMAX 40 -#define GCSWEEPCOST 10 + +// Cost of sweeping one element (the size of a small object divided by +// some adjust for the sweep speed) +#define GCSWEEPCOST (sizeof(DObject) / 4) + +// Cost of calling of one destructor #define GCFINALIZECOST 100 // TYPES ------------------------------------------------------------------- @@ -99,6 +105,8 @@ // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- +static size_t CalcStepSize(); + // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -108,7 +116,6 @@ namespace GC size_t AllocBytes; size_t Threshold; size_t Estimate; -size_t AllocCount; DObject *Gray; DObject *Root; DObject *SoftRoots; @@ -118,11 +125,15 @@ EGCState State = GCS_Pause; int Pause = DEFAULT_GCPAUSE; int StepMul = DEFAULT_GCMUL; int StepCount; -size_t Dept; +uint64_t CheckTime; bool FinalGC; // PRIVATE DATA DEFINITIONS ------------------------------------------------ +static int LastCollectTime; // Time last time collector finished +static size_t LastCollectAlloc; // Memory allocation when collector finished +static size_t MinStepSize; // Cover at least this much memory per step + // CODE -------------------------------------------------------------------- //========================================================================== @@ -161,8 +172,8 @@ size_t PropagateMark() // // SweepList // -// Runs a limited sweep on a list, returning the location where to resume -// the sweep at next time. (FIXME: Horrible Engrish in this description.) +// Runs a limited sweep on a list, returning the position in the list just +// after the last object swept. // //========================================================================== @@ -254,6 +265,26 @@ void MarkArray(DObject **obj, size_t count) } } +//========================================================================== +// +// CalcStepSize +// +// Decide how big a step should be based, depending on how long it took to +// allocate up to the threshold from the amount left after the previous +// collection. +// +//========================================================================== + +static size_t CalcStepSize() +{ + int time_passed = CheckTime - LastCollectTime; + auto alloc = min(LastCollectAlloc, Estimate); + size_t bytes_gained = AllocBytes > alloc ? AllocBytes - alloc : 0; + return (StepMul > 0 && time_passed > 0) + ? std::max(GCSTEPSIZE, bytes_gained / time_passed * StepMul / 100) + : std::numeric_limits::max() / 2; // no limit +} + //========================================================================== // // MarkRoot @@ -310,6 +341,10 @@ static void Atomic() SweepPos = &Root; State = GCS_Sweep; Estimate = AllocBytes; + + // Now that we are about to start a sweep, establish a baseline minimum + // step size for how much memory we want to sweep each CheckGC(). + MinStepSize = CalcStepSize(); } //========================================================================== @@ -354,7 +389,8 @@ static size_t SingleStep() case GCS_Finalize: State = GCS_Pause; // end collection - Dept = 0; + LastCollectAlloc = AllocBytes; + LastCollectTime = CheckTime; return 0; default: @@ -374,29 +410,26 @@ static size_t SingleStep() void Step() { - size_t lim = (GCSTEPSIZE/100) * StepMul; - size_t olim; - if (lim == 0) - { - lim = (~(size_t)0) / 2; // no limit - } - Dept += AllocBytes - Threshold; + // We recalculate a step size in case the rate of allocation went up + // since we started sweeping because we don't want to fall behind. + // However, we also don't want to go slower than what was decided upon + // when the sweep began if the rate of allocation has slowed. + size_t lim = max(CalcStepSize(), MinStepSize); do { - olim = lim; - lim -= SingleStep(); - } while (olim > lim && State != GCS_Pause); - if (State != GCS_Pause) - { - if (Dept < GCSTEPSIZE) + size_t done = SingleStep(); + if (done < lim) { - Threshold = AllocBytes + GCSTEPSIZE; // - lim/StepMul + lim -= done; } else { - Dept -= GCSTEPSIZE; - Threshold = AllocBytes; + lim = 0; } + } while (lim && State != GCS_Pause); + if (State != GCS_Pause) + { + Threshold = AllocBytes; } else { @@ -571,16 +604,13 @@ ADD_STAT(gc) " Sweep ", "Finalize " }; FString out; - out.Format("[%s] Alloc:%6zuK Thresh:%6zuK Est:%6zuK Steps: %d", + out.Format("[%s] Alloc:%6zuK Thresh:%6zuK Est:%6zuK Steps: %d %zuK", StateStrings[GC::State], (GC::AllocBytes + 1023) >> 10, (GC::Threshold + 1023) >> 10, (GC::Estimate + 1023) >> 10, - GC::StepCount); - if (GC::State != GC::GCS_Pause) - { - out.AppendFormat(" %zuK", (GC::Dept + 1023) >> 10); - } + GC::StepCount, + (GC::MinStepSize + 1023) >> 10); return out; } diff --git a/source/common/objects/dobjgc.h b/source/common/objects/dobjgc.h index edd34e4ca..1fd293263 100644 --- a/source/common/objects/dobjgc.h +++ b/source/common/objects/dobjgc.h @@ -43,9 +43,6 @@ namespace GC // Number of bytes currently allocated through M_Malloc/M_Realloc. extern size_t AllocBytes; - // Number of allocated objects since last CheckGC call. - extern size_t AllocCount; - // Amount of memory to allocate before triggering a collection. extern size_t Threshold; @@ -73,6 +70,9 @@ namespace GC // Is this the final collection just before exit? extern bool FinalGC; + // Counts the number of times CheckGC has been called. + extern uint64_t CheckTime; + // Current white value for known-dead objects. static inline uint32_t OtherWhite() { @@ -108,15 +108,11 @@ namespace GC } // Check if it's time to collect, and do a collection step if it is. - static inline bool CheckGC() + static inline void CheckGC() { - AllocCount = 0; + CheckTime++; if (AllocBytes >= Threshold) - { Step(); - return true; - } - return false; } // Forces a collection to start now. @@ -184,6 +180,13 @@ class TObjPtr DObject *o; }; public: + TObjPtr() = default; + TObjPtr(const TObjPtr &q) = default; + + TObjPtr(T q) noexcept + : pp(q) + { + } T operator=(T q) { pp = q; diff --git a/source/common/rendering/v_video.cpp b/source/common/rendering/v_video.cpp index dffb9cc77..277144aa8 100644 --- a/source/common/rendering/v_video.cpp +++ b/source/common/rendering/v_video.cpp @@ -121,7 +121,6 @@ CUSTOM_CVAR(Int, vid_preferbackend, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_N Printf("Changing the video backend requires a restart for " GAMENAME ".\n"); } -//CVAR(Int, vid_renderer, 1, 0) // for some stupid mods which threw caution out of the window... CUSTOM_CVAR(Int, uiscale, 0, CVAR_ARCHIVE | CVAR_NOINITCALL) { diff --git a/source/common/statusbar/base_sbar.cpp b/source/common/statusbar/base_sbar.cpp index 9d4d3214c..53d4c03b4 100644 --- a/source/common/statusbar/base_sbar.cpp +++ b/source/common/statusbar/base_sbar.cpp @@ -352,7 +352,7 @@ void DStatusBarCore::SetScale() int horz = HorizontalResolution; int vert = VerticalResolution; double refaspect = horz / double(vert); - double screenaspect = ActiveRatio(w, h); + double screenaspect = w / double(h); if ((horz == 320 && vert == 200) || (horz == 640 && vert == 400)) { diff --git a/source/core/mainloop.cpp b/source/core/mainloop.cpp index ee7554a9f..624cca9ba 100644 --- a/source/core/mainloop.cpp +++ b/source/core/mainloop.cpp @@ -373,19 +373,6 @@ static void GameTicker() break; } - - GC::CheckGC(); - // Do some more aggressive GC maintenance when the game ticker is inactive. - if ((gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) || paused) - { - size_t ac = max(10, GC::AllocCount); - for (size_t cnt = 0; cnt < ac; cnt++) - { - if (!GC::CheckGC()) break; - } - } - - }