mesa/src/freedreno/decode/scripts/parse-submits.lua
Vinson Lee 8c8496e2f6
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run
freedreno: Sort MRTs so output is stable
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7095
Signed-off-by: Vinson Lee <vlee@freedesktop.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35402>
2025-06-08 14:07:50 +00:00

418 lines
9.7 KiB
Lua

-- Parse cmdstream dump and analyse blits and batches
--local posix = require "posix"
function printf(fmt, ...)
return io.write(string.format(fmt, ...))
end
function dbg(fmt, ...)
--printf(fmt, ...)
end
printf("Analyzing Data...\n")
local r = rnn.init("a630")
-- Each submit, all draws will target the same N MRTs:
local mrts = {}
local allmrts = {} -- includes historical render targets
function push_mrt(fmt, w, h, samples, base, flag, gmem)
dbg("MRT: %s %ux%u 0x%x\n", fmt, w, h, base)
local mrt = {}
mrt.format = fmt
mrt.w = w
mrt.h = h
mrt.samples = samples
mrt.base = base
mrt.flag = flag
mrt.gmem = gmem
mrts[base] = mrt
allmrts[base] = mrt
end
-- And each each draw will read from M sources/textures:
local sources = {}
function push_source(fmt, w, h, samples, base, flag)
dbg("SRC: %s %ux%u 0x%x\n", fmt, w, h, base)
local source = {}
source.format = fmt
source.w = w
source.h = h
source.samples = samples
source.base = base
source.flag = flag
sources[base] = source
end
local binw
local binh
local nbins
local blits = 0
local draws = 0
local drawmode
local cleared
local restored
local resolved
local nullbatch
local depthtest
local depthwrite
local stenciltest
local stencilwrite
function reset()
dbg("reset\n")
mrts = {}
sources = {}
draws = 0
blits = 0
cleared = {}
restored = {}
resolved = {}
depthtest = false
depthwrite = false
stenciltest = false
stencilwrite = false
drawmode = Nil
end
function start_submit()
dbg("start_submit\n")
reset()
nullbatch = true
end
function finish()
dbg("finish\n")
printf("\n")
-- TODO we get false-positives for 'NULL BATCH!' because we don't have
-- a really good way to differentiate between submits and cmds. Ie.
-- with growable cmdstream, and a large # of tiles, IB1 can get split
-- across multiple buffers. Since we ignore GMEM draws for window-
-- offset != 0,0, the later cmds will appear as null batches
if draws == 0 and blits == 0 then
if nullbatch then
printf("NULL BATCH!\n");
end
return
end
if draws > 0 then
printf("Batch:\n")
printf("-------\n")
printf(" # of draws: %u\n", draws)
printf(" mode: %s\n", drawmode)
if drawmode == "RM6_BIN_RENDER_START" then
printf(" bin size: %ux%u (%u bins)\n", binw, binh, nbins)
end
if depthtest or depthwrite then
printf(" ")
if depthtest then
printf("DEPTHTEST ")
end
if depthwrite then
printf("DEPTHWRITE")
end
printf("\n")
end
if stenciltest or stencilwrite then
printf(" ")
if stenciltest then
printf("STENCILTEST ")
end
if stencilwrite then
printf("STENCILWRITE")
end
printf("\n")
end
else
printf("Blit:\n")
printf("-----\n")
end
local keys = {}
for base in pairs(mrts) do
table.insert(keys,base)
end
table.sort(keys)
for _,base in ipairs(keys) do
local mrt = mrts[base]
printf(" MRT[0x%x:0x%x]:\t%ux%u\t\t%s (%s)", base, mrt.flag, mrt.w, mrt.h, mrt.format, mrt.samples)
if drawmode == "RM6_BIN_RENDER_START" then
if cleared[mrt.gmem] then
printf("\tCLEARED")
end
if restored[mrt.gmem] then
printf("\tRESTORED")
end
if resolved[mrt.gmem] then
printf("\tRESOLVED")
end
else
if cleared[mrt.base] then
printf("\tCLEARED")
end
end
printf("\n")
end
function print_source(source)
printf(" SRC[0x%x:0x%x]:\t%ux%u\t\t%s (%s)\n", source.base, source.flag, source.w, source.h, source.format, source.samples)
end
for base,source in pairs(sources) do
-- only show sources that have been previously rendered to, other
-- textures are less interesting. Possibly this should be an
-- option somehow
if draws < 10 then
print_source(source)
elseif allmrts[base] or draws == 0 then
print_source(source)
elseif source.flag and allmrts[source.flag] then
print_source(source)
end
end
reset()
end
function end_submit()
dbg("end_submit\n")
finish()
end
-- Track the current mode:
local mode = ""
function CP_SET_MARKER(pkt, size)
mode = pkt[0].MODE
dbg("mode: %s\n", mode)
end
function CP_EVENT_WRITE(pkt, size)
if tostring(pkt[0].EVENT) ~= "BLIT" then
return
end
nullbatch = false
local m = tostring(mode)
if m == "RM6_BIN_RENDER_START" then
-- either clear or restore:
if r.RB_BLIT_INFO.CLEAR_MASK == 0 then
restored[r.RB_BLIT_BASE_GMEM] = 1
else
cleared[r.RB_BLIT_BASE_GMEM] = 1
end
-- push_mrt() because we could have GMEM
-- passes with only a clear and no draws:
local flag = 0
local sysmem = 0;
-- try to match up the GMEM addr with the MRT/DEPTH state,
-- to avoid relying on RB_BLIT_DST also getting written:
for n = 0,r.RB_FS_OUTPUT_CNTL1.MRT-1 do
if r.RB_MRT[n].BASE_GMEM == r.RB_BLIT_BASE_GMEM then
sysmem = r.RB_MRT[n].BASE
flag = r.RB_MRT_FLAG_BUFFER[n].ADDR
break
end
end
if sysmem == 0 and r.RB_BLIT_BASE_GMEM == r.RB_DEPTH_BUFFER_BASE_GMEM then
sysmem = r.RB_DEPTH_BUFFER_BASE
flag = r.RB_DEPTH_FLAG_BUFFER_BASE
end
--NOTE this can get confused by previous blits:
--if sysmem == 0 then
-- -- fallback:
-- sysmem = r.RB_BLIT_DST
-- flag = r.RB_BLIT_FLAG_DST
--end
if not r.RB_BLIT_DST_INFO.FLAGS then
flag = 0
end
-- TODO maybe just emit RB_BLIT_DST/HI for clears.. otherwise
-- we get confused by stale values in registers.. not sure
-- if this is a problem w/ blob
push_mrt(r.RB_BLIT_DST_INFO.COLOR_FORMAT,
r.RB_BLIT_SCISSOR_BR.X + 1,
r.RB_BLIT_SCISSOR_BR.Y + 1,
r.RB_BLIT_DST_INFO.SAMPLES,
sysmem,
flag,
r.RB_BLIT_BASE_GMEM)
elseif m == "RM6_BIN_RESOLVE" then
resolved[r.RB_BLIT_BASE_GMEM] = 1
else
printf("I am confused!!!\n")
end
end
function A6XX_TEX_CONST(pkt, size)
push_source(pkt[0].FMT,
pkt[1].WIDTH, pkt[1].HEIGHT,
pkt[0].SAMPLES,
pkt[4].BASE_LO | (pkt[5].BASE_HI << 32),
pkt[7].FLAG_LO | (pkt[8].FLAG_HI << 32))
end
function handle_blit()
-- blob sometimes uses CP_BLIT for resolves, so filter those out:
-- TODO it would be nice to not hard-code GMEM addr:
-- TODO I guess the src can be an offset from GMEM addr..
if r.SP_PS_2D_SRC == 0x100000 and not r.RB_2D_BLIT_CNTL.SOLID_COLOR then
resolved[0] = 1
return
end
if draws > 0 then
finish()
end
reset()
drawmode = "BLIT"
-- This kinda assumes that we are doing full img blits, which is maybe
-- Not completely legit. We could perhaps instead just track pitch and
-- size/pitch?? Or maybe the size doesn't matter much
push_mrt(r.RB_2D_DST_INFO.COLOR_FORMAT,
r.GRAS_2D_DST_BR.X + 1,
r.GRAS_2D_DST_BR.Y + 1,
"MSAA_ONE",
r.RB_2D_DST,
r.RB_2D_DST_FLAGS,
-1)
if r.RB_2D_BLIT_CNTL.SOLID_COLOR then
dbg("CLEAR=%x\n", r.RB_2D_DST)
cleared[r.RB_2D_DST] = 1
else
push_source(r.SP_2D_SRC_FORMAT.COLOR_FORMAT,
r.GRAS_2D_SRC_BR_X.X + 1,
r.GRAS_2D_SRC_BR_Y.Y + 1,
"MSAA_ONE",
r.SP_PS_2D_SRC,
r.SP_PS_2D_SRC_FLAGS)
end
blits = blits + 1
finish()
end
function valid_transition(curmode, newmode)
if curmode == "RM6_BIN_VISIBILITY" and newmode == "RM6_BIN_RENDER_START" then
return true
end
if curmode == "RM6_BIN_RENDER_START" and newmode == "RM6_BIN_RESOLVE" then
return true
end
return false
end
function draw(primtype, nindx)
dbg("draw: %s (%s)\n", primtype, mode)
nullbatch = false
if primtype == "BLIT_OP_SCALE" then
handle_blit()
return
elseif primtype == "EVENT:BLIT" then
return
end
local m = tostring(mode)
-- detect changes in drawmode which indicate a different
-- pass.. BINNING->GMEM means same pass, but other
-- transitions mean different pass:
if drawmode and m ~= drawmode then
dbg("%s -> %s transition\n", drawmode, m)
if not valid_transition(drawmode, m) then
dbg("invalid transition, new render pass!\n")
finish()
reset()
end
end
if m ~= "RM6_BIN_RENDER_START" and m ~= "RM6_DIRECT_RENDER" then
if m == "RM6_BIN_VISIBILITY" then
drawmode = m
return
end
if m == "RM6_BIN_RESOLVE" and primtype == "EVENT:BLIT" then
return
end
if m == "RM6_BLIT2DSCALE" and primtype == "EVENT:LRZ_CLEAR" then
return
end
printf("unknown MODE %s for primtype %s\n", m, primtype)
return
end
-- Only count the first tile for GMEM mode to avoid counting
-- each draw for each tile
if m == "RM6_BIN_RENDER_START" then
if r.RB_WINDOW_OFFSET.X ~= 0 or r.RB_WINDOW_OFFSET.Y ~= 0 then
return
end
end
drawmode = m
local render_components = {}
render_components[0] = r.RB_RENDER_COMPONENTS.RT0;
render_components[1] = r.RB_RENDER_COMPONENTS.RT1;
render_components[2] = r.RB_RENDER_COMPONENTS.RT2;
render_components[3] = r.RB_RENDER_COMPONENTS.RT3;
render_components[4] = r.RB_RENDER_COMPONENTS.RT4;
render_components[5] = r.RB_RENDER_COMPONENTS.RT5;
render_components[6] = r.RB_RENDER_COMPONENTS.RT6;
render_components[7] = r.RB_RENDER_COMPONENTS.RT7;
for n = 0,r.RB_FS_OUTPUT_CNTL1.MRT-1 do
if render_components[n] ~= 0 then
push_mrt(r.RB_MRT[n].BUF_INFO.COLOR_FORMAT,
r.GRAS_SC_SCREEN_SCISSOR[0].BR.X + 1,
r.GRAS_SC_SCREEN_SCISSOR[0].BR.Y + 1,
r.RB_BLIT_GMEM_MSAA_CNTL.SAMPLES,
r.RB_MRT[n].BASE,
r.RB_MRT_FLAG_BUFFER[n].ADDR,
r.RB_MRT[n].BASE_GMEM)
end
end
local depthbase = r.RB_DEPTH_BUFFER_BASE
if depthbase ~= 0 then
push_mrt(r.RB_DEPTH_BUFFER_INFO.DEPTH_FORMAT,
r.GRAS_SC_SCREEN_SCISSOR[0].BR.X + 1,
r.GRAS_SC_SCREEN_SCISSOR[0].BR.Y + 1,
r.RB_BLIT_GMEM_MSAA_CNTL.SAMPLES,
depthbase,
r.RB_DEPTH_FLAG_BUFFER_BASE,
r.RB_DEPTH_BUFFER_BASE_GMEM)
end
if r.RB_DEPTH_CNTL.Z_WRITE_ENABLE then
depthwrite = true
end
if r.RB_DEPTH_CNTL.Z_TEST_ENABLE then
depthtest = true
end
-- clearly 0 != false.. :-/
if r.RB_STENCILWRMASK.WRMASK ~= 0 then
stencilwrite = true
end
if r.RB_STENCIL_CONTROL.STENCIL_ENABLE then
stenciltest = true
end
-- TODO should also check for stencil buffer for z32+s8 case
if m == "RM6_BIN_RENDER_START" then
binw = r.VSC_BIN_SIZE.WIDTH
binh = r.VSC_BIN_SIZE.HEIGHT
nbins = r.VSC_BIN_COUNT.NX * r.VSC_BIN_COUNT.NY
end
draws = draws + 1
end