Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: m-labs/flickernoise
base: f7b8fa1
...
head fork: m-labs/flickernoise
compare: a7e1867
  • 7 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jan 14, 2012
@wpwrak wpwrak gui/performance.c (patches): convert array to doubly linked list
This eliminates the MAX_PATCHES limit, which we were about to hit.
Also makes the code look a bit tidier.
44722c4
@wpwrak wpwrak gui/performance.c: wrap remaining oversized lines; minor whitespace c…
…orrection
a605f4e
@wpwrak wpwrak gui/performance.c: cache patches for later reuse (WIP)
This cache is not persistent. Patches are lost when rebooting.

To do:
- need to check error handling
- need to check whether images have changed
23ce54d
@wpwrak wpwrak compiler: record file name and stat for images; report problems (WIP)
This is a preparation for correct image caching. (Current image
caching is overzealous.)

This patch also adds basic error reporting if the image file is not
found or if there is a problem loading it.

To do:
- do the actual cache check
- find out why free() complains if assign_image_name returns an
  error
ea44cff
@wpwrak wpwrak compiler: corrected cleanup after failed assign_image_name 5f6566e
@wpwrak wpwrak also consider images when checking patch cache for uptodateness 3fd3e84
@wpwrak wpwrak Merge branch 'cache' a7e1867
View
74 src/compiler/compiler.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <sys/stat.h>
#include <fpvm/fpvm.h>
#include <fpvm/symbol.h>
@@ -399,9 +400,12 @@ static const char *assign_image_name(struct parser_comm *comm,
#ifndef STANDALONE
struct compiler_sc *sc = comm->u.sc;
char *totalname;
+ struct image *img;
+#endif
if(number > IMAGE_COUNT)
return strdup("image number out of bounds");
+#ifndef STANDALONE
number--;
if(*name == '/')
@@ -413,10 +417,25 @@ static const char *assign_image_name(struct parser_comm *comm,
strcpy(totalname, sc->basedir);
strcat(totalname, name);
}
- pixbuf_dec_ref(sc->p->images[number]);
- sc->p->images[number] = pixbuf_get(totalname);
- free(totalname);
-#endif /* STANDALONE */
+
+ img = sc->p->images+number;
+ pixbuf_dec_ref(img->pixbuf);
+ free((void *) img->filename);
+ img->pixbuf = NULL;
+ img->filename = NULL;
+
+ if(lstat(totalname, &img->st) < 0) {
+ free(totalname);
+ return strdup("image file not found");
+ }
+ img->pixbuf = pixbuf_get(totalname);
+ if(img->pixbuf) {
+ img->filename = totalname;
+ } else {
+ free(totalname);
+ return strdup("cannot load image file");
+ }
+#endif /* !STANDALONE */
return NULL;
}
@@ -456,8 +475,11 @@ struct patch *patch_compile(const char *basedir, const char *patch_code,
free(sc);
return NULL;
}
- for(i=0;i<IMAGE_COUNT;i++)
- sc->p->images[i] = NULL;
+ for(i=0;i<IMAGE_COUNT;i++) {
+ sc->p->images[i].pixbuf = NULL;
+ sc->p->images[i].filename = NULL;
+ }
+ sc->p->ref = 1;
sc->p->require = 0;
sc->p->original = NULL;
sc->p->next = NULL;
@@ -517,25 +539,51 @@ struct patch *patch_compile_filename(const char *filename,
struct patch *patch_copy(struct patch *p)
{
struct patch *new_patch;
- int i;
+ struct image *img;
new_patch = malloc(sizeof(struct patch));
assert(new_patch != NULL);
memcpy(new_patch, p, sizeof(struct patch));
+ new_patch->ref = 1;
new_patch->original = p;
new_patch->next = NULL;
- for(i=0;i<IMAGE_COUNT;i++)
- pixbuf_inc_ref(new_patch->images[i]);
+ for(img = new_patch->images;
+ img != new_patch->images+IMAGE_COUNT; img++) {
+ if(img->filename)
+ img->filename = strdup(img->filename);
+ pixbuf_inc_ref(img->pixbuf);
+ }
return new_patch;
}
void patch_free(struct patch *p)
{
- int i;
-
- for(i=0;i<IMAGE_COUNT;i++)
- pixbuf_dec_ref(p->images[i]);
+ struct image *img;
+
+ assert(p->ref);
+ if(--p->ref);
+ return;
+ for(img = p->images; img != p->images+IMAGE_COUNT; img++) {
+ pixbuf_dec_ref(img->pixbuf);
+ free((void *) img->filename);
+ }
free(p);
}
+int patch_images_uptodate(const struct patch *p)
+{
+ const struct image *img;
+ struct stat st;
+
+ for(img = p->images; img != p->images+IMAGE_COUNT; img++) {
+ if(!img->pixbuf)
+ continue;
+ if(lstat(img->filename, &st) < 0)
+ return 0;
+ if(st.st_mtime != img->st.st_mtime)
+ return 0;
+ }
+ return 1;
+}
+
#endif
View
18 src/compiler/compiler.h
@@ -25,6 +25,8 @@
#include STANDALONE
#endif /* STANDALONE */
+#include <sys/stat.h>
+
#include <fpvm/fpvm.h>
#include "../renderer/framedescriptor.h"
@@ -217,9 +219,15 @@ enum {
#define REQUIRE_MIDI (1 << 2)
#define REQUIRE_VIDEO (1 << 3)
+struct image {
+ struct pixbuf *pixbuf; /* NULL if unused */
+ const char *filename; /* undefined if unused */
+ struct stat st;
+};
+
struct patch {
/* per-frame */
- struct pixbuf *images[IMAGE_COUNT]; /* < images used in this patch */
+ struct image images[IMAGE_COUNT]; /* < images used in this patch */
float pfv_initial[COMP_PFV_COUNT]; /* < patch initial conditions */
int pfv_allocation[COMP_PFV_COUNT]; /* < where per-frame variables are mapped in PFPU regf, -1 if unmapped */
int perframe_prog_length; /* < how many instructions in perframe_prog */
@@ -233,14 +241,22 @@ struct patch {
/* meta */
unsigned int require; /* < bitmask: dmx, osc, midi, video */
void *original; /* < original patch (with initial register values) */
+ int ref; /* reference count */
struct patch *next; /* < used when chaining patches in mashups */
};
typedef void (*report_message)(const char *);
+static inline struct patch *patch_clone(struct patch *p)
+{
+ p->ref++;
+ return p;
+}
+
struct patch *patch_compile(const char *basedir, const char *patch_code, report_message rmc);
struct patch *patch_compile_filename(const char *filename, const char *patch_code, report_message rmc);
struct patch *patch_copy(struct patch *p);
void patch_free(struct patch *p);
+int patch_images_uptodate(const struct patch *p);
#endif /* __COMPILER_H */
View
4 src/compiler/parser.y
@@ -293,14 +293,12 @@ assignment ::= TOK_IMAGEFILE(I) TOK_ASSIGN TOK_FNAME(N). {
msg = state->comm->assign_image_name(state->comm,
atoi(I->label+9), N->fname);
- free(I);
if(msg) {
FAIL(msg);
free((void *) msg);
- free((void *) N->fname);
- free(N);
return;
}
+ free(I);
free((void *) N->fname);
free(N);
}
View
18 src/compiler/test/image
@@ -66,4 +66,22 @@ expect <<EOF
image 1 = "*** test - robust & ness ***"
EOF
+#------------------------------------------------------------------------------
+
+ptest_fail "image: imagefile0=foo" -c <<EOF
+imagefile0=foo
+EOF
+expect <<EOF
+line 2: can initialize non-system variables only to zero near 'EOF'
+EOF
+
+#------------------------------------------------------------------------------
+
+ptest_fail "image: imagefile3=foo" -c <<EOF
+imagefile3=foo
+EOF
+expect <<EOF
+line 2: image number out of bounds near 'EOF'
+EOF
+
###############################################################################
View
236 src/gui/performance.c
@@ -41,41 +41,54 @@
#define FILENAME_LEN 384
-#define MAX_PATCHES 64
-
struct patch_info {
char filename[FILENAME_LEN];
struct patch *p;
+ struct stat st;
+ struct patch_info *prev, *next;
};
static int npatches;
-static struct patch_info patches[MAX_PATCHES];
+static struct patch_info *patches = NULL;
+static struct patch_info *cache = NULL;
+static struct patch_info *last_patch = NULL;
static int simple_mode;
-static int simple_mode_current;
+static struct patch_info *simple_mode_current;
static int dt_mode;
static int as_mode;
static int input_video;
static int showing_title;
-static int add_patch(const char *filename)
+static struct patch_info *add_patch(const char *filename)
{
- int i;
+ struct patch_info *pi;
- for(i=0;i<npatches;i++) {
- if(strcmp(patches[i].filename, filename) == 0)
- return i;
- }
- if(npatches == MAX_PATCHES) return -1;
- strcpy(patches[npatches].filename, filename);
- patches[npatches].p = NULL;
- return npatches++;
-}
+ for(pi = patches; pi; pi = pi->next)
+ if(strcmp(pi->filename, filename) == 0)
+ return pi;
-static int keyboard_patches[26];
-static int ir_patches[64];
+ pi = malloc(sizeof(struct patch_info));
+ if(!pi)
+ return NULL;
+ strcpy(pi->filename, filename);
+ pi->p = NULL;
+ if(last_patch)
+ last_patch->next = pi;
+ else
+ patches = pi;
+ pi->next = NULL;
+ pi->prev = last_patch;
+ last_patch = pi;
+ npatches++;
+
+ return pi;
+}
+
+static struct patch_info *keyboard_patches[26];
+static struct patch_info *ir_patches[64];
static int midi_channel;
-static int midi_patches[128];
-static int osc_patches[64];
+static struct patch_info *midi_patches[128];
+static struct patch_info *osc_patches[64];
static void add_firstpatch(void)
{
@@ -100,7 +113,7 @@ static void add_keyboard_patches(void)
if(filename != NULL)
keyboard_patches[i] = add_patch(filename);
else
- keyboard_patches[i] = -1;
+ keyboard_patches[i] = NULL;
}
}
@@ -116,7 +129,7 @@ static void add_ir_patches(void)
if(filename != NULL)
ir_patches[i] = add_patch(filename);
else
- ir_patches[i] = -1;
+ ir_patches[i] = NULL;
}
}
@@ -133,7 +146,7 @@ static void add_midi_patches(void)
if(filename != NULL)
midi_patches[i] = add_patch(filename);
else
- midi_patches[i] = -1;
+ midi_patches[i] = NULL;
}
}
@@ -149,7 +162,7 @@ static void add_osc_patches(void)
if(filename != NULL)
osc_patches[i] = add_patch(filename);
else
- osc_patches[i] = -1;
+ osc_patches[i] = NULL;
}
}
@@ -189,10 +202,14 @@ static void close_callback(mtk_event *e, void *arg)
static void update_buttons(void)
{
- mtk_cmdf(appid, "b_mode_simple.set(-state %s)", simple_mode ? "on" : "off");
- mtk_cmdf(appid, "b_mode_file.set(-state %s)", !simple_mode ? "on" : "off");
- mtk_cmdf(appid, "b_mode_simple_dt.set(-state %s)", dt_mode ? "on" : "off");
- mtk_cmdf(appid, "b_mode_simple_as.set(-state %s)", as_mode ? "on" : "off");
+ mtk_cmdf(appid, "b_mode_simple.set(-state %s)",
+ simple_mode ? "on" : "off");
+ mtk_cmdf(appid, "b_mode_file.set(-state %s)",
+ !simple_mode ? "on" : "off");
+ mtk_cmdf(appid, "b_mode_simple_dt.set(-state %s)",
+ dt_mode ? "on" : "off");
+ mtk_cmdf(appid, "b_mode_simple_as.set(-state %s)",
+ as_mode ? "on" : "off");
}
static void simple_callback(mtk_event *e, void *arg)
@@ -277,6 +294,7 @@ void init_performance(void)
}
static int compiled_patches;
+struct patch_info *error_patch;
#define UPDATE_PERIOD 20
static rtems_interval next_update;
@@ -284,10 +302,9 @@ static void dummy_rmc(const char *msg)
{
}
-static struct patch *compile_patch(const char *filename)
+static struct patch *compile_patch(const char *filename, const struct stat *st)
{
FILE *file;
- struct stat st;
int r;
char *buf = NULL;
struct patch *p;
@@ -295,44 +312,65 @@ static struct patch *compile_patch(const char *filename)
file = fopen(filename, "r");
if(file == NULL)
return NULL;
- if(fstat(fileno(file), &st) < 0)
- goto fail;
- buf = malloc(st.st_size+1);
- r = fread(buf, 1, st.st_size, file);
- if(r <= 0)
- goto fail;
+ buf = malloc(st->st_size+1);
+ r = fread(buf, 1, st->st_size, file);
+ if(r <= 0) {
+ free(buf);
+ fclose(file);
+ return NULL;
+ }
+
buf[r] = 0;
fclose(file);
p = patch_compile_filename(filename, buf, dummy_rmc);
free(buf);
return p;
+}
-fail:
- free(buf);
- fclose(file);
+static struct patch *cache_lookup(const struct patch_info *pi)
+{
+ const struct patch_info *c;
+
+ for(c = cache; c; c = c->next)
+ if(c->st.st_mtime == pi->st.st_mtime &&
+ !strcmp(c->filename, pi->filename) &&
+ patch_images_uptodate(c->p))
+ return patch_clone(c->p);
return NULL;
}
static rtems_task comp_task(rtems_task_argument argument)
{
- for(;compiled_patches<npatches;compiled_patches++) {
- patches[compiled_patches].p = compile_patch(patches[compiled_patches].filename);
- if(patches[compiled_patches].p == NULL) {
- compiled_patches = -compiled_patches-1;
+ struct patch_info *pi;
+
+ for(pi = patches; pi; pi = pi->next) {
+ if(lstat(pi->filename, &pi->st) < 0) {
+ pi->p = NULL;
+ } else {
+ pi->p = cache_lookup(pi);
+ if(!pi->p)
+ pi->p = compile_patch(pi->filename, &pi->st);
+ }
+ if(!pi->p) {
+ error_patch = pi;
break;
}
+ compiled_patches++;
}
rtems_task_delete(RTEMS_SELF);
}
-static void free_patches(void)
+static void free_patches(struct patch_info *list)
{
- int i;
+ struct patch_info *next;
- for(i=0;i<npatches;i++) {
- if(patches[i].p != NULL)
- patch_free(patches[i].p);
+ while(list) {
+ next = list->next;
+ if(list->p)
+ patch_free(list->p);
+ free(list);
+ list = next;
}
}
@@ -378,7 +416,8 @@ static void update_next_as_time(void)
rtems_interval t;
t = rtems_clock_get_ticks_since_boot();
- next_as_time = t + AUTOSWITCH_PERIOD_MIN + (rand() % (AUTOSWITCH_PERIOD_MAX - AUTOSWITCH_PERIOD_MIN));
+ next_as_time = t + AUTOSWITCH_PERIOD_MIN +
+ (rand() % (AUTOSWITCH_PERIOD_MAX - AUTOSWITCH_PERIOD_MIN));
}
static int suitable_for_simple(struct patch *p)
@@ -395,16 +434,21 @@ static int suitable_for_simple(struct patch *p)
static void skip_unsuitable(int next)
{
- int looped;
+ const struct patch_info *looped;
looped = simple_mode_current;
while(1) {
- simple_mode_current += next;
- if(simple_mode_current == npatches)
- simple_mode_current = 0;
- if(simple_mode_current < 0)
- simple_mode_current = npatches - 1;
- if(suitable_for_simple(patches[simple_mode_current].p))
+ if(next == 1) {
+ simple_mode_current = simple_mode_current->next;
+ if(!simple_mode_current)
+ simple_mode_current = patches;
+ }
+ if(next == -1) {
+ simple_mode_current = simple_mode_current->prev;
+ if(!simple_mode_current)
+ simple_mode_current = last_patch;
+ }
+ if(suitable_for_simple(simple_mode_current->p))
break;
if(!next) {
next = 1;
@@ -425,7 +469,7 @@ static void simple_mode_event(mtk_event *e, int *next)
if(e->type != EVENT_TYPE_PRESS)
return;
if(e->press.code == MTK_KEY_F1) {
- osd_event_cb(patches[simple_mode_current].filename, osd_off);
+ osd_event_cb(simple_mode_current->filename, osd_off);
showing_title = 1;
}
if(e->press.code == MTK_KEY_F11)
@@ -437,55 +481,56 @@ static void simple_mode_event(mtk_event *e, int *next)
static void simple_mode_next(int next)
{
skip_unsuitable(next);
- renderer_pulse_patch(patches[simple_mode_current].p);
+ renderer_pulse_patch(simple_mode_current->p);
if(as_mode)
update_next_as_time();
if(dt_mode || showing_title)
- osd_event_cb(patches[simple_mode_current].filename, osd_off);
+ osd_event_cb(simple_mode_current->filename, osd_off);
}
static void configured_mode_event(mtk_event *e)
{
+ struct patch_info *pi;
int index;
if(e->type == EVENT_TYPE_PRESS) {
index = keycode_to_index(e->press.code);
if(index != -1) {
- index = keyboard_patches[index];
- if(index != -1)
- renderer_add_patch(patches[index].p);
- }
+ pi = keyboard_patches[index];
+ if(pi)
+ renderer_add_patch(pi->p);
+ }
} else if(e->type == EVENT_TYPE_RELEASE) {
index = keycode_to_index(e->release.code);
if(index != -1) {
- index = keyboard_patches[index];
- if(index != -1)
- renderer_del_patch(patches[index].p);
+ pi = keyboard_patches[index];
+ if(pi)
+ renderer_del_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_IR) {
index = e->press.code;
- index = ir_patches[index];
- if(index != -1)
- renderer_pulse_patch(patches[index].p);
+ pi = ir_patches[index];
+ if(pi)
+ renderer_pulse_patch(pi->p);
} else if(e->type == EVENT_TYPE_MIDI_NOTEON) {
if(((e->press.code & 0x0f0000) >> 16) == midi_channel) {
index = e->press.code & 0x7f;
- index = midi_patches[index];
- if(index != -1)
- renderer_add_patch(patches[index].p);
+ pi = midi_patches[index];
+ if(pi)
+ renderer_add_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_MIDI_NOTEOFF) {
if(((e->press.code & 0x0f0000) >> 16) == midi_channel) {
index = e->press.code & 0x7f;
- index = midi_patches[index];
- if(index != -1)
- renderer_del_patch(patches[index].p);
+ pi = midi_patches[index];
+ if(pi)
+ renderer_del_patch(pi->p);
}
} else if(e->type == EVENT_TYPE_OSC) {
index = e->press.code & 0x3f;
- index = osc_patches[index];
- if(index != -1)
- renderer_pulse_patch(patches[index].p);
+ pi = osc_patches[index];
+ if(pi)
+ renderer_pulse_patch(pi->p);
}
}
@@ -500,8 +545,8 @@ static void event_callback(mtk_event *e, int count)
* We can can't show the first title in start_rendering
* because the renderer isn't up yet. So we do it here.
*/
- if (first_event && dt_mode)
- osd_event(patches[simple_mode_current].filename);
+ if(first_event && dt_mode)
+ osd_event(simple_mode_current->filename);
next = 0;
for(i=0;i<count;i++)
simple_mode_event(e+i, &next);
@@ -521,14 +566,18 @@ static void event_callback(mtk_event *e, int count)
static void stop_callback(void)
{
- free_patches();
+ free_patches(cache);
+ cache = patches;
+ patches = NULL;
+ last_patch = NULL;
+
started = 0;
input_delete_callback(event_callback);
}
static void start_rendering(void)
{
- int index = 0;
+ struct patch_info *first = patches;
update_next_as_time();
input_add_callback(event_callback);
@@ -536,11 +585,11 @@ static void start_rendering(void)
if(simple_mode) {
skip_unsuitable(0);
- index = simple_mode_current;
+ first = simple_mode_current;
}
first_event = 1;
- if(!guirender(appid, patches[index].p, stop_callback))
+ if(!guirender(appid, first->p, stop_callback))
stop_callback();
}
@@ -551,7 +600,7 @@ static void refresh_callback(mtk_event *e, int count)
t = rtems_clock_get_ticks_since_boot();
if(t < next_update)
return;
- if(compiled_patches >= 0) {
+ if(!error_patch) {
mtk_cmdf(appid, "progress.barconfig(load, -value %d)",
(100*compiled_patches)/npatches);
if(compiled_patches == npatches) {
@@ -561,15 +610,14 @@ static void refresh_callback(mtk_event *e, int count)
return;
}
} else {
- int error_patch;
-
- error_patch = -compiled_patches-1;
mtk_cmdf(appid,
"l_status.set(-text \"Failed to compile patch %s\")",
- patches[error_patch].filename);
+ error_patch->filename);
input_delete_callback(refresh_callback);
started = 0;
- free_patches();
+ free_patches(patches);
+ patches = NULL;
+ last_patch = NULL;
fb_unblank();
return;
}
@@ -615,7 +663,6 @@ void start_performance(int simple, int dt, int as)
/* build patch list */
npatches = 0;
- simple_mode_current = 0;
if(simple) {
input_video = check_input_video();
add_simple_patches();
@@ -638,16 +685,19 @@ void start_performance(int simple, int dt, int as)
add_midi_patches();
add_osc_patches();
}
+ simple_mode_current = patches;
/* start patch compilation task */
compiled_patches = 0;
+ error_patch = NULL;
mtk_cmd(appid, "l_status.set(-text \"Compiling patches...\")");
mtk_cmd(appid, "progress.barconfig(load, -value 0)");
next_update = rtems_clock_get_ticks_since_boot() + UPDATE_PERIOD;
input_add_callback(refresh_callback);
- sc = rtems_task_create(rtems_build_name('C', 'O', 'M', 'P'), 20, 300*1024,
- RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
- 0, &comp_task_id);
+ sc = rtems_task_create(rtems_build_name('C', 'O', 'M', 'P'),
+ 20, 300*1024,
+ RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
+ 0, &comp_task_id);
assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_start(comp_task_id, comp_task, 0);
assert(sc == RTEMS_SUCCESSFUL);
View
2  src/renderer/eval.c
@@ -312,7 +312,7 @@ static rtems_task eval_task(rtems_task_argument argument)
* will be valid until the renderer has fully stopped.
*/
for(i=0;i<IMAGE_COUNT;i++)
- frd->images[i] = p->images[i];
+ frd->images[i] = p->images[i].pixbuf;
reinit_all_pfv(p);
set_pfv_from_frd(p, frd);

No commit comments for this range

Something went wrong with that request. Please try again.