Path: blob/21.2-virgl/src/freedreno/decode/script.c
4565 views
/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */12/*3* Copyright (C) 2014 Rob Clark <[email protected]>4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the "Software"),7* to deal in the Software without restriction, including without limitation8* the rights to use, copy, modify, merge, publish, distribute, sublicense,9* and/or sell copies of the Software, and to permit persons to whom the10* Software is furnished to do so, subject to the following conditions:11*12* The above copyright notice and this permission notice (including the next13* paragraph) shall be included in all copies or substantial portions of the14* Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR17* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,18* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL19* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER20* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,21* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE22* SOFTWARE.23*24* Authors:25* Rob Clark <[email protected]>26*/2728#define LUA_COMPAT_APIINTCASTS2930#include <assert.h>31#include <lauxlib.h>32#include <lua.h>33#include <lualib.h>34#include <stdio.h>35#include <stdlib.h>36#include <string.h>3738#include "cffdec.h"39#include "rnnutil.h"40#include "script.h"4142static lua_State *L;4344#if 045#define DBG(fmt, ...) \46do { \47printf(" ** %s:%d ** " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \48} while (0)49#else50#define DBG(fmt, ...) \51do { \52} while (0)53#endif5455/* An rnn based decoder, which can either be decoding current register56* values, or domain based decoding of a pm4 packet.57*58*/59struct rnndec {60struct rnn base;6162/* for pm4 packet decoding: */63uint32_t sizedwords;64uint32_t *dwords;65};6667static inline struct rnndec *68to_rnndec(struct rnn *rnn)69{70return (struct rnndec *)rnn;71}7273static uint32_t74rnn_val(struct rnn *rnn, uint32_t regbase)75{76struct rnndec *rnndec = to_rnndec(rnn);7778if (!rnndec->sizedwords) {79return reg_val(regbase);80} else if (regbase < rnndec->sizedwords) {81return rnndec->dwords[regbase];82} else {83// XXX throw an error84return -1;85}86}8788/* does not return */89static void90error(const char *fmt)91{92fprintf(stderr, fmt, lua_tostring(L, -1));93exit(1);94}9596/*97* An enum type that can be used as string or number:98*/99100struct rnndenum {101const char *str;102int val;103};104105static int106l_meta_rnn_enum_tostring(lua_State *L)107{108struct rnndenum *e = lua_touserdata(L, 1);109if (e->str) {110lua_pushstring(L, e->str);111} else {112char buf[32];113sprintf(buf, "%u", e->val);114lua_pushstring(L, buf);115}116return 1;117}118119/* so, this doesn't actually seem to be implemented yet, but hopefully120* some day lua comes to it's senses121*/122static int123l_meta_rnn_enum_tonumber(lua_State *L)124{125struct rnndenum *e = lua_touserdata(L, 1);126lua_pushinteger(L, e->val);127return 1;128}129130static const struct luaL_Reg l_meta_rnn_enum[] = {131{"__tostring", l_meta_rnn_enum_tostring},132{"__tonumber", l_meta_rnn_enum_tonumber},133{NULL, NULL} /* sentinel */134};135136static void137pushenum(struct lua_State *L, int val, struct rnnenum *info)138{139struct rnndenum *e = lua_newuserdata(L, sizeof(*e));140141e->val = val;142e->str = NULL;143144for (int i = 0; i < info->valsnum; i++) {145if (info->vals[i]->valvalid && (info->vals[i]->value == val)) {146e->str = info->vals[i]->name;147break;148}149}150151luaL_newmetatable(L, "rnnmetaenum");152luaL_setfuncs(L, l_meta_rnn_enum, 0);153lua_pop(L, 1);154155luaL_setmetatable(L, "rnnmetaenum");156}157158/* Expose rnn decode to script environment as "rnn" library:159*/160161struct rnndoff {162struct rnn *rnn;163struct rnndelem *elem;164uint64_t offset;165};166167static void168push_rnndoff(lua_State *L, struct rnn *rnn, struct rnndelem *elem,169uint64_t offset)170{171struct rnndoff *rnndoff = lua_newuserdata(L, sizeof(*rnndoff));172rnndoff->rnn = rnn;173rnndoff->elem = elem;174rnndoff->offset = offset;175}176177static int l_rnn_etype_array(lua_State *L, struct rnn *rnn,178struct rnndelem *elem, uint64_t offset);179static int l_rnn_etype_reg(lua_State *L, struct rnn *rnn, struct rnndelem *elem,180uint64_t offset);181182static int183pushdecval(struct lua_State *L, struct rnn *rnn, uint32_t regval,184struct rnntypeinfo *info)185{186union rnndecval val;187switch (rnn_decodelem(rnn, info, regval, &val)) {188case RNN_TTYPE_ENUM:189case RNN_TTYPE_INLINE_ENUM:190pushenum(L, val.i, info->eenum);191return 1;192case RNN_TTYPE_INT:193lua_pushinteger(L, val.i);194return 1;195case RNN_TTYPE_UINT:196case RNN_TTYPE_HEX:197lua_pushunsigned(L, val.u);198return 1;199case RNN_TTYPE_FLOAT:200lua_pushnumber(L, val.f);201return 1;202case RNN_TTYPE_BOOLEAN:203lua_pushboolean(L, val.u);204return 1;205case RNN_TTYPE_INVALID:206default:207return 0;208}209}210211static int212l_rnn_etype(lua_State *L, struct rnn *rnn, struct rnndelem *elem,213uint64_t offset)214{215int ret;216uint32_t regval;217DBG("elem=%p (%d), offset=%lu", elem, elem->type, offset);218switch (elem->type) {219case RNN_ETYPE_REG:220/* if a register has no bitfields, just return221* the raw value:222*/223regval = rnn_val(rnn, offset);224regval <<= elem->typeinfo.shr;225ret = pushdecval(L, rnn, regval, &elem->typeinfo);226if (ret)227return ret;228return l_rnn_etype_reg(L, rnn, elem, offset);229case RNN_ETYPE_ARRAY:230return l_rnn_etype_array(L, rnn, elem, offset);231default:232/* hmm.. */233printf("unhandled type: %d\n", elem->type);234return 0;235}236}237238/*239* Struct Object:240* To implement stuff like 'RB_MRT[n].CONTROL' we need a struct-object241* to represent the current array index (ie. 'RB_MRT[n]')242*/243244static int245l_rnn_struct_meta_index(lua_State *L)246{247struct rnndoff *rnndoff = lua_touserdata(L, 1);248const char *name = lua_tostring(L, 2);249struct rnndelem *elem = rnndoff->elem;250int i;251252for (i = 0; i < elem->subelemsnum; i++) {253struct rnndelem *subelem = elem->subelems[i];254if (!strcmp(name, subelem->name)) {255return l_rnn_etype(L, rnndoff->rnn, subelem,256rnndoff->offset + subelem->offset);257}258}259260return 0;261}262263static const struct luaL_Reg l_meta_rnn_struct[] = {264{"__index", l_rnn_struct_meta_index}, {NULL, NULL} /* sentinel */265};266267static int268l_rnn_etype_struct(lua_State *L, struct rnn *rnn, struct rnndelem *elem,269uint64_t offset)270{271push_rnndoff(L, rnn, elem, offset);272273luaL_newmetatable(L, "rnnmetastruct");274luaL_setfuncs(L, l_meta_rnn_struct, 0);275lua_pop(L, 1);276277luaL_setmetatable(L, "rnnmetastruct");278279return 1;280}281282/*283* Array Object:284*/285286static int287l_rnn_array_meta_index(lua_State *L)288{289struct rnndoff *rnndoff = lua_touserdata(L, 1);290int idx = lua_tointeger(L, 2);291struct rnndelem *elem = rnndoff->elem;292uint64_t offset = rnndoff->offset + (elem->stride * idx);293294DBG("rnndoff=%p, idx=%d, numsubelems=%d", rnndoff, idx,295rnndoff->elem->subelemsnum);296297/* if just a single sub-element, it is directly a register,298* otherwise we need to accumulate the array index while299* we wait for the register name within the array..300*/301if (elem->subelemsnum == 1) {302return l_rnn_etype(L, rnndoff->rnn, elem->subelems[0], offset);303} else {304return l_rnn_etype_struct(L, rnndoff->rnn, elem, offset);305}306307return 0;308}309310static const struct luaL_Reg l_meta_rnn_array[] = {311{"__index", l_rnn_array_meta_index}, {NULL, NULL} /* sentinel */312};313314static int315l_rnn_etype_array(lua_State *L, struct rnn *rnn, struct rnndelem *elem,316uint64_t offset)317{318push_rnndoff(L, rnn, elem, offset);319320luaL_newmetatable(L, "rnnmetaarray");321luaL_setfuncs(L, l_meta_rnn_array, 0);322lua_pop(L, 1);323324luaL_setmetatable(L, "rnnmetaarray");325326return 1;327}328329/*330* Register element:331*/332333static int334l_rnn_reg_meta_index(lua_State *L)335{336struct rnndoff *rnndoff = lua_touserdata(L, 1);337const char *name = lua_tostring(L, 2);338struct rnndelem *elem = rnndoff->elem;339struct rnntypeinfo *info = &elem->typeinfo;340struct rnnbitfield **bitfields;341int bitfieldsnum;342int i;343344switch (info->type) {345case RNN_TTYPE_BITSET:346bitfields = info->ebitset->bitfields;347bitfieldsnum = info->ebitset->bitfieldsnum;348break;349case RNN_TTYPE_INLINE_BITSET:350bitfields = info->bitfields;351bitfieldsnum = info->bitfieldsnum;352break;353default:354printf("invalid register type: %d\n", info->type);355return 0;356}357358for (i = 0; i < bitfieldsnum; i++) {359struct rnnbitfield *bf = bitfields[i];360if (!strcmp(name, bf->name)) {361uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);362363regval &= typeinfo_mask(&bf->typeinfo);364regval >>= bf->typeinfo.low;365regval <<= bf->typeinfo.shr;366367DBG("name=%s, info=%p, subelemsnum=%d, type=%d, regval=%x", name, info,368rnndoff->elem->subelemsnum, bf->typeinfo.type, regval);369370return pushdecval(L, rnndoff->rnn, regval, &bf->typeinfo);371}372}373374printf("invalid member: %s\n", name);375return 0;376}377378static int379l_rnn_reg_meta_tostring(lua_State *L)380{381struct rnndoff *rnndoff = lua_touserdata(L, 1);382uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);383struct rnndecaddrinfo *info = rnn_reginfo(rnndoff->rnn, rnndoff->offset);384char *decoded;385if (info && info->typeinfo) {386decoded = rnndec_decodeval(rnndoff->rnn->vc, info->typeinfo, regval);387} else {388asprintf(&decoded, "%08x", regval);389}390lua_pushstring(L, decoded);391free(decoded);392if (info) {393free(info->name);394free(info);395}396return 1;397}398399static int400l_rnn_reg_meta_tonumber(lua_State *L)401{402struct rnndoff *rnndoff = lua_touserdata(L, 1);403uint32_t regval = rnn_val(rnndoff->rnn, rnndoff->offset);404405regval <<= rnndoff->elem->typeinfo.shr;406407lua_pushnumber(L, regval);408return 1;409}410411static const struct luaL_Reg l_meta_rnn_reg[] = {412{"__index", l_rnn_reg_meta_index},413{"__tostring", l_rnn_reg_meta_tostring},414{"__tonumber", l_rnn_reg_meta_tonumber},415{NULL, NULL} /* sentinel */416};417418static int419l_rnn_etype_reg(lua_State *L, struct rnn *rnn, struct rnndelem *elem,420uint64_t offset)421{422push_rnndoff(L, rnn, elem, offset);423424luaL_newmetatable(L, "rnnmetareg");425luaL_setfuncs(L, l_meta_rnn_reg, 0);426lua_pop(L, 1);427428luaL_setmetatable(L, "rnnmetareg");429430return 1;431}432433/*434*435*/436437static int438l_rnn_meta_index(lua_State *L)439{440struct rnn *rnn = lua_touserdata(L, 1);441const char *name = lua_tostring(L, 2);442struct rnndelem *elem;443444elem = rnn_regelem(rnn, name);445if (!elem)446return 0;447448return l_rnn_etype(L, rnn, elem, elem->offset);449}450451static int452l_rnn_meta_gc(lua_State *L)453{454// TODO455// struct rnn *rnn = lua_touserdata(L, 1);456// rnn_deinit(rnn);457return 0;458}459460static const struct luaL_Reg l_meta_rnn[] = {461{"__index", l_rnn_meta_index},462{"__gc", l_rnn_meta_gc},463{NULL, NULL} /* sentinel */464};465466static int467l_rnn_init(lua_State *L)468{469const char *gpuname = lua_tostring(L, 1);470struct rnndec *rnndec = lua_newuserdata(L, sizeof(*rnndec));471_rnn_init(&rnndec->base, 0);472rnn_load(&rnndec->base, gpuname);473rnndec->sizedwords = 0;474475luaL_newmetatable(L, "rnnmeta");476luaL_setfuncs(L, l_meta_rnn, 0);477lua_pop(L, 1);478479luaL_setmetatable(L, "rnnmeta");480481return 1;482}483484static int485l_rnn_enumname(lua_State *L)486{487struct rnn *rnn = lua_touserdata(L, 1);488const char *name = lua_tostring(L, 2);489uint32_t val = (uint32_t)lua_tonumber(L, 3);490lua_pushstring(L, rnn_enumname(rnn, name, val));491return 1;492}493494static int495l_rnn_regname(lua_State *L)496{497struct rnn *rnn = lua_touserdata(L, 1);498uint32_t regbase = (uint32_t)lua_tonumber(L, 2);499lua_pushstring(L, rnn_regname(rnn, regbase, 1));500return 1;501}502503static int504l_rnn_regval(lua_State *L)505{506struct rnn *rnn = lua_touserdata(L, 1);507uint32_t regbase = (uint32_t)lua_tonumber(L, 2);508uint32_t regval = (uint32_t)lua_tonumber(L, 3);509struct rnndecaddrinfo *info = rnn_reginfo(rnn, regbase);510char *decoded;511if (info && info->typeinfo) {512decoded = rnndec_decodeval(rnn->vc, info->typeinfo, regval);513} else {514asprintf(&decoded, "%08x", regval);515}516lua_pushstring(L, decoded);517free(decoded);518if (info) {519free(info->name);520free(info);521}522return 1;523}524525static const struct luaL_Reg l_rnn[] = {526{"init", l_rnn_init},527{"enumname", l_rnn_enumname},528{"regname", l_rnn_regname},529{"regval", l_rnn_regval},530{NULL, NULL} /* sentinel */531};532533/* Expose the register state to script enviroment as a "regs" library:534*/535536static int537l_reg_written(lua_State *L)538{539uint32_t regbase = (uint32_t)lua_tonumber(L, 1);540lua_pushnumber(L, reg_written(regbase));541return 1;542}543544static int545l_reg_lastval(lua_State *L)546{547uint32_t regbase = (uint32_t)lua_tonumber(L, 1);548lua_pushnumber(L, reg_lastval(regbase));549return 1;550}551552static int553l_reg_val(lua_State *L)554{555uint32_t regbase = (uint32_t)lua_tonumber(L, 1);556lua_pushnumber(L, reg_val(regbase));557return 1;558}559560static const struct luaL_Reg l_regs[] = {561{"written", l_reg_written},562{"lastval", l_reg_lastval},563{"val", l_reg_val},564{NULL, NULL} /* sentinel */565};566567/* Expose API to lookup snapshot buffers:568*/569570uint64_t gpubaseaddr(uint64_t gpuaddr);571unsigned hostlen(uint64_t gpuaddr);572573/* given address, return base-address of buffer: */574static int575l_bo_base(lua_State *L)576{577uint64_t addr = (uint64_t)lua_tonumber(L, 1);578lua_pushnumber(L, gpubaseaddr(addr));579return 1;580}581582/* given address, return the remaining size of the buffer: */583static int584l_bo_size(lua_State *L)585{586uint64_t addr = (uint64_t)lua_tonumber(L, 1);587lua_pushnumber(L, hostlen(addr));588return 1;589}590591static const struct luaL_Reg l_bos[] = {592{"base", l_bo_base}, {"size", l_bo_size}, {NULL, NULL} /* sentinel */593};594595static void596openlib(const char *lib, const luaL_Reg *reg)597{598lua_newtable(L);599luaL_setfuncs(L, reg, 0);600lua_setglobal(L, lib);601}602603/* called at start to load the script: */604int605script_load(const char *file)606{607int ret;608609assert(!L);610611L = luaL_newstate();612luaL_openlibs(L);613openlib("bos", l_bos);614openlib("regs", l_regs);615openlib("rnn", l_rnn);616617ret = luaL_loadfile(L, file);618if (ret)619error("%s\n");620621ret = lua_pcall(L, 0, LUA_MULTRET, 0);622if (ret)623error("%s\n");624625return 0;626}627628/* called at start of each cmdstream file: */629void630script_start_cmdstream(const char *name)631{632if (!L)633return;634635lua_getglobal(L, "start_cmdstream");636637/* if no handler just ignore it: */638if (!lua_isfunction(L, -1)) {639lua_pop(L, 1);640return;641}642643lua_pushstring(L, name);644645/* do the call (1 arguments, 0 result) */646if (lua_pcall(L, 1, 0, 0) != 0)647error("error running function `f': %s\n");648}649650/* called at each DRAW_INDX, calls script drawidx fxn to process651* the current state652*/653void654script_draw(const char *primtype, uint32_t nindx)655{656if (!L)657return;658659lua_getglobal(L, "draw");660661/* if no handler just ignore it: */662if (!lua_isfunction(L, -1)) {663lua_pop(L, 1);664return;665}666667lua_pushstring(L, primtype);668lua_pushnumber(L, nindx);669670/* do the call (2 arguments, 0 result) */671if (lua_pcall(L, 2, 0, 0) != 0)672error("error running function `f': %s\n");673}674675static int676l_rnn_meta_dom_index(lua_State *L)677{678struct rnn *rnn = lua_touserdata(L, 1);679uint32_t offset = (uint32_t)lua_tonumber(L, 2);680struct rnndelem *elem;681682/* TODO might be nicer if the arg isn't a number, to search the domain683* for matching bitfields.. so that the script could do something like684* 'pkt.WIDTH' insteadl of 'pkt[1].WIDTH', ie. not have to remember the685* offset of the dword containing the bitfield..686*/687688elem = rnn_regoff(rnn, offset);689if (!elem)690return 0;691692return l_rnn_etype(L, rnn, elem, elem->offset);693}694695/*696* A wrapper object for rnndomain based decoding of an array of dwords697* (ie. for pm4 packet decoding). Mostly re-uses the register-value698* decoding for the individual dwords and bitfields.699*/700701static int702l_rnn_meta_dom_gc(lua_State *L)703{704// TODO705// struct rnn *rnn = lua_touserdata(L, 1);706// rnn_deinit(rnn);707return 0;708}709710static const struct luaL_Reg l_meta_rnn_dom[] = {711{"__index", l_rnn_meta_dom_index},712{"__gc", l_rnn_meta_dom_gc},713{NULL, NULL} /* sentinel */714};715716/* called to general pm4 packet decoding, such as texture/sampler state717*/718void719script_packet(uint32_t *dwords, uint32_t sizedwords, struct rnn *rnn,720struct rnndomain *dom)721{722if (!L)723return;724725lua_getglobal(L, dom->name);726727/* if no handler for the packet, just ignore it: */728if (!lua_isfunction(L, -1)) {729lua_pop(L, 1);730return;731}732733struct rnndec *rnndec = lua_newuserdata(L, sizeof(*rnndec));734735rnndec->base = *rnn;736rnndec->base.dom[0] = dom;737rnndec->base.dom[1] = NULL;738rnndec->dwords = dwords;739rnndec->sizedwords = sizedwords;740741luaL_newmetatable(L, "rnnmetadom");742luaL_setfuncs(L, l_meta_rnn_dom, 0);743lua_pop(L, 1);744745luaL_setmetatable(L, "rnnmetadom");746747lua_pushnumber(L, sizedwords);748749if (lua_pcall(L, 2, 0, 0) != 0)750error("error running function `f': %s\n");751}752753/* helper to call fxn that takes and returns void: */754static void755simple_call(const char *name)756{757if (!L)758return;759760lua_getglobal(L, name);761762/* if no handler just ignore it: */763if (!lua_isfunction(L, -1)) {764lua_pop(L, 1);765return;766}767768/* do the call (0 arguments, 0 result) */769if (lua_pcall(L, 0, 0, 0) != 0)770error("error running function `f': %s\n");771}772773/* called at end of each cmdstream file: */774void775script_end_cmdstream(void)776{777simple_call("end_cmdstream");778}779780/* called at start of submit/issueibcmds: */781void782script_start_submit(void)783{784simple_call("start_submit");785}786787/* called at end of submit/issueibcmds: */788void789script_end_submit(void)790{791simple_call("end_submit");792}793794/* called after last cmdstream file: */795void796script_finish(void)797{798if (!L)799return;800801simple_call("finish");802803lua_close(L);804L = NULL;805}806807808