Harbor

branch main
showing the latest snapshot on main
trace.odin 5.2 KB · Plain text
gpu/render_ir/trace.odin 0644 Raw
package render_ir

import "core:fmt"
import "core:mem"
import "core:strings"

@(private)
trace_begin_pass :: proc(buf: ^strings.Builder, wrote_line: ^bool, ir: ^Frame_IR, pass_handle: Pass_Handle) {
	pass, ok := get_pass(ir, pass_handle)
	if !ok {
		dump_write_line(
			buf,
			wrote_line,
			fmt.aprintf("begin_pass invalid handle=%d", pass_handle, allocator = context.temp_allocator),
		)
		return
	}

	dump_write_line(
		buf,
		wrote_line,
		fmt.aprintf(
			"begin_pass #%d %s name=\"%s\"",
			pass_handle,
			format_pass_kind(pass.kind),
			pass.name,
			allocator = context.temp_allocator,
		),
	)
}

@(private)
trace_end_pass :: proc(buf: ^strings.Builder, wrote_line: ^bool, pass_handle: Pass_Handle) {
	if pass_handle == INVALID_PASS {
		return
	}
	dump_write_line(
		buf,
		wrote_line,
		fmt.aprintf("end_pass #%d", pass_handle, allocator = context.temp_allocator),
	)
}

@(private)
trace_bind_pipeline :: proc(buf: ^strings.Builder, wrote_line: ^bool, ir: ^Frame_IR, pipeline_handle: Pipeline_Handle) {
	pipeline, ok := get_pipeline(ir, pipeline_handle)
	if !ok {
		dump_write_line(
			buf,
			wrote_line,
			fmt.aprintf("bind_pipeline invalid handle=%d", pipeline_handle, allocator = context.temp_allocator),
		)
		return
	}

	dump_write_line(
		buf,
		wrote_line,
		fmt.aprintf(
			"bind_pipeline #%d %s name=\"%s\"",
			pipeline_handle,
			format_pipeline_kind(pipeline.kind),
			pipeline.name,
			allocator = context.temp_allocator,
		),
	)
}

@(private)
trace_enter_pass :: proc(
	buf: ^strings.Builder,
	wrote_line: ^bool,
	ir: ^Frame_IR,
	current_pass: ^Pass_Handle,
	current_pipeline: ^Pipeline_Handle,
	next_pass: Pass_Handle,
) {
	if next_pass == INVALID_PASS {
		dump_write_line(buf, wrote_line, "begin_pass invalid handle=0")
		current_pass^ = INVALID_PASS
		current_pipeline^ = INVALID_PIPELINE
		return
	}

	if current_pass^ == next_pass {
		return
	}

	trace_end_pass(buf, wrote_line, current_pass^)
	trace_begin_pass(buf, wrote_line, ir, next_pass)
	current_pass^ = next_pass
	current_pipeline^ = INVALID_PIPELINE
}

@(private)
trace_ensure_pipeline :: proc(
	buf: ^strings.Builder,
	wrote_line: ^bool,
	ir: ^Frame_IR,
	current_pipeline: ^Pipeline_Handle,
	next_pipeline: Pipeline_Handle,
) {
	if next_pipeline == INVALID_PIPELINE {
		dump_write_line(buf, wrote_line, "bind_pipeline invalid handle=0")
		current_pipeline^ = INVALID_PIPELINE
		return
	}

	if current_pipeline^ == next_pipeline {
		return
	}

	trace_bind_pipeline(buf, wrote_line, ir, next_pipeline)
	current_pipeline^ = next_pipeline
}

trace_frame_ir :: proc(ir: ^Frame_IR, allocator: mem.Allocator = context.allocator) -> string {
	buf := strings.builder_make(allocator)
	wrote_line := false
	current_pass := INVALID_PASS
	current_pipeline := INVALID_PIPELINE

	dump_write_line(&buf, &wrote_line, "Trace")

	for _, i in ir.commands {
		handle := Command_Handle(i + 1)
		record, record_ok := get_command_record(ir, handle)
		if !record_ok {
			dump_write_line(
				&buf,
				&wrote_line,
				fmt.aprintf("cmd #%d invalid_record", i + 1, allocator = context.temp_allocator),
			)
			continue
		}

		switch record.kind {
		case .Draw:
			draw, draw_ok := get_draw(ir, handle)
			if !draw_ok {
				dump_write_line(
					&buf,
					&wrote_line,
					fmt.aprintf("cmd #%d invalid_draw", i + 1, allocator = context.temp_allocator),
				)
				continue
			}

			trace_enter_pass(&buf, &wrote_line, ir, &current_pass, &current_pipeline, draw.pass)
			trace_ensure_pipeline(&buf, &wrote_line, ir, &current_pipeline, draw.pipeline)
			if draw_kind_is_packet(draw.kind) {
				packet := draw.packet
				dump_write_line(
					&buf,
					&wrote_line,
					fmt.aprintf(
						"draw_packet kind=%s target=%d layer=%d order=%s sort_key=%d sequence=%d geometry=%s/%d vertices=%d instances=%d",
						format_draw_kind(draw.kind),
						packet.target,
						packet.layer,
						format_order_mode(packet.order),
						packet.sort_key,
						packet.sequence,
						format_geometry_kind(packet.geometry.kind),
						packet.geometry.resource,
						packet.geometry.vertex_count,
						packet.instances.count,
						allocator = context.temp_allocator,
					),
				)
				continue
			}
			dump_write_line(
				&buf,
				&wrote_line,
				fmt.aprintf(
					"draw vertex_count=%d instance_count=%d",
					draw.vertex_count,
					draw.instance_count,
					allocator = context.temp_allocator,
				),
			)
		case .Dispatch:
			dispatch, dispatch_ok := get_dispatch(ir, handle)
			if !dispatch_ok {
				dump_write_line(
					&buf,
					&wrote_line,
					fmt.aprintf("cmd #%d invalid_dispatch", i + 1, allocator = context.temp_allocator),
				)
				continue
			}

			trace_enter_pass(&buf, &wrote_line, ir, &current_pass, &current_pipeline, dispatch.pass)
			trace_ensure_pipeline(&buf, &wrote_line, ir, &current_pipeline, dispatch.pipeline)
			dump_write_line(
				&buf,
				&wrote_line,
				fmt.aprintf(
					"dispatch groups=%d,%d,%d shader_id=%d buffers=%s push_constants_size=%d barrier_after=%v",
					dispatch.groups[0],
					dispatch.groups[1],
					dispatch.groups[2],
					dispatch.shader_id,
					format_dispatch_buffers(dispatch^),
					u32(len(dispatch.push_constants)),
					dispatch.barrier_after,
					allocator = context.temp_allocator,
				),
			)
		}
	}

	trace_end_pass(&buf, &wrote_line, current_pass)
	return strings.to_string(buf)
}