1 /*
2 * cl_retinex_handler.cpp - CL retinex handler
3 *
4 * Copyright (c) 2016 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: wangfei <feix.w.wang@intel.com>
19 * Wind Yuan <feng.yuan@intel.com>
20 */
21
22 #include "cl_utils.h"
23 #include "cl_retinex_handler.h"
24 #include <algorithm>
25 #include "cl_device.h"
26
27 namespace XCam {
28
29 static uint32_t retinex_gauss_scale [3] = {2, 8, 20}; //{20, 60, 150};
30 static float retinex_gauss_sigma [3] = {2.0f, 8.0f, 20.0f}; //{12.0f, 40.0f, 120.0f};
31 static float retinex_config_log_min = -0.12f; // -0.18f
32 static float retinex_config_log_max = 0.18f; //0.2f
33
34 enum {
35 KernelScaler = 0,
36 KernelGaussian,
37 KernelRetinex,
38 };
39
40 const static XCamKernelInfo kernel_retinex_info [] = {
41 {
42 "kernel_image_scaler",
43 #include "kernel_image_scaler.clx"
44 , 0,
45 },
46 {
47 "kernel_gauss",
48 #include "kernel_gauss.clx"
49 , 0,
50 },
51 {
52 "kernel_retinex",
53 #include "kernel_retinex.clx"
54 , 0,
55 },
56 };
57
CLRetinexScalerImageKernel(const SmartPtr<CLContext> & context,const CLImageScalerMemoryLayout mem_layout,SmartPtr<CLRetinexImageHandler> & retinex)58 CLRetinexScalerImageKernel::CLRetinexScalerImageKernel (
59 const SmartPtr<CLContext> &context,
60 const CLImageScalerMemoryLayout mem_layout,
61 SmartPtr<CLRetinexImageHandler> &retinex)
62 : CLScalerKernel (context, mem_layout)
63 , _retinex(retinex)
64 {
65 }
66
67 SmartPtr<VideoBuffer>
get_input_buffer()68 CLRetinexScalerImageKernel::get_input_buffer ()
69 {
70 return _retinex->get_input_buf ();
71 }
72
73 SmartPtr<VideoBuffer>
get_output_buffer()74 CLRetinexScalerImageKernel::get_output_buffer ()
75 {
76 return _retinex->get_scaler_buf1 ();
77 }
78
CLRetinexGaussImageKernel(const SmartPtr<CLContext> & context,SmartPtr<CLRetinexImageHandler> & retinex,uint32_t index,uint32_t radius,float sigma)79 CLRetinexGaussImageKernel::CLRetinexGaussImageKernel (
80 const SmartPtr<CLContext> &context,
81 SmartPtr<CLRetinexImageHandler> &retinex,
82 uint32_t index,
83 uint32_t radius, float sigma)
84 : CLGaussImageKernel (context, radius, sigma)
85 , _retinex (retinex)
86 , _index (index)
87 {
88 }
89
90 SmartPtr<VideoBuffer>
get_input_buf()91 CLRetinexGaussImageKernel::get_input_buf ()
92 {
93 return _retinex->get_scaler_buf1 ();
94 }
95
96 SmartPtr<VideoBuffer>
get_output_buf()97 CLRetinexGaussImageKernel::get_output_buf ()
98 {
99 return _retinex->get_gaussian_buf (_index);
100 }
101
CLRetinexImageKernel(const SmartPtr<CLContext> & context,SmartPtr<CLRetinexImageHandler> & retinex)102 CLRetinexImageKernel::CLRetinexImageKernel (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex)
103 : CLImageKernel (context, "kernel_retinex"),
104 _retinex (retinex)
105 {
106 }
107
108 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)109 CLRetinexImageKernel::prepare_arguments (
110 CLArgList &args, CLWorkSize &work_size)
111 {
112 SmartPtr<CLContext> context = get_context ();
113 SmartPtr<VideoBuffer> input = _retinex->get_input_buf ();
114 SmartPtr<VideoBuffer> output = _retinex->get_output_buf ();
115
116 const VideoBufferInfo & video_info_in = input->get_video_info ();
117 const VideoBufferInfo & video_info_out = output->get_video_info ();
118 SmartPtr<CLImage> image_in, image_in_uv;
119 SmartPtr<CLImage> image_out, image_out_uv;
120 SmartPtr<CLImage> image_in_ga[XCAM_RETINEX_MAX_SCALE];
121
122 CLImageDesc cl_desc_in, cl_desc_out, cl_desc_ga;
123
124 cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32;
125 cl_desc_in.format.image_channel_order = CL_RGBA;
126 cl_desc_in.width = video_info_in.width / 4; // 16;
127 cl_desc_in.height = video_info_in.height;
128 cl_desc_in.row_pitch = video_info_in.strides[0];
129 image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]);
130
131 cl_desc_in.height = video_info_in.height / 2;
132 cl_desc_in.row_pitch = video_info_in.strides[1];
133 image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]);
134
135 cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32;
136 cl_desc_out.format.image_channel_order = CL_RGBA;
137 cl_desc_out.width = video_info_out.width / 4; // 16;
138 cl_desc_out.height = video_info_out.height;
139 cl_desc_out.row_pitch = video_info_out.strides[0];
140 image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]);
141
142 cl_desc_out.height = video_info_out.height / 2;
143 cl_desc_out.row_pitch = video_info_out.strides[1];
144 image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]);
145
146 XCAM_FAIL_RETURN (
147 WARNING,
148 image_in->is_valid () && image_in_uv->is_valid () &&
149 image_out->is_valid () && image_out_uv->is_valid(),
150 XCAM_RETURN_ERROR_MEM,
151 "cl image kernel(%s) in/out memory not available", get_kernel_name ());
152
153 for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
154 SmartPtr<VideoBuffer> gaussian_buf = _retinex->get_gaussian_buf (i);
155 XCAM_ASSERT (gaussian_buf.ptr ());
156
157 const VideoBufferInfo & video_info_gauss = gaussian_buf->get_video_info ();
158
159 cl_desc_ga.format.image_channel_data_type = CL_UNORM_INT8;
160 cl_desc_ga.format.image_channel_order = CL_R;
161 cl_desc_ga.width = video_info_gauss.width;
162 cl_desc_ga.height = video_info_gauss.height;
163 cl_desc_ga.row_pitch = video_info_gauss.strides[0];
164 image_in_ga[i] = convert_to_climage (context, gaussian_buf, cl_desc_ga, video_info_gauss.offsets[0]);
165
166 XCAM_FAIL_RETURN (
167 WARNING,
168 image_in_ga[i]->is_valid (),
169 XCAM_RETURN_ERROR_MEM,
170 "cl image kernel(%s) gauss memory[%d] is invalid", get_kernel_name (), i);
171 }
172 CLRetinexConfig retinex_config;
173 retinex_config.log_min = retinex_config_log_min;
174 retinex_config.log_max = retinex_config_log_max;
175 retinex_config.gain = 1.0f / (retinex_config.log_max - retinex_config.log_min);
176 retinex_config.width = (float)video_info_in.width;
177 retinex_config.height = (float)video_info_in.height;
178
179 //set args;
180 args.push_back (new CLMemArgument (image_in));
181 args.push_back (new CLMemArgument (image_in_uv));
182 for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
183 args.push_back (new CLMemArgument (image_in_ga[i]));
184 }
185 args.push_back (new CLMemArgument (image_out));
186 args.push_back (new CLMemArgument (image_out_uv));
187 args.push_back (new CLArgumentT<CLRetinexConfig> (retinex_config));
188
189 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
190 work_size.global[0] = video_info_out.width / 4;
191 work_size.global[1] = video_info_out.height;
192 work_size.local[0] = 16;
193 work_size.local[1] = 2;
194
195 return XCAM_RETURN_NO_ERROR;
196 }
197
CLRetinexImageHandler(const SmartPtr<CLContext> & context,const char * name)198 CLRetinexImageHandler::CLRetinexImageHandler (const SmartPtr<CLContext> &context, const char *name)
199 : CLImageHandler (context, name)
200 , _scaler_factor(XCAM_RETINEX_SCALER_FACTOR)
201 {
202 }
203
204 void
emit_stop()205 CLRetinexImageHandler::emit_stop ()
206 {
207 if (_scaler_buf_pool.ptr ())
208 _scaler_buf_pool->stop ();
209 }
210
211 XCamReturn
prepare_output_buf(SmartPtr<VideoBuffer> & input,SmartPtr<VideoBuffer> & output)212 CLRetinexImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
213 {
214 CLImageHandler::prepare_output_buf(input, output);
215 XCamReturn ret = XCAM_RETURN_NO_ERROR;
216 ret = prepare_scaler_buf (input->get_video_info ());
217 XCAM_FAIL_RETURN(
218 WARNING,
219 ret == XCAM_RETURN_NO_ERROR,
220 ret,
221 "CLRetinexImageHandler prepare scaled video buf failed");
222
223 return XCAM_RETURN_NO_ERROR;
224 }
225
226 XCamReturn
prepare_scaler_buf(const VideoBufferInfo & video_info)227 CLRetinexImageHandler::prepare_scaler_buf (const VideoBufferInfo &video_info)
228 {
229 if (!_scaler_buf_pool.ptr ()) {
230 SmartPtr<CLContext> context = get_context ();
231 VideoBufferInfo scaler_video_info;
232 uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _scaler_factor), 8);
233 uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _scaler_factor), 4);
234
235 scaler_video_info.init (video_info.format, new_width, new_height);
236
237 _scaler_buf_pool = new CLVideoBufferPool ();
238 XCAM_ASSERT (_scaler_buf_pool.ptr ());
239 _scaler_buf_pool->set_video_info (scaler_video_info);
240 _scaler_buf_pool->reserve (XCAM_RETINEX_MAX_SCALE + 1);
241
242 _scaler_buf1 = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
243 XCAM_ASSERT (_scaler_buf1.ptr ());
244
245 for (int i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
246 _gaussian_buf[i] = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
247 XCAM_ASSERT (_gaussian_buf[i].ptr ());
248 }
249 }
250
251 return XCAM_RETURN_NO_ERROR;
252 }
253
254 bool
set_retinex_kernel(SmartPtr<CLRetinexImageKernel> & kernel)255 CLRetinexImageHandler::set_retinex_kernel(SmartPtr<CLRetinexImageKernel> &kernel)
256 {
257 SmartPtr<CLImageKernel> image_kernel = kernel;
258 add_kernel (image_kernel);
259 _retinex_kernel = kernel;
260 return true;
261 }
262
263 bool
set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> & kernel)264 CLRetinexImageHandler::set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> &kernel)
265 {
266 SmartPtr<CLImageKernel> image_kernel = kernel;
267 add_kernel (image_kernel);
268 _retinex_scaler_kernel = kernel;
269 return true;
270 }
271
272 static SmartPtr<CLRetinexScalerImageKernel>
create_kernel_retinex_scaler(const SmartPtr<CLContext> & context,SmartPtr<CLRetinexImageHandler> handler)273 create_kernel_retinex_scaler (
274 const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler)
275 {
276 SmartPtr<CLRetinexScalerImageKernel> kernel;
277
278 kernel = new CLRetinexScalerImageKernel (context, CL_IMAGE_SCALER_NV12_Y, handler);
279 XCAM_ASSERT (kernel.ptr ());
280 XCAM_FAIL_RETURN (
281 ERROR, kernel->build_kernel (kernel_retinex_info[KernelScaler], NULL) == XCAM_RETURN_NO_ERROR, NULL,
282 "build retinex scaler kernel(%s) failed", kernel_retinex_info[KernelScaler].kernel_name);
283
284 XCAM_ASSERT (kernel->is_valid ());
285 return kernel;
286 }
287
288 static SmartPtr<CLRetinexGaussImageKernel>
create_kernel_retinex_gaussian(const SmartPtr<CLContext> & context,SmartPtr<CLRetinexImageHandler> handler,uint32_t index,uint32_t radius,float sigma)289 create_kernel_retinex_gaussian (
290 const SmartPtr<CLContext> &context,
291 SmartPtr<CLRetinexImageHandler> handler,
292 uint32_t index,
293 uint32_t radius, float sigma)
294 {
295 SmartPtr<CLRetinexGaussImageKernel> kernel;
296 char build_options[1024];
297
298 xcam_mem_clear (build_options);
299 snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius);
300
301 kernel = new CLRetinexGaussImageKernel (context, handler, index, radius, sigma);
302 XCAM_ASSERT (kernel.ptr ());
303 XCAM_FAIL_RETURN (
304 ERROR, kernel->build_kernel (kernel_retinex_info[KernelGaussian], build_options) == XCAM_RETURN_NO_ERROR, NULL,
305 "build retinex gaussian kernel(%s) failed", kernel_retinex_info[KernelGaussian].kernel_name);
306
307 XCAM_ASSERT (kernel->is_valid ());
308
309 return kernel;
310 }
311
312 static SmartPtr<CLRetinexImageKernel>
create_kernel_retinex(const SmartPtr<CLContext> & context,SmartPtr<CLRetinexImageHandler> handler)313 create_kernel_retinex (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler)
314 {
315 SmartPtr<CLRetinexImageKernel> kernel;
316 char build_options[1024];
317
318 xcam_mem_clear (build_options);
319 snprintf (build_options, sizeof (build_options), " -DRETINEX_SCALE_SIZE=%d ", XCAM_RETINEX_MAX_SCALE);
320
321 kernel = new CLRetinexImageKernel (context, handler);
322 XCAM_ASSERT (kernel.ptr ());
323 XCAM_FAIL_RETURN (
324 ERROR, kernel->build_kernel (kernel_retinex_info[KernelRetinex], build_options) == XCAM_RETURN_NO_ERROR, NULL,
325 "build retinex kernel(%s) failed", kernel_retinex_info[KernelRetinex].kernel_name);
326
327 XCAM_ASSERT (kernel->is_valid ());
328 return kernel;
329 }
330
331 SmartPtr<CLImageHandler>
create_cl_retinex_image_handler(const SmartPtr<CLContext> & context)332 create_cl_retinex_image_handler (const SmartPtr<CLContext> &context)
333 {
334 SmartPtr<CLRetinexImageHandler> retinex_handler;
335
336 SmartPtr<CLRetinexScalerImageKernel> retinex_scaler_kernel;
337 SmartPtr<CLRetinexImageKernel> retinex_kernel;
338
339 retinex_handler = new CLRetinexImageHandler (context, "cl_handler_retinex");
340 retinex_scaler_kernel = create_kernel_retinex_scaler (context, retinex_handler);
341 XCAM_FAIL_RETURN (
342 ERROR,
343 retinex_scaler_kernel.ptr () && retinex_scaler_kernel->is_valid (),
344 NULL,
345 "Retinex handler create scaler kernel failed");
346 retinex_handler->set_retinex_scaler_kernel (retinex_scaler_kernel);
347
348 for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
349 SmartPtr<CLImageKernel> retinex_gauss_kernel;
350 retinex_gauss_kernel = create_kernel_retinex_gaussian (
351 context, retinex_handler, i, retinex_gauss_scale [i], retinex_gauss_sigma [i]);
352 XCAM_FAIL_RETURN (
353 ERROR,
354 retinex_gauss_kernel.ptr () && retinex_gauss_kernel->is_valid (),
355 NULL,
356 "Retinex handler create gaussian kernel failed");
357 retinex_handler->add_kernel (retinex_gauss_kernel);
358 }
359
360 retinex_kernel = create_kernel_retinex (context, retinex_handler);
361 XCAM_FAIL_RETURN (
362 ERROR,
363 retinex_kernel.ptr () && retinex_kernel->is_valid (),
364 NULL,
365 "Retinex handler create retinex kernel failed");
366 retinex_handler->set_retinex_kernel (retinex_kernel);
367
368 return retinex_handler;
369 }
370
371 }
372