• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2 
3 /*
4  * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * Authors:
26  *    Rob Clark <robclark@freedesktop.org>
27  */
28 
29 #define LUA_COMPAT_APIINTCASTS
30 
31 #include <assert.h>
32 #include <lauxlib.h>
33 #include <lua.h>
34 #include <lualib.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "cffdec.h"
40 #include "rnnutil.h"
41 #include "script.h"
42 
43 static lua_State *L;
44 
45 #if 0
46 #define DBG(fmt, ...)                                                          \
47    do {                                                                        \
48       printf(" ** %s:%d ** " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \
49    } while (0)
50 #else
51 #define DBG(fmt, ...)                                                          \
52    do {                                                                        \
53    } while (0)
54 #endif
55 
56 /* An rnn based decoder, which can either be decoding current register
57  * values, or domain based decoding of a pm4 packet.
58  *
59  */
60 struct rnndec {
61    struct rnn base;
62 
63    /* for pm4 packet decoding: */
64    uint32_t sizedwords;
65    uint32_t *dwords;
66 };
67 
68 static inline struct rnndec *
to_rnndec(struct rnn * rnn)69 to_rnndec(struct rnn *rnn)
70 {
71    return (struct rnndec *)rnn;
72 }
73 
74 static uint32_t
rnn_val(struct rnn * rnn,uint32_t regbase)75 rnn_val(struct rnn *rnn, uint32_t regbase)
76 {
77    struct rnndec *rnndec = to_rnndec(rnn);
78 
79    if (!rnndec->sizedwords) {
80       return reg_val(regbase);
81    } else if (regbase < rnndec->sizedwords) {
82       return rnndec->dwords[regbase];
83    } else {
84       // XXX throw an error
85       return -1;
86    }
87 }
88 
89 /* does not return */
90 static void
error(const char * fmt)91 error(const char *fmt)
92 {
93    fprintf(stderr, fmt, lua_tostring(L, -1));
94    exit(1);
95 }
96 
97 /*
98  * An enum type that can be used as string or number:
99  */
100 
101 struct rnndenum {
102    const char *str;
103    int val;
104 };
105 
106 static int
l_meta_rnn_enum_tostring(lua_State * L)107 l_meta_rnn_enum_tostring(lua_State *L)
108 {
109    struct rnndenum *e = lua_touserdata(L, 1);
110    if (e->str) {
111       lua_pushstring(L, e->str);
112    } else {
113       char buf[32];
114       sprintf(buf, "%u", e->val);
115       lua_pushstring(L, buf);
116    }
117    return 1;
118 }
119 
120 /* so, this doesn't actually seem to be implemented yet, but hopefully
121  * some day lua comes to it's senses
122  */
123 static int
l_meta_rnn_enum_tonumber(lua_State * L)124 l_meta_rnn_enum_tonumber(lua_State *L)
125 {
126    struct rnndenum *e = lua_touserdata(L, 1);
127    lua_pushinteger(L, e->val);
128    return 1;
129 }
130 
131 static const struct luaL_Reg l_meta_rnn_enum[] = {
132    {"__tostring", l_meta_rnn_enum_tostring},
133    {"__tonumber", l_meta_rnn_enum_tonumber},
134    {NULL, NULL} /* sentinel */
135 };
136 
137 static void
pushenum(struct lua_State * L,int val,struct rnnenum * info)138 pushenum(struct lua_State *L, int val, struct rnnenum *info)
139 {
140    struct rnndenum *e = lua_newuserdata(L, sizeof(*e));
141 
142    e->val = val;
143    e->str = NULL;
144 
145    for (int i = 0; i < info->valsnum; i++) {
146       if (info->vals[i]->valvalid && (info->vals[i]->value == val)) {
147          e->str = info->vals[i]->name;
148          break;
149       }
150    }
151 
152    luaL_newmetatable(L, "rnnmetaenum");
153    luaL_setfuncs(L, l_meta_rnn_enum, 0);
154    lua_pop(L, 1);
155 
156    luaL_setmetatable(L, "rnnmetaenum");
157 }
158 
159 /* Expose rnn decode to script environment as "rnn" library:
160  */
161 
162 struct rnndoff {
163    struct rnn *rnn;
164    struct rnndelem *elem;
165    uint64_t offset;
166 };
167 
168 static void
push_rnndoff(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)169 push_rnndoff(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
170              uint64_t offset)
171 {
172    struct rnndoff *rnndoff = lua_newuserdata(L, sizeof(*rnndoff));
173    rnndoff->rnn = rnn;
174    rnndoff->elem = elem;
175    rnndoff->offset = offset;
176 }
177 
178 static int l_rnn_etype_array(lua_State *L, struct rnn *rnn,
179                              struct rnndelem *elem, uint64_t offset);
180 static int l_rnn_etype_reg(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
181                            uint64_t offset);
182 
183 static int
pushdecval(struct lua_State * L,struct rnn * rnn,uint32_t regval,struct rnntypeinfo * info)184 pushdecval(struct lua_State *L, struct rnn *rnn, uint32_t regval,
185            struct rnntypeinfo *info)
186 {
187    union rnndecval val;
188    switch (rnn_decodelem(rnn, info, regval, &val)) {
189    case RNN_TTYPE_ENUM:
190    case RNN_TTYPE_INLINE_ENUM:
191       pushenum(L, val.i, info->eenum);
192       return 1;
193    case RNN_TTYPE_INT:
194       lua_pushinteger(L, val.i);
195       return 1;
196    case RNN_TTYPE_UINT:
197    case RNN_TTYPE_HEX:
198       lua_pushunsigned(L, val.u);
199       return 1;
200    case RNN_TTYPE_FLOAT:
201       lua_pushnumber(L, val.f);
202       return 1;
203    case RNN_TTYPE_BOOLEAN:
204       lua_pushboolean(L, val.u);
205       return 1;
206    case RNN_TTYPE_INVALID:
207    default:
208       return 0;
209    }
210 }
211 
212 static int
l_rnn_etype(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)213 l_rnn_etype(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
214             uint64_t offset)
215 {
216    int ret;
217    uint32_t regval;
218    DBG("elem=%p (%d), offset=%lu", elem, elem->type, offset);
219    switch (elem->type) {
220    case RNN_ETYPE_REG:
221       /* if a register has no bitfields, just return
222        * the raw value:
223        */
224       regval = rnn_val(rnn, offset);
225       regval <<= elem->typeinfo.shr;
226       ret = pushdecval(L, rnn, regval, &elem->typeinfo);
227       if (ret)
228          return ret;
229       return l_rnn_etype_reg(L, rnn, elem, offset);
230    case RNN_ETYPE_ARRAY:
231       return l_rnn_etype_array(L, rnn, elem, offset);
232    default:
233       /* hmm.. */
234       printf("unhandled type: %d\n", elem->type);
235       return 0;
236    }
237 }
238 
239 /*
240  * Struct Object:
241  * To implement stuff like 'RB_MRT[n].CONTROL' we need a struct-object
242  * to represent the current array index (ie. 'RB_MRT[n]')
243  */
244 
245 static int
l_rnn_struct_meta_index(lua_State * L)246 l_rnn_struct_meta_index(lua_State *L)
247 {
248    struct rnndoff *rnndoff = lua_touserdata(L, 1);
249    const char *name = lua_tostring(L, 2);
250    struct rnndelem *elem = rnndoff->elem;
251    int i;
252 
253    for (i = 0; i < elem->subelemsnum; i++) {
254       struct rnndelem *subelem = elem->subelems[i];
255       if (!strcmp(name, subelem->name)) {
256          return l_rnn_etype(L, rnndoff->rnn, subelem,
257                             rnndoff->offset + subelem->offset);
258       }
259    }
260 
261    return 0;
262 }
263 
264 static const struct luaL_Reg l_meta_rnn_struct[] = {
265    {"__index", l_rnn_struct_meta_index}, {NULL, NULL} /* sentinel */
266 };
267 
268 static int
l_rnn_etype_struct(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)269 l_rnn_etype_struct(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
270                    uint64_t offset)
271 {
272    push_rnndoff(L, rnn, elem, offset);
273 
274    luaL_newmetatable(L, "rnnmetastruct");
275    luaL_setfuncs(L, l_meta_rnn_struct, 0);
276    lua_pop(L, 1);
277 
278    luaL_setmetatable(L, "rnnmetastruct");
279 
280    return 1;
281 }
282 
283 /*
284  * Array Object:
285  */
286 
287 static int
l_rnn_array_meta_index(lua_State * L)288 l_rnn_array_meta_index(lua_State *L)
289 {
290    struct rnndoff *rnndoff = lua_touserdata(L, 1);
291    int idx = lua_tointeger(L, 2);
292    struct rnndelem *elem = rnndoff->elem;
293    uint64_t offset = rnndoff->offset + (elem->stride * idx);
294 
295    DBG("rnndoff=%p, idx=%d, numsubelems=%d", rnndoff, idx,
296        rnndoff->elem->subelemsnum);
297 
298    /* if just a single sub-element, it is directly a register,
299     * otherwise we need to accumulate the array index while
300     * we wait for the register name within the array..
301     */
302    if (elem->subelemsnum == 1) {
303       return l_rnn_etype(L, rnndoff->rnn, elem->subelems[0], offset);
304    } else {
305       return l_rnn_etype_struct(L, rnndoff->rnn, elem, offset);
306    }
307 
308    return 0;
309 }
310 
311 static const struct luaL_Reg l_meta_rnn_array[] = {
312    {"__index", l_rnn_array_meta_index}, {NULL, NULL} /* sentinel */
313 };
314 
315 static int
l_rnn_etype_array(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)316 l_rnn_etype_array(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
317                   uint64_t offset)
318 {
319    push_rnndoff(L, rnn, elem, offset);
320 
321    luaL_newmetatable(L, "rnnmetaarray");
322    luaL_setfuncs(L, l_meta_rnn_array, 0);
323    lua_pop(L, 1);
324 
325    luaL_setmetatable(L, "rnnmetaarray");
326 
327    return 1;
328 }
329 
330 /*
331  * Register element:
332  */
333 
334 static int
l_rnn_reg_meta_index(lua_State * L)335 l_rnn_reg_meta_index(lua_State *L)
336 {
337    struct rnndoff *rnndoff = lua_touserdata(L, 1);
338    const char *name = lua_tostring(L, 2);
339    struct rnndelem *elem = rnndoff->elem;
340    struct rnntypeinfo *info = &elem->typeinfo;
341    struct rnnbitfield **bitfields;
342    int bitfieldsnum;
343    int i;
344 
345    switch (info->type) {
346    case RNN_TTYPE_BITSET:
347       bitfields = info->ebitset->bitfields;
348       bitfieldsnum = info->ebitset->bitfieldsnum;
349       break;
350    case RNN_TTYPE_INLINE_BITSET:
351       bitfields = info->bitfields;
352       bitfieldsnum = info->bitfieldsnum;
353       break;
354    default:
355       printf("invalid register type: %d\n", info->type);
356       return 0;
357    }
358 
359    for (i = 0; i < bitfieldsnum; i++) {
360       struct rnnbitfield *bf = bitfields[i];
361       if (!strcmp(name, bf->name)) {
362          uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);
363 
364          regval &= typeinfo_mask(&bf->typeinfo);
365          regval >>= bf->typeinfo.low;
366          regval <<= bf->typeinfo.shr;
367 
368          DBG("name=%s, info=%p, subelemsnum=%d, type=%d, regval=%x", name, info,
369              rnndoff->elem->subelemsnum, bf->typeinfo.type, regval);
370 
371          return pushdecval(L, rnndoff->rnn, regval, &bf->typeinfo);
372       }
373    }
374 
375    printf("invalid member: %s\n", name);
376    return 0;
377 }
378 
379 static int
l_rnn_reg_meta_tostring(lua_State * L)380 l_rnn_reg_meta_tostring(lua_State *L)
381 {
382    struct rnndoff *rnndoff = lua_touserdata(L, 1);
383    uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);
384    struct rnndecaddrinfo *info = rnn_reginfo(rnndoff->rnn, rnndoff->offset);
385    char *decoded;
386    if (info && info->typeinfo) {
387       decoded = rnndec_decodeval(rnndoff->rnn->vc, info->typeinfo, regval);
388    } else {
389       asprintf(&decoded, "%08x", regval);
390    }
391    lua_pushstring(L, decoded);
392    free(decoded);
393    if (info) {
394       free(info->name);
395       free(info);
396    }
397    return 1;
398 }
399 
400 static int
l_rnn_reg_meta_tonumber(lua_State * L)401 l_rnn_reg_meta_tonumber(lua_State *L)
402 {
403    struct rnndoff *rnndoff = lua_touserdata(L, 1);
404    uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);
405 
406    regval <<= rnndoff->elem->typeinfo.shr;
407 
408    lua_pushnumber(L, regval);
409    return 1;
410 }
411 
412 static const struct luaL_Reg l_meta_rnn_reg[] = {
413    {"__index", l_rnn_reg_meta_index},
414    {"__tostring", l_rnn_reg_meta_tostring},
415    {"__tonumber", l_rnn_reg_meta_tonumber},
416    {NULL, NULL} /* sentinel */
417 };
418 
419 static int
l_rnn_etype_reg(lua_State * L,struct rnn * rnn,struct rnndelem * elem,uint64_t offset)420 l_rnn_etype_reg(lua_State *L, struct rnn *rnn, struct rnndelem *elem,
421                 uint64_t offset)
422 {
423    push_rnndoff(L, rnn, elem, offset);
424 
425    luaL_newmetatable(L, "rnnmetareg");
426    luaL_setfuncs(L, l_meta_rnn_reg, 0);
427    lua_pop(L, 1);
428 
429    luaL_setmetatable(L, "rnnmetareg");
430 
431    return 1;
432 }
433 
434 /*
435  *
436  */
437 
438 static int
l_rnn_meta_index(lua_State * L)439 l_rnn_meta_index(lua_State *L)
440 {
441    struct rnn *rnn = lua_touserdata(L, 1);
442    const char *name = lua_tostring(L, 2);
443    struct rnndelem *elem;
444 
445    elem = rnn_regelem(rnn, name);
446    if (!elem)
447       return 0;
448 
449    return l_rnn_etype(L, rnn, elem, elem->offset);
450 }
451 
452 static int
l_rnn_meta_gc(lua_State * L)453 l_rnn_meta_gc(lua_State *L)
454 {
455    // TODO
456    // struct rnn *rnn = lua_touserdata(L, 1);
457    // rnn_deinit(rnn);
458    return 0;
459 }
460 
461 static const struct luaL_Reg l_meta_rnn[] = {
462    {"__index", l_rnn_meta_index},
463    {"__gc", l_rnn_meta_gc},
464    {NULL, NULL} /* sentinel */
465 };
466 
467 static int
l_rnn_init(lua_State * L)468 l_rnn_init(lua_State *L)
469 {
470    const char *gpuname = lua_tostring(L, 1);
471    struct rnndec *rnndec = lua_newuserdata(L, sizeof(*rnndec));
472    _rnn_init(&rnndec->base, 0);
473    rnn_load(&rnndec->base, gpuname);
474    rnndec->sizedwords = 0;
475 
476    luaL_newmetatable(L, "rnnmeta");
477    luaL_setfuncs(L, l_meta_rnn, 0);
478    lua_pop(L, 1);
479 
480    luaL_setmetatable(L, "rnnmeta");
481 
482    return 1;
483 }
484 
485 static int
l_rnn_enumname(lua_State * L)486 l_rnn_enumname(lua_State *L)
487 {
488    struct rnn *rnn = lua_touserdata(L, 1);
489    const char *name = lua_tostring(L, 2);
490    uint32_t val = (uint32_t)lua_tonumber(L, 3);
491    lua_pushstring(L, rnn_enumname(rnn, name, val));
492    return 1;
493 }
494 
495 static int
l_rnn_regname(lua_State * L)496 l_rnn_regname(lua_State *L)
497 {
498    struct rnn *rnn = lua_touserdata(L, 1);
499    uint32_t regbase = (uint32_t)lua_tonumber(L, 2);
500    lua_pushstring(L, rnn_regname(rnn, regbase, 1));
501    return 1;
502 }
503 
504 static int
l_rnn_regval(lua_State * L)505 l_rnn_regval(lua_State *L)
506 {
507    struct rnn *rnn = lua_touserdata(L, 1);
508    uint32_t regbase = (uint32_t)lua_tonumber(L, 2);
509    uint32_t regval = (uint32_t)lua_tonumber(L, 3);
510    struct rnndecaddrinfo *info = rnn_reginfo(rnn, regbase);
511    char *decoded;
512    if (info && info->typeinfo) {
513       decoded = rnndec_decodeval(rnn->vc, info->typeinfo, regval);
514    } else {
515       asprintf(&decoded, "%08x", regval);
516    }
517    lua_pushstring(L, decoded);
518    free(decoded);
519    if (info) {
520       free(info->name);
521       free(info);
522    }
523    return 1;
524 }
525 
526 static const struct luaL_Reg l_rnn[] = {
527    {"init", l_rnn_init},
528    {"enumname", l_rnn_enumname},
529    {"regname", l_rnn_regname},
530    {"regval", l_rnn_regval},
531    {NULL, NULL} /* sentinel */
532 };
533 
534 /* Expose the register state to script enviroment as a "regs" library:
535  */
536 
537 static int
l_reg_written(lua_State * L)538 l_reg_written(lua_State *L)
539 {
540    uint32_t regbase = (uint32_t)lua_tonumber(L, 1);
541    lua_pushnumber(L, reg_written(regbase));
542    return 1;
543 }
544 
545 static int
l_reg_lastval(lua_State * L)546 l_reg_lastval(lua_State *L)
547 {
548    uint32_t regbase = (uint32_t)lua_tonumber(L, 1);
549    lua_pushnumber(L, reg_lastval(regbase));
550    return 1;
551 }
552 
553 static int
l_reg_val(lua_State * L)554 l_reg_val(lua_State *L)
555 {
556    uint32_t regbase = (uint32_t)lua_tonumber(L, 1);
557    lua_pushnumber(L, reg_val(regbase));
558    return 1;
559 }
560 
561 static const struct luaL_Reg l_regs[] = {
562    {"written", l_reg_written},
563    {"lastval", l_reg_lastval},
564    {"val", l_reg_val},
565    {NULL, NULL} /* sentinel */
566 };
567 
568 /* Expose API to lookup snapshot buffers:
569  */
570 
571 uint64_t gpubaseaddr(uint64_t gpuaddr);
572 unsigned hostlen(uint64_t gpuaddr);
573 
574 /* given address, return base-address of buffer: */
575 static int
l_bo_base(lua_State * L)576 l_bo_base(lua_State *L)
577 {
578    uint64_t addr = (uint64_t)lua_tonumber(L, 1);
579    lua_pushnumber(L, gpubaseaddr(addr));
580    return 1;
581 }
582 
583 /* given address, return the remaining size of the buffer: */
584 static int
l_bo_size(lua_State * L)585 l_bo_size(lua_State *L)
586 {
587    uint64_t addr = (uint64_t)lua_tonumber(L, 1);
588    lua_pushnumber(L, hostlen(addr));
589    return 1;
590 }
591 
592 static const struct luaL_Reg l_bos[] = {
593    {"base", l_bo_base}, {"size", l_bo_size}, {NULL, NULL} /* sentinel */
594 };
595 
596 static void
openlib(const char * lib,const luaL_Reg * reg)597 openlib(const char *lib, const luaL_Reg *reg)
598 {
599    lua_newtable(L);
600    luaL_setfuncs(L, reg, 0);
601    lua_setglobal(L, lib);
602 }
603 
604 /* called at start to load the script: */
605 int
script_load(const char * file)606 script_load(const char *file)
607 {
608    int ret;
609 
610    assert(!L);
611 
612    L = luaL_newstate();
613    luaL_openlibs(L);
614    openlib("bos", l_bos);
615    openlib("regs", l_regs);
616    openlib("rnn", l_rnn);
617 
618    ret = luaL_loadfile(L, file);
619    if (ret)
620       error("%s\n");
621 
622    ret = lua_pcall(L, 0, LUA_MULTRET, 0);
623    if (ret)
624       error("%s\n");
625 
626    return 0;
627 }
628 
629 /* called at start of each cmdstream file: */
630 void
script_start_cmdstream(const char * name)631 script_start_cmdstream(const char *name)
632 {
633    if (!L)
634       return;
635 
636    lua_getglobal(L, "start_cmdstream");
637 
638    /* if no handler just ignore it: */
639    if (!lua_isfunction(L, -1)) {
640       lua_pop(L, 1);
641       return;
642    }
643 
644    lua_pushstring(L, name);
645 
646    /* do the call (1 arguments, 0 result) */
647    if (lua_pcall(L, 1, 0, 0) != 0)
648       error("error running function `f': %s\n");
649 }
650 
651 /* called at each DRAW_INDX, calls script drawidx fxn to process
652  * the current state
653  */
654 void
script_draw(const char * primtype,uint32_t nindx)655 script_draw(const char *primtype, uint32_t nindx)
656 {
657    if (!L)
658       return;
659 
660    lua_getglobal(L, "draw");
661 
662    /* if no handler just ignore it: */
663    if (!lua_isfunction(L, -1)) {
664       lua_pop(L, 1);
665       return;
666    }
667 
668    lua_pushstring(L, primtype);
669    lua_pushnumber(L, nindx);
670 
671    /* do the call (2 arguments, 0 result) */
672    if (lua_pcall(L, 2, 0, 0) != 0)
673       error("error running function `f': %s\n");
674 }
675 
676 static int
l_rnn_meta_dom_index(lua_State * L)677 l_rnn_meta_dom_index(lua_State *L)
678 {
679    struct rnn *rnn = lua_touserdata(L, 1);
680    uint32_t offset = (uint32_t)lua_tonumber(L, 2);
681    struct rnndelem *elem;
682 
683    /* TODO might be nicer if the arg isn't a number, to search the domain
684     * for matching bitfields.. so that the script could do something like
685     * 'pkt.WIDTH' insteadl of 'pkt[1].WIDTH', ie. not have to remember the
686     * offset of the dword containing the bitfield..
687     */
688 
689    elem = rnn_regoff(rnn, offset);
690    if (!elem)
691       return 0;
692 
693    return l_rnn_etype(L, rnn, elem, elem->offset);
694 }
695 
696 /*
697  * A wrapper object for rnndomain based decoding of an array of dwords
698  * (ie. for pm4 packet decoding).  Mostly re-uses the register-value
699  * decoding for the individual dwords and bitfields.
700  */
701 
702 static int
l_rnn_meta_dom_gc(lua_State * L)703 l_rnn_meta_dom_gc(lua_State *L)
704 {
705    // TODO
706    // struct rnn *rnn = lua_touserdata(L, 1);
707    // rnn_deinit(rnn);
708    return 0;
709 }
710 
711 static const struct luaL_Reg l_meta_rnn_dom[] = {
712    {"__index", l_rnn_meta_dom_index},
713    {"__gc", l_rnn_meta_dom_gc},
714    {NULL, NULL} /* sentinel */
715 };
716 
717 /* called to general pm4 packet decoding, such as texture/sampler state
718  */
719 void
script_packet(uint32_t * dwords,uint32_t sizedwords,struct rnn * rnn,struct rnndomain * dom)720 script_packet(uint32_t *dwords, uint32_t sizedwords, struct rnn *rnn,
721               struct rnndomain *dom)
722 {
723    if (!L)
724       return;
725 
726    lua_getglobal(L, dom->name);
727 
728    /* if no handler for the packet, just ignore it: */
729    if (!lua_isfunction(L, -1)) {
730       lua_pop(L, 1);
731       return;
732    }
733 
734    struct rnndec *rnndec = lua_newuserdata(L, sizeof(*rnndec));
735 
736    rnndec->base = *rnn;
737    rnndec->base.dom[0] = dom;
738    rnndec->base.dom[1] = NULL;
739    rnndec->dwords = dwords;
740    rnndec->sizedwords = sizedwords;
741 
742    luaL_newmetatable(L, "rnnmetadom");
743    luaL_setfuncs(L, l_meta_rnn_dom, 0);
744    lua_pop(L, 1);
745 
746    luaL_setmetatable(L, "rnnmetadom");
747 
748    lua_pushnumber(L, sizedwords);
749 
750    if (lua_pcall(L, 2, 0, 0) != 0)
751       error("error running function `f': %s\n");
752 }
753 
754 /* helper to call fxn that takes and returns void: */
755 static void
simple_call(const char * name)756 simple_call(const char *name)
757 {
758    if (!L)
759       return;
760 
761    lua_getglobal(L, name);
762 
763    /* if no handler just ignore it: */
764    if (!lua_isfunction(L, -1)) {
765       lua_pop(L, 1);
766       return;
767    }
768 
769    /* do the call (0 arguments, 0 result) */
770    if (lua_pcall(L, 0, 0, 0) != 0)
771       error("error running function `f': %s\n");
772 }
773 
774 /* called at end of each cmdstream file: */
775 void
script_end_cmdstream(void)776 script_end_cmdstream(void)
777 {
778    simple_call("end_cmdstream");
779 }
780 
781 /* called at start of submit/issueibcmds: */
782 void
script_start_submit(void)783 script_start_submit(void)
784 {
785    simple_call("start_submit");
786 }
787 
788 /* called at end of submit/issueibcmds: */
789 void
script_end_submit(void)790 script_end_submit(void)
791 {
792    simple_call("end_submit");
793 }
794 
795 /* called after last cmdstream file: */
796 void
script_finish(void)797 script_finish(void)
798 {
799    if (!L)
800       return;
801 
802    simple_call("finish");
803 
804    lua_close(L);
805    L = NULL;
806 }
807