summaryrefslogtreecommitdiff
path: root/pkg/macos/iosurface/iosurface.zig
blob: 37f8712ba427183fe363d627b5019b40a1caeef8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const c = @import("c.zig").c;
const foundation = @import("../foundation.zig");
const graphics = @import("../graphics.zig");
const video = @import("../video.zig");

pub const IOSurface = opaque {
    pub const Error = error{
        InvalidOperation,
    };

    pub const Properties = struct {
        width: c_int,
        height: c_int,
        pixel_format: video.PixelFormat,
        bytes_per_element: c_int,
        colorspace: ?*graphics.ColorSpace,
    };

    pub fn init(properties: Properties) Allocator.Error!*IOSurface {
        var w = try foundation.Number.create(.int, &properties.width);
        defer w.release();
        var h = try foundation.Number.create(.int, &properties.height);
        defer h.release();
        var pf = try foundation.Number.create(.int, &@as(c_int, @intFromEnum(properties.pixel_format)));
        defer pf.release();
        var bpe = try foundation.Number.create(.int, &properties.bytes_per_element);
        defer bpe.release();

        var properties_dict = try foundation.Dictionary.create(
            &[_]?*const anyopaque{
                c.kIOSurfaceWidth,
                c.kIOSurfaceHeight,
                c.kIOSurfacePixelFormat,
                c.kIOSurfaceBytesPerElement,
            },
            &[_]?*const anyopaque{ w, h, pf, bpe },
        );
        defer properties_dict.release();

        var surface = @as(?*IOSurface, @ptrFromInt(@intFromPtr(
            c.IOSurfaceCreate(@ptrCast(properties_dict)),
        ))) orelse return error.OutOfMemory;

        if (properties.colorspace) |space| {
            surface.setColorSpace(space);
        }

        return surface;
    }

    pub fn deinit(self: *IOSurface) void {
        // We mark it purgeable so that it is immediately unloaded, so that we
        // don't have to wait for CoreFoundation garbage collection to trigger.
        _ = c.IOSurfaceSetPurgeable(
            @ptrCast(self),
            c.kIOSurfacePurgeableEmpty,
            null,
        );
        foundation.CFRelease(self);
    }

    pub fn retain(self: *IOSurface) void {
        foundation.CFRetain(self);
    }

    pub fn release(self: *IOSurface) void {
        foundation.CFRelease(self);
    }

    pub fn setColorSpace(self: *IOSurface, colorspace: *graphics.ColorSpace) void {
        const serialized_colorspace = graphics.c.CGColorSpaceCopyPropertyList(
            @ptrCast(colorspace),
        ).?;
        defer foundation.CFRelease(@constCast(serialized_colorspace));

        c.IOSurfaceSetValue(
            @ptrCast(self),
            c.kIOSurfaceColorSpace,
            @ptrCast(serialized_colorspace),
        );
    }

    pub inline fn lock(self: *IOSurface) void {
        c.IOSurfaceLock(
            @ptrCast(self),
            0,
            null,
        );
    }
    pub inline fn unlock(self: *IOSurface) void {
        c.IOSurfaceUnlock(
            @ptrCast(self),
            0,
            null,
        );
    }

    pub inline fn getAllocSize(self: *IOSurface) usize {
        return c.IOSurfaceGetAllocSize(@ptrCast(self));
    }

    pub inline fn getWidth(self: *IOSurface) usize {
        return c.IOSurfaceGetWidth(@ptrCast(self));
    }

    pub inline fn getHeight(self: *IOSurface) usize {
        return c.IOSurfaceGetHeight(@ptrCast(self));
    }

    pub inline fn getBytesPerElement(self: *IOSurface) usize {
        return c.IOSurfaceGetBytesPerElement(@ptrCast(self));
    }

    pub inline fn getBytesPerRow(self: *IOSurface) usize {
        return c.IOSurfaceGetBytesPerRow(@ptrCast(self));
    }

    pub inline fn getBaseAddress(self: *IOSurface) ?[*]u8 {
        return @ptrCast(c.IOSurfaceGetBaseAddress(@ptrCast(self)));
    }

    pub inline fn getElementWidth(self: *IOSurface) usize {
        return c.IOSurfaceGetElementWidth(@ptrCast(self));
    }

    pub inline fn getElementHeight(self: *IOSurface) usize {
        return c.IOSurfaceGetElementHeight(@ptrCast(self));
    }

    pub inline fn getPixelFormat(self: *IOSurface) video.PixelFormat {
        return @enumFromInt(c.IOSurfaceGetPixelFormat(@ptrCast(self)));
    }
};