Harbor

branch main
showing the latest snapshot on main
compile_memory_test.odin 3.0 KB · Plain text
shader/compile_memory_test.odin 0644 Raw
package shader

import "core:mem"
import "core:testing"

TRACKED_COMPUTE_SOURCE :: `
struct Params
	count: uint
	scale: float
end

struct DataBuffer
	values: [64]float
end

@group(0) @binding(0) buffer params: Params
@group(0) @binding(1) buffer data: DataBuffer

@entry(compute)
@workgroup_size(64, 1, 1)
function main(@builtin(global_invocation_id) global_id: uvec3)
	let idx = global_id.x
	data.values[idx] = data.values[idx] * params.scale
end
`

@(test)
test_compile_result_destroy_releases_success_allocations :: proc(t: ^testing.T) {
	track: mem.Tracking_Allocator
	mem.tracking_allocator_init(&track, context.allocator)
	track.bad_free_callback = mem.tracking_allocator_bad_free_callback_add_to_array
	defer mem.tracking_allocator_destroy(&track)

	allocator := mem.tracking_allocator(&track)
	result := compile(TRACKED_COMPUTE_SOURCE, {
		target    = .WGSL,
		stage     = .Compute,
		opt_level = .Basic,
	}, "tracked_success.luma", allocator)

	testing.expect(t, result.success)
	testing.expect(t, len(result.output) > 0)
	testing.expect(t, len(result.reflection.entry_points) > 0)
	testing.expect(t, len(result.reflection.bindings) > 0)
	destroy_compile_result(&result)

	testing.expect_value(t, len(track.allocation_map), 0)
	testing.expect_value(t, len(track.bad_free_array), 0)
}

@(test)
test_compile_result_destroy_releases_failure_allocations :: proc(t: ^testing.T) {
	track: mem.Tracking_Allocator
	mem.tracking_allocator_init(&track, context.allocator)
	track.bad_free_callback = mem.tracking_allocator_bad_free_callback_add_to_array
	defer mem.tracking_allocator_destroy(&track)

	allocator := mem.tracking_allocator(&track)
	result := compile("function main(\n", {
		target = .WGSL,
		stage  = .Compute,
	}, "tracked_failure.luma", allocator)

	testing.expect(t, !result.success)
	testing.expect(t, len(result.diagnostics) > 0)
	testing.expect(t, len(result.diagnostics[0].message) > 0)
	destroy_compile_result(&result)

	testing.expect_value(t, len(track.allocation_map), 0)
	testing.expect_value(t, len(track.bad_free_array), 0)
}

@(test)
test_compile_result_owned_across_repeated_compiles :: proc(t: ^testing.T) {
	track: mem.Tracking_Allocator
	mem.tracking_allocator_init(&track, context.allocator)
	track.bad_free_callback = mem.tracking_allocator_bad_free_callback_add_to_array
	defer mem.tracking_allocator_destroy(&track)

	allocator := mem.tracking_allocator(&track)
	first := compile(TRACKED_COMPUTE_SOURCE, {
		target    = .WGSL,
		stage     = .Compute,
		opt_level = .Basic,
	}, "first.luma", allocator)
	second := compile("function main(\n", {
		target = .WGSL,
		stage  = .Compute,
	}, "second.luma", allocator)

	testing.expect(t, first.success)
	testing.expect(t, len(first.output) > 0)
	testing.expect(t, len(first.reflection.entry_points) > 0)
	testing.expect(t, !second.success)
	testing.expect(t, len(second.diagnostics) > 0)

	destroy_compile_result(&second)
	destroy_compile_result(&first)

	testing.expect_value(t, len(track.allocation_map), 0)
	testing.expect_value(t, len(track.bad_free_array), 0)
}