1 /*
2  * cl_3d_denoise_handler.cpp - CL 3D noise reduction handler
3  *
4  *  Copyright (c) 2015 Intel Corporation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Author: Wei Zong <wei.zong@intel.com>
19  */
20 
21 #include "cl_utils.h"
22 #include "cl_3d_denoise_handler.h"
23 
24 namespace XCam {
25 
26 #define CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT  3
27 #define CL_3D_DENOISE_REFERENCE_FRAME_COUNT      3
28 #define CL_3D_DENOISE_WG_WIDTH   4
29 #define CL_3D_DENOISE_WG_HEIGHT  16
30 
31 #define CL_3D_DENOISE_ENABLE_SUBGROUP 1
32 #define CL_3D_DENOISE_IIR_FILTERING   1
33 
34 #if CL_3D_DENOISE_ENABLE_SUBGROUP
35 #define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise"
36 #else
37 #define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise_slm"
38 #endif
39 
40 enum {
41     Kernel3DDenoise,
42     Kernel3DDenoiseSLM,
43 };
44 
45 const XCamKernelInfo kernel_3d_denoise_info[] = {
46     {
47         "kernel_3d_denoise",
48 #include "kernel_3d_denoise.clx"
49         , 0,
50     },
51 
52     {
53         "kernel_3d_denoise_slm",
54 #include "kernel_3d_denoise_slm.clx"
55         , 0,
56     },
57 };
58 
CL3DDenoiseImageKernel(const SmartPtr<CLContext> & context,const char * name,uint32_t channel,SmartPtr<CL3DDenoiseImageHandler> & handler)59 CL3DDenoiseImageKernel::CL3DDenoiseImageKernel (
60     const SmartPtr<CLContext> &context,
61     const char *name,
62     uint32_t channel,
63     SmartPtr<CL3DDenoiseImageHandler> &handler)
64     : CLImageKernel (context, name)
65     , _channel (channel)
66     , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT)
67     , _handler (handler)
68 {
69 }
70 
71 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)72 CL3DDenoiseImageKernel::prepare_arguments (
73     CLArgList &args, CLWorkSize &work_size)
74 {
75     SmartPtr<CLContext> context = get_context ();
76 
77     SmartPtr<VideoBuffer> input = _handler->get_input_buf ();
78     SmartPtr<VideoBuffer> output = _handler->get_output_buf ();
79 
80     const VideoBufferInfo & video_info_in = input->get_video_info ();
81     const VideoBufferInfo & video_info_out = output->get_video_info ();
82 
83     uint32_t info_index = 0;
84     if (_channel == CL_IMAGE_CHANNEL_Y) {
85         info_index = 0;
86     } else if (_channel == CL_IMAGE_CHANNEL_UV) {
87         info_index = 1;
88     }
89 
90     CLImageDesc cl_desc_in, cl_desc_out;
91     cl_desc_in.format.image_channel_order = CL_RGBA;
92 #if CL_3D_DENOISE_ENABLE_SUBGROUP
93     cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16;
94     cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 8) / 8;
95 #else
96     cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8;
97     cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 4) / 4;
98 #endif
99     cl_desc_in.height = video_info_in.height >> info_index;
100     cl_desc_in.row_pitch = video_info_in.strides[info_index];
101 
102     cl_desc_out.format.image_channel_order = CL_RGBA;
103 #if CL_3D_DENOISE_ENABLE_SUBGROUP
104     cl_desc_out.format.image_channel_data_type = CL_UNSIGNED_INT16;
105     cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 8) / 8;
106 #else
107     cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8;
108     cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 4) / 4;
109 #endif
110     cl_desc_out.height = video_info_out.height >> info_index;
111     cl_desc_out.row_pitch = video_info_out.strides[info_index];
112 
113     _ref_count = _handler->get_ref_framecount ();
114     float gain = 5.0f / (_handler->get_denoise_config ().gain + 0.0001f);
115     float threshold = 2.0f * _handler->get_denoise_config ().threshold[info_index];
116 
117     SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]);
118     SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]);
119     XCAM_ASSERT (image_in->is_valid () && image_out->is_valid ());
120     XCAM_FAIL_RETURN (
121         WARNING,
122         image_in->is_valid () && image_out->is_valid (),
123         XCAM_RETURN_ERROR_MEM,
124         "cl image kernel(%s) in/out memory not available", get_kernel_name ());
125 
126     if (_image_in_list.size () < _ref_count) {
127         while (_image_in_list.size () < _ref_count) {
128             _image_in_list.push_back (image_in);
129         }
130     } else {
131         _image_in_list.pop_back ();
132         _image_in_list.push_front (image_in);
133     }
134 
135     if (!_image_out_prev.ptr ()) {
136         _image_out_prev = image_in;
137     }
138 
139     //set args;
140     args.push_back (new CLArgumentT<float> (gain));
141     args.push_back (new CLArgumentT<float> (threshold));
142     args.push_back (new CLMemArgument (_image_out_prev));
143     args.push_back (new CLMemArgument (image_out));
144 
145     uint8_t image_list_count = _image_in_list.size ();
146     for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) {
147         args.push_back (new CLMemArgument (*it));
148     }
149 
150     //backup enough buffers for kernel
151     for (; image_list_count < CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT; ++image_list_count) {
152         args.push_back (new CLMemArgument (image_in));
153     }
154 
155     //set worksize
156     work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
157 #if CL_3D_DENOISE_ENABLE_SUBGROUP
158     work_size.local[0] = CL_3D_DENOISE_WG_WIDTH;
159     work_size.local[1] = CL_3D_DENOISE_WG_HEIGHT;
160     work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]);
161     work_size.global[1] = (cl_desc_in.height +  work_size.local[1] - 1) / work_size.local[1] * work_size.local[1];
162 #else
163     work_size.local[0] = 8;
164     work_size.local[1] = 1;
165     work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]);
166     work_size.global[1] = XCAM_ALIGN_UP(cl_desc_in.height / 8, 8 * work_size.local[1]);
167 #endif
168 
169     _image_out_prev = image_out;
170 
171     return XCAM_RETURN_NO_ERROR;
172 }
173 
CL3DDenoiseImageHandler(const SmartPtr<CLContext> & context,const char * name)174 CL3DDenoiseImageHandler::CL3DDenoiseImageHandler (const SmartPtr<CLContext> &context, const char *name)
175     : CLImageHandler (context, name)
176     , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT - 2)
177 {
178     _config.gain = 1.0f;
179     _config.threshold[0] = 0.05f;
180     _config.threshold[1] = 0.05f;
181 }
182 
183 bool
set_ref_framecount(const uint8_t count)184 CL3DDenoiseImageHandler::set_ref_framecount (const uint8_t count)
185 {
186     _ref_count = count;
187 
188     return true;
189 }
190 
191 bool
set_denoise_config(const XCam3aResultTemporalNoiseReduction & config)192 CL3DDenoiseImageHandler::set_denoise_config (const XCam3aResultTemporalNoiseReduction& config)
193 {
194     _config = config;
195 
196     return true;
197 }
198 
199 XCamReturn
prepare_parameters(SmartPtr<VideoBuffer> & input,SmartPtr<VideoBuffer> & output)200 CL3DDenoiseImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
201 {
202     _input_buf = input;
203     _output_buf = output;
204     return XCAM_RETURN_NO_ERROR;
205 }
206 
207 static SmartPtr<CLImageKernel>
create_3d_denoise_kernel(const SmartPtr<CLContext> & context,SmartPtr<CL3DDenoiseImageHandler> handler,uint32_t channel,uint8_t ref_count)208 create_3d_denoise_kernel (
209     const SmartPtr<CLContext> &context, SmartPtr<CL3DDenoiseImageHandler> handler,
210     uint32_t channel, uint8_t ref_count)
211 {
212     char build_options[1024];
213     xcam_mem_clear (build_options);
214 
215     snprintf (build_options, sizeof (build_options),
216               " -DREFERENCE_FRAME_COUNT=%d"
217               " -DWORKGROUP_WIDTH=%d"
218               " -DWORKGROUP_HEIGHT=%d"
219               " -DENABLE_IIR_FILERING=%d",
220               ref_count,
221               CL_3D_DENOISE_WG_WIDTH,
222               CL_3D_DENOISE_WG_HEIGHT,
223               CL_3D_DENOISE_IIR_FILTERING);
224 
225 #if CL_3D_DENOISE_ENABLE_SUBGROUP
226     int kernel_index = Kernel3DDenoise;
227 #else
228     int kernel_index = Kernel3DDenoiseSLM;
229 #endif
230 
231     SmartPtr<CLImageKernel> kernel =
232         new CL3DDenoiseImageKernel (context, KERNEL_3D_DENOISE_NAME, channel, handler);
233     XCAM_ASSERT (kernel.ptr ());
234     XCAM_FAIL_RETURN (
235         ERROR, kernel->build_kernel (kernel_3d_denoise_info[kernel_index], build_options) == XCAM_RETURN_NO_ERROR,
236         NULL, "build 3d denoise kernel failed");
237     return kernel;
238 }
239 
240 SmartPtr<CLImageHandler>
create_cl_3d_denoise_image_handler(const SmartPtr<CLContext> & context,uint32_t channel,uint8_t ref_count)241 create_cl_3d_denoise_image_handler (
242     const SmartPtr<CLContext> &context, uint32_t channel, uint8_t ref_count)
243 {
244     SmartPtr<CL3DDenoiseImageHandler> denoise_handler;
245     SmartPtr<CLImageKernel> denoise_kernel;
246 
247     denoise_handler = new CL3DDenoiseImageHandler (context, "cl_3d_denoise_handler");
248     XCAM_ASSERT (denoise_handler.ptr ());
249     denoise_handler->set_ref_framecount (ref_count);
250 
251     if (channel & CL_IMAGE_CHANNEL_Y) {
252         denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_Y, ref_count);
253         XCAM_FAIL_RETURN (
254             ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create Y channel kernel failed.");
255 
256         denoise_handler->add_kernel (denoise_kernel);
257     }
258 
259     if (channel & CL_IMAGE_CHANNEL_UV) {
260         denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_UV, ref_count);
261         XCAM_FAIL_RETURN (
262             ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create UV channel kernel failed.");
263 
264         denoise_handler->add_kernel (denoise_kernel);
265     }
266 
267     return denoise_handler;
268 }
269 };
270