Home | History | Annotate | Download | only in soft
      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 (at) 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:
     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
    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
    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
    158 static void dump_buf (const SmartPtr<VideoBuffer> buf, ...) {
    159     XCAM_UNUSED (buf);
    160 }
    161 template <class SoftImageT>
    162 static void dump_soft (const SmartPtr<SoftImageT> &image, ...) {
    163     XCAM_UNUSED (image);
    164 }
    165 static void dump_level_buf (const SmartPtr<VideoBuffer> buf, ...) {
    166     XCAM_UNUSED (buf);
    167 }
    168 #endif
    169 
    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 
    178 SoftBlender::~SoftBlender ()
    179 {
    180 }
    181 
    182 bool
    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
    195 SoftBlender::terminate ()
    196 {
    197     _priv_config->stop ();
    198     return SoftHandler::terminate ();
    199 }
    200 
    201 XCamReturn
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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>
    855 create_soft_blender ()
    856 {
    857     SmartPtr<SoftBlender> blender = new SoftBlender();
    858     XCAM_ASSERT (blender.ptr ());
    859     return blender;
    860 }
    861 
    862 SmartPtr<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