• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &param,
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> &param,
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> &param,
104         const SmartPtr<VideoBuffer> &buf,
105         const SoftBlender::BufIdx idx);
106 
107     XCamReturn start_reconstruct_task_by_lap (
108         const SmartPtr<ImageHandler::Parameters> &param,
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> &param,
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> &param,
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> &param,
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> &param,
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> &param,
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> &param,
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> &param)
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