Shared library rework & external async API support

This commit is contained in:
Jarcode
2019-08-28 00:24:59 -07:00
parent 5630e2314b
commit f562bc690d
12 changed files with 322 additions and 114 deletions

View File

@@ -1,4 +1,4 @@
.PHONY: all install clean
.PHONY: all install clean ninja build
# In case these were specified explicitly as options instead of environment variables, export them to child processes
export DESTDIR
@@ -6,12 +6,12 @@ export CFLAGS
BUILD_DIR = build
MESON_CONF = $(BUILD_DIR)
MESON_CONF = $(BUILD_DIR) -Ddisable_obs=true
# Support assigning standalone/debug builds as the old Makefile did, otherwise complain
ifneq ($(BUILD),debug)
MESON_CONF += --buildtype=release
MESON_CONF += --prefix /usr --buildtype=release
ifdef BUILD
@echo "WARNING: ignoring build option '$(BUILD)' in compatibility Makefile"
endif
@@ -34,6 +34,7 @@ $(shell if [ '$(STATE)' != "`cat build_state`" ]; then echo '$(STATE)' > build_s
ifndef BUILD
@echo ""
@echo "PACKAGE MAINTAINER NOTICE: Configuring release build for compatibility with old makefile."
@echo " Some new features may be missing."
@echo " If you are a package maintainer consider using meson directly!"
@echo ""
endif
@@ -50,7 +51,7 @@ ninja: build
ninja -C $(BUILD_DIR)
install:
cd $(BUILD_DIR) && meson install
ninja -C build install
clean:
rm -rf $(BUILD_DIR)

26
glava-cli/cli.c Normal file
View File

@@ -0,0 +1,26 @@
#include <glava.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
static renderer_handle handle;
static void handle_term (int _) {
printf("Interrupt recieved, closing...\n");
glava_terminate(&handle);
}
static void handle_reload(int _) {
printf("User signal recieved, reloading...\n");
glava_reload(&handle);
}
int main(int argc, char** argv) {
const struct sigaction term_action = { .sa_handler = handle_term };
const struct sigaction reload_action = { .sa_handler = handle_reload };
sigaction(SIGTERM, &term_action, NULL);
sigaction(SIGINT, &term_action, NULL);
sigaction(SIGUSR1, &reload_action, NULL);
glava_entry(argc, argv, &handle);
return EXIT_SUCCESS;
}

67
glava-obs/entry.c Normal file
View File

@@ -0,0 +1,67 @@
#include <stdlib.h>
#include <obs-module.h>
#include <obs.h>
#include <util/threading.h>
#include <util/platform.h>
OBS_DECLARE_MODULE();
struct mod_state {
obs_source_t* source;
os_event_t* stop_signal;
pthread_t thread;
bool initialized;
};
static const char* get_name(void* _) {
UNUSED_PARAMETER(_);
return "GLava Source";
}
static void destroy(void* data) {
struct mod_state* s = (struct mod_state*) data;
if (s) {
if (s->initialized) {
os_event_signal(s->stop_signal);
pthread_join(s->thread, NULL);
}
os_event_destroy(s->stop_signal);
bfree(s);
}
}
static void* work_thread(void* data) {
return NULL;
}
static void* create(obs_data_t* settings, obs_source_t* source) {
struct mod_state* s = bzalloc(sizeof(struct mod_state));
s->source = source;
if (os_event_init(&s->stop_signal, OS_EVENT_TYPE_MANUAL) != 0) {
destroy(s);
return NULL;
}
if (pthread_create(&s->thread, NULL, work_thread, s) != 0) {
destroy(s);
return NULL;
}
s->initialized = true;
return s;
}
struct obs_source_info glava_src = {
.id = "glava",
.type = OBS_SOURCE_TYPE_INPUT,
.output_flags = OBS_SOURCE_ASYNC_VIDEO,
.get_name = get_name,
.create = create,
.destroy = destroy
};
bool obs_module_load(void) {
obs_register_source(&glava_src);
return true;
}

View File

@@ -5,7 +5,6 @@
#include <string.h>
#include <pthread.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
@@ -73,7 +72,12 @@
#define ACCESSPERMS (S_IRWXU|S_IRWXG|S_IRWXO) /* 0777 */
#endif
static bool reload = false;
static volatile bool reload = false;
__attribute__((noreturn, visibility("default"))) void glava_return_builtin(void) { exit(EXIT_SUCCESS); }
__attribute__((noreturn, visibility("default"))) void glava_abort_builtin (void) { exit(EXIT_FAILURE); }
__attribute__((noreturn, visibility("default"))) void (*glava_return) (void) = glava_return_builtin;
__attribute__((noreturn, visibility("default"))) void (*glava_abort) (void) = glava_abort_builtin;
/* Copy installed shaders/configuration from the installed location
(usually /etc/xdg). Modules (folders) will be linked instead of
@@ -86,13 +90,13 @@ static void copy_cfg(const char* path, const char* dest, bool verbose) {
DIR* dir = opendir(path);
if (!dir) {
fprintf(stderr, "'%s' does not exist\n", path);
exit(EXIT_FAILURE);
glava_abort();
}
umask(~(S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH));
if (mkdir(dest, ACCESSPERMS) && errno != EEXIST) {
fprintf(stderr, "could not create directory '%s': %s\n", dest, strerror(errno));
exit(EXIT_FAILURE);
glava_abort();
}
struct dirent* d;
@@ -232,28 +236,48 @@ static struct option p_opts[] = {
static renderer* rd = NULL;
static void handle_term(int signum) {
if (rd->alive) {
puts("\nInterrupt recieved, closing...");
rd->alive = false;
}
}
static void handle_reload(int signum) {
if (rd->alive) {
puts("\nSIGUSR1 recieved, reloading...");
rd->alive = false;
}
reload = true;
}
#define append_buf(buf, sz_store, ...) \
({ \
buf = realloc(buf, ++(*sz_store) * sizeof(*buf)); \
buf[*sz_store - 1] = __VA_ARGS__; \
})
int main(int argc, char** argv) {
/* Wait for renderer target texture to be initialized and valid */
__attribute__((visibility("default"))) void glava_wait(renderer_handle* ref) {
while(__atomic_load_n(ref, __ATOMIC_SEQ_CST) == NULL) {
/* Edge case: handle has not been assigned */
struct timespec tv = {
.tv_sec = 0, .tv_nsec = 10 * 1000000
};
nanosleep(&tv, NULL);
}
pthread_mutex_lock(&(*ref)->lock);
pthread_cond_wait(&(*ref)->cond, &(*ref)->lock);
pthread_mutex_unlock(&(*ref)->lock);
}
/* Atomic size request */
__attribute__((visibility("default"))) void glava_sizereq(renderer_handle r, int x, int y, int w, int h) {
r->sizereq = (typeof(r->sizereq)) { .x = x, .y = y, .w = w, .h = h };
__atomic_store_n(&r->sizereq_flag, GLAVA_REQ_RESIZE, __ATOMIC_SEQ_CST);
}
/* Atomic terminate request */
__attribute__((visibility("default"))) void glava_terminate(renderer_handle* ref) {
renderer_handle store = __atomic_exchange_n(ref, NULL, __ATOMIC_SEQ_CST);
__atomic_store_n(&store->alive, false, __ATOMIC_SEQ_CST);
}
/* Atomic reload request */
__attribute__((visibility("default"))) void glava_reload(renderer_handle* ref) {
renderer_handle store = __atomic_exchange_n(ref, NULL, __ATOMIC_SEQ_CST);
__atomic_store_n(&reload, true, __ATOMIC_SEQ_CST);
__atomic_store_n(&store->alive, false, __ATOMIC_SEQ_CST);
}
/* Main entry */
__attribute__((visibility("default"))) void glava_entry(int argc, char** argv, renderer_handle* ret) {
/* Evaluate these macros only once, since they allocate */
const char
@@ -284,10 +308,10 @@ int main(int argc, char** argv) {
case 'm': force = optarg; break;
case 'b': backend = optarg; break;
case 'a': audio_impl_name = optarg; break;
case '?': exit(EXIT_FAILURE); break;
case '?': glava_abort(); break;
case 'V':
puts(GLAVA_VERSION_STRING);
exit(EXIT_SUCCESS);
glava_return();
break;
default:
case 'h': {
@@ -297,7 +321,7 @@ int main(int argc, char** argv) {
bsz += snprintf(buf + bsz, sizeof(buf) - bsz, "\t\"%s\"%s\n", audio_impls[t]->name,
!strcmp(audio_impls[t]->name, audio_impl_name) ? " (default)" : "");
printf(help_str, argc > 0 ? argv[0] : "glava", buf);
exit(EXIT_SUCCESS);
glava_return();
break;
}
case 'p': {
@@ -323,7 +347,7 @@ int main(int argc, char** argv) {
if (*parsed_name == '\0') {
fprintf(stderr, "Error: invalid pipe binding name: \"%s\"\n"
"Zero length names are not permitted.\n", parsed_name);
exit(EXIT_FAILURE);
glava_abort();
}
for (char* c = parsed_name; *c != '\0'; ++c) {
switch (*c) {
@@ -331,7 +355,7 @@ int main(int argc, char** argv) {
if (c == parsed_name) {
fprintf(stderr, "Error: invalid pipe binding name: \"%s\" ('%c')\n"
"Valid names may not start with a number.\n", parsed_name, *c);
exit(EXIT_FAILURE);
glava_abort();
}
case 'a' ... 'z':
case 'A' ... 'Z':
@@ -340,13 +364,13 @@ int main(int argc, char** argv) {
fprintf(stderr, "Error: invalid pipe binding name: \"%s\" ('%c')\n"
"Valid names may only contain [a..z], [A..Z], [0..9] "
"and '_' characters.\n", parsed_name, *c);
exit(EXIT_FAILURE);
glava_abort();
}
}
for (size_t t = 0; t < binds_sz; ++t) {
if (!strcmp(binds[t].name, parsed_name)) {
fprintf(stderr, "Error: attempted to re-bind pipe argument: \"%s\"\n", parsed_name);
exit(EXIT_FAILURE);
glava_abort();
}
}
int type = -1;
@@ -364,7 +388,7 @@ int main(int argc, char** argv) {
}
if (type == -1) {
fprintf(stderr, "Error: Unsupported `--pipe` GLSL type: \"%s\"\n", parsed_type);
exit(EXIT_FAILURE);
glava_abort();
}
struct rd_bind bd = {
.name = parsed_name,
@@ -391,13 +415,13 @@ int main(int argc, char** argv) {
}
if (stdin_type == -1) {
fprintf(stderr, "Error: Unsupported `--stdin` GLSL type: \"%s\"\n", optarg);
exit(EXIT_FAILURE);
glava_abort();
}
break;
}
conflict_error:
fprintf(stderr, "Error: cannot use `--pipe` and `--stdin` together\n");
exit(EXIT_FAILURE);
glava_abort();
#ifdef GLAVA_DEBUG
case 'T': {
entry = "test_rc.glsl";
@@ -409,7 +433,7 @@ int main(int argc, char** argv) {
if (copy_mode) {
copy_cfg(install_path, user_path, verbose);
exit(EXIT_SUCCESS);
glava_return();
}
/* Handle `--force` argument as a request override */
@@ -424,12 +448,6 @@ int main(int argc, char** argv) {
append_buf(requests, &requests_sz, NULL);
append_buf(binds, &binds_sz, (struct rd_bind) { .name = NULL });
const struct sigaction term_action = { .sa_handler = handle_term };
const struct sigaction reload_action = { .sa_handler = handle_reload };
sigaction(SIGTERM, &term_action, NULL);
sigaction(SIGINT, &term_action, NULL);
sigaction(SIGUSR1, &reload_action, NULL);
float* b0, * b1, * lb, * rb;
size_t t;
struct audio_data audio;
@@ -446,13 +464,14 @@ int main(int argc, char** argv) {
if (!impl) {
fprintf(stderr, "The specified audio backend (\"%s\") is not available.\n", audio_impl_name);
exit(EXIT_FAILURE);
glava_abort();
}
instantiate:
reload = false;
rd = rd_new(system_shader_paths, entry, (const char**) requests,
instantiate: {}
rd = rd_new(system_shader_paths, entry, (const char**) requests,
backend, binds, stdin_type, desktop, verbose, test);
if (ret)
__atomic_store_n(ret, rd, __ATOMIC_SEQ_CST);
b0 = malloc(rd->bufsize_request * sizeof(float));
b1 = malloc(rd->bufsize_request * sizeof(float));
@@ -488,7 +507,7 @@ instantiate:
if (verbose) printf("Using audio source: %s\n", audio.source);
pthread_create(&thread, NULL, impl->entry, (void*) &audio);
while (rd->alive) {
while (__atomic_load_n(&rd->alive, __ATOMIC_SEQ_CST)) {
rd_time(rd); /* update timer for this frame */
@@ -526,7 +545,7 @@ instantiate:
if (rd_test_evaluate(rd)) {
fprintf(stderr, "Test results did not match expected output\n");
fflush(stderr);
exit(EXIT_FAILURE);
glava_abort();
}
}
#endif
@@ -542,6 +561,6 @@ instantiate:
free(lb);
free(rb);
rd_destroy(rd);
if (reload)
if (__atomic_exchange_n(&reload, false, __ATOMIC_SEQ_CST))
goto instantiate;
}

40
glava/glava.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef _GLAVA_H
#define _GLAVA_H
#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>
#define GLAVA_REQ_NONE 0
#define GLAVA_REQ_RESIZE 1
struct gl_data;
typedef struct renderer {
volatile bool alive;
bool mirror_input;
size_t bufsize_request, rate_request, samplesize_request;
char* audio_source_request;
int off_tex; /* final GL texture for offscreen rendering */
pthread_mutex_t lock; /* lock for reading from offscreen texture */
pthread_cond_t cond; /* cond for reading from offscreen texture */
volatile struct {
int x, y, w, h;
} sizereq;
volatile int sizereq_flag;
struct gl_data* gl;
} renderer;
/* External API */
typedef struct renderer* volatile renderer_handle;
__attribute__((noreturn, visibility("default"))) void (*glava_abort) (void);
__attribute__((noreturn, visibility("default"))) void (*glava_return) (void);
__attribute__((visibility("default"))) void glava_assign_external_ctx (void* ctx);
__attribute__((visibility("default"))) void glava_entry (int argc, char** argv, renderer_handle* ret);
__attribute__((visibility("default"))) void glava_terminate (renderer_handle* ref);
__attribute__((visibility("default"))) void glava_reload (renderer_handle* ref);
__attribute__((visibility("default"))) void glava_sizereq (renderer_handle r, int x, int y, int w, int h);
__attribute__((visibility("default"))) void glava_wait (renderer_handle* ref);
#endif /* _GLAVA_H */

View File

@@ -65,6 +65,8 @@ DECL_WINDOW_HINT_STUB(set_maximized);
extern struct gl_wcb wcb_glfw;
static bool offscreen(void) { return false; }
static void* create_and_bind(const char* name, const char* class,
const char* type, const char** states,
size_t states_sz,

View File

@@ -25,14 +25,14 @@
#include "render.h"
#include "xwin.h"
typedef struct __GLXcontextRec *GLXContext;
typedef struct __GLXcontextRec* GLXContext;
typedef XID GLXPixmap;
typedef XID GLXDrawable;
typedef void (*__GLXextFuncPtr)(void);
/* GLX 1.3 and later */
typedef struct __GLXFBConfigRec *GLXFBConfig;
typedef struct __GLXFBConfigRec* GLXFBConfig;
typedef XID GLXFBConfigID;
typedef XID GLXContextID;
typedef XID GLXWindow;
@@ -59,7 +59,6 @@ typedef XID GLXPbuffer;
#define GLX_ACCUM_BLUE_SIZE 16
#define GLX_ACCUM_ALPHA_SIZE 17
/*
* Error codes returned by glXGetConfig:
*/
@@ -184,6 +183,20 @@ struct glxwin {
static Atom ATOM__MOTIF_WM_HINTS, ATOM_WM_DELETE_WINDOW, ATOM_WM_PROTOCOLS, ATOM__NET_ACTIVE_WINDOW, ATOM__XROOTPMAP_ID;
static GLXContext sharelist_ctx;
static bool sharelist_assigned = false;
static bool offscreen(void) {
return sharelist_assigned;
}
/* Public function that can be called before GLava instantiation for offscreen rendering hooks */
/* This hook resides here since it relies on GLX functionality. */
__attribute__((visibility("default"))) void glava_assign_external_ctx(void* ctx) {
sharelist_ctx = (GLXContext) ctx;
sharelist_assigned = true;
}
static void init(void) {
display = XOpenDisplay(NULL);
if (!display) {
@@ -201,7 +214,7 @@ static void init(void) {
if (!hgl && !hglx) {
fprintf(stderr, "Failed to load GLX functions (libGL and libGLX do not exist!)\n");
exit(EXIT_FAILURE);
glava_abort();
}
/* Depending on the graphics driver, the GLX functions that we need may either be in libGL or
@@ -212,7 +225,7 @@ static void init(void) {
if (!s && hglx) s = dlsym(hglx, symbol);
if (!s) {
fprintf(stderr, "Failed to resolve GLX symbol: `%s`\n", symbol);
exit(EXIT_FAILURE);
glava_abort();
}
return s;
}
@@ -338,7 +351,12 @@ static void* create_and_bind(const char* name, const char* class,
int d, int h,
int x, int y,
int version_major, int version_minor,
bool clickthrough, bool offscreen) {
bool clickthrough, bool off) {
/* Assume offscreen rendering if hook has been used */
if (offscreen())
off = true;
struct glxwin* w = malloc(sizeof(struct glxwin));
*w = (struct glxwin) {
.override_state = '\0',
@@ -347,7 +365,7 @@ static void* create_and_bind(const char* name, const char* class,
.should_render = true,
.bg_changed = false,
.clickthrough = false,
.offscreen = offscreen
.offscreen = off
};
XVisualInfo* vi;
@@ -362,7 +380,7 @@ static void* create_and_bind(const char* name, const char* class,
"\nGLX extension version mismatch on the current display (1.4+ required, %d.%d available)\n"
"This is usually due to an outdated X server or graphics drivers.\n\n",
glx_minor, glx_major);
exit(EXIT_FAILURE);
glava_abort();
}
static int gl_attrs[] = {
@@ -393,7 +411,7 @@ static void* create_and_bind(const char* name, const char* class,
"glXChooseFBConfig(): failed with attrs "
"(GLX_CONTEXT_MAJOR_VERSION_ARB, GLX_CONTEXT_MINOR_VERSION_ARB)\n\n",
version_major, version_minor);
exit(EXIT_FAILURE);
glava_abort();
}
for (int t = 0; t < fb_sz; ++t) {
@@ -486,7 +504,7 @@ static void* create_and_bind(const char* name, const char* class,
abort();
}
if (!(w->context = glXCreateContextAttribsARB(display, config, 0, True, context_attrs))) {
if (!(w->context = glXCreateContextAttribsARB(display, config, sharelist_assigned ? sharelist_ctx : 0, True, context_attrs))) {
fprintf(stderr, "glXCreateContextAttribsARB(): failed\n");
abort();
}

View File

@@ -6,6 +6,7 @@
#include <dirent.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -147,24 +148,21 @@ struct gl_data {
bool bg_setup;
GLuint sm_utex, sm_usz, sm_uw;
bool sm_setup;
bool test_mode;
struct gl_sfbo off_sfbo;
#ifdef GLAVA_DEBUG
struct {
float r, g, b, a;
} test_eval_color;
bool debug_verbose;
bool assigned_debug_cb;
bool test_mode;
struct gl_sfbo test_sfbo;
#endif
};
#ifdef GLAVA_DEBUG
bool rd_get_test_mode(struct renderer* r) {
struct gl_data* gl = r->gl;
return gl->test_mode;
}
#endif
/* load shader file */
static GLuint shaderload(const char* rpath,
@@ -819,8 +817,14 @@ struct renderer* rd_new(const char** paths, const char* entry,
.bufsize_request = 8192,
.rate_request = 22000,
.samplesize_request = 1024,
.audio_source_request = NULL
.audio_source_request = NULL,
.off_tex = 0,
.lock = PTHREAD_MUTEX_INITIALIZER,
.cond = PTHREAD_COND_INITIALIZER,
.sizereq_flag = 0
};
pthread_mutex_lock(&r->lock);
struct gl_data* gl = r->gl;
*gl = (struct gl_data) {
@@ -863,19 +867,19 @@ struct renderer* rd_new(const char** paths, const char* entry,
.binds = bindings,
.bg_setup = false,
.sm_setup = false,
#ifdef GLAVA_DEBUG
.test_eval_color = { 0.0F, 0.0F, 0.0F, 0.0F },
.debug_verbose = verbose,
.assigned_debug_cb = false,
.test_mode = test_mode,
.test_sfbo = {
.off_sfbo = {
.name = "test",
.shader = 0,
.indirect = false,
.nativeonly = false,
.binds = NULL,
.binds_sz = 0
}
},
#ifdef GLAVA_DEBUG
.test_eval_color = { 0.0F, 0.0F, 0.0F, 0.0F },
.debug_verbose = verbose,
.assigned_debug_cb = false,
#endif
};
@@ -905,7 +909,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
fprintf(stderr, "\t\"%s\"\n", wcbs[t]->name);
}
}
exit(EXIT_FAILURE);
glava_abort();
}
if (verbose) printf("Using backend: '%s'\n", backend);
@@ -966,7 +970,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
if (!gl->copy_desktop && !native_opacity && strcmp("none", (char*) args[0])) {
fprintf(stderr, "Invalid opacity option: '%s'\n", (char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
})
},
@@ -992,7 +996,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
};
if (!ext_parse_color((char*) args[0], 2, results)) {
fprintf(stderr, "Invalid value for `setbg` request: '%s'\n", (char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
})
},
@@ -1008,7 +1012,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
};
if (!ext_parse_color((char*) args[0], 2, results)) {
fprintf(stderr, "Invalid value for `setbg` request: '%s'\n", (char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
})
},
@@ -1042,7 +1046,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
current->nativeonly = *(bool*) args[0];
else {
fprintf(stderr, "`nativeonly` request needs module context\n");
exit(EXIT_FAILURE);
glava_abort();
}
})
},
@@ -1157,7 +1161,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
fprintf(stderr, "Cannot add transformation to uniform '%s':"
" uniform does not exist! (%d present in this unit)\n",
(const char*) args[0], (int) current->binds_sz);
exit(EXIT_FAILURE);
glava_abort();
}
struct gl_transform* tran = NULL;
for (t = 0; t < sizeof(transform_functions) / sizeof(struct gl_transform); ++t) {
@@ -1170,12 +1174,12 @@ struct renderer* rd_new(const char** paths, const char* entry,
fprintf(stderr, "Cannot add transformation '%s' to uniform '%s':"
" transform function does not exist!\n",
(const char*) args[1], (const char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
if (tran->type != bind->type) {
fprintf(stderr, "Cannot apply '%s' to uniform '%s': mismatching types\n",
(const char*) args[1], (const char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
++bind->t_sz;
bind->transformations =
@@ -1190,13 +1194,13 @@ struct renderer* rd_new(const char** paths, const char* entry,
if (!current) {
fprintf(stderr, "Cannot bind uniform '%s' outside of a context"
" (load a module first!)\n", (const char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
struct gl_bind_src* src = lookup_bind_src((const char*) args[0]);
if (!src) {
fprintf(stderr, "Cannot bind uniform '%s': bind type does not exist!\n",
(const char*) args[0]);
exit(EXIT_FAILURE);
glava_abort();
}
++current->binds_sz;
current->binds = realloc(current->binds, current->binds_sz * sizeof(struct gl_bind));
@@ -1246,7 +1250,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
errno != ENOTDIR &&
errno != ELOOP ) {
fprintf(stderr, "Failed to load entry '%s': %s\n", se_buf, strerror(errno));
exit(EXIT_FAILURE);
glava_abort();
} else continue;
}
fstat(fd, &st);
@@ -1275,7 +1279,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
errno != ELOOP) {
fprintf(stderr, "Failed to load desktop environment specific presets "
"at '%s': %s\n", se_buf, strerror(errno));
exit(EXIT_FAILURE);
glava_abort();
} else {
printf("No presets for current desktop environment (\"%s\"), "
"using default presets for embedding\n", env);
@@ -1284,7 +1288,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
if (fd == -1) {
fprintf(stderr, "Failed to load default presets at '%s': %s\n",
se_buf, strerror(errno));
exit(EXIT_FAILURE);
glava_abort();
}
}
}
@@ -1336,7 +1340,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
"No module was selected, edit '%s' to load "
"a module with `#request mod [name]`\n",
entry);
exit(EXIT_FAILURE);
glava_abort();
}
gl->w = gl->wcb->create_and_bind(wintitle, "GLava", xwintype, (const char**) xwinstates, xwinstates_sz,
@@ -1442,7 +1446,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
if (skip && verbose) printf("disabled: '%s'\n", d->d_name);
/* check for compilation failure */
if (!id && !skip)
exit(EXIT_FAILURE);
glava_abort();
s->shader = id;
@@ -1472,7 +1476,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
s->pipe_uniforms[u] = glGetUniformLocation(id, buf);
} else {
fprintf(stderr, "failed to format binding: \"%s\"\n", bd->name);
exit(EXIT_FAILURE);
glava_abort();
}
++u;
}
@@ -1492,14 +1496,15 @@ struct renderer* rd_new(const char** paths, const char* entry,
gl->stages = stages;
gl->stages_sz = count;
#ifdef GLAVA_DEBUG
{
if (gl->test_mode || gl->wcb->offscreen()) {
int w, h;
gl->wcb->get_fbsize(gl->w, &w, &h);
setup_sfbo(&gl->test_sfbo, w, h);
setup_sfbo(&gl->off_sfbo, w, h);
r->off_tex = gl->off_sfbo.tex;
pthread_cond_signal(&r->cond);
pthread_mutex_unlock(&r->lock);
}
#endif
{
struct gl_sfbo* final = NULL;
@@ -1636,6 +1641,13 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
irb[t] = irbs + ((irbe - irbs) * mod);
}
}
/* Handle external resize requests */
if (gl->wcb->offscreen()) {
if (__atomic_exchange_n(&r->sizereq_flag, GLAVA_REQ_NONE, __ATOMIC_SEQ_CST) == GLAVA_REQ_RESIZE)
gl->wcb->set_geometry(gl->w, r->sizereq.x, r->sizereq.y, r->sizereq.w, r->sizereq.h);
}
int ww, wh, wx, wy;
gl->wcb->get_fbsize(gl->w, &ww, &wh);
gl->wcb->get_pos(gl->w, &wx, &wy);
@@ -1647,9 +1659,8 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
setup_sfbo(&gl->stages[t], ww, wh);
}
}
#ifdef GLAVA_DEBUG
setup_sfbo(&gl->test_sfbo, ww, wh);
#endif
if (gl->test_mode || gl->wcb->offscreen())
setup_sfbo(&gl->off_sfbo, ww, wh);
}
/* Resize and grab new background data if needed */
@@ -1843,11 +1854,9 @@ bool rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
if (current->indirect)
glBindFramebuffer(GL_FRAMEBUFFER, current->fbo);
#ifdef GLAVA_DEBUG
if (!current->indirect && gl->test_mode) {
glBindFramebuffer(GL_FRAMEBUFFER, gl->test_sfbo.fbo);
if (!current->indirect && (gl->test_mode || gl->wcb->offscreen())) {
glBindFramebuffer(GL_FRAMEBUFFER, gl->off_sfbo.fbo);
}
#endif
glClear(GL_COLOR_BUFFER_BIT);

View File

@@ -2,6 +2,11 @@
#ifndef RENDER_H
#define RENDER_H
#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>
#include "glava.h"
extern const struct {
const char* n;
int i;
@@ -18,15 +23,6 @@ extern bool glad_instantiated;
#define PIPE_DEFAULT "_"
struct gl_data;
typedef struct renderer {
bool alive, mirror_input;
size_t bufsize_request, rate_request, samplesize_request;
char* audio_source_request;
struct gl_data* gl;
} renderer;
struct rd_bind {
const char* name;
const char* stype;
@@ -53,6 +49,7 @@ struct gl_wcb* rd_get_wcb (struct renderer*);
/* gl_wcb - OpenGL Window Creation Backend interface */
struct gl_wcb {
const char* name;
bool (*offscreen) (void);
void (*init) (void);
void* (*create_and_bind)(const char* name, const char* class,
const char* type, const char** states,
@@ -96,6 +93,7 @@ struct gl_wcb {
#define WCB_ATTACH(B, N) \
struct gl_wcb N = { \
.name = B, \
WCB_FUNC(offscreen), \
WCB_FUNC(init), \
WCB_FUNC(create_and_bind), \
WCB_FUNC(should_close), \

View File

@@ -295,7 +295,7 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
if ((shminfo.shmid = shmget(IPC_PRIVATE, image->bytes_per_line * image->height,
IPC_CREAT | 0777)) == -1) {
fprintf(stderr, "shmget() failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
glava_abort();
}
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
shminfo.readOnly = false;
@@ -314,7 +314,7 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
if (image) {
bool invalid = false, aligned = false;
GLenum type;
GLenum type = 0;
switch (image->bits_per_pixel) {
case 16:
switch (image->depth) {

View File

@@ -21,7 +21,6 @@ else
add_project_arguments(
'-O2',
'-Wstringop-overflow=0',
'-Wmaybe-uninitialized=0',
language: 'c'
)
if get_option('glad')
@@ -83,17 +82,27 @@ endif
add_project_arguments(
'-DGLAVA_VERSION="'+glava_version+'"',
'-DSHADER_INSTALL_PATH="'+shaderdir+'"',
'-DSHADER_INSTALL_PATH="'+shaderdir+'/glava"',
'-I/usr/include/obs',
'-fvisibility=hidden',
language: 'c'
)
executable(
libglava = shared_library(
'glava',
sources: run_command('find', 'glava', '-type', 'f', '-name', '*.c', '-print').stdout().strip().split('\n'),
dependencies: glava_dependencies,
install: true
)
executable(
'glava',
sources: run_command('find', 'glava-cli', '-type', 'f', '-name', '*.c', '-print').stdout().strip().split('\n'),
link_with: libglava,
include_directories: 'glava',
install: true
)
executable(
'glava-config',
sources: run_command('find', 'glava-config', '-type', 'f', '-name', '*.c', '-print').stdout().strip().split('\n'),
@@ -105,4 +114,22 @@ executable(
install: true
)
install_subdir('shaders/glava', install_dir: shaderdir+'/../')
if not get_option('disable_obs')
shared_library(
'glava-obs',
sources: run_command('find', 'glava-obs', '-type', 'f', '-name', '*.c', '-print').stdout().strip().split('\n'),
link_with: libglava,
dependencies: [
dependency('threads'),
cc.find_library('GL'),
cc.find_library('X11'),
cc.find_library('obs'),
cc.find_library('dl')
],
install: true,
install_dir : '/usr/lib/obs-plugins'
)
endif
install_subdir('shaders/glava', install_dir: shaderdir)
install_headers('glava/glava.h')

View File

@@ -1,5 +1,6 @@
option('shaderdir', type: 'string', value: '/etc/xdg/glava/', description: 'Default shader directory')
option('shaderdir', type: 'string', value: '/etc/xdg', description: 'System shader directory location')
option('enable_glfw', type: 'boolean', value: false, description: 'Enable GLFW backend')
option('disable_glx', type: 'boolean', value: false, description: 'Disable GLX')
option('standalone', type: 'boolean', value: false, description: 'OS-independent build')
option('glad', type: 'boolean', value: false, description: 'Regenerate GLAD')
option('disable_obs', type: 'boolean', value: false, description: 'Dsiable OBS plugin support')