From c645269c86256be75ddd495dabd49993103df5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Fri, 20 Dec 2024 17:14:35 +0100 Subject: [PATCH] Only copy the live portion of parts when SRT is enabled One major downside of SRT is that a RenderableSimulation has to be copied between the main thread and the rendering thread, which may actually take more time than to render on the main thread. This commit reduces the impact of this copy by copying only the subset of RenderableSimulation::parts that actually matters. --- src/debug/DebugParts.cpp | 4 ++-- src/graphics/Renderer.cpp | 6 +++--- src/lua/LuaSimulation.cpp | 4 ++-- src/simulation/Air.cpp | 2 +- src/simulation/Editing.cpp | 8 ++++---- src/simulation/ElementDefs.h | 3 ++- src/simulation/Simulation.cpp | 32 ++++++++++++++++---------------- src/simulation/Simulation.h | 29 +++++++++++++++++++++++++---- src/simulation/elements/EMP.cpp | 2 +- src/simulation/elements/ETRD.cpp | 6 +++--- 10 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/debug/DebugParts.cpp b/src/debug/DebugParts.cpp index 30748cd5b..7f0dea788 100644 --- a/src/debug/DebugParts.cpp +++ b/src/debug/DebugParts.cpp @@ -18,7 +18,7 @@ void DebugParts::Draw() Graphics * g = ui::Engine::Ref().g; int x = 0, y = 0, lpx = 0, lpy = 0; - String info = String::Build(sim->parts_lastActiveIndex, "/", NPART, " (", Format::Precision((float)sim->parts_lastActiveIndex/(NPART)*100.0f, 2), "%)"); + String info = String::Build(sim->parts.lastActiveIndex, "/", NPART, " (", Format::Precision((float)sim->parts.lastActiveIndex/(NPART)*100.0f, 2), "%)"); for (int i = 0; i < NPART; i++) { if (sim->parts[i].type) @@ -26,7 +26,7 @@ void DebugParts::Draw() else g->AddPixel({ x, y }, 0x000000_rgb .WithAlpha(180)); - if (i == sim->parts_lastActiveIndex) + if (i == sim->parts.lastActiveIndex) { lpx = x; lpy = y; diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 6d42e7272..af5659b31 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -249,7 +249,7 @@ void Renderer::render_parts() int orbd[4] = {0, 0, 0, 0}, orbl[4] = {0, 0, 0, 0}; int drawing_budget = 1000000; //Serves as an upper bound for costly effects such as SPARK, FLARE and LFLARE - auto *parts = sim->parts; + auto &parts = sim->parts; if (gridSize)//draws the grid { for (ny=0; nyparts_lastActiveIndex; i++) { + for(i = 0; i<=sim->parts.lastActiveIndex; i++) { if (sim->parts[i].type && sim->parts[i].type >= 0 && sim->parts[i].type < PT_NUM) { t = sim->parts[i].type; @@ -801,7 +801,7 @@ void Renderer::render_parts() type = PT_PRTO; else if (type == PT_PRTO) type = PT_PRTI; - for (int z = 0; z <= sim->parts_lastActiveIndex; z++) + for (int z = 0; z <= sim->parts.lastActiveIndex; z++) { if (parts[z].type == type) { diff --git a/src/lua/LuaSimulation.cpp b/src/lua/LuaSimulation.cpp index c9dad3cbc..f3ed5480a 100644 --- a/src/lua/LuaSimulation.cpp +++ b/src/lua/LuaSimulation.cpp @@ -862,7 +862,7 @@ static int resetTemp(lua_State *L) auto &sd = SimulationData::CRef(); auto &elements = sd.elements; bool onlyConductors = luaL_optint(L, 1, 0); - for (int i = 0; i < sim->parts_lastActiveIndex; i++) + for (int i = 0; i < sim->parts.lastActiveIndex; i++) { if (sim->parts[i].type && (elements[sim->parts[i].type].HeatConduct || !onlyConductors)) { @@ -1286,7 +1286,7 @@ static int brush(lua_State *L) static int partsClosure(lua_State *L) { auto *lsi = GetLSI(); - for (int i = lua_tointeger(L, lua_upvalueindex(1)); i <= lsi->sim->parts_lastActiveIndex; ++i) + for (int i = lua_tointeger(L, lua_upvalueindex(1)); i <= lsi->sim->parts.lastActiveIndex; ++i) { if (lsi->sim->parts[i].type) { diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp index 60f564559..376012bdf 100644 --- a/src/simulation/Air.cpp +++ b/src/simulation/Air.cpp @@ -418,7 +418,7 @@ void Air::ApproximateBlockAirMaps() { auto &sd = SimulationData::CRef(); auto &elements = sd.elements; - for (int i = 0; i <= sim.parts_lastActiveIndex; i++) + for (int i = 0; i <= sim.parts.lastActiveIndex; i++) { int type = sim.parts[i].type; if (!type) diff --git a/src/simulation/Editing.cpp b/src/simulation/Editing.cpp index ca8b995e6..241e97dbf 100644 --- a/src/simulation/Editing.cpp +++ b/src/simulation/Editing.cpp @@ -25,7 +25,7 @@ std::unique_ptr Simulation::CreateSnapshot() const snap->BlockAirH .insert (snap->BlockAirH .begin(), &air->bmap_blockairh[0][0], &air->bmap_blockairh[0][0] + NCELL); snap->FanVelocityX .insert (snap->FanVelocityX .begin(), &fvx [0][0] , &fvx [0][0] + NCELL); snap->FanVelocityY .insert (snap->FanVelocityY .begin(), &fvy [0][0] , &fvy [0][0] + NCELL); - snap->Particles .insert (snap->Particles .begin(), &parts [0] , &parts [0] + parts_lastActiveIndex + 1); + snap->Particles .insert (snap->Particles .begin(), &parts [0] , &parts [0] + parts.lastActiveIndex + 1); snap->PortalParticles.insert (snap->PortalParticles.begin(), &portalp[0][0][0], &portalp[0][0][0] + CHANNELS * 8 * 80); snap->WirelessData .insert (snap->WirelessData .begin(), &wireless[0][0] , &wireless[0][0] + CHANNELS * 2); snap->stickmen .insert (snap->stickmen .begin(), &fighters[0] , &fighters[0] + MAX_FIGHTERS); @@ -45,7 +45,7 @@ void Simulation::Restore(const Snapshot &snap) std::fill(elementCount, elementCount + PT_NUM, 0); elementRecount = true; force_stacking_check = true; - for (auto &part : parts) + for (auto &part : parts.data) { part.type = 0; } @@ -78,7 +78,7 @@ void Simulation::Restore(const Snapshot &snap) signs = snap.signs; frameCount = snap.FrameCount; rng.state(snap.RngState); - parts_lastActiveIndex = NPART - 1; + parts.lastActiveIndex = NPART - 1; RecalcFreeParticles(false); } @@ -90,7 +90,7 @@ void Simulation::clear_area(int area_x, int area_y, int area_w, int area_h) area_w = intersection.size.X; area_h = intersection.size.Y; float fx = area_x-.5f, fy = area_y-.5f; - for (int i = 0; i <= parts_lastActiveIndex; i++) + for (int i = 0; i <= parts.lastActiveIndex; i++) { if (parts[i].type) if (parts[i].x >= fx && parts[i].x <= fx+area_w+1 && parts[i].y >= fy && parts[i].y <= fy+area_h+1) diff --git a/src/simulation/ElementDefs.h b/src/simulation/ElementDefs.h index 3f16befde..f54edd41b 100644 --- a/src/simulation/ElementDefs.h +++ b/src/simulation/ElementDefs.h @@ -39,7 +39,7 @@ constexpr auto FLAG_MOVABLE = UINT32_C(0x00000008); // compatibility with constexpr auto FLAG_PHOTDECO = UINT32_C(0x00000008); // compatibility with old saves (decorated photons), only applies to PHOT. Having the same value as FLAG_MOVABLE is fine because they apply to different elements, and this saves space for future flags, -#define UPDATE_FUNC_ARGS Simulation* sim, int i, int x, int y, int surround_space, int nt, Particle *parts, int pmap[YRES][XRES] +#define UPDATE_FUNC_ARGS Simulation* sim, int i, int x, int y, int surround_space, int nt, Parts &parts, int pmap[YRES][XRES] #define UPDATE_FUNC_SUBCALL_ARGS sim, i, x, y, surround_space, nt, parts, pmap #define GRAPHICS_FUNC_ARGS GraphicsFuncContext &gfctx, const Particle *cpart, int nx, int ny, int *pixel_mode, int* cola, int *colr, int *colg, int *colb, int *firea, int *firer, int *fireg, int *fireb @@ -83,3 +83,4 @@ constexpr bool InBounds(int x, int y) } struct playerst; +struct Parts; diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 08154b0b5..2b4853555 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -39,7 +39,7 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2 bloc }; std::vector existingParticles; auto pasteArea = RES.OriginRect() & RectSized(partP, save->blockSize * CELL); - for (int i = 0; i <= parts_lastActiveIndex; i++) + for (int i = 0; i <= parts.lastActiveIndex; i++) { if (parts[i].type) { @@ -132,8 +132,8 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2 bloc auto i = pfree; pfree = parts[i].life; NUM_PARTS += 1; - if (i > parts_lastActiveIndex) - parts_lastActiveIndex = i; + if (i > parts.lastActiveIndex) + parts.lastActiveIndex = i; parts[i] = tempPart; elementCount[tempPart.type]++; @@ -219,7 +219,7 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2 bloc parts[i].tmp3 = 0; } } - parts_lastActiveIndex = NPART-1; + parts.lastActiveIndex = NPART-1; force_stacking_check = true; Element_PPIP_ppip_changed = 1; @@ -992,7 +992,7 @@ void Simulation::clear_sim(void) parts[NPART-1].life = -1; pfree = 0; NUM_PARTS = 0; - parts_lastActiveIndex = 0; + parts.lastActiveIndex = 0; memset(pmap, 0, sizeof(pmap)); memset(fvx, 0, sizeof(fvx)); memset(fvy, 0, sizeof(fvy)); @@ -1890,7 +1890,7 @@ int Simulation::create_part(int p, int x, int y, int t, int v) i = p; } - if (i>parts_lastActiveIndex) parts_lastActiveIndex = i; + if (i>parts.lastActiveIndex) parts.lastActiveIndex = i; parts[i] = elements[t].DefaultProperties; parts[i].type = t; @@ -1993,7 +1993,7 @@ void Simulation::create_gain_photon(int pp)//photons from PHOT going through GLO pfree = parts[i].life; NUM_PARTS += 1; - if (i>parts_lastActiveIndex) parts_lastActiveIndex = i; + if (i>parts.lastActiveIndex) parts.lastActiveIndex = i; parts[i].type = PT_PHOT; parts[i].life = 680; @@ -2032,7 +2032,7 @@ void Simulation::create_cherenkov_photon(int pp)//photons from NEUT going throug pfree = parts[i].life; NUM_PARTS += 1; - if (i>parts_lastActiveIndex) parts_lastActiveIndex = i; + if (i>parts.lastActiveIndex) parts.lastActiveIndex = i; lr = rng.between(0, 1); @@ -2210,7 +2210,7 @@ void Simulation::UpdateParticles(int start, int end) //the main particle loop function, goes over all particles. auto &sd = SimulationData::CRef(); auto &elements = sd.elements; - for (auto i = start; i < end && i <= parts_lastActiveIndex; i++) + for (auto i = start; i < end && i <= parts.lastActiveIndex; i++) { if (parts[i].type) { @@ -3363,7 +3363,7 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) auto &sd = SimulationData::CRef(); auto &elements = sd.elements; //the particle loop that resets the pmap/photon maps every frame, to update them. - for (int i = 0; i <= parts_lastActiveIndex; i++) + for (int i = 0; i <= parts.lastActiveIndex; i++) { if (parts[i].type) { @@ -3431,13 +3431,13 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) } if (lastPartUnused == -1) { - pfree = (parts_lastActiveIndex>=(NPART-1)) ? -1 : parts_lastActiveIndex+1; + pfree = (parts.lastActiveIndex>=(NPART-1)) ? -1 : parts.lastActiveIndex+1; } else { - parts[lastPartUnused].life = (parts_lastActiveIndex>=(NPART-1)) ? -1 : parts_lastActiveIndex+1; + parts[lastPartUnused].life = (parts.lastActiveIndex>=(NPART-1)) ? -1 : parts.lastActiveIndex+1; } - parts_lastActiveIndex = lastPartUsed; + parts.lastActiveIndex = lastPartUsed; if (elementRecount) elementRecount = false; } @@ -3446,7 +3446,7 @@ void Simulation::SimulateGoL() { auto &builtinGol = SimulationData::builtinGol; CGOL = 0; - for (int i = 0; i <= parts_lastActiveIndex; ++i) + for (int i = 0; i <= parts.lastActiveIndex; ++i) { auto &part = parts[i]; if (part.type != PT_LIFE) @@ -3652,7 +3652,7 @@ void Simulation::CheckStacking() } if (excessive_stacking_found) { - for (int i = 0; i <= parts_lastActiveIndex; i++) + for (int i = 0; i <= parts.lastActiveIndex; i++) { if (parts[i].type) { @@ -3877,7 +3877,7 @@ void Simulation::BeforeSim() // update PPIP tmp? if (Element_PPIP_ppip_changed) { - for (int i = 0; i <= parts_lastActiveIndex; i++) + for (int i = 0; i <= parts.lastActiveIndex; i++) { if (parts[i].type==PT_PPIP) { diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index 22dc2ebb2..d9ae34150 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -34,6 +34,30 @@ class Renderer; class Air; class GameSave; +struct Parts +{ + std::array data; + // initialized in clear_sim + int lastActiveIndex; + + operator const Particle *() const + { + return data.data(); + } + + operator Particle *() + { + return data.data(); + } + + Parts &operator =(const Parts &other) + { + std::copy(other.data.begin(), other.data.begin() + lastActiveIndex + 1, data.begin()); + lastActiveIndex = other.lastActiveIndex; + return *this; + } +}; + struct RenderableSimulation { GravityInput gravIn; @@ -56,15 +80,12 @@ struct RenderableSimulation unsigned char bmap[YCELLS][XCELLS]; unsigned char emap[YCELLS][XCELLS]; - Particle parts[NPART]; + Parts parts; int pmap[YRES][XRES]; int photons[YRES][XRES]; int aheat_enable = 0; - // initialized in clear_sim - int parts_lastActiveIndex; - bool useLuaCallbacks = false; }; diff --git a/src/simulation/elements/EMP.cpp b/src/simulation/elements/EMP.cpp index 443dbcb14..82cb62f19 100644 --- a/src/simulation/elements/EMP.cpp +++ b/src/simulation/elements/EMP.cpp @@ -105,7 +105,7 @@ void Element_EMP_Trigger(Simulation *sim, int triggerCount) float prob_randDLAY = Probability::binomial_gte1(triggerCount, 1.0f/70); - for (int r = 0; r <=sim->parts_lastActiveIndex; r++) + for (int r = 0; r <=sim->parts.lastActiveIndex; r++) { int t = parts[r].type; auto rx = int(parts[r].x); diff --git a/src/simulation/elements/ETRD.cpp b/src/simulation/elements/ETRD.cpp index 888069817..74f991eea 100644 --- a/src/simulation/elements/ETRD.cpp +++ b/src/simulation/elements/ETRD.cpp @@ -115,7 +115,7 @@ int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId) // If the simulation contains lots of particles, check near the target position first since going through all particles will be slow. // Threshold = number of positions checked, *2 because it's likely to access memory all over the place (less cache friendly) and there's extra logic needed // TODO: probably not optimal if excessive stacking is used - if (sim->parts_lastActiveIndex > (int)deltaPos.size()*2) + if (sim->parts.lastActiveIndex > (int)deltaPos.size()*2) { for (std::vector::iterator iter = deltaPos.begin(), end = deltaPos.end(); iter != end; ++iter) { @@ -145,7 +145,7 @@ int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId) // If neighbor search didn't find a suitable particle, search all particles if (foundI < 0) { - for (int i = 0; i <= sim->parts_lastActiveIndex; i++) + for (int i = 0; i <= sim->parts.lastActiveIndex; i++) { if (parts[i].type == PT_ETRD && !parts[i].life) { @@ -164,7 +164,7 @@ int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId) { // Recalculate countLife0, and search for the closest suitable particle int countLife0 = 0; - for (int i = 0; i <= sim->parts_lastActiveIndex; i++) + for (int i = 0; i <= sim->parts.lastActiveIndex; i++) { if (parts[i].type == PT_ETRD && !parts[i].life) {