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