1 /*
2 * soft_blender.cpp - soft blender class implementation
3 *
4 * Copyright (c) 2017 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 "soft_blender.h"
22 #include "xcam_utils.h"
23 #include "soft_image.h"
24 #include "soft_worker.h"
25 #include "soft_blender_tasks_priv.h"
26 #include "image_file_handle.h"
27 #include "soft_video_buf_allocator.h"
28 #include <map>
29
30 #define OVERLAP_POOL_SIZE 6
31 #define LAP_POOL_SIZE 4
32
33 #define DUMP_BLENDER 0
34
35 namespace XCam {
36
37 using namespace XCamSoftTasks;
38
39 DECLARE_WORK_CALLBACK (CbGaussDownScale, SoftBlender, gauss_scale_done);
40 DECLARE_WORK_CALLBACK (CbBlendTask, SoftBlender, blend_task_done);
41 DECLARE_WORK_CALLBACK (CbReconstructTask, SoftBlender, reconstruct_done);
42 DECLARE_WORK_CALLBACK (CbLapTask, SoftBlender, lap_done);
43
44 typedef std::map<void*, SmartPtr<BlendTask::Args>> MapBlendArgs;
45 typedef std::map<void*, SmartPtr<ReconstructTask::Args>> MapReconsArgs;
46
47 namespace SoftBlenderPriv {
48
49 struct PyramidResource {
50 SmartPtr<BufferPool> overlap_pool;
51 SmartPtr<GaussDownScale> scale_task[SoftBlender::BufIdxCount];
52 SmartPtr<LaplaceTask> lap_task[SoftBlender::BufIdxCount];
53 SmartPtr<ReconstructTask> recon_task;
54 SmartPtr<UcharImage> coef_mask;
55 MapReconsArgs recons_args;
56 };
57
58 /* Level0: G[0] = gauss(in), Lap[0] = in - upsample(G[0])
59 Level1: G[1] = gauss(G[0]), Lap[1] = G[0] - upsample(G[1])
60 ..
61 LevelN: G[N] = gauss(G[N-1]),
62 blend[N] = blend (Ga[N)], Gb[N)])
63 Level(N-1): Reconst[N-1] = reconstruct (blend[N], LapA[N-1], LapB[N-1])
64 ...
65 Level1: reconst[1] = reconstruct (reconst[2], LapA[1], LapB[1])
66 Level0: output = reconstruct (reconst[1], LapA[0], LapB[0])
67
68 LevelN: Pool[N].size = G[N].size
69 */
70 class BlenderPrivConfig {
71 public:
72 PyramidResource pyr_layer[XCAM_SOFT_PYRAMID_MAX_LEVEL];
73 uint32_t pyr_levels;
74 SmartPtr<BlendTask> last_level_blend;
75 SmartPtr<BufferPool> first_lap_pool;
76 SmartPtr<UcharImage> orig_mask;
77
78 Mutex map_args_mutex;
79 MapBlendArgs blend_args;
80
81 private:
82 SoftBlender *_blender;
83
84 public:
BlenderPrivConfig(SoftBlender * blender,uint32_t level)85 BlenderPrivConfig (SoftBlender *blender, uint32_t level)
86 : pyr_levels (level)
87 , _blender (blender)
88 {}
89
90 XCamReturn init_first_masks (uint32_t width, uint32_t height);
91 XCamReturn scale_down_masks (uint32_t level, uint32_t width, uint32_t height);
92
93 XCamReturn start_scaler (
94 const SmartPtr<ImageHandler::Parameters> ¶m,
95 const SmartPtr<VideoBuffer> &in_buf,
96 const uint32_t level, const SoftBlender::BufIdx idx);
97
98 XCamReturn start_lap_task (
99 const SmartPtr<ImageHandler::Parameters> ¶m,
100 const uint32_t level, const SoftBlender::BufIdx idx,
101 const SmartPtr<GaussDownScale::Args> &scale_args);
102 XCamReturn start_blend_task (
103 const SmartPtr<ImageHandler::Parameters> ¶m,
104 const SmartPtr<VideoBuffer> &buf,
105 const SoftBlender::BufIdx idx);
106
107 XCamReturn start_reconstruct_task_by_lap (
108 const SmartPtr<ImageHandler::Parameters> ¶m,
109 const SmartPtr<VideoBuffer> &lap,
110 const uint32_t level, const SoftBlender::BufIdx idx);
111 XCamReturn start_reconstruct_task_by_gauss (
112 const SmartPtr<ImageHandler::Parameters> ¶m,
113 const SmartPtr<VideoBuffer> &gauss,
114 const uint32_t level);
115 XCamReturn start_reconstruct_task (const SmartPtr<ReconstructTask::Args> &args, const uint32_t level);
116 XCamReturn stop ();
117 };
118
119 };
120
121 #if DUMP_BLENDER
122 #define dump_buf dump_buf_perfix_path
123
124 template <class SoftImageT>
125 static void
dump_soft(const SmartPtr<SoftImageT> & image,const char * name,int32_t level)126 dump_soft (const SmartPtr<SoftImageT> &image, const char *name, int32_t level)
127 {
128 XCAM_ASSERT (image.ptr ());
129 char file_name[256];
130 if (level < 0)
131 snprintf (file_name, 256, "%s-%dx%d.soft", name, image->get_width(), image->get_height());
132 else
133 snprintf (file_name, 256, "%s-L%d-%dx%d.soft", name, level, image->get_width(), image->get_height());
134
135 #if 0
136 typename SoftImageT::Type *ptr = image->get_buf_ptr (0, 0);
137 printf ("Print level:%d, line:0\n", level);
138 for (uint32_t i = 0; i < image->get_width (); ++i) {
139 printf ("%.1f ", (float)(ptr[i]));
140 }
141 printf ("\n");
142 #endif
143
144 SoftImageFile<SoftImageT> file(file_name, "wb");
145 file.write_buf (image);
146 file.close ();
147 }
148
149 static
dump_level_buf(const SmartPtr<VideoBuffer> buf,const char * name,uint32_t level,uint32_t idx)150 void dump_level_buf (const SmartPtr<VideoBuffer> buf, const char *name, uint32_t level, uint32_t idx)
151 {
152 char file_name[256];
153 XCAM_ASSERT (name);
154 snprintf (file_name, 256, "%s-L%d-Idx%d", name, level, idx);
155 dump_buf_perfix_path (buf, file_name);
156 }
157 #else
dump_buf(const SmartPtr<VideoBuffer> buf,...)158 static void dump_buf (const SmartPtr<VideoBuffer> buf, ...) {
159 XCAM_UNUSED (buf);
160 }
161 template <class SoftImageT>
dump_soft(const SmartPtr<SoftImageT> & image,...)162 static void dump_soft (const SmartPtr<SoftImageT> &image, ...) {
163 XCAM_UNUSED (image);
164 }
dump_level_buf(const SmartPtr<VideoBuffer> buf,...)165 static void dump_level_buf (const SmartPtr<VideoBuffer> buf, ...) {
166 XCAM_UNUSED (buf);
167 }
168 #endif
169
SoftBlender(const char * name)170 SoftBlender::SoftBlender (const char *name)
171 : SoftHandler (name)
172 , Blender (SOFT_BLENDER_ALIGNMENT_X, SOFT_BLENDER_ALIGNMENT_Y)
173 {
174 _priv_config = new SoftBlenderPriv::BlenderPrivConfig (this, XCAM_SOFT_PYRAMID_DEFAULT_LEVEL);
175 XCAM_ASSERT (_priv_config.ptr ());
176 }
177
~SoftBlender()178 SoftBlender::~SoftBlender ()
179 {
180 }
181
182 bool
set_pyr_levels(uint32_t num)183 SoftBlender::set_pyr_levels (uint32_t num)
184 {
185 XCAM_ASSERT (num > 0);
186 XCAM_FAIL_RETURN (
187 ERROR, num > 0, false,
188 "blender:%s set_pyr_levels failed, level(%d) must > 0", XCAM_STR (get_name ()), num);
189
190 _priv_config->pyr_levels = num;
191 return true;
192 }
193
194 XCamReturn
terminate()195 SoftBlender::terminate ()
196 {
197 _priv_config->stop ();
198 return SoftHandler::terminate ();
199 }
200
201 XCamReturn
blend(const SmartPtr<VideoBuffer> & in0,const SmartPtr<VideoBuffer> & in1,SmartPtr<VideoBuffer> & out_buf)202 SoftBlender::blend (
203 const SmartPtr<VideoBuffer> &in0,
204 const SmartPtr<VideoBuffer> &in1,
205 SmartPtr<VideoBuffer> &out_buf)
206 {
207 SmartPtr<BlenderParam> param = new BlenderParam (in0, in1, out_buf);
208 XCamReturn ret = execute_buffer (param, true);
209 if (xcam_ret_is_ok(ret) && !out_buf.ptr ()) {
210 out_buf = param->out_buf;
211 }
212 return ret;
213 }
214
215 XCamReturn
stop()216 SoftBlenderPriv::BlenderPrivConfig::stop ()
217 {
218 for (uint32_t i = 0; i < pyr_levels; ++i) {
219 if (pyr_layer[i].scale_task[SoftBlender::Idx0].ptr ()) {
220 pyr_layer[i].scale_task[SoftBlender::Idx0]->stop ();
221 pyr_layer[i].scale_task[SoftBlender::Idx0].release ();
222 }
223 if (pyr_layer[i].scale_task[SoftBlender::Idx1].ptr ()) {
224 pyr_layer[i].scale_task[SoftBlender::Idx1]->stop ();
225 pyr_layer[i].scale_task[SoftBlender::Idx1].release ();
226 }
227 if (pyr_layer[i].lap_task[SoftBlender::Idx0].ptr ()) {
228 pyr_layer[i].lap_task[SoftBlender::Idx0]->stop ();
229 pyr_layer[i].lap_task[SoftBlender::Idx0].release ();
230 }
231 if (pyr_layer[i].lap_task[SoftBlender::Idx1].ptr ()) {
232 pyr_layer[i].lap_task[SoftBlender::Idx1]->stop ();
233 pyr_layer[i].lap_task[SoftBlender::Idx0].release ();
234 }
235 if (pyr_layer[i].recon_task.ptr ()) {
236 pyr_layer[i].recon_task->stop ();
237 pyr_layer[i].recon_task.release ();
238 }
239
240 if (pyr_layer[i].overlap_pool.ptr ()) {
241 pyr_layer[i].overlap_pool->stop ();
242 }
243 }
244
245 if (last_level_blend.ptr ()) {
246 last_level_blend->stop ();
247 last_level_blend.release ();
248 }
249 return XCAM_RETURN_NO_ERROR;
250 }
251
252 XCamReturn
init_first_masks(uint32_t width,uint32_t height)253 SoftBlenderPriv::BlenderPrivConfig::init_first_masks (uint32_t width, uint32_t height)
254 {
255 uint32_t aligned_width = XCAM_ALIGN_UP (width, SOFT_BLENDER_ALIGNMENT_X);
256
257 orig_mask = new UcharImage (
258 width, height, aligned_width);
259 XCAM_ASSERT (orig_mask.ptr ());
260 XCAM_ASSERT (orig_mask->is_valid ());
261 std::vector<float> gauss_table;
262 std::vector<Uchar> mask_line;
263 uint32_t i = 0, j = 0;
264
265 uint32_t quater = width / 4;
266 XCAM_ASSERT (quater > 1);
267 get_gauss_table (quater, (quater + 1) / 4.0f, gauss_table, false);
268 for (i = 0; i < gauss_table.size (); ++i) {
269 float value = ((i < quater) ? (128.0f * (2.0f - gauss_table[i])) : (128.0f * gauss_table[i]));
270 value = XCAM_CLAMP (value, 0.0f, 255.0f);
271 gauss_table[i] = value;
272 }
273
274 mask_line.resize (aligned_width);
275 uint32_t gauss_start_pos = (width - gauss_table.size ()) / 2;
276 for (i = 0; i < gauss_start_pos; ++i) {
277 mask_line[i] = 255;
278 }
279 for (j = 0; j < gauss_table.size (); ++i, ++j) {
280 mask_line[i] = (Uchar)gauss_table[j];
281 }
282 for (; i < mask_line.size (); ++i) {
283 mask_line[i] = 0;
284 }
285
286 for (uint32_t h = 0; h < height; ++h) {
287 Uchar *ptr = orig_mask->get_buf_ptr (0, h);
288 memcpy (ptr, mask_line.data (), aligned_width);
289 }
290
291 dump_soft (orig_mask, "mask_orig", -1);
292
293 return XCAM_RETURN_NO_ERROR;
294 }
295
296 XCamReturn
scale_down_masks(uint32_t level,uint32_t width,uint32_t height)297 SoftBlenderPriv::BlenderPrivConfig::scale_down_masks (uint32_t level, uint32_t width, uint32_t height)
298 {
299 XCAM_ASSERT (width % SOFT_BLENDER_ALIGNMENT_X == 0);
300 XCAM_ASSERT (height % SOFT_BLENDER_ALIGNMENT_Y == 0);
301
302 pyr_layer[level].coef_mask = new UcharImage (width, height);
303 XCAM_ASSERT (pyr_layer[level].coef_mask.ptr ());
304
305 SmartPtr<GaussScaleGray::Args> args = new GaussScaleGray::Args;
306 if (level == 0) {
307 args->in_luma = orig_mask;
308 } else {
309 args->in_luma = pyr_layer[level - 1].coef_mask;
310 }
311 args->out_luma = pyr_layer[level].coef_mask;
312 SmartPtr<GaussScaleGray> worker = new GaussScaleGray;
313 WorkSize size ((args->out_luma->get_width () + 1) / 2, (args->out_luma->get_height () + 1) / 2);
314 worker->set_local_size (size);
315 worker->set_global_size (size);
316 XCamReturn ret = worker->work (args);
317
318 dump_soft (pyr_layer[level].coef_mask, "mask", (int32_t)level);
319 return ret;
320 }
321
322 XCamReturn
start_scaler(const SmartPtr<ImageHandler::Parameters> & param,const SmartPtr<VideoBuffer> & in_buf,const uint32_t level,const SoftBlender::BufIdx idx)323 SoftBlenderPriv::BlenderPrivConfig::start_scaler (
324 const SmartPtr<ImageHandler::Parameters> ¶m,
325 const SmartPtr<VideoBuffer> &in_buf,
326 const uint32_t level, const SoftBlender::BufIdx idx)
327 {
328 XCAM_ASSERT (level < pyr_levels);
329 XCAM_ASSERT (idx < SoftBlender::BufIdxCount);
330 SmartPtr<SoftWorker> worker = pyr_layer[level].scale_task[idx];
331 XCAM_ASSERT (worker.ptr ());
332
333 XCAM_ASSERT (pyr_layer[level].overlap_pool.ptr ());
334 SmartPtr<VideoBuffer> out_buf = pyr_layer[level].overlap_pool->get_buffer ();
335 XCAM_FAIL_RETURN (
336 ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
337 "blender:(%s) start_scaler failed, level(%d),idx(%d) get output buffer empty.",
338 XCAM_STR (_blender->get_name ()), level, (int)idx);
339
340 SmartPtr<GaussDownScale::Args> args = new GaussDownScale::Args (param, level, idx, in_buf, out_buf);
341 if (level == 0) {
342 Rect in_area = _blender->get_input_merge_area (idx);
343 const VideoBufferInfo &buf_info = in_buf->get_video_info ();
344 if (in_area.width == 0 || in_area.height == 0) {
345 in_area.width = buf_info.width;
346 in_area.height = buf_info.height;
347 }
348 XCAM_ASSERT (in_area.pos_x % SOFT_BLENDER_ALIGNMENT_X == 0);
349 XCAM_ASSERT (in_area.pos_y % SOFT_BLENDER_ALIGNMENT_Y == 0);
350 args->in_luma = new UcharImage (
351 in_buf, in_area.width, in_area.height, buf_info.strides[0],
352 buf_info.offsets[0] + in_area.pos_x + in_area.pos_y * buf_info.strides[0]);
353 args->in_uv = new Uchar2Image (
354 in_buf, in_area.width / 2, in_area.height / 2, buf_info.strides[1],
355 buf_info.offsets[1] + in_area.pos_x + buf_info.strides[1] * in_area.pos_y / 2);
356 } else {
357 args->in_luma = new UcharImage (in_buf, 0);
358 args->in_uv = new Uchar2Image (in_buf, 1);
359 }
360 args->out_luma = new UcharImage (out_buf, 0);
361 args->out_uv = new Uchar2Image (out_buf, 1);
362
363 XCAM_ASSERT (out_buf->get_video_info ().width % 2 == 0 && out_buf->get_video_info ().height % 2 == 0);
364
365 uint32_t thread_x = 2, thread_y = 2;
366 WorkSize work_unit = worker->get_work_uint ();
367 WorkSize global_size (
368 xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0],
369 xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]);
370 WorkSize local_size (
371 xcam_ceil(global_size.value[0], thread_x) / thread_x ,
372 xcam_ceil(global_size.value[1], thread_y) / thread_y);
373
374 worker->set_local_size (local_size);
375 worker->set_global_size (global_size);
376
377 return worker->work (args);
378 }
379
380 XCamReturn
start_lap_task(const SmartPtr<ImageHandler::Parameters> & param,const uint32_t level,const SoftBlender::BufIdx idx,const SmartPtr<GaussDownScale::Args> & scale_args)381 SoftBlenderPriv::BlenderPrivConfig::start_lap_task (
382 const SmartPtr<ImageHandler::Parameters> ¶m,
383 const uint32_t level, const SoftBlender::BufIdx idx,
384 const SmartPtr<GaussDownScale::Args> &scale_args)
385 {
386 XCAM_ASSERT (level < pyr_levels);
387 XCAM_ASSERT (idx < SoftBlender::BufIdxCount);
388 SmartPtr<VideoBuffer> gauss = scale_args->out_buf;
389
390 SmartPtr<VideoBuffer> out_buf;
391 if (level == 0) {
392 XCAM_ASSERT (first_lap_pool.ptr ());
393 out_buf = first_lap_pool->get_buffer ();
394 } else {
395 XCAM_ASSERT (pyr_layer[level - 1].overlap_pool.ptr ());
396 out_buf = pyr_layer[level - 1].overlap_pool->get_buffer ();
397 }
398
399 XCAM_FAIL_RETURN (
400 ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
401 "blender:(%s) start_lap_task failed, level(%d),idx(%d) get output buffer empty.",
402 XCAM_STR (_blender->get_name ()), level, (int)idx);
403
404 SmartPtr<LaplaceTask::Args> args = new LaplaceTask::Args (param, level, idx, out_buf);
405 args->orig_luma = scale_args->in_luma;//new UcharImage (orig, 0);
406 args->orig_uv = scale_args->in_uv; //new Uchar2Image (orig, 1);
407 args->gauss_luma = new UcharImage (gauss, 0);
408 args->gauss_uv = new Uchar2Image (gauss, 1);
409 args->out_luma = new UcharImage (out_buf, 0);
410 args->out_uv = new Uchar2Image (out_buf, 1);
411
412 SmartPtr<SoftWorker> worker = pyr_layer[level].lap_task[idx];
413 XCAM_ASSERT (worker.ptr ());
414
415 uint32_t thread_x = 2, thread_y = 2;
416 WorkSize work_unit = worker->get_work_uint ();
417 WorkSize global_size (
418 xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0],
419 xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]);
420 WorkSize local_size (
421 xcam_ceil(global_size.value[0], thread_x) / thread_x ,
422 xcam_ceil(global_size.value[1], thread_y) / thread_y);
423
424
425 worker->set_local_size (local_size);
426 worker->set_global_size (global_size);
427
428 return worker->work (args);
429 }
430
431 XCamReturn
start_blend_task(const SmartPtr<ImageHandler::Parameters> & param,const SmartPtr<VideoBuffer> & buf,const SoftBlender::BufIdx idx)432 SoftBlenderPriv::BlenderPrivConfig::start_blend_task (
433 const SmartPtr<ImageHandler::Parameters> ¶m,
434 const SmartPtr<VideoBuffer> &buf,
435 const SoftBlender::BufIdx idx)
436 {
437
438 SmartPtr<BlendTask::Args> args;
439 uint32_t last_level = pyr_levels - 1;
440
441 {
442 SmartLock locker (map_args_mutex);
443 MapBlendArgs::iterator i = blend_args.find (param.ptr ());
444 if (i == blend_args.end ()) {
445 args = new BlendTask::Args (param, pyr_layer[last_level].coef_mask);
446 XCAM_ASSERT (args.ptr ());
447 blend_args.insert (std::make_pair((void*)param.ptr (), args));
448 XCAM_LOG_DEBUG ("soft_blender:%s init blender args", XCAM_STR (_blender->get_name ()));
449 } else {
450 args = (*i).second;
451 }
452 args->in_luma[idx] = new UcharImage (buf, 0);
453 args->in_uv[idx] = new Uchar2Image (buf, 1);
454 XCAM_ASSERT (args->in_luma[idx].ptr () && args->in_uv[idx].ptr ());
455
456 if (!args->in_luma[SoftBlender::Idx0].ptr () || !args->in_luma[SoftBlender::Idx1].ptr ())
457 return XCAM_RETURN_BYPASS;
458
459 blend_args.erase (i);
460 }
461
462 XCAM_ASSERT (args.ptr ());
463 XCAM_ASSERT (args->in_luma[SoftBlender::Idx0]->get_width () == args->in_luma[SoftBlender::Idx1]->get_width ());
464
465 XCAM_ASSERT (pyr_layer[last_level].overlap_pool.ptr ());
466 SmartPtr<VideoBuffer> out_buf = pyr_layer[last_level].overlap_pool->get_buffer ();
467 XCAM_FAIL_RETURN (
468 ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
469 "blender:(%s) start_blend_task failed, last level blend buffer empty.",
470 XCAM_STR (_blender->get_name ()), (int)idx);
471 args->out_luma = new UcharImage (out_buf, 0);
472 args->out_uv = new Uchar2Image (out_buf, 1);
473 args->out_buf = out_buf;
474
475 // process 4x1 uv each loop
476 SmartPtr<SoftWorker> worker = last_level_blend;
477 XCAM_ASSERT (worker.ptr ());
478
479 uint32_t thread_x = 2, thread_y = 2;
480 WorkSize work_unit = worker->get_work_uint ();
481 WorkSize global_size (
482 xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0],
483 xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]);
484 WorkSize local_size (
485 xcam_ceil (global_size.value[0], thread_x) / thread_x,
486 xcam_ceil (global_size.value[1], thread_y) / thread_y);
487
488 worker->set_local_size (local_size);
489 worker->set_global_size (global_size);
490
491 return worker->work (args);
492 }
493
494 XCamReturn
start_reconstruct_task(const SmartPtr<ReconstructTask::Args> & args,const uint32_t level)495 SoftBlenderPriv::BlenderPrivConfig::start_reconstruct_task (
496 const SmartPtr<ReconstructTask::Args> &args, const uint32_t level)
497 {
498 XCAM_ASSERT (args.ptr ());
499 XCAM_ASSERT (args->lap_luma[SoftBlender::Idx0].ptr () && args->lap_luma[SoftBlender::Idx1].ptr () && args->gauss_luma.ptr ());
500 XCAM_ASSERT (args->lap_luma[SoftBlender::Idx0]->get_width () == args->lap_luma[SoftBlender::Idx1]->get_width ());
501 SmartPtr<VideoBuffer> out_buf;
502 if (level == 0) {
503 out_buf = args->get_param ()->out_buf;
504 XCAM_ASSERT (out_buf.ptr ());
505 args->mask = orig_mask;
506
507 Rect out_area = _blender->get_merge_window ();
508 const VideoBufferInfo &out_info = out_buf->get_video_info ();
509 if (out_area.width == 0 || out_area.height == 0) {
510 out_area.width = out_info.width;
511 out_area.height = out_info.height;
512 }
513 XCAM_ASSERT (out_area.pos_x % SOFT_BLENDER_ALIGNMENT_X == 0);
514 XCAM_ASSERT (out_area.pos_y % SOFT_BLENDER_ALIGNMENT_Y == 0);
515 args->out_luma = new UcharImage (
516 out_buf, out_area.width, out_area.height, out_info.strides[0],
517 out_info.offsets[0] + out_area.pos_x + out_area.pos_y * out_info.strides[0]);
518 args->out_uv = new Uchar2Image (
519 out_buf, out_area.width / 2, out_area.height / 2, out_info.strides[1],
520 out_info.offsets[1] + out_area.pos_x + out_area.pos_y / 2 * out_info.strides[1]);
521 } else {
522 out_buf = pyr_layer[level - 1].overlap_pool->get_buffer ();
523 XCAM_FAIL_RETURN (
524 ERROR, out_buf.ptr (), XCAM_RETURN_ERROR_MEM,
525 "blender:(%s) start_reconstruct_task failed, out buffer is empty.", XCAM_STR (_blender->get_name ()));
526 args->mask = pyr_layer[level - 1].coef_mask;
527 args->out_luma = new UcharImage (out_buf, 0);
528 args->out_uv = new Uchar2Image (out_buf, 1);
529 }
530
531 args->out_buf = out_buf;
532
533 SmartPtr<SoftWorker> worker = pyr_layer[level].recon_task;
534 XCAM_ASSERT (worker.ptr ());
535
536 uint32_t thread_x = 2, thread_y = 2;
537 WorkSize work_unit = worker->get_work_uint ();
538 WorkSize global_size (
539 xcam_ceil (args->out_luma->get_width (), work_unit.value[0]) / work_unit.value[0],
540 xcam_ceil (args->out_luma->get_height (), work_unit.value[1]) / work_unit.value[1]);
541 WorkSize local_size (
542 xcam_ceil (global_size.value[0], thread_x) / thread_x,
543 xcam_ceil (global_size.value[1], thread_y) / thread_y);
544
545 worker->set_local_size (local_size);
546 worker->set_global_size (global_size);
547
548 return worker->work (args);
549 }
550
551 XCamReturn
start_reconstruct_task_by_gauss(const SmartPtr<ImageHandler::Parameters> & param,const SmartPtr<VideoBuffer> & gauss,const uint32_t level)552 SoftBlenderPriv::BlenderPrivConfig::start_reconstruct_task_by_gauss (
553 const SmartPtr<ImageHandler::Parameters> ¶m,
554 const SmartPtr<VideoBuffer> &gauss,
555 const uint32_t level)
556 {
557 SmartPtr<ReconstructTask::Args> args;
558 {
559 SmartLock locker (map_args_mutex);
560 MapReconsArgs::iterator i = pyr_layer[level].recons_args.find (param.ptr ());
561 if (i == pyr_layer[level].recons_args.end ()) {
562 args = new ReconstructTask::Args (param, level);
563 XCAM_ASSERT (args.ptr ());
564 pyr_layer[level].recons_args.insert (std::make_pair((void*)param.ptr (), args));
565 XCAM_LOG_DEBUG ("soft_blender:%s init recons_args level(%d)", XCAM_STR (_blender->get_name ()), level);
566 } else {
567 args = (*i).second;
568 }
569 args->gauss_luma = new UcharImage (gauss, 0);
570 args->gauss_uv = new Uchar2Image (gauss, 1);
571 XCAM_ASSERT (args->gauss_luma.ptr () && args->gauss_uv.ptr ());
572
573 if (!args->lap_luma[SoftBlender::Idx0].ptr () || !args->lap_luma[SoftBlender::Idx1].ptr ())
574 return XCAM_RETURN_BYPASS;
575
576 pyr_layer[level].recons_args.erase (i);
577 }
578
579 return start_reconstruct_task (args, level);
580 }
581
582 XCamReturn
start_reconstruct_task_by_lap(const SmartPtr<ImageHandler::Parameters> & param,const SmartPtr<VideoBuffer> & lap,const uint32_t level,const SoftBlender::BufIdx idx)583 SoftBlenderPriv::BlenderPrivConfig::start_reconstruct_task_by_lap (
584 const SmartPtr<ImageHandler::Parameters> ¶m,
585 const SmartPtr<VideoBuffer> &lap,
586 const uint32_t level,
587 const SoftBlender::BufIdx idx)
588 {
589 SmartPtr<ReconstructTask::Args> args;
590 {
591 SmartLock locker (map_args_mutex);
592 MapReconsArgs::iterator i = pyr_layer[level].recons_args.find (param.ptr ());
593 if (i == pyr_layer[level].recons_args.end ()) {
594 args = new ReconstructTask::Args (param, level);
595 XCAM_ASSERT (args.ptr ());
596 pyr_layer[level].recons_args.insert (std::make_pair((void*)param.ptr (), args));
597 XCAM_LOG_DEBUG ("soft_blender:%s init recons_args level(%d)", XCAM_STR (_blender->get_name ()), level);
598 } else {
599 args = (*i).second;
600 }
601 args->lap_luma[idx] = new UcharImage (lap, 0);
602 args->lap_uv[idx] = new Uchar2Image (lap, 1);
603 XCAM_ASSERT (args->lap_luma[idx].ptr () && args->lap_uv[idx].ptr ());
604
605 if (!args->gauss_luma.ptr () || !args->lap_luma[SoftBlender::Idx0].ptr () ||
606 !args->lap_luma[SoftBlender::Idx1].ptr ())
607 return XCAM_RETURN_BYPASS;
608
609 pyr_layer[level].recons_args.erase (i);
610 }
611
612 return start_reconstruct_task (args, level);
613 }
614
615 XCamReturn
start_work(const SmartPtr<ImageHandler::Parameters> & base)616 SoftBlender::start_work (const SmartPtr<ImageHandler::Parameters> &base)
617 {
618 XCamReturn ret = XCAM_RETURN_NO_ERROR;
619 SmartPtr<BlenderParam> param = base.dynamic_cast_ptr<BlenderParam> ();
620
621 XCAM_FAIL_RETURN (
622 ERROR, param.ptr () && param->in1_buf.ptr () && param->out_buf.ptr (), XCAM_RETURN_ERROR_PARAM,
623 "blender:%s start_work failed, params(in1/out buf) are not fully set or type not correct",
624 XCAM_STR (get_name ()));
625
626 //start gauss scale level0: idx0
627 ret = _priv_config->start_scaler (param, param->in_buf, 0, Idx0);
628 XCAM_FAIL_RETURN (
629 ERROR, xcam_ret_is_ok (ret), ret,
630 "blender:%s start_work failed on idx0", XCAM_STR (get_name ()));
631
632 //start gauss scale level0: idx1
633 ret = _priv_config->start_scaler (param, param->in1_buf, 0, Idx1);
634 XCAM_FAIL_RETURN (
635 ERROR, xcam_ret_is_ok (ret), ret,
636 "blender:%s start_work failed on idx1", XCAM_STR (get_name ()));
637
638 //param->in_buf.release ();
639 //param->in1_buf.release ();
640
641 return ret;
642 };
643
644 XCamReturn
configure_resource(const SmartPtr<Parameters> & param)645 SoftBlender::configure_resource (const SmartPtr<Parameters> ¶m)
646 {
647 XCAM_ASSERT (_priv_config->pyr_levels <= XCAM_SOFT_PYRAMID_MAX_LEVEL);
648 const VideoBufferInfo &in0_info = param->in_buf->get_video_info ();
649 XCAM_FAIL_RETURN (
650 ERROR, in0_info.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
651 "blender:%s only support format(NV12) but input format is %s",
652 XCAM_STR(get_name ()), xcam_fourcc_to_string (in0_info.format));
653
654 Rect in0_area, in1_area, out_area;
655 in0_area = get_input_merge_area (Idx0);
656 in1_area = get_input_merge_area (Idx1);
657 out_area = get_merge_window ();
658 XCAM_FAIL_RETURN (
659 ERROR,
660 in0_area.width == in1_area.width && in1_area.width == out_area.width &&
661 in0_area.height == in1_area.height && in1_area.height == out_area.height,
662 XCAM_RETURN_ERROR_PARAM,
663 "blender:%s input/output overlap area was not same. in0(w:%d,h:%d), in1(w:%d,h:%d), out(w:%d,h:%d)",
664 XCAM_STR(get_name ()), in0_area.width, in0_area.height,
665 in1_area.width, in1_area.height, out_area.width, out_area.height);
666
667 VideoBufferInfo out_info;
668 uint32_t out_width(0), out_height(0);
669 get_output_size (out_width, out_height);
670 XCAM_FAIL_RETURN (
671 ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
672 "blender:%s output size was not set", XCAM_STR(get_name ()));
673
674 out_info.init (
675 in0_info.format, out_width, out_height,
676 XCAM_ALIGN_UP (out_width, SOFT_BLENDER_ALIGNMENT_X), XCAM_ALIGN_UP (out_height, SOFT_BLENDER_ALIGNMENT_Y));
677 set_out_video_info (out_info);
678
679 VideoBufferInfo overlap_info;
680 Rect merge_size = get_merge_window ();
681 //overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
682 XCAM_ASSERT (merge_size.width % SOFT_BLENDER_ALIGNMENT_X == 0);
683
684 overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
685 _priv_config->first_lap_pool = new SoftVideoBufAllocator (overlap_info);
686 XCAM_FAIL_RETURN (
687 ERROR, _priv_config->first_lap_pool->reserve (LAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
688 "blender:%s reserve lap buffer pool(w:%d,h:%d) failed",
689 XCAM_STR(get_name ()), overlap_info.width, overlap_info.height);
690
691 SmartPtr<Worker::Callback> gauss_scale_cb = new CbGaussDownScale (this);
692 SmartPtr<Worker::Callback> lap_cb = new CbLapTask (this);
693 SmartPtr<Worker::Callback> reconst_cb = new CbReconstructTask (this);
694 XCAM_ASSERT (gauss_scale_cb.ptr () && lap_cb.ptr () && reconst_cb.ptr ());
695
696 XCamReturn ret = _priv_config->init_first_masks (merge_size.width, merge_size.height);
697 XCAM_FAIL_RETURN (
698 ERROR, xcam_ret_is_ok (ret), ret,
699 "blender:%s init masks failed", XCAM_STR (get_name ()));
700
701 for (uint32_t i = 0; i < _priv_config->pyr_levels; ++i) {
702 merge_size.width = XCAM_ALIGN_UP ((merge_size.width + 1) / 2, SOFT_BLENDER_ALIGNMENT_X);
703 merge_size.height = XCAM_ALIGN_UP ((merge_size.height + 1) / 2, SOFT_BLENDER_ALIGNMENT_Y);
704 overlap_info.init (in0_info.format, merge_size.width, merge_size.height);
705
706 _priv_config->pyr_layer[i].overlap_pool = new SoftVideoBufAllocator (overlap_info);
707 XCAM_ASSERT (_priv_config->pyr_layer[i].overlap_pool.ptr ());
708 XCAM_FAIL_RETURN (
709 ERROR, _priv_config->pyr_layer[i].overlap_pool->reserve (OVERLAP_POOL_SIZE), XCAM_RETURN_ERROR_MEM,
710 "blender:%s reserve buffer pool(w:%d,h:%d) failed",
711 XCAM_STR(get_name ()), overlap_info.width, overlap_info.height);
712
713 ret = _priv_config->scale_down_masks (i, merge_size.width, merge_size.height);
714 XCAM_FAIL_RETURN (
715 ERROR, xcam_ret_is_ok (ret), ret,
716 "blender:(%s) first time scale coeff mask failed. level:%d", XCAM_STR (get_name ()), i);
717
718 _priv_config->pyr_layer[i].scale_task[SoftBlender::Idx0] = new GaussDownScale (gauss_scale_cb);
719 XCAM_ASSERT (_priv_config->pyr_layer[i].scale_task[SoftBlender::Idx0].ptr ());
720 _priv_config->pyr_layer[i].scale_task[SoftBlender::Idx1] = new GaussDownScale (gauss_scale_cb);
721 XCAM_ASSERT (_priv_config->pyr_layer[i].scale_task[SoftBlender::Idx1].ptr ());
722 _priv_config->pyr_layer[i].lap_task[SoftBlender::Idx0] = new LaplaceTask (lap_cb);
723 XCAM_ASSERT (_priv_config->pyr_layer[i].lap_task[SoftBlender::Idx0].ptr ());
724 _priv_config->pyr_layer[i].lap_task[SoftBlender::Idx1] = new LaplaceTask (lap_cb);
725 XCAM_ASSERT (_priv_config->pyr_layer[i].lap_task[SoftBlender::Idx1].ptr ());
726 _priv_config->pyr_layer[i].recon_task = new ReconstructTask (reconst_cb);
727 XCAM_ASSERT (_priv_config->pyr_layer[i].recon_task.ptr ());
728 }
729
730 _priv_config->last_level_blend = new BlendTask (new CbBlendTask (this));
731 XCAM_ASSERT (_priv_config->last_level_blend.ptr ());
732
733 return XCAM_RETURN_NO_ERROR;
734 }
735
736 void
gauss_scale_done(const SmartPtr<Worker> & worker,const SmartPtr<Worker::Arguments> & base,const XCamReturn error)737 SoftBlender::gauss_scale_done (
738 const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
739 {
740 XCAM_UNUSED (worker);
741
742 XCamReturn ret = XCAM_RETURN_NO_ERROR;
743 SmartPtr<GaussDownScale::Args> args = base.dynamic_cast_ptr<GaussDownScale::Args> ();
744 XCAM_ASSERT (args.ptr ());
745 const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
746 uint32_t level = args->level;
747 BufIdx idx = args->idx;
748 uint32_t next_level = level + 1;
749
750 XCAM_ASSERT (param.ptr ());
751 XCAM_ASSERT (level < _priv_config->pyr_levels);
752
753 if (!check_work_continue (param, error))
754 return;
755
756 dump_level_buf (args->out_buf, "gauss-scale", level, idx);
757
758 ret = _priv_config->start_lap_task (param, level, idx, args);//args->in_buf, args->out_buf);
759 if (!xcam_ret_is_ok (ret)) {
760 work_broken (param, ret);
761 }
762
763 if (next_level == _priv_config->pyr_levels) { // last level
764 ret = _priv_config->start_blend_task (param, args->out_buf, idx);
765 } else {
766 ret = _priv_config->start_scaler (param, args->out_buf, next_level, idx);
767 }
768
769 if (!xcam_ret_is_ok (ret)) {
770 work_broken (param, ret);
771 }
772 }
773
774 void
lap_done(const SmartPtr<Worker> & worker,const SmartPtr<Worker::Arguments> & base,const XCamReturn error)775 SoftBlender::lap_done (
776 const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
777 {
778 XCAM_UNUSED (worker);
779
780 XCamReturn ret = XCAM_RETURN_NO_ERROR;
781 SmartPtr<LaplaceTask::Args> args = base.dynamic_cast_ptr<LaplaceTask::Args> ();
782 XCAM_ASSERT (args.ptr ());
783 const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
784 XCAM_ASSERT (param.ptr ());
785 uint32_t level = args->level;
786 BufIdx idx = args->idx;
787 XCAM_ASSERT (level < _priv_config->pyr_levels);
788
789 if (!check_work_continue (param, error))
790 return;
791
792 dump_level_buf (args->out_buf, "lap", level, idx);
793
794 ret = _priv_config->start_reconstruct_task_by_lap (param, args->out_buf, level, idx);
795
796 if (!xcam_ret_is_ok (ret)) {
797 work_broken (param, ret);
798 }
799 }
800
801 void
blend_task_done(const SmartPtr<Worker> & worker,const SmartPtr<Worker::Arguments> & base,const XCamReturn error)802 SoftBlender::blend_task_done (
803 const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
804 {
805 XCAM_UNUSED (worker);
806
807 XCamReturn ret = XCAM_RETURN_NO_ERROR;
808 SmartPtr<BlendTask::Args> args = base.dynamic_cast_ptr<BlendTask::Args> ();
809 XCAM_ASSERT (args.ptr ());
810 const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
811 XCAM_ASSERT (param.ptr ());
812
813 if (!check_work_continue (param, error))
814 return;
815
816 dump_buf (args->out_buf, "blend-last");
817 ret = _priv_config->start_reconstruct_task_by_gauss (param, args->out_buf, _priv_config->pyr_levels - 1);
818
819 if (!xcam_ret_is_ok (ret)) {
820 work_broken (param, ret);
821 }
822 }
823
824 void
reconstruct_done(const SmartPtr<Worker> & worker,const SmartPtr<Worker::Arguments> & base,const XCamReturn error)825 SoftBlender::reconstruct_done (
826 const SmartPtr<Worker> &worker, const SmartPtr<Worker::Arguments> &base, const XCamReturn error)
827 {
828 XCAM_UNUSED (worker);
829
830 XCamReturn ret = XCAM_RETURN_NO_ERROR;
831 SmartPtr<ReconstructTask::Args> args = base.dynamic_cast_ptr<ReconstructTask::Args> ();
832 XCAM_ASSERT (args.ptr ());
833 const SmartPtr<ImageHandler::Parameters> param = args->get_param ();
834 XCAM_ASSERT (param.ptr ());
835 uint32_t level = args->level;
836 XCAM_ASSERT (level < _priv_config->pyr_levels);
837
838 if (!check_work_continue (param, error))
839 return;
840
841 dump_level_buf (args->out_buf, "reconstruct", level, 0);
842
843 if (level == 0) {
844 work_well_done (param, error);
845 return;
846 }
847
848 ret = _priv_config->start_reconstruct_task_by_gauss (param, args->out_buf, level - 1);
849 if (!xcam_ret_is_ok (ret)) {
850 work_broken (param, ret);
851 }
852 }
853
854 SmartPtr<SoftHandler>
create_soft_blender()855 create_soft_blender ()
856 {
857 SmartPtr<SoftBlender> blender = new SoftBlender();
858 XCAM_ASSERT (blender.ptr ());
859 return blender;
860 }
861
862 SmartPtr<Blender>
create_soft_blender()863 Blender::create_soft_blender ()
864 {
865 SmartPtr<SoftHandler> handler = XCam::create_soft_blender ();
866 return handler.dynamic_cast_ptr<Blender> ();
867 }
868
869 }
870