1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include "device/device_task.h"
21 
22 #include "render/buffers.h"
23 
24 #include "util/util_algorithm.h"
25 #include "util/util_time.h"
26 
27 CCL_NAMESPACE_BEGIN
28 
29 /* Device Task */
30 
DeviceTask(Type type_)31 DeviceTask::DeviceTask(Type type_)
32     : type(type_),
33       x(0),
34       y(0),
35       w(0),
36       h(0),
37       rgba_byte(0),
38       rgba_half(0),
39       buffer(0),
40       sample(0),
41       num_samples(1),
42       shader_input(0),
43       shader_output(0),
44       shader_eval_type(0),
45       shader_filter(0),
46       shader_x(0),
47       shader_w(0),
48       buffers(nullptr)
49 {
50   last_update_time = time_dt();
51 }
52 
get_subtask_count(int num,int max_size) const53 int DeviceTask::get_subtask_count(int num, int max_size) const
54 {
55   if (max_size != 0) {
56     int max_size_num;
57 
58     if (type == SHADER) {
59       max_size_num = (shader_w + max_size - 1) / max_size;
60     }
61     else {
62       max_size = max(1, max_size / w);
63       max_size_num = (h + max_size - 1) / max_size;
64     }
65 
66     num = max(max_size_num, num);
67   }
68 
69   if (type == SHADER) {
70     num = min(shader_w, num);
71   }
72   else if (type == RENDER) {
73   }
74   else {
75     num = min(h, num);
76   }
77 
78   return num;
79 }
80 
split(list<DeviceTask> & tasks,int num,int max_size) const81 void DeviceTask::split(list<DeviceTask> &tasks, int num, int max_size) const
82 {
83   num = get_subtask_count(num, max_size);
84 
85   if (type == SHADER) {
86     for (int i = 0; i < num; i++) {
87       int tx = shader_x + (shader_w / num) * i;
88       int tw = (i == num - 1) ? shader_w - i * (shader_w / num) : shader_w / num;
89 
90       DeviceTask task = *this;
91 
92       task.shader_x = tx;
93       task.shader_w = tw;
94 
95       tasks.push_back(task);
96     }
97   }
98   else if (type == RENDER) {
99     for (int i = 0; i < num; i++)
100       tasks.push_back(*this);
101   }
102   else {
103     for (int i = 0; i < num; i++) {
104       int ty = y + (h / num) * i;
105       int th = (i == num - 1) ? h - i * (h / num) : h / num;
106 
107       DeviceTask task = *this;
108 
109       task.y = ty;
110       task.h = th;
111 
112       tasks.push_back(task);
113     }
114   }
115 }
116 
update_progress(RenderTile * rtile,int pixel_samples)117 void DeviceTask::update_progress(RenderTile *rtile, int pixel_samples)
118 {
119   if (type == FILM_CONVERT)
120     return;
121 
122   if (update_progress_sample) {
123     if (pixel_samples == -1) {
124       pixel_samples = shader_w;
125     }
126     update_progress_sample(pixel_samples, rtile ? rtile->sample : 0);
127   }
128 
129   if (update_tile_sample) {
130     double current_time = time_dt();
131 
132     if (current_time - last_update_time >= 1.0) {
133       update_tile_sample(*rtile);
134 
135       last_update_time = current_time;
136     }
137   }
138 }
139 
140 /* Adaptive Sampling */
141 
AdaptiveSampling()142 AdaptiveSampling::AdaptiveSampling() : use(true), adaptive_step(0), min_samples(0)
143 {
144 }
145 
146 /* Render samples in steps that align with the adaptive filtering. */
align_static_samples(int samples) const147 int AdaptiveSampling::align_static_samples(int samples) const
148 {
149   if (samples > adaptive_step) {
150     /* Make multiple of adaptive_step. */
151     while (samples % adaptive_step != 0) {
152       samples--;
153     }
154   }
155   else if (samples < adaptive_step) {
156     /* Make divisor of adaptive_step. */
157     while (adaptive_step % samples != 0) {
158       samples--;
159     }
160   }
161 
162   return max(samples, 1);
163 }
164 
165 /* Render samples in steps that align with the adaptive filtering, with the
166  * suggested number of samples dynamically changing. */
align_dynamic_samples(int offset,int samples) const167 int AdaptiveSampling::align_dynamic_samples(int offset, int samples) const
168 {
169   /* Round so that we end up on multiples of adaptive_samples. */
170   samples += offset;
171 
172   if (samples > adaptive_step) {
173     /* Make multiple of adaptive_step. */
174     while (samples % adaptive_step != 0) {
175       samples--;
176     }
177   }
178 
179   samples -= offset;
180 
181   return max(samples, 1);
182 }
183 
need_filter(int sample) const184 bool AdaptiveSampling::need_filter(int sample) const
185 {
186   if (sample > min_samples) {
187     return (sample & (adaptive_step - 1)) == (adaptive_step - 1);
188   }
189   else {
190     return false;
191   }
192 }
193 
194 CCL_NAMESPACE_END
195