Compare commits

..

3 Commits

Author SHA1 Message Date
mid
b1a1b9a1eb 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.
2025-10-15 09:45:38 +03:00
mid
cc70d9138a Don't fuckin call SetImage from the not UI thread wtf 2025-10-15 09:42:06 +03:00
mid
28e7fa3365 Fix vpx encoding 2025-10-12 16:57:58 +03:00
8 changed files with 128 additions and 101 deletions

View File

@ -5,7 +5,7 @@
#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) {
CHiImage *img = malloc(sizeof(*img));
CHiImage *img = calloc(1, sizeof(*img));
img->bpc = bpc;
img->channels = channels;
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);
img->owned = !data;
img->uuid = CHi_NextUUID();
assert(stride % 16 == 0);
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);
}
}
CUTIVIS size_t CHi_NextUUID() {
static size_t i = 0;
return i++;
}

View File

@ -1,5 +1,6 @@
#pragma once
#include<stddef.h>
#include<stdint.h>
#include"defs.h"
@ -18,6 +19,7 @@ typedef struct CHiImage {
uint8_t *data8;
};
uint8_t owned;
size_t uuid;
} CHiImage;
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 size_t CHi_NextUUID();
#ifdef __cplusplus
}
#endif

View File

@ -344,8 +344,16 @@ static int muxmkv_perform(CHiPubNode *pubn) {
assert((frame->flags & CUTIHI_BS_SETUP_PACKET) == 0);
bool freeAvcc = false;
size_t avccSz = 0;
uint8_t *avcc = annexb_to_avcc(frame->ptr, frame->sz, &avccSz);
uint8_t *avcc = NULL;
if(CHi_Crawl(&pubn->sinks[0])->type == CUTIHI_VAL_H264BS) {
avcc = annexb_to_avcc(frame->ptr, frame->sz, &avccSz);
freeAvcc = true;
} else {
avcc = frame->ptr;
avccSz = frame->sz;
}
size_t simpleBlockSize = 4 + avccSz;
@ -360,7 +368,10 @@ static int muxmkv_perform(CHiPubNode *pubn) {
ebml_writer_put(&this->wr, 0xA3, EBML_BINARY, (EBMLPrimitive) {.binary = {.length = simpleBlockSize, .ptr = simpleBlock}});
free(simpleBlock);
if(freeAvcc) {
free(avcc);
}
CHi_BS_Pop(this->videoBacklog, 1);
}

119
hi/node.c
View File

@ -522,14 +522,14 @@ typedef struct {
CHiPubNode pubn;
char *cachePath;
CHiImage *cacheImg;
} ImageNode;
} ImageImpl;
static int image_perform(CHiPubNode *node) {
ImageNode *internal = (ImageNode*) node;
ImageImpl *impl = node->impl;
node->sources->type = CUTIHI_VAL_SAMPLE;
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) {
return 1;
}
@ -539,13 +539,13 @@ static int image_perform(CHiPubNode *node) {
return 1;
}
if(internal->cacheImg) {
CHi_Image_Free(internal->cacheImg);
internal->cacheImg = NULL;
if(impl->cacheImg) {
CHi_Image_Free(impl->cacheImg);
impl->cacheImg = NULL;
}
}
if(!internal->cacheImg) {
if(!impl->cacheImg) {
size_t w = 0, h = 0, n = 4;
float *data = stbi_loadf(fn, &w, &h, &n, 4);
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);
internal->cacheImg = img;
impl->cacheImg = img;
for(size_t y = 0; y < img->height; y++) {
for(size_t x = 0; x < img->width; x++) {
@ -566,12 +566,12 @@ static int image_perform(CHiPubNode *node) {
}
}
free(internal->cachePath);
internal->cachePath = strdup(fn);
free(impl->cachePath);
impl->cachePath = strdup(fn);
}
if(CHi_Node_Active(node)) {
node->sources->data.sample = internal->cacheImg;
node->sources->data.sample = impl->cacheImg;
} else {
node->sources->data.sample = NULL;
}
@ -579,15 +579,10 @@ static int image_perform(CHiPubNode *node) {
return 1;
}
CUTIVIS CHiPubNode *CHi_Image() {
CHiPubNode *n = calloc(1, sizeof(ImageNode));
n->type = CUTIHI_T('CIma','ge ');
CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CIma','ge '), 1, 1, sizeof(ImageImpl));
n->Start = n->Stop = NULL;
n->Perform = image_perform;
n->sinkCount = 1;
n->sinks = calloc(sizeof(*n->sinks), 1);
n->sourceCount = 1;
n->sources = calloc(sizeof(*n->sources), 1);
((ImageNode*) n)->cachePath = strdup("");
((ImageImpl*) n->impl)->cachePath = strdup("");
return n;
}
@ -638,32 +633,40 @@ static int embed_perform(CHiPubNode *node) {
return 1;
}
CUTIVIS CHiPubNode *CHi_Embed() {
CHiPubNode *n = calloc(1, sizeof(*n));
n->type = CUTIHI_T('CEmb','ed ');
CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CEmb','ed '), 1 + 3 * CUTIHI_EMBED_MAX_SMALLS, 1, 0);
n->Start = n->Stop = NULL;
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;
}
struct ConstantSampleImpl {
size_t cacheW;
size_t cacheH;
float cacheCol[4];
};
static int constantsample_perform(CHiPubNode *node) {
struct ConstantSampleImpl *impl = node->impl;
node->sources[0].type = CUTIHI_VAL_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]);
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];
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);
if(CHi_Node_Active(node)) {
for(size_t y = 0; y < h; y++) {
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 + 1] = sink->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 + 0] = color->data.vec4[2] * 65535;
img->data16[y * img->stride / 2 + x * 4 + 1] = color->data.vec4[1] * 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;
}
}
@ -673,18 +676,13 @@ static int constantsample_perform(CHiPubNode *node) {
return 1;
}
CUTIVIS CHiPubNode *CHi_ConstantSample() {
CHiPubNode *n = calloc(1, sizeof(*n));
n->type = CUTIHI_T('CCns','tCol');
CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CCns','tCol'), 2, 1, sizeof(struct ConstantSampleImpl));
n->Start = n->Stop = NULL;
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[0].data.vec4[0] = 1280;
n->sinks[0].data.vec4[1] = 720;
n->sinks[1].type = CUTIHI_VAL_VEC4;
n->sinks[1].data.vec4[0] = 1280;
n->sinks[1].data.vec4[1] = 720;
return n;
}
@ -848,14 +846,9 @@ static int modulate_perform(CHiPubNode *node) {
return 1;
}
CUTIVIS CHiPubNode *CHi_Modulate() {
CHiPubNode *n = calloc(1, sizeof(*n));
n->type = CUTIHI_T('CMod','ulat');
CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CMod','ulat'), 4, 1, 0);
n->Start = n->Stop = NULL;
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].data.vec4[0] = 1;
@ -885,14 +878,9 @@ CUTIVIS float CHi_Time_GetDelta(CHiNodeGraph *ng) {
return ng->timedelta;
}
CUTIVIS CHiPubNode *CHi_Time() {
CHiPubNode *n = calloc(1, sizeof(*n));
n->type = CUTIHI_T('CTim','e ');
CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CTim','e '), 0, 1, 0);
n->Start = n->Stop = NULL;
n->Perform = time_perform;
n->sinkCount = 0;
n->sinks = NULL;
n->sourceCount = 1;
n->sources = calloc(sizeof(*n->sources), 1);
return n;
}
@ -1085,7 +1073,13 @@ CUTIVIS CHiPubNode *CHi_Preview() {
return n;
}
struct ChromaKeyImpl {
uint64_t cacheImg;
float cacheCol[4];
};
static int chromakey_perform(CHiPubNode *n) {
struct ChromaKeyImpl *impl = n->impl;
CHiValue *sampleV = CHi_Crawl(&n->sinks[0]);
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);
}
impl->cacheImg = src->uuid;
memcpy(impl->cacheCol, colorV->data.vec4, sizeof(impl->cacheCol));
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);
@ -1190,14 +1187,12 @@ static int chromakey_perform(CHiPubNode *n) {
return 1;
}
CUTIVIS CHiPubNode *CHi_ChromaKey() {
CHiPubNode *n = calloc(1, sizeof(*n));
n->type = CUTIHI_T('CChr','omaK');
CHiPubNode *n = CHi_AllocNode(CUTIHI_T('CChr','omaK'), 2, 1, sizeof(struct ChromaKeyImpl));
n->Start = n->Stop = NULL;
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[1] = 1;
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;
#define CUTIHI_PERFORM_UPDATED 1
#define CUTIHI_PERFORM_NOTUPDATED 0
int (*Perform)(struct CHiPubNode *node);
int (*Start)(struct CHiPubNode *node);
int (*Stop)(struct CHiPubNode *node);
@ -110,6 +108,8 @@ typedef struct CHiPubNode {
} lifespan;
char _dfsmark;
uint8_t impl[];
} CHiPubNode;
typedef enum {
@ -293,6 +293,8 @@ CUTIVIS void CHi_Node_Destroy(CHiPubNode*);
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
}
#endif

View File

@ -42,7 +42,7 @@ static int encodevpx_perform(CHiPubNode *pub) {
MTR_BEGIN("CHi", "encodevp9_perform");
pub->sources[0].type = CUTIHI_VAL_VP9BS;
pub->sources[0].type = pub->type == CUTIHI_T('CEnc','GVP8') ? CUTIHI_VAL_VP8BS : CUTIHI_VAL_VP9BS;
pub->sources[0].data.bitstream = NULL;
if(node->state == WAITING) return 1;

View File

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

View File

@ -37,7 +37,13 @@ static int INJECTED_PREVIEW_FUNC(CHiPubNode *preview) {
CHiValue *val = CHi_Crawl(&preview->sinks[0]);
if(val->type == CUTIHI_VAL_SAMPLE && val->data.sample) {
float t = CHi_Time_Get(preview->ng);
globaldis->CallAfter([=](){
globaldis->viewer->SetImage(val->data.sample);
globaldis->timeline->Refresh();
globaldis->stba->SetStatusText(wxString::Format("%02i:%02i:%06.03fs", (int) (t / 3600), (int) (t / 60), fmodf(t, 60)));
});
}
return 1;
@ -301,21 +307,6 @@ Frame::Frame() : wxFrame(NULL, wxID_ANY, "Cuticle", wxDefaultPosition, {wxSystem
} else {
CHi_BeginCompilation(graph->backendNG);
toolbar.btnPerform->SetLabel("Kill");
std::thread{[=](){
while(graph->backendNG->compilationStatus == CUTIHI_COMP_RUNNING) {
CallAfter([=](){
float t = CHi_Time_Get(graph->backendNG);
stba->SetStatusText(wxString::Format("%02i:%02i:%06.03fs", (int) (t / 3600), (int) (t / 60), fmodf(t, 60)));
});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
CallAfter([=](){
stba->SetStatusText("Compilation has ended.");
});
}}.detach();
}
});
@ -412,6 +403,9 @@ void Frame::LoadProject(std::string filename) {
auto tlba = ((Frame*) ng->ud)->tlba;
tlba->EnableTool(wxID_SAVE, true);
tlba->EnableTool(wxID_OPEN, true);
auto stba = ((Frame*) ng->ud)->stba;
stba->SetStatusText("Compilation has ended.");
});
};