package render_ir_tests import ir "../../render_ir" import "core:testing" make_mask_frame :: proc() -> ( frame: ir.Frame_IR, target: ir.Target_Handle, coverage: ir.Resource_Handle, ) { frame = ir.init_frame_ir() target = ir.add_target( &frame, { kind = .Present, name = "present", width = 256, height = 256, color_format = .B8G8R8A8_SRGB, clear_color = {0, 0, 0, 1}, clear_depth = 1, }, ) coverage = ir.add_buffer(&frame, "mask-coverage", 256, {.Vertex}, {.Host_Visible}, .Transient) return } @(test) test_mask_clip_model_validates_semantic_handles :: proc(t: ^testing.T) { frame, target, coverage := make_mask_frame() defer ir.destroy_frame_ir(&frame) mask := ir.add_mask( &frame, { target = target, name = "round-coverage", source_kind = .Geometry_Coverage, coverage_resource = coverage, vertex_count = 6, }, ) clip := ir.add_clip(&frame, {target = target, kind = .Mask, mask = mask}) testing.expect(t, mask != ir.INVALID_MASK) testing.expect(t, clip != ir.INVALID_CLIP) testing.expect_value(t, ir.mask_count(&frame), 1) testing.expect_value(t, ir.clip_count(&frame), 1) diagnostics := ir.init_diagnostics() defer ir.destroy_diagnostics(&diagnostics) ir.validate_intent_handles(&frame, &diagnostics) testing.expect_value(t, len(diagnostics.items), 0) } @(test) test_mask_clip_rejects_invalid_mask_handle :: proc(t: ^testing.T) { frame, target, _ := make_mask_frame() defer ir.destroy_frame_ir(&frame) _ = ir.add_clip(&frame, {target = target, kind = .Mask, mask = ir.Mask_Handle(99)}) diagnostics := ir.init_diagnostics() defer ir.destroy_diagnostics(&diagnostics) ir.validate_intent_handles(&frame, &diagnostics) testing.expect(t, ir.has_errors(&diagnostics)) testing.expect_value(t, diagnostics.items[0].code, ir.Diagnostic_Code.Invalid_Mask) } @(test) test_mask_clip_rejects_target_mismatch :: proc(t: ^testing.T) { frame, target_a, coverage := make_mask_frame() defer ir.destroy_frame_ir(&frame) target_b := ir.add_target( &frame, { kind = .Present, name = "other", width = 256, height = 256, color_format = .B8G8R8A8_SRGB, clear_color = {0, 0, 0, 1}, clear_depth = 1, }, ) mask := ir.add_mask( &frame, {target = target_a, name = "mask", source_kind = .Geometry_Coverage, coverage_resource = coverage, vertex_count = 3}, ) _ = ir.add_clip(&frame, {target = target_b, kind = .Mask, mask = mask}) diagnostics := ir.init_diagnostics() defer ir.destroy_diagnostics(&diagnostics) ir.validate_intent_handles(&frame, &diagnostics) testing.expect(t, ir.has_errors(&diagnostics)) testing.expect_value(t, diagnostics.items[0].code, ir.Diagnostic_Code.Invalid_Mask) } @(test) test_mask_clip_rejects_missing_source :: proc(t: ^testing.T) { frame, target, _ := make_mask_frame() defer ir.destroy_frame_ir(&frame) _ = ir.add_mask(&frame, {target = target, name = "empty"}) diagnostics := ir.init_diagnostics() defer ir.destroy_diagnostics(&diagnostics) ir.validate_intent_handles(&frame, &diagnostics) testing.expect(t, ir.has_errors(&diagnostics)) testing.expect_value(t, diagnostics.items[0].code, ir.Diagnostic_Code.Invalid_Mask) } @(test) test_mask_clip_lowering_refuses_until_stencil_capability_exists :: proc(t: ^testing.T) { frame, target, coverage := make_mask_frame() defer ir.destroy_frame_ir(&frame) mask := ir.add_mask( &frame, {target = target, name = "mask", source_kind = .Geometry_Coverage, coverage_resource = coverage, vertex_count = 3}, ) _ = ir.add_clip(&frame, {target = target, kind = .Mask, mask = mask}) diagnostics := ir.init_diagnostics() defer ir.destroy_diagnostics(&diagnostics) ir.validate_mask_clips_supported(&frame, &diagnostics, false) testing.expect(t, ir.has_errors(&diagnostics)) testing.expect_value(t, diagnostics.items[0].code, ir.Diagnostic_Code.Stencil_Unsupported) ir.reset_diagnostics(&diagnostics) ir.validate_mask_clips_supported(&frame, &diagnostics, true) testing.expect(t, !ir.has_errors(&diagnostics)) }