erebus

diff liberebus/src/erebus.cc @ 26:c8a6fb04fefa

multithreadededit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Jun 2014 19:19:40 +0300
parents 6204e4d3f445
children 0ced900e15a7
line diff
     1.1 --- a/liberebus/src/erebus.cc	Sat May 31 06:21:09 2014 +0300
     1.2 +++ b/liberebus/src/erebus.cc	Sun Jun 01 19:19:40 2014 +0300
     1.3 @@ -12,8 +12,7 @@
     1.4  
     1.5  using namespace std::chrono;
     1.6  
     1.7 -#define INVALID_RECT	Rect{0, 0, 0, 0}
     1.8 -
     1.9 +static void render_block(struct erebus *ctx, Block blk);
    1.10  static void render_pixel(struct erebus *ctx, int x, int y, int sample);
    1.11  
    1.12  static std::mt19937 rnd_gen;
    1.13 @@ -34,7 +33,7 @@
    1.14  
    1.15  	ctx->scn = 0;
    1.16  	ctx->cur_time = 0;
    1.17 -	ctx->cur_rect = INVALID_RECT;
    1.18 +	ctx->cur_frame = 0;
    1.19  
    1.20  	erb_setoptf(ctx, ERB_OPT_GAMMA, 2.2);
    1.21  	erb_setopti(ctx, ERB_OPT_MAX_ITER, 6);
    1.22 @@ -125,16 +124,24 @@
    1.23  void erb_begin_frame(struct erebus *ctx, long ms)
    1.24  {
    1.25  	printf("starting new frame...\n");
    1.26 +	++ctx->cur_frame;
    1.27 +	ctx->cur_sample = 0;
    1.28  	ctx->cur_time = ms;
    1.29  
    1.30  	int xsz = erb_getopti(ctx, ERB_OPT_WIDTH);
    1.31  	int ysz = erb_getopti(ctx, ERB_OPT_HEIGHT);
    1.32  
    1.33 -	ctx->fbimg.create(xsz, ysz);
    1.34 -	ctx->accum.create(xsz, ysz);
    1.35 +	if(!ctx->fbimg.get_pixels() || ctx->fbimg.get_width() != xsz || ctx->fbimg.get_height() < ysz) {
    1.36 +		ctx->fbimg.create(xsz, ysz);
    1.37 +		ctx->accum.create(xsz, ysz);
    1.38 +	} else {
    1.39 +		ctx->fbimg.clear();
    1.40 +		ctx->accum.clear();
    1.41 +	}
    1.42  
    1.43 -	ctx->cur_rect = INVALID_RECT;
    1.44  	ctx->inv_gamma = 1.0f / erb_getoptf(ctx, ERB_OPT_GAMMA);
    1.45 +
    1.46 +	ctx->scn->update(ctx->cur_time);
    1.47  }
    1.48  
    1.49  int erb_render(struct erebus *ctx, long timeout)
    1.50 @@ -142,56 +149,48 @@
    1.51  	return erb_render_rect(ctx, 0, 0, ctx->fbimg.get_width(), ctx->fbimg.get_height(), timeout);
    1.52  }
    1.53  
    1.54 +#define BLKSZ	32
    1.55 +
    1.56  int erb_render_rect(struct erebus *ctx, int x, int y, int width, int height, long timeout)
    1.57  {
    1.58 +	while(ctx->tpool.pending()) {
    1.59 +		if(timeout > 0) {
    1.60 +			long wait_interval = ctx->tpool.wait(timeout);
    1.61 +			timeout -= wait_interval;
    1.62 +		} else {
    1.63 +			return 1;
    1.64 +		}
    1.65 +	}
    1.66 +
    1.67  	if(!width || !height) return -1;
    1.68  
    1.69 -	Rect rect{x, y, width, height};
    1.70 -	if(ctx->cur_rect != rect) {
    1.71 -		// starting a new rendering apparently
    1.72 -		ctx->cur_rect = rect;
    1.73 -		ctx->cur_pixel_x = x;
    1.74 -		ctx->cur_pixel_y = y;
    1.75 -		ctx->cur_sample = 0;
    1.76 +	int startx = x;
    1.77 +	int endx = x + width;
    1.78 +	int endy = y + height;
    1.79 +
    1.80 +	while(y < endy) {
    1.81 +		x = startx;
    1.82 +		while(x < endx) {
    1.83 +			Block blk;
    1.84 +			blk.x = x;
    1.85 +			blk.y = y;
    1.86 +			blk.width = std::min(BLKSZ, endx - x);
    1.87 +			blk.height = std::min(BLKSZ, endy - y);
    1.88 +			blk.sample = ctx->cur_sample;
    1.89 +			blk.frame = ctx->cur_frame;
    1.90 +
    1.91 +			ctx->tpool.add_work(std::bind(render_block, ctx, blk));
    1.92 +
    1.93 +			x += BLKSZ;
    1.94 +		}
    1.95 +		y += BLKSZ;
    1.96  	}
    1.97  
    1.98 -	ctx->scn->update();
    1.99 +	++ctx->cur_sample;
   1.100 +	ctx->tpool.wait(timeout);	// wait for completion
   1.101 +	return ctx->cur_sample > erb_getopti(ctx, ERB_OPT_MAX_SAMPLES) ? 0 : 1;
   1.102 +}
   1.103  
   1.104 -	int max_samples = erb_getopti(ctx, ERB_OPT_MAX_SAMPLES);
   1.105 -
   1.106 -	if(timeout > 0) {
   1.107 -		auto start_time = steady_clock::now();
   1.108 -		while(duration_cast<milliseconds>(steady_clock::now() - start_time).count() < timeout) {
   1.109 -			render_pixel(ctx, ctx->cur_pixel_x, ctx->cur_pixel_y, ctx->cur_sample);
   1.110 -
   1.111 -			if(++ctx->cur_pixel_x >= ctx->cur_rect.width) {
   1.112 -				ctx->cur_pixel_x = ctx->cur_rect.x;
   1.113 -				if(++ctx->cur_pixel_y >= ctx->cur_rect.height) {
   1.114 -					ctx->cur_pixel_y = ctx->cur_rect.y;
   1.115 -					if(++ctx->cur_sample >= max_samples) {
   1.116 -						ctx->cur_rect = INVALID_RECT;
   1.117 -						return 0;
   1.118 -					}
   1.119 -				}
   1.120 -			}
   1.121 -		}
   1.122 -		return 1;
   1.123 -	}
   1.124 -
   1.125 -	if(max_samples == INF_SAMPLES) {
   1.126 -		// don't allow infinite samples when rendering non-progressively
   1.127 -		max_samples = 128;
   1.128 -	}
   1.129 -
   1.130 -	for(int i=0; i<height; i++) {
   1.131 -		for(int j=0; j<width; j++) {
   1.132 -			for(int k=0; k<max_samples; k++) {
   1.133 -				render_pixel(ctx, j, i, k);
   1.134 -			}
   1.135 -		}
   1.136 -	}
   1.137 -	return 0;
   1.138 -}
   1.139  
   1.140  int erb_get_progress(struct erebus *ctx)
   1.141  {
   1.142 @@ -335,6 +334,19 @@
   1.143  	return unirnd(rnd_gen);
   1.144  }
   1.145  
   1.146 +static void render_block(struct erebus *ctx, Block blk)
   1.147 +{
   1.148 +	if(blk.frame < ctx->cur_frame) {
   1.149 +		return;	// skip stale blocks
   1.150 +	}
   1.151 +
   1.152 +	for(int i=0; i<blk.height; i++) {
   1.153 +		for(int j=0; j<blk.width; j++) {
   1.154 +			render_pixel(ctx, blk.x + j, blk.y + i, blk.sample);
   1.155 +		}
   1.156 +	}
   1.157 +}
   1.158 +
   1.159  static void render_pixel(struct erebus *ctx, int x, int y, int sample)
   1.160  {
   1.161  	Camera *cam = ctx->scn->get_active_camera();
   1.162 @@ -360,14 +372,3 @@
   1.163  	pix[2] = pow(accum[2] * inv_samples, ctx->inv_gamma);
   1.164  	pix[3] = accum[3] * inv_samples;
   1.165  }
   1.166 -
   1.167 -bool Rect::operator ==(const Rect &r) const
   1.168 -{
   1.169 -	return memcmp(this, &r, sizeof r) == 0;
   1.170 -}
   1.171 -
   1.172 -bool Rect::operator !=(const Rect &r) const
   1.173 -{
   1.174 -	return memcmp(this, &r, sizeof r) != 0;
   1.175 -}
   1.176 -