-
Notifications
You must be signed in to change notification settings - Fork 334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Faster wire rendering #2955
Faster wire rendering #2955
Conversation
5be50ac
to
9b34ace
Compare
The only problem I see is the wire used to render even if ent was Invalid, which I guess would correspond to world entity. If ent is Invalid then it uses world offsets for the wire instead of entity local offsets. We might still want that behavior. |
The wire tool itself doesn't even let you attach wires to the world so this probably isn't an issue. |
lua/wire/wireshared.lua
Outdated
local ents_orientations = {} | ||
local ents_cached_positions = {} | ||
|
||
local LocalToWorld = FindMetaTable("Entity").LocalToWorld | ||
local orientation, cur_cached_positions, cur_ent | ||
|
||
function WireLib.LocalToWorld_UseEnt(ent) | ||
if cur_ent == ent then return end -- call this as much as you want | ||
|
||
orientation = ents_orientations[ent] | ||
cur_cached_positions = ents_cached_positions[ent] | ||
cur_ent = ent | ||
|
||
if not orientation or not cur_cached_positions then | ||
ents_orientations[ent] = { ent:GetPos(), ent:GetAngles() } | ||
cur_cached_positions = {} | ||
ents_cached_positions[ent] = cur_cached_positions | ||
return | ||
end | ||
|
||
local pos = ent:GetPos() | ||
local ang = ent:GetAngles() | ||
|
||
if not rawequal(orientation[1], pos) or not rawequal(orientation[2], ang) then | ||
orientation[1] = pos | ||
orientation[2] = ang | ||
cur_cached_positions = {} | ||
ents_cached_positions[ent] = cur_cached_positions | ||
return | ||
end | ||
|
||
op = retrieve | ||
end | ||
|
||
function WireLib.LocalToWorld_Find(pos) | ||
local fetch = cur_cached_positions[pos] | ||
if fetch then return fetch | ||
else | ||
cur_cached_positions[pos] = LocalToWorld(cur_ent, pos) | ||
return cur_cached_positions[pos] | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be generalized to something cleaner like
local ents_computed_data = setmetatable({}, {__index=function(t,k) local r=setmetatable({}, {__index=function(t,k) local r={pos = Vector(math.huge), ang = Angle()} t[k]=r return r end}) t[k]=r end})
function WireLib.ComputeIfEntityTransformDirty(ent, key, compute)
local data = ents_computed_data[ent][key]
local pos, ang = ent:GetPos(), ent:GetAngles()
if not (rawequal(orientation[1], data.pos) and rawequal(orientation[2], data.ang)) then
data.pos = pos
data.ang = ang
data.computed = compute(ent)
end
return data.computed
end
-- Example usage
local wires = WireLib.ComputeIfEntityTransformDirty(ent, "wires", function(ent)
return {<list of transformed vectors>}
end)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should also prevent memory leaking caused by the vector lookup table
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even better:
function WireLib.GetComputeIfEntityTransformDirty(compute)
local ents_computed_data = setmetatable({}, {__index=function(t,k) local r={pos = Vector(math.huge), ang = Angle()} t[k]=r return r end})
return function(ent, ...)
local data = ents_computed_data[ent]
local pos, ang = ent:GetPos(), ent:GetAngles()
if not (rawequal(orientation[1], data.pos) and rawequal(orientation[2], data.ang)) then
data.pos = pos
data.ang = ang
data.computed = compute(ent, ...)
end
return data.computed
end
end
-- Example usage
local wireTransformer = WireLib.GetComputeIfEntityTransformDirty(function(ent, local_wires)
return {<list of transformed vectors>}
end)
local wirePositions = wireTransformer(ent, local_wires)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea to put it on the entity itself. Will look into doing it like that this weekend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to do this much longer ago. Gonna actually do it now.
Also, fuck off github-actions bot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data.computed = compute(ent, ...)
Varargs are not jittable, going to avoid this
This pull request has been marked as stale as there haven't been any changes in the past month. It will be closed in 15 days. |
fa8981c
to
da4aec6
Compare
GetPos and GetAngles return new objects every time they are called.
@thegrb93 With all due respect, while your code is cleaner, it looks like it might be really really expensive to use in practice. I will not be implementing your requested changes at this time. |
Fix error on destruct with nil streams Fix client to server sending
Improved the implementation to cache vectors like yours and did more optimization. If its still slow then we can revert to the simpler method, but this should be as fast as if not faster. |
Can be simplified further function WireLib.GetComputeIfEntityTransformDirty(compute)
return setmetatable({}, {
__index=function(t,ent) local r={Vector(math.huge), Angle()} t[ent]=r return r end,
__call=function(t,ent)
local data = t[ent]
local pos, ang = GetPos(ent), GetAngles(ent)
if pos~=data[1] or ang~=data[2] then
data[1] = pos
data[2] = ang
data[3] = compute(ent)
end
return data[3]
end
})
end |
Seems to be working |
It's not perfect, but it's certainly better that what we had before. Cleaned up a bunch of old code that doesn't do anything and added some micro-optimizations where doable (but they didn't have much of an impact in my testing)
The big change with this PR is that entities with stupid amounts of wires will no longer drop your FPS provided they remain stationary. This is thanks to a new LocalToWorld result caching system, which avoids creating new vector objects for repeated calls with the same input vector.
This LocalToWorld cache system is now a part of
WireLib
so it can be used in other files where applicable. The more it's used, the better the global performance should become.