Cycles: OpenCL tweaks
[blender.git] / intern / cycles / render / filter.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 "camera.h"
20 #include "device.h"
21 #include "filter.h"
22 #include "scene.h"
23
24 #include "kernel_types.h"
25
26 #include "util_algorithm.h"
27 #include "util_debug.h"
28 #include "util_math.h"
29
30 CCL_NAMESPACE_BEGIN
31
32 Filter::Filter()
33 {
34         filter_type = FILTER_BOX;
35         filter_width = 1.0f;
36         need_update = true;
37 }
38
39 Filter::~Filter()
40 {
41 }
42
43 static float filter_func_box(float v, float width)
44 {
45         return (float)1;
46 }
47
48 static float filter_func_gaussian(float v, float width)
49 {
50         v *= (float)2/width;
51         return (float)expf((float)-2*v*v);
52 }
53
54 static vector<float> filter_table(FilterType type, float width)
55 {
56         const int filter_table_size = FILTER_TABLE_SIZE;
57         vector<float> filter_table_cdf(filter_table_size+1);
58         vector<float> filter_table(filter_table_size+1);
59         float (*filter_func)(float, float) = NULL;
60         int i, half_size = filter_table_size/2;
61
62         switch(type) {
63                 case FILTER_BOX:
64                         filter_func = filter_func_box;
65                         break;
66                 case FILTER_GAUSSIAN:
67                         filter_func = filter_func_gaussian;
68                         break;
69                 default:
70                         assert(0);
71         }
72
73         /* compute cumulative distribution function */
74         filter_table_cdf[0] = 0.0f;
75         
76         for(i=0; i<filter_table_size; i++) {
77                 float x = i*width*0.5f/(filter_table_size-1);
78                 float y = filter_func(x, width);
79                 filter_table_cdf[i+1] += filter_table_cdf[i] + fabsf(y);
80         }
81
82         for(i=0; i<=filter_table_size; i++)
83                 filter_table_cdf[i] /= filter_table_cdf[filter_table_size];
84         
85         /* create importance sampling table */
86         for(i=0; i<=half_size; i++) {
87                 float x = i/(float)half_size;
88                 int index = upper_bound(filter_table_cdf.begin(), filter_table_cdf.end(), x) - filter_table_cdf.begin();
89                 float t;
90
91                 if(index < filter_table_size+1) {
92                         t = (x - filter_table_cdf[index])/(filter_table_cdf[index+1] - filter_table_cdf[index]);
93                 }
94                 else {
95                         t = 0.0f;
96                         index = filter_table_size;
97                 }
98
99                 float y = ((index + t)/(filter_table_size))*width;
100
101                 filter_table[half_size+i] = 0.5f*(1.0f + y);
102                 filter_table[half_size-i] = 0.5f*(1.0f - y);
103         }
104
105         return filter_table;
106 }
107
108 void Filter::device_update(Device *device, DeviceScene *dscene)
109 {
110         if(!need_update)
111                 return;
112
113         device_free(device, dscene);
114
115         /* update __filter_table */
116         vector<float> table = filter_table(filter_type, filter_width);
117
118         dscene->filter_table.copy(&table[0], table.size());
119         device->tex_alloc("__filter_table", dscene->filter_table, true);
120
121         need_update = false;
122 }
123
124 void Filter::device_free(Device *device, DeviceScene *dscene)
125 {
126         device->tex_free(dscene->filter_table);
127         dscene->filter_table.clear();
128 }
129
130 bool Filter::modified(const Filter& filter)
131 {
132         return !(filter_type == filter.filter_type &&
133                 filter_width == filter.filter_width);
134 }
135
136 void Filter::tag_update(Scene *scene)
137 {
138         need_update = true;
139 }
140
141 CCL_NAMESPACE_END
142