panwrap-decoder.c 29.1 KB
Newer Older
1
/*
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
2
 * © Copyright 2017-2018 The Panfrost Community
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */

#include "panwrap.h"
#include <mali-ioctl.h>
#include <mali-job.h>
18
#include <stdio.h>
19
#include <memory.h>
20

21 22
#include "panwrap-shader.h"

23 24
#define MEMORY_PROP(obj, p) {\
	char *a = pointer_as_memory_reference(obj->p); \
25 26 27 28
	panwrap_prop("%s = %s", #p, a); \
	free(a); \
}

29 30 31 32 33
#define DYN_MEMORY_PROP(obj, no, p) { \
	if (obj->p) \
		panwrap_prop("%s = %s_%d_p", #p, #p, no); \
}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
34 35
#define FLAG_INFO(flag) { MALI_GL_##flag, "MALI_GL_" #flag }
static const struct panwrap_flag_info gl_enable_flag_info[] = {
36 37
	FLAG_INFO(CULL_FACE_FRONT),
	FLAG_INFO(CULL_FACE_BACK),
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
38 39 40 41
	{}
};
#undef FLAG_INFO

42 43 44 45 46 47 48 49 50
#define FLAG_INFO(flag) { MALI_CLEAR_##flag, "MALI_CLEAR_" #flag }
static const struct panwrap_flag_info clear_flag_info[] = {
	FLAG_INFO(FAST),
	FLAG_INFO(SLOW),
	FLAG_INFO(SLOW_STENCIL),
	{}
};
#undef FLAG_INFO

51 52
#define FLAG_INFO(flag) { MALI_##flag, "MALI_" #flag }
static const struct panwrap_flag_info u3_flag_info[] = {
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
53
	FLAG_INFO(HAS_MSAA),
54 55 56 57
	FLAG_INFO(CAN_DISCARD),
	FLAG_INFO(HAS_BLEND_SHADER),
	{}
};
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
58 59 60

static const struct panwrap_flag_info u4_flag_info[] = {
	FLAG_INFO(NO_MSAA),
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
61
	FLAG_INFO(STENCIL_TEST),
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
62 63
	{}
};
64
#undef FLAG_INFO
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
65

66 67 68 69 70 71 72
#define FLAG_INFO(flag) { MALI_FRAMEBUFFER_##flag, "MALI_FRAMEBUFFER_" #flag }
static const struct panwrap_flag_info u2_flag_info[] = {
	FLAG_INFO(MSAA_A),
	FLAG_INFO(MSAA_B),
	FLAG_INFO(MSAA_8),
	{}
};
73
#undef FLAG_INFO
74

75 76
extern char* replace_fragment;
extern char* replace_vertex;
77 78 79

static char *panwrap_job_type_name(enum mali_job_type type)
{
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
80
#define DEFINE_CASE(name) case JOB_TYPE_ ## name: return "JOB_TYPE_" #name
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	switch (type) {
	DEFINE_CASE(NULL);
	DEFINE_CASE(SET_VALUE);
	DEFINE_CASE(CACHE_FLUSH);
	DEFINE_CASE(COMPUTE);
	DEFINE_CASE(VERTEX);
	DEFINE_CASE(TILER);
	DEFINE_CASE(FUSED);
	DEFINE_CASE(FRAGMENT);
	case JOB_NOT_STARTED:
		return "NOT_STARTED";
	default:
		panwrap_log("Warning! Unknown job type %x\n", type);
		return "!?!?!?";
	}
#undef DEFINE_CASE
}

static char *panwrap_gl_mode_name(enum mali_gl_mode mode)
{
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
101
#define DEFINE_CASE(name) case MALI_ ## name: return "MALI_" #name
102 103 104 105 106 107
	switch(mode) {
	DEFINE_CASE(GL_POINTS);
	DEFINE_CASE(GL_LINES);
	DEFINE_CASE(GL_TRIANGLES);
	DEFINE_CASE(GL_TRIANGLE_STRIP);
	DEFINE_CASE(GL_TRIANGLE_FAN);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
108 109
	DEFINE_CASE(GL_LINE_STRIP);
	DEFINE_CASE(GL_LINE_LOOP);
110 111 112 113 114
	default: return "MALI_GL_TRIANGLES /* XXX: Unknown GL mode, check dump */";
	}
#undef DEFINE_CASE
}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
static char *panwrap_stencil_func_name(enum mali_stencil_func mode)
{
#define DEFINE_CASE(name) case MALI_STENCIL_ ## name: return "MALI_STENCIL_" #name
	switch(mode) {
	DEFINE_CASE(NEVER);
	DEFINE_CASE(LESS);
	DEFINE_CASE(EQUAL);
	DEFINE_CASE(LEQUAL);
	DEFINE_CASE(GREATER);
	DEFINE_CASE(NOTEQUAL);
	DEFINE_CASE(GEQUAL);
	DEFINE_CASE(ALWAYS);
	default: return "MALI_STENCIL_NEVER /* XXX: Unknown stencil function, check dump */";
	}
#undef DEFINE_CASE
}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
132 133 134 135 136 137 138 139 140 141
static void panwrap_property_u32_list(const char *name, const u32 *lst, size_t c)
{
	panwrap_log(".%s = { ", name);
	panwrap_indent++;
	for (int i = 0; i < c; ++i)
		panwrap_log_cont("0x%" PRIx32 ", ", lst[i]);
	panwrap_indent--;
	panwrap_log_cont("},\n");
}

142 143 144 145 146 147 148
static inline char *panwrap_decode_fbd_type(enum mali_fbd_type type)
{
	if (type == MALI_SFBD)      return "SFBD";
	else if (type == MALI_MFBD) return "MFBD";
	else return "WTF!?";
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162
static bool
panwrap_deduplicate(struct panwrap_mapped_memory *mem, uint64_t gpu_va, const char *name, int number)
{
	if (mem->touched[(gpu_va - mem->gpu_va) / sizeof(uint32_t)]) {
		/* XXX: Is this correct? */
		panwrap_log("mali_ptr %s_%d_p = %s_%d_p;\n", name, number, name, number - 1);
		return true;
	}

	return false;
}

static void
panwrap_replay_sfbd(uint64_t gpu_va, int job_no)
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
163
{
164
	struct panwrap_mapped_memory *mem = panwrap_find_mapped_gpu_mem_containing(gpu_va);
165
	const struct mali_single_framebuffer *PANWRAP_PTR_VAR(s, mem, (mali_ptr) gpu_va);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
166

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
167
	/* FBDs are frequently duplicated, so watch for this */
168
	if (panwrap_deduplicate(mem, gpu_va, "framebuffer", job_no)) return;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
169

170
	panwrap_log("struct mali_single_framebuffer framebuffer_%d = {\n", job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
171 172 173 174 175
	panwrap_indent++;

	panwrap_prop("unknown1 = 0x%" PRIx32, s->unknown1);
	panwrap_prop("flags = 0x%" PRIx32, s->flags);
	panwrap_prop("heap_free_address = 0x%" PRIx64, s->heap_free_address);
176 177 178 179

	panwrap_log(".unknown2 = ");
	panwrap_log_decoded_flags(u2_flag_info, s->unknown2);
	panwrap_log_cont(",\n");
180

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
181 182
	panwrap_prop("width = MALI_POSITIVE(%" PRId16 ")", s->width + 1);
	panwrap_prop("height = MALI_POSITIVE(%" PRId16 ")", s->height + 1);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
183 184 185

	panwrap_property_u32_list("weights", s->weights, MALI_FBD_HIERARCHY_WEIGHTS);

186 187 188 189 190 191 192
	/* Earlier in the actual commandstream -- right before width -- but we
	 * delay to flow nicer */

	panwrap_log(".clear_flags = ");
	panwrap_log_decoded_flags(clear_flag_info, s->clear_flags);
	panwrap_log_cont(",\n");

193 194 195 196
	if (s->depth_buffer | s->depth_buffer_enable) {
		panwrap_prop("depth_buffer = " MALI_PTR_FMT, s->depth_buffer);
		panwrap_prop("depth_buffer_enable = %s", DS_ENABLE(s->depth_buffer_enable));
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
197

198 199 200 201
	if (s->stencil_buffer | s->stencil_buffer_enable) {
		panwrap_prop("stencil_buffer = " MALI_PTR_FMT, s->depth_buffer);
		panwrap_prop("stencil_buffer_enable = %s", DS_ENABLE(s->stencil_buffer_enable));
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
202

203 204 205 206 207 208
	if (s->clear_color_1 | s->clear_color_2 | s->clear_color_3 | s->clear_color_4) {
		panwrap_prop("clear_color_1 = 0x%" PRIx32, s->clear_color_1);
		panwrap_prop("clear_color_2 = 0x%" PRIx32, s->clear_color_2);
		panwrap_prop("clear_color_3 = 0x%" PRIx32, s->clear_color_3);
		panwrap_prop("clear_color_4 = 0x%" PRIx32, s->clear_color_4);
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
209

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
210
	if (s->clear_depth_1 != 0 || s->clear_depth_2 != 0 || s->clear_depth_3 != 0 || s->clear_depth_4 != 0) {
211 212 213 214 215
		panwrap_prop("clear_depth_1 = %f", s->clear_depth_1);
		panwrap_prop("clear_depth_2 = %f", s->clear_depth_2);
		panwrap_prop("clear_depth_3 = %f", s->clear_depth_3);
		panwrap_prop("clear_depth_4 = %f", s->clear_depth_4);
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
216

217 218 219
	if (s->clear_stencil) {
		panwrap_prop("clear_stencil = 0x%x", s->clear_stencil);
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
220

221 222 223
	MEMORY_PROP(s, unknown_address_0);
	MEMORY_PROP(s, unknown_address_1);
	MEMORY_PROP(s, unknown_address_2);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
224 225 226 227

	panwrap_prop("unknown8 = 0x%" PRIx32, s->unknown8);
	panwrap_prop("unknown9 = 0x%" PRIx32, s->unknown9);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
228
	panwrap_prop("tiler_jc_list = 0x%" PRIx64, s->tiler_jc_list);
229 230

	MEMORY_PROP(s, unknown_address_4);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
231 232 233 234 235 236 237 238 239 240 241 242 243

	panwrap_indent--;
	panwrap_log("};\n");

	int zero_sum_pun = 0;
	zero_sum_pun += s->zero1;
	zero_sum_pun += s->zero2;
	for (int i = 0; i < sizeof(s->zero3)/sizeof(s->zero3[0]); ++i) zero_sum_pun += s->zero3[i];
	for (int i = 0; i < sizeof(s->zero6)/sizeof(s->zero6[0]); ++i) zero_sum_pun += s->zero6[i];

	if (zero_sum_pun)
		panwrap_msg("Zero sum tripped (%d), replay may be wrong\n", zero_sum_pun);

244
	TOUCH(mem, (mali_ptr) gpu_va, *s, "framebuffer", job_no, true);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
245 246
}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
247
void panwrap_replay_attributes(const struct panwrap_mapped_memory *mem,
248
			       mali_ptr addr, int job_no, int count, bool varying)
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
249
{
250
	char *prefix = varying ? "varyings" : "attributes";
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
251

252 253
	/* Varyings in particular get duplicated between parts of the job */
	if (panwrap_deduplicate(mem, addr, prefix, job_no)) return;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
254

255
	struct mali_attr *attr = panwrap_fetch_gpu_mem(mem, addr, sizeof(struct mali_attr) * count); 
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
256

257 258
	char base[128];
	snprintf(base, sizeof(base), "%s_data_%d", prefix, job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
259

260 261
	for (int i = 0; i < count; ++i) {
		mali_ptr raw_elements = attr[i].elements & ~3;
262

263 264
		size_t vertex_count;
		size_t component_count;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
265

266 267 268
		if (!varying) {
			/* TODO: Attributes are not necessarily float32 vectors in general;
			 * decoding like this without snarfing types from the shader is unsafe all things considered */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
269

270
			float *buffer = panwrap_fetch_gpu_mem(mem, raw_elements, attr[i].size);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
271

272 273
			vertex_count = attr[i].size / attr[i].stride;
			component_count = attr[i].stride / sizeof(float);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
274

275
			panwrap_log("float %s_%d[] = {\n", base, i);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
276

277 278 279
			panwrap_indent++;
			for (int row = 0; row < vertex_count; row++) {
				panwrap_log_empty();
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
280

281 282
				for (int i = 0; i < component_count; i++)
					panwrap_log_cont("%ff, ", buffer[i]);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
283

284 285 286 287 288 289
				panwrap_log_cont("\n");

				buffer += component_count;
			}
			panwrap_indent--;
			panwrap_log("};\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
290

291
			TOUCH_LEN(mem, raw_elements, attr[i].size, base, i, true);
292 293 294 295 296 297 298
		} else {
			/* TODO: Allocate space for varyings dynamically? */

			char *a = pointer_as_memory_reference(raw_elements);
			panwrap_log("mali_ptr %s_%d_p = %s;\n", base, i, a);
			free(a);
		}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
299
	}
300

301
	panwrap_log("struct mali_attr %s_%d[] = {\n", prefix, job_no);
302 303
	panwrap_indent++;

304 305 306 307 308 309 310 311 312 313 314
	for (int i = 0; i < count; ++i) {
		panwrap_log("{\n");
		panwrap_indent++;

		int flags = attr[i].elements & 3;
		panwrap_prop("elements = (%s_%d_p) | %d", base, i, attr[i].elements & 3);

		panwrap_prop("stride = 0x%" PRIx32, attr[i].stride);
		panwrap_prop("size = 0x%" PRIx32, attr[i].size);
		panwrap_indent--;
		panwrap_log("}, \n");
315 316 317 318 319
	}

	panwrap_indent--;
	panwrap_log("};\n");

320
	TOUCH_LEN(mem, addr, sizeof(*attr) * count, prefix, job_no, true);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
321 322
}

323 324 325 326 327 328 329 330 331 332 333 334 335
static mali_ptr
panwrap_replay_shader_address(const char *name, mali_ptr ptr)
{
	/* TODO: Decode flags */
	mali_ptr shader_ptr = ptr & ~15;

	char *a = pointer_as_memory_reference(shader_ptr);
	panwrap_prop("%s = (%s) | %d", name, a, (int) (ptr & 15));
	free(a);

	return shader_ptr;
}

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
static void
panwrap_replay_stencil(const char *name, u32 raw)
{
	uint8_t ref 	= raw & 0xFF;
	uint8_t mask 	= (raw >> 8) & 0xFF;
	uint8_t func	= (raw >> 16) & 0x7;

	uint8_t f1	= (raw >> 19) & 0x7;
	uint8_t f2	= (raw >> 22) & 0x7;
	uint8_t f3	= (raw >> 25) & 0x7;

	const char *func_str = panwrap_stencil_func_name(func);

	panwrap_prop("stencil_%s = MAKE_STENCIL_TEST(%s, 0x%02X, %d) /* %d,%d,%d */", name, func_str, mask, ref, f1, f2, f3);
}

352 353
static int
panwrap_replay_vertex_or_tiler_job(const struct mali_job_descriptor_header *h,
354 355 356 357 358 359
					const struct panwrap_mapped_memory *mem,
					mali_ptr payload, int job_no)
{
	struct mali_payload_vertex_tiler *PANWRAP_PTR_VAR(v, mem, payload);
	struct mali_shader_meta *meta;
	struct panwrap_mapped_memory *attr_mem;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
360
	mali_ptr shader_meta_ptr = (u64) (uintptr_t) (v->_shader_upper << 4);
361

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
362
	/* TODO: Isn't this an -M-FBD? What's the difference? */
363
	panwrap_replay_sfbd((u64) (uintptr_t) v->framebuffer, job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
364

365
	int varying_count, attribute_count, uniform_count;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
366

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
367 368 369 370 371 372 373
	if (shader_meta_ptr) {
		struct panwrap_mapped_memory *smem = panwrap_find_mapped_gpu_mem_containing(shader_meta_ptr);
		struct mali_shader_meta *PANWRAP_PTR_VAR(s, smem, shader_meta_ptr);

		panwrap_log("struct mali_shader_meta shader_meta_%d = {\n", job_no);
		panwrap_indent++;

374
		mali_ptr shader_ptr = panwrap_replay_shader_address("shader", s->shader);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
375

376 377
		if (s->zero1)
			panwrap_msg("XXX shader zero tripped\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
378

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
379
		panwrap_prop("attribute_count = %" PRId16, s->attribute_count);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
380
		panwrap_prop("varying_count = %" PRId16, s->varying_count);
381 382 383 384
		panwrap_prop("uniform_count = %" PRId16, s->uniform_count);
		panwrap_prop("work_count = %" PRId16, s->work_count);
		panwrap_prop("unknown1 = 0x%" PRIx32, s->unknown1);
		panwrap_prop("unknown2 = 0x%" PRIx32, s->unknown2);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
385

386 387
		/* Save for dumps */
		attribute_count = s->attribute_count;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
388
		varying_count = s->varying_count;
389
		uniform_count = s->uniform_count; 
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
390

391 392 393
		/* WTF? All zero for vertex shaders; block of assorted, largely
		 * unknown fields for fragment shaders. Let's figure it out,
		 * girls :) */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
394

395 396 397 398
		if (s->depth_units || s->depth_factor) {
			panwrap_prop("depth_units = MALI_NEGATIVE(%f)", s->depth_units - 1.0f);
			panwrap_prop("depth_factor = %f", s->depth_factor);
		}
399 400 401 402

		panwrap_log(".unknown2_3 = ");
		panwrap_log_decoded_flags(u3_flag_info, s->unknown2_3);
		panwrap_log_cont(",\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
403

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
404 405 406 407
		panwrap_log(".unknown2_4 = ");
		panwrap_log_decoded_flags(u4_flag_info, s->unknown2_4);
		panwrap_log_cont(",\n");

408 409
		if (s->stencil_front)
			panwrap_replay_stencil("front", s->stencil_front);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
410

411 412
		if (s->stencil_back)
			panwrap_replay_stencil("back", s->stencil_back);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
413

414 415
		panwrap_prop("unknown2_7 = 0x%" PRIx32, s->unknown2_7);
		panwrap_prop("unknown2_8 = 0x%" PRIx32, s->unknown2_8);
416 417 418 419

		if (s->unknown2_3 & MALI_HAS_BLEND_SHADER) {
			panwrap_replay_shader_address("blend_shader", s->blend_shader);
		} else {
420
			panwrap_prop("blend_equation = 0x%" PRIx64, s->blend_equation);
421
		}
422

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
423 424
		panwrap_indent--;
		panwrap_log("};\n");
425
		TOUCH(smem, shader_meta_ptr, *meta, "shader_meta", job_no, false);
426

427
		panwrap_shader_disassemble(shader_ptr, job_no, h->job_type);
428

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
429 430
	} else
		panwrap_msg("<no shader>\n");
431
	
432 433 434
	if (v->viewport) {
		struct panwrap_mapped_memory *fmem = panwrap_find_mapped_gpu_mem_containing(v->viewport);
		struct mali_viewport *PANWRAP_PTR_VAR(f, fmem, v->viewport);
435

436
		panwrap_log("struct mali_viewport viewport_%d = {\n", job_no);
437
		panwrap_indent++;
438
		panwrap_log(".floats = {\n");
439 440 441 442 443 444
		panwrap_indent++;

		for (int i = 0; i < sizeof(f->floats) / sizeof(f->floats[0]); i += 2)
			panwrap_log("%ff, %ff,\n", f->floats[i], f->floats[i + 1]);

		panwrap_indent--;
445
		panwrap_log("},\n");
446 447 448 449 450 451 452 453 454

		/* Only the higher coordinates are MALI_POSITIVE scaled */

		panwrap_prop("viewport0 = { %d, %d }",
				f->viewport0[0], f->viewport0[1]);

		panwrap_prop("viewport1 = { MALI_POSITIVE(%d), MALI_POSITIVE(%d) }",
				f->viewport1[0] + 1, f->viewport1[1] + 1);

455 456 457
		panwrap_indent--;
		panwrap_log("};\n");

458
		TOUCH(fmem, v->viewport, *f, "viewport", job_no, true);
459
	}
460 461

	if (v->attribute_meta) {
462
		panwrap_log("struct mali_attr_meta attribute_meta_%d[] = {\n", job_no);
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
		panwrap_indent++;

		size_t count = 0;

		struct mali_attr_meta *attr_meta;
		mali_ptr p;

		attr_mem = panwrap_find_mapped_gpu_mem_containing(v->attribute_meta);

		for (p = v->attribute_meta;
		     *PANWRAP_PTR(attr_mem, p, u64) != 0;
		     p += sizeof(struct mali_attr_meta), count++) {
			attr_meta = panwrap_fetch_gpu_mem(attr_mem, p,
							  sizeof(*attr_mem));

			panwrap_log("{ .index = %d, .flags = 0x%" PRIx64 "},\n",
479
					attr_meta->index, (u64) attr_meta->flags);
480 481 482 483 484
		}

		panwrap_indent--;
		panwrap_log("};\n");

485
		TOUCH_LEN(attr_mem, v->attribute_meta, sizeof(struct mali_attr_meta) * count, "attribute_meta", job_no, true);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
486 487 488

		attr_mem = panwrap_find_mapped_gpu_mem_containing(v->attributes);

489
		panwrap_replay_attributes( attr_mem, v->attributes, job_no, attribute_count, false);
490
	}
491

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
492 493 494 495 496 497
	/* Varyings are encoded like attributes but not actually sent; we just
	 * pass a zero buffer with the right stride/size set, (or whatever)
	 * since the GPU will write to it itself */

	if (v->varyings) {
		attr_mem = panwrap_find_mapped_gpu_mem_containing(v->varyings);
498

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
499 500
		/* Number of descriptors depends on whether there are
		 * non-internal varyings */
501

502
		panwrap_replay_attributes(attr_mem, v->varyings, job_no, varying_count > 1 ? 2 : 1, true);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
503 504
	}

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
505 506 507
	/* XXX: This entire block is such a hack... where are uniforms configured exactly? */

	if (v->uniforms) {
508
		int rows = uniform_count, width = 4;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
509 510 511 512 513 514 515 516 517 518
		size_t sz = rows * width * sizeof(float);

		struct panwrap_mapped_memory *uniform_mem = panwrap_find_mapped_gpu_mem_containing(v->uniforms);
		panwrap_fetch_gpu_mem(uniform_mem, v->uniforms, sz);
		float *PANWRAP_PTR_VAR(uniforms, uniform_mem, v->uniforms);

		panwrap_log("float uniforms_%d[] = {\n", job_no);

		panwrap_indent++;
		for (int row = 0; row < rows; row++) {
519
			panwrap_log_empty();
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
520 521 522 523 524 525 526 527 528 529 530

			for (int i = 0; i < width; i++)
				panwrap_log_cont("%ff, ", uniforms[i]);

			panwrap_log_cont("\n");

			uniforms += width;
		}
		panwrap_indent--;
		panwrap_log("};\n");

531
		TOUCH_LEN(mem, v->uniforms, sz, "uniforms", job_no, true);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
532 533
	}

534 535 536 537 538 539 540 541 542
	if (v->unknown1) {
		struct panwrap_mapped_memory *umem = panwrap_find_mapped_gpu_mem_containing(v->unknown1);

		if (umem) {
			u64 *PANWRAP_PTR_VAR(u, umem, v->unknown1);

			mali_ptr ptr = *u >> 8;
			uint8_t flags = *u & 0xFF;

543 544 545 546 547
			/* Points to... a buffer of zeroes in the same region?
			 * *shrug* Deliberate 0 length so we don't memset
			 * anything out */
			
			panwrap_log("u32 inner_unknown1_%d = 0; /* XXX */\n", job_no);
548
			TOUCH_LEN(umem, ptr, 0, "inner_unknown1", job_no, true);
549 550

			panwrap_log("u64 unknown1_%d = ((inner_unknown1_%d_p) << 8) | %d;\n", job_no, job_no, flags);
551
			TOUCH(umem, v->unknown1, u64, "unknown1", job_no, true);
552 553
		}
	}
554 555 556 557 558

	if (v->unknown6) {
		struct panwrap_mapped_memory *umem = panwrap_find_mapped_gpu_mem_containing(v->unknown6);

		if (umem) {
559
			struct mali_unknown6 *PANWRAP_PTR_VAR(u, umem, v->unknown6 & ~0xF);
560 561 562 563 564 565 566 567 568 569 570

			panwrap_log("struct mali_unknown6 unknown6_%d = {\n", job_no);
			panwrap_indent++;

			panwrap_prop("unknown0 = 0x%" PRIx64, u->unknown0);
			panwrap_prop("unknown1 = 0x%" PRIx64, u->unknown1);


			panwrap_indent--;
			panwrap_log("};\n");

571
			TOUCH(umem, v->unknown6 & ~0xF, *u, "unknown6", job_no, true);
572 573
		}
	}
574

575 576
	/* Just a pointer to... another pointer >_< */

577 578
	if (v->texture_trampoline) {
		struct panwrap_mapped_memory *mmem = panwrap_find_mapped_gpu_mem_containing(v->texture_trampoline);
579 580

		if (mmem) {
581
			mali_ptr *PANWRAP_PTR_VAR(u, mmem, v->texture_trampoline);
582 583

			char *a = pointer_as_memory_reference(*u);
584
			panwrap_log("uint64_t texture_trampoline_%d = %s;", job_no, a);
585 586
			free(a);

587
			TOUCH(mmem, v->texture_trampoline, *u, "texture_trampoline", job_no, true);
588 589 590 591 592 593 594 595 596 597

			/* Now, finally, descend down into the texture descriptor */
			struct panwrap_mapped_memory *tmem = panwrap_find_mapped_gpu_mem_containing(*u);

			if (tmem) {
				struct mali_texture_descriptor *PANWRAP_PTR_VAR(t, tmem, *u);

				panwrap_log("struct mali_texture_descriptor texture_descriptor_%d = {\n", job_no);
				panwrap_indent++;

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
598 599
				panwrap_prop("width = MALI_POSITIVE(%" PRId16 ")", t->width + 1);
				panwrap_prop("height = MALI_POSITIVE(%" PRId16 ")", t->height + 1);
600

601
				panwrap_prop("unknown1 = 0x%" PRIx32, t->unknown1);
602
				
603 604 605
				/* TODO: I don't understand how these work at all yet */
				panwrap_prop("format1 = 0x%" PRIx32, t->format1);
				panwrap_prop("format2 = 0x%" PRIx32, t->format2);
606

607
				panwrap_prop("unknown3 = 0x%" PRIx32, t->unknown3);
608

609 610 611
				panwrap_prop("unknown5 = 0x%" PRIx32, t->unknown5);
				panwrap_prop("unknown6 = 0x%" PRIx32, t->unknown6);
				panwrap_prop("unknown7 = 0x%" PRIx32, t->unknown7);
612 613 614

				MEMORY_PROP(t, swizzled_bitmap_0);
				MEMORY_PROP(t, swizzled_bitmap_1);
615 616 617 618

				panwrap_indent--;
				panwrap_log("};\n");

619
				TOUCH(tmem, *u, *t, "texture_descriptor", job_no, false);
620
			}
621 622 623
		}
	}

624 625 626 627 628 629 630 631 632
	if (v->sampler_descriptor) {
		struct panwrap_mapped_memory *smem = panwrap_find_mapped_gpu_mem_containing(v->sampler_descriptor);

		if (smem) {
			struct mali_sampler_descriptor *PANWRAP_PTR_VAR(s, smem, v->sampler_descriptor);

			panwrap_log("struct mali_sampler_descriptor sampler_descriptor_%d = {\n", job_no);
			panwrap_indent++;

633
			/* Only the lower two bits are understood right now; the rest we display as hex */
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
634
			panwrap_log(".filter_mode = MALI_GL_TEX_MIN(%s) | MALI_GL_TEX_MAG(%s) | 0x%" PRIx32",\n",
635 636 637
				       	MALI_FILTER_NAME(s->filter_mode & MALI_GL_TEX_MIN_MASK),
				       	MALI_FILTER_NAME(s->filter_mode & MALI_GL_TEX_MAG_MASK),
					s->filter_mode & ~3);
638 639 640 641 642 643 644

			panwrap_prop("unknown1 = 0x%" PRIx32, s->unknown1);
			panwrap_prop("unknown2 = 0x%" PRIx32, s->unknown2);

			panwrap_indent--;
			panwrap_log("};\n");

645
			TOUCH(smem, v->sampler_descriptor, *s, "sampler_descriptor", job_no, false);
646 647
		}
	}
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668

	if (v->indices) {
		struct panwrap_mapped_memory *imem = panwrap_find_mapped_gpu_mem_containing(v->indices);

		if (imem) {
			/* Indices are literally just a u32 array :) */

			uint32_t *PANWRAP_PTR_VAR(indices, imem, v->indices);

			panwrap_log("uint32_t indices_%d[] = {\n", job_no);
			panwrap_indent++;

			for(int i = 0; i < (v->index_count + 1); i += 3)
				panwrap_log("%d, %d, %d,\n",
						indices[i],
						indices[i + 1],
						indices[i + 2]);

			panwrap_indent--;
			panwrap_log("};\n");

669
			TOUCH_LEN(imem, v->indices, sizeof(uint32_t) * (v->index_count + 1), "indices", job_no, false);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
670 671
		}
	}
672 673


674
	panwrap_log("struct mali_payload_vertex_tiler payload_%d = {\n", job_no);
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
	panwrap_indent++;

	panwrap_prop("line_width = %ff", v->line_width);
	panwrap_prop("vertex_count = MALI_POSITIVE(%" PRId32 ")", v->vertex_count + 1);
	panwrap_prop("unk1 = 0x%" PRIx32, v->unk1);

	if (h->job_type == JOB_TYPE_TILER) {
		panwrap_prop("draw_mode = 0x%" PRIx32 " | %s", v->draw_mode & ~(0xF), panwrap_gl_mode_name(v->draw_mode & 0xF));
	} else {
		panwrap_prop("draw_mode = 0x%" PRIx32, v->draw_mode);
	}

	/* Index count only exists for tiler jobs anyway */ 

	if (v->index_count)
		panwrap_prop("index_count = MALI_POSITIVE(%" PRId32 ")", v->index_count + 1);

	uint32_t remaining_gl_enables = v->gl_enables;

	panwrap_log(".gl_enables = ");
	
	if (h->job_type == JOB_TYPE_TILER) {
		panwrap_log_cont("MALI_GL_FRONT_FACE(MALI_GL_%s) | ",
		    v->gl_enables & MALI_GL_FRONT_FACE(MALI_GL_CW) ? "CW" : "CCW");

		remaining_gl_enables &= ~(MALI_GL_FRONT_FACE(1));
	}

	panwrap_log_decoded_flags(gl_enable_flag_info, remaining_gl_enables);

	panwrap_log_cont(",\n");

	if (h->job_type == JOB_TYPE_VERTEX && v->index_count)
		panwrap_msg("Warning: index count set in vertex job\n");

	if (v->zero0 | v->zero1 | v->zero3 | v->zero4 | v->zero5 | v->zero6) {
		panwrap_msg("Zero tripped, replay may be wrong\n");
		panwrap_prop("zero0 = 0x%" PRIx32, v->zero0);
		panwrap_prop("zero1 = 0x%" PRIx32, v->zero1);
		panwrap_prop("zero3 = 0x%" PRIx32, v->zero3);
		panwrap_prop("zero4 = 0x%" PRIx32, v->zero4);
		panwrap_prop("zero5 = 0x%" PRIx32, v->zero5);
		panwrap_prop("zero6 = 0x%" PRIx32, v->zero6);
	}

720
	DYN_MEMORY_PROP(v, job_no, indices);
721
	//DYN_MEMORY_PROP(v, job_no, unknown0);
722
	DYN_MEMORY_PROP(v, job_no, unknown1); 
723
	DYN_MEMORY_PROP(v, job_no, texture_trampoline);
724
	DYN_MEMORY_PROP(v, job_no, sampler_descriptor);
725 726 727 728
	DYN_MEMORY_PROP(v, job_no, uniforms);
	DYN_MEMORY_PROP(v, job_no, attributes); 
	DYN_MEMORY_PROP(v, job_no, attribute_meta); 
	DYN_MEMORY_PROP(v, job_no, varyings); 
729
	//DYN_MEMORY_PROP(v, job_no, unknown6);
730
	DYN_MEMORY_PROP(v, job_no, viewport);
731
	DYN_MEMORY_PROP(v, job_no, framebuffer);
732

733
	MEMORY_PROP(v, unknown0);
734

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
735
	panwrap_prop("_shader_upper = (shader_meta_%d_p) >> 4", job_no);
736 737
	panwrap_prop("flags = %d", v->flags); 

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
738 739
	if (v->unknown6)
		panwrap_prop("unknown6 = (unknown6_%d_p) | 0x%X", job_no, v->unknown6 & 0xF);
740

741 742 743
	panwrap_indent--;
	panwrap_log("};\n");

744
	return sizeof(*v);
745 746
}

747
static int panwrap_replay_fragment_job(const struct panwrap_mapped_memory *mem,
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
748 749 750 751
					mali_ptr payload, int job_no)
{
	const struct mali_payload_fragment *PANWRAP_PTR_VAR(s, mem, payload);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
752 753
	bool fbd_dumped = false;

754
	if ((s->framebuffer & FBD_TYPE) == MALI_SFBD) {
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
755 756 757 758 759 760 761 762
		/* Only SFBDs are understood, not MFBDs. We're speculating,
		 * based on the versioning, kernel code, etc, that the
		 * difference is between Single FrameBuffer Descriptor and
		 * Multiple FrmaeBuffer Descriptor; the change apparently lines
		 * up with multi-framebuffer support being added (T7xx onwards,
		 * including Gxx). In any event, there's some field shuffling
		 * that we haven't looked into yet. */

763
		panwrap_replay_sfbd(s->framebuffer & FBD_MASK, job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
764 765 766
		fbd_dumped = true;
	}

767
	uintptr_t p = (uintptr_t) s->framebuffer & FBD_MASK;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
768

769
	panwrap_log("struct mali_payload_fragment payload_%d = {\n", job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
770
	panwrap_indent++;
771

772 773 774
	if (s->zero)
		panwrap_msg("ZT\n");

775 776 777
	/* See the comments by the macro definitions for mathematical context
	 * on why this is so weird */

778 779 780 781 782 783 784 785 786
	panwrap_prop("min_tile_coord = MALI_COORDINATE_TO_TILE_MIN(%d, %d, %d)",
			MALI_TILE_COORD_X(s->min_tile_coord) << MALI_TILE_SHIFT,
			MALI_TILE_COORD_Y(s->min_tile_coord) << MALI_TILE_SHIFT,
			MALI_TILE_COORD_FLAGS(s->min_tile_coord));

	panwrap_prop("max_tile_coord = MALI_COORDINATE_TO_TILE_MAX(%d, %d, %d)",
			(MALI_TILE_COORD_X(s->max_tile_coord) + 1) << MALI_TILE_SHIFT,
			(MALI_TILE_COORD_Y(s->max_tile_coord) + 1) << MALI_TILE_SHIFT,
			MALI_TILE_COORD_FLAGS(s->max_tile_coord));
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
787

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
788 789 790
	/* If the FBD was just decoded, we can refer to it by pointer. If not,
	 * we have to fallback on offsets. */

791
	const char *fbd_type = s->framebuffer & MALI_MFBD ? "MALI_MFBD" : "MALI_SFBD";
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
792 793

	if (fbd_dumped)
794
		panwrap_prop("framebuffer = framebuffer_%d_p | %s", job_no, fbd_type);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
795
	else
796
		panwrap_prop("framebuffer = %s | %s", pointer_as_memory_reference(p), fbd_type);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
797

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
798 799
	panwrap_indent--;
	panwrap_log("};\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
800

801
	return sizeof(*s);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
802 803
}

804 805
static int job_descriptor_number = 0;

806
int panwrap_replay_jc(mali_ptr jc_gpu_va)
807 808 809
{
	struct mali_job_descriptor_header *h;

810 811
	int start_number;

812
	bool first = true;
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
813
	bool last_size;
814

815
	do {
816 817 818
		struct panwrap_mapped_memory *mem =
			panwrap_find_mapped_gpu_mem_containing(jc_gpu_va);

819 820 821
		void *payload;

		h = PANWRAP_PTR(mem, jc_gpu_va, typeof(*h));
822 823 824 825

		int offset = h->job_descriptor_size == MALI_JOB_32 ? 4 : 0;
		mali_ptr payload_ptr = jc_gpu_va + sizeof(*h) - offset;

826 827 828
		payload = panwrap_fetch_gpu_mem(mem, payload_ptr,
						MALI_PAYLOAD_SIZE);

829 830
		int job_no = job_descriptor_number++;

831 832 833
		if (first)
			start_number = job_no;

834 835 836
		panwrap_log("struct mali_job_descriptor_header job_%d = {\n", job_no);
		panwrap_indent++;

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
837
		panwrap_prop("job_type = %s", panwrap_job_type_name(h->job_type));
838

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
839 840 841
		/* Save for next job fixing */
		last_size = h->job_descriptor_size;

842 843 844
		if (h->job_descriptor_size)
			panwrap_prop("job_descriptor_size = %d", h->job_descriptor_size);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
845 846 847 848 849 850 851 852 853 854 855 856
		if (h->exception_status)
			panwrap_prop("exception_status = %d", h->exception_status);

		if (h->first_incomplete_task)
			panwrap_prop("first_incomplete_task = %d", h->first_incomplete_task);

		if (h->fault_pointer)
			panwrap_prop("fault_pointer = 0x%" PRIx64, h->fault_pointer);

		if (h->job_barrier)
			panwrap_prop("job_barrier = %d", h->job_barrier);

857 858
		panwrap_prop("job_index = %d", h->job_index);

Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
859 860 861
		if (h->unknown_flags)
			panwrap_prop("unknown_flags = %d", h->unknown_flags);

862
		if (h->job_dependency_index_1)
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
863
			panwrap_prop("job_dependency_index_1 = %d", h->job_dependency_index_1);
864

865 866
		if (h->job_dependency_index_2)
			panwrap_prop("job_dependency_index_2 = %d", h->job_dependency_index_2);
867

868 869 870
		panwrap_indent--;
		panwrap_log("};\n");

871 872 873 874 875
		/* Do not touch the field yet -- decode the payload first, and
		 * don't touch that either. This is essential for the uploads
		 * to occur in sequence and therefore be dynamically allocated
		 * correctly. Do note the size, however, for that related
		 * reason. */
876

877
		int payload_size = 0;
878

879 880 881 882 883
		switch (h->job_type) {
		case JOB_TYPE_SET_VALUE:
			{
				struct mali_payload_set_value *s = payload;

884
				panwrap_log("struct mali_payload_set_value payload_%d = {\n", job_no);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
885
				panwrap_indent++;
886
				MEMORY_PROP(s, out);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
887 888 889
				panwrap_prop("unknown = 0x%" PRIX64, s->unknown);
				panwrap_indent--;
				panwrap_log("};\n");
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
890

891
				payload_size = sizeof(*s);
Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
892

893 894 895 896
				break;
			}
		case JOB_TYPE_TILER:
		case JOB_TYPE_VERTEX:
897 898
			payload_size = panwrap_replay_vertex_or_tiler_job(h, mem, payload_ptr, job_no);

899 900
			break;
		case JOB_TYPE_FRAGMENT:
901
			payload_size = panwrap_replay_fragment_job(mem, payload_ptr, job_no);
902 903 904 905
			break;
		default:
			break;
		}
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926

		/* Touch the job descriptor fields, careful about 32/64-bit */
		TOUCH_JOB_HEADER(mem, jc_gpu_va, sizeof(*h), offset, job_no);

		/* Touch the payload immediately after, sequentially */
		TOUCH_SEQUENTIAL(mem, payload_ptr, payload_size, "payload", job_no);

		/* Handle linkage */

		if (!first) {
			panwrap_log("((struct mali_job_descriptor_header *) (uintptr_t) job_%d_p)->", job_no - 1);

			if (last_size)
				panwrap_log_cont("next_job_64 = job_%d_p;\n\n", job_no);
			else
				panwrap_log_cont("next_job_32 = (u32) (uintptr_t) job_%d_p;\n\n", job_no);
		}

		first = false;


Alyssa Rosenzweig's avatar
Alyssa Rosenzweig committed
927
	} while ((jc_gpu_va = h->job_descriptor_size ? h->next_job_64 : h->next_job_32));
928 929

	return start_number;
930
}
931

932 933 934 935 936 937 938 939 940 941 942 943
void panwrap_replay_soft_replay_payload(mali_ptr jc_gpu_va, int job_no)
{
	struct mali_jd_replay_payload *v;

	struct panwrap_mapped_memory *mem =
		panwrap_find_mapped_gpu_mem_containing(jc_gpu_va);

	v = PANWRAP_PTR(mem, jc_gpu_va, typeof(*v));

	panwrap_log("struct mali_jd_replay_payload soft_replay_payload_%d = {\n", job_no);
	panwrap_indent++;

944 945 946
	MEMORY_PROP(v, tiler_jc_list);
	MEMORY_PROP(v, fragment_jc);
	MEMORY_PROP(v, tiler_heap_free);
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968

	panwrap_prop("fragment_hierarchy_mask = 0x%" PRIx32, v->fragment_hierarchy_mask);
	panwrap_prop("tiler_hierarchy_mask = 0x%" PRIx32, v->tiler_hierarchy_mask);
	panwrap_prop("hierarchy_default_weight = 0x%" PRIx32, v->hierarchy_default_weight);

	panwrap_log(".tiler_core_req = ");
	if (v->tiler_core_req)
		ioctl_log_decoded_jd_core_req(v->tiler_core_req);
	else
		panwrap_log_cont("0");
	panwrap_log_cont(",\n");

	panwrap_log(".fragment_core_req = ");
	if (v->fragment_core_req)
		ioctl_log_decoded_jd_core_req(v->fragment_core_req);
	else
		panwrap_log_cont("0");
	panwrap_log_cont(",\n");

	panwrap_indent--;
	panwrap_log("};\n");

969
	TOUCH(mem, jc_gpu_va, *v, "soft_replay_payload", job_no, false);
970 971
}

972
int panwrap_replay_soft_replay(mali_ptr jc_gpu_va)
973 974
{
	struct mali_jd_replay_jc *v;
975 976
	int start_no;
	bool first = true;
977 978 979 980 981 982 983 984

	do {
		struct panwrap_mapped_memory *mem =
			panwrap_find_mapped_gpu_mem_containing(jc_gpu_va);

		v = PANWRAP_PTR(mem, jc_gpu_va, typeof(*v));

		int job_no = job_descriptor_number++;
985 986 987 988 989 990 991

		if (first)
			start_no = job_no;

		first = false;

		panwrap_log("struct mali_jd_replay_jc job_%d = {\n", job_no);
992 993
		panwrap_indent++;

994 995
		MEMORY_PROP(v, next);
		MEMORY_PROP(v, jc);
996 997 998 999

		panwrap_indent--;
		panwrap_log("};\n");

1000 1001
		panwrap_replay_soft_replay_payload(jc_gpu_va + sizeof(struct mali_jd_replay_jc), job_no);

1002
		TOUCH(mem, jc_gpu_va, *v, "job", job_no, false);
1003
	} while ((jc_gpu_va = v->next));
1004 1005

	return start_no;
1006
}