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> ¶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 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> ¶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 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 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 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> ¶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 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 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> ¶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 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