
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.
206 lines
5.0 KiB
C++
206 lines
5.0 KiB
C++
#include"node.h"
|
|
|
|
#include<stdlib.h>
|
|
|
|
#include<X11/Xlib.h>
|
|
#include<X11/Xutil.h>
|
|
#include<sys/ipc.h>
|
|
#include<sys/shm.h>
|
|
#include<X11/extensions/XShm.h>
|
|
#include<tmmintrin.h>
|
|
#include<smmintrin.h>
|
|
|
|
#include<time.h>
|
|
|
|
#include<string.h>
|
|
|
|
#include"img.h"
|
|
|
|
#include"linearity.h"
|
|
|
|
#include"minitrace.h"
|
|
|
|
static thread_local Display *d;
|
|
static thread_local Window root;
|
|
|
|
static int find_window(Display *d, Window *w, const char *contains) {
|
|
if(contains) {
|
|
int found = 0;
|
|
Atom atom = XInternAtom(d, "_NET_CLIENT_LIST", 1);
|
|
Atom actualType;
|
|
int format;
|
|
unsigned long numItems, bytesAfter;
|
|
|
|
Window *list;
|
|
XTextProperty windowName;
|
|
|
|
int status = XGetWindowProperty(d, root, atom, 0L, ~0L, 0, AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, (unsigned char**) &list);
|
|
|
|
if(status >= Success) {
|
|
for(int i = 0; i < numItems; i++) {
|
|
status = XGetWMName(d, list[i], &windowName);
|
|
if(status >= Success) {
|
|
if(windowName.value && strstr((const char*) windowName.value, contains)) {
|
|
*w = list[i];
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
XFree(list);
|
|
|
|
return found;
|
|
} else {
|
|
*w = root;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
typedef struct {
|
|
Window xcache;
|
|
XImage *ximg;
|
|
XShmSegmentInfo shminfo;
|
|
|
|
CHiImage *vcache;
|
|
} WindowImpl;
|
|
|
|
static int window_perform(CHiPubNode *n) {
|
|
auto *w = (WindowImpl*) n->impl;
|
|
|
|
if(!d) {
|
|
d = XOpenDisplay(NULL);
|
|
root = RootWindow(d, DefaultScreen(d));
|
|
}
|
|
|
|
MTR_BEGIN("CHi", "window_perform");
|
|
|
|
Window toshoot;
|
|
if(!find_window(d, &toshoot, CHi_Crawl(&n->sinks[0])->data.text)) return 0;
|
|
|
|
size_t stride;
|
|
if(!w->xcache || w->xcache != toshoot) {
|
|
w->xcache = toshoot;
|
|
|
|
XWindowAttributes attrs;
|
|
XGetWindowAttributes(d, toshoot, &attrs);
|
|
|
|
w->ximg = XShmCreateImage(d, attrs.visual, 32, ZPixmap, NULL, &w->shminfo, attrs.width, attrs.height);
|
|
stride = ((w->ximg->bytes_per_line + 15) & ~15);
|
|
w->shminfo.shmid = shmget(IPC_PRIVATE, stride * w->ximg->height, IPC_CREAT | 0777);
|
|
w->shminfo.shmaddr = w->ximg->data = (char*) shmat(w->shminfo.shmid, 0, 0);
|
|
w->shminfo.readOnly = False;
|
|
XShmAttach(d, &w->shminfo);
|
|
|
|
w->vcache = CHi_Image_New(2, 4, (8 * attrs.width + 15) & ~15, attrs.width, attrs.height, NULL);
|
|
} else {
|
|
stride = ((w->ximg->bytes_per_line + 15) & ~15);
|
|
}
|
|
|
|
XWindowAttributes toshootattrs;
|
|
XGetWindowAttributes(d, w->xcache, &toshootattrs);
|
|
|
|
XShmGetImage(d, w->xcache, w->ximg, 0, 0, AllPlanes);
|
|
|
|
bool ignoreAlpha = CHi_Crawl(&n->sinks[1])->data.vec4[0] != 0;
|
|
|
|
// Turn u8 image to u16
|
|
#pragma omp parallel for
|
|
for(size_t y = 0; y < w->vcache->height; y++) {
|
|
for(size_t x = 0; x < w->vcache->width; x += 2) {
|
|
__m128i c = _mm_loadu_si128((__m128i*) ((uintptr_t) w->ximg->data + y * w->ximg->bytes_per_line + x * 4));
|
|
c = _mm_shuffle_epi8(c, _mm_set_epi8(7, -128, 6, -128, 5, -128, 4, -128, 3, -128, 2, -128, 1, -128, 0, -128));
|
|
if(ignoreAlpha) {
|
|
c = _mm_or_si128(c, _mm_set_epi16(0xFFFF, 0, 0, 0, 0xFFFF, 0, 0, 0));
|
|
}
|
|
c = apply_gamma_epi16(c, _mm_set_ps(1, 2.2f, 2.2f, 2.2f));
|
|
_mm_storeu_si128((__m128i*) ((uintptr_t) w->vcache->data16 + y * w->vcache->stride + x * 8), c);
|
|
}
|
|
}
|
|
|
|
n->sources[0].type = CUTIHI_VAL_SAMPLE;
|
|
n->sources[0].data.sample = w->vcache;
|
|
|
|
MTR_END("CHi", "window_perform");
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void window_destroy(CHiPubNode *pubn) {
|
|
auto *n = (WindowImpl*) pubn->impl;
|
|
|
|
if(n->vcache) {
|
|
XShmDetach(d, &n->shminfo);
|
|
shmdt(n->shminfo.shmaddr);
|
|
XDestroyImage(n->ximg);
|
|
}
|
|
|
|
free(pubn);
|
|
}
|
|
|
|
CUTIVIS CHiPubNode *CHi_Window() {
|
|
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
|
|
|
|
struct WindowListDatum {
|
|
Window handle;
|
|
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;
|
|
int format;
|
|
unsigned long numItems, bytesAfter;
|
|
|
|
Window *list;
|
|
XTextProperty windowName;
|
|
|
|
int status = XGetWindowProperty(d, root, atom, 0L, ~0L, 0, AnyPropertyType, &actualType, &format, &numItems, &bytesAfter, (unsigned char**) &list);
|
|
|
|
if(status >= Success) {
|
|
WindowListDatum *data = (WindowListDatum*) calloc(numItems, sizeof(*data));
|
|
size_t successfulWindows = 0;
|
|
|
|
for(size_t i = 0; i < numItems; i++) {
|
|
status = XGetWMName(d, list[i], &windowName);
|
|
if(status >= Success) {
|
|
data[successfulWindows].handle = list[i];
|
|
strncpy(data[successfulWindows].name, (char*) windowName.value, sizeof(data[successfulWindows].name));
|
|
|
|
successfulWindows++;
|
|
}
|
|
}
|
|
|
|
XFree(list);
|
|
|
|
*buf = data;
|
|
return successfulWindows;
|
|
}
|
|
|
|
*buf = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
CUTIVIS const char *CHi_Window_GetName(void *buf, size_t i) {
|
|
return ((WindowListDatum*) buf)[i].name;
|
|
}
|
|
CUTIVIS size_t CHi_Window_GetHandle(void *buf, size_t i) {
|
|
return ((WindowListDatum*) buf)[i].handle;
|
|
}
|
|
CUTIVIS void CHi_Window_FreeList(void *buf) {
|
|
free(buf);
|
|
}
|