#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <stdint.h>
#include <time.h>

#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libdrm/drm.h>
#include <libdrm/drm_mode.h>

int main() {
    int fd = open("/dev/dri/card0", O_RDWR);
    if (fd < 0) { perror("open /dev/dri/card0"); return 1; }

    drmModeRes *res = drmModeGetResources(fd);
    drmModeConnector *conn = NULL;

    for (int i = 0; i < res->count_connectors; i++) {
        conn = drmModeGetConnector(fd, res->connectors[i]);
        if (conn && conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
            break;
        drmModeFreeConnector(conn);
        conn = NULL;
    }

    if (!conn) { printf("No display\n"); return 1; }

    drmModeModeInfo mode = conn->modes[0];
    drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoder_id);

    struct drm_mode_create_dumb create = {};
    create.width = mode.hdisplay;
    create.height = mode.vdisplay;
    create.bpp = 32;
    drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);

    uint32_t fb;
    drmModeAddFB(fd, create.width, create.height, 24, 32,
                 create.pitch, create.handle, &fb);

    struct drm_mode_map_dumb map = {};
    map.handle = create.handle;
    drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);

    volatile uint32_t *buf = mmap(0, create.size,
                                 PROT_READ | PROT_WRITE,
                                 MAP_SHARED, fd, map.offset);

    drmModeSetCrtc(fd, enc->crtc_id, fb, 0, 0,
                   &conn->connector_id, 1, &mode);

    printf("%dx%d\n", create.width, create.height);
    fflush(stdout); 

    int stride = create.pitch / 4;
    int scale = 8;

    size_t width = mode.hdisplay;
    size_t height = mode.vdisplay;
    size_t frame_size = width * height * sizeof(uint32_t);
    uint32_t *frame_buf = malloc(frame_size);

    if (!frame_buf) { perror("malloc"); return 1; }

    while (1) {
        size_t n = fread(frame_buf, 1, frame_size, stdin);
        if (n != frame_size) {
            // EOF or partial frame, exit cleanly
            break;
        }
        memcpy((void*)buf, frame_buf, frame_size);
        drmModeDirtyFB(fd, fb, NULL, 0);
    }

    free(frame_buf);
    munmap((void*)buf, create.size);

    return 0;
}
