batteries
batteries copied to clipboard
Remove requirement to bit library in colour module.
I have not fully tested this, so please do.
will need to find some time to write tests to ensure this is working as intended!
the amount of modulos make me a bit nervous performance wise though vs the bit operations, especially when compiled. i think i'd prefer a flag to use the bit library for speed rather than just removing the dependency entirely.
While it's true that the modulos are scary, looking at luajit.me, the bitshifts itself perform a double-to-integer conversion, shift, then integer-to-double conversion. While the modulo version performs everything at double without any conversion.
Still, I think it's also good idea to check the correctness AND benchmark it.
benchmark/test
do
local start_time = love.timer.getTime()
local test_repeats = 1000
local iters = 100
local abs = math.abs
for _ = 1, test_repeats do
local accum = 0
for i = 1, iters do
--computed so it can't be inlined
local r, g, b, a = 1 / i, 0.5 / i, 0.25 / i, i / 100
--test pack
local rgb = colour.pack_rgb(r, g, b)
local rgba = colour.pack_rgba(r, g, b, a)
local argb = colour.pack_argb(r, g, b, a)
accum = accum + rgb + rgba
local r1, g1, b1 = colour.unpack_rgb(rgb)
local r2, g2, b2, a2 = colour.unpack_rgba(rgba)
local r3, g3, b3, a3 = colour.unpack_argb(argb)
--check
if abs(r1 - r) > 1 / 256 then error(("bad unpack: %f vs %f"):format(r1, r)) end
if abs(g1 - g) > 1 / 256 then error(("bad unpack: %f vs %f"):format(g1, g)) end
if abs(b1 - b) > 1 / 256 then error(("bad unpack: %f vs %f"):format(b1, b)) end
if abs(r2 - r) > 1 / 256 then error(("bad unpack: %f vs %f"):format(r2, r)) end
if abs(g2 - g) > 1 / 256 then error(("bad unpack: %f vs %f"):format(g2, g)) end
if abs(b2 - b) > 1 / 256 then error(("bad unpack: %f vs %f"):format(b2, b)) end
if abs(a2 - a) > 1 / 256 then error(("bad unpack: %f vs %f"):format(a2, a)) end
if abs(r3 - r) > 1 / 256 then error(("bad unpack: %f vs %f"):format(r3, r)) end
if abs(g3 - g) > 1 / 256 then error(("bad unpack: %f vs %f"):format(g3, g)) end
if abs(b3 - b) > 1 / 256 then error(("bad unpack: %f vs %f"):format(b3, b)) end
if abs(a3 - a) > 1 / 256 then error(("bad unpack: %f vs %f"):format(a3, a)) end
end
end
local end_time = love.timer.getTime()
local total_time = (end_time - start_time)
print(("total time: %0.4fms per test: %0.4fms"):format(total_time * 1000, total_time * 1000 / test_repeats))
love.event.quit()
return
end
without bit
[max@compy-mj arco]$ love .
total time: 6.9082ms per test: 0.0069ms
[max@compy-mj arco]$ love .
total time: 6.6903ms per test: 0.0067ms
[max@compy-mj arco]$ love .
total time: 6.7483ms per test: 0.0067ms
with bit
[max@compy-mj arco]$ love .
total time: 6.5429ms per test: 0.0065ms
[max@compy-mj arco]$ love .
total time: 6.6917ms per test: 0.0067ms
[max@compy-mj arco]$ love .
total time: 6.5934ms per test: 0.0066ms
ie very slightly faster with bit
after talking with @slime73 via discord i decided to just keep both implementations and pick one depending on if the bit module is present or not, which doesn't cost much other than code size and maintainability. Will pull in your commit so you hopefully get correct attribution according to git, will see how the merge looks.
we can consider something (global or inline local config var) to force no bitops if required :+1: