Cycles: merge of changes from tomato branch.
[blender-staging.git] / intern / cycles / render / buffers.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <stdlib.h>
20
21 #include "buffers.h"
22 #include "device.h"
23
24 #include "util_debug.h"
25 #include "util_foreach.h"
26 #include "util_hash.h"
27 #include "util_image.h"
28 #include "util_math.h"
29 #include "util_opengl.h"
30 #include "util_time.h"
31 #include "util_types.h"
32
33 CCL_NAMESPACE_BEGIN
34
35 /* Buffer Params */
36
37 BufferParams::BufferParams()
38 {
39         width = 0;
40         height = 0;
41
42         full_x = 0;
43         full_y = 0;
44         full_width = 0;
45         full_height = 0;
46
47         Pass::add(PASS_COMBINED, passes);
48 }
49
50 void BufferParams::get_offset_stride(int& offset, int& stride)
51 {
52         offset = -(full_x + full_y*width);
53         stride = width;
54 }
55
56 bool BufferParams::modified(const BufferParams& params)
57 {
58         return !(full_x == params.full_x
59                 && full_y == params.full_y
60                 && width == params.width
61                 && height == params.height
62                 && full_width == params.full_width
63                 && full_height == params.full_height
64                 && Pass::equals(passes, params.passes));
65 }
66
67 int BufferParams::get_passes_size()
68 {
69         int size = 0;
70
71         foreach(Pass& pass, passes)
72                 size += pass.components;
73         
74         return align_up(size, 4);
75 }
76
77 /* Render Buffer Task */
78
79 RenderTile::RenderTile()
80 {
81         x = 0;
82         y = 0;
83         w = 0;
84         h = 0;
85
86         start_sample = 0;
87         num_samples = 0;
88         resolution = 0;
89
90         offset = 0;
91         stride = 0;
92
93         buffer = 0;
94         rng_state = 0;
95         rgba = 0;
96
97         buffers = NULL;
98 }
99
100 /* Render Buffers */
101
102 RenderBuffers::RenderBuffers(Device *device_)
103 {
104         device = device_;
105 }
106
107 RenderBuffers::~RenderBuffers()
108 {
109         device_free();
110 }
111
112 void RenderBuffers::device_free()
113 {
114         if(buffer.device_pointer) {
115                 device->mem_free(buffer);
116                 buffer.clear();
117         }
118
119         if(rng_state.device_pointer) {
120                 device->mem_free(rng_state);
121                 rng_state.clear();
122         }
123 }
124
125 void RenderBuffers::reset(Device *device, BufferParams& params_)
126 {
127         params = params_;
128
129         /* free existing buffers */
130         device_free();
131         
132         /* allocate buffer */
133         buffer.resize(params.width*params.height*params.get_passes_size());
134         device->mem_alloc(buffer, MEM_READ_WRITE);
135         device->mem_zero(buffer);
136
137         /* allocate rng state */
138         rng_state.resize(params.width, params.height);
139
140         uint *init_state = rng_state.resize(params.width, params.height);
141         int x, y, width = params.width, height = params.height;
142         
143         for(x = 0; x < width; x++)
144                 for(y = 0; y < height; y++)
145                         init_state[x + y*width] = hash_int_2d(params.full_x+x, params.full_y+y);
146
147         device->mem_alloc(rng_state, MEM_READ_WRITE);
148         device->mem_copy_to(rng_state);
149 }
150
151 bool RenderBuffers::copy_from_device()
152 {
153         if(!buffer.device_pointer)
154                 return false;
155
156         device->mem_copy_from(buffer, 0, params.width, params.height, params.get_passes_size()*sizeof(float));
157
158         return true;
159 }
160
161 bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels)
162 {
163         int pass_offset = 0;
164
165         foreach(Pass& pass, params.passes) {
166                 if(pass.type != type) {
167                         pass_offset += pass.components;
168                         continue;
169                 }
170
171                 float *in = (float*)buffer.data_pointer + pass_offset;
172                 int pass_stride = params.get_passes_size();
173
174                 float scale = (pass.filter)? 1.0f/(float)sample: 1.0f;
175                 float scale_exposure = (pass.exposure)? scale*exposure: scale;
176
177                 int size = params.width*params.height;
178
179                 if(components == 1) {
180                         assert(pass.components == components);
181
182                         /* scalar */
183                         if(type == PASS_DEPTH) {
184                                 for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
185                                         float f = *in;
186                                         pixels[0] = (f == 0.0f)? 1e10f: f*scale_exposure;
187                                 }
188                         }
189                         else {
190                                 for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
191                                         float f = *in;
192                                         pixels[0] = f*scale_exposure;
193                                 }
194                         }
195                 }
196                 else if(components == 3) {
197                         assert(pass.components == 4);
198
199                         if(pass.divide_type != PASS_NONE) {
200                                 /* RGB lighting passes that need to divide out color */
201                                 pass_offset = 0;
202                                 foreach(Pass& color_pass, params.passes) {
203                                         if(color_pass.type == pass.divide_type)
204                                                 break;
205                                         pass_offset += color_pass.components;
206                                 }
207
208                                 float *in_divide = (float*)buffer.data_pointer + pass_offset;
209
210                                 for(int i = 0; i < size; i++, in += pass_stride, in_divide += pass_stride, pixels += 3) {
211                                         float3 f = make_float3(in[0], in[1], in[2]);
212                                         float3 f_divide = make_float3(in_divide[0], in_divide[1], in_divide[2]);
213
214                                         f = safe_divide_color(f*exposure, f_divide);
215
216                                         pixels[0] = f.x;
217                                         pixels[1] = f.y;
218                                         pixels[2] = f.z;
219                                 }
220                         }
221                         else {
222                                 /* RGB/vector */
223                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 3) {
224                                         float3 f = make_float3(in[0], in[1], in[2]);
225
226                                         pixels[0] = f.x*scale_exposure;
227                                         pixels[1] = f.y*scale_exposure;
228                                         pixels[2] = f.z*scale_exposure;
229                                 }
230                         }
231                 }
232                 else if(components == 4) {
233                         assert(pass.components == components);
234
235                         /* RGBA */
236                         if(type == PASS_SHADOW) {
237                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
238                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
239                                         float invw = (f.w > 0.0f)? 1.0f/f.w: 1.0f;
240
241                                         pixels[0] = f.x*invw;
242                                         pixels[1] = f.y*invw;
243                                         pixels[2] = f.z*invw;
244                                         pixels[3] = 1.0f;
245                                 }
246                         }
247                         else if(type == PASS_MOTION) {
248                                 /* need to normalize by number of samples accumulated for motion */
249                                 pass_offset = 0;
250                                 foreach(Pass& color_pass, params.passes) {
251                                         if(color_pass.type == PASS_MOTION_WEIGHT)
252                                                 break;
253                                         pass_offset += color_pass.components;
254                                 }
255
256                                 float *in_weight = (float*)buffer.data_pointer + pass_offset;
257
258                                 for(int i = 0; i < size; i++, in += pass_stride, in_weight += pass_stride, pixels += 4) {
259                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
260                                         float w = in_weight[0];
261                                         float invw = (w > 0.0f)? 1.0f/w: 0.0f;
262
263                                         pixels[0] = f.x*invw;
264                                         pixels[1] = f.y*invw;
265                                         pixels[2] = f.z*invw;
266                                         pixels[3] = f.w*invw;
267                                 }
268                         }
269                         else {
270                                 for(int i = 0; i < size; i++, in += pass_stride, pixels += 4) {
271                                         float4 f = make_float4(in[0], in[1], in[2], in[3]);
272
273                                         pixels[0] = f.x*scale_exposure;
274                                         pixels[1] = f.y*scale_exposure;
275                                         pixels[2] = f.z*scale_exposure;
276
277                                         /* clamp since alpha might be > 1.0 due to russian roulette */
278                                         pixels[3] = clamp(f.w*scale, 0.0f, 1.0f);
279                                 }
280                         }
281                 }
282
283                 return true;
284         }
285
286         return false;
287 }
288
289 /* Display Buffer */
290
291 DisplayBuffer::DisplayBuffer(Device *device_)
292 {
293         device = device_;
294         draw_width = 0;
295         draw_height = 0;
296         transparent = true; /* todo: determine from background */
297 }
298
299 DisplayBuffer::~DisplayBuffer()
300 {
301         device_free();
302 }
303
304 void DisplayBuffer::device_free()
305 {
306         if(rgba.device_pointer) {
307                 device->pixels_free(rgba);
308                 rgba.clear();
309         }
310 }
311
312 void DisplayBuffer::reset(Device *device, BufferParams& params_)
313 {
314         draw_width = 0;
315         draw_height = 0;
316
317         params = params_;
318
319         /* free existing buffers */
320         device_free();
321
322         /* allocate display pixels */
323         rgba.resize(params.width, params.height);
324         device->pixels_alloc(rgba);
325 }
326
327 void DisplayBuffer::draw_set(int width, int height)
328 {
329         assert(width <= params.width && height <= params.height);
330
331         draw_width = width;
332         draw_height = height;
333 }
334
335 void DisplayBuffer::draw(Device *device)
336 {
337         if(draw_width != 0 && draw_height != 0) {
338                 glPushMatrix();
339                 glTranslatef(params.full_x, params.full_y, 0.0f);
340
341                 device->draw_pixels(rgba, 0, draw_width, draw_height, 0, params.width, params.height, transparent);
342
343                 glPopMatrix();
344         }
345 }
346
347 bool DisplayBuffer::draw_ready()
348 {
349         return (draw_width != 0 && draw_height != 0);
350 }
351
352 void DisplayBuffer::write(Device *device, const string& filename)
353 {
354         int w = draw_width;
355         int h = draw_height;
356
357         if(w == 0 || h == 0)
358                 return;
359
360         /* read buffer from device */
361         device->pixels_copy_from(rgba, 0, w, h);
362
363         /* write image */
364         ImageOutput *out = ImageOutput::create(filename);
365         ImageSpec spec(w, h, 4, TypeDesc::UINT8);
366         int scanlinesize = w*4*sizeof(uchar);
367
368         out->open(filename, spec);
369
370         /* conversion for different top/bottom convention */
371         out->write_image(TypeDesc::UINT8,
372                 (uchar*)rgba.data_pointer + (h-1)*scanlinesize,
373                 AutoStride,
374                 -scanlinesize,
375                 AutoStride);
376
377         out->close();
378
379         delete out;
380 }
381
382 CCL_NAMESPACE_END
383