//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; }
//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; }
//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; }