systemless 0.12.17

High-Level Emulation for classic Macintosh applications
Documentation
#include <metal_stdlib>

using namespace metal;

struct RasterVertex {
    float4 position [[position]];
    float2 tex_coord;
};

vertex RasterVertex raster_vertex(uint vertex_id [[vertex_id]]) {
    constexpr float2 positions[] = {
        {-1.0,  1.0},
        {-1.0, -1.0},
        { 1.0,  1.0},
        { 1.0, -1.0},
    };
    constexpr float2 tex_coords[] = {
        {0.0, 0.0},
        {0.0, 1.0},
        {1.0, 0.0},
        {1.0, 1.0},
    };

    RasterVertex out;
    out.position = float4(positions[vertex_id], 0.0, 1.0);
    out.tex_coord = tex_coords[vertex_id];
    return out;
}

fragment float4 raster_fragment(
    RasterVertex in [[stage_in]],
    texture2d<float> framebuffer [[texture(0)]])
{
    constexpr sampler nearest_sampler(
        coord::normalized,
        address::clamp_to_edge,
        filter::nearest);
    return framebuffer.sample(nearest_sampler, in.tex_coord);
}

struct GuestFrameUniforms {
    uint row_bytes;
    uint width;
    uint height;
    uint pixel_size;
    uint content_left;
    uint content_top;
    uint cursor_kind;
    uint cursor_width;
    uint cursor_height;
    int cursor_left;
    int cursor_top;
};

struct GuestCursorData {
    uint data_rows[16];
    uint mask_rows[16];
    uint color_pixels[256];
};

static float4 unpack_argb(uint argb) {
    return float4(
        float((argb >> 16) & 0xFF) / 255.0,
        float((argb >> 8) & 0xFF) / 255.0,
        float(argb & 0xFF) / 255.0,
        1.0);
}

fragment float4 guest_raster_fragment(
    RasterVertex in [[stage_in]],
    device const uchar* framebuffer [[buffer(0)]],
    constant uint* palette [[buffer(1)]],
    constant GuestFrameUniforms& frame [[buffer(2)]],
    constant GuestCursorData& cursor [[buffer(3)]])
{
    uint x = frame.content_left
        + min(uint(in.tex_coord.x * float(frame.width)), frame.width - 1);
    uint y = frame.content_top
        + min(uint(in.tex_coord.y * float(frame.height)), frame.height - 1);
    uint argb;

    if (frame.pixel_size == 8) {
        uint index = framebuffer[y * frame.row_bytes + x];
        argb = palette[index];
    } else {
        uchar packed = framebuffer[y * frame.row_bytes + x / 8];
        bool black = (packed & (0x80 >> (x & 7))) != 0;
        argb = black ? 0xFF000000 : 0xFFFFFFFF;
    }

    int cursor_x = int(x) - frame.cursor_left;
    int cursor_y = int(y) - frame.cursor_top;
    if (frame.cursor_kind != 0
        && cursor_x >= 0 && cursor_y >= 0
        && cursor_x < int(frame.cursor_width)
        && cursor_y < int(frame.cursor_height)) {
        uint row = uint(cursor_y);
        uint column = uint(cursor_x);
        uint bit = column < 16 ? (0x8000 >> column) : 0;
        bool mask_set = row < 16 && column < 16 && (cursor.mask_rows[row] & bit) != 0;

        if (frame.cursor_kind == 1) {
            if (mask_set) {
                argb = (cursor.data_rows[row] & bit) != 0 ? 0xFF000000 : 0xFFFFFFFF;
            }
        } else {
            uint cursor_argb = cursor.color_pixels[row * frame.cursor_width + column];
            if (mask_set) {
                argb = cursor_argb | 0xFF000000;
            } else if (cursor_argb == 0xFF000000) {
                argb ^= 0x00FFFFFF;
            }
        }
    }

    return unpack_argb(argb);
}