0a7bf96fed7edfb0d5d82f7895c789e528cfa1a6
[blender.git] / intern / cycles / device / opencl / opencl_mega.cpp
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 #ifdef WITH_OPENCL
18
19 #include "device/opencl/opencl.h"
20
21 #include "render/buffers.h"
22
23 #include "kernel/kernel_types.h"
24
25 #include "util/util_md5.h"
26 #include "util/util_path.h"
27 #include "util/util_time.h"
28
29 CCL_NAMESPACE_BEGIN
30
31 class OpenCLDeviceMegaKernel : public OpenCLDeviceBase
32 {
33 public:
34         OpenCLProgram path_trace_program;
35
36         OpenCLDeviceMegaKernel(DeviceInfo& info, Stats &stats, Profiler &profiler, bool background_)
37         : OpenCLDeviceBase(info, stats, profiler, background_),
38           path_trace_program(this, "megakernel", "kernel.cl", "-D__COMPILE_ONLY_MEGAKERNEL__ ")
39         {
40         }
41
42         virtual bool show_samples() const {
43                 return true;
44         }
45
46         virtual BVHLayoutMask get_bvh_layout_mask() const {
47                 return BVH_LAYOUT_BVH2;
48         }
49
50         virtual bool load_kernels(const DeviceRequestedFeatures& /*requested_features*/,
51                                   vector<OpenCLProgram*> &programs)
52         {
53                 path_trace_program.add_kernel(ustring("path_trace"));
54                 programs.push_back(&path_trace_program);
55                 return true;
56         }
57
58         ~OpenCLDeviceMegaKernel()
59         {
60                 task_pool.stop();
61                 path_trace_program.release();
62         }
63
64         void path_trace(RenderTile& rtile, int sample)
65         {
66                 scoped_timer timer(&rtile.buffers->render_time);
67
68                 /* Cast arguments to cl types. */
69                 cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
70                 cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
71                 cl_int d_x = rtile.x;
72                 cl_int d_y = rtile.y;
73                 cl_int d_w = rtile.w;
74                 cl_int d_h = rtile.h;
75                 cl_int d_offset = rtile.offset;
76                 cl_int d_stride = rtile.stride;
77
78                 /* Sample arguments. */
79                 cl_int d_sample = sample;
80
81                 cl_kernel ckPathTraceKernel = path_trace_program(ustring("path_trace"));
82
83                 cl_uint start_arg_index =
84                         kernel_set_args(ckPathTraceKernel,
85                                         0,
86                                         d_data,
87                                         d_buffer);
88
89                 set_kernel_arg_buffers(ckPathTraceKernel, &start_arg_index);
90
91                 start_arg_index += kernel_set_args(ckPathTraceKernel,
92                                                    start_arg_index,
93                                                    d_sample,
94                                                    d_x,
95                                                    d_y,
96                                                    d_w,
97                                                    d_h,
98                                                    d_offset,
99                                                    d_stride);
100
101                 enqueue_kernel(ckPathTraceKernel, d_w, d_h);
102         }
103
104         void thread_run(DeviceTask *task)
105         {
106                 if(task->type == DeviceTask::FILM_CONVERT) {
107                         film_convert(*task, task->buffer, task->rgba_byte, task->rgba_half);
108                 }
109                 else if(task->type == DeviceTask::SHADER) {
110                         shader(*task);
111                 }
112                 else if(task->type == DeviceTask::RENDER) {
113                         RenderTile tile;
114                         DenoisingTask denoising(this, *task);
115
116                         /* Keep rendering tiles until done. */
117                         while(task->acquire_tile(this, tile)) {
118                                 if(tile.task == RenderTile::PATH_TRACE) {
119                                         int start_sample = tile.start_sample;
120                                         int end_sample = tile.start_sample + tile.num_samples;
121
122                                         for(int sample = start_sample; sample < end_sample; sample++) {
123                                                 if(task->get_cancel()) {
124                                                         if(task->need_finish_queue == false)
125                                                                 break;
126                                                 }
127
128                                                 path_trace(tile, sample);
129
130                                                 tile.sample = sample + 1;
131
132                                                 task->update_progress(&tile, tile.w*tile.h);
133                                         }
134
135                                         /* Complete kernel execution before release tile */
136                                         /* This helps in multi-device render;
137                                          * The device that reaches the critical-section function
138                                          * release_tile waits (stalling other devices from entering
139                                          * release_tile) for all kernels to complete. If device1 (a
140                                          * slow-render device) reaches release_tile first then it would
141                                          * stall device2 (a fast-render device) from proceeding to render
142                                          * next tile.
143                                          */
144                                         clFinish(cqCommandQueue);
145                                 }
146                                 else if(tile.task == RenderTile::DENOISE) {
147                                         tile.sample = tile.start_sample + tile.num_samples;
148                                         denoise(tile, denoising);
149                                         task->update_progress(&tile, tile.w*tile.h);
150                                 }
151
152                                 task->release_tile(tile);
153                         }
154                 }
155         }
156
157         bool is_split_kernel()
158         {
159                 return false;
160         }
161 };
162
163 Device *opencl_create_mega_device(DeviceInfo& info, Stats& stats, Profiler &profiler, bool background)
164 {
165         return new OpenCLDeviceMegaKernel(info, stats, profiler, background);
166 }
167
168 CCL_NAMESPACE_END
169
170 #endif