From 90793f6a6727ddd54a3c27259393eb5479d4472a Mon Sep 17 00:00:00 2001 From: helixhorned Date: Sun, 10 Feb 2013 16:23:54 +0000 Subject: [PATCH] Lunatic: working tsprite methods, static members, struct array timing test. git-svn-id: https://svn.eduke32.com/eduke32@3468 1a8010ca-5511-0410-912e-c29ae57300e0 --- .../eduke32/source/lunatic/defs_common.lua | 125 ++++++++++++++---- polymer/eduke32/source/lunatic/test.elua | 42 ++++-- .../source/lunatic/test/sprite_access.con | 57 ++++++++ 3 files changed, 190 insertions(+), 34 deletions(-) create mode 100644 polymer/eduke32/source/lunatic/test/sprite_access.con diff --git a/polymer/eduke32/source/lunatic/defs_common.lua b/polymer/eduke32/source/lunatic/defs_common.lua index 347c31242..5a88f2a66 100644 --- a/polymer/eduke32/source/lunatic/defs_common.lua +++ b/polymer/eduke32/source/lunatic/defs_common.lua @@ -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) diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index ca3959be4..191425ce8 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -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) diff --git a/polymer/eduke32/source/lunatic/test/sprite_access.con b/polymer/eduke32/source/lunatic/test/sprite_access.con new file mode 100644 index 000000000..4569d9c17 --- /dev/null +++ b/polymer/eduke32/source/lunatic/test/sprite_access.con @@ -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