From 0160841dde496462badfae2b0ac0a603bd34225d Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 19 Dec 2018 18:17:21 +0100 Subject: [PATCH 1/8] - reverse the order of the texture list before resolving it. Since this deletes the resolved elements one by one and needs to start at the front to ensure consistency, it is better to reverse the order so that the deletions take place at the end of the list which requires a lot less data movement. On Total Chaos this slowed down texture setup to the point where the mod was basically unlaunchable. --- src/tarray.h | 18 +++++++++++++++++- src/textures/formats/multipatchtexture.h | 22 ++++++++++++++++++++++ src/textures/multipatchtexturebuilder.cpp | 13 +++++++++++-- src/zstring.h | 5 +++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/tarray.h b/src/tarray.h index 524c0942e..1c5faca43 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -497,6 +497,14 @@ public: Array = nullptr; } } + + void Swap(TArray &other) + { + std::swap(Array, other.Array); + std::swap(Count, other.Count); + std::swap(Most, other.Most); + } + private: T *Array; unsigned int Count; @@ -760,6 +768,7 @@ struct FMap hash_t NumUsed; }; + template class TMapIterator; template class TMapConstIterator; @@ -947,6 +956,14 @@ public: DelKey(key); } + void Swap(MyType &other) + { + std::swap(Nodes, other.Nodes); + std::swap(LastFree, other.LastFree); + std::swap(Size, other.Size); + std::swap(NumUsed, other.NumUsed); + } + protected: struct IPair // This must be the same as Pair above, but with a { // non-const Key. @@ -1518,4 +1535,3 @@ private: T *Array; unsigned int Count; }; - diff --git a/src/textures/formats/multipatchtexture.h b/src/textures/formats/multipatchtexture.h index 3d7800832..8337ffe6c 100644 --- a/src/textures/formats/multipatchtexture.h +++ b/src/textures/formats/multipatchtexture.h @@ -89,8 +89,30 @@ struct BuildInfo int LeftOffset[2] = {}; int TopOffset[2] = {}; FImageTexture *tex = nullptr; + + void swap(BuildInfo &other) + { + Name.Swap(other.Name); + Parts.Swap(other.Parts); + Inits.Swap(other.Inits); + std::swap(Width, other.Width); + std::swap(Height, other.Height); + std::swap(Scale, other.Scale); + std::swap(bWorldPanning, other.bWorldPanning); + std::swap(DefinitionLump, other.DefinitionLump); + std::swap(bComplex, bComplex); + std::swap(textual, other.textual); + std::swap(bNoDecals, other.bNoDecals); + std::swap(LeftOffset[0], other.LeftOffset[0]); + std::swap(LeftOffset[1], other.LeftOffset[1]); + std::swap(TopOffset[0], other.TopOffset[0]); + std::swap(TopOffset[1], other.TopOffset[1]); + std::swap(tex, other.tex); + } }; + + class FMultipatchTextureBuilder { FTextureManager &TexMan; diff --git a/src/textures/multipatchtexturebuilder.cpp b/src/textures/multipatchtexturebuilder.cpp index 7be8a69e5..4675220f5 100644 --- a/src/textures/multipatchtexturebuilder.cpp +++ b/src/textures/multipatchtexturebuilder.cpp @@ -922,11 +922,21 @@ void FMultipatchTextureBuilder::ResolveAllPatches() } // Now try to resolve the images. We only can do this at the end when all multipatch textures are set up. int i = 0; + + // reverse the list so that the Delete operation in the loop below deletes at the end. + // For normal sized lists this is of no real concern, but Total Chaos has over 250000 textures where this becomes a performance issue. + for (unsigned i = 0; i < BuiltTextures.Size() / 2; i++) + { + // std::swap is VERY inefficient here... + BuiltTextures[i].swap(BuiltTextures[BuiltTextures.Size() - 1 - i]); + } + + while (BuiltTextures.Size() > 0) { bool donesomething = false; - for (unsigned i = 0; i < BuiltTextures.Size(); i++) + for (int i = BuiltTextures.Size()-1; i>= 0; i--) { auto &buildinfo = BuiltTextures[i]; bool hasEmpty = false; @@ -969,7 +979,6 @@ void FMultipatchTextureBuilder::ResolveAllPatches() } BuiltTextures.Delete(i); - i--; donesomething = true; } } diff --git a/src/zstring.h b/src/zstring.h index 67fef4a18..334fbcb1f 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -148,6 +148,11 @@ public: char *LockBuffer(); // Obtain write access to the character buffer void UnlockBuffer(); // Allow shared access to the character buffer + void Swap(FString &other) + { + std::swap(Chars, other.Chars); + } + operator const char *() const { return Chars; } const char *GetChars() const { return Chars; } From 3291d8e9ac4aceafad9a0a53e875d2c1ae667016 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 19 Dec 2018 15:25:42 +0100 Subject: [PATCH 2/8] - made Ammo.GetParentAmmo virtual --- wadsrc/static/zscript/inventory/ammo.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt index b08f39601..cc97611e0 100644 --- a/wadsrc/static/zscript/inventory/ammo.txt +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -66,7 +66,7 @@ class Ammo : Inventory // //=========================================================================== - Class GetParentAmmo () + virtual Class GetParentAmmo () { class type = GetClass(); From 0faa9111b9d8795c87567b1697c8495fe4ae80c0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 19 Dec 2018 18:41:53 +0100 Subject: [PATCH 3/8] - moved P_OpenMapData and related content out of p_setup.cpp. --- src/CMakeLists.txt | 1 + src/g_levellocals.h | 97 ++++----- src/p_openmap.cpp | 413 +++++++++++++++++++++++++++++++++++++ src/p_setup.cpp | 384 ---------------------------------- src/scripting/vmthunks.cpp | 13 ++ 5 files changed, 478 insertions(+), 430 deletions(-) create mode 100644 src/p_openmap.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6d39692e5..4fb943691 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -963,6 +963,7 @@ set (PCH_SOURCES p_map.cpp p_maputl.cpp p_mobj.cpp + p_openmap.cpp p_pillar.cpp p_plats.cpp p_pspr.cpp diff --git a/src/g_levellocals.h b/src/g_levellocals.h index c9eceabb6..ee9cbbe9c 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -46,7 +46,54 @@ #include "r_data/r_sections.h" #include "r_data/r_canvastexture.h" -struct FLevelLocals + +struct FLevelData +{ + TArray vertexes; + TArray sectors; + TArray linebuffer; // contains the line lists for the sectors. + TArray lines; + TArray sides; + TArray segs; + TArray subsectors; + TArray nodes; + TArray gamesubsectors; + TArray gamenodes; + node_t *headgamenode; + TArray rejectmatrix; + TArray Zones; + + TArray sectorPortals; + TArray linePortals; + + // Portal information. + FDisplacementTable Displacements; + FPortalBlockmap PortalBlockmap; + TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. + TArray portalGroups; + TArray linePortalSpans; + FSectionContainer sections; + FCanvasTextureInfo canvasTextureInfo; + + // [ZZ] Destructible geometry information + TMap healthGroups; + + FBlockmap blockmap; + + // These are copies of the loaded map data that get used by the savegame code to skip unaltered fields + // Without such a mechanism the savegame format would become too slow and large because more than 80-90% are normally still unaltered. + TArray loadsectors; + TArray loadlines; + TArray loadsides; + + // Maintain single and multi player starting spots. + TArray deathmatchstarts; + FPlayerStart playerstarts[MAXPLAYERS]; + TArray AllPlayerStarts; + +}; + +struct FLevelLocals : public FLevelData { void Tick(); void Mark(); @@ -76,57 +123,12 @@ struct FLevelLocals uint64_t ShaderStartTime = 0; // tell the shader system when we started the level (forces a timer restart) - TArray vertexes; - TArray sectors; - TArray linebuffer; // contains the line lists for the sectors. - TArray lines; - TArray sides; - TArray segs; - TArray subsectors; - TArray nodes; - TArray gamesubsectors; - TArray gamenodes; - node_t *headgamenode; - TArray rejectmatrix; - static const int BODYQUESIZE = 32; TObjPtr bodyque[BODYQUESIZE]; int bodyqueslot; - - TArray sectorPortals; - TArray linePortals; - - // Portal information. - FDisplacementTable Displacements; - FPortalBlockmap PortalBlockmap; - TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. - TArray portalGroups; - TArray linePortalSpans; - FSectionContainer sections; - FCanvasTextureInfo canvasTextureInfo; - int NumMapSections; - TArray Zones; - - // [ZZ] Destructible geometry information - TMap healthGroups; - - FBlockmap blockmap; - - // These are copies of the loaded map data that get used by the savegame code to skip unaltered fields - // Without such a mechanism the savegame format would become too slow and large because more than 80-90% are normally still unaltered. - TArray loadsectors; - TArray loadlines; - TArray loadsides; - - // Maintain single and multi player starting spots. - TArray deathmatchstarts; - FPlayerStart playerstarts[MAXPLAYERS]; - TArray AllPlayerStarts; - - uint32_t flags; uint32_t flags2; uint32_t flags3; @@ -224,6 +226,8 @@ struct FLevelLocals } }; +#ifndef NO_DEFINE_LEVEL + extern FLevelLocals level; inline int vertex_t::Index() const @@ -350,3 +354,4 @@ inline bool line_t::hitSkyWall(AActor* mo) const backsector->GetTexture(sector_t::ceiling) == skyflatnum && mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this)); } +#endif \ No newline at end of file diff --git a/src/p_openmap.cpp b/src/p_openmap.cpp new file mode 100644 index 000000000..9331dca72 --- /dev/null +++ b/src/p_openmap.cpp @@ -0,0 +1,413 @@ +/* +** p_openmap.cpp +** +** creates the data structures needed to load a map from the resource files. +** +**--------------------------------------------------------------------------- +** Copyright 2005-2018 Christoph Oelckers +** Copyright 2005-2016 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "p_setup.h" +#include "i_system.h" +#include "cmdlib.h" +#include "w_wad.h" +#include "md5.h" +#include "g_levellocals.h" + +inline bool P_IsBuildMap(MapData *map) +{ + return false; +} + +//=========================================================================== +// +// GetMapIndex +// +// Gets the type of map lump or -1 if invalid or -2 if required and not found. +// +//=========================================================================== + +struct checkstruct +{ + const char lumpname[9]; + bool required; +}; + +static int GetMapIndex(const char *mapname, int lastindex, const char *lumpname, bool needrequired) +{ + static const checkstruct check[] = + { + {"", true}, + {"THINGS", true}, + {"LINEDEFS", true}, + {"SIDEDEFS", true}, + {"VERTEXES", true}, + {"SEGS", false}, + {"SSECTORS", false}, + {"NODES", false}, + {"SECTORS", true}, + {"REJECT", false}, + {"BLOCKMAP", false}, + {"BEHAVIOR", false}, + //{"SCRIPTS", false}, + }; + + if (lumpname==NULL) lumpname=""; + + for(size_t i=lastindex+1;iresource = FResourceFile::OpenResourceFile(mapname, true); + wadReader = map->resource->GetReader(); + } + else + { + FString fmt; + int lump_wad; + int lump_map; + int lump_name = -1; + + // Check for both *.wad and *.map in order to load Build maps + // as well. The higher one will take precedence. + // Names with more than 8 characters will only be checked as .wad and .map. + if (strlen(mapname) <= 8) lump_name = Wads.CheckNumForName(mapname); + fmt.Format("maps/%s.wad", mapname); + lump_wad = Wads.CheckNumForFullName(fmt); + fmt.Format("maps/%s.map", mapname); + lump_map = Wads.CheckNumForFullName(fmt); + + if (lump_name > lump_wad && lump_name > lump_map && lump_name != -1) + { + int lumpfile = Wads.GetLumpFile(lump_name); + int nextfile = Wads.GetLumpFile(lump_name+1); + + map->lumpnum = lump_name; + + if (lumpfile != nextfile) + { + // The following lump is from a different file so whatever this is, + // it is not a multi-lump Doom level so let's assume it is a Build map. + map->MapLumps[0].Reader = Wads.ReopenLumpReader(lump_name); + if (!P_IsBuildMap(map)) + { + delete map; + return NULL; + } + return map; + } + + // This case can only happen if the lump is inside a real WAD file. + // As such any special handling for other types of lumps is skipped. + map->MapLumps[0].Reader = Wads.ReopenLumpReader(lump_name); + strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(lump_name), 8); + map->Encrypted = Wads.IsEncryptedFile(lump_name); + map->InWad = true; + + if (map->Encrypted) + { // If it's encrypted, then it's a Blood file, presumably a map. + if (!P_IsBuildMap(map)) + { + delete map; + return NULL; + } + return map; + } + + int index = 0; + + if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP") != 0) + { + for(int i = 1;; i++) + { + // Since levels must be stored in WADs they can't really have full + // names and for any valid level lump this always returns the short name. + const char * lumpname = Wads.GetLumpFullName(lump_name + i); + try + { + index = GetMapIndex(mapname, index, lumpname, !justcheck); + } + catch(...) + { + delete map; + throw; + } + if (index == -2) + { + delete map; + return NULL; + } + if (index == ML_BEHAVIOR) map->HasBehavior = true; + + // The next lump is not part of this map anymore + if (index < 0) break; + + map->MapLumps[index].Reader = Wads.ReopenLumpReader(lump_name + i); + strncpy(map->MapLumps[index].Name, lumpname, 8); + } + } + else + { + map->isText = true; + map->MapLumps[1].Reader = Wads.ReopenLumpReader(lump_name + 1); + for(int i = 2;; i++) + { + const char * lumpname = Wads.GetLumpFullName(lump_name + i); + + if (lumpname == NULL) + { + I_Error("Invalid map definition for %s", mapname); + } + else if (!stricmp(lumpname, "ZNODES")) + { + index = ML_GLZNODES; + } + else if (!stricmp(lumpname, "BLOCKMAP")) + { + // there is no real point in creating a blockmap but let's use it anyway + index = ML_BLOCKMAP; + } + else if (!stricmp(lumpname, "REJECT")) + { + index = ML_REJECT; + } + else if (!stricmp(lumpname, "DIALOGUE")) + { + index = ML_CONVERSATION; + } + else if (!stricmp(lumpname, "BEHAVIOR")) + { + index = ML_BEHAVIOR; + map->HasBehavior = true; + } + else if (!stricmp(lumpname, "ENDMAP")) + { + break; + } + else continue; + map->MapLumps[index].Reader = Wads.ReopenLumpReader(lump_name + i); + strncpy(map->MapLumps[index].Name, lumpname, 8); + } + } + return map; + } + else + { + if (lump_map > lump_wad) + { + lump_wad = lump_map; + } + if (lump_wad == -1) + { + delete map; + return NULL; + } + map->lumpnum = lump_wad; + auto reader = Wads.ReopenLumpReader(lump_wad); + map->resource = FResourceFile::OpenResourceFile(Wads.GetLumpFullName(lump_wad), reader, true); + wadReader = map->resource->GetReader(); + } + } + uint32_t id; + + // Although we're using the resource system, we still want to be sure we're + // reading from a wad file. + wadReader->Seek(0, FileReader::SeekSet); + wadReader->Read(&id, sizeof(id)); + + if (id == IWAD_ID || id == PWAD_ID) + { + char maplabel[9]=""; + int index=0; + + map->MapLumps[0].Reader = map->resource->GetLump(0)->NewReader(); + strncpy(map->MapLumps[0].Name, map->resource->GetLump(0)->Name, 8); + + for(uint32_t i = 1; i < map->resource->LumpCount(); i++) + { + const char* lumpname = map->resource->GetLump(i)->Name; + + if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) + { + map->isText = true; + map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetLump(i)->NewReader(); + strncpy(map->MapLumps[ML_TEXTMAP].Name, lumpname, 8); + for(int i = 2;; i++) + { + lumpname = map->resource->GetLump(i)->Name; + if (!strnicmp(lumpname, "ZNODES",8)) + { + index = ML_GLZNODES; + } + else if (!strnicmp(lumpname, "BLOCKMAP",8)) + { + // there is no real point in creating a blockmap but let's use it anyway + index = ML_BLOCKMAP; + } + else if (!strnicmp(lumpname, "REJECT",8)) + { + index = ML_REJECT; + } + else if (!strnicmp(lumpname, "DIALOGUE",8)) + { + index = ML_CONVERSATION; + } + else if (!strnicmp(lumpname, "BEHAVIOR",8)) + { + index = ML_BEHAVIOR; + map->HasBehavior = true; + } + else if (!strnicmp(lumpname, "ENDMAP",8)) + { + return map; + } + else continue; + map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); + strncpy(map->MapLumps[index].Name, lumpname, 8); + } + } + + if (i>0) + { + try + { + index = GetMapIndex(maplabel, index, lumpname, !justcheck); + } + catch(...) + { + delete map; + throw; + } + if (index == -2) + { + delete map; + return NULL; + } + if (index == ML_BEHAVIOR) map->HasBehavior = true; + + // The next lump is not part of this map anymore + if (index < 0) break; + } + else + { + strncpy(maplabel, lumpname, 8); + maplabel[8]=0; + } + + map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); + strncpy(map->MapLumps[index].Name, lumpname, 8); + } + } + else + { + // This is a Build map and not subject to WAD consistency checks. + //map->MapLumps[0].Size = wadReader->GetLength(); + if (!P_IsBuildMap(map)) + { + delete map; + return NULL; + } + } + return map; +} + +bool P_CheckMapData(const char *mapname) +{ + MapData *mapd = P_OpenMapData(mapname, true); + if (mapd == NULL) return false; + delete mapd; + return true; +} + +//=========================================================================== +// +// MapData :: GetChecksum +// +// Hashes a map based on its header, THINGS, LINEDEFS, SIDEDEFS, SECTORS, +// and BEHAVIOR lumps. Node-builder generated lumps are not included. +// +//=========================================================================== + +void MapData::GetChecksum(uint8_t cksum[16]) +{ + MD5Context md5; + + if (isText) + { + md5.Update(Reader(ML_TEXTMAP), Size(ML_TEXTMAP)); + } + else + { + md5.Update(Reader(ML_LABEL), Size(ML_LABEL)); + md5.Update(Reader(ML_THINGS), Size(ML_THINGS)); + md5.Update(Reader(ML_LINEDEFS), Size(ML_LINEDEFS)); + md5.Update(Reader(ML_SIDEDEFS), Size(ML_SIDEDEFS)); + md5.Update(Reader(ML_SECTORS), Size(ML_SECTORS)); + } + if (HasBehavior) + { + md5.Update(Reader(ML_BEHAVIOR), Size(ML_BEHAVIOR)); + } + md5.Final(cksum); +} diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 16f609152..7dc77bf85 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -136,11 +136,6 @@ CVAR (Bool, showloadtimes, false, 0); static void P_Shutdown (); -inline bool P_IsBuildMap(MapData *map) -{ - return false; -} - inline bool P_LoadBuildMap(uint8_t *mapdata, size_t len, FMapThing **things, int *numthings) { return false; @@ -168,385 +163,6 @@ bool ForceNodeBuild; static void P_AllocateSideDefs (MapData *map, int count); -//=========================================================================== -// -// GetMapIndex -// -// Gets the type of map lump or -1 if invalid or -2 if required and not found. -// -//=========================================================================== - -struct checkstruct -{ - const char lumpname[9]; - bool required; -}; - -static int GetMapIndex(const char *mapname, int lastindex, const char *lumpname, bool needrequired) -{ - static const checkstruct check[] = - { - {"", true}, - {"THINGS", true}, - {"LINEDEFS", true}, - {"SIDEDEFS", true}, - {"VERTEXES", true}, - {"SEGS", false}, - {"SSECTORS", false}, - {"NODES", false}, - {"SECTORS", true}, - {"REJECT", false}, - {"BLOCKMAP", false}, - {"BEHAVIOR", false}, - //{"SCRIPTS", false}, - }; - - if (lumpname==NULL) lumpname=""; - - for(size_t i=lastindex+1;iresource = FResourceFile::OpenResourceFile(mapname, true); - wadReader = map->resource->GetReader(); - } - else - { - FString fmt; - int lump_wad; - int lump_map; - int lump_name = -1; - - // Check for both *.wad and *.map in order to load Build maps - // as well. The higher one will take precedence. - // Names with more than 8 characters will only be checked as .wad and .map. - if (strlen(mapname) <= 8) lump_name = Wads.CheckNumForName(mapname); - fmt.Format("maps/%s.wad", mapname); - lump_wad = Wads.CheckNumForFullName(fmt); - fmt.Format("maps/%s.map", mapname); - lump_map = Wads.CheckNumForFullName(fmt); - - if (lump_name > lump_wad && lump_name > lump_map && lump_name != -1) - { - int lumpfile = Wads.GetLumpFile(lump_name); - int nextfile = Wads.GetLumpFile(lump_name+1); - - map->lumpnum = lump_name; - - if (lumpfile != nextfile) - { - // The following lump is from a different file so whatever this is, - // it is not a multi-lump Doom level so let's assume it is a Build map. - map->MapLumps[0].Reader = Wads.ReopenLumpReader(lump_name); - if (!P_IsBuildMap(map)) - { - delete map; - return NULL; - } - return map; - } - - // This case can only happen if the lump is inside a real WAD file. - // As such any special handling for other types of lumps is skipped. - map->MapLumps[0].Reader = Wads.ReopenLumpReader(lump_name); - strncpy(map->MapLumps[0].Name, Wads.GetLumpFullName(lump_name), 8); - map->Encrypted = Wads.IsEncryptedFile(lump_name); - map->InWad = true; - - if (map->Encrypted) - { // If it's encrypted, then it's a Blood file, presumably a map. - if (!P_IsBuildMap(map)) - { - delete map; - return NULL; - } - return map; - } - - int index = 0; - - if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP") != 0) - { - for(int i = 1;; i++) - { - // Since levels must be stored in WADs they can't really have full - // names and for any valid level lump this always returns the short name. - const char * lumpname = Wads.GetLumpFullName(lump_name + i); - try - { - index = GetMapIndex(mapname, index, lumpname, !justcheck); - } - catch(...) - { - delete map; - throw; - } - if (index == -2) - { - delete map; - return NULL; - } - if (index == ML_BEHAVIOR) map->HasBehavior = true; - - // The next lump is not part of this map anymore - if (index < 0) break; - - map->MapLumps[index].Reader = Wads.ReopenLumpReader(lump_name + i); - strncpy(map->MapLumps[index].Name, lumpname, 8); - } - } - else - { - map->isText = true; - map->MapLumps[1].Reader = Wads.ReopenLumpReader(lump_name + 1); - for(int i = 2;; i++) - { - const char * lumpname = Wads.GetLumpFullName(lump_name + i); - - if (lumpname == NULL) - { - I_Error("Invalid map definition for %s", mapname); - } - else if (!stricmp(lumpname, "ZNODES")) - { - index = ML_GLZNODES; - } - else if (!stricmp(lumpname, "BLOCKMAP")) - { - // there is no real point in creating a blockmap but let's use it anyway - index = ML_BLOCKMAP; - } - else if (!stricmp(lumpname, "REJECT")) - { - index = ML_REJECT; - } - else if (!stricmp(lumpname, "DIALOGUE")) - { - index = ML_CONVERSATION; - } - else if (!stricmp(lumpname, "BEHAVIOR")) - { - index = ML_BEHAVIOR; - map->HasBehavior = true; - } - else if (!stricmp(lumpname, "ENDMAP")) - { - break; - } - else continue; - map->MapLumps[index].Reader = Wads.ReopenLumpReader(lump_name + i); - strncpy(map->MapLumps[index].Name, lumpname, 8); - } - } - return map; - } - else - { - if (lump_map > lump_wad) - { - lump_wad = lump_map; - } - if (lump_wad == -1) - { - delete map; - return NULL; - } - map->lumpnum = lump_wad; - auto reader = Wads.ReopenLumpReader(lump_wad); - map->resource = FResourceFile::OpenResourceFile(Wads.GetLumpFullName(lump_wad), reader, true); - wadReader = map->resource->GetReader(); - } - } - uint32_t id; - - // Although we're using the resource system, we still want to be sure we're - // reading from a wad file. - wadReader->Seek(0, FileReader::SeekSet); - wadReader->Read(&id, sizeof(id)); - - if (id == IWAD_ID || id == PWAD_ID) - { - char maplabel[9]=""; - int index=0; - - map->MapLumps[0].Reader = map->resource->GetLump(0)->NewReader(); - strncpy(map->MapLumps[0].Name, map->resource->GetLump(0)->Name, 8); - - for(uint32_t i = 1; i < map->resource->LumpCount(); i++) - { - const char* lumpname = map->resource->GetLump(i)->Name; - - if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) - { - map->isText = true; - map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetLump(i)->NewReader(); - strncpy(map->MapLumps[ML_TEXTMAP].Name, lumpname, 8); - for(int i = 2;; i++) - { - lumpname = map->resource->GetLump(i)->Name; - if (!strnicmp(lumpname, "ZNODES",8)) - { - index = ML_GLZNODES; - } - else if (!strnicmp(lumpname, "BLOCKMAP",8)) - { - // there is no real point in creating a blockmap but let's use it anyway - index = ML_BLOCKMAP; - } - else if (!strnicmp(lumpname, "REJECT",8)) - { - index = ML_REJECT; - } - else if (!strnicmp(lumpname, "DIALOGUE",8)) - { - index = ML_CONVERSATION; - } - else if (!strnicmp(lumpname, "BEHAVIOR",8)) - { - index = ML_BEHAVIOR; - map->HasBehavior = true; - } - else if (!strnicmp(lumpname, "ENDMAP",8)) - { - return map; - } - else continue; - map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); - strncpy(map->MapLumps[index].Name, lumpname, 8); - } - } - - if (i>0) - { - try - { - index = GetMapIndex(maplabel, index, lumpname, !justcheck); - } - catch(...) - { - delete map; - throw; - } - if (index == -2) - { - delete map; - return NULL; - } - if (index == ML_BEHAVIOR) map->HasBehavior = true; - - // The next lump is not part of this map anymore - if (index < 0) break; - } - else - { - strncpy(maplabel, lumpname, 8); - maplabel[8]=0; - } - - map->MapLumps[index].Reader = map->resource->GetLump(i)->NewReader(); - strncpy(map->MapLumps[index].Name, lumpname, 8); - } - } - else - { - // This is a Build map and not subject to WAD consistency checks. - //map->MapLumps[0].Size = wadReader->GetLength(); - if (!P_IsBuildMap(map)) - { - delete map; - return NULL; - } - } - return map; -} - -bool P_CheckMapData(const char *mapname) -{ - MapData *mapd = P_OpenMapData(mapname, true); - if (mapd == NULL) return false; - delete mapd; - return true; -} - -//=========================================================================== -// -// MapData :: GetChecksum -// -// Hashes a map based on its header, THINGS, LINEDEFS, SIDEDEFS, SECTORS, -// and BEHAVIOR lumps. Node-builder generated lumps are not included. -// -//=========================================================================== - -void MapData::GetChecksum(uint8_t cksum[16]) -{ - MD5Context md5; - - if (isText) - { - md5.Update(Reader(ML_TEXTMAP), Size(ML_TEXTMAP)); - } - else - { - md5.Update(Reader(ML_LABEL), Size(ML_LABEL)); - md5.Update(Reader(ML_THINGS), Size(ML_THINGS)); - md5.Update(Reader(ML_LINEDEFS), Size(ML_LINEDEFS)); - md5.Update(Reader(ML_SIDEDEFS), Size(ML_SIDEDEFS)); - md5.Update(Reader(ML_SECTORS), Size(ML_SECTORS)); - } - if (HasBehavior) - { - md5.Update(Reader(ML_BEHAVIOR), Size(ML_BEHAVIOR)); - } - md5.Final(cksum); -} - -DEFINE_ACTION_FUNCTION(FLevelLocals, GetChecksum) -{ - PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); - char md5string[33]; - - for(int j = 0; j < 16; ++j) - { - sprintf(md5string + j * 2, "%02x", level.md5[j]); - } - - ACTION_RETURN_STRING((const char*)md5string); -} - //=========================================================================== // // Sets a sidedef's texture and prints a message if it's not present. diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index ad44203b1..b29af9f9c 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -2506,6 +2506,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetUDMFString, ZGetUDMFString) ACTION_RETURN_STRING(GetUDMFString(type, index, key)); } +DEFINE_ACTION_FUNCTION(FLevelLocals, GetChecksum) +{ + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + char md5string[33]; + + for (int j = 0; j < 16; ++j) + { + sprintf(md5string + j * 2, "%02x", level.md5[j]); + } + + ACTION_RETURN_STRING((const char*)md5string); +} + //===================================================================================== // // From 8c52f20373aecbab19bdd95f5f27a33b0af5f865 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 20 Dec 2018 04:27:30 +0100 Subject: [PATCH 4/8] - fix MemcpyCommand not using the same lines for the threads as softpoly (visible as a race condition when screenblocks didn't start at top of screen) --- src/polyrenderer/drawers/poly_triangle.cpp | 19 +++----- src/polyrenderer/drawers/poly_triangle.h | 16 ++++++- src/polyrenderer/drawers/screen_triangle.cpp | 49 +++++++++++++------- src/swrenderer/drawers/r_thread.cpp | 5 ++ 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp index 1949b06e3..fab366296 100644 --- a/src/polyrenderer/drawers/poly_triangle.cpp +++ b/src/polyrenderer/drawers/poly_triangle.cpp @@ -68,17 +68,16 @@ void PolyTriangleDrawer::SetViewport(const DrawerCommandQueuePtr &queue, int x, isBgraRenderTarget = dest_bgra; int offsetx = clamp(x, 0, dest_width); - int offsety = clamp(y, 0, dest_height); int pixelsize = dest_bgra ? 4 : 1; int viewport_x = x - offsetx; - int viewport_y = y - offsety; + int viewport_y = y; int viewport_width = width; int viewport_height = height; - dest += (offsetx + offsety * dest_pitch) * pixelsize; + dest += offsetx * pixelsize; dest_width = clamp(viewport_x + viewport_width, 0, dest_width - offsetx); - dest_height = clamp(viewport_y + viewport_height, 0, dest_height - offsety); + dest_height = clamp(viewport_y + viewport_height, 0, dest_height); queue->Push(viewport_x, viewport_y, viewport_width, viewport_height, dest, dest_width, dest_height, dest_pitch, dest_bgra); } @@ -127,13 +126,11 @@ void PolyTriangleThreadData::ClearStencil(uint8_t value) int height = buffer->Height(); uint8_t *data = buffer->Values(); - int start_y = numa_node * height / num_numa_nodes; - int end_y = (numa_node + 1) * height / num_numa_nodes; - int core_skip = (num_cores - (start_y - core) % num_cores) % num_cores; - start_y += core_skip; + int skip = skipped_by_thread(0); + int count = count_for_thread(0, height); - data += start_y * width; - for (int y = start_y; y < end_y; y += num_cores) + data += skip * width; + for (int i = 0; i < count; i++) { memset(data, value, width); data += num_cores * width; @@ -151,8 +148,6 @@ void PolyTriangleThreadData::SetViewport(int x, int y, int width, int height, ui dest_height = new_dest_height; dest_pitch = new_dest_pitch; dest_bgra = new_dest_bgra; - numa_start_y = numa_node * screen->GetHeight() / num_numa_nodes; - numa_end_y = (numa_node + 1) * screen->GetHeight() / num_numa_nodes; ccw = true; weaponScene = false; } diff --git a/src/polyrenderer/drawers/poly_triangle.h b/src/polyrenderer/drawers/poly_triangle.h index fadc799d6..4504a3950 100644 --- a/src/polyrenderer/drawers/poly_triangle.h +++ b/src/polyrenderer/drawers/poly_triangle.h @@ -71,7 +71,11 @@ public: int numa_start_y; int numa_end_y; - // The number of lines to skip to reach the first line to be rendered by this thread + bool line_skipped_by_thread(int line) + { + return line < numa_start_y || line >= numa_end_y || line % num_cores != core; + } + int skipped_by_thread(int first_line) { int clip_first_line = MAX(first_line, numa_start_y); @@ -79,6 +83,13 @@ public: return clip_first_line + core_skip - first_line; } + int count_for_thread(int first_line, int count) + { + count = MIN(count, numa_end_y - first_line); + int c = (count - skipped_by_thread(first_line) + num_cores - 1) / num_cores; + return MAX(c, 0); + } + // Varyings float worldposX[MAXWIDTH]; float worldposY[MAXWIDTH]; @@ -97,6 +108,8 @@ public: uint8_t *dest = nullptr; bool weaponScene = false; + int viewport_y = 0; + private: ShadedTriVertex ShadeVertex(const PolyDrawArgs &drawargs, const void *vertices, int index); void DrawShadedTriangle(const ShadedTriVertex *vertices, bool ccw, TriDrawTriangleArgs *args); @@ -105,7 +118,6 @@ private: static int ClipEdge(const ShadedTriVertex *verts, ShadedTriVertex *clippedvert); int viewport_x = 0; - int viewport_y = 0; int viewport_width = 0; int viewport_height = 0; bool ccw = true; diff --git a/src/polyrenderer/drawers/screen_triangle.cpp b/src/polyrenderer/drawers/screen_triangle.cpp index 551753c20..151e86a9f 100644 --- a/src/polyrenderer/drawers/screen_triangle.cpp +++ b/src/polyrenderer/drawers/screen_triangle.cpp @@ -60,73 +60,84 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat ShadedTriVertex *sortedVertices[3]; SortVertices(args, sortedVertices); + int clipleft = 0; + int cliptop = MAX(thread->viewport_y, thread->numa_start_y); int clipright = thread->dest_width; - int cliptop = thread->numa_start_y; int clipbottom = MIN(thread->dest_height, thread->numa_end_y); int topY = (int)(sortedVertices[0]->y + 0.5f); int midY = (int)(sortedVertices[1]->y + 0.5f); int bottomY = (int)(sortedVertices[2]->y + 0.5f); - topY = MAX(topY, 0); - midY = clamp(midY, 0, clipbottom); + topY = MAX(topY, cliptop); + midY = MIN(midY, clipbottom); bottomY = MIN(bottomY, clipbottom); if (topY >= bottomY) return; + topY += thread->skipped_by_thread(topY); + int num_cores = thread->num_cores; + // Find start/end X positions for each line covered by the triangle: int16_t edges[MAXHEIGHT * 2]; + int y = topY; + float longDX = sortedVertices[2]->x - sortedVertices[0]->x; float longDY = sortedVertices[2]->y - sortedVertices[0]->y; float longStep = longDX / longDY; - float longPos = sortedVertices[0]->x + longStep * (topY + 0.5f - sortedVertices[0]->y) + 0.5f; + float longPos = sortedVertices[0]->x + longStep * (y + 0.5f - sortedVertices[0]->y) + 0.5f; + longStep *= num_cores; - if (topY < midY) + if (y < midY) { float shortDX = sortedVertices[1]->x - sortedVertices[0]->x; float shortDY = sortedVertices[1]->y - sortedVertices[0]->y; float shortStep = shortDX / shortDY; - float shortPos = sortedVertices[0]->x + shortStep * (topY + 0.5f - sortedVertices[0]->y) + 0.5f; + float shortPos = sortedVertices[0]->x + shortStep * (y + 0.5f - sortedVertices[0]->y) + 0.5f; + shortStep *= num_cores; - for (int y = topY; y < midY; y++) + while (y < midY) { int x0 = (int)shortPos; int x1 = (int)longPos; if (x1 < x0) std::swap(x0, x1); - x0 = clamp(x0, 0, clipright); - x1 = clamp(x1, 0, clipright); + x0 = clamp(x0, clipleft, clipright); + x1 = clamp(x1, clipleft, clipright); edges[y << 1] = x0; edges[(y << 1) + 1] = x1; shortPos += shortStep; longPos += longStep; + y += num_cores; } } - if (midY < bottomY) + if (y < bottomY) { float shortDX = sortedVertices[2]->x - sortedVertices[1]->x; float shortDY = sortedVertices[2]->y - sortedVertices[1]->y; float shortStep = shortDX / shortDY; - float shortPos = sortedVertices[1]->x + shortStep * (midY + 0.5f - sortedVertices[1]->y) + 0.5f; + float shortPos = sortedVertices[1]->x + shortStep * (y + 0.5f - sortedVertices[1]->y) + 0.5f; + shortStep *= num_cores; - for (int y = midY; y < bottomY; y++) + while (y < bottomY) { int x0 = (int)shortPos; int x1 = (int)longPos; if (x1 < x0) std::swap(x0, x1); - x0 = clamp(x0, 0, clipright); - x1 = clamp(x1, 0, clipright); + x0 = clamp(x0, clipleft, clipright); + x1 = clamp(x1, clipleft, clipright); edges[y << 1] = x0; edges[(y << 1) + 1] = x1; shortPos += shortStep; longPos += longStep; + y += num_cores; } } @@ -183,8 +194,14 @@ void DrawTriangle(const TriDrawTriangleArgs *args, PolyTriangleThreadData *threa if (OptT::Flags & SWTRI_WriteStencil) stencilWriteValue = args->uniforms->StencilWriteValue(); + float weaponWOffset; + if ((OptT::Flags & SWTRI_DepthTest) || (OptT::Flags & SWTRI_WriteDepth)) + { + weaponWOffset = thread->weaponScene ? 1.0f : 0.0f; + } + int num_cores = thread->num_cores; - for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores) + for (int y = topY; y < bottomY; y += num_cores) { int x = edges[y << 1]; int xend = edges[(y << 1) + 1]; @@ -198,7 +215,7 @@ void DrawTriangle(const TriDrawTriangleArgs *args, PolyTriangleThreadData *threa float startX = x + (0.5f - v1X); float startY = y + (0.5f - v1Y); - posXW = v1W + stepXW * startX + args->gradientY.W * startY + (thread->weaponScene ? 1.0f : 0.0f); + posXW = v1W + stepXW * startX + args->gradientY.W * startY + weaponWOffset; } #ifndef NO_SSE diff --git a/src/swrenderer/drawers/r_thread.cpp b/src/swrenderer/drawers/r_thread.cpp index 5055e259b..e8b6eeada 100644 --- a/src/swrenderer/drawers/r_thread.cpp +++ b/src/swrenderer/drawers/r_thread.cpp @@ -142,6 +142,11 @@ void DrawerThreads::WorkerMain(DrawerThread *thread) thread->current_queue++; thread->numa_start_y = thread->numa_node * screen->GetHeight() / thread->num_numa_nodes; thread->numa_end_y = (thread->numa_node + 1) * screen->GetHeight() / thread->num_numa_nodes; + if (thread->poly) + { + thread->poly->numa_start_y = thread->numa_start_y; + thread->poly->numa_end_y = thread->numa_end_y; + } start_lock.unlock(); // Do the work: From b0d8a813f94cc298b9b484fa4438e7599b09e090 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 20 Dec 2018 04:50:45 +0100 Subject: [PATCH 5/8] - fix missing line number for the function throwing the exception and remove the duplicate call stack line --- src/scripting/vm/jit.cpp | 18 ++++++++++----- src/scripting/vm/jit_flow.cpp | 41 +++++++++++++++++++++-------------- src/scripting/vm/jitintern.h | 4 ++-- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/scripting/vm/jit.cpp b/src/scripting/vm/jit.cpp index 1e94e3ada..1813d19ca 100644 --- a/src/scripting/vm/jit.cpp +++ b/src/scripting/vm/jit.cpp @@ -156,6 +156,8 @@ asmjit::CCFunc *JitCompiler::Codegen() LineInfo[j] = info; } + std::stable_sort(LineInfo.begin(), LineInfo.end(), [](const JitLineInfo &a, const JitLineInfo &b) { return a.InstructionIndex < b.InstructionIndex; }); + return func; } @@ -444,17 +446,15 @@ void JitCompiler::EmitNullPointerThrow(int index, EVMAbortException reason) cc.je(label); } -void JitCompiler::ThrowException(VMScriptFunction *func, VMOP *line, int reason) +void JitCompiler::ThrowException(int reason) { - ThrowAbortException(func, line, (EVMAbortException)reason, nullptr); + ThrowAbortException((EVMAbortException)reason, nullptr); } void JitCompiler::EmitThrowException(EVMAbortException reason) { - auto call = CreateCall(&JitCompiler::ThrowException); - call->setArg(0, asmjit::imm_ptr(sfunc)); - call->setArg(1, asmjit::imm_ptr(pc)); - call->setArg(2, asmjit::imm(reason)); + auto call = CreateCall(&JitCompiler::ThrowException); + call->setArg(0, asmjit::imm(reason)); } asmjit::Label JitCompiler::EmitThrowExceptionLabel(EVMAbortException reason) @@ -464,6 +464,12 @@ asmjit::Label JitCompiler::EmitThrowExceptionLabel(EVMAbortException reason) cc.bind(label); EmitThrowException(reason); cc.setCursor(cursor); + + JitLineInfo info; + info.Label = label; + info.LineNumber = sfunc->PCToLine(pc); + LineInfo.Push(info); + return label; } diff --git a/src/scripting/vm/jit_flow.cpp b/src/scripting/vm/jit_flow.cpp index 0ca8bf437..96b7bcec0 100644 --- a/src/scripting/vm/jit_flow.cpp +++ b/src/scripting/vm/jit_flow.cpp @@ -330,15 +330,18 @@ void JitCompiler::EmitBOUND() auto cursor = cc.getCursor(); auto label = cc.newLabel(); cc.bind(label); - auto call = CreateCall(&JitCompiler::ThrowArrayOutOfBounds); - call->setArg(0, asmjit::imm_ptr(sfunc)); - call->setArg(1, asmjit::imm_ptr(pc)); - call->setArg(2, regD[A]); - call->setArg(3, asmjit::imm(BC)); + auto call = CreateCall(&JitCompiler::ThrowArrayOutOfBounds); + call->setArg(0, regD[A]); + call->setArg(1, asmjit::imm(BC)); cc.setCursor(cursor); cc.cmp(regD[A], (int)BC); cc.jae(label); + + JitLineInfo info; + info.Label = label; + info.LineNumber = sfunc->PCToLine(pc); + LineInfo.Push(info); } void JitCompiler::EmitBOUND_K() @@ -346,15 +349,18 @@ void JitCompiler::EmitBOUND_K() auto cursor = cc.getCursor(); auto label = cc.newLabel(); cc.bind(label); - auto call = CreateCall(&JitCompiler::ThrowArrayOutOfBounds); - call->setArg(0, asmjit::imm_ptr(sfunc)); - call->setArg(1, asmjit::imm_ptr(pc)); - call->setArg(2, regD[A]); - call->setArg(3, asmjit::imm(konstd[BC])); + auto call = CreateCall(&JitCompiler::ThrowArrayOutOfBounds); + call->setArg(0, regD[A]); + call->setArg(1, asmjit::imm(konstd[BC])); cc.setCursor(cursor); cc.cmp(regD[A], (int)konstd[BC]); cc.jae(label); + + JitLineInfo info; + info.Label = label; + info.LineNumber = sfunc->PCToLine(pc); + LineInfo.Push(info); } void JitCompiler::EmitBOUND_R() @@ -362,18 +368,21 @@ void JitCompiler::EmitBOUND_R() auto cursor = cc.getCursor(); auto label = cc.newLabel(); cc.bind(label); - auto call = CreateCall(&JitCompiler::ThrowArrayOutOfBounds); - call->setArg(0, asmjit::imm_ptr(sfunc)); - call->setArg(1, asmjit::imm_ptr(pc)); - call->setArg(2, regD[A]); - call->setArg(3, regD[B]); + auto call = CreateCall(&JitCompiler::ThrowArrayOutOfBounds); + call->setArg(0, regD[A]); + call->setArg(1, regD[B]); cc.setCursor(cursor); cc.cmp(regD[A], regD[B]); cc.jae(label); + + JitLineInfo info; + info.Label = label; + info.LineNumber = sfunc->PCToLine(pc); + LineInfo.Push(info); } -void JitCompiler::ThrowArrayOutOfBounds(VMScriptFunction *func, VMOP *line, int index, int size) +void JitCompiler::ThrowArrayOutOfBounds(int index, int size) { if (index >= size) { diff --git a/src/scripting/vm/jitintern.h b/src/scripting/vm/jitintern.h index deb0378f0..67659e6e0 100644 --- a/src/scripting/vm/jitintern.h +++ b/src/scripting/vm/jitintern.h @@ -219,8 +219,8 @@ private: void EmitThrowException(EVMAbortException reason); asmjit::Label EmitThrowExceptionLabel(EVMAbortException reason); - static void ThrowArrayOutOfBounds(VMScriptFunction *func, VMOP *line, int index, int size); - static void ThrowException(VMScriptFunction *func, VMOP *line, int reason); + static void ThrowArrayOutOfBounds(int index, int size); + static void ThrowException(int reason); asmjit::X86Gp CheckRegD(int r0, int r1); asmjit::X86Xmm CheckRegF(int r0, int r1); From e05cedfc0d72c4a89b59311a3d97d77150ef5f1a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 20 Dec 2018 12:40:38 +0100 Subject: [PATCH 6/8] removed the unused DefaultExtension variant taking a char *. --- src/cmdlib.cpp | 27 --------------------------- src/cmdlib.h | 1 - 2 files changed, 28 deletions(-) diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index af89cb352..b313f5691 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -195,33 +195,6 @@ bool DirEntryExists(const char *pathname, bool *isdir) return res; } -//========================================================================== -// -// DefaultExtension -- char array version -// -// Appends the extension to a pathname if it does not already have one. -// -//========================================================================== - -void DefaultExtension (char *path, const char *extension) -{ - char *src; -// -// if path doesn't have a .EXT, append extension -// (extension should include the .) -// - src = path + strlen(path) - 1; - - while (src != path && !IsSeperator(*src)) - { - if (*src == '.') - return; // it has an extension - src--; - } - - strcat (path, extension); -} - //========================================================================== // // DefaultExtension -- FString version diff --git a/src/cmdlib.h b/src/cmdlib.h index 7a5fa21a6..d187b43cf 100644 --- a/src/cmdlib.h +++ b/src/cmdlib.h @@ -27,7 +27,6 @@ extern FString progdir; void FixPathSeperator (char *path); static void inline FixPathSeperator (FString &path) { path.ReplaceChars('\\', '/'); } -void DefaultExtension (char *path, const char *extension); void DefaultExtension (FString &path, const char *extension); FString ExtractFilePath (const char *path); From 120b9502912ccf81962b0fa1d67ba2472791cf80 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 20 Dec 2018 18:10:06 +0100 Subject: [PATCH 7/8] - changed FTextureManager::ReplaceTexture to only append the new texture instead of replacing the old one. This should ensure that other references to the original will remain valid. --- src/textures/texture.cpp | 2 +- src/textures/texturemanager.cpp | 15 ++++----------- src/textures/textures.h | 1 - 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 44203413a..118bbf5bc 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -138,7 +138,7 @@ FTexture::FTexture (const char *name, int lumpnum) : Scale(1,1), SourceLump(lumpnum), UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false), - bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bKeepAround(false), bFullNameTexture(false), + bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bFullNameTexture(false), Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0) { bBrightmapChecked = false; diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 799edb4aa..584664d3f 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -468,17 +468,10 @@ void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, b newtexture->Name = oldtexture->Name; newtexture->UseType = oldtexture->UseType; - Textures[index].Texture = newtexture; - - newtexture->id = oldtexture->id; - if (free && !oldtexture->bKeepAround) - { - delete oldtexture; - } - else - { - oldtexture->id.SetInvalid(); - } + // Add the new texture at the end of the texture list and clear the old one's name to ensure it won't be found anymore + // We cannot actually replace it because it may be referenced by some other texture. + oldtexture->Name = ""; + AddTexture(newtexture); } //========================================================================== diff --git a/src/textures/textures.h b/src/textures/textures.h index a91be051b..52ed052db 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -407,7 +407,6 @@ protected: // fully composited before subjected to any kind of postprocessing instead of // doing it per patch. uint8_t bMultiPatch:2; // This is a multipatch texture (we really could use real type info for textures...) - uint8_t bKeepAround:1; // This texture was used as part of a multi-patch texture. Do not free it. uint8_t bFullNameTexture : 1; uint8_t bBrightmapChecked : 1; // Set to 1 if brightmap has been checked uint8_t bGlowing : 1; // Texture glow color From d140d767a497d20a8272a308a5d9e7b7199ee47e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 20 Dec 2018 18:20:25 +0100 Subject: [PATCH 8/8] - changed last commit to let the replacement take the original's place and add the old texture at the end with its name cleared. This is to ensure that this won't break ranged animations but aside from that should produce the same end result. --- src/textures/texturemanager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 584664d3f..1c535f4df 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -468,10 +468,10 @@ void FTextureManager::ReplaceTexture (FTextureID picnum, FTexture *newtexture, b newtexture->Name = oldtexture->Name; newtexture->UseType = oldtexture->UseType; - // Add the new texture at the end of the texture list and clear the old one's name to ensure it won't be found anymore - // We cannot actually replace it because it may be referenced by some other texture. + Textures[index].Texture = newtexture; + newtexture->id = oldtexture->id; oldtexture->Name = ""; - AddTexture(newtexture); + AddTexture(oldtexture); } //==========================================================================