void vizp_filter(FILE *file, Filter *filter) { int begun = 0; fprintf(file, "subgraph cluster_%p {\n" "label = \"%s\";\n" "node [style=filled];\n" "\"%p\" [label = \"{<type>%s ", filter, filter->fc->name, filter, filter->fc->name); if (ea_count(filter->in)) { fprintf(file, "| { <in>in "); begun = 1; } if (ea_count(filter->out)) { if (begun) fprintf(file, "| <out>out "); else { fprintf(file, "| { <out>out "); begun = 1; } } if (ea_count(filter->core)) { if (begun) fprintf(file, "| <core>core "); else { fprintf(file, "| { <core>core "); begun = 1; } } if (ea_count(filter->tune)) { if (begun) fprintf(file, "| <tune>tune "); else { fprintf(file, "| { <tune>tune "); begun = 1; } } if (ea_count(filter->settings)) { if (begun) fprintf(file, "| <settings>settings "); else { fprintf(file, "| { <settings>settings "); begun = 1; } } fprintf(file, "}}\"]\n"); vizp_ar(file, filter->in, filter, "in"); vizp_ar(file, filter->out, filter, "out"); vizp_ar(file, filter->core, filter, "core"); vizp_ar(file, filter->tune, filter, "tune"); vizp_ar(file, filter->settings, filter, "settings"); fprintf(file, "}\n"); }
//FIXME on sinks should replace old connection! Con *filter_connect_real(Filter *source, int out, Filter *sink, int in) { Con *con = malloc(sizeof(Con)); con->source = eina_array_data_get(source->out, out); con->sink = eina_array_data_get(sink->in, in); if (!source->node->con_trees_out) source->node->con_trees_out = eina_array_new(1); if (!sink->node->con_trees_in) sink->node->con_trees_in = eina_array_new(1); if (ea_count(source->node->con_trees_out)) { printf("WARNING: have con_trees_out\n"); while (ea_count(source->node->con_trees_out)) ea_pop(source->node->con_trees_out); } if (ea_count(sink->node->con_trees_in)) { printf("WARNING: have con_trees_in\n"); while (ea_count(sink->node->con_trees_in)) ea_pop(sink->node->con_trees_in); } eina_array_push(source->node->con_trees_out, con); eina_array_push(sink->node->con_trees_in, con); filter_hash_invalidate(source); return con; }
int lime_setting_int_set(Filter *f, const char *setting, int value) { int i; Meta *m; if (!ea_count(f->settings)) return -1; for(i=0;i<ea_count(f->settings);i++) { m = ea_data(f->settings, i); if (!strcmp(setting, m->name)) { assert(m->data); *(int*)m->data = value; filter_hash_invalidate(f); if (f->setting_changed) f->setting_changed(f); lime_config_reset(f); return 0; } } return -1; }
int lime_setting_string_set(Filter *f, const char *setting, const char *value) { int i; Meta *m; const char *str; if (!ea_count(f->settings)) return -1; str = eina_stringshare_add(value); for(i=0;i<ea_count(f->settings);i++) { m = ea_data(f->settings, i); if (!strcmp(setting, m->name)) { m->data = str; filter_hash_invalidate(f); if (f->setting_changed) f->setting_changed(f); lime_config_reset(f); return 0; } } eina_stringshare_del(str); return -1; }
void render_state_del(Render_State *state) { assert(ea_count(state->currstate) == 0); assert(ea_count(state->ready) == 0); assert(state->pending == 0); eina_array_free(state->currstate); eina_array_free(state->ready); free(state); }
//FIXME leaves out the last filter (which should be the sink!), add check if it really is the sink? char *lime_filter_chain_serialize(Filter *f) { int i; //FIXME handle large settings char *buf = malloc(4096); char *str = buf; Meta *m; buf[0] = '\0'; while (f && f->node_orig->con_trees_out && ea_count(f->node_orig->con_trees_out)) { str += sprintf(str, "%s", f->fc->shortname); for(i=0;i<ea_count(f->settings);i++) { m = ea_data(f->settings, i); if (m->data) switch (m->type) { case MT_INT : str += sprintf(str, ":%s=%d", m->name, *(int*)m->data); break; case MT_FLOAT : str += sprintf(str, ":%s=%f", m->name, *(float*)m->data); break; case MT_STRING : assert(!strchr((char*)m->data, ':')); str += sprintf(str, ":%s=%s", m->name, string_escape_colon((char*)m->data)); break; } else printf("no data for %s\n", m->name); } if (f->node_orig->con_trees_out && ea_count(f->node_orig->con_trees_out)) f = ((Con*)ea_data(f->node_orig->con_trees_out, 0))->sink->filter; else f = NULL; /* FIXME if (f->out && ea_count(f->out)) f = eina_array_data_get(f->out, 0); else f = NULL;*/ if (f && f->node_orig->con_trees_out && ea_count(f->node_orig->con_trees_out)) str += sprintf(str, ","); } if (buf[0] == '\0') { free(buf); buf = NULL; } return buf; }
Eina_Array *ea_copy(Eina_Array *a) { int i; Eina_Array *b; if (ea_count(a)) b = ea_new(ea_count(a)); else b = ea_new(4); for(i=0; i<ea_count(a); i++) ea_push(b, ea_data(a, i)); return b; }
void con_del_real(Con *con) { if (con->source->filter->node->con_trees_out && ea_count(con->source->filter->node->con_trees_out)) ea_pop(con->source->filter->node->con_trees_out); if (con->sink->filter->node->con_trees_in && ea_count(con->sink->filter->node->con_trees_in)) ea_pop(con->sink->filter->node->con_trees_in); assert(!ea_count(con->source->filter->node->con_trees_out)); assert(!ea_count(con->sink->filter->node->con_trees_in)); free(con); }
void con_del(Con *con) { //FIXME als del real? if (con->source->filter->node_orig->con_trees_out && ea_count(con->source->filter->node_orig->con_trees_out)) ea_pop(con->source->filter->node_orig->con_trees_out); if (con->sink->filter->node_orig->con_trees_in && ea_count(con->sink->filter->node_orig->con_trees_in)) ea_pop(con->sink->filter->node_orig->con_trees_in); assert(!ea_count(con->source->filter->node_orig->con_trees_out)); assert(!ea_count(con->sink->filter->node_orig->con_trees_in)); free(con); }
void filter_calc_valid_req_area(Filter *f, Rect *area, Rect *req_area) { Dim *ch_dim; int x, y, w, h; int div; //calc area filter_calc_req_area(f, area, req_area); //restrict to prev filters output assert(f->node->con_ch_in && ea_count(f->node->con_ch_in)); ch_dim = meta_child_data_by_type(ea_data(f->node->con_ch_in, 0), MT_IMGSIZE); div = 1u<<req_area->corner.scale; x = ch_dim->x/div; y = ch_dim->y/div; w = ch_dim->width/div; h = ch_dim->height/div; if (x > req_area->corner.x) { req_area->width = req_area->width - x + req_area->corner.x; req_area->corner.x = x; } if (y > req_area->corner.y) { req_area->height = req_area->height - y + req_area->corner.y; req_area->corner.y = y; } if (x + w < req_area->corner.x + req_area->width) req_area->width = x + w - req_area->corner.x; if (y + h < req_area->corner.y + req_area->height) req_area->height = y + h - req_area->corner.y; }
static void _meta_array2hash(Eina_Hash *hash, Eina_Array *trees) { int i; for(i=0;i<ea_count(trees);i++) _meta2hash(hash, ea_data(trees, i)); }
int lime_setting_type_get(Filter *f, const char *setting) { int i; Meta *m; if (!ea_count(f->settings)) return -1; for(i=0;i<ea_count(f->settings);i++) { m = ea_data(f->settings, i); if (!strcmp(setting, m->name)) return m->type; } return -1; }
Filter *filter_chain_last_filter(Filter *f) { while (f->node_orig->con_trees_out && ea_count(f->node_orig->con_trees_out)) f = ((Con*)ea_data(f->node_orig->con_trees_out, 0))->sink->filter; return f; }
Filter *filter_chain_first_filter(Filter *f) { while (f->node_orig->con_trees_in && ea_count(f->node_orig->con_trees_in)) f = ((Con*)ea_data(f->node_orig->con_trees_in, 0))->source->filter; return f; }
void filter_hash_recalc(Filter *f) { Filter *next; int i; int len; len = snprintf(f->hash.data, 1020, "%u%s", f->hash.prevhash, f->fc->shortname); if (len >= 1020) abort(); for(i=0;i<ea_count(f->settings);i++) { len += mt_data_snprint(&f->hash.data[len], 1024-len, ((Meta*)ea_data(f->settings, i))->type, ((Meta*)ea_data(f->settings, i))->data); if (len >= 1020) abort(); } for(i=0;i<ea_count(f->tune);i++) { if (!((Meta*)ea_data(f->tune, i))->data) { printf("FIXME! no data for tune %d (%s) in %s\n", i, ((Meta*)ea_data(f->tune, i))->name, f->fc->shortname); continue; } //assert(((Meta*)ea_data(f->tune, i))->data); len += mt_data_snprint(&f->hash.data[len], 1024-len, ((Meta*)ea_data(f->tune, i))->type, ((Meta*)ea_data(f->tune, i))->data); if (len >= 1020) abort(); } len += snprintf(&f->hash.data[len], 1024-len, "tail"); f->hash.len = len; f->hash.hash = eina_hash_superfast(f->hash.data, len); if (f->node->con_trees_out && ea_count(f->node->con_trees_out)) { assert(ea_count(f->node->con_trees_out) == 1); next = ((Con *)ea_data(f->node->con_trees_out, 0))->sink->filter; next->hash.prevhash = f->hash.hash; filter_hash_recalc(next); } }
Filter *filter_chain_next_filter(Filter *f) { if (f->node_orig->con_trees_out && ea_count(f->node_orig->con_trees_out)) { return ((Con*)ea_data(f->node_orig->con_trees_out, 0))->sink->filter; } return NULL; }
void *filter_core_by_type(Filter *f, int type) { int i; for(i=0;i<ea_count(f->core);i++) if (type == ((Meta*)ea_data(f->core, i))->type) return ((Meta*)ea_data(f->core, i))->data; return NULL; }
void *filter_core_by_name(Filter *f, const char *name) { int i; for(i=0;i<ea_count(f->core);i++) if (!strcmp(name, ((Meta*)ea_data(f->core, i))->name)) return ((Meta*)ea_data(f->core, i))->data; return NULL; }
//FIXME on sinks should replace old connection! Con *filter_connect(Filter *source, int out, Filter *sink, int in) { Con *con = malloc(sizeof(Con)); //no composition yet assert(in == 0); assert(out == 0); assert(source->in); assert(sink->out); lime_config_reset(sink); lime_config_reset(source); con->source = eina_array_data_get(source->out, out); con->sink = eina_array_data_get(sink->in, in); if (!source->node_orig->con_trees_out) source->node_orig->con_trees_out = eina_array_new(1); if (!sink->node_orig->con_trees_in) sink->node_orig->con_trees_in = eina_array_new(1); if (!ea_count(source->node_orig->con_trees_out)) eina_array_push(source->node_orig->con_trees_out, con); else { while (ea_count(source->node_orig->con_trees_out)) con_del(ea_pop(source->node_orig->con_trees_out)); eina_array_push(source->node_orig->con_trees_out, con); } if (!ea_count(sink->node_orig->con_trees_in)) eina_array_push(sink->node_orig->con_trees_in, con); else { while (ea_count(sink->node_orig->con_trees_in)) con_del(ea_pop(sink->node_orig->con_trees_in)); eina_array_push(sink->node_orig->con_trees_in, con); } filter_hash_invalidate(source); return con; }
void *filter_core_by_subtype(Filter *f, int type, char *subtype) { int i; for(i=0;i<ea_count(f->core);i++) if (type == ((Meta*)ea_data(f->core, i))->type && ((Meta*)ea_data(f->core, i))->type_str && !strcmp(((Meta*)ea_data(f->core, i))->type_str, subtype)) return ((Meta*)ea_data(f->core, i))->data; return NULL; }
void render_state_print(Render_State *state, int t_id) { int i; printf("%4d ", t_id); for(i=0;i<ea_count(state->currstate);i++) { printf("%4dx%4d ", ((Render_Node*)ea_data(state->currstate, i))->pos.x, ((Render_Node*)ea_data(state->currstate, i))->pos.y); } printf("\n"); }
static void _worker_linear(Filter *f, Eina_Array *in, Eina_Array *out, Rect *area, int thread_id) { int ch; int i, j; Tiledata *in_td, *out_td; Rect *in_area; assert(in && ea_count(in) == 3); assert(out && ea_count(out) == 3); in_area = &((Tiledata*)ea_data(in, 0))->area; if (area->corner.scale) for(ch=0;ch<3;ch++) { in_td = (Tiledata*)ea_data(in, ch); out_td = (Tiledata*)ea_data(out, ch); for(j=0;j<DEFAULT_TILE_SIZE*2;j+=2) for(i=0;i<DEFAULT_TILE_SIZE*2;i+=2) tileptr8(out_td, i/2+area->corner.x, j/2+area->corner.y)[0] = (tileptr8(in_td, i+in_area->corner.x, j+in_area->corner.y)[0] +tileptr8(in_td, i+1+in_area->corner.x, j+in_area->corner.y)[0] +tileptr8(in_td, i+in_area->corner.x, j+1+in_area->corner.y)[0] +tileptr8(in_td, i+1+in_area->corner.x, j+1+in_area->corner.y)[0] +2 ) / 4; } else for(ch=0;ch<3;ch++) { in_td = (Tiledata*)ea_data(in, ch); out_td = (Tiledata*)ea_data(out, ch); assert(in_td->area.width == out_td->area.width); assert(in_td->area.height == out_td->area.height); memcpy(out_td->data, in_td->data, out_td->area.width*out_td->area.height); } }
int end_of_iteration(Render_Node *node) { if (node->mode == MODE_CLOBBER) { if (node->channel < ea_count(node->f->node->con_ch_in)) return 0; else return 1; } else if (node->mode == MODE_ITER) { int ret = node->f->mode_iter->iter_eoi(node->iter, node->pos, node->channel); return ret; } else abort(); }
void incnode(Render_Node *node) { if (node->mode == MODE_CLOBBER) { node->pos.x += node->tw; if (node->pos.x >= node->area.corner.x+node->area.width) { if (node->area.corner.x >= 0) node->pos.x = (node->area.corner.x/node->tw)*node->tw; else node->pos.x = ((node->area.corner.x-node->tw+1)/node->tw)*node->tw; node->pos.y += node->th; if (node->pos.y >= node->area.corner.y+node->area.height) { if (node->area.corner.y >= 0) node->pos.y = (node->area.corner.y/node->th)*node->th; else node->pos.y = ((node->area.corner.y-node->th+1)/node->th)*node->th; node->channel++; if (node->channel < ea_count(node->f_source)) { node->f_source_curr = ea_data(node->f_source, node->channel); node->tw = tw_get(node->f_source_curr, node->area.corner.scale); node->th = th_get(node->f_source_curr, node->area.corner.scale); filter_calc_valid_req_area(node->f, &node->tile->area, &node->area); if (node->area.corner.x >= 0) node->pos.x = (node->area.corner.x/node->tw)*node->tw; else node->pos.x = ((node->area.corner.x-node->tw+1)/node->tw)*node->tw; if (node->area.corner.y >= 0) node->pos.y = (node->area.corner.y/node->th)*node->th; else node->pos.y = ((node->area.corner.y-node->th+1)/node->th)*node->th; node->pos.scale = node->area.corner.scale; } } } } else if (node->mode == MODE_ITER) { node->f->mode_iter->iter_next(node->iter, &node->pos, &node->channel); node->tw = tw_get(node->f_source_curr, node->pos.scale); node->th = th_get(node->f_source_curr, node->pos.scale); } else abort(); }
void render_node_del(Render_Node *node) { int i; if (node->inputs) { for(i=0;i<ea_count(node->inputs);i++) tiledata_del(ea_data(node->inputs, i)); eina_array_free(node->inputs); } if (node->f_source) eina_array_free(node->f_source); if (node->tile && !cache_tile_get(&node->tile->hash)) tile_del(node->tile); free(node); }
//gives the predecessor according to channel Filter *filter_get_input_filter(Filter *f, int channel) { Filter *input; if (!f->node->con_ch_in) return NULL; if (ea_count(f->node->con_ch_in) <= channel) return NULL; input = ((Meta*)ea_data(f->node->con_ch_in, channel))->filter; //FIXME too simple, channels? while (!input->mode_buffer && !input->mode_iter) input = filter_get_input_filter(input, channel); return input; }
static void _worker(Filter *f, Eina_Array *in, Eina_Array *out, Rect *area, int thread_id) { _Data *data = ea_data(f->data, thread_id); uint32_t render_r, frac, actual_r; int ch; int i, j; int x, y; Rect *in_area; actual_r = r_calc(*data->sigma, area->corner.scale); frac = actual_r % 16; actual_r = actual_r / 16; render_r = actual_r+1; Tiledata buf_t1; Tiledata buf_t2; Rect buf_area; _area_calc(f, area, &buf_area); buf_t1.area = buf_area; buf_t2.area = buf_area; buf_t1.data = data->buf1; buf_t2.data = data->buf2; assert(in && ea_count(in) == 3); assert(out && ea_count(out) == 3); in_area = &((Tiledata*)ea_data(in, 0))->area; for(ch=0;ch<3;ch++) { if (!render_r) { assert(area->corner.x == in_area->corner.x); memcpy(((Tiledata*)ea_data(out, ch))->data, ((Tiledata*)ea_data(in, ch))->data, DEFAULT_TILE_AREA); } else { for(i=0;i<(DEFAULT_TILE_SIZE+2*render_r*3);i++) { x = i+area->corner.x-render_r*3; y = area->corner.y-2*render_r; _accu_blur(x, y, ea_data(in, ch), &buf_t1, actual_r, 2*render_r, in_area->width, buf_area.width, frac); } for(i=0;i<(DEFAULT_TILE_SIZE+2*render_r*3);i++) { x = i+area->corner.x-render_r*3; y = area->corner.y-render_r; _accu_blur(x, y, &buf_t1, &buf_t2, actual_r, render_r, buf_area.width, buf_area.width, frac); } for(i=0;i<(DEFAULT_TILE_SIZE+2*actual_r*3);i++) { x = i+area->corner.x-actual_r*3; y = area->corner.y; _accu_blur(x, y, &buf_t2, &buf_t1, actual_r, 0, buf_area.width, buf_area.width, frac); } for(j=0;j<DEFAULT_TILE_SIZE;j++) { x = area->corner.x-2*render_r; y = j+area->corner.y; _accu_blur_x(x, y, &buf_t1, &buf_t2, actual_r, 2*render_r, frac); } for(j=0;j<DEFAULT_TILE_SIZE;j++) { x = area->corner.x-render_r; y = j+area->corner.y; _accu_blur_x(x, y, &buf_t2, &buf_t1, actual_r, render_r, frac); } for(j=0;j<DEFAULT_TILE_SIZE;j++) { x = area->corner.x; y = j+area->corner.y; _accu_blur_x(x, y, &buf_t1, ea_data(out, ch), actual_r, 0, frac); } } } }
void filter_fill_thread_data(Filter *f, int thread_id) { if (f->mode_buffer->data_new) while (ea_count(f->data) <= thread_id) ea_push(f->data, f->mode_buffer->data_new(f, ea_data(f->data, 0))); }
//render area with external threading void lime_render_area(Rect *area, Filter *f, int thread_id) { int j; Render_Node *waiter; Render_Node *job; Dim *ch_dim; if (!f) return; lime_lock(); lime_config_test(f); lime_filter_config_ref(f); ch_dim = meta_child_data_by_type(ea_data(f->node->con_ch_in, 0), MT_IMGSIZE); assert(area->corner.x < DIV_SHIFT_ROUND_UP(ch_dim->width, area->corner.scale)); assert(area->corner.y < DIV_SHIFT_ROUND_UP(ch_dim->height, area->corner.scale)); Render_State *state = render_state_new(area, f); while ((job = render_state_getjob(state))) { assert(job->need == 0); if (job->mode == MODE_CLOBBER || job->mode == MODE_INPUT) { assert(job->tile->refs > 0); filter_render_tile(job, thread_id); } //MODE_ITER else if (job->mode == MODE_ITER) { if (job->f->mode_iter->finish) job->f->mode_iter->finish(job->f); } else abort(); if (job->tile && job->tile->want) while(ea_count(job->tile->want)) { waiter = ea_pop(job->tile->want); if (waiter->mode != MODE_ITER) { for(j=0;j<ea_count(waiter->f_source);j++) if (filter_hash_value_get(ea_data(waiter->f_source, j)) == job->tile->filterhash) //FIXME channel selection, use paired channels not blindly the same number! clobbertile_add(ea_data(waiter->inputs, j), ea_data(job->tile->channels, j)); } waiter->need--; if (!waiter->need) { ea_push(waiter->state->ready, waiter); waiter->state->pending--; } //FIXME add proper interface! else if (!strcmp(waiter->f->fc->shortname, "savejpeg") || !strcmp(waiter->f->fc->shortname, "savetiff")) cache_stats_print(); } if (job->tile) job->tile->refs--; render_node_del(job); } render_state_del(state); lime_filter_config_unref(f); lime_unlock(); }
void filter_del(Filter *f) { Eina_Hash *metas; lime_config_reset(f); pthread_mutex_destroy(&f->lock); /*if (f->node->con_trees_in && ea_count(f->node->con_trees_in)) filter_deconfigure(((Con*)ea_data(f->node->con_trees_in, 0))->source->filter);*/ if (f->node->con_trees_in) { if (ea_count(f->node->con_trees_in)) con_del_real(ea_pop(f->node->con_trees_in)); eina_array_free(f->node->con_trees_in); f->node->con_trees_in = NULL; } if (f->node->con_trees_out) { if (ea_count(f->node->con_trees_out)) con_del_real(ea_pop(f->node->con_trees_out)); eina_array_free(f->node->con_trees_out); f->node->con_trees_out = NULL; } if (f->node_orig->con_trees_in) { if (ea_count(f->node_orig->con_trees_in)) con_del(ea_pop(f->node_orig->con_trees_in)); eina_array_free(f->node_orig->con_trees_in); f->node_orig->con_trees_in = NULL; } if (f->node_orig->con_trees_out) { if (ea_count(f->node_orig->con_trees_out)) con_del(ea_pop(f->node_orig->con_trees_out)); eina_array_free(f->node_orig->con_trees_out); f->node_orig->con_trees_out = NULL; } if (f->node->con_ch_in) eina_array_free(f->node->con_ch_in); if (f->del) f->del(f); else printf("FIXME! del filter %s!\n", f->fc->shortname); while(ea_count(f->metas)) meta_del(ea_pop(f->metas)); eina_array_free(f->metas); eina_array_free(f->in); eina_array_free(f->out); eina_array_free(f->tune); eina_array_free(f->settings); eina_array_free(f->core); fg_node_del(f->node); fg_node_del(f->node_orig); eina_array_free(f->data); if (f->mode_buffer) filter_mode_buffer_del(f->mode_buffer); if (f->mode_iter) filter_mode_iter_del(f->mode_iter); if (f->tw_s) free(f->tw_s); if (f->th_s) free(f->th_s); free(f); }