1 /*
2 * cl_pyramid_blender.cpp - CL multi-band blender
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: Wind Yuan <feng.yuan@intel.com>
19 */
20
21 #include "cl_pyramid_blender.h"
22 #include <algorithm>
23 #include "xcam_obj_debug.h"
24 #include "cl_device.h"
25 #include "cl_utils.h"
26
27 #if CL_PYRAMID_ENABLE_DUMP
28 #define BLENDER_PROFILING_START(name) XCAM_STATIC_PROFILING_START(name)
29 #define BLENDER_PROFILING_END(name, times_of_print) XCAM_STATIC_PROFILING_END(name, times_of_print)
30 #else
31 #define BLENDER_PROFILING_START(name)
32 #define BLENDER_PROFILING_END(name, times_of_print)
33 #endif
34
35 //#define SAMPLER_POSITION_OFFSET -0.25f
36 #define SAMPLER_POSITION_OFFSET 0.0f
37
38 #define SEAM_POS_TYPE int16_t
39 #define SEAM_SUM_TYPE float
40 #define SEAM_MASK_TYPE uint8_t
41
42 namespace XCam {
43
44 enum {
45 KernelPyramidTransform = 0,
46 KernelPyramidReconstruct,
47 KernelPyramidBlender,
48 KernelPyramidScale,
49 KernelPyramidCopy,
50 KernelPyramidLap,
51 KernelImageDiff,
52 KernelSeamDP,
53 KernelSeamMaskScale,
54 KernelSeamMaskScaleSLM,
55 KernelSeamBlender
56 };
57
58 static const XCamKernelInfo kernels_info [] = {
59 {
60 "kernel_gauss_scale_transform",
61 #include "kernel_gauss_lap_pyramid.clx"
62 , 0,
63 },
64 {
65 "kernel_gauss_lap_reconstruct",
66 #include "kernel_gauss_lap_pyramid.clx"
67 , 0,
68 },
69 {
70 "kernel_pyramid_blend",
71 #include "kernel_gauss_lap_pyramid.clx"
72 , 0,
73 },
74 {
75 "kernel_pyramid_scale",
76 #include "kernel_gauss_lap_pyramid.clx"
77 , 0,
78 },
79 {
80 "kernel_pyramid_copy",
81 #include "kernel_gauss_lap_pyramid.clx"
82 , 0,
83 },
84 {
85 "kernel_lap_transform",
86 #include "kernel_gauss_lap_pyramid.clx"
87 , 0,
88 },
89 {
90 "kernel_image_diff",
91 #include "kernel_gauss_lap_pyramid.clx"
92 , 0,
93 },
94 {
95 "kernel_seam_dp",
96 #include "kernel_gauss_lap_pyramid.clx"
97 , 0,
98 },
99 {
100 "kernel_mask_gauss_scale",
101 #include "kernel_gauss_lap_pyramid.clx"
102 , 0,
103 },
104 {
105 "kernel_mask_gauss_scale_slm",
106 #include "kernel_gauss_lap_pyramid.clx"
107 , 0,
108 },
109 {
110 "kernel_seam_mask_blend",
111 #include "kernel_gauss_lap_pyramid.clx"
112 , 0,
113 }
114 };
115
116 static uint32_t
clamp(int32_t i,int32_t min,int32_t max)117 clamp(int32_t i, int32_t min, int32_t max)
118 {
119 if (i < min)
120 return min;
121 if (i > max - 1)
122 return max - 1;
123 return i;
124 }
125
126 static float*
get_gauss_coeffs(int radius,float sigma)127 get_gauss_coeffs (int radius, float sigma)
128 {
129 static int g_radius = 0;
130 static float g_sigma = 0;
131 static float g_table[512] = {0.0f};
132
133 int i;
134 int scale = radius * 2 + 1;
135 float dis = 0.0f, sum = 0.0f;
136
137 if (g_radius == radius && g_sigma == sigma)
138 return g_table;
139
140 XCAM_ASSERT (scale < 512);
141
142 for (i = 0; i < scale; i++) {
143 dis = ((float)i - radius) * ((float)i - radius);
144 g_table[i] = exp(-dis / (2.0f * sigma * sigma));
145 sum += g_table[i];
146 }
147
148 for(i = 0; i < scale; i++)
149 g_table[i] = g_table[i] / sum;
150
151 g_radius = radius;
152 g_sigma = sigma;
153
154 return g_table;
155 }
156
157 static bool
gauss_blur_buffer(SmartPtr<CLBuffer> & buf,int buf_len,int g_radius,float g_sigma)158 gauss_blur_buffer (SmartPtr<CLBuffer> &buf, int buf_len, int g_radius, float g_sigma)
159 {
160 float *buf_ptr = NULL;
161 float *coeff = NULL;
162 XCamReturn ret = XCAM_RETURN_NO_ERROR;
163 float *tmp_ptr = NULL;
164
165 coeff = get_gauss_coeffs (g_radius, g_sigma);
166 XCAM_ASSERT (coeff);
167
168 ret = buf->enqueue_map((void*&)buf_ptr, 0, buf_len * sizeof (float));
169 XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, false, "gauss_blur_buffer failed on enqueue_map");
170
171 tmp_ptr = (float *)xcam_malloc (buf_len * sizeof (float));
172 XCAM_ASSERT (tmp_ptr);
173 for (int i = 0; i < buf_len; ++i) {
174 tmp_ptr[i] = 0.0f;
175 for (int j = -g_radius; j <= (int)g_radius; ++j) {
176 tmp_ptr[i] += buf_ptr[clamp(i + j, 0, buf_len)] * coeff[g_radius + j];
177 }
178 }
179
180 for (int i = 0; i < buf_len; ++i) {
181 buf_ptr[i] = tmp_ptr[i];
182 }
183 xcam_free (tmp_ptr);
184 buf->enqueue_unmap((void*)buf_ptr);
185 return true;
186 }
187
PyramidLayer()188 PyramidLayer::PyramidLayer ()
189 : blend_width (0)
190 , blend_height (0)
191 {
192 for (int plane = 0; plane < CLBlenderPlaneMax; ++plane) {
193 for (int i = 0; i < XCAM_BLENDER_IMAGE_NUM; ++i) {
194 gauss_offset_x[plane][i] = 0;
195 lap_offset_x[plane][i] = 0;
196 }
197 mask_width [plane] = 0;
198 }
199 }
200
CLPyramidBlender(const SmartPtr<CLContext> & context,const char * name,int layers,bool need_uv,bool need_seam,CLBlenderScaleMode scale_mode)201 CLPyramidBlender::CLPyramidBlender (
202 const SmartPtr<CLContext> &context, const char *name,
203 int layers, bool need_uv, bool need_seam, CLBlenderScaleMode scale_mode)
204 : CLBlender (context, name, need_uv, scale_mode)
205 , _layers (0)
206 , _need_seam (need_seam)
207 , _seam_pos_stride (0)
208 , _seam_width (0)
209 , _seam_height (0)
210 , _seam_pos_offset_x (0)
211 , _seam_pos_valid_width (0)
212 , _seam_mask_done (false)
213 {
214 if (layers <= 1)
215 _layers = 1;
216 else if (layers > XCAM_CL_PYRAMID_MAX_LEVEL)
217 _layers = XCAM_CL_PYRAMID_MAX_LEVEL;
218 else
219 _layers = (uint32_t)layers;
220 }
221
~CLPyramidBlender()222 CLPyramidBlender::~CLPyramidBlender ()
223 {
224 }
225
226 SmartPtr<CLImage>
get_gauss_image(uint32_t layer,uint32_t buf_index,bool is_uv)227 CLPyramidBlender::get_gauss_image (uint32_t layer, uint32_t buf_index, bool is_uv)
228 {
229 XCAM_ASSERT (layer < _layers);
230 XCAM_ASSERT (buf_index < XCAM_BLENDER_IMAGE_NUM);
231 uint32_t plane = (is_uv ? 1 : 0);
232 return _pyramid_layers[layer].gauss_image[plane][buf_index];
233 }
234
235 SmartPtr<CLImage>
get_lap_image(uint32_t layer,uint32_t buf_index,bool is_uv)236 CLPyramidBlender::get_lap_image (uint32_t layer, uint32_t buf_index, bool is_uv)
237 {
238 XCAM_ASSERT (layer < _layers);
239 XCAM_ASSERT (buf_index < XCAM_BLENDER_IMAGE_NUM);
240 uint32_t plane = (is_uv ? 1 : 0);
241
242 return _pyramid_layers[layer].lap_image[plane][buf_index];
243 }
244
245 SmartPtr<CLImage>
get_blend_image(uint32_t layer,bool is_uv)246 CLPyramidBlender::get_blend_image (uint32_t layer, bool is_uv)
247 {
248 XCAM_ASSERT (layer < _layers);
249 uint32_t plane = (is_uv ? 1 : 0);
250
251 return _pyramid_layers[layer].blend_image[plane][BlendImageIndex];
252 }
253
254 SmartPtr<CLImage>
get_reconstruct_image(uint32_t layer,bool is_uv)255 CLPyramidBlender::get_reconstruct_image (uint32_t layer, bool is_uv)
256 {
257 XCAM_ASSERT (layer < _layers);
258 uint32_t plane = (is_uv ? 1 : 0);
259 return _pyramid_layers[layer].blend_image[plane][ReconstructImageIndex];
260 }
261
262 SmartPtr<CLImage>
get_scale_image(bool is_uv)263 CLPyramidBlender::get_scale_image (bool is_uv)
264 {
265 uint32_t plane = (is_uv ? 1 : 0);
266 return _pyramid_layers[0].scale_image[plane];
267 }
268
269 SmartPtr<CLBuffer>
get_blend_mask(uint32_t layer,bool is_uv)270 CLPyramidBlender::get_blend_mask (uint32_t layer, bool is_uv)
271 {
272 XCAM_ASSERT (layer < _layers);
273 uint32_t plane = (is_uv ? 1 : 0);
274 return _pyramid_layers[layer].blend_mask[plane];
275 }
276
277 SmartPtr<CLImage>
get_seam_mask(uint32_t layer)278 CLPyramidBlender::get_seam_mask (uint32_t layer)
279 {
280 XCAM_ASSERT (layer < _layers);
281 return _pyramid_layers[layer].seam_mask[CLSeamMaskCoeff];
282 }
283
284 const PyramidLayer &
get_pyramid_layer(uint32_t layer) const285 CLPyramidBlender::get_pyramid_layer (uint32_t layer) const
286 {
287 return _pyramid_layers[layer];
288 }
289
290 const SmartPtr<CLImage> &
get_image_diff() const291 CLPyramidBlender::get_image_diff () const
292 {
293 return _image_diff;
294 }
295
296 void
get_seam_info(uint32_t & width,uint32_t & height,uint32_t & stride) const297 CLPyramidBlender::get_seam_info (uint32_t &width, uint32_t &height, uint32_t &stride) const
298 {
299 width = _seam_width;
300 height = _seam_height;
301 stride = _seam_pos_stride;
302 }
303
304 void
get_seam_pos_info(uint32_t & offset_x,uint32_t & valid_width) const305 CLPyramidBlender::get_seam_pos_info (uint32_t &offset_x, uint32_t &valid_width) const
306 {
307 offset_x = _seam_pos_offset_x;
308 valid_width = _seam_pos_valid_width;
309 }
310
311 void
bind_buf_to_layer0(SmartPtr<CLContext> context,SmartPtr<VideoBuffer> & input0,SmartPtr<VideoBuffer> & input1,SmartPtr<VideoBuffer> & output,const Rect & merge0_rect,const Rect & merge1_rect,bool need_uv,CLBlenderScaleMode scale_mode)312 PyramidLayer::bind_buf_to_layer0 (
313 SmartPtr<CLContext> context,
314 SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1, SmartPtr<VideoBuffer> &output,
315 const Rect &merge0_rect, const Rect &merge1_rect, bool need_uv, CLBlenderScaleMode scale_mode)
316 {
317 const VideoBufferInfo &in0_info = input0->get_video_info ();
318 const VideoBufferInfo &in1_info = input1->get_video_info ();
319 const VideoBufferInfo &out_info = output->get_video_info ();
320 int max_plane = (need_uv ? 2 : 1);
321 uint32_t divider_vert[2] = {1, 2};
322
323 XCAM_ASSERT (in0_info.height == in1_info.height);
324 XCAM_ASSERT (merge0_rect.width == merge1_rect.width);
325
326 this->blend_width = XCAM_ALIGN_UP (merge0_rect.width, XCAM_CL_BLENDER_ALIGNMENT_X);
327 this->blend_height = merge0_rect.height;
328
329 CLImageDesc cl_desc;
330 cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
331 cl_desc.format.image_channel_order = CL_RGBA;
332
333 for (int i_plane = 0; i_plane < max_plane; ++i_plane) {
334 cl_desc.width = in0_info.width / 8;
335 cl_desc.height = in0_info.height / divider_vert[i_plane];
336 cl_desc.row_pitch = in0_info.strides[i_plane];
337 this->gauss_image[i_plane][0] = convert_to_climage (context, input0, cl_desc, in0_info.offsets[i_plane]);
338 this->gauss_offset_x[i_plane][0] = merge0_rect.pos_x; // input0 offset
339
340 cl_desc.width = in1_info.width / 8;
341 cl_desc.height = in1_info.height / divider_vert[i_plane];
342 cl_desc.row_pitch = in1_info.strides[i_plane];
343 this->gauss_image[i_plane][1] = convert_to_climage (context, input1, cl_desc, in1_info.offsets[i_plane]);
344 this->gauss_offset_x[i_plane][1] = merge1_rect.pos_x; // input1 offset
345
346 cl_desc.width = out_info.width / 8;
347 cl_desc.height = out_info.height / divider_vert[i_plane];
348 cl_desc.row_pitch = out_info.strides[i_plane];
349
350 if (scale_mode == CLBlenderScaleLocal) {
351 this->scale_image[i_plane] = convert_to_climage (context, output, cl_desc, out_info.offsets[i_plane]);
352
353 cl_desc.width = XCAM_ALIGN_UP (this->blend_width, XCAM_CL_BLENDER_ALIGNMENT_X) / 8;
354 cl_desc.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[i_plane]) / divider_vert[i_plane];
355 uint32_t row_pitch = CLImage::calculate_pixel_bytes (cl_desc.format) *
356 XCAM_ALIGN_UP (cl_desc.width, XCAM_CL_IMAGE_ALIGNMENT_X);
357 uint32_t size = row_pitch * cl_desc.height;
358 SmartPtr<CLBuffer> cl_buf = new CLBuffer (context, size);
359 XCAM_ASSERT (cl_buf.ptr () && cl_buf->is_valid ());
360 cl_desc.row_pitch = row_pitch;
361 this->blend_image[i_plane][ReconstructImageIndex] = new CLImage2D (context, cl_desc, 0, cl_buf);
362 } else {
363 this->blend_image[i_plane][ReconstructImageIndex] =
364 convert_to_climage (context, output, cl_desc, out_info.offsets[i_plane]);
365 }
366 XCAM_ASSERT (this->blend_image[i_plane][ReconstructImageIndex].ptr ());
367 }
368
369 }
370
371 void
init_layer0(SmartPtr<CLContext> context,bool last_layer,bool need_uv,int mask_radius,float mask_sigma)372 PyramidLayer::init_layer0 (SmartPtr<CLContext> context, bool last_layer, bool need_uv, int mask_radius, float mask_sigma)
373 {
374 XCAM_ASSERT (this->blend_width && this->blend_height);
375
376 //init mask
377 this->mask_width[0] = this->blend_width;
378 uint32_t mask_size = this->mask_width[0] * sizeof (float);
379 this->blend_mask[0] = new CLBuffer(context, mask_size);
380 float *blend_ptr = NULL;
381 XCamReturn ret = this->blend_mask[0]->enqueue_map((void*&)blend_ptr, 0, mask_size);
382 if (!xcam_ret_is_ok (ret)) {
383 XCAM_LOG_ERROR ("PyramidLayer init layer0 failed in blend_mask mem_map");
384 return;
385 }
386
387 for (uint32_t i_ptr = 0; i_ptr < this->mask_width[0]; ++i_ptr) {
388 if (i_ptr <= this->mask_width[0] / 2)
389 blend_ptr[i_ptr] = 1.0f;
390 else
391 blend_ptr[i_ptr] = 0.0f;
392 }
393 this->blend_mask[0]->enqueue_unmap ((void*)blend_ptr);
394 gauss_blur_buffer (this->blend_mask[0], this->mask_width[0], mask_radius, mask_sigma);
395
396 if (need_uv)
397 copy_mask_from_y_to_uv (context);
398
399 if (last_layer)
400 return;
401
402 int max_plane = (need_uv ? 2 : 1);
403 uint32_t divider_vert[2] = {1, 2};
404 CLImageDesc cl_desc;
405 cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
406 cl_desc.format.image_channel_order = CL_RGBA;
407 for (int i_plane = 0; i_plane < max_plane; ++i_plane) {
408 cl_desc.width = this->blend_width / 8;
409 cl_desc.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[i_plane]) / divider_vert[i_plane];
410
411 this->blend_image[i_plane][BlendImageIndex] = new CLImage2D (context, cl_desc);
412 this->lap_image[i_plane][0] = new CLImage2D (context, cl_desc);
413 this->lap_image[i_plane][1] = new CLImage2D (context, cl_desc);
414 this->lap_offset_x[i_plane][0] = this->lap_offset_x[i_plane][1] = 0;
415
416 #if CL_PYRAMID_ENABLE_DUMP
417 this->dump_gauss_resize[i_plane] = new CLImage2D (context, cl_desc);
418 this->dump_original[i_plane][0] = new CLImage2D (context, cl_desc);
419 this->dump_original[i_plane][1] = new CLImage2D (context, cl_desc);
420 this->dump_final[i_plane] = new CLImage2D (context, cl_desc);
421 #endif
422 }
423 }
424
425 void
build_cl_images(SmartPtr<CLContext> context,bool last_layer,bool need_uv)426 PyramidLayer::build_cl_images (SmartPtr<CLContext> context, bool last_layer, bool need_uv)
427 {
428 uint32_t size = 0, row_pitch = 0;
429 CLImageDesc cl_desc_set;
430 SmartPtr<CLBuffer> cl_buf;
431 uint32_t divider_vert[2] = {1, 2};
432 uint32_t max_plane = (need_uv ? 2 : 1);
433
434 cl_desc_set.format.image_channel_data_type = CL_UNSIGNED_INT16;
435 cl_desc_set.format.image_channel_order = CL_RGBA;
436
437 for (uint32_t plane = 0; plane < max_plane; ++plane) {
438 for (int i_image = 0; i_image < XCAM_BLENDER_IMAGE_NUM; ++i_image) {
439 cl_desc_set.row_pitch = 0;
440 cl_desc_set.width = XCAM_ALIGN_UP (this->blend_width, XCAM_CL_BLENDER_ALIGNMENT_X) / 8;
441 cl_desc_set.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[plane]) / divider_vert[plane];
442
443 //gauss y image created by cl buffer
444 row_pitch = CLImage::calculate_pixel_bytes (cl_desc_set.format) *
445 XCAM_ALIGN_UP (cl_desc_set.width, XCAM_CL_IMAGE_ALIGNMENT_X);
446 size = row_pitch * cl_desc_set.height;
447 cl_buf = new CLBuffer (context, size);
448 XCAM_ASSERT (cl_buf.ptr () && cl_buf->is_valid ());
449 cl_desc_set.row_pitch = row_pitch;
450 this->gauss_image[plane][i_image] = new CLImage2D (context, cl_desc_set, 0, cl_buf);
451 XCAM_ASSERT (this->gauss_image[plane][i_image].ptr ());
452 this->gauss_offset_x[plane][i_image] = 0; // offset to 0, need recalculate if for deep multi-band blender
453 }
454
455 cl_desc_set.width = XCAM_ALIGN_UP (this->blend_width, XCAM_CL_BLENDER_ALIGNMENT_X) / 8;
456 cl_desc_set.height = XCAM_ALIGN_UP (this->blend_height, divider_vert[plane]) / divider_vert[plane];
457 row_pitch = CLImage::calculate_pixel_bytes (cl_desc_set.format) *
458 XCAM_ALIGN_UP (cl_desc_set.width, XCAM_CL_IMAGE_ALIGNMENT_X);
459 size = row_pitch * cl_desc_set.height;
460 cl_buf = new CLBuffer (context, size);
461 XCAM_ASSERT (cl_buf.ptr () && cl_buf->is_valid ());
462 cl_desc_set.row_pitch = row_pitch;
463 this->blend_image[plane][ReconstructImageIndex] = new CLImage2D (context, cl_desc_set, 0, cl_buf);
464 XCAM_ASSERT (this->blend_image[plane][ReconstructImageIndex].ptr ());
465 #if CL_PYRAMID_ENABLE_DUMP
466 this->dump_gauss_resize[plane] = new CLImage2D (context, cl_desc_set);
467 this->dump_original[plane][0] = new CLImage2D (context, cl_desc_set);
468 this->dump_original[plane][1] = new CLImage2D (context, cl_desc_set);
469 this->dump_final[plane] = new CLImage2D (context, cl_desc_set);
470 #endif
471 if (!last_layer) {
472 cl_desc_set.row_pitch = 0;
473 this->blend_image[plane][BlendImageIndex] = new CLImage2D (context, cl_desc_set);
474 XCAM_ASSERT (this->blend_image[plane][BlendImageIndex].ptr ());
475 for (int i_image = 0; i_image < XCAM_BLENDER_IMAGE_NUM; ++i_image) {
476 this->lap_image[plane][i_image] = new CLImage2D (context, cl_desc_set);
477 XCAM_ASSERT (this->lap_image[plane][i_image].ptr ());
478 this->lap_offset_x[plane][i_image] = 0; // offset to 0, need calculate from next layer if for deep multi-band blender
479 }
480 }
481 }
482 }
483
484 bool
copy_mask_from_y_to_uv(SmartPtr<CLContext> & context)485 PyramidLayer::copy_mask_from_y_to_uv (SmartPtr<CLContext> &context)
486 {
487 XCamReturn ret = XCAM_RETURN_NO_ERROR;
488 XCAM_ASSERT (this->mask_width[0]);
489 XCAM_ASSERT (this->blend_mask[0].ptr ());
490
491 this->mask_width[1] = (this->mask_width[0] + 1) / 2;
492 this->blend_mask[1] = new CLBuffer (context, this->mask_width[1] * sizeof(float));
493 XCAM_ASSERT (this->blend_mask[1].ptr ());
494
495 float *from_ptr = NULL;
496 float *to_ptr = NULL;
497 ret = this->blend_mask[1]->enqueue_map ((void*&)to_ptr, 0, this->mask_width[1] * sizeof(float));
498 XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "PyramidLayer copy mask failed in blend_mask[1] mem_map");
499 ret = this->blend_mask[0]->enqueue_map((void*&)from_ptr, 0, this->mask_width[0] * sizeof(float));
500 XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "PyramidLayer copy mask failed in blend_mask[0] mem_map");
501
502 for (int i = 0; i < (int)this->mask_width[1]; ++i) {
503 if (i * 2 + 1 >= (int)this->mask_width[0]) { // todo i* 2 + 1
504 XCAM_ASSERT (i * 2 < (int)this->mask_width[0]);
505 to_ptr[i] = from_ptr[i * 2] / 2.0f;
506 } else {
507 to_ptr[i] = (from_ptr[i * 2] + from_ptr[i * 2 + 1]) / 2.0f;
508 }
509 }
510 this->blend_mask[1]->enqueue_unmap ((void*)to_ptr);
511 this->blend_mask[0]->enqueue_unmap ((void*)from_ptr);
512
513 return true;
514 }
515
516 void
last_layer_buffer_redirect()517 CLPyramidBlender::last_layer_buffer_redirect ()
518 {
519 PyramidLayer &layer = _pyramid_layers[_layers - 1];
520 uint32_t max_plane = (need_uv () ? 2 : 1);
521
522 for (uint32_t plane = 0; plane < max_plane; ++plane) {
523 layer.blend_image[plane][BlendImageIndex] = layer.blend_image[plane][ReconstructImageIndex];
524
525 for (uint32_t i_image = 0; i_image < XCAM_BLENDER_IMAGE_NUM; ++i_image) {
526 layer.lap_image[plane][i_image] = layer.gauss_image[plane][i_image];
527 }
528 }
529 }
530
531 void
dump_layer_mask(uint32_t layer,bool is_uv)532 CLPyramidBlender::dump_layer_mask (uint32_t layer, bool is_uv)
533 {
534 const PyramidLayer &pyr_layer = get_pyramid_layer (layer);
535 int plane = (is_uv ? 1 : 0);
536
537 float *mask_ptr = NULL;
538 XCamReturn ret = pyr_layer.blend_mask[plane]->enqueue_map ((void*&)mask_ptr, 0, pyr_layer.mask_width[plane] * sizeof(float));
539 if (!xcam_ret_is_ok (ret)) {
540 XCAM_LOG_ERROR ("CLPyramidBlender dump mask failed in blend_mask(layer:%d) mem_map", layer);
541 return;
542 }
543
544 printf ("layer(%d)(-%s) mask, width:%d\n", layer, (is_uv ? "UV" : "Y"), pyr_layer.mask_width[plane]);
545 for (uint32_t i = 0; i < pyr_layer.mask_width[plane]; ++i) {
546 printf ("%.03f\t", mask_ptr[i]);
547 }
548 printf ("\n");
549
550 pyr_layer.blend_mask[plane]->enqueue_unmap ((void*)mask_ptr);
551 }
552
553 static bool
gauss_fill_mask(SmartPtr<CLContext> context,PyramidLayer & prev,PyramidLayer & to,bool need_uv,int mask_radius,float mask_sigma)554 gauss_fill_mask (
555 SmartPtr<CLContext> context, PyramidLayer &prev, PyramidLayer &to, bool need_uv,
556 int mask_radius, float mask_sigma)
557 {
558 XCamReturn ret = XCAM_RETURN_NO_ERROR;
559 uint32_t mask_size = to.blend_width * sizeof (float);
560 uint32_t prev_size = prev.mask_width[0] * sizeof (float);
561 float *pre_ptr = NULL;
562 int i;
563
564 //gauss to[0]
565 to.mask_width[0] = to.blend_width;
566 to.blend_mask[0] = new CLBuffer (context, mask_size);
567 XCAM_ASSERT (to.blend_mask[0].ptr ());
568 float *mask0_ptr = NULL;
569 ret = to.blend_mask[0]->enqueue_map((void*&)mask0_ptr, 0, mask_size);
570 XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "gauss_fill_mask failed in destination image mem_map");
571
572 ret = prev.blend_mask[0]->enqueue_map((void*&)pre_ptr, 0, prev_size);
573 XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "gauss_fill_mask failed in source image mem_map");
574
575 for (i = 0; i < (int)to.blend_width; ++i) {
576 if (i * 2 + 1 >= (int)prev.mask_width[0]) { // todo i* 2 + 1
577 XCAM_ASSERT (i * 2 < (int)prev.mask_width[0]);
578 mask0_ptr[i] = pre_ptr[i * 2] / 2.0f;
579 } else {
580 mask0_ptr[i] = (pre_ptr[i * 2] + pre_ptr[i * 2 + 1]) / 2.0f;
581 }
582 }
583 prev.blend_mask[0]->enqueue_unmap ((void*)pre_ptr);
584 to.blend_mask[0]->enqueue_unmap ((void*)mask0_ptr);
585
586 gauss_blur_buffer (to.blend_mask[0], to.mask_width[0], mask_radius, mask_sigma);
587
588 if (need_uv)
589 to.copy_mask_from_y_to_uv (context);
590
591 return true;
592 }
593
594 XCamReturn
allocate_cl_buffers(SmartPtr<CLContext> context,SmartPtr<VideoBuffer> & input0,SmartPtr<VideoBuffer> & input1,SmartPtr<VideoBuffer> & output)595 CLPyramidBlender::allocate_cl_buffers (
596 SmartPtr<CLContext> context,
597 SmartPtr<VideoBuffer> &input0, SmartPtr<VideoBuffer> &input1,
598 SmartPtr<VideoBuffer> &output)
599 {
600 uint32_t index = 0;
601 const Rect & window = get_merge_window ();
602 bool need_reallocate = true;
603 XCamReturn ret = XCAM_RETURN_NO_ERROR;
604
605 BLENDER_PROFILING_START (allocate_cl_buffers);
606
607 need_reallocate =
608 (window.width != (int32_t)_pyramid_layers[0].blend_width ||
609 (window.height != 0 && window.height != (int32_t)_pyramid_layers[0].blend_height));
610 _pyramid_layers[0].bind_buf_to_layer0 (
611 context, input0, input1, output,
612 get_input_merge_area (0), get_input_merge_area (1),
613 need_uv (), get_scale_mode ());
614
615 if (need_reallocate) {
616 int g_radius = (((float)(window.width - 1) / 2) / (1 << _layers)) * 1.2f;
617 float g_sigma = (float)g_radius;
618
619 _pyramid_layers[0].init_layer0 (context, (0 == _layers - 1), need_uv(), g_radius, g_sigma);
620
621 for (index = 1; index < _layers; ++index) {
622 _pyramid_layers[index].blend_width = (_pyramid_layers[index - 1].blend_width + 1) / 2;
623 _pyramid_layers[index].blend_height = (_pyramid_layers[index - 1].blend_height + 1) / 2;
624
625 _pyramid_layers[index].build_cl_images (context, (index == _layers - 1), need_uv ());
626 if (!_need_seam) {
627 gauss_fill_mask (context, _pyramid_layers[index - 1], _pyramid_layers[index], need_uv (), g_radius, g_sigma);
628 }
629 }
630
631 if (_need_seam) {
632 ret = init_seam_buffers (context);
633 XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender init seam buffer failed");
634 }
635 }
636
637 //last layer buffer redirect
638 last_layer_buffer_redirect ();
639 _seam_mask_done = false;
640
641 BLENDER_PROFILING_END (allocate_cl_buffers, 50);
642
643 return XCAM_RETURN_NO_ERROR;
644 }
645
646 XCamReturn
init_seam_buffers(SmartPtr<CLContext> context)647 CLPyramidBlender::init_seam_buffers (SmartPtr<CLContext> context)
648 {
649 const PyramidLayer &layer0 = get_pyramid_layer (0);
650 CLImageDesc cl_desc;
651
652 _seam_width = layer0.blend_width;
653 _seam_height = layer0.blend_height;
654 _seam_pos_stride = XCAM_ALIGN_UP (_seam_width, 64); // need a buffer large enough to avoid judgement in kernel
655 _seam_pos_offset_x = XCAM_ALIGN_UP (_seam_width / 4, XCAM_CL_BLENDER_ALIGNMENT_X);
656 if (_seam_pos_offset_x >= _seam_width)
657 _seam_pos_offset_x = 0;
658 _seam_pos_valid_width = XCAM_ALIGN_DOWN (_seam_width / 2, XCAM_CL_BLENDER_ALIGNMENT_X);
659 if (_seam_pos_valid_width <= 0)
660 _seam_pos_valid_width = XCAM_CL_BLENDER_ALIGNMENT_X;
661 XCAM_ASSERT (_seam_pos_offset_x + _seam_pos_valid_width <= _seam_width);
662
663 XCAM_ASSERT (layer0.blend_width > 0 && layer0.blend_height > 0);
664 cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
665 cl_desc.format.image_channel_order = CL_RGBA;
666 cl_desc.width = _seam_width / 8;
667 cl_desc.height = _seam_height;
668 cl_desc.row_pitch = CLImage::calculate_pixel_bytes (cl_desc.format) *
669 XCAM_ALIGN_UP (cl_desc.width, XCAM_CL_IMAGE_ALIGNMENT_X);
670
671 uint32_t image_diff_size = cl_desc.row_pitch * _seam_height;
672 SmartPtr<CLBuffer> cl_diff_buf = new CLBuffer (context, image_diff_size);
673 XCAM_FAIL_RETURN (
674 ERROR,
675 cl_diff_buf.ptr () && cl_diff_buf->is_valid (),
676 XCAM_RETURN_ERROR_CL,
677 "CLPyramidBlender init seam buffer failed to create image_difference buffers");
678
679 _image_diff = new CLImage2D (context, cl_desc, 0, cl_diff_buf);
680 XCAM_FAIL_RETURN (
681 ERROR,
682 _image_diff.ptr () && _image_diff->is_valid (),
683 XCAM_RETURN_ERROR_CL,
684 "CLPyramidBlender init seam buffer failed to bind image_difference data");
685
686 uint32_t pos_buf_size = sizeof (SEAM_POS_TYPE) * _seam_pos_stride * _seam_height;
687 uint32_t sum_buf_size = sizeof (SEAM_SUM_TYPE) * _seam_pos_stride * 2; // 2 lines
688 _seam_pos_buf = new CLBuffer (context, pos_buf_size, CL_MEM_READ_WRITE);
689 _seam_sum_buf = new CLBuffer (context, sum_buf_size, CL_MEM_READ_WRITE);
690 XCAM_FAIL_RETURN (
691 ERROR,
692 _seam_pos_buf.ptr () && _seam_pos_buf->is_valid () &&
693 _seam_sum_buf.ptr () && _seam_sum_buf->is_valid (),
694 XCAM_RETURN_ERROR_CL,
695 "CLPyramidBlender init seam buffer failed to create seam buffers");
696
697 uint32_t mask_width = XCAM_ALIGN_UP(_seam_width, XCAM_CL_BLENDER_ALIGNMENT_X);
698 uint32_t mask_height = XCAM_ALIGN_UP(_seam_height, 2);
699 for (uint32_t i = 0; i < _layers; ++i) {
700 cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
701 cl_desc.format.image_channel_order = CL_RGBA;
702 cl_desc.width = mask_width / 8;
703 cl_desc.height = mask_height;
704 cl_desc.row_pitch = CLImage::calculate_pixel_bytes (cl_desc.format) *
705 XCAM_ALIGN_UP (cl_desc.width, XCAM_CL_IMAGE_ALIGNMENT_X);
706
707 uint32_t mask_size = cl_desc.row_pitch * mask_height;
708 SmartPtr<CLBuffer> cl_buf0 = new CLBuffer (context, mask_size);
709 SmartPtr<CLBuffer> cl_buf1 = new CLBuffer (context, mask_size);
710 XCAM_ASSERT (cl_buf0.ptr () && cl_buf0->is_valid () && cl_buf1.ptr () && cl_buf1->is_valid ());
711
712 _pyramid_layers[i].seam_mask[CLSeamMaskTmp] = new CLImage2D (context, cl_desc, 0, cl_buf0);
713 _pyramid_layers[i].seam_mask[CLSeamMaskCoeff] = new CLImage2D (context, cl_desc, 0, cl_buf1);
714 XCAM_FAIL_RETURN (
715 ERROR,
716 _pyramid_layers[i].seam_mask[CLSeamMaskTmp].ptr () && _pyramid_layers[i].seam_mask[CLSeamMaskTmp]->is_valid () &&
717 _pyramid_layers[i].seam_mask[CLSeamMaskCoeff].ptr () && _pyramid_layers[i].seam_mask[CLSeamMaskCoeff]->is_valid (),
718 XCAM_RETURN_ERROR_CL,
719 "CLPyramidBlender init seam buffer failed to create seam_mask buffer");
720
721 mask_width = XCAM_ALIGN_UP(mask_width / 2, XCAM_CL_BLENDER_ALIGNMENT_X);
722 mask_height = XCAM_ALIGN_UP(mask_height / 2, 2);
723 }
724
725 return XCAM_RETURN_NO_ERROR;
726 }
727
728 static void
assign_mask_line(SEAM_MASK_TYPE * mask_ptr,int line,int stride,int delimiter)729 assign_mask_line (SEAM_MASK_TYPE *mask_ptr, int line, int stride, int delimiter)
730 {
731 #define MASK_1 0xFFFF
732 #define MASK_0 0x00
733
734 SEAM_MASK_TYPE *line_ptr = mask_ptr + line * stride;
735 int mask_1_len = delimiter + 1;
736
737 memset (line_ptr, MASK_1, sizeof (SEAM_MASK_TYPE) * mask_1_len);
738 memset (line_ptr + mask_1_len, MASK_0, sizeof (SEAM_MASK_TYPE) * (stride - mask_1_len));
739 }
740
741 XCamReturn
fill_seam_mask()742 CLPyramidBlender::fill_seam_mask ()
743 {
744 XCamReturn ret = XCAM_RETURN_NO_ERROR;
745 XCAM_ASSERT (_seam_pos_buf.ptr () && _seam_sum_buf.ptr ());
746 uint32_t pos_buf_size = sizeof (SEAM_POS_TYPE) * _seam_pos_stride * _seam_height;
747 uint32_t sum_buf_size = sizeof (SEAM_SUM_TYPE) * _seam_pos_stride * 2;
748 SEAM_SUM_TYPE *sum_ptr;
749 SEAM_POS_TYPE *pos_ptr;
750 SEAM_MASK_TYPE *mask_ptr;
751
752 if (_seam_mask_done)
753 return XCAM_RETURN_NO_ERROR;
754
755 ret = _seam_sum_buf->enqueue_map ((void *&)sum_ptr, 0, sum_buf_size, CL_MAP_READ);
756 XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender map seam_sum_buf failed");
757
758 float min_sum = 9999999999.0f, tmp_sum;
759 int pos = 0, min_pos0, min_pos1;
760 int i = 0;
761 SEAM_SUM_TYPE *sum_ptr0 = sum_ptr, *sum_ptr1 = sum_ptr + _seam_pos_stride;
762 for (i = (int)_seam_pos_offset_x; i < (int)(_seam_pos_offset_x + _seam_pos_valid_width); ++i) {
763 tmp_sum = sum_ptr0[i] + sum_ptr1[i];
764 if (tmp_sum >= min_sum)
765 continue;
766 pos = (int)i;
767 min_sum = tmp_sum;
768 }
769 _seam_sum_buf->enqueue_unmap ((void*)sum_ptr);
770 min_pos0 = min_pos1 = pos;
771
772 BLENDER_PROFILING_START (fill_seam_mask);
773
774 // reset layer0 seam_mask
775 SmartPtr<CLImage> seam_mask = _pyramid_layers[0].seam_mask[CLSeamMaskTmp];
776 const CLImageDesc &mask_desc = seam_mask->get_image_desc ();
777 size_t mask_origin[3] = {0, 0, 0};
778 size_t mask_region[3] = {mask_desc.width, mask_desc.height, 1};
779 size_t mask_row_pitch;
780 size_t mask_slice_pitch;
781 ret = seam_mask->enqueue_map ((void *&)mask_ptr, mask_origin, mask_region,
782 &mask_row_pitch, &mask_slice_pitch, CL_MAP_READ);
783 XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender map seam_mask failed");
784 uint32_t mask_stride = mask_row_pitch / sizeof (SEAM_MASK_TYPE);
785 ret = _seam_pos_buf->enqueue_map ((void *&)pos_ptr, 0, pos_buf_size, CL_MAP_READ);
786 XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidBlender map seam_pos_buf failed");
787 //printf ("***********min sum:%.3f, pos:%d, sum0:%.3f, sum1:%.3f\n", min_sum, pos, sum_ptr0[pos], sum_ptr1[pos]);
788 for (i = _seam_height / 2 - 1; i >= 0; --i) {
789 assign_mask_line (mask_ptr, i, mask_stride, min_pos0);
790 min_pos0 = pos_ptr [i * _seam_pos_stride + min_pos0];
791 }
792
793 for (i = _seam_height / 2; i < (int)_seam_height; ++i) {
794 assign_mask_line (mask_ptr, i, mask_stride, min_pos1);
795 min_pos1 = pos_ptr [i * _seam_pos_stride + min_pos1];
796 }
797 for (; i < (int)mask_desc.height; ++i) {
798 assign_mask_line (mask_ptr, i, mask_stride, min_pos1);
799 }
800
801 seam_mask->enqueue_unmap ((void*)mask_ptr);
802 _seam_pos_buf->enqueue_unmap ((void*)pos_ptr);
803
804 _seam_mask_done = true;
805
806 BLENDER_PROFILING_END (fill_seam_mask, 50);
807 return XCAM_RETURN_NO_ERROR;
808 }
809
810 XCamReturn
execute_done(SmartPtr<VideoBuffer> & output)811 CLPyramidBlender::execute_done (SmartPtr<VideoBuffer> &output)
812 {
813 int max_plane = (need_uv () ? 2 : 1);
814 XCAM_UNUSED (output);
815
816 #if CL_PYRAMID_ENABLE_DUMP
817 dump_buffers ();
818 #endif
819
820 for (int i_plane = 0; i_plane < max_plane; ++i_plane) {
821 _pyramid_layers[0].gauss_image[i_plane][0].release ();
822 _pyramid_layers[0].gauss_image[i_plane][1].release ();
823 _pyramid_layers[0].blend_image[i_plane][ReconstructImageIndex].release ();
824
825 if (_layers <= 1) {
826 _pyramid_layers[_layers - 1].blend_image[i_plane][BlendImageIndex].release ();
827 _pyramid_layers[_layers - 1].lap_image[i_plane][0].release ();
828 _pyramid_layers[_layers - 1].lap_image[i_plane][1].release ();
829 }
830 }
831
832 return XCAM_RETURN_NO_ERROR;
833 }
834
CLPyramidBlendKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,bool is_uv,bool need_seam)835 CLPyramidBlendKernel::CLPyramidBlendKernel (
836 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender,
837 uint32_t layer, bool is_uv, bool need_seam)
838 : CLImageKernel (context)
839 , _blender (blender)
840 , _layer (layer)
841 , _is_uv (is_uv)
842 , _need_seam (need_seam)
843 {
844 }
845
846 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)847 CLPyramidBlendKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
848 {
849 SmartPtr<CLContext> context = get_context ();
850
851 SmartPtr<CLImage> image_in0 = get_input_0 ();
852 SmartPtr<CLImage> image_in1 = get_input_1 ();
853 SmartPtr<CLImage> image_out = get_output ();
854 SmartPtr<CLMemory> buf_mask;
855 if (_need_seam)
856 buf_mask = get_seam_mask ();
857 else
858 buf_mask = get_blend_mask ();
859
860 XCAM_ASSERT (image_in0.ptr () && image_in1.ptr () && image_out.ptr ());
861 const CLImageDesc &cl_desc_out = image_out->get_image_desc ();
862
863 args.push_back (new CLMemArgument (image_in0));
864 args.push_back (new CLMemArgument (image_in1));
865 args.push_back (new CLMemArgument (buf_mask));
866 args.push_back (new CLMemArgument (image_out));
867
868 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
869 work_size.local[0] = 8;
870 work_size.local[1] = 8;
871 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]);
872 work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height, work_size.local[1]);
873 return XCAM_RETURN_NO_ERROR;
874 }
875
CLPyramidTransformKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,uint32_t buf_index,bool is_uv)876 CLPyramidTransformKernel::CLPyramidTransformKernel (
877 const SmartPtr<CLContext> &context,
878 SmartPtr<CLPyramidBlender> &blender,
879 uint32_t layer,
880 uint32_t buf_index,
881 bool is_uv)
882 : CLImageKernel (context)
883 , _blender (blender)
884 , _layer (layer)
885 , _buf_index (buf_index)
886 , _is_uv (is_uv)
887 {
888 XCAM_ASSERT (layer <= XCAM_CL_PYRAMID_MAX_LEVEL);
889 XCAM_ASSERT (buf_index <= XCAM_BLENDER_IMAGE_NUM);
890 }
891
892 static bool
change_image_format(SmartPtr<CLContext> context,SmartPtr<CLImage> input,SmartPtr<CLImage> & output,const CLImageDesc & new_desc)893 change_image_format (
894 SmartPtr<CLContext> context, SmartPtr<CLImage> input,
895 SmartPtr<CLImage> &output, const CLImageDesc &new_desc)
896 {
897 SmartPtr<CLImage2D> previous = input.dynamic_cast_ptr<CLImage2D> ();
898 if (!previous.ptr () || !previous->get_bind_buf ().ptr ())
899 return false;
900
901 SmartPtr<CLBuffer> bind_buf = previous->get_bind_buf ();
902 output = new CLImage2D (context, new_desc, 0, bind_buf);
903 if (!output.ptr ())
904 return false;
905 return true;
906 }
907
908 int32_t
get_input_gauss_offset_x()909 CLPyramidTransformKernel::get_input_gauss_offset_x ()
910 {
911 const PyramidLayer &layer = _blender->get_pyramid_layer (_layer);
912 uint32_t plane_index = (_is_uv ? 1 : 0);
913 return layer.gauss_offset_x[plane_index][_buf_index];
914 }
915
916 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)917 CLPyramidTransformKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
918 {
919 SmartPtr<CLContext> context = get_context ();
920
921 SmartPtr<CLImage> image_in_gauss = get_input_gauss();
922 SmartPtr<CLImage> image_out_gauss = get_output_gauss();
923 //SmartPtr<CLImage> image_out_lap = get_output_lap ();
924 const CLImageDesc &cl_desc_out_gauss_pre = image_out_gauss->get_image_desc ();
925
926 CLImageDesc cl_desc_out_gauss;
927 cl_desc_out_gauss.format.image_channel_data_type = CL_UNSIGNED_INT8;
928 cl_desc_out_gauss.format.image_channel_order = CL_RGBA;
929 cl_desc_out_gauss.width = cl_desc_out_gauss_pre.width * 2;
930 cl_desc_out_gauss.height = cl_desc_out_gauss_pre.height;
931 cl_desc_out_gauss.row_pitch = cl_desc_out_gauss_pre.row_pitch;
932 SmartPtr<CLImage> format_image_out;
933 change_image_format (context, image_out_gauss, format_image_out, cl_desc_out_gauss);
934 XCAM_FAIL_RETURN (
935 ERROR,
936 format_image_out.ptr () && format_image_out->is_valid (),
937 XCAM_RETURN_ERROR_CL,
938 "CLPyramidTransformKernel change output gauss image format failed");
939
940 int gauss_offset_x = get_input_gauss_offset_x () / 8;
941 XCAM_ASSERT (gauss_offset_x * 8 == get_input_gauss_offset_x ());
942
943 args.push_back (new CLMemArgument (image_in_gauss));
944 args.push_back (new CLArgumentT<int> (gauss_offset_x));
945 args.push_back (new CLMemArgument (format_image_out));
946
947 #if CL_PYRAMID_ENABLE_DUMP
948 int plane = _is_uv ? 1 : 0;
949 SmartPtr<CLImage> dump_original = _blender->get_pyramid_layer (_layer).dump_original[plane][_buf_index];
950
951 args.push_back (new CLMemArgument (dump_original));
952
953 printf ("L%dI%d: gauss_offset_x:%d \n", _layer, _buf_index, gauss_offset_x);
954 #endif
955
956 const int workitem_lines = 2;
957 int gloabal_y = XCAM_ALIGN_UP (cl_desc_out_gauss.height, workitem_lines) / workitem_lines;
958 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
959 work_size.local[0] = 16;
960 work_size.local[1] = 4;
961 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out_gauss.width, work_size.local[0]);
962 work_size.global[1] = XCAM_ALIGN_UP (gloabal_y, work_size.local[1]);
963
964 return XCAM_RETURN_NO_ERROR;
965 }
966
CLSeamDiffKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender)967 CLSeamDiffKernel::CLSeamDiffKernel (
968 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender)
969 : CLImageKernel (context)
970 , _blender (blender)
971 {
972 }
973
974 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)975 CLSeamDiffKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
976 {
977 const PyramidLayer &layer0 = _blender->get_pyramid_layer (0);
978 SmartPtr<CLImage> image0 = layer0.gauss_image[CLBlenderPlaneY][0];
979 SmartPtr<CLImage> image1 = layer0.gauss_image[CLBlenderPlaneY][1];
980 SmartPtr<CLImage> out_diff = _blender->get_image_diff ();
981 CLImageDesc out_diff_desc = out_diff->get_image_desc ();
982
983 int image_offset_x[XCAM_BLENDER_IMAGE_NUM];
984
985 for (uint32_t i = 0; i < XCAM_BLENDER_IMAGE_NUM; ++i) {
986 image_offset_x[i] = layer0.gauss_offset_x[CLBlenderPlaneY][i] / 8;
987 }
988
989 args.push_back (new CLMemArgument (image0));
990 args.push_back (new CLArgumentT<int> (image_offset_x[0]));
991 args.push_back (new CLMemArgument (image1));
992 args.push_back (new CLArgumentT<int> (image_offset_x[1]));
993 args.push_back (new CLMemArgument (out_diff));
994
995 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
996 work_size.local[0] = 8;
997 work_size.local[1] = 4;
998 work_size.global[0] = XCAM_ALIGN_UP (out_diff_desc.width, work_size.local[0]);
999 work_size.global[1] = XCAM_ALIGN_UP (out_diff_desc.height, work_size.local[1]);
1000
1001 return XCAM_RETURN_NO_ERROR;
1002 }
1003
CLSeamDPKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender)1004 CLSeamDPKernel::CLSeamDPKernel (
1005 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender)
1006 : CLImageKernel (context)
1007 , _blender (blender)
1008 {
1009 }
1010
1011 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)1012 CLSeamDPKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
1013 {
1014 #define ELEMENT_PIXEL 1
1015
1016 uint32_t width, height, stride;
1017 uint32_t pos_offset_x, pos_valid_width;
1018 _blender->get_seam_info (width, height, stride);
1019 _blender->get_seam_pos_info (pos_offset_x, pos_valid_width);
1020 int seam_height = (int)height;
1021 int seam_stride = (int)stride / ELEMENT_PIXEL;
1022 int seam_offset_x = (int)pos_offset_x / ELEMENT_PIXEL; // ushort8
1023 int seam_valid_with = (int)pos_valid_width / ELEMENT_PIXEL;
1024 int max_pos = (int)(pos_offset_x + pos_valid_width - 1);
1025
1026 SmartPtr<CLImage> image = _blender->get_image_diff ();
1027 SmartPtr<CLBuffer> pos_buf = _blender->get_seam_pos_buf ();
1028 SmartPtr<CLBuffer> sum_buf = _blender->get_seam_sum_buf ();
1029 XCAM_ASSERT (image.ptr () && pos_buf.ptr () && sum_buf.ptr ());
1030
1031 CLImageDesc cl_orig = image->get_image_desc ();
1032 CLImageDesc cl_desc_convert;
1033 cl_desc_convert.format.image_channel_data_type = CL_UNSIGNED_INT8;
1034 cl_desc_convert.format.image_channel_order = CL_R;
1035 cl_desc_convert.width = cl_orig.width * (8 / ELEMENT_PIXEL);
1036 cl_desc_convert.height = cl_orig.height;
1037 cl_desc_convert.row_pitch = cl_orig.row_pitch;
1038
1039 SmartPtr<CLImage> convert_image;
1040 change_image_format (get_context (), image, convert_image, cl_desc_convert);
1041 XCAM_ASSERT (convert_image.ptr () && convert_image->is_valid ());
1042
1043 args.push_back (new CLMemArgument (convert_image));
1044 args.push_back (new CLMemArgument (pos_buf));
1045 args.push_back (new CLMemArgument (sum_buf));
1046 args.push_back (new CLArgumentT<int> (seam_offset_x));
1047 args.push_back (new CLArgumentT<int> (seam_valid_with));
1048 args.push_back (new CLArgumentT<int> (max_pos));
1049 args.push_back (new CLArgumentT<int> (seam_height));
1050 args.push_back (new CLArgumentT<int> (seam_stride));
1051
1052 work_size.dim = 1;
1053 work_size.local[0] = XCAM_ALIGN_UP(seam_valid_with, 16);
1054 work_size.global[0] = work_size.local[0] * 2;
1055
1056 return XCAM_RETURN_NO_ERROR;
1057 }
1058
CLPyramidSeamMaskKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,bool scale,bool need_slm)1059 CLPyramidSeamMaskKernel::CLPyramidSeamMaskKernel (
1060 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender,
1061 uint32_t layer, bool scale, bool need_slm)
1062 : CLImageKernel (context)
1063 , _blender (blender)
1064 , _layer (layer)
1065 , _need_scale (scale)
1066 , _need_slm (need_slm)
1067 {
1068 XCAM_ASSERT (layer < blender->get_layers ());
1069 }
1070
1071 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)1072 CLPyramidSeamMaskKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
1073 {
1074 XCamReturn ret = XCAM_RETURN_NO_ERROR;
1075 ret = _blender->fill_seam_mask ();
1076 XCAM_FAIL_RETURN (ERROR, ret == XCAM_RETURN_NO_ERROR, ret, "CLPyramidSeamMaskKernel fill seam mask failed");
1077
1078 SmartPtr<CLContext> context = get_context ();
1079 const PyramidLayer &cur_layer = _blender->get_pyramid_layer (_layer);
1080 SmartPtr<CLImage> input_image = cur_layer.seam_mask[CLSeamMaskTmp];
1081 SmartPtr<CLImage> out_gauss = cur_layer.seam_mask[CLSeamMaskCoeff];
1082 CLImageDesc out_gauss_desc = out_gauss->get_image_desc ();
1083
1084 XCAM_ASSERT (input_image.ptr () && out_gauss.ptr ());
1085 XCAM_ASSERT (input_image->is_valid () && out_gauss->is_valid ());
1086
1087 args.push_back (new CLMemArgument (input_image));
1088 args.push_back (new CLMemArgument (out_gauss));
1089
1090
1091
1092 if (_need_slm) {
1093 int image_width = out_gauss_desc.width;
1094 args.push_back (new CLArgumentT<int> (image_width));
1095 }
1096
1097 if (_need_scale) {
1098 const PyramidLayer &next_layer = _blender->get_pyramid_layer (_layer + 1);
1099 SmartPtr<CLImage> out_orig = next_layer.seam_mask[CLSeamMaskTmp];
1100 CLImageDesc input_desc, output_desc;
1101 input_desc = out_orig->get_image_desc ();
1102 output_desc.format.image_channel_data_type = CL_UNSIGNED_INT8;
1103 output_desc.format.image_channel_order = CL_RGBA;
1104 output_desc.width = input_desc.width * 2;
1105 output_desc.height = input_desc.height;
1106 output_desc.row_pitch = input_desc.row_pitch;
1107
1108 SmartPtr<CLImage> output_scale_image;
1109 change_image_format (context, out_orig, output_scale_image, output_desc);
1110 args.push_back (new CLMemArgument (output_scale_image));
1111 }
1112
1113 uint32_t workitem_height = XCAM_ALIGN_UP (out_gauss_desc.height, 2) / 2;
1114
1115 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
1116
1117 if (_need_slm) {
1118 work_size.local[0] = XCAM_ALIGN_UP (out_gauss_desc.width, 16);
1119 work_size.local[1] = 1;
1120 work_size.global[0] = work_size.local[0];
1121 work_size.global[1] = workitem_height;
1122 } else {
1123 work_size.local[0] = 8;
1124 work_size.local[1] = 4;
1125 work_size.global[0] = XCAM_ALIGN_UP (out_gauss_desc.width, work_size.local[0]);
1126 work_size.global[1] = XCAM_ALIGN_UP (workitem_height, work_size.local[1]);
1127 }
1128
1129 return XCAM_RETURN_NO_ERROR;
1130 }
1131
CLPyramidLapKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,uint32_t buf_index,bool is_uv)1132 CLPyramidLapKernel::CLPyramidLapKernel (
1133 const SmartPtr<CLContext> &context,
1134 SmartPtr<CLPyramidBlender> &blender,
1135 uint32_t layer,
1136 uint32_t buf_index,
1137 bool is_uv)
1138 : CLImageKernel (context)
1139 , _blender (blender)
1140 , _layer (layer)
1141 , _buf_index (buf_index)
1142 , _is_uv (is_uv)
1143 {
1144 XCAM_ASSERT (layer <= XCAM_CL_PYRAMID_MAX_LEVEL);
1145 XCAM_ASSERT (buf_index <= XCAM_BLENDER_IMAGE_NUM);
1146 }
1147
1148 int32_t
get_cur_gauss_offset_x()1149 CLPyramidLapKernel::get_cur_gauss_offset_x ()
1150 {
1151 const PyramidLayer &layer = _blender->get_pyramid_layer (_layer);
1152 uint32_t plane_index = (_is_uv ? 1 : 0);
1153 return layer.gauss_offset_x[plane_index][_buf_index];
1154 }
1155
1156 int32_t
get_output_lap_offset_x()1157 CLPyramidLapKernel::get_output_lap_offset_x ()
1158 {
1159 const PyramidLayer &layer = _blender->get_pyramid_layer (_layer);
1160 uint32_t plane_index = (_is_uv ? 1 : 0);
1161 return layer.lap_offset_x[plane_index][_buf_index];
1162 }
1163
1164 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)1165 CLPyramidLapKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
1166 {
1167 SmartPtr<CLContext> context = get_context ();
1168
1169 SmartPtr<CLImage> cur_gauss_image = get_current_gauss();
1170 SmartPtr<CLImage> next_gauss_image_tmp = get_next_gauss();
1171 SmartPtr<CLImage> image_out_lap = get_output_lap ();
1172 const CLImageDesc &cl_desc_next_gauss_tmp = next_gauss_image_tmp->get_image_desc ();
1173 const CLImageDesc &cl_desc_out_lap = image_out_lap->get_image_desc ();
1174 float next_gauss_pixel_width = 0.0f, next_gauss_pixel_height = 0.0f;
1175
1176 CLImageDesc cl_desc_next_gauss;
1177 if (!_is_uv) {
1178 cl_desc_next_gauss.format.image_channel_data_type = CL_UNORM_INT8;
1179 cl_desc_next_gauss.format.image_channel_order = CL_R;
1180 cl_desc_next_gauss.width = cl_desc_next_gauss_tmp.width * 8;
1181 } else {
1182 cl_desc_next_gauss.format.image_channel_data_type = CL_UNORM_INT8;
1183 cl_desc_next_gauss.format.image_channel_order = CL_RG;
1184 cl_desc_next_gauss.width = cl_desc_next_gauss_tmp.width * 4;
1185 }
1186 cl_desc_next_gauss.height = cl_desc_next_gauss_tmp.height;
1187 cl_desc_next_gauss.row_pitch = cl_desc_next_gauss_tmp.row_pitch;
1188 SmartPtr<CLImage> next_gauss;
1189 change_image_format (context, next_gauss_image_tmp, next_gauss, cl_desc_next_gauss);
1190 XCAM_FAIL_RETURN (
1191 ERROR,
1192 next_gauss.ptr () && next_gauss->is_valid (),
1193 XCAM_RETURN_ERROR_CL,
1194 "CLPyramidTransformKernel change output gauss image format failed");
1195
1196 next_gauss_pixel_width = cl_desc_next_gauss.width;
1197 next_gauss_pixel_height = cl_desc_next_gauss.height;
1198
1199 // out format(current layer): CL_UNSIGNED_INT16 + CL_RGBA
1200 float out_width = CLImage::calculate_pixel_bytes (cl_desc_next_gauss.format) * cl_desc_next_gauss.width * 2.0f / 8.0f;
1201 float out_height = next_gauss_pixel_height * 2.0f;
1202 float sampler_offset_x = SAMPLER_POSITION_OFFSET / next_gauss_pixel_width;
1203 float sampler_offset_y = SAMPLER_POSITION_OFFSET / next_gauss_pixel_height;
1204
1205 int cur_gauss_offset_x = get_cur_gauss_offset_x () / 8;
1206 XCAM_ASSERT (cur_gauss_offset_x * 8 == get_cur_gauss_offset_x ());
1207 int lap_offset_x = get_output_lap_offset_x () / 8;
1208 XCAM_ASSERT (lap_offset_x * 8 == get_output_lap_offset_x ());
1209
1210 args.push_back (new CLMemArgument (cur_gauss_image));
1211 args.push_back (new CLArgumentT<int> (cur_gauss_offset_x));
1212 args.push_back (new CLMemArgument (next_gauss));
1213 args.push_back (new CLArgumentT<float> (sampler_offset_x));
1214 args.push_back (new CLArgumentT<float> (sampler_offset_y));
1215 args.push_back (new CLMemArgument (image_out_lap));
1216 args.push_back (new CLArgumentT<int> (lap_offset_x));
1217 args.push_back (new CLArgumentT<float> (out_width));
1218 args.push_back (new CLArgumentT<float> (out_height));
1219
1220 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
1221 work_size.local[0] = 8;
1222 work_size.local[1] = 4;
1223 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out_lap.width, work_size.local[0]);
1224 work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out_lap.height, work_size.local[1]);
1225
1226 return XCAM_RETURN_NO_ERROR;
1227 }
1228
CLPyramidReconstructKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,bool is_uv)1229 CLPyramidReconstructKernel::CLPyramidReconstructKernel (
1230 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender,
1231 uint32_t layer, bool is_uv)
1232 : CLImageKernel (context)
1233 , _blender (blender)
1234 , _layer (layer)
1235 , _is_uv (is_uv)
1236 {
1237 XCAM_ASSERT (layer <= XCAM_CL_PYRAMID_MAX_LEVEL);
1238 }
1239
1240 int
get_output_reconstrcut_offset_x()1241 CLPyramidReconstructKernel::get_output_reconstrcut_offset_x ()
1242 {
1243 if (_layer > 0)
1244 return 0;
1245 const Rect & window = _blender->get_merge_window ();
1246 XCAM_ASSERT (window.pos_x % XCAM_CL_BLENDER_ALIGNMENT_X == 0);
1247 return window.pos_x;
1248 }
1249
1250 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)1251 CLPyramidReconstructKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
1252 {
1253 SmartPtr<CLContext> context = get_context ();
1254
1255 SmartPtr<CLImage> image_in_reconst = get_input_reconstruct();
1256 SmartPtr<CLImage> image_in_lap = get_input_lap ();
1257 SmartPtr<CLImage> image_out_reconst = get_output_reconstruct();
1258 const CLImageDesc &cl_desc_in_reconst_pre = image_in_reconst->get_image_desc ();
1259 // out_desc should be same as image_in_lap
1260 const CLImageDesc &cl_desc_out_reconst = image_in_lap->get_image_desc (); // don't change
1261 float input_gauss_width = 0.0f, input_gauss_height = 0.0f;
1262
1263 CLImageDesc cl_desc_in_reconst;
1264 cl_desc_in_reconst.format.image_channel_data_type = CL_UNORM_INT8;
1265 if (_is_uv) {
1266 cl_desc_in_reconst.format.image_channel_order = CL_RG;
1267 cl_desc_in_reconst.width = cl_desc_in_reconst_pre.width * 4;
1268 } else {
1269 cl_desc_in_reconst.format.image_channel_order = CL_R;
1270 cl_desc_in_reconst.width = cl_desc_in_reconst_pre.width * 8;
1271 }
1272 cl_desc_in_reconst.height = cl_desc_in_reconst_pre.height;
1273 cl_desc_in_reconst.row_pitch = cl_desc_in_reconst_pre.row_pitch;
1274 SmartPtr<CLImage> input_reconstruct;
1275 change_image_format (context, image_in_reconst, input_reconstruct, cl_desc_in_reconst);
1276 XCAM_FAIL_RETURN (
1277 ERROR,
1278 input_reconstruct.ptr () && input_reconstruct->is_valid (),
1279 XCAM_RETURN_ERROR_CL,
1280 "CLPyramidTransformKernel change output gauss image format failed");
1281
1282 input_gauss_width = cl_desc_in_reconst.width;
1283 input_gauss_height = cl_desc_in_reconst.height;
1284
1285 float out_reconstruct_width = CLImage::calculate_pixel_bytes (cl_desc_in_reconst.format) * cl_desc_in_reconst.width * 2.0f / 8.0f;
1286 float out_reconstruct_height = input_gauss_height * 2.0f;
1287 float in_sampler_offset_x = SAMPLER_POSITION_OFFSET / input_gauss_width;
1288 float in_sampler_offset_y = SAMPLER_POSITION_OFFSET / input_gauss_height;
1289 int out_reconstruct_offset_x = 0;
1290
1291 if (_blender->get_scale_mode () == CLBlenderScaleLocal) {
1292 out_reconstruct_offset_x = 0;
1293 } else {
1294 out_reconstruct_offset_x = get_output_reconstrcut_offset_x () / 8;
1295 XCAM_ASSERT (out_reconstruct_offset_x * 8 == get_output_reconstrcut_offset_x ());
1296 }
1297
1298 args.push_back (new CLMemArgument (input_reconstruct));
1299 args.push_back (new CLArgumentT<float> (in_sampler_offset_x));
1300 args.push_back (new CLArgumentT<float> (in_sampler_offset_y));
1301 args.push_back (new CLMemArgument (image_in_lap));
1302 args.push_back (new CLMemArgument (image_out_reconst));
1303 args.push_back (new CLArgumentT<int> (out_reconstruct_offset_x));
1304 args.push_back (new CLArgumentT<float> (out_reconstruct_width));
1305 args.push_back (new CLArgumentT<float> (out_reconstruct_height));
1306
1307 #if CL_PYRAMID_ENABLE_DUMP
1308 int i_plane = (_is_uv ? 1 : 0);
1309 const PyramidLayer &cur_layer = _blender->get_pyramid_layer (_layer);
1310 SmartPtr<CLImage> dump_gauss_resize = cur_layer.dump_gauss_resize[i_plane];
1311 SmartPtr<CLImage> dump_final = cur_layer.dump_final[i_plane];
1312
1313 args.push_back (new CLMemArgument (dump_gauss_resize));
1314 args.push_back (new CLMemArgument (dump_final));
1315
1316 printf ("Rec%d: reconstruct_offset_x:%d, out_width:%.2f, out_height:%.2f, in_sampler_offset_x:%.2f, in_sampler_offset_y:%.2f\n",
1317 _layer, out_reconstruct_offset_x, out_reconstruct_width, out_reconstruct_height,
1318 in_sampler_offset_x, in_sampler_offset_y);
1319 #endif
1320
1321 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
1322 work_size.local[0] = 4;
1323 work_size.local[1] = 8;
1324 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out_reconst.width, work_size.local[0]);
1325 work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out_reconst.height, work_size.local[1]);
1326
1327 return XCAM_RETURN_NO_ERROR;
1328 }
1329
1330
1331 void
dump_buffers()1332 CLPyramidBlender::dump_buffers ()
1333 {
1334 static int frame_count = 0;
1335 SmartPtr<CLImage> image;
1336 ++frame_count;
1337
1338 // dump difference between original image and final image
1339 #if 0
1340 #define CM_NUM 3
1341 SmartPtr<CLImage> images[CM_NUM];
1342 const Rect & window = get_merge_window ();
1343 int offsets[3] = {window.pos_x, window.pos_x, 0};
1344 //right edge
1345 //int offsets[3] = {0 + window.width - 8, window.pos_x + window.width - 8, window.width - 8};
1346 size_t row_pitch[CM_NUM];
1347 size_t slice_pitch[CM_NUM];
1348 uint8_t *ptr[CM_NUM] = {NULL, NULL, NULL};
1349 uint32_t i = 0;
1350
1351 #if 1
1352 // Y
1353 // left edge
1354 images[0] = this->get_pyramid_layer (0).gauss_image[0][0];
1355 // right edge
1356 //images[0] = this->get_pyramid_layer (0).gauss_image[0][1];
1357 images[1] = this->get_pyramid_layer (0).blend_image[0][ReconstructImageIndex];
1358 images[2] = this->get_pyramid_layer (0).dump_final[0];
1359 #else
1360 // UV
1361 // left edge
1362 images[0] = this->get_pyramid_layer (0).gauss_image[1][0];
1363 // right edge
1364 //images[0] = this->get_pyramid_layer (0).gauss_image[1][1];
1365 images[1] = this->get_pyramid_layer (0).blend_image[1][ReconstructImageIndex];
1366 images[2] = this->get_pyramid_layer (0).dump_final[1];
1367 #endif
1368
1369 for (i = 0; i < CM_NUM; ++i) {
1370 const CLImageDesc &desc = images[i]->get_image_desc ();
1371 size_t origin[3] = {0, 0, 0};
1372 size_t region[3] = {desc.width, desc.height, 1};
1373 XCamReturn ret = images[i]->enqueue_map ((void *&)ptr[i], origin, region, &row_pitch[i], &slice_pitch[i], CL_MAP_READ);
1374 XCAM_ASSERT (ret == XCAM_RETURN_NO_ERROR);
1375 }
1376 // offset UV, workaround of beignet
1377 //offsets[0] += row_pitch[0] * 1088;
1378 //offsets[1] += row_pitch[1] * 1088;
1379
1380 printf ("layer 0(UV) comparison, original / final-image / reconstruct offset:%d, width:%d\n", window.pos_x, window.width);
1381 for (int ih = 250; ih < 280; ++ih) {
1382 uint8_t *lines[CM_NUM];
1383 for (i = 0; i < 2 /*CM_NUM*/; ++i) {
1384 uint8_t *l = (uint8_t *)ptr[i] + offsets[i] + row_pitch[i] * ih + 0;
1385 lines[i] = l;
1386 printf ("%02x%02x%02x%02x%02x%02x%02x%02x ", l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7]);
1387 }
1388 //printf differrence between original and final image
1389 printf ("delta(orig - final):");
1390 for (i = 0; i < 10; ++i) {
1391 printf ("%02x", (uint32_t)(lines[0][i] - lines[1][i]) & 0xFF);
1392 }
1393 printf ("\n");
1394 }
1395
1396 for (i = 0; i < CM_NUM; ++i) {
1397 images[i]->enqueue_unmap (ptr[i]);
1398 }
1399 #endif
1400
1401 #define DUMP_IMAGE(prefix, image, layer) \
1402 desc = (image)->get_image_desc (); \
1403 snprintf (filename, sizeof(filename), prefix "_L%d-%dx%d", \
1404 layer, (image)->get_pixel_bytes () * desc.width, desc.height); \
1405 dump_image (image, filename)
1406
1407 // dump image data to file
1408 CLImageDesc desc;
1409 char filename[1024];
1410
1411 image = this->get_image_diff ();
1412 if (image.ptr ()) {
1413 DUMP_IMAGE ("dump_image_diff", image, 0);
1414 }
1415
1416 for (uint32_t i_layer = 0; i_layer < get_layers (); ++i_layer) {
1417 //dump seam mask
1418 image = this->get_pyramid_layer(i_layer).seam_mask[CLSeamMaskTmp];
1419 if (image.ptr ()) {
1420 DUMP_IMAGE ("dump_seam_tmp", image, i_layer);
1421 }
1422
1423 image = this->get_pyramid_layer(i_layer).seam_mask[CLSeamMaskCoeff];
1424 if (image.ptr ()) {
1425 DUMP_IMAGE ("dump_seam_coeff", image, i_layer);
1426 }
1427
1428 image = this->get_blend_image (i_layer, false); // layer 1
1429 DUMP_IMAGE ("dump_blend", image, i_layer);
1430
1431 if (i_layer > 0) { //layer : [1, _layers -1]
1432 image = this->get_gauss_image (i_layer, 0, false);
1433 DUMP_IMAGE ("dump_gaussI0", image, i_layer);
1434 image = this->get_gauss_image (i_layer, 1, false);
1435 DUMP_IMAGE ("dump_gaussI1", image, i_layer);
1436 }
1437
1438 if (i_layer < get_layers () - 1) {
1439 image = this->get_lap_image (i_layer, 0, false); // layer : [0, _layers -2]
1440 DUMP_IMAGE ("dump_lap_I0", image, i_layer);
1441 }
1442 }
1443
1444 #if CL_PYRAMID_ENABLE_DUMP
1445 image = this->get_pyramid_layer (0).dump_gauss_resize[0];
1446 DUMP_IMAGE ("dump_gauss_resize", image, 0);
1447
1448 image = this->get_pyramid_layer (0).dump_original[0][0];
1449 DUMP_IMAGE ("dump_orginalI0", image, 0);
1450 image = this->get_pyramid_layer (0).dump_original[0][1];
1451 DUMP_IMAGE ("dump_orginalI1", image, 0);
1452
1453 image = this->get_pyramid_layer (0).dump_final[CLBlenderPlaneY];
1454 DUMP_IMAGE ("dump_final", image, 0);
1455 #endif
1456
1457 #if 0
1458 this->dump_layer_mask (0, false);
1459 this->dump_layer_mask (1, false);
1460
1461 //this->dump_layer_mask (0, true);
1462 //this->dump_layer_mask (1, true);
1463 #endif
1464
1465 }
1466
CLBlenderLocalScaleKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,bool is_uv)1467 CLBlenderLocalScaleKernel::CLBlenderLocalScaleKernel (
1468 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender, bool is_uv)
1469 : CLBlenderScaleKernel (context, is_uv)
1470 , _blender (blender)
1471 {
1472 }
1473
1474 SmartPtr<CLImage>
get_input_image()1475 CLBlenderLocalScaleKernel::get_input_image ()
1476 {
1477 SmartPtr<CLContext> context = get_context ();
1478
1479 SmartPtr<CLImage> rec_image = _blender->get_reconstruct_image (0, _is_uv);
1480 const CLImageDesc &rec_desc = rec_image->get_image_desc ();
1481
1482 CLImageDesc new_desc;
1483 new_desc.format.image_channel_data_type = CL_UNORM_INT8;
1484 if (_is_uv) {
1485 new_desc.format.image_channel_order = CL_RG;
1486 new_desc.width = rec_desc.width * 4;
1487 } else {
1488 new_desc.format.image_channel_order = CL_R;
1489 new_desc.width = rec_desc.width * 8;
1490 }
1491 new_desc.height = rec_desc.height;
1492 new_desc.row_pitch = rec_desc.row_pitch;
1493 SmartPtr<CLImage> new_image;
1494 change_image_format (context, rec_image, new_image, new_desc);
1495 XCAM_FAIL_RETURN (
1496 ERROR,
1497 new_image.ptr () && new_image->is_valid (),
1498 NULL,
1499 "CLBlenderLocalScaleKernel change image format failed");
1500
1501 _image_in = new_image;
1502 return new_image;
1503 }
1504
1505 SmartPtr<CLImage>
get_output_image()1506 CLBlenderLocalScaleKernel::get_output_image ()
1507 {
1508 return _blender->get_scale_image (_is_uv);
1509 }
1510
1511 bool
get_output_info(uint32_t & out_width,uint32_t & out_height,int & out_offset_x)1512 CLBlenderLocalScaleKernel::get_output_info (
1513 uint32_t &out_width, uint32_t &out_height, int &out_offset_x)
1514 {
1515 XCAM_ASSERT (_image_in.ptr ());
1516
1517 const Rect &window = _blender->get_merge_window ();
1518 const CLImageDesc &desc_in = _image_in->get_image_desc ();
1519
1520 out_width = window.width / 8;
1521 out_height = desc_in.height;
1522 out_offset_x = window.pos_x / 8;
1523
1524 XCAM_FAIL_RETURN (ERROR, out_width != 0, false, "get output info failed");
1525 return true;
1526 }
1527
CLPyramidCopyKernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t buf_index,bool is_uv)1528 CLPyramidCopyKernel::CLPyramidCopyKernel (
1529 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender,
1530 uint32_t buf_index, bool is_uv)
1531 : CLImageKernel (context)
1532 , _blender (blender)
1533 , _is_uv (is_uv)
1534 , _buf_index (buf_index)
1535 {
1536 }
1537
1538 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)1539 CLPyramidCopyKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
1540 {
1541 SmartPtr<CLContext> context = get_context ();
1542
1543 SmartPtr<CLImage> from = get_input ();
1544 SmartPtr<CLImage> to = get_output ();
1545
1546 const CLImageDesc &to_desc = to->get_image_desc ();
1547 const Rect &window = _blender->get_merge_window ();
1548 const Rect &input_area = _blender->get_input_valid_area (_buf_index);
1549 const Rect &merge_area = _blender->get_input_merge_area (_buf_index);
1550 int in_offset_x = 0;
1551 int out_offset_x = 0;
1552 int max_g_x = 0, max_g_y = 0;
1553
1554 if (_buf_index == 0) {
1555 in_offset_x = input_area.pos_x / 8;
1556 max_g_x = (merge_area.pos_x - input_area.pos_x) / 8;
1557 out_offset_x = window.pos_x / 8 - max_g_x;
1558 } else {
1559 in_offset_x = (merge_area.pos_x + merge_area.width) / 8;
1560 out_offset_x = (window.pos_x + window.width) / 8;
1561 max_g_x = (input_area.pos_x + input_area.width) / 8 - in_offset_x;
1562 }
1563 max_g_y = to_desc.height;
1564 XCAM_ASSERT (max_g_x > 0 && max_g_x <= (int)to_desc.width);
1565
1566 #if CL_PYRAMID_ENABLE_DUMP
1567 printf ("copy(%d), in_offset_x:%d, out_offset_x:%d, max_x:%d\n", _buf_index, in_offset_x, out_offset_x, max_g_x);
1568 #endif
1569
1570 args.push_back (new CLMemArgument (from));
1571 args.push_back (new CLArgumentT<int> (in_offset_x));
1572 args.push_back (new CLMemArgument (to));
1573 args.push_back (new CLArgumentT<int> (out_offset_x));
1574 args.push_back (new CLArgumentT<int> (max_g_x));
1575 args.push_back (new CLArgumentT<int> (max_g_y));
1576
1577 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
1578 work_size.local[0] = 16;
1579 work_size.local[1] = 4;
1580 work_size.global[0] = XCAM_ALIGN_UP (max_g_x, work_size.local[0]);
1581 work_size.global[1] = XCAM_ALIGN_UP (max_g_y, work_size.local[1]);
1582
1583 return XCAM_RETURN_NO_ERROR;
1584 }
1585
1586 static SmartPtr<CLImageKernel>
create_pyramid_transform_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,uint32_t buf_index,bool is_uv)1587 create_pyramid_transform_kernel (
1588 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender,
1589 uint32_t layer, uint32_t buf_index, bool is_uv)
1590 {
1591 char transform_option[1024];
1592 snprintf (
1593 transform_option, sizeof(transform_option),
1594 "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP);
1595
1596 SmartPtr<CLImageKernel> kernel;
1597 kernel = new CLPyramidTransformKernel (context, blender, layer, buf_index, is_uv);
1598 XCAM_ASSERT (kernel.ptr ());
1599 XCAM_FAIL_RETURN (
1600 ERROR,
1601 kernel->build_kernel (kernels_info[KernelPyramidTransform], transform_option) == XCAM_RETURN_NO_ERROR,
1602 NULL,
1603 "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y"));
1604 return kernel;
1605 }
1606
1607 static SmartPtr<CLImageKernel>
create_pyramid_lap_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,uint32_t buf_index,bool is_uv)1608 create_pyramid_lap_kernel (
1609 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender,
1610 uint32_t layer, uint32_t buf_index, bool is_uv)
1611 {
1612 char transform_option[1024];
1613 snprintf (
1614 transform_option, sizeof(transform_option),
1615 "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP);
1616
1617 SmartPtr<CLImageKernel> kernel;
1618 kernel = new CLPyramidLapKernel (context, blender, layer, buf_index, is_uv);
1619 XCAM_ASSERT (kernel.ptr ());
1620 XCAM_FAIL_RETURN (
1621 ERROR,
1622 kernel->build_kernel (kernels_info[KernelPyramidLap], transform_option) == XCAM_RETURN_NO_ERROR,
1623 NULL,
1624 "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y"));
1625 return kernel;
1626 }
1627
1628 static SmartPtr<CLImageKernel>
create_pyramid_reconstruct_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,bool is_uv)1629 create_pyramid_reconstruct_kernel (
1630 const SmartPtr<CLContext> &context,
1631 SmartPtr<CLPyramidBlender> &blender,
1632 uint32_t layer,
1633 bool is_uv)
1634 {
1635 char transform_option[1024];
1636 snprintf (
1637 transform_option, sizeof(transform_option),
1638 "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP);
1639
1640 SmartPtr<CLImageKernel> kernel;
1641 kernel = new CLPyramidReconstructKernel (context, blender, layer, is_uv);
1642 XCAM_ASSERT (kernel.ptr ());
1643 XCAM_FAIL_RETURN (
1644 ERROR,
1645 kernel->build_kernel (kernels_info[KernelPyramidReconstruct], transform_option) == XCAM_RETURN_NO_ERROR,
1646 NULL,
1647 "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y"));
1648 return kernel;
1649 }
1650
1651 static SmartPtr<CLImageKernel>
create_pyramid_blend_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,bool is_uv,bool need_seam)1652 create_pyramid_blend_kernel (
1653 const SmartPtr<CLContext> &context,
1654 SmartPtr<CLPyramidBlender> &blender,
1655 uint32_t layer,
1656 bool is_uv,
1657 bool need_seam)
1658 {
1659 char transform_option[1024];
1660 snprintf (
1661 transform_option, sizeof(transform_option),
1662 "-DPYRAMID_UV=%d -DCL_PYRAMID_ENABLE_DUMP=%d", (is_uv ? 1 : 0), CL_PYRAMID_ENABLE_DUMP);
1663
1664 SmartPtr<CLImageKernel> kernel;
1665 kernel = new CLPyramidBlendKernel (context, blender, layer, is_uv, need_seam);
1666 uint32_t index = KernelPyramidBlender;
1667 if (need_seam)
1668 index = KernelSeamBlender;
1669
1670 XCAM_ASSERT (kernel.ptr ());
1671 XCAM_FAIL_RETURN (
1672 ERROR,
1673 kernel->build_kernel (kernels_info[index], transform_option) == XCAM_RETURN_NO_ERROR,
1674 NULL,
1675 "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y"));
1676 return kernel;
1677 }
1678
1679 static SmartPtr<CLImageKernel>
create_pyramid_blender_local_scale_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,bool is_uv)1680 create_pyramid_blender_local_scale_kernel (
1681 const SmartPtr<CLContext> &context,
1682 SmartPtr<CLPyramidBlender> &blender,
1683 bool is_uv)
1684 {
1685 char transform_option[1024];
1686 snprintf (transform_option, sizeof(transform_option), "-DPYRAMID_UV=%d", is_uv ? 1 : 0);
1687
1688 SmartPtr<CLImageKernel> kernel;
1689 kernel = new CLBlenderLocalScaleKernel (context, blender, is_uv);
1690 XCAM_ASSERT (kernel.ptr ());
1691 XCAM_FAIL_RETURN (
1692 ERROR,
1693 kernel->build_kernel (kernels_info[KernelPyramidScale], transform_option) == XCAM_RETURN_NO_ERROR,
1694 NULL,
1695 "load pyramid blender local scaling kernel(%s) failed", is_uv ? "UV" : "Y");
1696 return kernel;
1697 }
1698
1699 static SmartPtr<CLImageKernel>
create_pyramid_copy_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t buf_index,bool is_uv)1700 create_pyramid_copy_kernel (
1701 const SmartPtr<CLContext> &context,
1702 SmartPtr<CLPyramidBlender> &blender,
1703 uint32_t buf_index,
1704 bool is_uv)
1705 {
1706 char transform_option[1024];
1707 snprintf (transform_option, sizeof(transform_option), "-DPYRAMID_UV=%d", (is_uv ? 1 : 0));
1708
1709 SmartPtr<CLImageKernel> kernel;
1710 kernel = new CLPyramidCopyKernel (context, blender, buf_index, is_uv);
1711 XCAM_ASSERT (kernel.ptr ());
1712 XCAM_FAIL_RETURN (
1713 ERROR,
1714 kernel->build_kernel (kernels_info[KernelPyramidCopy], transform_option) == XCAM_RETURN_NO_ERROR,
1715 NULL,
1716 "load pyramid blender kernel(%s) failed", (is_uv ? "UV" : "Y"));
1717 return kernel;
1718 }
1719
1720 static SmartPtr<CLImageKernel>
create_seam_diff_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender)1721 create_seam_diff_kernel (
1722 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender)
1723 {
1724 SmartPtr<CLImageKernel> kernel;
1725 kernel = new CLSeamDiffKernel (context, blender);
1726 XCAM_ASSERT (kernel.ptr ());
1727 XCAM_FAIL_RETURN (
1728 ERROR,
1729 kernel->build_kernel (kernels_info[KernelImageDiff], NULL) == XCAM_RETURN_NO_ERROR,
1730 NULL,
1731 "load seam diff kernel failed");
1732 return kernel;
1733 }
1734
1735 static SmartPtr<CLImageKernel>
create_seam_DP_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender)1736 create_seam_DP_kernel (
1737 const SmartPtr<CLContext> &context, SmartPtr<CLPyramidBlender> &blender)
1738 {
1739 SmartPtr<CLImageKernel> kernel;
1740 kernel = new CLSeamDPKernel (context, blender);
1741 XCAM_ASSERT (kernel.ptr ());
1742 XCAM_FAIL_RETURN (
1743 ERROR,
1744 kernel->build_kernel (kernels_info[KernelSeamDP], NULL) == XCAM_RETURN_NO_ERROR,
1745 NULL,
1746 "load seam DP kernel failed");
1747 return kernel;
1748 }
1749
1750 static SmartPtr<CLImageKernel>
create_seam_mask_scale_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLPyramidBlender> & blender,uint32_t layer,bool need_scale,bool need_slm)1751 create_seam_mask_scale_kernel (
1752 const SmartPtr<CLContext> &context,
1753 SmartPtr<CLPyramidBlender> &blender,
1754 uint32_t layer,
1755 bool need_scale,
1756 bool need_slm)
1757 {
1758 char build_option[1024];
1759 snprintf (build_option, sizeof(build_option), "-DENABLE_MASK_GAUSS_SCALE=%d", (need_scale ? 1 : 0));
1760 int kernel_idx = (need_slm ? KernelSeamMaskScaleSLM : KernelSeamMaskScale);
1761
1762 SmartPtr<CLImageKernel> kernel;
1763 kernel = new CLPyramidSeamMaskKernel (context, blender, layer, need_scale, need_slm);
1764 XCAM_ASSERT (kernel.ptr ());
1765 XCAM_FAIL_RETURN (
1766 ERROR,
1767 kernel->build_kernel (kernels_info[kernel_idx], build_option) == XCAM_RETURN_NO_ERROR,
1768 NULL,
1769 "load seam mask scale kernel failed");
1770 return kernel;
1771 }
1772
1773 SmartPtr<CLImageHandler>
create_pyramid_blender(const SmartPtr<CLContext> & context,int layer,bool need_uv,bool need_seam,CLBlenderScaleMode scale_mode)1774 create_pyramid_blender (
1775 const SmartPtr<CLContext> &context, int layer, bool need_uv,
1776 bool need_seam, CLBlenderScaleMode scale_mode)
1777 {
1778 SmartPtr<CLPyramidBlender> blender;
1779 SmartPtr<CLImageKernel> kernel;
1780 int i = 0;
1781 uint32_t buf_index = 0;
1782 int max_plane = (need_uv ? 2 : 1);
1783 bool uv_status[2] = {false, true};
1784
1785 XCAM_FAIL_RETURN (
1786 ERROR,
1787 layer > 0 && layer <= XCAM_CL_PYRAMID_MAX_LEVEL,
1788 NULL,
1789 "create_pyramid_blender failed with wrong layer:%d, please set it between %d and %d",
1790 layer, 1, XCAM_CL_PYRAMID_MAX_LEVEL);
1791
1792 blender = new CLPyramidBlender (context, "cl_pyramid_blender", layer, need_uv, need_seam, scale_mode);
1793 XCAM_ASSERT (blender.ptr ());
1794
1795 if (need_seam) {
1796 kernel = create_seam_diff_kernel (context, blender);
1797 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create seam diff kernel failed");
1798 blender->add_kernel (kernel);
1799
1800 kernel = create_seam_DP_kernel (context, blender);
1801 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create seam DP kernel failed");
1802 blender->add_kernel (kernel);
1803
1804 for (i = 0; i < layer; ++i) {
1805 bool need_scale = (i < layer - 1);
1806 bool need_slm = (i == 0);
1807 kernel = create_seam_mask_scale_kernel (context, blender, (uint32_t)i, need_scale, need_slm);
1808 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create seam mask scale kernel failed");
1809 blender->add_kernel (kernel);
1810 }
1811 }
1812
1813 for (int plane = 0; plane < max_plane; ++plane) {
1814 for (buf_index = 0; buf_index < XCAM_BLENDER_IMAGE_NUM; ++buf_index) {
1815 for (i = 0; i < layer - 1; ++i) {
1816 kernel = create_pyramid_transform_kernel (context, blender, (uint32_t)i, buf_index, uv_status[plane]);
1817 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid transform kernel failed");
1818 blender->add_kernel (kernel);
1819
1820 kernel = create_pyramid_lap_kernel (context, blender, (uint32_t)i, buf_index, uv_status[plane]);
1821 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid lap transform kernel failed");
1822 blender->add_kernel (kernel);
1823 }
1824 }
1825
1826 for (i = 0; i < layer; ++i) {
1827 kernel = create_pyramid_blend_kernel (context, blender, (uint32_t)i, uv_status[plane], need_seam);
1828 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid blend kernel failed");
1829 blender->add_kernel (kernel);
1830 }
1831
1832 for (i = layer - 2; i >= 0 && i < layer; --i) {
1833 kernel = create_pyramid_reconstruct_kernel (context, blender, (uint32_t)i, uv_status[plane]);
1834 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid reconstruct kernel failed");
1835 blender->add_kernel (kernel);
1836 }
1837
1838 if (scale_mode == CLBlenderScaleLocal) {
1839 kernel = create_pyramid_blender_local_scale_kernel (context, blender, uv_status[plane]);
1840 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid blender local scaling kernel failed");
1841 blender->add_kernel (kernel);
1842 }
1843
1844 for (buf_index = 0; buf_index < XCAM_BLENDER_IMAGE_NUM; ++buf_index) {
1845 kernel = create_pyramid_copy_kernel (context, blender, buf_index, uv_status[plane]);
1846 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create pyramid copy kernel failed");
1847 blender->add_kernel (kernel);
1848 }
1849 }
1850
1851 return blender;
1852 }
1853
1854 }
1855