mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-08-03 15:07:29 +02:00
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.
This commit is contained in:
@@ -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;
|
||||
|
@@ -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; ny<YRES; ny++)
|
||||
@@ -262,7 +262,7 @@ void Renderer::render_parts()
|
||||
}
|
||||
}
|
||||
foundParticles = 0;
|
||||
for(i = 0; i<=sim->parts_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)
|
||||
{
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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)
|
||||
|
@@ -25,7 +25,7 @@ std::unique_ptr<Snapshot> 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)
|
||||
|
@@ -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;
|
||||
|
@@ -39,7 +39,7 @@ void Simulation::Load(const GameSave *save, bool includePressure, Vec2<int> bloc
|
||||
};
|
||||
std::vector<ExistingParticle> 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<int> 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<int> 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)
|
||||
{
|
||||
|
@@ -34,6 +34,30 @@ class Renderer;
|
||||
class Air;
|
||||
class GameSave;
|
||||
|
||||
struct Parts
|
||||
{
|
||||
std::array<Particle, NPART> 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;
|
||||
};
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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<ETRD_deltaWithLength>::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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user