//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; }
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); }
//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_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); }
//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(); }
//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; }