first commit
authorThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Tue, 17 Sep 2024 21:54:57 +0000 (21:54 +0000)
committerThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Tue, 17 Sep 2024 21:54:57 +0000 (21:54 +0000)
13 files changed:
developer/Erebus/framebuffer_filter [new file with mode: 0755]
developer/Erebus/framebuffer_filter.c [new file with mode: 0644]
developer/Erebus/transform_frame_stream.c [new file with mode: 0644]
developer/Erebus/transform_frame_stream.c~ [new file with mode: 0644]
developer/Erebus/transform_frames.c [new file with mode: 0644]
developer/Erebus/transform_frames.c~ [new file with mode: 0644]
developer/cc/drm_info [new file with mode: 0755]
developer/cc/drm_info.c [new file with mode: 0644]
developer/cc/modified_transform_frame_stream.c [new file with mode: 0644]
developer/cc/transform_frame_stream [new file with mode: 0755]
developer/cc/transform_frame_stream.c [new file with mode: 0644]
developer/cc/transform_frame_stream_2.c [new file with mode: 0644]
developer/developer [new file with mode: 0644]

diff --git a/developer/Erebus/framebuffer_filter b/developer/Erebus/framebuffer_filter
new file mode 100755 (executable)
index 0000000..9b49c28
Binary files /dev/null and b/developer/Erebus/framebuffer_filter differ
diff --git a/developer/Erebus/framebuffer_filter.c b/developer/Erebus/framebuffer_filter.c
new file mode 100644 (file)
index 0000000..fefd64a
--- /dev/null
@@ -0,0 +1,85 @@
+// gcc framebuffer_filter.c -o framebuffer_filter
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <string.h>
+
+#define MAX_DELTA 10  // Max pixel change allowed
+
+// Function to clamp a value within a certain range
+unsigned char clamp(unsigned char current, unsigned char previous) {
+    if (current > previous + MAX_DELTA)
+        return previous + MAX_DELTA;
+    else if (current < previous - MAX_DELTA)
+        return previous - MAX_DELTA;
+    else
+        return current;
+}
+
+int main() {
+    int fb_fd = open("/dev/fb0", O_RDWR);
+    if (fb_fd == -1) {
+        perror("Error: cannot open framebuffer device");
+        return 1;
+    }
+
+    struct fb_var_screeninfo vinfo;
+    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo)) {
+        perror("Error reading variable information");
+        close(fb_fd);
+        return 1;
+    }
+
+    // Calculate the screen size
+    int screensize = vinfo.yres_virtual * vinfo.xres_virtual * vinfo.bits_per_pixel / 8;
+
+    // Map framebuffer into memory
+    unsigned char *fb_ptr = (unsigned char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
+    if ((intptr_t)fb_ptr == -1) {
+        perror("Error: failed to map framebuffer device to memory");
+        close(fb_fd);
+        return 1;
+    }
+
+    // Allocate memory for previous frame buffer
+    unsigned char *prev_frame = malloc(screensize);
+    if (!prev_frame) {
+        perror("Error: unable to allocate memory for previous frame");
+        munmap(fb_ptr, screensize);
+        close(fb_fd);
+        return 1;
+    }
+
+    // Initial copy of the framebuffer
+    memcpy(prev_frame, fb_ptr, screensize);
+
+    // Frame processing loop
+    while (1) {
+        // Process each pixel (assuming 32 bits per pixel - adjust as needed)
+        for (int i = 0; i < screensize; i += 4) {
+            // R, G, B values
+            fb_ptr[i] = clamp(fb_ptr[i], prev_frame[i]);       // Blue
+            fb_ptr[i + 1] = clamp(fb_ptr[i + 1], prev_frame[i + 1]);  // Green
+            fb_ptr[i + 2] = clamp(fb_ptr[i + 2], prev_frame[i + 2]);  // Red
+            // fb_ptr[i + 3] = Alpha channel, leave as is or modify if necessary
+        }
+
+        // Copy current frame to previous frame for the next iteration
+        memcpy(prev_frame, fb_ptr, screensize);
+
+        // Sleep to avoid high CPU usage
+        usleep(16000); // ~60 FPS
+    }
+
+    // Clean up
+    free(prev_frame);
+    munmap(fb_ptr, screensize);
+    close(fb_fd);
+    
+    return 0;
+}
diff --git a/developer/Erebus/transform_frame_stream.c b/developer/Erebus/transform_frame_stream.c
new file mode 100644 (file)
index 0000000..15ebf5f
--- /dev/null
@@ -0,0 +1,369 @@
+//
+// gcc -I/usr/include/libdrm drm_info.c -o transform_frame_stream -ldrm
+// ./transform_frame_stream
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+// --------------------------------------------------------------------------------
+// Pixel
+
+// These pixels have hardware support ,and thus must be packed in the order
+// expected by the hardware.
+// 0xAARRGGBB
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t blue;
+      uint8_t green;
+      uint8_t red;
+      uint8_t alpha;
+    };
+  } PixelRGBA;
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t alpha;
+      uint8_t red;
+      uint8_t green;
+      uint8_t blue;
+    };
+  } PixelRGBA;
+#else
+    #warning "Unknown __BYTE_ORDER__ found when packing a PixelRGBA."
+#endif
+
+const PixelRGBA black = {.aggregate = 0xff000000};
+const PixelRGBA white = {.aggregate = 0xffffffff};
+
+PixelRGBA·structure
+  (
+   PixelRGBA *to_px 
+   ,uint8_t red 
+   ,uint8_t green 
+   ,uint8_t blue 
+   ,uint8_t alpha
+   ){
+  px->blue  = blue;
+  px->green = green;
+  px->red   = red;
+  px->alpha = alpha;
+}
+PixelRGBA·destructure
+  (
+   PixelRGBA *from_px 
+   ,uint8_t *red 
+   ,uint8_t *green 
+   ,uint8_t *blue 
+   ,uint8_t *alpha
+   ){
+  *blue  = from_px->blue;
+  *green = from_px->green;
+  *red   = from_px->red;
+  *alpha = from_px->alpha;
+}
+
+
+// --------------------------------------------------------------------------------
+// Frame
+
+typedef struct __attribute__((packed)){
+  uint32_t width;
+  uint32_t height;
+  PixelRGBA data[];
+} FrameRGBA;
+
+FrameRGBA·alloc(int width ,int height){
+  bool null_frame = false;
+
+  if( width == 0 ){
+    fprintf(stderr, "FrameRGBA·alloc:: frame width of zero, so returning a null frame pointer\n");
+    null_frame = true;
+  }
+  if( height == 0 ){
+    fprintf(stderr, "FrameRGBA·alloc:: frame height of zero, so returning a null frame pointer\n");
+    null_frame = true;
+  }
+  if(null_frame) return NULL;
+  
+  FrameRGBA *frame = malloc(sizeof(FrameRGBA));
+  if(!frame){
+    fprintf(stderr ,"FrameRGBA·alloc::failed to allocate frame\n");
+    null_frame = true;
+  }
+  frame->data = malloc( width * height * sizeof(int) );
+  if(!frame->data){
+    fprintf(stderr ,"FrameRGBA·alloc::failed to allocate frame data\n");
+    null_frame = true;
+  }
+  if(null_frame) return NULL;
+  frame->width = width;
+  frame->height = height;
+  return frame;
+}
+FrameRGBA·alloc_same(Frame_data *frame){
+  if(!frame) return NULL;
+  return alloc(frame->width ,frame->height);
+}
+FrameRGBA·dealloc(FrameRGBA *frame){
+  free(frame);
+}
+
+FrameRGBA·dimensions(FrameRGBA *frame ,uint32_t *width ,uint32_t *height){
+  if(!frame){
+    *width = 0;
+    *height = 0;
+    return;
+  }
+  *width = frame->width;
+  *height = frame->height;
+}
+
+// both frames have already been allocated
+FrameRGBA·copy(FrameRGBA *from_frame ,FrameRGBA **to_frame_arg){
+  if(to_frame_arg == NULL) return;
+  if(*to_frame_arg == NULL) return;
+  if( from_frame == NULL ){
+    *to_frame = NULL;
+    return;
+  }
+  FrameRGBA *to_frame = *to_frame_arg;
+
+  int32_t width, height;
+  FrameRGBA·dimensions(from_frame ,&width ,&height);
+  if(**to_frame.width < width){
+    width = to_frame.width;
+    fprintf(stderr ,"FrameRGBA·copy:: from_frame is wider than to_frame ,there will be truncation\n");
+  }else if(to_frame.width > width){
+    fprintf(stderr ,"FrameRGBA·copy:: to_frame is wider, so stale uninitialized pixels will remain at the end of scan lines.\n");
+  }
+  if(to_frame.height < height){
+    height = to_frame.height;
+    fprintf(stderr ,"FrameRGBA·copy:: from_frame is taller than to_frame ,there will be truncation\n");
+  }else if(to_frame.height > height){
+    fprintf(stderr ,"FrameRGBA·copy:: to_frame is taller, so stale or uninitialized scan lines will remain at the bottom of the frame.\n");
+  }
+
+  int32_t j = 0;
+  int32_t offset = 0;
+  do{
+    memcpy(
+           from_frame->data + offset 
+           ,to_frame-data 
+           ,width * sizeof(PixelRGBA)
+           );
+    offset += width;
+    j++;
+  }while(j <= height);
+}
+// if i and j walk out of frame returns NULL
+PixelRGB *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
+  int32_t width, height;
+  FrameRGBA·dimensions(from_frame ,&width ,&height);
+  if(i > width) return NULL;
+  if(j > height) return NULL;
+  uint32_t line_size = from_frame->width * sizeof(PixelRGB);
+  return from_frame->data + j*line_size + i*sizeof(PixelRGB);
+}
+PixelRGB FrameRGBA·read(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
+  return *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j);
+}
+void FrameRGBA·write(FrameRGBA *to_frame ,uint32_t i ,uint32_t j ,PixelRGBA px){
+  *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j) = px;
+}
+
+// search frame for condition where f returns a non-null pointer
+// f is handed successive pointers to pixels in the frame.
+// f is given the frame in case it needs context.
+// f is given an argument is it is difficult to curry functions in C.
+void *FrameRGBA·exist
+(
+  FrameRGBA *frame 
+  ,void *f(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
+  ,void *arg
+  ){
+
+  if(!frame) return NULL;
+
+  void *item;
+  int32_t width, height;
+  FrameRGBA·dimensions(frame ,&width ,&height);
+  int32_t i = 0;
+  int32_t j = 0;
+  do{
+    PixelRGBA *px = FrameRGBA·access(frame ,i ,j);
+    if( item=f(frame ,px ,arg) ) return item;
+
+    if(i == width){
+      i = 0;
+      j++;
+    }else{ 
+      i++;
+    }
+  }while(j <= height);
+  return NULL;
+}
+
+typedef struct{
+  void f(FrameRGBA *frame ,PixelRGBA *px ,void *arg) f;
+  void *arg;
+} every_arg_t;
+void *(*every_f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg0){
+  every_arg_t *ea = arg0;
+  ea->f(frame ,px ,ea->arg);
+  return NULL;
+}
+void *FrameRGBA·every
+(
+  FrameRGBA *frame 
+  ,void *f(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
+  ,void *arg
+  ){
+  ever_arg_t ea = {.f = f ,.arg = arg};
+  FrameRGBA·exist(to_frame ,ever_f ,&ea);
+}
+
+void (*fill_f)(FrameRGBA *to_frame ,PixelRGBA *to_px ,void *arg){
+  PixelRGBA *px = arg;
+  *to_px = *px;
+  return NULL; 
+}
+FrameRGBA·fill(Frame_data *to_frame ,PixelRGB *fill_px){
+  FrameRGBA·every(to_frame ,fill_f ,fill_px);
+}
+FrameRGBA·fill_black(Frame_data *to_frame){
+  FrameRGBA·fill(to_frame ,&black);
+}
+FrameRGBA·fill_white(Frame_data *to_frame){
+  FrameRGBA·fill(to_frame ,&black);
+}
+
+// --------------------------------------------------------------------------------
+// Transform functions
+//   Given the previous frame, current frame, and an argument; modifies the
+//   current frame.
+
+int identity_transform(FrameRGBA *prev_frame ,FrameRGBA *curr_frame ,void *args){
+  // no processing in the identity transform
+  copy_FrameRGBA(curr_frame ,prev_frame);
+  return 0;  // Success
+}
+
+// --------------------------------------------------------------------------------
+// transform frame stream
+
+int transform_frame_stream(int (*transform)(FrameRGBA * ,FrameRGBA * ,void *) ,void *transform_args){
+  // Simulated screen info (would be fetched from the actual DRM system)
+  FrameRGBA *prev_frame = Framedata·alloc(3840 ,2400);
+  FrameRGBA *curr_frame = Framedata·alloc_same(prev_frame);
+
+  // Fornow ,we'll simulate grabbing the first frame by filling it with random values.
+  // In the real implementation ,you will fetch the current frame data from the DRM API.
+  for(int i = 0; i < width * height; i++){
+    curr_frame.data[i] = rand();  // Simulate grabbing a frame with random pixel data
+  }
+
+  // Call the transform function forthe first frame (identity in this case)
+  transform(&prev_frame ,&curr_frame ,transform_args);
+
+  // Main processing loop (simplified to one iteration fornow)
+  while (1){
+    // Simulate grabbing the next frame (we just reuse the current one forthis example)
+    // In real code ,you would fetch the next frame from the DRM system here.
+
+    // Call the transform function foreach new frame
+    transform(&prev_frame ,&curr_frame ,transform_args);
+
+    // Copy current frame to previous frame (fornext iteration)
+    memcpy(prev_frame.data ,curr_frame.data ,width * height * sizeof(unsigned int));
+
+    break;  // Exit after one loop forthis example (replace with continuous loop in real implementation)
+  }
+
+  // Clean up memory
+  free(prev_frame.data);
+  free(curr_frame.data);
+
+  return 0;  // Success
+}
+
+int main(int argc ,char **argv){
+  int fd;
+  drmModeRes *resources;
+  drmModeConnector *connector = NULL;
+  drmModeEncoder *encoder = NULL;
+  drmModeCrtc *crtc = NULL;
+
+  // Open the DRM device
+  fd = open("/dev/dri/card2" ,O_RDWR | O_CLOEXEC);
+  if(fd < 0){
+    perror("Cannot open DRM device");
+    return -1;
+  }
+
+  // Get resources
+  resources = drmModeGetResources(fd);
+  if(!resources){
+    perror("drmModeGetResources failed");
+    close(fd);
+    return -1;
+  }
+
+  // Find a connected connector
+  for(int i = 0; i < resources->count_connectors; i++){
+    connector = drmModeGetConnector(fd ,resources->connectors[i]);
+    if(connector->connection == DRM_MODE_CONNECTED){
+      break;
+    }
+    drmModeFreeConnector(connector);
+  }
+
+  if(!connector || connector->connection != DRM_MODE_CONNECTED){
+    printf("No connected connector found\n");
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Get encoder and CRTC
+  encoder = drmModeGetEncoder(fd ,connector->encoder_id);
+  if(!encoder){
+    perror("drmModeGetEncoder failed");
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  crtc = drmModeGetCrtc(fd ,encoder->crtc_id);
+  if(!crtc){
+    perror("drmModeGetCrtc failed");
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Call transform_frame_stream with identity transform
+  transform_frame_stream(identity_transform ,NULL);
+
+  // Clean up
+  drmModeFreeCrtc(crtc);
+  drmModeFreeEncoder(encoder);
+  drmModeFreeConnector(connector);
+  drmModeFreeResources(resources);
+  close(fd);
+
+  return 0;
+}
diff --git a/developer/Erebus/transform_frame_stream.c~ b/developer/Erebus/transform_frame_stream.c~
new file mode 100644 (file)
index 0000000..f45ce5d
--- /dev/null
@@ -0,0 +1,89 @@
+// gcc -I/usr/include/libdrm drm_info.c -o drm_info -ldrm
+// ./drm_info
+
+
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+
+int transform_frame_stream(){
+  printf("Framebuffer ID: %d\n", crtc->buffer_id);
+  printf("Resolution: %dx%d\n", crtc->width, crtc->height);
+}
+
+// no argument parsing for this first version.
+int main(int argc ,char **arc ,char **envp){
+
+  int fd;
+  drmModeRes *resources;
+  drmModeConnector *connector = NULL;
+  drmModeEncoder *encoder = NULL;
+  drmModeCrtc *crtc = NULL;
+
+  // Open the DRM device
+  fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC);
+  if (fd < 0) {
+    perror("Cannot open DRM device");
+    return -1;
+  }
+
+  // Get resources
+  resources = drmModeGetResources(fd);
+  if (!resources) {
+    perror("drmModeGetResources failed");
+    close(fd);
+    return -1;
+  }
+
+  // Find a connected connector
+  for (int i = 0; i < resources->count_connectors; i++) {
+    connector = drmModeGetConnector(fd, resources->connectors[i]);
+    if (connector->connection == DRM_MODE_CONNECTED) {
+      break;
+    }
+    drmModeFreeConnector(connector);
+  }
+
+  if (!connector || connector->connection != DRM_MODE_CONNECTED) {
+    printf("No connected connector found\n");
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Get encoder and CRTC
+  encoder = drmModeGetEncoder(fd, connector->encoder_id);
+  if (!encoder) {
+    perror("drmModeGetEncoder failed");
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  crtc = drmModeGetCrtc(fd, encoder->crtc_id);
+  if (!crtc) {
+    perror("drmModeGetCrtc failed");
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  int error;
+  error = transform_frame_stream(crtc->buffer);
+
+  // Clean up
+  drmModeFreeCrtc(crtc);
+  drmModeFreeEncoder(encoder);
+  drmModeFreeConnector(connector);
+  drmModeFreeResources(resources);
+  close(fd);
+
+  return error;
+}
diff --git a/developer/Erebus/transform_frames.c b/developer/Erebus/transform_frames.c
new file mode 100644 (file)
index 0000000..f45ce5d
--- /dev/null
@@ -0,0 +1,89 @@
+// gcc -I/usr/include/libdrm drm_info.c -o drm_info -ldrm
+// ./drm_info
+
+
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+
+int transform_frame_stream(){
+  printf("Framebuffer ID: %d\n", crtc->buffer_id);
+  printf("Resolution: %dx%d\n", crtc->width, crtc->height);
+}
+
+// no argument parsing for this first version.
+int main(int argc ,char **arc ,char **envp){
+
+  int fd;
+  drmModeRes *resources;
+  drmModeConnector *connector = NULL;
+  drmModeEncoder *encoder = NULL;
+  drmModeCrtc *crtc = NULL;
+
+  // Open the DRM device
+  fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC);
+  if (fd < 0) {
+    perror("Cannot open DRM device");
+    return -1;
+  }
+
+  // Get resources
+  resources = drmModeGetResources(fd);
+  if (!resources) {
+    perror("drmModeGetResources failed");
+    close(fd);
+    return -1;
+  }
+
+  // Find a connected connector
+  for (int i = 0; i < resources->count_connectors; i++) {
+    connector = drmModeGetConnector(fd, resources->connectors[i]);
+    if (connector->connection == DRM_MODE_CONNECTED) {
+      break;
+    }
+    drmModeFreeConnector(connector);
+  }
+
+  if (!connector || connector->connection != DRM_MODE_CONNECTED) {
+    printf("No connected connector found\n");
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Get encoder and CRTC
+  encoder = drmModeGetEncoder(fd, connector->encoder_id);
+  if (!encoder) {
+    perror("drmModeGetEncoder failed");
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  crtc = drmModeGetCrtc(fd, encoder->crtc_id);
+  if (!crtc) {
+    perror("drmModeGetCrtc failed");
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  int error;
+  error = transform_frame_stream(crtc->buffer);
+
+  // Clean up
+  drmModeFreeCrtc(crtc);
+  drmModeFreeEncoder(encoder);
+  drmModeFreeConnector(connector);
+  drmModeFreeResources(resources);
+  close(fd);
+
+  return error;
+}
diff --git a/developer/Erebus/transform_frames.c~ b/developer/Erebus/transform_frames.c~
new file mode 100644 (file)
index 0000000..dad6da8
--- /dev/null
@@ -0,0 +1,81 @@
+// gcc -I/usr/include/libdrm drm_info.c -o drm_info -ldrm
+// ./drm_info
+
+
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+int main() {
+    int fd;
+    drmModeRes *resources;
+    drmModeConnector *connector = NULL;
+    drmModeEncoder *encoder = NULL;
+    drmModeCrtc *crtc = NULL;
+
+    // Open the DRM device
+    fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC);
+    if (fd < 0) {
+        perror("Cannot open DRM device");
+        return -1;
+    }
+
+    // Get resources
+    resources = drmModeGetResources(fd);
+    if (!resources) {
+        perror("drmModeGetResources failed");
+        close(fd);
+        return -1;
+    }
+
+    // Find a connected connector
+    for (int i = 0; i < resources->count_connectors; i++) {
+        connector = drmModeGetConnector(fd, resources->connectors[i]);
+        if (connector->connection == DRM_MODE_CONNECTED) {
+            break;
+        }
+        drmModeFreeConnector(connector);
+    }
+
+    if (!connector || connector->connection != DRM_MODE_CONNECTED) {
+        printf("No connected connector found\n");
+        drmModeFreeResources(resources);
+        close(fd);
+        return -1;
+    }
+
+    // Get encoder and CRTC
+    encoder = drmModeGetEncoder(fd, connector->encoder_id);
+    if (!encoder) {
+        perror("drmModeGetEncoder failed");
+        drmModeFreeConnector(connector);
+        drmModeFreeResources(resources);
+        close(fd);
+        return -1;
+    }
+
+    crtc = drmModeGetCrtc(fd, encoder->crtc_id);
+    if (!crtc) {
+        perror("drmModeGetCrtc failed");
+        drmModeFreeEncoder(encoder);
+        drmModeFreeConnector(connector);
+        drmModeFreeResources(resources);
+        close(fd);
+        return -1;
+    }
+
+    printf("Framebuffer ID: %d\n", crtc->buffer_id);
+    printf("Resolution: %dx%d\n", crtc->width, crtc->height);
+
+    // Clean up
+    drmModeFreeCrtc(crtc);
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+
+    return 0;
+}
diff --git a/developer/cc/drm_info b/developer/cc/drm_info
new file mode 100755 (executable)
index 0000000..3722f7c
Binary files /dev/null and b/developer/cc/drm_info differ
diff --git a/developer/cc/drm_info.c b/developer/cc/drm_info.c
new file mode 100644 (file)
index 0000000..dad6da8
--- /dev/null
@@ -0,0 +1,81 @@
+// gcc -I/usr/include/libdrm drm_info.c -o drm_info -ldrm
+// ./drm_info
+
+
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+int main() {
+    int fd;
+    drmModeRes *resources;
+    drmModeConnector *connector = NULL;
+    drmModeEncoder *encoder = NULL;
+    drmModeCrtc *crtc = NULL;
+
+    // Open the DRM device
+    fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC);
+    if (fd < 0) {
+        perror("Cannot open DRM device");
+        return -1;
+    }
+
+    // Get resources
+    resources = drmModeGetResources(fd);
+    if (!resources) {
+        perror("drmModeGetResources failed");
+        close(fd);
+        return -1;
+    }
+
+    // Find a connected connector
+    for (int i = 0; i < resources->count_connectors; i++) {
+        connector = drmModeGetConnector(fd, resources->connectors[i]);
+        if (connector->connection == DRM_MODE_CONNECTED) {
+            break;
+        }
+        drmModeFreeConnector(connector);
+    }
+
+    if (!connector || connector->connection != DRM_MODE_CONNECTED) {
+        printf("No connected connector found\n");
+        drmModeFreeResources(resources);
+        close(fd);
+        return -1;
+    }
+
+    // Get encoder and CRTC
+    encoder = drmModeGetEncoder(fd, connector->encoder_id);
+    if (!encoder) {
+        perror("drmModeGetEncoder failed");
+        drmModeFreeConnector(connector);
+        drmModeFreeResources(resources);
+        close(fd);
+        return -1;
+    }
+
+    crtc = drmModeGetCrtc(fd, encoder->crtc_id);
+    if (!crtc) {
+        perror("drmModeGetCrtc failed");
+        drmModeFreeEncoder(encoder);
+        drmModeFreeConnector(connector);
+        drmModeFreeResources(resources);
+        close(fd);
+        return -1;
+    }
+
+    printf("Framebuffer ID: %d\n", crtc->buffer_id);
+    printf("Resolution: %dx%d\n", crtc->width, crtc->height);
+
+    // Clean up
+    drmModeFreeCrtc(crtc);
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+
+    return 0;
+}
diff --git a/developer/cc/modified_transform_frame_stream.c b/developer/cc/modified_transform_frame_stream.c
new file mode 100644 (file)
index 0000000..7e1a824
--- /dev/null
@@ -0,0 +1,136 @@
+
+// gcc -I/usr/include/libdrm transform_frame_stream.c -o transform_frame_stream -ldrm
+// ./transform_frame_stream
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <endian.h>
+
+// --------------------------------------------------------------------------------
+// Pixel
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t blue;
+      uint8_t green;
+      uint8_t red;
+      uint8_t alpha;
+    };
+  } PixelRGBA;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t alpha;
+      uint8_t red;
+      uint8_t green;
+      uint8_t blue;
+    };
+  } PixelRGBA;
+#else
+    #warning "Unknown __BYTE_ORDER__ found when packing a PixelRGBA."
+#endif
+
+PixelRGBA black = {.aggregate = 0xff000000};
+PixelRGBA white = {.aggregate = 0xffffffff};
+
+void PixelRGBA_structure(PixelRGBA *px, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha){
+  px->blue  = blue;
+  px->green = green;
+  px->red   = red;
+  px->alpha = alpha;
+}
+
+void PixelRGBA_destructure(PixelRGBA *px, uint8_t *red, uint8_t *green, uint8_t *blue, uint8_t *alpha){
+  *blue  = px->blue;
+  *green = px->green;
+  *red   = px->red;
+  *alpha = px->alpha;
+}
+
+PixelRGBA PixelRGBA_random(){
+  PixelRGBA px;
+  px.aggregate = rand();
+  return px;
+}
+
+// --------------------------------------------------------------------------------
+// Frame
+
+typedef struct{
+  uint32_t width;
+  uint32_t height;
+  PixelRGBA data[];
+} FrameRGBA;
+
+FrameRGBA *FrameRGBA_alloc(int width ,int height){
+  if(width == 0 || height == 0){
+    fprintf(stderr, "FrameRGBA_alloc: Invalid frame dimensions\n");
+    return NULL;
+  }
+
+  FrameRGBA *frame = (FrameRGBA *)malloc(sizeof(FrameRGBA) + width * height * sizeof(PixelRGBA));
+  if(!frame){
+    fprintf(stderr, "Failed to allocate memory for frame\n");
+    return NULL;
+  }
+
+  frame->width = width;
+  frame->height = height;
+
+  // Initialize frame with random pixels for now (could be replaced with real frame data later)
+  for(int i = 0; i < width * height; i++){
+    frame->data[i] = PixelRGBA_random();
+  }
+
+  return frame;
+}
+
+void FrameRGBA_free(FrameRGBA *frame){
+  if(frame){
+    free(frame);
+  }
+}
+
+// --------------------------------------------------------------------------------
+// Identity Transform
+
+void apply_identity_transform(FrameRGBA *frame){
+  // This is an identity transform, so nothing is changed in the frame
+  printf("Applying identity transform to frame\n");
+  // Normally, transformations would modify the frame data here
+}
+
+// --------------------------------------------------------------------------------
+// Main function to grab frames and apply identity transform
+
+int main(){
+  // Simulating grabbing a frame with fixed dimensions for now
+  int width = 640;
+  int height = 480;
+
+  FrameRGBA *frame = FrameRGBA_alloc(width, height);
+  if(!frame){
+    return EXIT_FAILURE;
+  }
+
+  // Apply identity transform (does nothing)
+  apply_identity_transform(frame);
+
+  // Simulate some output (e.g., saving frame, displaying, etc.)
+  printf("Frame processed and passed through identity transform\n");
+
+  // Clean up
+  FrameRGBA_free(frame);
+
+  return EXIT_SUCCESS;
+}
diff --git a/developer/cc/transform_frame_stream b/developer/cc/transform_frame_stream
new file mode 100755 (executable)
index 0000000..179a668
Binary files /dev/null and b/developer/cc/transform_frame_stream differ
diff --git a/developer/cc/transform_frame_stream.c b/developer/cc/transform_frame_stream.c
new file mode 100644 (file)
index 0000000..322caf6
--- /dev/null
@@ -0,0 +1,386 @@
+//
+// gcc -I/usr/include/libdrm transform_frame_stream.c -o transform_frame_stream -ldrm
+// ./transform_frame_stream
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <endian.h>
+
+// --------------------------------------------------------------------------------
+// Pixel
+
+// These pixels have hardware support ,and thus must be packed in the order
+// expected by the hardware.
+// 0xAARRGGBB
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t blue;
+      uint8_t green;
+      uint8_t red;
+      uint8_t alpha;
+    };
+  } PixelRGBA;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t alpha;
+      uint8_t red;
+      uint8_t green;
+      uint8_t blue;
+    };
+  } PixelRGBA;
+#else
+    #warning "Unknown __BYTE_ORDER__ found when packing a PixelRGBA."
+#endif
+
+PixelRGBA black = {.aggregate = 0xff000000};
+PixelRGBA white = {.aggregate = 0xffffffff};
+
+void PixelRGBA·structure
+  (
+   PixelRGBA *px 
+   ,uint8_t red 
+   ,uint8_t green 
+   ,uint8_t blue 
+   ,uint8_t alpha
+   ){
+  px->blue  = blue;
+  px->green = green;
+  px->red   = red;
+  px->alpha = alpha;
+}
+void PixelRGBA·destructure
+  (
+   PixelRGBA *px 
+   ,uint8_t *red 
+   ,uint8_t *green 
+   ,uint8_t *blue 
+   ,uint8_t *alpha
+   ){
+  *blue  = px->blue;
+  *green = px->green;
+  *red   = px->red;
+  *alpha = px->alpha;
+}
+
+PixelRGBA PixelRGBA·random(){
+  PixelRGBA px;
+  px.aggregate = rand();
+  return px;
+}
+
+
+
+// --------------------------------------------------------------------------------
+// Frame
+
+typedef struct{
+  uint32_t width;
+  uint32_t height;
+  PixelRGBA data[];
+} FrameRGBA;
+
+FrameRGBA *FrameRGBA·alloc(int width ,int height){
+  bool null_frame = false;
+
+  if( width == 0 ){
+    fprintf(stderr ,"FrameRGBA·alloc:: frame width of zero, so returning a null frame pointer\n");
+    null_frame = true;
+  }
+  if( height == 0 ){
+    fprintf(stderr ,"FrameRGBA·alloc:: frame height of zero, so returning a null frame pointer\n");
+    null_frame = true;
+  }
+  if(null_frame) return NULL;
+  
+  size_t size = sizeof(FrameRGBA) + width * height * sizeof(PixelRGBA);
+  FrameRGBA *frame = malloc(size);
+  if(!frame){
+    fprintf(stderr ,"FrameRGBA·alloc::failed to allocate frame\n");
+    return NULL;
+  }
+
+  frame->width = width;
+  frame->height = height;
+  return frame;
+}
+
+FrameRGBA *FrameRGBA·alloc_same(FrameRGBA *frame){
+  if(!frame) return NULL;
+  return FrameRGBA·alloc(frame->width ,frame->height);
+}
+
+void FrameRGBA·dealloc(FrameRGBA *frame){
+  free(frame);
+}
+
+void FrameRGBA·dimensions(FrameRGBA *frame ,uint32_t *width ,uint32_t *height){
+  if(!frame){
+    *width = 0;
+    *height = 0;
+    return;
+  }
+  *width = frame->width;
+  *height = frame->height;
+}
+
+// both frames have already been allocated
+void FrameRGBA·copy(FrameRGBA *from_frame ,FrameRGBA **to_frame_arg){
+  if( to_frame_arg == NULL ) return;
+  if(*to_frame_arg == NULL) return;
+  if( from_frame == NULL ){
+    *to_frame_arg = NULL;
+    return;
+  }
+  FrameRGBA *to_frame = *to_frame_arg;
+
+  uint32_t width ,height;
+  FrameRGBA·dimensions(from_frame ,&width ,&height);
+  if(to_frame->width < width){
+    width = to_frame->width;
+    fprintf(stderr ,"FrameRGBA·copy:: from_frame is wider than to_frame, there will be truncation\n");
+  }else if(to_frame->width > width){
+    fprintf(stderr ,"FrameRGBA·copy:: to_frame is wider, so stale uninitialized pixels will remain at the end of scan lines.\n");
+  }
+  if(to_frame->height < height){
+    height = to_frame->height;
+    fprintf(stderr ,"FrameRGBA·copy:: from_frame is taller than to_frame, there will be truncation\n");
+  }else if(to_frame->height > height){
+    fprintf(stderr ,"FrameRGBA·copy:: to_frame is taller, so stale or uninitialized scan lines will remain at the bottom of the frame.\n");
+  }
+
+  uint32_t j = 0;
+  uint32_t offset = 0;
+  do{
+    memcpy(
+           to_frame->data + offset, 
+           from_frame->data + offset, 
+           width * sizeof(PixelRGBA)
+           );
+    offset += width;
+    j++;
+  }while(j < height);
+}
+
+// if i and j walk out of frame returns NULL
+PixelRGBA *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
+  uint32_t width ,height;
+  FrameRGBA·dimensions(from_frame ,&width ,&height);
+  if(i >= width) return NULL;
+  if(j >= height) return NULL;
+  return &(from_frame->data[j * width + i]);
+}
+
+PixelRGBA FrameRGBA·read(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
+  return *FrameRGBA·access(from_frame ,i ,j);
+}
+
+void FrameRGBA·write(FrameRGBA *to_frame ,uint32_t i ,uint32_t j ,PixelRGBA px){
+  *FrameRGBA·access(to_frame ,i ,j) = px;
+}
+
+// search frame for condition where f returns a non-null pointer
+// f is handed successive pointers to pixels in the frame.
+// f is given the frame in case it needs context.
+// f is given an argument is it is difficult to curry functions in C.
+void *FrameRGBA·exist
+(
+  FrameRGBA *frame 
+  ,void *(*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
+  ,void *arg
+  ){
+
+  if(!frame) return NULL;
+
+  void *item;
+  uint32_t width ,height;
+  FrameRGBA·dimensions(frame ,&width ,&height);
+  uint32_t i = 0;
+  uint32_t j = 0;
+  do{
+    PixelRGBA *px = FrameRGBA·access(frame ,i ,j);
+    if( item=f(frame ,px ,arg) ) return item;
+
+    if( i == width - 1 ){
+      i = 0;
+      j++;
+    }else{ 
+      i++;
+    }
+  }while(j < height);
+  return NULL;
+}
+
+typedef struct{
+  void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg);
+  void *arg;
+} every_arg_t;
+
+void *every_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg0){
+  every_arg_t *ea = arg0;
+  ea->f(frame ,px ,ea->arg);
+  return NULL;
+}
+void FrameRGBA·every
+(
+  FrameRGBA *frame 
+  ,void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
+  ,void *arg
+  ){
+  every_arg_t ea = {.f = f ,.arg = arg};
+  FrameRGBA·exist(frame ,every_f ,&ea);
+}
+
+void fill_f(FrameRGBA *to_frame ,PixelRGBA *to_px ,void *arg){
+  PixelRGBA *px = arg;
+  *to_px = *px;
+}
+void FrameRGBA·fill(FrameRGBA *to_frame ,PixelRGBA *fill_px){
+  FrameRGBA·every(to_frame ,fill_f ,fill_px);
+}
+
+void FrameRGBA·fill_black(FrameRGBA *to_frame){
+  FrameRGBA·fill(to_frame ,&black);
+}
+
+void FrameRGBA·fill_white(FrameRGBA *to_frame){
+  FrameRGBA·fill(to_frame ,&white);
+}
+
+void fill_random_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg){
+  *px = PixelRGBA·random();
+}
+void FrameRGBA·fill_random(FrameRGBA *frame){
+  if(!frame) return;
+  FrameRGBA·every(frame ,fill_random_f ,NULL);
+}
+
+
+// --------------------------------------------------------------------------------
+// Transform functions
+//   Given the previous frame ,current frame ,and an argument; modifies the
+//   current frame.
+
+int identity_transform(FrameRGBA *prev_frame ,FrameRGBA *curr_frame ,void *args){
+  // no processing in the identity transform
+  FrameRGBA·copy(prev_frame ,&curr_frame);
+  return 0;  // Success
+}
+
+// --------------------------------------------------------------------------------
+// transform frame stream
+
+int transform_frame_stream(int (*transform)(FrameRGBA * ,FrameRGBA * ,void *) ,void *transform_args){
+  // Simulated screen info (would be fetched from the actual DRM system)
+  FrameRGBA *prev_frame = FrameRGBA·alloc(3840 ,2400);
+  FrameRGBA *curr_frame = FrameRGBA·alloc_same(prev_frame);
+
+  // For now ,we'll simulate grabbing the first frame by filling it with random values.
+  // In the real implementation ,you will fetch the current frame data from the DRM API.
+  uint32_t width ,height;
+  FrameRGBA·dimensions(curr_frame ,&width ,&height);
+  FrameRGBA·fill_random(curr_frame);
+
+  // Call the transform function for the first frame (identity in this case)
+  transform(prev_frame ,curr_frame ,transform_args);
+
+  // Main processing loop (simplified to one iteration for now)
+  while(1){
+    // Simulate grabbing the next frame (we just reuse the current one for this example)
+    // In real code ,you would fetch the next frame from the DRM system here.
+    FrameRGBA·fill_random(curr_frame);
+
+    // Call the transform function for each new frame
+    transform(prev_frame ,curr_frame ,transform_args);
+    FrameRGBA·copy(curr_frame ,&prev_frame);
+
+    break;  // Exit after one loop for this example (replace with continuous loop in real implementation)
+  }
+
+  // Clean up memory
+  FrameRGBA·dealloc(prev_frame);
+  FrameRGBA·dealloc(curr_frame);
+
+  return 0;  // Success
+}
+
+int main(int argc ,char **argv){
+  int fd;
+  drmModeRes *resources;
+  drmModeConnector *connector = NULL;
+  drmModeEncoder *encoder = NULL;
+  drmModeCrtc *crtc = NULL;
+
+  // Open the DRM device
+  fd = open("/dev/dri/card2",O_RDWR | O_CLOEXEC);
+  if(fd < 0){
+    perror("Cannot open DRM device");
+    return -1;
+  }
+
+  // Get resources
+  resources = drmModeGetResources(fd);
+  if(!resources){
+    perror("drmModeGetResources failed");
+    close(fd);
+    return -1;
+  }
+
+  // Find a connected connector
+  for(int i = 0; i < resources->count_connectors; i++){
+    connector = drmModeGetConnector(fd ,resources->connectors[i]);
+    if(connector->connection == DRM_MODE_CONNECTED){
+      break;
+    }
+    drmModeFreeConnector(connector);
+  }
+
+  if(!connector || connector->connection != DRM_MODE_CONNECTED){
+    printf("No connected connector found\n");
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Get encoder and CRTC
+  encoder = drmModeGetEncoder(fd ,connector->encoder_id);
+  if(!encoder){
+    perror("drmModeGetEncoder failed");
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  crtc = drmModeGetCrtc(fd ,encoder->crtc_id);
+  if(!crtc){
+    perror("drmModeGetCrtc failed");
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Call transform_frame_stream with identity transform
+  transform_frame_stream(identity_transform ,NULL);
+
+  // Clean up
+  drmModeFreeCrtc(crtc);
+  drmModeFreeEncoder(encoder);
+  drmModeFreeConnector(connector);
+  drmModeFreeResources(resources);
+  close(fd);
+
+  return 0;
+}
diff --git a/developer/cc/transform_frame_stream_2.c b/developer/cc/transform_frame_stream_2.c
new file mode 100644 (file)
index 0000000..322caf6
--- /dev/null
@@ -0,0 +1,386 @@
+//
+// gcc -I/usr/include/libdrm transform_frame_stream.c -o transform_frame_stream -ldrm
+// ./transform_frame_stream
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <endian.h>
+
+// --------------------------------------------------------------------------------
+// Pixel
+
+// These pixels have hardware support ,and thus must be packed in the order
+// expected by the hardware.
+// 0xAARRGGBB
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t blue;
+      uint8_t green;
+      uint8_t red;
+      uint8_t alpha;
+    };
+  } PixelRGBA;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t alpha;
+      uint8_t red;
+      uint8_t green;
+      uint8_t blue;
+    };
+  } PixelRGBA;
+#else
+    #warning "Unknown __BYTE_ORDER__ found when packing a PixelRGBA."
+#endif
+
+PixelRGBA black = {.aggregate = 0xff000000};
+PixelRGBA white = {.aggregate = 0xffffffff};
+
+void PixelRGBA·structure
+  (
+   PixelRGBA *px 
+   ,uint8_t red 
+   ,uint8_t green 
+   ,uint8_t blue 
+   ,uint8_t alpha
+   ){
+  px->blue  = blue;
+  px->green = green;
+  px->red   = red;
+  px->alpha = alpha;
+}
+void PixelRGBA·destructure
+  (
+   PixelRGBA *px 
+   ,uint8_t *red 
+   ,uint8_t *green 
+   ,uint8_t *blue 
+   ,uint8_t *alpha
+   ){
+  *blue  = px->blue;
+  *green = px->green;
+  *red   = px->red;
+  *alpha = px->alpha;
+}
+
+PixelRGBA PixelRGBA·random(){
+  PixelRGBA px;
+  px.aggregate = rand();
+  return px;
+}
+
+
+
+// --------------------------------------------------------------------------------
+// Frame
+
+typedef struct{
+  uint32_t width;
+  uint32_t height;
+  PixelRGBA data[];
+} FrameRGBA;
+
+FrameRGBA *FrameRGBA·alloc(int width ,int height){
+  bool null_frame = false;
+
+  if( width == 0 ){
+    fprintf(stderr ,"FrameRGBA·alloc:: frame width of zero, so returning a null frame pointer\n");
+    null_frame = true;
+  }
+  if( height == 0 ){
+    fprintf(stderr ,"FrameRGBA·alloc:: frame height of zero, so returning a null frame pointer\n");
+    null_frame = true;
+  }
+  if(null_frame) return NULL;
+  
+  size_t size = sizeof(FrameRGBA) + width * height * sizeof(PixelRGBA);
+  FrameRGBA *frame = malloc(size);
+  if(!frame){
+    fprintf(stderr ,"FrameRGBA·alloc::failed to allocate frame\n");
+    return NULL;
+  }
+
+  frame->width = width;
+  frame->height = height;
+  return frame;
+}
+
+FrameRGBA *FrameRGBA·alloc_same(FrameRGBA *frame){
+  if(!frame) return NULL;
+  return FrameRGBA·alloc(frame->width ,frame->height);
+}
+
+void FrameRGBA·dealloc(FrameRGBA *frame){
+  free(frame);
+}
+
+void FrameRGBA·dimensions(FrameRGBA *frame ,uint32_t *width ,uint32_t *height){
+  if(!frame){
+    *width = 0;
+    *height = 0;
+    return;
+  }
+  *width = frame->width;
+  *height = frame->height;
+}
+
+// both frames have already been allocated
+void FrameRGBA·copy(FrameRGBA *from_frame ,FrameRGBA **to_frame_arg){
+  if( to_frame_arg == NULL ) return;
+  if(*to_frame_arg == NULL) return;
+  if( from_frame == NULL ){
+    *to_frame_arg = NULL;
+    return;
+  }
+  FrameRGBA *to_frame = *to_frame_arg;
+
+  uint32_t width ,height;
+  FrameRGBA·dimensions(from_frame ,&width ,&height);
+  if(to_frame->width < width){
+    width = to_frame->width;
+    fprintf(stderr ,"FrameRGBA·copy:: from_frame is wider than to_frame, there will be truncation\n");
+  }else if(to_frame->width > width){
+    fprintf(stderr ,"FrameRGBA·copy:: to_frame is wider, so stale uninitialized pixels will remain at the end of scan lines.\n");
+  }
+  if(to_frame->height < height){
+    height = to_frame->height;
+    fprintf(stderr ,"FrameRGBA·copy:: from_frame is taller than to_frame, there will be truncation\n");
+  }else if(to_frame->height > height){
+    fprintf(stderr ,"FrameRGBA·copy:: to_frame is taller, so stale or uninitialized scan lines will remain at the bottom of the frame.\n");
+  }
+
+  uint32_t j = 0;
+  uint32_t offset = 0;
+  do{
+    memcpy(
+           to_frame->data + offset, 
+           from_frame->data + offset, 
+           width * sizeof(PixelRGBA)
+           );
+    offset += width;
+    j++;
+  }while(j < height);
+}
+
+// if i and j walk out of frame returns NULL
+PixelRGBA *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
+  uint32_t width ,height;
+  FrameRGBA·dimensions(from_frame ,&width ,&height);
+  if(i >= width) return NULL;
+  if(j >= height) return NULL;
+  return &(from_frame->data[j * width + i]);
+}
+
+PixelRGBA FrameRGBA·read(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
+  return *FrameRGBA·access(from_frame ,i ,j);
+}
+
+void FrameRGBA·write(FrameRGBA *to_frame ,uint32_t i ,uint32_t j ,PixelRGBA px){
+  *FrameRGBA·access(to_frame ,i ,j) = px;
+}
+
+// search frame for condition where f returns a non-null pointer
+// f is handed successive pointers to pixels in the frame.
+// f is given the frame in case it needs context.
+// f is given an argument is it is difficult to curry functions in C.
+void *FrameRGBA·exist
+(
+  FrameRGBA *frame 
+  ,void *(*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
+  ,void *arg
+  ){
+
+  if(!frame) return NULL;
+
+  void *item;
+  uint32_t width ,height;
+  FrameRGBA·dimensions(frame ,&width ,&height);
+  uint32_t i = 0;
+  uint32_t j = 0;
+  do{
+    PixelRGBA *px = FrameRGBA·access(frame ,i ,j);
+    if( item=f(frame ,px ,arg) ) return item;
+
+    if( i == width - 1 ){
+      i = 0;
+      j++;
+    }else{ 
+      i++;
+    }
+  }while(j < height);
+  return NULL;
+}
+
+typedef struct{
+  void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg);
+  void *arg;
+} every_arg_t;
+
+void *every_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg0){
+  every_arg_t *ea = arg0;
+  ea->f(frame ,px ,ea->arg);
+  return NULL;
+}
+void FrameRGBA·every
+(
+  FrameRGBA *frame 
+  ,void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
+  ,void *arg
+  ){
+  every_arg_t ea = {.f = f ,.arg = arg};
+  FrameRGBA·exist(frame ,every_f ,&ea);
+}
+
+void fill_f(FrameRGBA *to_frame ,PixelRGBA *to_px ,void *arg){
+  PixelRGBA *px = arg;
+  *to_px = *px;
+}
+void FrameRGBA·fill(FrameRGBA *to_frame ,PixelRGBA *fill_px){
+  FrameRGBA·every(to_frame ,fill_f ,fill_px);
+}
+
+void FrameRGBA·fill_black(FrameRGBA *to_frame){
+  FrameRGBA·fill(to_frame ,&black);
+}
+
+void FrameRGBA·fill_white(FrameRGBA *to_frame){
+  FrameRGBA·fill(to_frame ,&white);
+}
+
+void fill_random_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg){
+  *px = PixelRGBA·random();
+}
+void FrameRGBA·fill_random(FrameRGBA *frame){
+  if(!frame) return;
+  FrameRGBA·every(frame ,fill_random_f ,NULL);
+}
+
+
+// --------------------------------------------------------------------------------
+// Transform functions
+//   Given the previous frame ,current frame ,and an argument; modifies the
+//   current frame.
+
+int identity_transform(FrameRGBA *prev_frame ,FrameRGBA *curr_frame ,void *args){
+  // no processing in the identity transform
+  FrameRGBA·copy(prev_frame ,&curr_frame);
+  return 0;  // Success
+}
+
+// --------------------------------------------------------------------------------
+// transform frame stream
+
+int transform_frame_stream(int (*transform)(FrameRGBA * ,FrameRGBA * ,void *) ,void *transform_args){
+  // Simulated screen info (would be fetched from the actual DRM system)
+  FrameRGBA *prev_frame = FrameRGBA·alloc(3840 ,2400);
+  FrameRGBA *curr_frame = FrameRGBA·alloc_same(prev_frame);
+
+  // For now ,we'll simulate grabbing the first frame by filling it with random values.
+  // In the real implementation ,you will fetch the current frame data from the DRM API.
+  uint32_t width ,height;
+  FrameRGBA·dimensions(curr_frame ,&width ,&height);
+  FrameRGBA·fill_random(curr_frame);
+
+  // Call the transform function for the first frame (identity in this case)
+  transform(prev_frame ,curr_frame ,transform_args);
+
+  // Main processing loop (simplified to one iteration for now)
+  while(1){
+    // Simulate grabbing the next frame (we just reuse the current one for this example)
+    // In real code ,you would fetch the next frame from the DRM system here.
+    FrameRGBA·fill_random(curr_frame);
+
+    // Call the transform function for each new frame
+    transform(prev_frame ,curr_frame ,transform_args);
+    FrameRGBA·copy(curr_frame ,&prev_frame);
+
+    break;  // Exit after one loop for this example (replace with continuous loop in real implementation)
+  }
+
+  // Clean up memory
+  FrameRGBA·dealloc(prev_frame);
+  FrameRGBA·dealloc(curr_frame);
+
+  return 0;  // Success
+}
+
+int main(int argc ,char **argv){
+  int fd;
+  drmModeRes *resources;
+  drmModeConnector *connector = NULL;
+  drmModeEncoder *encoder = NULL;
+  drmModeCrtc *crtc = NULL;
+
+  // Open the DRM device
+  fd = open("/dev/dri/card2",O_RDWR | O_CLOEXEC);
+  if(fd < 0){
+    perror("Cannot open DRM device");
+    return -1;
+  }
+
+  // Get resources
+  resources = drmModeGetResources(fd);
+  if(!resources){
+    perror("drmModeGetResources failed");
+    close(fd);
+    return -1;
+  }
+
+  // Find a connected connector
+  for(int i = 0; i < resources->count_connectors; i++){
+    connector = drmModeGetConnector(fd ,resources->connectors[i]);
+    if(connector->connection == DRM_MODE_CONNECTED){
+      break;
+    }
+    drmModeFreeConnector(connector);
+  }
+
+  if(!connector || connector->connection != DRM_MODE_CONNECTED){
+    printf("No connected connector found\n");
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Get encoder and CRTC
+  encoder = drmModeGetEncoder(fd ,connector->encoder_id);
+  if(!encoder){
+    perror("drmModeGetEncoder failed");
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  crtc = drmModeGetCrtc(fd ,encoder->crtc_id);
+  if(!crtc){
+    perror("drmModeGetCrtc failed");
+    drmModeFreeEncoder(encoder);
+    drmModeFreeConnector(connector);
+    drmModeFreeResources(resources);
+    close(fd);
+    return -1;
+  }
+
+  // Call transform_frame_stream with identity transform
+  transform_frame_stream(identity_transform ,NULL);
+
+  // Clean up
+  drmModeFreeCrtc(crtc);
+  drmModeFreeEncoder(encoder);
+  drmModeFreeConnector(connector);
+  drmModeFreeResources(resources);
+  close(fd);
+
+  return 0;
+}
diff --git a/developer/developer b/developer/developer
new file mode 100644 (file)
index 0000000..e69de29