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; }
Filter *filter_gauss_blur_new(void) { Filter *filter = filter_new(&filter_core_gauss); Meta *in, *out, *channel, *bitdepth, *color[3], *setting, *bound; Meta *ch_out[3]; _Data *data = calloc(sizeof(_Data), 1); data->sigma = calloc(sizeof(float), 1); data->buf1 = malloc(BLURBUF); data->buf2 = malloc(BLURBUF); filter->fixme_outcount = 3; ea_push(filter->data, data); *data->sigma = 5.0; filter->mode_buffer = filter_mode_buffer_new(); filter->mode_buffer->worker = &_worker; filter->mode_buffer->threadsafe = 1; filter->mode_buffer->area_calc = &_area_calc; filter->mode_buffer->data_new = &_gauss_data_new; bitdepth = meta_new_data(MT_BITDEPTH, filter, malloc(sizeof(int))); *(int*)(bitdepth->data) = BD_U8; bitdepth->replace = bitdepth; out = meta_new(MT_BUNDLE, filter); eina_array_push(filter->out, out); channel = meta_new_channel(filter, 1); color[0] = meta_new_data(MT_COLOR, filter, malloc(sizeof(int))); *(int*)(color[0]->data) = CS_LAB_L; meta_attach(channel, color[0]); meta_attach(channel, bitdepth); meta_attach(out, channel); ch_out[0] = channel; channel = meta_new_channel(filter, 2); color[1] = meta_new_data(MT_COLOR, filter, malloc(sizeof(int))); *(int*)(color[1]->data) = CS_LAB_A; meta_attach(channel, color[1]); meta_attach(channel, bitdepth); meta_attach(out, channel); ch_out[1] = channel; channel = meta_new_channel(filter, 3); color[2] = meta_new_data(MT_COLOR, filter, malloc(sizeof(int))); *(int*)(color[2]->data) = CS_LAB_B; meta_attach(channel, color[2]); meta_attach(channel, bitdepth); meta_attach(out, channel); ch_out[2] = channel; in = meta_new(MT_BUNDLE, filter); in->replace = out; eina_array_push(filter->in, in); channel = meta_new_channel(filter, 1); color[0]->replace = color[0]; channel->replace = ch_out[0]; meta_attach(channel, color[0]); meta_attach(channel, bitdepth); meta_attach(in, channel); channel = meta_new_channel(filter, 2); color[1]->replace = color[1]; channel->replace = ch_out[1]; meta_attach(channel, color[1]); meta_attach(channel, bitdepth); meta_attach(in, channel); channel = meta_new_channel(filter, 3); color[2]->replace = color[2]; color[2]->replace = color[2]; channel->replace = ch_out[2]; meta_attach(channel, color[2]); meta_attach(channel, bitdepth); meta_attach(in, channel); setting = meta_new_data(MT_FLOAT, filter, data->sigma); meta_name_set(setting, "sigma"); eina_array_push(filter->settings, setting); bound = meta_new_data(MT_FLOAT, filter, malloc(sizeof(int))); *(float*)bound->data = 0; meta_name_set(bound, "PARENT_SETTING_MIN"); meta_attach(setting, bound); bound = meta_new_data(MT_FLOAT, filter, malloc(sizeof(int))); *(float*)bound->data = MAX_SIGMA; meta_name_set(bound, "PARENT_SETTING_MAX"); meta_attach(setting, bound); return filter; }
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(); }
//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; }
void filter_render_tile(Render_Node *job, int thread_id) { int i; struct timespec t_start; struct timespec t_stop; Eina_Array *channels; assert(job->f->mode_buffer); assert(job->f->mode_buffer->worker != NULL); assert(!job->tile->channels); assert(job->tile->refs); assert(job->mode != MODE_ITER); if (job->f->fixme_outcount) { channels = eina_array_new(4); for(i=0;i<job->f->fixme_outcount;i++) ea_push(channels, tiledata_new(&job->tile->area, 1, job->tile)); } else channels = 0; if (channels) assert(cache_tile_get(&job->tile->hash) != NULL); if (job->f->prepare && job->f->prepared_hash != job->f->hash.hash) { job->f->prepare(job->f); job->f->prepared_hash = job->f->hash.hash; } if (job->f->mode_buffer->threadsafe) lime_unlock(); if (job->f->mode_buffer->threadsafe) filter_fill_thread_data(job->f, thread_id); /*else { * if (!job->f->lock) { * job->f->lock = calloc(sizeof(pthread_mutex_t),1); * pthread_mutex_init(job->f->lock, NULL); } pthread_mutex_lock(job->f->lock); }*/ clock_gettime(CLOCK_THREAD_CPUTIME_ID,&t_start); if (job->f->mode_buffer->threadsafe) job->f->mode_buffer->worker(job->f, job->inputs, channels, &job->tile->area, thread_id); else job->f->mode_buffer->worker(job->f, job->inputs, channels, &job->tile->area, 0); clock_gettime(CLOCK_THREAD_CPUTIME_ID,&t_stop); //if (!job->f->mode_buffer->threadsafe) // pthread_mutex_unlock(job->f->lock); if (job->f->mode_buffer->threadsafe) lime_lock(); job->tile->time = t_stop.tv_sec*1000000000 - t_start.tv_sec*1000000000 + t_stop.tv_nsec - t_start.tv_nsec; job->tile->channels = channels; cache_stats_update(job->tile, 0, 0, job->tile->time, 0); //printf("render add %p filter %s\n", job->tile, job->f->fc->shortname); //??? //if (job->f->fixme_outcount) // cache_tile_channelmem_add(job->tile); }
//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; }
Filter *filter_down_new(void) { Filter *filter = filter_new(&filter_core_down); Meta *in, *out, *channel, *bitdepth, *setting, *bound; Meta *ch_out[3]; _Data *data = calloc(sizeof(_Data), 1); filter->fixme_outcount = 3; ea_push(filter->data, data); filter->mode_buffer = filter_mode_buffer_new(); filter->mode_buffer->worker = &_worker_linear; filter->mode_buffer->area_calc = &_area_calc; filter->setting_changed = &_setting_changed; bitdepth = meta_new_data(MT_BITDEPTH, filter, malloc(sizeof(int))); *(int*)(bitdepth->data) = BD_U8; bitdepth->replace = bitdepth; out = meta_new(MT_BUNDLE, filter); eina_array_push(filter->out, out); channel = meta_new_channel(filter, 1); data->color[0] = meta_new_data(MT_COLOR, filter, malloc(sizeof(int))); *(int*)(data->color[0]->data) = CS_LAB_L; meta_attach(channel, data->color[0]); meta_attach(channel, bitdepth); meta_attach(out, channel); ch_out[0] = channel; channel = meta_new_channel(filter, 2); data->color[1] = meta_new_data(MT_COLOR, filter, malloc(sizeof(int))); *(int*)(data->color[1]->data) = CS_LAB_A; meta_attach(channel, data->color[1]); meta_attach(channel, bitdepth); meta_attach(out, channel); ch_out[1] = channel; channel = meta_new_channel(filter, 3); data->color[2] = meta_new_data(MT_COLOR, filter, malloc(sizeof(int))); *(int*)(data->color[2]->data) = CS_LAB_B; meta_attach(channel, data->color[2]); meta_attach(channel, bitdepth); meta_attach(out, channel); ch_out[2] = channel; in = meta_new(MT_BUNDLE, filter); in->replace = out; eina_array_push(filter->in, in); channel = meta_new_channel(filter, 1); data->color[0]->replace = data->color[0]; channel->replace = ch_out[0]; meta_attach(channel, data->color[0]); meta_attach(channel, bitdepth); meta_attach(in, channel); channel = meta_new_channel(filter, 2); data->color[1]->replace = data->color[1]; channel->replace = ch_out[1]; meta_attach(channel, data->color[1]); meta_attach(channel, bitdepth); meta_attach(in, channel); channel = meta_new_channel(filter, 3); data->color[2]->replace = data->color[2]; channel->replace = ch_out[2]; meta_attach(channel, data->color[2]); meta_attach(channel, bitdepth); meta_attach(in, channel); setting = meta_new_data(MT_INT, filter, &data->colorspace); meta_name_set(setting, "colorspace"); eina_array_push(filter->settings, setting); bound = meta_new_data(MT_INT, filter, malloc(sizeof(int))); *(int*)bound->data = 0; meta_name_set(bound, "PARENT_SETTING_MIN"); meta_attach(setting, bound); bound = meta_new_data(MT_INT, filter, malloc(sizeof(int))); *(int*)bound->data = 1; meta_name_set(bound, "PARENT_SETTING_MAX"); meta_attach(setting, bound); return filter; }