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