Lunatic: working tsprite methods, static members, struct array timing test.

git-svn-id: https://svn.eduke32.com/eduke32@3468 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-02-10 16:23:54 +00:00
parent 1dd52a4d6e
commit 90793f6a67
3 changed files with 190 additions and 34 deletions

View file

@ -11,6 +11,7 @@ ffi.cdef "enum { _DEBUG_LUNATIC=1 }"
local bit = require("bit")
local string = require("string")
local table = require("table")
local assert = assert
local error = error
@ -103,8 +104,9 @@ end
ffi.cdef([[
typedef $ sectortype;
typedef $ walltype;
// NOTE: spritetype and tspritetype are different types with the same data members.
typedef $ spritetype;
typedef $ tspritetype;
typedef struct { spritetype; } tspritetype;
typedef struct {
const uint32_t mdanimtims;
@ -132,9 +134,7 @@ typedef struct {
} hitdata_t;
]],
ffi.typeof(SECTOR_STRUCT), ffi.typeof(WALL_STRUCT),
ffi.typeof(SPRITE_STRUCT), ffi.typeof(SPRITE_STRUCT))
-- NOTE: spritetype and tspritetype are different types with the same layout.
-- (XXX: is there a better way?)
ffi.typeof(SPRITE_STRUCT))
-- Define the "palette_t" type, which for us has .{r,g,b} fields and a
-- bound-checking array of length 3 overlaid.
@ -337,6 +337,12 @@ local sectortype_mt = {
}
ffi.metatype("sectortype", sectortype_mt)
local band = bit.band
local bor = bit.bor
local bnot = bit.bnot
local lshift = bit.lshift
local rshift = bit.rshift
local walltype_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(WALL_STRUCT)))
local walltype_mt = {
@ -366,19 +372,19 @@ local walltype_mt = {
--- Predicates
isblocking = function(w)
return (bit.band(w.cstat, 1)~=0)
return (band(w.cstat, 1)~=0)
end,
ismasked = function(w)
return (bit.band(w.cstat, 16)~=0)
return (band(w.cstat, 16)~=0)
end,
isoneway = function(w)
return (bit.band(w.cstat, 32)~=0)
return (band(w.cstat, 32)~=0)
end,
ishittable = function(w)
return (bit.band(w.cstat, 64)~=0)
return (band(w.cstat, 64)~=0)
end,
}
}
@ -388,13 +394,15 @@ local spriteext_mt = {
__index = {
-- Enable EVENT_ANIMATESPRITES for this sprite.
make_animated = function(sx)
sx.flags = bit.bor(sx.flags, 16)
sx.flags = bor(sx.flags, 16)
end,
},
}
ffi.metatype("spriteext_t", spriteext_mt)
local spritetype_ptr_ct = ffi.typeof("$ *", ffi.typeof(strip_const(SPRITE_STRUCT)))
-- NOTE: this is the *protected* tspritetype pointer.
local tspritetype_ptr_ct = ffi.typeof("$ *", ffi.typeof("tspritetype"))
local spritetype_mt = {
__pow = function(s, zofs)
@ -412,6 +420,15 @@ local spritetype_mt = {
-- XXX: for now, no checking
ffi.cast(spritetype_ptr_ct, s).yvel = yvel
end,
--- Custom setters
set_cstat_bits = function(s, bits)
s.cstat = bor(s.cstat, bits)
end,
clear_cstat_bits = function(s, bits)
s.cstat = band(s.cstat, bnot(bits))
end,
},
}
@ -430,20 +447,29 @@ end
local tspritetype_mt = deep_copy(spritetype_mt)
print(spritetype_mt)
print(spritetype_mt.__index)
print(tspritetype_mt)
print(tspritetype_mt.__index)
-- Methods that are specific to tsprites
-- XXX: doesn't work with LuaJIT git f772bed34b39448e3a9ab8d07f6d5c0c26300e1b
function tspritetype_mt.__index.dup(tspr)
if (ffiC.spritesortcnt >= ffiC.MAXSPRITESONSCREEN+0ULL) then
return nil
end
local newtspr = ffi.tsprite[ffiC.spritesortcnt]
local newtspr = ffiC.tsprite[ffiC.spritesortcnt]
ffi.copy(newtspr, tspr, ffi.sizeof(tspr))
ffiC.spritesortcnt = ffiC.spritesortcnt+1
return newtspr
end
function tspritetype_mt.__index.getspr(tspr)
return sprite[tspr.owner]
end
-- The user of this module can insert additional "spritetype" index
-- methods and register them with "ffi.metatype".
function finish_spritetype(mt_index)
@ -465,29 +491,76 @@ function setmtonce(tab, mt)
end
---- indirect C array access ----
local sector_mt = {
__index = function(tab, key)
if (key >= 0 and key < ffiC.numsectors) then return ffiC.sector[key] end
error('out-of-bounds sector[] read access', 2)
end,
__newindex = function() error('cannot write directly to sector[]', 2) end,
-- Construct const struct from table
local function conststruct(tab)
local strtab = { "const struct { int32_t " }
local vals = {}
for member, val in pairs(tab) do
strtab[#strtab+1] = member..","
vals[#vals+1] = val
end
strtab[#strtab] = strtab[#strtab]:gsub(',',';')
strtab[#strtab+1] = "}"
return ffi.new(table.concat(strtab), vals)
end
-- Static, non-instance members. Used to hold constants, for example
-- sprite.CSTAT.TRANSLUCENT1
local static_members = { sector={}, wall={}, sprite={} }
static_members.sector.STAT = conststruct
{
MASKED = 128,
-- NOTE the reversed order
TRANSLUCENT2 = 128,
TRANSLUCENT1 = 256,
TRANSLUCENT_BOTH_BITS = 256+128,
}
local wall_mt = {
__index = function(tab, key)
if (key >= 0 and key < ffiC.numwalls) then return ffiC.wall[key] end
error('out-of-bounds wall[] read access', 2)
end,
__newindex = function() error('cannot write directly to wall[]', 2) end,
static_members.wall.CSTAT = conststruct
{
MASKED = 64,
TRANSLUCENT1 = 128,
TRANSLUCENT2 = 512,
TRANSLUCENT_BOTH_BITS = 512+128,
}
static_members.sprite.CSTAT = conststruct
{
TRANSLUCENT1 = 2,
TRANSLUCENT2 = 512,
TRANSLUCENT_BOTH_BITS = 512+2,
}
local function GenStructMetatable(Structname, Boundname)
return {
__index = function(tab, key)
if (type(key)=="number") then
if (key >= 0 and key < ffiC[Boundname]) then
return ffiC[Structname][key]
end
error("out-of-bounds "..Structname.."[] read access", 2)
elseif (type(key)=="string") then
return static_members[Structname][key]
end
end,
__newindex = function() error("cannot write directly to "..Structname.."[]", 2) end,
}
end
local sector_mt = GenStructMetatable("sector", "numsectors")
local wall_mt = GenStructMetatable("wall", "numwalls")
local sprite_mt = GenStructMetatable("sprite", "MAXSPRITES")
local atsprite_mt = {
__index = function(tab, idx)
check_sprite_idx(idx)
local tspr = ffi.cast(spritetype_ptr_ct, ffiC.spriteext[idx]._tspr)
local tspr = ffi.cast(tspritetype_ptr_ct, ffiC.spriteext[idx]._tspr)
if (tspr == nil) then
error("tsprite of actor "..idx.." unavailable", 2)
end
@ -530,7 +603,7 @@ end
sector = setmtonce({}, sector_mt)
wall = setmtonce({}, wall_mt)
sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[]')
sprite = setmtonce({}, sprite_mt)
spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[]')
atsprite = setmtonce({}, atsprite_mt)

View file

@ -111,7 +111,7 @@ checkfail('gv.sprite[0].yrepeat = 100', "access forbidden")
-- indexing struct array with non-numeric type
checkfail('local i = sprite["qwe"]') -- this will produce an error inside the sprite metatable
checkfail('print(sprite[100000].ceilingpal)', "out-of-bounds sprite[] struct read access")
checkfail('print(sprite[100000].ceilingpal)', "out-of-bounds sprite[] read access")
checkfail('print(gv.sprite[0])', "access forbidden")
@ -186,9 +186,9 @@ checkfail("do local bt=require'bittest'; bt.QWE=1; end", "modifying module table
-- the cdata returned by player[] can't be made into a pointer!
checkfail("do local pl=player[0]; i=pl[1]; end")
checkfail("do local ud=gv.ud.camerasprite; end", "access forbidden") -- test for proper decl()
checkfail("sprite[0]:set_picnum(-10)", "attempt to set invalid picnum")
checkfail("sprite[0]:set_picnum(-10)", "invalid tile number")
checkfail("gv.g_sizes_of=nil; print(gv.g_sizes_of[0])", "write access forbidden")
checkfail("gv.cam.sect=-1", "passed out-of-bounds sector number")
checkfail("gv.cam.sect=-1", "invalid sector number")
printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))
@ -266,6 +266,29 @@ gameevent(gv.EVENT_ENTERLEVEL,
player[0].weapon.SHOTGUN.shoots = 1653
projectile[1653].drop = 0
t = gv.gethitickms()
local N=1
for n=1,N do
for i=0,gv.MAXSPRITES-1 do
sprite[i].filler = 1
end
for i=gv.MAXSPRITES-1,0,-1 do
sprite[i].shade = 1
end
for i=0,gv.MAXSPRITES-1 do
sprite[i].xoffset = 0
end
for i=gv.MAXSPRITES-1,0,-1 do
sprite[i].yoffset = 1
end
end
t = gv.gethitickms()-t
printf("%d x four 0..MAXSPRITES-1 iterations took %.03f us per outer iteration", N, (1000*t)/N)
-- Results on x86:
-- N=1: 480-1000 us (too large variance)
-- N=10: 190-210 us * 10 = 1.9-2.1 ms
-- N=100: about 160 us * 100 = about 16 ms
checkfail("gameevent('GAME', function() print('qwe') end)",
"must be called from top level")
end
@ -327,15 +350,18 @@ gameevent("DISPLAYROOMS",
end
)
local CS = sprite.CSTAT
gameevent("ANIMATESPRITES",
function(aci)
local tspr = atsprite[aci]
if (tspr.picnum==1680) then
--[[
if (tspr:getspr().picnum==1680) then
local tspr2 = tspr:dup()
tspr2.x = tspr2.x + 512*math.cos(gv.totalclock/120)
tspr2.y = tspr2.y + 512*math.sin(gv.totalclock/120)
--]]
if (tspr2) then
tspr2.x = tspr2.x + 512*math.cos(gv.totalclock/60)
tspr2.y = tspr2.y + 512*math.sin(gv.totalclock/60)
tspr2:set_cstat_bits(CS.TRANSLUCENT_BOTH_BITS)
end
end
end)

View file

@ -0,0 +1,57 @@
// Timing test for four 0..MAXSPRITES-1 access loops,
// fwd->back->fwd->back.
// Results with a LTO=1 RELEASE=1 C-CON build on x86: 42 ms for N=10.
// (Compare with Lunatic results in test.elua)
define N 10
gamevar n 0 0
gamevar i 0 0
gamevar t 0 0
gamevar t2 0 0
define MAXSPRITES 16384
define MAXSPRM1 16383 // MAXSPRITES-1
onevent EVENT_ENTERLEVEL
getticks t
setvar n 0
whilevarn n N
{
setvar i 0
whilevarvarn i MAXSPRITES
{
setactor[i].detail 1
addvar i 1
}
setvar i MAXSPRM1
whilevarvarn i -1
{
setactor[i].shade 1
subvar i 1
}
setvar i 0
whilevarvarn i MAXSPRITES
{
setactor[i].xoffset 0
addvar i 1
}
setvar i MAXSPRM1
whilevarvarn i -1
{
setactor[i].yoffset 0
subvar i 1
}
addvar n 1
}
getticks t2
subvarvar t2 t
redefinequote 114 %d x four 0..MAXSPITES-1 iterations took %d ms in total
qsprintf 115 114 n t2
echo 115
endevent