From: Thomas Walker Lynch Date: Thu, 19 Sep 2024 13:47:02 +0000 (+0000) Subject: adds index type, refactors frame X-Git-Url: https://git.reasoningtechnology.com/style/static/git-favicon.png?a=commitdiff_plain;h=42a241755becb06e8e1dc0478c015a6dc801e491;p=noflash adds index type, refactors frame --- diff --git a/developer/cc/Frame.c b/developer/cc/Frame.c index 91b18d5..106d0ac 100644 --- a/developer/cc/Frame.c +++ b/developer/cc/Frame.c @@ -1,157 +1,206 @@ /* - A display frame type. + The Frame type. - Frames to be read or written are passed by reference. - - Functions that allocate a new frame typically return a reference to the - newly allocated frame. - - Functions that accept an argument for holding an newly allocated frame, that - argument will be a pointer to the frame reference. E.g. f(Frame **generated), - *generated = NULL or *generated = malloc(...). + A size annotated 2D array of fixed sized elements. */ #include #include #include -#include -#include //-------------------------------------------------------------------------------- -// Abstract Frame Interface for any pixel type +// Frame instance typedef struct { - void (*alloc)(void *frame_instance, int width, int height); - void (*alloc_external_data)(void *frame_instance, int width, int height, void *data); - void (*dealloc)(void *frame_instance); - void (*copy)(void *from_frame, void *to_frame); - void (*read)(void *frame, int i, int j, void *result_px); - void (*write)(void *frame, int i, int j, const void *px); - void (*fill)(void *frame, const void *px); - void (*every)(void *frame, void (*f)(void *frame, void *px, void *arg), void *arg); -} Frame; + uint32_t pixel_size; + Index32·Instance data_array_bound; // array nx by ny + void *data; + void *meta_data; // whatever the programmer wants it to be +} Frame·Instance; -//-------------------------------------------------------------------------------- -// FrameGeneric instance state +typedef void* (*PixelPredicate)(Frame *frame ,void *pixel ,Index32·Instance index ,void *arg); -typedef struct { - uint32_t width; - uint32_t height; - Pixel *pixel_interface; // Pointer to the Pixel interface - void *data; // Pointer to pixel data (generic) - void *meta_data; // Optional metadata -} FrameGeneric·Instance; //-------------------------------------------------------------------------------- -// FrameGeneric interface +// Frame interface implementation + +// Allocate a frame and its element data +Frame·Instance *Frame·alloc(Index32·Instance data_array_bound ,uint32_t pixel_size ,void *metadata) { + // Check if either x or y is zero in the data_array_bound, which is not allowed + if( Index32·equal_or( Index32·structure(0, 0) ,data_array_bound) ){ + fprintf(stderr ,"Frame·alloc:: zero x or zero y in data_array_bound not supported\n"); + return NULL; + } -// Allocate a frame and its pixel data -void FrameGeneric·alloc(void *frame_instance, int width, int height) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - if (width == 0 || height == 0) { - fprintf(stderr, "FrameGeneric·alloc:: invalid dimensions\n"); - return; + // Allocate memory for the frame instance + Frame·Instance *frame = malloc( sizeof(Frame·Instance) ); + if( !frame ){ + fprintf(stderr ,"Frame·alloc:: malloc() failed to allocate frame instance\n"); + return NULL; } - frame->width = width; - frame->height = height; - size_t pixel_size = frame->pixel_interface->size(); - frame->data = malloc(width * height * pixel_size); - if (!frame->data) { - fprintf(stderr, "FrameGeneric·alloc:: failed to allocate pixel data\n"); + // Set frame's data_array_bound and pixel_size + frame->data_array_bound = data_array_bound; + frame->pixel_size = pixel_size; + + // Calculate total size for the data array and allocate it + size_t data_size; + if( !Index32·bounded_size(data_array_bound ,pixel_size ,&data_size) ){ + fprintf(stderr ,"Frame·alloc:: bounded size too large for frame data array\n"); + free(frame); + return NULL; + } + + frame->data = malloc(data_size); + if( !frame->data ){ + fprintf(stderr ,"Frame·alloc:: malloc() failed to allocate frame data array\n"); + free(frame); + return NULL; } + + // Initialize metadata if provided + frame->meta_data = metadata; + + return frame; } -// Allocate a frame with external pixel data -void FrameGeneric·alloc_external_data(void *frame_instance, int width, int height, void *data) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - frame->width = width; - frame->height = height; - frame->data = data; // External data passed in +// Allocate a frame with external element data +void Frame·alloc_external_data(Frame·Instance *frame ,Index32·Instance data_array_bound ,uint32_t pixel_size ,void *external_data) { + // Check if either x or y in the data_array_bound is zero, which is not allowed + if( Index32·equal_or( Index32·structure(0, 0) ,data_array_bound) ){ + fprintf(stderr ,"Frame·alloc_external_data:: zero x or zero y in data_array_bound not supported\n"); + return; + } + + // Set the frame's bounds and pixel size + frame->data_array_bound = data_array_bound; + frame->pixel_size = pixel_size; + + // Assign the external data pointer to the frame + frame->data = external_data; } + // Deallocate the frame -void FrameGeneric·dealloc(void *frame_instance) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - if (frame->data) { +void Frame·dealloc(Frame *frame_instance) { + Frame·Instance *frame = (Frame·Instance *)frame_instance; + if( frame->data ){ free(frame->data); frame->data = NULL; } + free(frame); } -// Copy one frame to another -void FrameGeneric·copy(void *from_frame_instance, void *to_frame_instance) { - FrameGeneric·Instance *from_frame = (FrameGeneric·Instance *)from_frame_instance; - FrameGeneric·Instance *to_frame = (FrameGeneric·Instance *)to_frame_instance; - - if (to_frame->width != from_frame->width || to_frame->height != from_frame->height) { - fprintf(stderr, "FrameGeneric·copy:: dimensions mismatch\n"); - return; +----- +// Access element at (i, j) +void* Frame·access(Frame *frame_instance ,int i ,int j) { + Frame·Instance *frame = (Frame·Instance *)frame_instance; + if( i >= frame->width || j >= frame->height ){ + fprintf(stderr ,"Frame·access:: index out of bounds\n"); + return NULL; } - - size_t pixel_size = from_frame->pixel_interface->size(); - memcpy(to_frame->data, from_frame->data, from_frame->width * from_frame->height * pixel_size); + + return (char*)frame->data + (j * frame->width + i) * frame->element_size; } -// Read a pixel from the frame -void FrameGeneric·read(void *frame_instance, int i, int j, void *result_px) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - if (i >= frame->width || j >= frame->height) { - fprintf(stderr, "FrameGeneric·read:: index out of bounds\n"); - return; +void* Frame·access(Frame·instance *frame ,Index32·Instance i){ + size_t offset; + if( !Index32·linear_offset(i ,n ,frame->pixel_size ,offset) ){ + return NULL; } - - size_t pixel_size = frame->pixel_interface->size(); - void *px = (char *)frame->data + (j * frame->width + i) * pixel_size; - memcpy(result_px, px, pixel_size); + return (char*)(frame->data) + offset; } -// Write a pixel to the frame -void FrameGeneric·write(void *frame_instance, int i, int j, const void *px) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - if (i >= frame->width || j >= frame->height) { - fprintf(stderr, "FrameGeneric·write:: index out of bounds\n"); - return; - } - - size_t pixel_size = frame->pixel_interface->size(); - void *dst_px = (char *)frame->data + (j * frame->width + i) * pixel_size; - memcpy(dst_px, px, pixel_size); +bool Frame·read(Frame·instance *frame ,Index32·Instance i ,void *pixel){ + void *pixel_in_frame = Frame·access(frame ,i); + if( !pixel_in_frame ) return false; + memcpy(pixel ,pixel_in_frame ,((Frame·Instance *)frame)->pixel_size); + return true; } -// Fill the frame with a specific pixel -void FrameGeneric·fill(void *frame_instance, const void *px) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - for (int j = 0; j < frame->height; j++) { - for (int i = 0; i < frame->width; i++) { - FrameGeneric·write(frame_instance, i, j, px); - } - } +bool Frame·write(Frame·Instance *frame ,Index32·Instance i ,const void *pixel){ + void *pixel_in_frame = Frame·access(frame ,i); + if( !pixel_in_frame ) return false; + memcpy(pixel_in_frame ,pixel ,frame->pixel_size); + return true; } -// Apply a function to every pixel in the frame -void FrameGeneric·every(void *frame_instance, void (*f)(void *frame, void *px, void *arg), void *arg) { - FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance; - size_t pixel_size = frame->pixel_interface->size(); - for (int j = 0; j < frame->height; j++) { - for (int i = 0; i < frame->width; i++) { - void *px = (char *)frame->data + (j * frame->width + i) * pixel_size; - f(frame_instance, px, arg); + +// Search for an element where f returns non-null (exist pattern) +void* Frame·exist(Frame·Instance *frame ,Frame·PixelPredicate f ,void *arg) { + if (!frame || !f) return NULL; + + Index32·Instance index = Index32·origin; // Start from (0, 0) + Index32·Instance bound = frame->data_array_bound; + + do{ + void *pixel = Frame·access(frame ,index); + if( pixel ){ + void *result = f(frame ,pixel ,index ,arg); + if( result ) return result; } - } + }while( Index32·increment(&index ,bound ,frame->pixel_size) ); + + return NULL; +} + +typedef struct { + Frame·PixelPredicate f; // PixelPredicate type for the function + void *arg; // User-provided metadata +} Frame·every_arg_t; + +void *Frame·every_1(Frame *frame ,void *pixel ,Index32·Instance index ,void *arg0) { + Frame·every_arg_t *ea = (Frame·every_arg_t *)arg0; + ea->f(frame ,pixel ,index ,ea->arg); + return NULL; // Return NULL for `every` +} + +void Frame·every(Frame *frame ,Frame·PixelPredicate f ,void *arg) { + Frame·every_arg_t ea = {.f = f ,.arg = arg}; + Frame·exist(frame ,Frame·every_1 ,&ea); +} + +typedef struct { + Frame·PixelPredicate f; // PixelPredicate type for the function + void *arg; // User-provided metadata +} Frame·all_arg_t; + +void *Frame·all_1(Frame *frame ,void *pixel ,Index32·Instance index ,void *arg0) { + Frame·all_arg_t *aa = (Frame·all_arg_t *)arg0; + if( !aa->f(frame ,pixel ,index ,aa->arg) ) return pixel; // If a pixel doesn't satisfy the predicate, return it + return NULL; +} + +bool Frame·all(Frame *frame ,Frame·PixelPredicate f ,void *arg) { + Frame·all_arg_t aa = {.f = f ,.arg = arg}; + return Frame·exist(frame ,Frame·all_1 ,&aa) == NULL; // If `exist` returns NULL, all elements satisfied the predicate +} + +// Fill the frame with a specific pixel +void *Frame·fill_1(Frame *frame ,void *pixel_in_frame ,Index32·Instance index ,void *arg) { + // `arg` contains the pixel value to fill with + const void *fill_pixel = arg; + memcpy(pixel_in_frame ,fill_pixel ,((Frame·Instance *)frame)->pixel_size); + return NULL; // Return NULL to indicate that we don't stop the loop (like `Frame·every`) +} +void Frame·fill(Frame *frame_instance ,const void *pixel) { + Frame·every(frame_instance ,Frame·fill_1 ,(void*)pixel); } //-------------------------------------------------------------------------------- -// FrameGeneric interface instance - -Frame FrameGeneric = { - .alloc = FrameGeneric·alloc - ,.alloc_external_data = FrameGeneric·alloc_external_data - ,.dealloc = FrameGeneric·dealloc - ,.copy = FrameGeneric·copy - ,.read = FrameGeneric·read - ,.write = FrameGeneric·write - ,.fill = FrameGeneric·fill - ,.every = FrameGeneric·every +// Frame interface instance + +Frame Frame = { + .alloc = Frame·alloc + ,.alloc_external_data = Frame·alloc_external_data + ,.dealloc = Frame·dealloc + ,.copy = Frame·copy + ,.access = Frame·access + ,.read = Frame·read + ,.write = Frame·write + ,.exist = Frame·exist + ,.every = Frame·every + ,.all = Frame·all + ,.fill = Frame·fill }; diff --git a/developer/cc/Index.c b/developer/cc/Index.c new file mode 100644 index 0000000..4d58c43 --- /dev/null +++ b/developer/cc/Index.c @@ -0,0 +1,281 @@ +/* + 32 bit 2D index, Used to index into the frame's data array. + +*/ + +//-------------------------------------------------------------------------------- +// instance + +#include +#include + +typedef struct { + uint32_t x; + uint32_t y; +} Index32·Instance; + +Index32·Instance Index32·origin = {0 ,0}; +Index32·Instance Index32·unit_x = {1 ,0}; +Index32·Instance Index32·unit_y = {0 ,1}; +Index32·Instance Index32·unit = {1 ,1}; +Index32·Instance Index32·max = (UINT32_max ,UINT32_max); + +Index32·Instance Index32·structure(uint32_t x ,uint32_t y){ + Index32·Instance i = {x ,y}; + return i; +} + +void Index32·destructure(Index32·Instance i ,uint32_t *x ,uint32_t *y){ + *x = i.x; + *y = i.y; +} + +void Index32·destructure_64(Index32·Instance i ,uint64_t *x ,uint64_t *y){ + *x = i.x; + *y = i.y; +} + + +//-------------------------------------------------------------------------------- +// relative location predicates + +// i is left of n (x-coordinate comparison) +bool Index32·i_left_of_n(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix < nx; +} + +// i is right of n (x-coordinate comparison) +bool Index32·i_right_of_n(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix > nx; +} + +// i is above n (y-coordinate comparison) +bool Index32·i_above_n(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return iy < ny; +} + +// i is below n (y-coordinate comparison) +bool Index32·i_below_n(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return iy > ny; +} + +// i is at the same x-coordinate as n +bool Index32·same_x(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix == nx; +} + +// i is at the same y-coordinate as n +bool Index32·same_y(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return iy == ny; +} + +//-------------------------------------------------------------------------------- +// comparison prediates + +// Check if two Index32 instances are equal +bool Index32·equal(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix == nx && iy == ny; +} + +// Check if either coordinate (x or y) is equal +bool Index32·equal_or(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix == nx || iy == ny; +} + +// Check if both coordinates are less than the corresponding coordinates of n +bool Index32·lesser(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix < nx && iy < ny; +} + +// Check if either coordinate is less than the corresponding coordinate of n +bool Index32·lesser_or(Index32·Instance i ,Index32·Instance n){ + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + return ix < nx || iy < ny; +} + + + +/* 1. If the length of x is not a multiple of delta, increment skips the last + (partial) element on a line. + + 2. xn boundary first approach + + xn is <= xmax, so if we pass xmax, we also pass xn (but not the converse). + + for all x0, we derive the unknown x1: + x1 = x0 + delta + + if x0 + delta > xmax there is an ov. + => if xmax - delta < x0 there is an ov, so: ov protected test: + + beyond_xn = ((UNINT32_MAX - delta) < x0) || (x0 + delta > xn); + + 3. xn boundary cleaner more intuitive approach (xn - x0 concept proposed by Saigen) + + x0 + delta >= xn ; this test can overflow + delta >= xn - x0 ; we expect that x0 < xn, but both values were passed in. + ; we protect the subtract + + beyond_xn = (x0 >= xn) || (delta >= xn - x0) + + ^ first term is where the user passed in an x0 that is already off the + scan line. Second term is the ov safe x0 +delta >= xn test. + + 4. yn boundary + + y0 + 1 >= yn ; can overlow, note also y0 was passed in. + +*/ +bool Index32·increment(Index32·Instance *i ,Index32·Instance n ,uint32_t delta) { + uint32_t x0 ,y0 ,x1 ,y1 ,xn ,yn; + Index32·destructure(*i ,&x0 ,&y0); + Index32·destructure(n ,&xn ,&yn); + + if(y0 >= yn) return false; + bool inc_beyond_xn= (x0 >= xn) || (delta > xn - x0); + + if(inc_beyond_xn){ + if(y0 + 1 >= yn) return false; + x1 = 0; + y1 = y0 + 1; + }else{ + x1 = x0 + delta; + y1 = y0; + } + + *i = Index32·structure(x1 ,y1); + return true; +} + +/* + Sum two vectors. No clipping to the frame. Returns false if the computed + result would overflow the result representation. + + ... + + Suppose we were using UINT4 numbers, then UINT4_MAX would be 15. Now if a + + b > 15 there is an overlow, such a computation would have to be done in a + promoted sized arithmetic. However, note, 15 - a, in 4 bit arithmetic will + always be representable. Hence a + b > 15 ==> b > 15 - a, which can also be + stated as 15 - a < b. + +*/ +bool Index32·plus(Index32·Instance a ,Index32·Instance b ,Index32·Instance *c) { + uint32_t a_x ,a_y ,b_x ,b_y; + + // Destructure a and b to get their x and y values + Index32·destructure(a ,&a_x ,&a_y); + Index32·destructure(b ,&b_x ,&b_y); + + // Check for overflow + if( (UINT32_MAX - a_x) < b_x ) return false; + if( (UINT32_MAX - a_y) < b_y ) return false; + + // Structure the result and assign to c + *c = Index32·structure(a_x + b_x ,a_y + b_y); + + return true; // Successful addition without overflow +} + +/* + Sum two vectors, returns false if the sum does not fit in the frame. + + This function is overflow and underflow safe. +*/ +bool Index32·plus_clipped(Index32·Instance base ,Index32·Instance delta ,Index32·Instance n ,Index32·Instance *result){ + Index32·Instance sum; + if( !Index32·plus(base ,delta ,&sum) ) return false; + if( !Index32·lesser(sum ,n) ) return false; + *result = sum; + return true; +} + +// Compute the number of bytes in 2D array with exclusive bound of n. +bool Index32·bounded_size(Index32·Instance n ,uint32_t element_size ,size_t *result_area) { + uint64_t x = n.x; + uint64_t y = n.y; + + // Count bits in x ,y, and element_size + int x_bits = count_bits(x); + int y_bits = count_bits(y); + int elem_bits = count_bits(element_size); + + // Determine the nber of bits in SIZE_MAX + int max_bits = count_bits(SIZE_MAX); + + // If the sum of the bits exceeds the number of bits in size_t, return false (overflow) + if (x_bits + y_bits + elem_bits > max_bits) { + return false; // Overflow detected + } + + // Safe to calculate the area + *result_area = (size_t)x * (size_t)y * element_size; + return true; // Successful computation +} + +#include +#include +#include + +typedef struct { + uint32_t x; + uint32_t y; +} Index32·Instance; + +// Calculates linear offset from the frame origin to index `i`, clipped to `n` +bool Index32·linear_offset(Index32·Instance i ,Index32·Instance n ,uint32_t element_size ,size_t *offset) { + if( !Index32·lesser(i ,n) ) return false; + + uint32_t ix ,iy ,nx ,ny; + Index32·destructure(i ,&ix ,&iy); + Index32·destructure(n ,&nx ,&ny); + + *offset = (size_t)(iy * nx + ix) * element_size; + + return true; +} + +// Example destructure function (for reference) +void Index32·destructure(Index32·Instance index ,uint32_t *x ,uint32_t *y) { + *x = index.x; + *y = index.y; +} diff --git a/developer/cc/Pixel_2.c b/developer/cc/Pixel_2.c deleted file mode 100644 index 400665d..0000000 --- a/developer/cc/Pixel_2.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - Pixel types - - Currently implements only RGBA, which are specified by the hardware; hence - they must be packed as: 0xAARRGGBB. - - For the sake of consistency, pixels are always passed by reference. Functions - that generate new pixels return the new pixel by value. -*/ - -#include -#include -#include // for rand() -#include -#include // for seeding rand() - -//-------------------------------------------------------------------------------- -// Pixel Abstract Interface - -typedef struct { - void* (*random)(); - void (*copy_from_uint32)(void *px0 ,uint32_t from_uint32); - bool (*equal)(const void *px0 ,const void *px1); - void* (*blend)(const void *px0 ,const void *px1); - void* (*invert)(const void *px0); - void* (*map_to_grayscale)(const void *px0); - void* (*black)(); - void* (*white)(); - void* (*neutral)(); -} Pixel; - -//-------------------------------------------------------------------------------- -// instance state for RGBA pixel type - -#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·Instance; -#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·Instance; -#else - #warning "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors." -#endif - -// Initialize a Pixel given the individual field values. -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; -} - -// Decompose a Pixel into its individual color components. -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; -} - -//-------------------------------------------------------------------------------- -// interface for PixelRGBA type - -// Generate a black pixel. -void* PixelRGBA·black(){ - PixelRGBA *px = malloc(sizeof(PixelRGBA)); - if( px ) px->aggregate = 0xff000000; - return px; -} - -// Generate a white pixel. -void* PixelRGBA·white(){ - PixelRGBA *px = malloc(sizeof(PixelRGBA)); - if( px ) px->aggregate = 0xffffffff; - return px; -} - -// Generate a neutral pixel. -void* PixelRGBA·neutral(){ - PixelRGBA *px = malloc(sizeof(PixelRGBA)); - if( px ) px->aggregate = 0x80808080; - return px; -} - -// Generate a random pixel. -void* PixelRGBA·random(){ - PixelRGBA *px = malloc(sizeof(PixelRGBA)); - if( px == NULL ) return NULL; - - #if RAND_MAX < 0xFFFFFFFF - px->aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF); - #else - px->aggregate = (uint32_t)rand(); - #endif - return px; -} - -// Copy from a uint32_t value to a PixelRGBA. -void PixelRGBA·copy_from_uint32(void *instance ,uint32_t from_uint32){ - PixelRGBA *to_px = (PixelRGBA *)instance; - to_px->aggregate = from_uint32; -} - -// Check if two pixels are equal. -bool PixelRGBA·equal(const void *px0 ,const void *px1){ - return ((PixelRGBA *)px0)->aggregate == ((PixelRGBA *)px1)->aggregate; -} - -// Blend two pixels. -void* PixelRGBA·blend(const void *px0 ,const void *px1){ - PixelRGBA *result = malloc(sizeof(PixelRGBA)); - if( !result ) return NULL; - - const PixelRGBA *p0 = (const PixelRGBA *)px0; - const PixelRGBA *p1 = (const PixelRGBA *)px1; - - result->alpha = (p0->alpha + p1->alpha) / 2; - result->red = (p0->red + p1->red) / 2; - result->green = (p0->green + p1->green) / 2; - result->blue = (p0->blue + p1->blue) / 2; - - return result; -} - -// Invert the colors of a pixel. -void* PixelRGBA·invert(const void *px0){ - PixelRGBA *result = malloc(sizeof(PixelRGBA)); - if( !result ) return NULL; - - const PixelRGBA *p = (const PixelRGBA *)px0; - result->red = 255 - p->red; - result->green = 255 - p->green; - result->blue = 255 - p->blue; - result->alpha = p->alpha; // Alpha remains unchanged - - return result; -} - -// Convert a pixel to grayscale. -void* PixelRGBA·map_to_grayscale(const void *px0){ - PixelRGBA *result = malloc(sizeof(PixelRGBA)); - if( !result ) return NULL; - - const PixelRGBA *p = (const PixelRGBA *)px0; - uint8_t gray_level = (uint8_t)(0.299 * p->red + 0.587 * p->green + 0.114 * p->blue); - - result->red = gray_level; - result->green = gray_level; - result->blue = gray_level; - result->alpha = p->alpha; - - return result; -} - -//-------------------------------------------------------------------------------- -// PixelRGBA interface instance - -Pixel PixelRGBA·Interface = { - .random = PixelRGBA·random - ,.copy_from_uint32 = PixelRGBA·copy_from_uint32 - ,.equal = PixelRGBA·equal - ,.blend = PixelRGBA·blend - ,.invert = PixelRGBA·invert - ,.map_to_grayscale = PixelRGBA·map_to_grayscale - ,.black = PixelRGBA·black - ,.white = PixelRGBA·white - ,.neutral = PixelRGBA·neutral -}; diff --git a/developer/cc/Pixel_2024-09-18T2100.c b/developer/cc/Pixel_2024-09-18T2100.c deleted file mode 100644 index ce17e52..0000000 --- a/developer/cc/Pixel_2024-09-18T2100.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - Pixel types - - Currently implements only RGBA, which are specified by the hardware; hence - they must be packed as: 0xAARRGGBB. - - For the sake of consistency, pixels are always passed by reference. Functions - that generate new pixels, return the new pixel by value. -*/ - -#include -#include -#include // for rand() -#include // for seeding rand() - -//-------------------------------------------------------------------------------- -// instance state - -#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 "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors." -#endif - -// Initialize a Pixel given the individual field values. -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; -} - -// take apart a Pixel -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; -} - -//-------------------------------------------------------------------------------- -// interface - -PixelRGBA PixelRGBA·black = {.aggregate = 0xff000000}; -PixelRGBA PixelRGBA·white = {.aggregate = 0xffffffff}; -PixelRGBA PixelRGBA·neutral = {.aggregate = 0x80808080}; - -// makes a Pixel with a random value. -PixelRGBA PixelRGBA·random(){ - PixelRGBA px; - #if RAND_MAX < 0xFFFFFFFF - px.aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF); - #else - px.aggregate = (uint32_t)rand(); - #endif - #if RAND_MAX < 0xFFFF - #warning "Pixel.c: warning standard rand() claims to deliver less than 16-bit values." - #endif - return px; -} - - -void PixelRGBA·copy_from_uint32(PixelRGBA *to_px ,uint32_t from_uint32){ - to_px->aggregate = from_uint32; -} - -bool PixelRGBA·equals(const PixelRGBA *px0 ,const PixelRGBA *px1) { - return px0->aggregate == px1->aggregate; -} - -PixelRGBA PixelRGBA·blend(const PixelRGBA *px0 ,const PixelRGBA *px1) { - PixelRGBA px2; - px2.alpha = (px0->alpha + px1->alpha) / 2; - px2.red = (px0->red + px1->red) / 2; - px2.green = (px0->green + px1->green) / 2; - px2.blue = (px0->blue + px1->blue) / 2; - return px2; -} - -PixelRGBA PixelRGBA·invert(const PixelRGBA *px0) { - PixelRGBA px2; - px2.red = 255 - px0->red; - px2.green = 255 - px0->green; - px2.blue = 255 - px0->blue; - px2.alpha = px0->alpha; - return px2; -} - -PixelRGBA PixelRGBA·map_to_grayscale(const PixelRGBA *px0) { - uint8_t gray_level = (uint8_t)(0.299 * px0->red + 0.587 * px0->green + 0.114 * px0->blue); - PixelRGBA px1 = - { - .red = gray_level - ,.green = gray_level - ,.blue = gray_level - ,.alpha = px0->alpha - }; - return px1; -} diff --git a/developer/cc/echo_frames_2024-09-18_1345.c b/developer/cc/echo_frames_2024-09-18_1345.c deleted file mode 100644 index dcea910..0000000 --- a/developer/cc/echo_frames_2024-09-18_1345.c +++ /dev/null @@ -1,76 +0,0 @@ -// gcc -I/usr/include/libdrm echo_frames.c -o echo_frames -ldrm -// sudo ./echo_frames - -/* -Echos frames. - -Proof of principle: grabs frame, does nothing to it, then displays it, in a loop. -*/ - -#include // For printf, fprintf, perror -#include // For malloc, free, NULL -#include // For open -#include // For close -#include // For memcpy -#include // For timing the loop -#include // For DRM functions -#include // For DRM Mode resources -#include // For mmap, munmap, PROT_READ, PROT_WRITE, MAP_SHARED, MAP_FAILED - -#include "Pixel.c" -#include "Frame.c" - -int main() { - int fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC); // Open the DRM device - if(fd < 0){ - perror("Failed to open DRM device"); - return -1; - } - - // Framebuffer ID: 108, resolution: 3840x2400 - int buffer_id = 108; - int width = 3840; - int height = 2400; - - // Allocate a DRM captured frame using the correct framebuffer ID - FrameRGBA *drm_frame = FrameRGBA·alloc_capture_drm(fd, width, height, buffer_id); - if(!drm_frame){ - fprintf(stderr, "Failed to allocate DRM frame\n"); - close(fd); - return -1; - } - - // Allocate a local frame for copying - FrameRGBA *local_frame = FrameRGBA·alloc_local(1920, 1080); - if(!local_frame){ - fprintf(stderr, "Failed to allocate local frame\n"); - FrameRGBA·dealloc(&drm_frame); - close(fd); - return -1; - } - - // Get current time for the 5-second loop duration - time_t start_time = time(NULL); - - // Loop for 5 seconds - while(time(NULL) - start_time < 5){ - // Capture from the DRM frame and copy to the local frame - FrameRGBA·copy(drm_frame, &local_frame); - - // Display the local frame (for simplicity, we use the DRM frame display method) - if(FrameRGBA·display(local_frame, fd, 0, 0) < 0){ // Replace with proper crtc and connector IDs - fprintf(stderr, "Failed to display local frame\n"); - FrameRGBA·dealloc(&drm_frame); - FrameRGBA·dealloc(&local_frame); - close(fd); - return -1; - } - } - - // Clean up and close DRM device - FrameRGBA·dealloc(&drm_frame); - FrameRGBA·dealloc(&local_frame); - close(fd); - - return 0; -} diff --git a/developer/cc/frame_2024-09-18_1221.c b/developer/cc/frame_2024-09-18_1221.c deleted file mode 100644 index 829228a..0000000 --- a/developer/cc/frame_2024-09-18_1221.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - A display frame type. - - Frames to be read or written are passed by reference. - - Functions that allocate a new frame typically return a reference to the - newly allocated frame. - - Functions that accept an argument for holding an newly allocated frame, that - argument will be a pointer to the frame reference. E.g. f(Frame **generated), - *generated = NULL or *gnerated = malloc(...). - -*/ - -#include -#include -#include - -// -------------------------------------------------------------------------------- -// instance state - -typedef struct{ - uint32_t width; - uint32_t height; - PixelRGBA data[]; -} FrameRGBA; - -// -------------------------------------------------------------------------------- -// interface - -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); - *frame = NULL; -} - -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){ - if(!from_frame) return NULL; - 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){ - if(!from_frame){ - fprintf(stderr, "FrameRGBA·read:: warning, empty frame, so returning a neutral pixel."); - return PixelRGBA·neutral; - } - return *FrameRGBA·access(from_frame ,i ,j); -} - -void FrameRGBA·write(FrameRGBA *to_frame ,uint32_t i ,uint32_t j ,PixelRGBA px){ - if(!to_frame){ - fprintf(stderr, "FrameRGBA·write:: warning, empty frame, write ignored."); - return; - } - *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){ - if(!to_frame) return; - PixelRGBA *px = arg; - *to_px = *px; -} -void FrameRGBA·fill(FrameRGBA *to_frame ,PixelRGBA *fill_px){ - if(!to_frame) return; - FrameRGBA·every(to_frame ,fill_f ,fill_px); -} - -void FrameRGBA·fill_black(FrameRGBA *to_frame){ - if(!to_frame) return; - FrameRGBA·fill(to_frame ,&black); -} - -void FrameRGBA·fill_white(FrameRGBA *to_frame){ - if(!to_frame) return; - 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); -} diff --git a/developer/cc/test_size b/developer/cc/test_size new file mode 100755 index 0000000..4e2e5b6 Binary files /dev/null and b/developer/cc/test_size differ diff --git a/developer/cc/test_size.c b/developer/cc/test_size.c new file mode 100644 index 0000000..1253513 --- /dev/null +++ b/developer/cc/test_size.c @@ -0,0 +1,56 @@ +// gcc test_size.c -o test_size + +#include +#include +#include +#include + +#include "Index.c" + +// Helper function to count the nber of bits in a given nber +int count_bits(uint64_t n) { + int bits = 0; + while (n) { + n >>= 1; + bits++; + } + return bits; +} + +// Compute the number of bytes in 2D array with exclusive bound of n. +bool Index32·bounded_size(Index32·Instance n, uint32_t element_size, size_t *result_area) { + uint64_t x = n.x; + uint64_t y = n.y; + + // Count bits in x, y, and element_size + int x_bits = count_bits(x); + int y_bits = count_bits(y); + int elem_bits = count_bits(element_size); + + // Determine the nber of bits in SIZE_MAX + int max_bits = count_bits(SIZE_MAX); + + // If the sum of the bits exceeds the number of bits in size_t, return false (overflow) + if (x_bits + y_bits + elem_bits > max_bits) { + return false; // Overflow detected + } + + // Safe to calculate the area + *result_area = (size_t)x * (size_t)y * element_size; + return true; // Successful computation +} + +int main() { + Index32·Instance n = {50000, 50000}; // Example dimensions + uint32_t element_size = 16; // Example element size + size_t result_area; + + bool success = Index32·bounded_size(n, element_size, &result_area); + + if (!success) { + printf("Overflow detected during area calculation.\n"); + } else { + printf("Area: %zu\n", result_area); + } + return 0; +}