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; }
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_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; }
//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; }
static int _setting_changed(Filter *f) { _Data *data = ea_data(f->data, 0); switch (data->colorspace) { case 0 : *(int*)(data->color[0]->data) = CS_RGB_R; *(int*)(data->color[1]->data) = CS_RGB_G; *(int*)(data->color[2]->data) = CS_RGB_B; f->mode_buffer->worker = &_worker_gamma; break; case 1 : *(int*)(data->color[0]->data) = CS_LAB_L; *(int*)(data->color[1]->data) = CS_LAB_A; *(int*)(data->color[2]->data) = CS_LAB_B; f->mode_buffer->worker = &_worker_linear; break; case 2 : *(int*)(data->color[0]->data) = CS_YUV_Y; *(int*)(data->color[1]->data) = CS_YUV_U; *(int*)(data->color[2]->data) = CS_YUV_V; f->mode_buffer->worker = &_worker_linear; break; default : abort(); } return 0; }
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; }
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; }
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; }
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; }
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; }
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)); }
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 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"); }
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; }
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); } }
static void _area_calc(Filter *f, Rect *in, Rect *out) { _Data *data = ea_data(f->data, 0); uint32_t render_r, actual_r; actual_r = r_calc(*data->sigma, in->corner.scale)/16; render_r = actual_r+1; out->corner.scale = in->corner.scale; out->corner.x = in->corner.x - render_r*3; out->corner.y = in->corner.y - render_r*3; out->width = in->width + 2*render_r*3; out->height = in->height + 2*render_r*3; }
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; }
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; }
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); } }
static void _worker(Filter *f, Eina_Array *in, Eina_Array *out, Rect *area, int thread_id) { int i, j, ch; int w, h; uint16_t *output; uint16_t *input; uint16_t *pos; int scale; _Data *data = ea_data(f->data, 0); Tiledata *in_td, *out_td; Rect in_area; lfModifier *mod; float *coords; float x, y; float fx, fy; assert(in && ea_count(in) == 1); assert(out && ea_count(out) == 1); hack_tiledata_fixsize_mt(6, ea_data(out, 0)); in_td = ((Tiledata*)ea_data(in, 0)); in_area = in_td->area; input = in_td->data; out_td = ((Tiledata*)ea_data(out, 0)); output = out_td->data; //has been executed by area calc! (hacky?) assert(data->common->exif_loaded); if (check_exif(data)) { printf("FIXME: lensfun pass through if lens not identified! %d\n", data->common->exif_loaded); return; } if (area->corner.scale) { scale = area->corner.scale-1; w = ((Dim*)data->common->dim_in_meta->data)->width; h = ((Dim*)data->common->dim_in_meta->data)->height; mod = lf_modifier_new(data->common->lens, data->common->lens->CropFactor, w>>scale, h>>scale); lf_modifier_initialize(mod, data->common->lens, LF_PF_U16, data->common->f, data->common->f_num, data->common->f_dist, 0.0, LF_RECTILINEAR, LF_MODIFY_ALL, 0); coords = malloc(2*3*sizeof(float)*area->width); //FIXME fix negative y and x rounding (->fx) for(j=0;j<area->height;j++) { lf_modifier_apply_subpixel_geometry_distortion(mod, area->corner.x, area->corner.y+j, area->width, 1, coords); for(i=0;i<area->width;i++) for(ch=0;ch<3;ch++) { //FIXME can we realiably catch this in area_calc? x = coords[i*2*3+ch*2]; y = coords[i*2*3+ch*2+1]; if (x < in_area.corner.x || x >= in_area.corner.x+in_area.width-1) continue; if (y < in_area.corner.y || y >= in_area.corner.y+in_area.height-1) continue; fx = x-(int)x; fy = y-(int)y; pos = tileptr16_3(in_td, x, y) + ch; tileptr16_3(out_td, area->corner.x+i, area->corner.y+j)[ch] = pos[0]*(1.0-fx)*(1.0-fy) +pos[3]*(fx)*(1.0-fy) +pos[in_area.width*3]*(1.0-fx)*(fy) +pos[in_area.width*3+3]*(fx)*(fy); } } lf_modifier_destroy(mod); free(coords); }
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))); }
//FIXME check if setting does exist, give some debug info if parsing fails! Eina_List *lime_filter_chain_deserialize(char *str) { int i; int checksettings; Meta *m; Filter *f, *last_f = NULL; Eina_List *filters = NULL; str = strdup(str); char *last = str + strlen(str); char *next = str; char *next_comma; char *cur = str; const char *setting; char *tmp; while (cur) { next = next_single_colon(cur); next_comma = strchr(cur, ','); if (next || next_comma) { if (next && (next < next_comma || !next_comma)) { printf("%s with settings\n", cur); checksettings = 1; *next = '\0'; f = lime_filter_new(cur); } else if (next_comma && (next > next_comma || !next)) { printf("%s no settings\n", cur); checksettings = 0; *next_comma = '\0'; f = lime_filter_new(cur); cur = next_comma+1; next = NULL; } else { //FIXME check rethink? abort(); } } else { printf("%s last filter no settings\n", cur); checksettings = 0; f = lime_filter_new(cur); next = NULL; cur = NULL; } if (!f) { printf("no filter for %s\n", cur); return NULL; } if (next && next+1 < last) cur = next+1; else checksettings = 0; //f = fc->filter_new_f(); if (last_f) lime_filter_connect(last_f, f); last_f = f; filters = eina_list_append(filters, f); //settings if (cur && checksettings) { next = strchr(cur, '='); if (strchr(cur, ',') && next > strchr(cur, ',')) break; while (next) { *next = '\0'; setting = cur; assert(next+1 < last); cur = next+1; if (!ea_count(f->settings)) { printf("no settings for %s\n", f->fc->name); return NULL; } for(i=0;i<ea_count(f->settings);i++) { m = ea_data(f->settings, i); if (!strncmp(setting, m->name, strlen(setting))) { setting = m->name; break; } } switch (lime_setting_type_get(f, setting)) { case MT_INT : lime_setting_int_set(f, setting, atoi(cur)); break; case MT_FLOAT : lime_setting_float_set(f, setting, atof(cur)); break; case MT_STRING : tmp = strdup(cur); if (next_single_colon(tmp)) *next_single_colon(tmp) = '\0'; if (strchr(tmp, ',')) *strchr(tmp, ',') = '\0'; lime_setting_string_set(f, setting, string_unescape_colon(tmp)); printf("set %s to %s\n", setting, string_unescape_colon(tmp)); free(tmp); break; default : if (lime_setting_type_get(f, setting) == -1) printf("setting %s for filter %s not known (filter implementation changed?)\n", setting, f->fc->name); else printf("FIXME implement type %s settings parsing\n", mt_type_str(lime_setting_type_get(f, setting))); } next = next_single_colon(cur); if (next && next+1 < last && (!strchr(cur, ',') || next < strchr(cur, ','))) { cur = next+1; next = strchr(cur, '='); } else next = NULL; } if (cur) cur = strchr(cur, ','); if (cur) cur++; } if (cur >= last) cur = NULL; } free(str); return filters; }
//f_source: source-filter by channel Render_Node *render_node_new(Filter *f, Tile *tile, Render_State *state, int depth) { int i; Rect inputs_area; Render_Node *node = calloc(sizeof(Render_Node), 1); Rect *area; if (tile) area = &tile->area; else area = NULL; node->state = state; node->depth = depth; if (f->node->con_ch_in && ea_count(f->node->con_ch_in)) node->f_source = eina_array_new(4); for(i=0;i<ea_count(f->node->con_ch_in);i++) ea_push(node->f_source, filter_get_input_filter(f, i)); node->f = f; node->tile = tile; node->inputs = eina_array_new(4); if (node->f_source && f->mode_iter) { node->mode = MODE_ITER; node->iter = f->mode_iter->iter_new(f, area, node->f_source, &node->pos, &node->channel); 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); } else if (node->f_source && f->mode_buffer) { node->mode = MODE_CLOBBER; node->channel = 0; assert(area); filter_calc_valid_req_area(f, area, &node->area); 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); assert(f->node->con_ch_in && ea_count(f->node->con_ch_in)); 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; //this is the input provided to filtes, so it will always be as large as actually requested by the filter filter_calc_req_area(f, area, &inputs_area); for(i=0;i<ea_count(f->node->con_ch_in);i++) ea_push(node->inputs, tiledata_new(&inputs_area, 1, NULL)); } else node->mode = MODE_INPUT; return node; }
//return 0 on success Render_Node *render_state_getjob( Render_State *state) { int i; Rect area; Tilehash hash; Render_Node *node; Tile *tile; Render_Node *jobnode; int found; struct timespec t_start; struct timespec t_stop; if (ea_count(state->ready)) return ea_pop(state->ready); if (!ea_count(state->currstate)) { if (state->pending) { if (!ea_count(state->ready)) { clock_gettime(CLOCK_MONOTONIC,&t_start); lime_unlock(); while(state->pending && !ea_count(state->ready)) { usleep(1000); lime_lock(); lime_unlock(); } lime_lock(); clock_gettime(CLOCK_MONOTONIC,&t_stop); printf("we were blocked!\n"); global_stat_thread_blocked += t_stop.tv_sec - t_start.tv_sec + (t_stop.tv_nsec - t_start.tv_nsec)*1.0/1000000000.0; } assert(ea_count(state->ready)); return ea_pop(state->ready); } return NULL; } node = ea_data(state->currstate, ea_count(state->currstate)-1); while (node) { if (!end_of_iteration(node)) { area.corner.x = node->pos.x; area.corner.y = node->pos.y; area.corner.scale = node->pos.scale; area.width = node->tw; area.height = node->th; hash = tile_hash_calc(filter_get_input_filter(node->f, node->channel), &area); if ((tile = cache_tile_get(&hash))) { cache_stats_update(tile, 1, 0, 0, 0); assert(node->mode); //check if we're alredy waiting for this tile on another channel found = 0; if (tile->want) for(i=0;i<ea_count(tile->want);i++) if (node == ea_data(tile->want, i)) { found = 1; break; } if (found) { //do nothing, we just continue } else if (!tile->channels) { //tile is not yet rendered, push ref if (!tile->want) tile->want = eina_array_new(4); node->need++; ea_push(tile->want, node); } else { if (node->mode == MODE_CLOBBER) { //TODO attention: we assume channels are always processed in the same order clobbertile_add(ea_data(node->inputs, node->channel), ea_data(tile->channels, node->channel)); assert(ea_count(node->inputs) > node->channel); } else if (node->mode == MODE_ITER) { node->f->mode_iter->worker(node->f, ea_data(tile->channels, node->channel), node->channel, NULL, NULL, 0); } else abort(); } incnode(node); } //this node does not need any input tiles else if (!ea_count(node->f_source_curr->node->con_ch_in)) { jobnode = render_node_new(node->f_source_curr, tile_new(&area, hash, node->f_source_curr, node->f, node->depth), state, node->depth+1); assert(jobnode->f->fixme_outcount); cache_tile_add(jobnode->tile); cache_stats_update(jobnode->tile, 0, 1, 0, 0); //don't incnode so parent node will recheck for this tile //the parent will propably be added to tile->need return jobnode; } //node needs input tiles else { tile = tile_new(&area, hash, node->f_source_curr, node->f, node->depth); cache_stats_update(tile, 0, 1, 0, 0); if (node->f->fixme_outcount); cache_tile_add(tile); jobnode = render_node_new(node->f_source_curr, tile, state, node->depth+1); tile->want = eina_array_new(4); node->need++; ea_push(tile->want, node); //FIXME this incnode would cause problems with tiffsave! //incnode(node); node = jobnode; //don't incnode so parent node will recheck for this tile //the parent will propably be added to tile->need ea_push(state->currstate, node); //to lock it in the currstate array node->need += 1000; } } else { //all inputs have been processed //this doesn't mean that all inputs are available jobnode = node; node = ea_pop(state->currstate); node->need -= 1000; assert(node == jobnode); if (jobnode->need) { //what happens with jobnode? //why this code?? if (ea_count(state->currstate)) node = ea_data(state->currstate, ea_count(state->currstate)-1); else node = NULL; state->pending++; } else return jobnode; } } if (ea_count(state->ready)) return ea_pop(state->ready); if (state->pending) { lime_unlock(); while(state->pending && !ea_count(state->ready)) { usleep(1000); lime_lock(); lime_unlock(); } lime_lock(); assert(ea_count(state->ready)); return ea_pop(state->ready); } return NULL; }
//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(); }