1-- Parse cmdstream dump and analyse blits and batches 2 3--local posix = require "posix" 4 5function printf(fmt, ...) 6 return io.write(string.format(fmt, ...)) 7end 8 9function dbg(fmt, ...) 10 --printf(fmt, ...) 11end 12 13printf("Analyzing Data...\n") 14 15local r = rnn.init("a630") 16 17-- Each submit, all draws will target the same N MRTs: 18local mrts = {} 19local allmrts = {} -- includes historical render targets 20function push_mrt(fmt, w, h, samples, base, flag, gmem) 21 dbg("MRT: %s %ux%u 0x%x\n", fmt, w, h, base) 22 23 local mrt = {} 24 mrt.format = fmt 25 mrt.w = w 26 mrt.h = h 27 mrt.samples = samples 28 mrt.base = base 29 mrt.flag = flag 30 mrt.gmem = gmem 31 32 mrts[base] = mrt 33 allmrts[base] = mrt 34end 35 36-- And each each draw will read from M sources/textures: 37local sources = {} 38function push_source(fmt, w, h, samples, base, flag) 39 dbg("SRC: %s %ux%u 0x%x\n", fmt, w, h, base) 40 41 local source = {} 42 source.format = fmt 43 source.w = w 44 source.h = h 45 source.samples = samples 46 source.base = base 47 source.flag = flag 48 49 sources[base] = source 50end 51 52local binw 53local binh 54local nbins 55local blits = 0 56local draws = 0 57local drawmode 58local cleared 59local restored 60local resolved 61local nullbatch 62local depthtest 63local depthwrite 64local stenciltest 65local stencilwrite 66 67function reset() 68 dbg("reset\n") 69 mrts = {} 70 sources = {} 71 draws = 0 72 blits = 0 73 cleared = {} 74 restored = {} 75 resolved = {} 76 depthtest = false 77 depthwrite = false 78 stenciltest = false 79 stencilwrite = false 80 drawmode = Nil 81end 82 83function start_submit() 84 dbg("start_submit\n") 85 reset() 86 nullbatch = true 87end 88 89function finish() 90 dbg("finish\n") 91 92 printf("\n") 93 94 -- TODO we get false-positives for 'NULL BATCH!' because we don't have 95 -- a really good way to differentiate between submits and cmds. Ie. 96 -- with growable cmdstream, and a large # of tiles, IB1 can get split 97 -- across multiple buffers. Since we ignore GMEM draws for window- 98 -- offset != 0,0, the later cmds will appear as null batches 99 if draws == 0 and blits == 0 then 100 if nullbatch then 101 printf("NULL BATCH!\n"); 102 end 103 return 104 end 105 106 if draws > 0 then 107 printf("Batch:\n") 108 printf("-------\n") 109 printf(" # of draws: %u\n", draws) 110 printf(" mode: %s\n", drawmode) 111 if drawmode == "RM6_GMEM" then 112 printf(" bin size: %ux%u (%u bins)\n", binw, binh, nbins) 113 end 114 if depthtest or depthwrite then 115 printf(" ") 116 if depthtest then 117 printf("DEPTHTEST ") 118 end 119 if depthwrite then 120 printf("DEPTHWRITE") 121 end 122 printf("\n") 123 end 124 if stenciltest or stencilwrite then 125 printf(" ") 126 if stenciltest then 127 printf("STENCILTEST ") 128 end 129 if stencilwrite then 130 printf("STENCILWRITE") 131 end 132 printf("\n") 133 end 134 else 135 printf("Blit:\n") 136 printf("-----\n") 137 end 138 139 for base,mrt in pairs(mrts) do 140 printf(" MRT[0x%x:0x%x]:\t%ux%u\t\t%s (%s)", base, mrt.flag, mrt.w, mrt.h, mrt.format, mrt.samples) 141 if drawmode == "RM6_GMEM" then 142 if cleared[mrt.gmem] then 143 printf("\tCLEARED") 144 end 145 if restored[mrt.gmem] then 146 printf("\tRESTORED") 147 end 148 if resolved[mrt.gmem] then 149 printf("\tRESOLVED") 150 end 151 else 152 if cleared[mrt.base] then 153 printf("\tCLEARED") 154 end 155 end 156 printf("\n") 157 end 158 159 function print_source(source) 160 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) 161 end 162 163 for base,source in pairs(sources) do 164 -- only show sources that have been previously rendered to, other 165 -- textures are less interesting. Possibly this should be an 166 -- option somehow 167 if draws < 10 then 168 print_source(source) 169 elseif allmrts[base] or draws == 0 then 170 print_source(source) 171 elseif source.flag and allmrts[source.flag] then 172 print_source(source) 173 end 174 end 175 reset() 176end 177 178function end_submit() 179 dbg("end_submit\n") 180 finish() 181end 182 183-- Track the current mode: 184local mode = "" 185function CP_SET_MARKER(pkt, size) 186 mode = pkt[0].MARKER 187 dbg("mode: %s\n", mode) 188end 189 190function CP_EVENT_WRITE(pkt, size) 191 if tostring(pkt[0].EVENT) ~= "BLIT" then 192 return 193 end 194 nullbatch = false 195 local m = tostring(mode) 196 if m == "RM6_GMEM" then 197 -- either clear or restore: 198 if r.RB_BLIT_INFO.CLEAR_MASK == 0 then 199 restored[r.RB_BLIT_BASE_GMEM] = 1 200 else 201 cleared[r.RB_BLIT_BASE_GMEM] = 1 202 end 203 -- push_mrt() because we could have GMEM 204 -- passes with only a clear and no draws: 205 local flag = 0 206 local sysmem = 0; 207 -- try to match up the GMEM addr with the MRT/DEPTH state, 208 -- to avoid relying on RB_BLIT_DST also getting written: 209 for n = 0,r.RB_FS_OUTPUT_CNTL1.MRT-1 do 210 if r.RB_MRT[n].BASE_GMEM == r.RB_BLIT_BASE_GMEM then 211 sysmem = r.RB_MRT[n].BASE 212 flag = r.RB_MRT_FLAG_BUFFER[n].ADDR 213 break 214 end 215 end 216 if sysmem == 0 and r.RB_BLIT_BASE_GMEM == r.RB_DEPTH_BUFFER_BASE_GMEM then 217 sysmem = r.RB_DEPTH_BUFFER_BASE 218 flag = r.RB_DEPTH_FLAG_BUFFER_BASE 219 220 end 221 --NOTE this can get confused by previous blits: 222 --if sysmem == 0 then 223 -- -- fallback: 224 -- sysmem = r.RB_BLIT_DST 225 -- flag = r.RB_BLIT_FLAG_DST 226 --end 227 if not r.RB_BLIT_DST_INFO.FLAGS then 228 flag = 0 229 end 230 -- TODO maybe just emit RB_BLIT_DST/HI for clears.. otherwise 231 -- we get confused by stale values in registers.. not sure 232 -- if this is a problem w/ blob 233 push_mrt(r.RB_BLIT_DST_INFO.COLOR_FORMAT, 234 r.RB_BLIT_SCISSOR_BR.X + 1, 235 r.RB_BLIT_SCISSOR_BR.Y + 1, 236 r.RB_BLIT_DST_INFO.SAMPLES, 237 sysmem, 238 flag, 239 r.RB_BLIT_BASE_GMEM) 240 elseif m == "RM6_RESOLVE" then 241 resolved[r.RB_BLIT_BASE_GMEM] = 1 242 else 243 printf("I am confused!!!\n") 244 end 245end 246 247function A6XX_TEX_CONST(pkt, size) 248 push_source(pkt[0].FMT, 249 pkt[1].WIDTH, pkt[1].HEIGHT, 250 pkt[0].SAMPLES, 251 pkt[4].BASE_LO | (pkt[5].BASE_HI << 32), 252 pkt[7].FLAG_LO | (pkt[8].FLAG_HI << 32)) 253end 254 255function handle_blit() 256 -- blob sometimes uses CP_BLIT for resolves, so filter those out: 257 -- TODO it would be nice to not hard-code GMEM addr: 258 -- TODO I guess the src can be an offset from GMEM addr.. 259 if r.SP_PS_2D_SRC == 0x100000 and not r.RB_2D_BLIT_CNTL.SOLID_COLOR then 260 resolved[0] = 1 261 return 262 end 263 if draws > 0 then 264 finish() 265 end 266 reset() 267 drawmode = "BLIT" 268 -- This kinda assumes that we are doing full img blits, which is maybe 269 -- Not completely legit. We could perhaps instead just track pitch and 270 -- size/pitch?? Or maybe the size doesn't matter much 271 push_mrt(r.RB_2D_DST_INFO.COLOR_FORMAT, 272 r.GRAS_2D_DST_BR.X + 1, 273 r.GRAS_2D_DST_BR.Y + 1, 274 "MSAA_ONE", 275 r.RB_2D_DST, 276 r.RB_2D_DST_FLAGS, 277 -1) 278 if r.RB_2D_BLIT_CNTL.SOLID_COLOR then 279 dbg("CLEAR=%x\n", r.RB_2D_DST) 280 cleared[r.RB_2D_DST] = 1 281 else 282 push_source(r.SP_2D_SRC_FORMAT.COLOR_FORMAT, 283 r.GRAS_2D_SRC_BR_X.X + 1, 284 r.GRAS_2D_SRC_BR_Y.Y + 1, 285 "MSAA_ONE", 286 r.SP_PS_2D_SRC, 287 r.SP_PS_2D_SRC_FLAGS) 288 end 289 blits = blits + 1 290 finish() 291end 292 293function valid_transition(curmode, newmode) 294 if curmode == "RM6_BINNING" and newmode == "RM6_GMEM" then 295 return true 296 end 297 if curmode == "RM6_GMEM" and newmode == "RM6_RESOLVE" then 298 return true 299 end 300 return false 301end 302 303function draw(primtype, nindx) 304 dbg("draw: %s (%s)\n", primtype, mode) 305 nullbatch = false 306 if primtype == "BLIT_OP_SCALE" then 307 handle_blit() 308 return 309 elseif primtype == "EVENT:BLIT" then 310 return 311 end 312 313 local m = tostring(mode) 314 315 -- detect changes in drawmode which indicate a different 316 -- pass.. BINNING->GMEM means same pass, but other 317 -- transitions mean different pass: 318 if drawmode and m ~= drawmode then 319 dbg("%s -> %s transition\n", drawmode, m) 320 if not valid_transition(drawmode, m) then 321 dbg("invalid transition, new render pass!\n") 322 finish() 323 reset() 324 end 325 end 326 327 if m ~= "RM6_GMEM" and m ~= "RM6_BYPASS" then 328 if m == "RM6_BINNING" then 329 drawmode = m 330 return 331 end 332 if m == "RM6_RESOLVE" and primtype == "EVENT:BLIT" then 333 return 334 end 335 printf("unknown MODE %s for primtype %s\n", m, primtype) 336 return 337 end 338 339 -- Only count the first tile for GMEM mode to avoid counting 340 -- each draw for each tile 341 if m == "RM6_GMEM" then 342 if r.RB_WINDOW_OFFSET.X ~= 0 or r.RB_WINDOW_OFFSET.Y ~= 0 then 343 return 344 end 345 end 346 347 drawmode = m 348 local render_components = {} 349 render_components[0] = r.RB_RENDER_COMPONENTS.RT0; 350 render_components[1] = r.RB_RENDER_COMPONENTS.RT1; 351 render_components[2] = r.RB_RENDER_COMPONENTS.RT2; 352 render_components[3] = r.RB_RENDER_COMPONENTS.RT3; 353 render_components[4] = r.RB_RENDER_COMPONENTS.RT4; 354 render_components[5] = r.RB_RENDER_COMPONENTS.RT5; 355 render_components[6] = r.RB_RENDER_COMPONENTS.RT6; 356 render_components[7] = r.RB_RENDER_COMPONENTS.RT7; 357 for n = 0,r.RB_FS_OUTPUT_CNTL1.MRT-1 do 358 if render_components[n] ~= 0 then 359 push_mrt(r.RB_MRT[n].BUF_INFO.COLOR_FORMAT, 360 r.GRAS_SC_SCREEN_SCISSOR[0].BR.X + 1, 361 r.GRAS_SC_SCREEN_SCISSOR[0].BR.Y + 1, 362 r.RB_MSAA_CNTL.SAMPLES, 363 r.RB_MRT[n].BASE, 364 r.RB_MRT_FLAG_BUFFER[n].ADDR, 365 r.RB_MRT[n].BASE_GMEM) 366 end 367 end 368 369 local depthbase = r.RB_DEPTH_BUFFER_BASE 370 371 if depthbase ~= 0 then 372 push_mrt(r.RB_DEPTH_BUFFER_INFO.DEPTH_FORMAT, 373 r.GRAS_SC_SCREEN_SCISSOR[0].BR.X + 1, 374 r.GRAS_SC_SCREEN_SCISSOR[0].BR.Y + 1, 375 r.RB_MSAA_CNTL.SAMPLES, 376 depthbase, 377 r.RB_DEPTH_FLAG_BUFFER_BASE, 378 r.RB_DEPTH_BUFFER_BASE_GMEM) 379 end 380 381 if r.RB_DEPTH_CNTL.Z_WRITE_ENABLE then 382 depthwrite = true 383 end 384 385 if r.RB_DEPTH_CNTL.Z_TEST_ENABLE then 386 depthtest = true 387 end 388 389 -- clearly 0 != false.. :-/ 390 if r.RB_STENCILWRMASK.WRMASK ~= 0 then 391 stencilwrite = true 392 end 393 394 if r.RB_STENCIL_CONTROL.STENCIL_ENABLE then 395 stenciltest = true 396 end 397 398 -- TODO should also check for stencil buffer for z32+s8 case 399 400 if m == "RM6_GMEM" then 401 binw = r.VSC_BIN_SIZE.WIDTH 402 binh = r.VSC_BIN_SIZE.HEIGHT 403 nbins = r.VSC_BIN_COUNT.NX * r.VSC_BIN_COUNT.NY 404 end 405 406 draws = draws + 1 407end 408 409