refactor: specify number of video input buffers
Clang Lint CI / lint-no-video (push) Successful in 1m5s
Clang Build CI / run-no-video (push) Successful in 1m5s
Clang Build CI / run-video (push) Successful in 1m5s
Clang Build CI / build-release (push) Successful in 2m24s
Clang Lint CI / lint-video (push) Successful in 2m22s

This commit is contained in:
2026-05-15 00:09:51 +02:00
parent 06d175c4fd
commit 37a492d00d
9 changed files with 172 additions and 150 deletions
+3 -2
View File
@@ -174,9 +174,9 @@ These are configurable in the [`forge_project.cfg`](#forge_projectcfg).
### CLI arguments ### CLI arguments
```txt ```txt
forge steel-dev forge steel-VERSION
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf] usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vb=COUNT] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf]
Fusion Of Real-time Generative Effects. Fusion Of Real-time Generative Effects.
@@ -196,6 +196,7 @@ options:
-nar, --no-auto-random do not randomize state (default) -nar, --no-auto-random do not randomize state (default)
-arc, --auto-random-cycle auto random cycle length (default: 4) -arc, --auto-random-cycle auto random cycle length (default: 4)
-vi, --video-in path to video capture device (multiple allowed) -vi, --video-in path to video capture device (multiple allowed)
-vb, --video-buffers number of video buffers to use (default: 2)
-vs, --video-size video capture desired height (default: internal texture height) -vs, --video-size video capture desired height (default: internal texture height)
-vr, --video-reconnect auto-reconnect video (default) -vr, --video-reconnect auto-reconnect video (default)
-nvr, --no-video-reconnect do not auto-reconnect video -nvr, --no-video-reconnect do not auto-reconnect video
-5
View File
@@ -51,8 +51,6 @@ UNIFORM_STATE_PREFIX=iState
UNIFORM_ACTIVE_PREFIX=iActive UNIFORM_ACTIVE_PREFIX=iActive
# Input X format raw integer value # Input X format raw integer value
UNIFORM_IN_FORMAT_PREFIX=iInputFormat UNIFORM_IN_FORMAT_PREFIX=iInputFormat
# Input X should use swap texture or not (0/1)
UNIFORM_IN_SWAP_PREFIX=iInputSwap
# --- uniform vec2 --- # --- uniform vec2 ---
@@ -106,9 +104,6 @@ IN_COUNT=2
# To which texture will be bound video device X # To which texture will be bound video device X
IN_1_OUT=1 IN_1_OUT=1
IN_2_OUT=2 IN_2_OUT=2
# To which texture will be bound swap buffers (for double-buffering)
IN_1_SWAP_OUT=3
IN_2_SWAP_OUT=4
# === FRAGMENT SHADERS # === FRAGMENT SHADERS
# Fragment shaders will be read from the CLI directory as "fragX.glsl" # Fragment shaders will be read from the CLI directory as "fragX.glsl"
+35 -33
View File
@@ -32,6 +32,7 @@ static void print_help(int status_code) {
#ifdef VIDEO_IN #ifdef VIDEO_IN
"[-vi=FILE] " "[-vi=FILE] "
"[-vs=SIZE] " "[-vs=SIZE] "
"[-vb=COUNT] "
"[-vr / -nvr] " "[-vr / -nvr] "
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
"[-is=SIZE] " "[-is=SIZE] "
@@ -63,6 +64,8 @@ static void print_help(int status_code) {
#ifdef VIDEO_IN #ifdef VIDEO_IN
" -vi, --video-in path to video capture device (multiple " " -vi, --video-in path to video capture device (multiple "
"allowed)\n" "allowed)\n"
" -vb, --video-buffers number of video buffers to use (default: "
"2)\n"
" -vs, --video-size video capture desired height (default: " " -vs, --video-size video capture desired height (default: "
"internal texture height)\n" "internal texture height)\n"
" -vr, --video-reconnect auto-reconnect video (default)\n" " -vr, --video-reconnect auto-reconnect video (default)\n"
@@ -134,9 +137,12 @@ void args_parse(Parameters *params, int argc, char **argv) {
params->demo = false; params->demo = false;
params->auto_random = false; params->auto_random = false;
params->auto_random_cycle = 4; params->auto_random_cycle = 4;
#ifdef VIDEO_IN
params->video_in.length = 0; params->video_in.length = 0;
params->video_buffers = 2;
params->video_size = 0; params->video_size = 0;
params->video_reconnect = true; params->video_reconnect = true;
#endif /* VIDEO_IN */
params->internal_size = 720; params->internal_size = 720;
params->load_state = true; params->load_state = true;
params->save_state = true; params->save_state = true;
@@ -184,38 +190,6 @@ void args_parse(Parameters *params, int argc, char **argv) {
if (params->auto_random_cycle == 0) { if (params->auto_random_cycle == 0) {
invalid_value(arg, value); invalid_value(arg, value);
} }
} else if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) {
#ifdef VIDEO_IN
if (params->video_in.length == MAX_VIDEO) {
log_error("maximum video input reached");
exit(EXIT_FAILURE);
}
strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN);
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
#ifdef VIDEO_IN
params->video_size = parse_uint(arg, value);
if (params->video_size == 0) {
invalid_value(arg, value);
}
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) {
#ifdef VIDEO_IN
params->video_reconnect = true;
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) {
#ifdef VIDEO_IN
params->video_reconnect = false;
#else
invalid_arg(arg);
#endif /* VIDEO_IN */
} else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) {
params->internal_size = parse_uint(arg, value); params->internal_size = parse_uint(arg, value);
if (params->internal_size == 0) { if (params->internal_size == 0) {
@@ -238,7 +212,34 @@ void args_parse(Parameters *params, int argc, char **argv) {
} else if (is_arg(arg, "-tf") || is_arg(arg, "--trace-fps")) { } else if (is_arg(arg, "-tf") || is_arg(arg, "--trace-fps")) {
params->trace_fps = true; params->trace_fps = true;
} else { } else {
#ifdef VIDEO_IN
if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) {
if (params->video_in.length == MAX_VIDEO) {
log_error("maximum video input reached");
exit(EXIT_FAILURE);
}
strlcpy(params->video_in.values[params->video_in.length++], value,
STR_LEN);
} else if (is_arg(arg, "-vb") || is_arg(arg, "--video-buffers")) {
params->video_buffers = parse_uint(arg, value);
if (params->video_buffers == 0) {
invalid_value(arg, value);
}
} else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) {
params->video_size = parse_uint(arg, value);
if (params->video_size == 0) {
invalid_value(arg, value);
}
} else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) {
params->video_reconnect = true;
} else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) {
params->video_reconnect = false;
} else {
invalid_arg(arg);
}
#else
invalid_arg(arg); invalid_arg(arg);
#endif /* VIDEO_IN */
} }
} }
@@ -247,8 +248,9 @@ void args_parse(Parameters *params, int argc, char **argv) {
log_error("monitor screen cannot be the same as output screen"); log_error("monitor screen cannot be the same as output screen");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
#ifdef VIDEO_IN
if (params->video_size == 0) { if (params->video_size == 0) {
params->video_size = params->internal_size; params->video_size = params->internal_size;
} }
#endif /* VIDEO_IN */
} }
+5 -4
View File
@@ -70,7 +70,7 @@ static void init_context() {
memset(context.input_resolutions, 0, sizeof(context.input_resolutions)); memset(context.input_resolutions, 0, sizeof(context.input_resolutions));
memset(context.input_formats, 0, sizeof(context.input_formats)); memset(context.input_formats, 0, sizeof(context.input_formats));
memset(context.input_fps, 0, sizeof(context.input_fps)); memset(context.input_fps, 0, sizeof(context.input_fps));
memset(context.input_swap, 0, sizeof(context.input_swap)); memset(context.input_index, 0, sizeof(context.input_index));
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
} }
@@ -85,7 +85,7 @@ static void init_inputs() {
for (unsigned int i = 0; i < init_params.video_in.length; i++) { for (unsigned int i = 0; i < init_params.video_in.length; i++) {
video_init(&video_captures.values[i], init_params.video_in.values[i], video_init(&video_captures.values[i], init_params.video_in.values[i],
init_params.video_size); init_params.video_size, init_params.video_buffers);
if (!video_captures.values[i].error) { if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width; context.input_resolutions[i][0] = video_captures.values[i].width;
@@ -121,7 +121,7 @@ background_reconnect_video_captures(__attribute__((unused)) void *args) {
if (video_captures.values[i].disconnected) { if (video_captures.values[i].disconnected) {
video_free(&video_captures.values[i]); video_free(&video_captures.values[i]);
video_init(&video_captures.values[i], init_params.video_in.values[i], video_init(&video_captures.values[i], init_params.video_in.values[i],
init_params.video_size); init_params.video_size, init_params.video_buffers);
if (!video_captures.values[i].error) { if (!video_captures.values[i].error) {
context.input_resolutions[i][0] = video_captures.values[i].width; context.input_resolutions[i][0] = video_captures.values[i].width;
@@ -292,7 +292,8 @@ static bool init(const Parameters *params) {
} }
#ifdef VIDEO_IN #ifdef VIDEO_IN
shaders_link_inputs(&program, &project, &video_captures); shaders_link_inputs(&program, &project, &video_captures,
init_params.video_buffers);
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
if (program.error) { if (program.error) {
+77 -53
View File
@@ -191,18 +191,20 @@ static void rebind_textures(const ShaderProgram *program) {
#ifdef VIDEO_IN #ifdef VIDEO_IN
static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input, static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
unsigned int input_index, unsigned int input_index,
unsigned int texture_index, bool swap, unsigned int sub_index, bool reload) {
bool reload) { unsigned int texture_index =
program->tex_count + input_index * program->sub_video_count + sub_index;
if (reload) { if (reload) {
glDeleteTextures(1, program->textures + texture_index); glDeleteTextures(1, program->textures + texture_index);
if (check_glerror(program, "link_input_to_texture/glDeleteTextures")) { if (check_glerror(program, "link_input_to_texture/glDeleteTextures")) {
return false; return false;
} }
}
glGenTextures(1, program->textures + texture_index); glGenTextures(1, program->textures + texture_index);
if (check_glerror(program, "link_input_to_texture/glGenTextures")) { if (check_glerror(program, "link_input_to_texture/glGenTextures")) {
return false; return false;
}
} }
EGLImageKHR dma_image; EGLImageKHR dma_image;
@@ -217,7 +219,7 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
EGL_LINUX_DRM_FOURCC_EXT, EGL_LINUX_DRM_FOURCC_EXT,
input->pixelformat, input->pixelformat,
EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_FD_EXT,
swap ? input->exp_fd_swap : input->exp_fd, input->exp_fd[sub_index],
EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT,
0, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT,
@@ -230,11 +232,8 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
return false; return false;
} }
if (swap) { program->dma_images[input_index * program->sub_video_count + sub_index] =
program->dma_images_swap[input_index] = dma_image; dma_image;
} else {
program->dma_images[input_index] = dma_image;
}
glActiveTexture(GL_TEXTURE0 + texture_index); glActiveTexture(GL_TEXTURE0 + texture_index);
if (check_glerror(program, "link_input_to_texture/glActiveTexture")) { if (check_glerror(program, "link_input_to_texture/glActiveTexture")) {
@@ -259,33 +258,35 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
return false; return false;
} }
log_info("Texture %d linked to %s", texture_index, input->name); log_info("Texture %d linked to %s[%d]", texture_index, input->name,
sub_index);
return true; return true;
} }
static bool init_input(ShaderProgram *program, const ConfigFile *config, static bool init_input(ShaderProgram *program, const ConfigFile *config,
VideoCaptureArray *inputs, unsigned int i, bool reload) { VideoCaptureArray *inputs, unsigned int input_index,
bool reload) {
unsigned int tex_i; unsigned int tex_i;
unsigned int sub_index;
char name[STR_LEN]; char name[STR_LEN];
if (i < inputs->length && !inputs->values[i].error) { if (input_index < inputs->length && input_index < program->in_count &&
snprintf(name, STR_LEN, "IN_%d_OUT", i + 1); !inputs->values[input_index].error) {
snprintf(name, STR_LEN, "IN_%d_OUT", input_index + 1);
tex_i = config_file_get_int(config, name, 0); tex_i = config_file_get_int(config, name, 0);
if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, false, for (sub_index = 0; sub_index < inputs->values[input_index].buf_count;
reload)) { sub_index++) {
return false; if (!link_input_to_texture(program, &inputs->values[input_index],
} input_index, sub_index, reload)) {
if (inputs->values[i].with_swap) {
snprintf(name, STR_LEN, "IN_%d_SWAP_OUT", i + 1);
tex_i = config_file_get_int(config, name, 0);
if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, true,
reload)) {
return false; return false;
} }
} }
program->input_tex_map[input_index] = tex_i;
program->tex_map[tex_i] =
program->tex_count + input_index * program->sub_video_count;
} else { } else {
log_warn("Cannot link input %d", i + 1); log_warn("Cannot link input %d", input_index + 1);
} }
return true; return true;
} }
@@ -535,13 +536,6 @@ static bool init_single_program(ShaderProgram *program, unsigned int i,
glGetUniformLocation(program->programs[i], name); glGetUniformLocation(program->programs[i], name);
} }
prefix = config_file_get_str(config, "UNIFORM_IN_SWAP_PREFIX", "iInputSwap");
for (unsigned int j = 0; j < program->in_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
program->iinswap_locations[i * program->in_count + j] =
glGetUniformLocation(program->programs[i], name);
}
prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed"); prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed");
for (unsigned int j = 0; j < program->frag_count; j++) { for (unsigned int j = 0; j < program->frag_count; j++) {
snprintf(name, STR_LEN, "%s%d", prefix, j + 1); snprintf(name, STR_LEN, "%s%d", prefix, j + 1);
@@ -650,8 +644,7 @@ static void update_viewport(ShaderProgram *program, const Context *context) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0],
context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
check_glerror_ro( check_glerror_ro("update_viewport/glTexImage2D");
"update_viewport/glTexImage2D"); // TODO dont remap input textures
} }
program->last_resolution[0] = context->resolution[0]; program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1]; program->last_resolution[1] = context->resolution[1];
@@ -736,8 +729,6 @@ static void use_program(const ShaderProgram *program, int i, bool output,
context->input_formats[j]); context->input_formats[j]);
write_uniform_1i(program->iinfps_locations[i * program->in_count + j], write_uniform_1i(program->iinfps_locations[i * program->in_count + j],
context->input_fps[j]); context->input_fps[j]);
write_uniform_1i(program->iinswap_locations[i * program->in_count + j],
context->input_swap[j] ? 1 : 0);
} }
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
@@ -781,10 +772,9 @@ static void use_program(const ShaderProgram *program, int i, bool output,
} }
// set GL_TEXTURE(X) to uniform sampler2D texX // set GL_TEXTURE(X) to uniform sampler2D texX
// TODO perform input swap here
for (unsigned int j = 0; j < program->tex_count; j++) { for (unsigned int j = 0; j < program->tex_count; j++) {
write_uniform_1i(program->textures_locations[i * program->tex_count + j], write_uniform_1i(program->textures_locations[i * program->tex_count + j],
j); program->tex_map[j]);
} }
// draw output // draw output
@@ -793,11 +783,16 @@ static void use_program(const ShaderProgram *program, int i, bool output,
void shaders_init(ShaderProgram *program, const Project *project, void shaders_init(ShaderProgram *program, const Project *project,
const Context *context, bool rebind) { const Context *context, bool rebind) {
unsigned int i;
if (!rebind) { if (!rebind) {
program->error = false; program->error = false;
program->last_resolution[0] = context->resolution[0]; program->last_resolution[0] = context->resolution[0];
program->last_resolution[1] = context->resolution[1]; program->last_resolution[1] = context->resolution[1];
program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9); program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9);
memset(program->tex_map, 0, sizeof(program->tex_map));
for (i = 0; i < program->tex_count; i++) {
program->tex_map[i] = i;
}
program->frag_count = project->frag_count; program->frag_count = project->frag_count;
program->frag_output_index = program->frag_output_index =
config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1; config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1;
@@ -812,7 +807,7 @@ void shaders_init(ShaderProgram *program, const Project *project,
#ifdef VIDEO_IN #ifdef VIDEO_IN
memset(program->dma_images, 0, sizeof(program->dma_images)); memset(program->dma_images, 0, sizeof(program->dma_images));
memset(program->dma_images_swap, 0, sizeof(program->dma_images_swap)); memset(program->input_tex_map, 0, sizeof(program->input_tex_map));
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
if (!init_gl(program)) { if (!init_gl(program)) {
@@ -848,31 +843,50 @@ void shaders_init(ShaderProgram *program, const Project *project,
#ifdef VIDEO_IN #ifdef VIDEO_IN
void shaders_relink_input(ShaderProgram *program, const Project *project, void shaders_relink_input(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs, unsigned int i) { VideoCaptureArray *inputs, unsigned int input_index) {
// shaders_free_input(program, i); shaders_free_input(program, input_index);
init_input(program, &project->config, inputs, i, true); init_input(program, &project->config, inputs, input_index, true);
} }
void shaders_link_inputs(ShaderProgram *program, const Project *project, void shaders_link_inputs(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs) { VideoCaptureArray *inputs, unsigned int buffer_count) {
for (unsigned int i = 0; i < program->in_count; i++) { unsigned int i;
program->sub_video_count = buffer_count;
for (i = 0; i < program->in_count; i++) {
init_input(program, &project->config, inputs, i, false); init_input(program, &project->config, inputs, i, false);
} }
} }
void shaders_free_input(ShaderProgram *program, unsigned int input_index) { void shaders_free_input(ShaderProgram *program, unsigned int input_index) {
if (program->dma_images[input_index] != EGL_NO_IMAGE_KHR) { unsigned int sub_index;
eglDestroyImageKHR(program->egl_display, program->dma_images[input_index]); for (sub_index = 0; sub_index < program->sub_video_count; sub_index++) {
program->dma_images[input_index] = EGL_NO_IMAGE_KHR; if (program->dma_images[input_index * program->sub_video_count +
} sub_index] != EGL_NO_IMAGE_KHR) {
if (program->dma_images_swap[input_index] != EGL_NO_IMAGE_KHR) { eglDestroyImageKHR(
eglDestroyImageKHR(program->egl_display, program->egl_display,
program->dma_images_swap[input_index]); program
program->dma_images_swap[input_index] = EGL_NO_IMAGE_KHR; ->dma_images[input_index * program->sub_video_count + sub_index]);
program->dma_images[input_index * program->sub_video_count + sub_index] =
EGL_NO_IMAGE_KHR;
}
} }
check_eglerror_ro("shaders_free_input/eglDestroyImageKHR"); check_eglerror_ro("shaders_free_input/eglDestroyImageKHR");
} }
static void update_inputs_tex_map(ShaderProgram *program,
const Context *context) {
unsigned int i;
unsigned int tex_i;
for (i = 0; i < program->in_count; i++) {
if (context->input_formats[i] != 0) {
tex_i = program->input_tex_map[i];
program->tex_map[tex_i] = program->tex_count +
i * program->sub_video_count +
context->input_index[i];
}
}
}
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
void shaders_update(ShaderProgram *program, const File *fragment_shader, void shaders_update(ShaderProgram *program, const File *fragment_shader,
@@ -887,6 +901,10 @@ void shaders_update(ShaderProgram *program, const File *fragment_shader,
void shaders_compute(ShaderProgram *program, const Context *context, void shaders_compute(ShaderProgram *program, const Context *context,
bool monitor, bool output_only) { bool monitor, bool output_only) {
#ifdef VIDEO_IN
update_inputs_tex_map(program, context);
#endif /* VIDEO_IN */
if (!output_only) { if (!output_only) {
glBindVertexArray(program->vertex_array[0]); glBindVertexArray(program->vertex_array[0]);
@@ -923,6 +941,12 @@ void shaders_free(const ShaderProgram *program) {
glDeleteTextures(program->tex_count, program->textures); glDeleteTextures(program->tex_count, program->textures);
check_glerror_ro("shaders_free/glDeleteTextures"); check_glerror_ro("shaders_free/glDeleteTextures");
#ifdef VIDEO_IN
glDeleteTextures(program->in_count * program->sub_video_count,
program->textures + program->tex_count);
check_glerror_ro("shaders_free/glDeleteTextures");
#endif
glDeleteBuffers(1, &program->vertex_buffer); glDeleteBuffers(1, &program->vertex_buffer);
check_glerror_ro("shaders_free/glDeleteBuffers"); check_glerror_ro("shaders_free/glDeleteBuffers");
} }
+1 -1
View File
@@ -12,7 +12,7 @@ void shaders_relink_input(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs, unsigned int i); VideoCaptureArray *inputs, unsigned int i);
void shaders_link_inputs(ShaderProgram *program, const Project *project, void shaders_link_inputs(ShaderProgram *program, const Project *project,
VideoCaptureArray *inputs); VideoCaptureArray *inputs, unsigned int buffer_count);
void shaders_free_input(ShaderProgram *program, unsigned int input_index); void shaders_free_input(ShaderProgram *program, unsigned int input_index);
+12 -10
View File
@@ -45,10 +45,13 @@ typedef struct Parameters {
bool demo; bool demo;
bool auto_random; bool auto_random;
unsigned int auto_random_cycle; unsigned int auto_random_cycle;
#ifdef VIDEO_IN
StringArray video_in; StringArray video_in;
unsigned int video_buffers;
unsigned int video_size; unsigned int video_size;
unsigned int internal_size;
bool video_reconnect; bool video_reconnect;
#endif /* VIDEO_IN */
unsigned int internal_size;
bool load_state; bool load_state;
bool save_state; bool save_state;
bool midi_reconnect; bool midi_reconnect;
@@ -85,6 +88,7 @@ typedef struct ShaderProgram {
GLuint vertex_array[2]; GLuint vertex_array[2];
unsigned int tex_count; unsigned int tex_count;
unsigned int tex_map[ARRAY_SIZE];
GLuint textures[ARRAY_SIZE]; GLuint textures[ARRAY_SIZE];
unsigned int frag_count; unsigned int frag_count;
@@ -105,7 +109,6 @@ typedef struct ShaderProgram {
GLuint iinres_locations[ARRAY_SIZE]; GLuint iinres_locations[ARRAY_SIZE];
GLuint iinfmt_locations[ARRAY_SIZE]; GLuint iinfmt_locations[ARRAY_SIZE];
GLuint iinfps_locations[ARRAY_SIZE]; GLuint iinfps_locations[ARRAY_SIZE];
GLuint iinswap_locations[ARRAY_SIZE];
GLuint idemo_locations[ARRAY_SIZE]; GLuint idemo_locations[ARRAY_SIZE];
GLuint iautorand_locations[ARRAY_SIZE]; GLuint iautorand_locations[ARRAY_SIZE];
GLuint iautorandcycle_locations[ARRAY_SIZE]; GLuint iautorandcycle_locations[ARRAY_SIZE];
@@ -130,9 +133,10 @@ typedef struct ShaderProgram {
unsigned int in_count; unsigned int in_count;
#ifdef VIDEO_IN #ifdef VIDEO_IN
unsigned int sub_video_count;
unsigned int input_tex_map[MAX_VIDEO];
EGLDisplay egl_display; EGLDisplay egl_display;
EGLImageKHR dma_images[MAX_VIDEO]; EGLImageKHR dma_images[MAX_VIDEO];
EGLImageKHR dma_images_swap[MAX_VIDEO];
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
} ShaderProgram; } ShaderProgram;
@@ -163,7 +167,7 @@ typedef struct Context {
vec2 input_resolutions[MAX_VIDEO]; vec2 input_resolutions[MAX_VIDEO];
unsigned int input_formats[MAX_VIDEO]; unsigned int input_formats[MAX_VIDEO];
unsigned int input_fps[MAX_VIDEO]; unsigned int input_fps[MAX_VIDEO];
bool input_swap[MAX_VIDEO]; unsigned int input_index[MAX_VIDEO];
#endif /* VIDEO_IN */ #endif /* VIDEO_IN */
double time; double time;
Tempo tempo; Tempo tempo;
@@ -190,17 +194,15 @@ typedef struct VideoCapture {
_Atomic bool error; _Atomic bool error;
_Atomic bool disconnected; _Atomic bool disconnected;
_Atomic bool needs_reload; _Atomic bool needs_reload;
bool with_swap; unsigned int buf_count;
_Atomic bool swap; unsigned int buf_index;
int fd; int fd;
int exp_fd; int exp_fd[ARRAY_SIZE];
int exp_fd_swap;
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
unsigned int pixelformat; unsigned int pixelformat;
unsigned int bytesperline; unsigned int bytesperline;
struct v4l2_buffer buf; struct v4l2_buffer buf[ARRAY_SIZE];
struct v4l2_buffer buf_swap;
} VideoCapture; } VideoCapture;
typedef struct VideoCaptureArray { typedef struct VideoCaptureArray {
+38 -41
View File
@@ -192,14 +192,15 @@ static bool set_format(VideoCapture *video_capture) {
return true; return true;
} }
static bool request_buffers(VideoCapture *video_capture) { static bool request_buffers(VideoCapture *video_capture,
unsigned int buffer_count) {
struct v4l2_requestbuffers reqbuf; struct v4l2_requestbuffers reqbuf;
memset(&reqbuf, 0, sizeof(reqbuf)); memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.type = buf_type; reqbuf.type = buf_type;
reqbuf.memory = V4L2_MEMORY_MMAP; reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = 2; // TODO buffer array with count from parameters reqbuf.count = buffer_count;
if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) { if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) {
ioctl_error(video_capture, "VIDIOC_REQBUFS", ioctl_error(video_capture, "VIDIOC_REQBUFS",
@@ -209,7 +210,7 @@ static bool request_buffers(VideoCapture *video_capture) {
log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count); log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count);
video_capture->with_swap = reqbuf.count > 1; video_capture->buf_count = reqbuf.count;
return true; return true;
} }
@@ -239,16 +240,15 @@ static bool export_buffer(VideoCapture *video_capture, int *fd,
} }
static bool export_buffers(VideoCapture *video_capture) { static bool export_buffers(VideoCapture *video_capture) {
bool result; unsigned int i;
result = export_buffer(video_capture, &video_capture->exp_fd, 0); for (i = 0; i < video_capture->buf_count; i++) {
if (!export_buffer(video_capture, &video_capture->exp_fd[i], i)) {
if (result && video_capture->with_swap) { return false;
result = }
result && export_buffer(video_capture, &video_capture->exp_fd_swap, 1);
} }
return result; return true;
} }
static bool open_stream(VideoCapture *video_capture) { static bool open_stream(VideoCapture *video_capture) {
@@ -274,10 +274,10 @@ static void create_image_buffer(const VideoCapture *video_capture,
} }
static void create_image_buffers(VideoCapture *video_capture) { static void create_image_buffers(VideoCapture *video_capture) {
create_image_buffer(video_capture, &video_capture->buf, 0); unsigned int i;
if (video_capture->with_swap) { for (i = 0; i < video_capture->buf_count; i++) {
create_image_buffer(video_capture, &video_capture->buf_swap, 1); create_image_buffer(video_capture, &video_capture->buf[i], i);
} }
} }
@@ -286,31 +286,26 @@ static void close_stream(const VideoCapture *video_capture) {
} }
static unsigned int read_video(VideoCapture *video_capture) { static unsigned int read_video(VideoCapture *video_capture) {
unsigned int result;
struct v4l2_capability cap; struct v4l2_capability cap;
result = 0; if (ioctl(video_capture->fd, VIDIOC_DQBUF,
&video_capture->buf[video_capture->buf_index]) != -1) {
ioctl(video_capture->fd, VIDIOC_QBUF,
&video_capture->buf[video_capture->buf_index]);
video_capture->buf_index =
(video_capture->buf_index + 1) % video_capture->buf_count;
return true;
}
if ((video_capture->swap || !video_capture->with_swap) && if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) {
ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) != -1) {
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf);
result = 1;
} else if (!video_capture->swap && video_capture->with_swap &&
ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf_swap) !=
-1) {
ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf_swap);
result = 2;
} else if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) {
video_capture->error = true; video_capture->error = true;
} }
return result; return false;
} }
void video_init(VideoCapture *video_capture, const char *name, void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height) { unsigned int preferred_height, unsigned int buffer_count) {
open_device(video_capture, name); open_device(video_capture, name);
if (video_capture->error) { if (video_capture->error) {
@@ -329,7 +324,7 @@ void video_init(VideoCapture *video_capture, const char *name,
return; return;
} }
if (!request_buffers(video_capture)) { if (!request_buffers(video_capture, buffer_count)) {
return; return;
} }
@@ -352,14 +347,15 @@ void *video_background_read(void *args) {
bool trace_fps = process_args->trace_fps; bool trace_fps = process_args->trace_fps;
Timer timer; Timer timer;
double fps; double fps;
unsigned int video_result; bool result;
log_info("(%s) background acquisition started", video_capture->name); log_info("(%s) background acquisition started", video_capture->name);
timer_init(&timer, 30); timer_init(&timer, 30);
while (!context->stop && !video_capture->error) { while (!context->stop && !video_capture->error) {
video_result = read_video(video_capture); result = read_video(video_capture);
if (video_result > 0 && timer_inc(&timer)) {
if (result && timer_inc(&timer)) {
fps = timer_reset(&timer); fps = timer_reset(&timer);
context->input_fps[input_index] = (unsigned int)round(fps); context->input_fps[input_index] = (unsigned int)round(fps);
@@ -367,9 +363,9 @@ void *video_background_read(void *args) {
log_trace("(%s) %.2ffps", video_capture->name, fps); log_trace("(%s) %.2ffps", video_capture->name, fps);
} }
} }
if (video_result > 0) {
context->input_swap[input_index] = video_capture->swap = if (result) {
video_result == 2; context->input_index[input_index] = video_capture->buf_index;
} }
} }
if (context->stop) { if (context->stop) {
@@ -385,13 +381,14 @@ void *video_background_read(void *args) {
} }
void video_free(const VideoCapture *video_capture) { void video_free(const VideoCapture *video_capture) {
unsigned int i;
close_stream(video_capture); close_stream(video_capture);
if (video_capture->exp_fd != -1) {
close(video_capture->exp_fd); for (i = 0; i < video_capture->buf_count; i++) {
} close(video_capture->exp_fd[i]);
if (video_capture->exp_fd_swap != -1) {
close(video_capture->exp_fd_swap);
} }
if (video_capture->fd != -1) { if (video_capture->fd != -1) {
close(video_capture->fd); close(video_capture->fd);
} }
+1 -1
View File
@@ -6,7 +6,7 @@
#ifdef VIDEO_IN #ifdef VIDEO_IN
void video_init(VideoCapture *video_capture, const char *name, void video_init(VideoCapture *video_capture, const char *name,
unsigned int preferred_height); unsigned int preferred_height, unsigned int buffer_count);
void *video_background_read(void *args); void *video_background_read(void *args);