diff --git a/main.c b/main.c index 0b14878..7302cec 100644 --- a/main.c +++ b/main.c @@ -3,15 +3,70 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include +typedef struct { + uint32_t *buf; + uint32_t handle; + uint32_t id; + uint32_t pitch; + uint32_t size; +} fb_info_t; + +fb_info_t fb_init(int fd, drmModeModeInfo mode) +{ + int err; + + struct drm_mode_create_dumb create = { + .width = mode.hdisplay, + .height = mode.vdisplay, + .bpp = 32, + }; + err = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); + assert(err != -1); + + uint32_t id; + err = drmModeAddFB( + fd, create.width, create.height, 24, 32, create.pitch, create.handle, + &id); + assert(err == 0); + + struct drm_mode_map_dumb map = { .handle = create.handle }; + err = ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); + assert(err != -1); + + uint32_t *buf = mmap( + 0, create.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, map.offset); + assert(buf != MAP_FAILED); + + return (fb_info_t) { + .buf = buf, + .handle = create.handle, + .id = id, + .pitch = create.pitch, + .size = create.size, + }; +} + +void fb_cleanup(int fd, fb_info_t fb) +{ + munmap(fb.buf, fb.size); + drmModeRmFB(fd, fb.id); + struct drm_mode_destroy_dumb delete = { .handle = fb.handle }; + ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &delete); +} + +static void page_flip_handler(int, unsigned, unsigned, unsigned, void *) +{ +} + int main() { int err; @@ -26,53 +81,54 @@ int main() drmModeModeInfo mode = conn->modes[0]; uint32_t conn_id = conn->connector_id; - struct drm_mode_create_dumb create_req = { - .width = mode.hdisplay, - .height = mode.vdisplay, - .bpp = 32, + fb_info_t fbs[2] = { + fb_init(fd, mode), + fb_init(fd, mode), }; - err = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req); - assert(err != -1); + int front = 0, back = 1; - uint32_t fb_id; - err = drmModeAddFB( - fd, create_req.width, create_req.height, 24, 32, create_req.pitch, - create_req.handle, &fb_id); - assert(err == 0); - - err = drmModeSetCrtc(fd, res->crtcs[0], fb_id, 0, 0, &conn_id, 1, &mode); + err = drmModeSetCrtc( + fd, res->crtcs[0], fbs[front].id, 0, 0, &conn_id, 1, &mode); assert(err == 0); drmModeCrtc *crtc = drmModeGetCrtc(fd, res->crtcs[0]); assert(crtc != nullptr); - struct drm_mode_map_dumb map_req = { .handle = create_req.handle }; - err = ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req); - assert(err != -1); + fd_set set; + FD_ZERO(&set); + FD_SET(fd, &set); - uint32_t *const fb = mmap( - 0, create_req.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, - map_req.offset); - assert(fb != MAP_FAILED); + drmEventContext ev = { + .version = DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler = page_flip_handler, + }; - for (int y = 0; y < mode.vdisplay; ++y) { - for (int x = 0; x < mode.hdisplay; ++x) { - const uint8_t r = (x * 255) / mode.hdisplay; - const uint8_t g = (y * 255) / mode.vdisplay; - const uint8_t b = 128; - fb[y * (create_req.pitch / 4) + x] = (r << 16) | (g << 8) | b; + for (uint64_t frame = 0; frame < (10 * 60); ++frame) { + for (int y = 0; y < mode.vdisplay; ++y) { + for (int x = 0; x < mode.hdisplay; ++x) { + const uint8_t r = (x + frame) % 256; + const uint8_t g = (y + frame) & 256; + const uint8_t b = (x + y + frame) % 256; + fbs[back].buf[y * (fbs[back].pitch / 4) + x] + = (r << 16) | (g << 8) | b; + } } + + drmModePageFlip( + fd, crtc->crtc_id, fbs[back].id, DRM_MODE_PAGE_FLIP_EVENT, + nullptr); + select(fd + 1, &set, nullptr, nullptr, nullptr); + drmHandleEvent(fd, &ev); + + front = (front + 1) & 1; + back = (back + 1) & 1; } - getchar(); - - munmap(fb, create_req.size); - struct drm_mode_destroy_dumb delete_req - = { .handle = create_req.handle }; - ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &delete_req); - drmModeSetCrtc( fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, &conn_id, 1, &crtc->mode); + + fb_cleanup(fd, fbs[0]); + fb_cleanup(fd, fbs[1]); drmModeFreeCrtc(crtc); drmModeFreeConnector(conn); drmModeFreeResources(res);