Architectural updates

1. Introduce image UUIDs, so nodes may check for source updates.
2. Flip over design. Now, CHiPubNodes contain private data, instead of
CHiPubNodes being contained within private data. Each node must cache
its source data if it wants to conditionally run.
This commit is contained in:
mid 2025-10-15 09:45:38 +03:00
parent cc70d9138a
commit b1a1b9a1eb
5 changed files with 104 additions and 82 deletions

View File

@ -5,7 +5,7 @@
#include<assert.h> #include<assert.h>
CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride, uint16_t width, uint16_t height, void *data) { CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride, uint16_t width, uint16_t height, void *data) {
CHiImage *img = malloc(sizeof(*img)); CHiImage *img = calloc(1, sizeof(*img));
img->bpc = bpc; img->bpc = bpc;
img->channels = channels; img->channels = channels;
img->stride = stride; img->stride = stride;
@ -15,6 +15,8 @@ CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride,
else img->data16 = _mm_malloc(bpc * stride * height + 16, 16); else img->data16 = _mm_malloc(bpc * stride * height + 16, 16);
img->owned = !data; img->owned = !data;
img->uuid = CHi_NextUUID();
assert(stride % 16 == 0); assert(stride % 16 == 0);
return img; return img;
@ -40,3 +42,8 @@ CUTIVIS void CHi_Restride(const void *oldbuf_, void *newbuf_, uint16_t oldStride
memmove(&newbuf[newStride * row], &oldbuf[oldStride * row], oldStride); memmove(&newbuf[newStride * row], &oldbuf[oldStride * row], oldStride);
} }
} }
CUTIVIS size_t CHi_NextUUID() {
static size_t i = 0;
return i++;
}

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include<stddef.h>
#include<stdint.h> #include<stdint.h>
#include"defs.h" #include"defs.h"
@ -18,6 +19,7 @@ typedef struct CHiImage {
uint8_t *data8; uint8_t *data8;
}; };
uint8_t owned; uint8_t owned;
size_t uuid;
} CHiImage; } CHiImage;
CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride, uint16_t width, uint16_t height, void *data); CUTIVIS CHiImage* CHi_Image_New(uint8_t bpc, uint8_t channels, uint16_t stride, uint16_t width, uint16_t height, void *data);
@ -25,6 +27,8 @@ CUTIVIS void CHi_Image_Free(CHiImage *img);
CUTIVIS void CHi_Restride(const void *oldbuf, void *newbuf, uint16_t oldStride, uint16_t newStride, uint16_t rows); CUTIVIS void CHi_Restride(const void *oldbuf, void *newbuf, uint16_t oldStride, uint16_t newStride, uint16_t rows);
CUTIVIS size_t CHi_NextUUID();
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

119
hi/node.c
View File

@ -522,14 +522,14 @@ typedef struct {
CHiPubNode pubn; CHiPubNode pubn;
char *cachePath; char *cachePath;
CHiImage *cacheImg; CHiImage *cacheImg;
} ImageNode; } ImageImpl;
static int image_perform(CHiPubNode *node) { static int image_perform(CHiPubNode *node) {
ImageNode *internal = (ImageNode*) node; ImageImpl *impl = node->impl;
node->sources->type = CUTIHI_VAL_SAMPLE; node->sources->type = CUTIHI_VAL_SAMPLE;
const char *fn = node->sinks[CUTIHI_IMAGE_IN_FILE].data.text; const char *fn = node->sinks[CUTIHI_IMAGE_IN_FILE].data.text;
if(fn && (!internal->cachePath || strcmp(internal->cachePath, fn))) { if(fn && (!impl->cachePath || strcmp(impl->cachePath, fn))) {
if(node->sinks[CUTIHI_IMAGE_IN_FILE].type == CUTIHI_VAL_NONE) { if(node->sinks[CUTIHI_IMAGE_IN_FILE].type == CUTIHI_VAL_NONE) {
return 1; return 1;
} }
@ -539,13 +539,13 @@ static int image_perform(CHiPubNode *node) {
return 1; return 1;
} }
if(internal->cacheImg) { if(impl->cacheImg) {
CHi_Image_Free(internal->cacheImg); CHi_Image_Free(impl->cacheImg);
internal->cacheImg = NULL; impl->cacheImg = NULL;
} }
} }
if(!internal->cacheImg) { if(!impl->cacheImg) {
size_t w = 0, h = 0, n = 4; size_t w = 0, h = 0, n = 4;
float *data = stbi_loadf(fn, &w, &h, &n, 4); float *data = stbi_loadf(fn, &w, &h, &n, 4);
if(!data) { if(!data) {
@ -554,7 +554,7 @@ static int image_perform(CHiPubNode *node) {
} }
CHiImage *img = CHi_Image_New(2, 4, (w * 8 + 15) & ~15, w, h, NULL); CHiImage *img = CHi_Image_New(2, 4, (w * 8 + 15) & ~15, w, h, NULL);
internal->cacheImg = img; impl->cacheImg = img;
for(size_t y = 0; y < img->height; y++) { for(size_t y = 0; y < img->height; y++) {
for(size_t x = 0; x < img->width; x++) { for(size_t x = 0; x < img->width; x++) {
@ -566,12 +566,12 @@ static int image_perform(CHiPubNode *node) {
} }
} }
free(internal->cachePath); free(impl->cachePath);
internal->cachePath = strdup(fn); impl->cachePath = strdup(fn);
} }
if(CHi_Node_Active(node)) { if(CHi_Node_Active(node)) {
node->sources->data.sample = internal->cacheImg; node->sources->data.sample = impl->cacheImg;
} else { } else {
node->sources->data.sample = NULL; node->sources->data.sample = NULL;
} }
@ -579,15 +579,10 @@ static int image_perform(CHiPubNode *node) {
return 1; return 1;
} }
CUTIVIS CHiPubNode *CHi_Image() { CUTIVIS CHiPubNode *CHi_Image() {
CHiPubNode *n = calloc(1, sizeof(ImageNode)); CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CIma','ge '), 1, 1, sizeof(ImageImpl));
n->type = CUTIHI_T('CIma','ge ');
n->Start = n->Stop = NULL; n->Start = n->Stop = NULL;
n->Perform = image_perform; n->Perform = image_perform;
n->sinkCount = 1; ((ImageImpl*) n->impl)->cachePath = strdup("");
n->sinks = calloc(sizeof(*n->sinks), 1);
n->sourceCount = 1;
n->sources = calloc(sizeof(*n->sources), 1);
((ImageNode*) n)->cachePath = strdup("");
return n; return n;
} }
@ -638,32 +633,40 @@ static int embed_perform(CHiPubNode *node) {
return 1; return 1;
} }
CUTIVIS CHiPubNode *CHi_Embed() { CUTIVIS CHiPubNode *CHi_Embed() {
CHiPubNode *n = calloc(1, sizeof(*n)); CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CEmb','ed '), 1 + 3 * CUTIHI_EMBED_MAX_SMALLS, 1, 0);
n->type = CUTIHI_T('CEmb','ed ');
n->Start = n->Stop = NULL; n->Start = n->Stop = NULL;
n->Perform = embed_perform; n->Perform = embed_perform;
n->sinks = calloc(sizeof(*n->sinks), n->sinkCount = 1 + 3 * CUTIHI_EMBED_MAX_SMALLS);
n->sources = calloc(sizeof(*n->sources), n->sourceCount = 1);
return n; return n;
} }
struct ConstantSampleImpl {
size_t cacheW;
size_t cacheH;
float cacheCol[4];
};
static int constantsample_perform(CHiPubNode *node) { static int constantsample_perform(CHiPubNode *node) {
struct ConstantSampleImpl *impl = node->impl;
node->sources[0].type = CUTIHI_VAL_SAMPLE; node->sources[0].type = CUTIHI_VAL_SAMPLE;
if(node->sources->data.sample) CHi_Image_Free(node->sources->data.sample); if(node->sources->data.sample) CHi_Image_Free(node->sources->data.sample);
CHiValue *sink = CHi_Crawl(&node->sinks[0]); CHiValue *color = CHi_Crawl(&node->sinks[0]);
CHiValue *sz = CHi_Crawl(&node->sinks[1]); CHiValue *sz = CHi_Crawl(&node->sinks[1]);
size_t w = sz->data.vec4[0] < 1 ? 1 : sz->data.vec4[0]; size_t w = sz->data.vec4[0] < 1 ? 1 : sz->data.vec4[0];
size_t h = sz->data.vec4[1] < 1 ? 1 : sz->data.vec4[1]; size_t h = sz->data.vec4[1] < 1 ? 1 : sz->data.vec4[1];
impl->cacheW = w;
impl->cacheH = h;
memcpy(impl->cacheCol, color->data.vec4, sizeof(impl->cacheCol));
CHiImage *img = CHi_Image_New(2, 4, 8 * ((w + 1) & ~1), w, h, NULL); CHiImage *img = CHi_Image_New(2, 4, 8 * ((w + 1) & ~1), w, h, NULL);
if(CHi_Node_Active(node)) { if(CHi_Node_Active(node)) {
for(size_t y = 0; y < h; y++) { for(size_t y = 0; y < h; y++) {
for(size_t x = 0; x < w; x++) { for(size_t x = 0; x < w; x++) {
img->data16[y * img->stride / 2 + x * 4 + 0] = sink->data.vec4[2] * 65535; img->data16[y * img->stride / 2 + x * 4 + 0] = color->data.vec4[2] * 65535;
img->data16[y * img->stride / 2 + x * 4 + 1] = sink->data.vec4[1] * 65535; img->data16[y * img->stride / 2 + x * 4 + 1] = color->data.vec4[1] * 65535;
img->data16[y * img->stride / 2 + x * 4 + 2] = sink->data.vec4[0] * 65535; img->data16[y * img->stride / 2 + x * 4 + 2] = color->data.vec4[0] * 65535;
img->data16[y * img->stride / 2 + x * 4 + 3] = 65535; img->data16[y * img->stride / 2 + x * 4 + 3] = 65535;
} }
} }
@ -673,18 +676,13 @@ static int constantsample_perform(CHiPubNode *node) {
return 1; return 1;
} }
CUTIVIS CHiPubNode *CHi_ConstantSample() { CUTIVIS CHiPubNode *CHi_ConstantSample() {
CHiPubNode *n = calloc(1, sizeof(*n)); CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CCns','tCol'), 2, 1, sizeof(struct ConstantSampleImpl));
n->type = CUTIHI_T('CCns','tCol');
n->Start = n->Stop = NULL; n->Start = n->Stop = NULL;
n->Perform = constantsample_perform; n->Perform = constantsample_perform;
n->sinkCount = 2;
n->sinks = calloc(sizeof(*n->sinks), n->sinkCount);
n->sourceCount = 1;
n->sources = calloc(sizeof(*n->sources), n->sourceCount);
n->sinks[0].type = CUTIHI_VAL_VEC4; n->sinks[1].type = CUTIHI_VAL_VEC4;
n->sinks[0].data.vec4[0] = 1280; n->sinks[1].data.vec4[0] = 1280;
n->sinks[0].data.vec4[1] = 720; n->sinks[1].data.vec4[1] = 720;
return n; return n;
} }
@ -848,14 +846,9 @@ static int modulate_perform(CHiPubNode *node) {
return 1; return 1;
} }
CUTIVIS CHiPubNode *CHi_Modulate() { CUTIVIS CHiPubNode *CHi_Modulate() {
CHiPubNode *n = calloc(1, sizeof(*n)); CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CMod','ulat'), 4, 1, 0);
n->type = CUTIHI_T('CMod','ulat');
n->Start = n->Stop = NULL; n->Start = n->Stop = NULL;
n->Perform = modulate_perform; n->Perform = modulate_perform;
n->sinkCount = 4;
n->sinks = calloc(sizeof(*n->sinks), n->sinkCount);
n->sourceCount = 1;
n->sources = calloc(sizeof(*n->sources), n->sourceCount);
n->sinks[0].type = CUTIHI_VAL_VEC4; n->sinks[0].type = CUTIHI_VAL_VEC4;
n->sinks[0].data.vec4[0] = 1; n->sinks[0].data.vec4[0] = 1;
@ -885,14 +878,9 @@ CUTIVIS float CHi_Time_GetDelta(CHiNodeGraph *ng) {
return ng->timedelta; return ng->timedelta;
} }
CUTIVIS CHiPubNode *CHi_Time() { CUTIVIS CHiPubNode *CHi_Time() {
CHiPubNode *n = calloc(1, sizeof(*n)); CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CTim','e '), 0, 1, 0);
n->type = CUTIHI_T('CTim','e ');
n->Start = n->Stop = NULL; n->Start = n->Stop = NULL;
n->Perform = time_perform; n->Perform = time_perform;
n->sinkCount = 0;
n->sinks = NULL;
n->sourceCount = 1;
n->sources = calloc(sizeof(*n->sources), 1);
return n; return n;
} }
@ -1085,7 +1073,13 @@ CUTIVIS CHiPubNode *CHi_Preview() {
return n; return n;
} }
struct ChromaKeyImpl {
uint64_t cacheImg;
float cacheCol[4];
};
static int chromakey_perform(CHiPubNode *n) { static int chromakey_perform(CHiPubNode *n) {
struct ChromaKeyImpl *impl = n->impl;
CHiValue *sampleV = CHi_Crawl(&n->sinks[0]); CHiValue *sampleV = CHi_Crawl(&n->sinks[0]);
CHiValue *colorV = CHi_Crawl(&n->sinks[1]); CHiValue *colorV = CHi_Crawl(&n->sinks[1]);
@ -1099,6 +1093,9 @@ static int chromakey_perform(CHiPubNode *n) {
CHi_Image_Free(n->sources[0].data.sample); CHi_Image_Free(n->sources[0].data.sample);
} }
impl->cacheImg = src->uuid;
memcpy(impl->cacheCol, colorV->data.vec4, sizeof(impl->cacheCol));
n->sources[0].type = CUTIHI_VAL_SAMPLE; n->sources[0].type = CUTIHI_VAL_SAMPLE;
CHiImage *dst = n->sources[0].data.sample = CHi_Image_New(2, 4, (src->width * src->bpc * src->channels + 15) & ~15, src->width, src->height, NULL); CHiImage *dst = n->sources[0].data.sample = CHi_Image_New(2, 4, (src->width * src->bpc * src->channels + 15) & ~15, src->width, src->height, NULL);
@ -1190,14 +1187,12 @@ static int chromakey_perform(CHiPubNode *n) {
return 1; return 1;
} }
CUTIVIS CHiPubNode *CHi_ChromaKey() { CUTIVIS CHiPubNode *CHi_ChromaKey() {
CHiPubNode *n = calloc(1, sizeof(*n)); CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CChr','omaK'), 2, 1, sizeof(struct ChromaKeyImpl));
n->type = CUTIHI_T('CChr','omaK');
n->Start = n->Stop = NULL; n->Start = n->Stop = NULL;
n->Perform = chromakey_perform; n->Perform = chromakey_perform;
n->sinks = calloc(sizeof(*n->sinks), n->sinkCount = 2);
n->sources = calloc(sizeof(*n->sources), n->sourceCount = 1);
n->sinks[1].type = CUTIHI_VAL_VEC4; // Default green // Default green
n->sinks[1].type = CUTIHI_VAL_VEC4;
n->sinks[1].data.vec4[0] = 0; n->sinks[1].data.vec4[0] = 0;
n->sinks[1].data.vec4[1] = 1; n->sinks[1].data.vec4[1] = 1;
n->sinks[1].data.vec4[2] = 0; n->sinks[1].data.vec4[2] = 0;
@ -1258,3 +1253,23 @@ CUTIVIS void CHi_AddError(CHiPubNode *node, const char *err, size_t sink) {
} }
} }
} }
CUTIVIS CHiPubNode *CHi_AllocNode(uint64_t type, size_t sinkCount, size_t sourceCount, size_t implSize) {
CHiPubNode *n = calloc(1, sizeof(*n) + implSize);
if(!n) {
return NULL;
}
n->type = type;
n->sinks = calloc(n->sinkCount = sinkCount, sizeof(*n->sinks));
if(!n->sinks) {
free(n);
return NULL;
}
n->sources = calloc(n->sourceCount = sourceCount, sizeof(*n->sources));
if(!n->sources) {
free(n->sinks);
free(n);
return NULL;
}
return n;
}

View File

@ -84,8 +84,6 @@ typedef struct CHiPubNode {
uint32_t flags; uint32_t flags;
#define CUTIHI_PERFORM_UPDATED 1
#define CUTIHI_PERFORM_NOTUPDATED 0
int (*Perform)(struct CHiPubNode *node); int (*Perform)(struct CHiPubNode *node);
int (*Start)(struct CHiPubNode *node); int (*Start)(struct CHiPubNode *node);
int (*Stop)(struct CHiPubNode *node); int (*Stop)(struct CHiPubNode *node);
@ -110,6 +108,8 @@ typedef struct CHiPubNode {
} lifespan; } lifespan;
char _dfsmark; char _dfsmark;
uint8_t impl[];
} CHiPubNode; } CHiPubNode;
typedef enum { typedef enum {
@ -293,6 +293,8 @@ CUTIVIS void CHi_Node_Destroy(CHiPubNode*);
CUTIVIS void CHi_AddError(CHiPubNode*, const char *err, size_t sink); CUTIVIS void CHi_AddError(CHiPubNode*, const char *err, size_t sink);
CUTIVIS CHiPubNode *CHi_AllocNode(uint64_t type, size_t sinkCount, size_t sourceCount, size_t implSize);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -20,8 +20,8 @@
#include"minitrace.h" #include"minitrace.h"
static Display *d; static thread_local Display *d;
static Window root; static thread_local Window root;
static int find_window(Display *d, Window *w, const char *contains) { static int find_window(Display *d, Window *w, const char *contains) {
if(contains) { if(contains) {
@ -59,17 +59,20 @@ static int find_window(Display *d, Window *w, const char *contains) {
} }
typedef struct { typedef struct {
CHiPubNode pub;
Window xcache; Window xcache;
XImage *ximg; XImage *ximg;
XShmSegmentInfo shminfo; XShmSegmentInfo shminfo;
CHiImage *vcache; CHiImage *vcache;
} CHiWindowNode; } WindowImpl;
static int window_perform(CHiPubNode *n) { static int window_perform(CHiPubNode *n) {
CHiWindowNode *w = (CHiWindowNode*) n; auto *w = (WindowImpl*) n->impl;
if(!d) {
d = XOpenDisplay(NULL);
root = RootWindow(d, DefaultScreen(d));
}
MTR_BEGIN("CHi", "window_perform"); MTR_BEGIN("CHi", "window_perform");
@ -100,7 +103,7 @@ static int window_perform(CHiPubNode *n) {
XShmGetImage(d, w->xcache, w->ximg, 0, 0, AllPlanes); XShmGetImage(d, w->xcache, w->ximg, 0, 0, AllPlanes);
bool ignoreAlpha = CHi_Crawl(&w->pub.sinks[1])->data.vec4[0] != 0; bool ignoreAlpha = CHi_Crawl(&n->sinks[1])->data.vec4[0] != 0;
// Turn u8 image to u16 // Turn u8 image to u16
#pragma omp parallel for #pragma omp parallel for
@ -125,7 +128,7 @@ static int window_perform(CHiPubNode *n) {
} }
static void window_destroy(CHiPubNode *pubn) { static void window_destroy(CHiPubNode *pubn) {
CHiWindowNode *n = (CHiWindowNode*) pubn; auto *n = (WindowImpl*) pubn->impl;
if(n->vcache) { if(n->vcache) {
XShmDetach(d, &n->shminfo); XShmDetach(d, &n->shminfo);
@ -137,25 +140,11 @@ static void window_destroy(CHiPubNode *pubn) {
} }
CUTIVIS CHiPubNode *CHi_Window() { CUTIVIS CHiPubNode *CHi_Window() {
if(!d) { CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CWin','dow '), 2, 1, sizeof(WindowImpl));
d = XOpenDisplay(NULL); n->Start = n->Stop = NULL;
root = RootWindow(d, DefaultScreen(d)); n->Perform = window_perform;
} n->Destroy = window_destroy;
return n;
CHiWindowNode *n = (CHiWindowNode*) calloc(1, sizeof(*n));
n->pub.type = CUTIHI_T('CWin','dow ');
n->pub.Start = n->pub.Stop = NULL;
n->pub.Perform = window_perform;
n->pub.Destroy = window_destroy;
n->pub.sinkCount = 1;
n->pub.sinks = (CHiValue*) calloc(sizeof(*n->pub.sinks), 2);
n->pub.sourceCount = 1;
n->pub.sources = (CHiValue*) calloc(sizeof(*n->pub.sources), 1);
n->xcache = 0;
n->vcache = NULL;
return &n->pub;
} }
// All of the following are ews // All of the following are ews
@ -165,6 +154,11 @@ struct WindowListDatum {
char name[128]; char name[128];
}; };
CUTIVIS size_t CHi_Window_GetList(void **buf) { CUTIVIS size_t CHi_Window_GetList(void **buf) {
if(!d) {
d = XOpenDisplay(NULL);
root = RootWindow(d, DefaultScreen(d));
}
int found = 0; int found = 0;
Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1); Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1);
Atom actualType; Atom actualType;