/* * cl_bayer_basic_handler.cpp - CL bayer basic handler * * Copyright (c) 2015 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: Wind Yuan */ #include "cl_utils.h" #include "cl_bayer_basic_handler.h" #include "xcam_thread.h" #define GROUP_CELL_X_SIZE 64 #define GROUP_CELL_Y_SIZE 4 #define STATS_3A_CELL_X_SIZE 8 #define STATS_3A_CELL_Y_SIZE GROUP_CELL_Y_SIZE #define STANDARD_3A_STATS_SIZE 8 #define ENABLE_IMAGE_2D_INPUT 0 namespace XCam { static const XCamKernelInfo kernel_bayer_basic_info = { "kernel_bayer_basic", #include "kernel_bayer_basic.clx" , 0, }; struct BayerPostData { SmartPtr image_buffer; SmartPtr stats_cl_buf; }; class CLBayer3AStatsThread : public Thread { public: CLBayer3AStatsThread (CLBayerBasicImageHandler *handler) : Thread ("CLBayer3AStatsThread") , _handler (handler) {} ~CLBayer3AStatsThread () {} virtual bool emit_stop (); bool queue_stats (SmartPtr &buf, SmartPtr &stats); SmartPtr pop_buf (); protected: virtual bool loop (); virtual void stopped (); private: CLBayerBasicImageHandler *_handler; SafeList _stats_process_list; SafeList _buffer_done_list; }; bool CLBayer3AStatsThread::emit_stop () { _stats_process_list.pause_pop (); _buffer_done_list.pause_pop (); _stats_process_list.wakeup (); _buffer_done_list.wakeup (); return Thread::emit_stop (); } bool CLBayer3AStatsThread::queue_stats (SmartPtr &buf, SmartPtr &stats) { XCAM_FAIL_RETURN ( WARNING, buf.ptr () && stats.ptr (), false, "cl bayer 3a-stats thread has error buffer/stats to queue"); SmartPtr data = new BayerPostData; XCAM_ASSERT (data.ptr ()); data->image_buffer = buf; data->stats_cl_buf = stats; return _stats_process_list.push (data); } SmartPtr CLBayer3AStatsThread::pop_buf () { return _buffer_done_list.pop (); } void CLBayer3AStatsThread::stopped () { _stats_process_list.clear (); _buffer_done_list.clear (); } bool CLBayer3AStatsThread::loop () { XCamReturn ret = XCAM_RETURN_NO_ERROR; SmartPtr data; data = _stats_process_list.pop (); if (!data.ptr ()) { XCAM_LOG_INFO ("cl bayer 3a-stats thread is going to stop, processing data empty"); return false; } XCAM_ASSERT (data->image_buffer.ptr ()); XCAM_ASSERT (data->stats_cl_buf.ptr ()); XCAM_ASSERT (_handler); ret = _handler->process_stats_buffer (data->image_buffer, data->stats_cl_buf); XCAM_FAIL_RETURN ( WARNING, ret == XCAM_RETURN_NO_ERROR, false, "cl bayer 3a-stats thread has error buffer on kernel post processing"); XCAM_FAIL_RETURN ( ERROR, _buffer_done_list.push (data->image_buffer), false, "cl bayer 3a-stats thread failed to queue done-buffers"); return true; } CLBayerBasicImageKernel::CLBayerBasicImageKernel (const SmartPtr &context) : CLImageKernel (context, "kernel_bayer_basic") { } XCamReturn CLBayerBasicImageHandler::process_stats_buffer (SmartPtr &buffer, SmartPtr &cl_stats) { SmartPtr stats_3a; SmartPtr context = get_context (); XCAM_OBJ_PROFILING_START; context->finish (); stats_3a = _3a_stats_context->copy_stats_out (cl_stats); if (!stats_3a.ptr ()) { XCAM_LOG_DEBUG ("copy 3a stats failed, maybe handler stopped"); return XCAM_RETURN_ERROR_CL; } stats_3a->set_timestamp (buffer->get_timestamp ()); buffer->attach_buffer (stats_3a); if (cl_stats.ptr ()) _3a_stats_context->release_buffer (cl_stats); XCAM_OBJ_PROFILING_END ("3a_stats_cpu_copy(async)", XCAM_OBJ_DUR_FRAME_NUM); return post_stats (stats_3a); } CLBayerBasicImageHandler::CLBayerBasicImageHandler ( const SmartPtr &context, const char *name) : CLImageHandler (context, name) , _is_first_buf (true) { _blc_config.level_gr = XCAM_CL_BLC_DEFAULT_LEVEL; _blc_config.level_r = XCAM_CL_BLC_DEFAULT_LEVEL; _blc_config.level_b = XCAM_CL_BLC_DEFAULT_LEVEL; _blc_config.level_gb = XCAM_CL_BLC_DEFAULT_LEVEL; _blc_config.color_bits = 10; _wb_config.r_gain = 1.0; _wb_config.gr_gain = 1.0; _wb_config.gb_gain = 1.0; _wb_config.b_gain = 1.0; for(int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++) _gamma_table[i] = (float)i / 256.0f; _gamma_table[XCAM_GAMMA_TABLE_SIZE] = 0.9999f; _3a_stats_context = new CL3AStatsCalculatorContext (context); XCAM_ASSERT (_3a_stats_context.ptr ()); _3a_stats_thread = new CLBayer3AStatsThread (this); XCAM_ASSERT (_3a_stats_thread.ptr ()); XCAM_OBJ_PROFILING_INIT; } CLBayerBasicImageHandler::~CLBayerBasicImageHandler () { _3a_stats_thread->stop (); _3a_stats_context->clean_up_data (); } void CLBayerBasicImageHandler::set_stats_bits (uint32_t stats_bits) { XCAM_ASSERT (_3a_stats_context.ptr ()); _3a_stats_context->set_bit_depth (stats_bits); } bool CLBayerBasicImageHandler::set_bayer_kernel (SmartPtr &kernel) { SmartPtr image_kernel = kernel; add_kernel (image_kernel); _bayer_kernel = kernel; return true; } bool CLBayerBasicImageHandler::set_blc_config (const XCam3aResultBlackLevel &blc) { _blc_config.level_r = (float)blc.r_level; _blc_config.level_gr = (float)blc.gr_level; _blc_config.level_gb = (float)blc.gb_level; _blc_config.level_b = (float)blc.b_level; //_blc_config.color_bits = 0; return true; } bool CLBayerBasicImageHandler::set_wb_config (const XCam3aResultWhiteBalance &wb) { _wb_config.r_gain = (float)wb.r_gain; _wb_config.gr_gain = (float)wb.gr_gain; _wb_config.gb_gain = (float)wb.gb_gain; _wb_config.b_gain = (float)wb.b_gain; return true; } bool CLBayerBasicImageHandler::set_gamma_table (const XCam3aResultGammaTable &gamma) { for(int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++) _gamma_table[i] = (float)gamma.table[i] / 256.0f; return true; } void CLBayerBasicImageHandler::emit_stop () { _3a_stats_context->pre_stop (); _3a_stats_thread->emit_stop (); } XCamReturn CLBayerBasicImageHandler::prepare_buffer_pool_video_info ( const VideoBufferInfo &input, VideoBufferInfo &output) { uint32_t format = XCAM_PIX_FMT_SGRBG16_planar; bool format_inited = output.init (format, input.width / 2 , input.height / 2); XCAM_FAIL_RETURN ( WARNING, format_inited, XCAM_RETURN_ERROR_PARAM, "CL image handler(%s) output format(%s) unsupported", get_name (), xcam_fourcc_to_string (format)); return XCAM_RETURN_NO_ERROR; } XCamReturn CLBayerBasicImageHandler::prepare_parameters ( SmartPtr &input, SmartPtr &output) { SmartPtr context = get_context (); const VideoBufferInfo & in_video_info = input->get_video_info (); const VideoBufferInfo & out_video_info = output->get_video_info (); CLImageDesc in_image_info; CLImageDesc out_image_info; CLArgList args; CLWorkSize work_size; XCAM_ASSERT (_bayer_kernel.ptr ()); if (!_3a_stats_context->is_ready () && !_3a_stats_context->allocate_data ( in_video_info, STANDARD_3A_STATS_SIZE / STATS_3A_CELL_X_SIZE, STANDARD_3A_STATS_SIZE / STATS_3A_CELL_Y_SIZE)) { XCAM_LOG_WARNING ("CL3AStatsCalculatorContext allocate data failed"); return XCAM_RETURN_ERROR_MEM; } if (_is_first_buf) { XCAM_FAIL_RETURN ( WARNING, _3a_stats_thread->start (), XCAM_RETURN_ERROR_THREAD, "cl bayer basic handler start 3a stats thread failed"); } in_image_info.format.image_channel_order = CL_RGBA; in_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; //CL_UNORM_INT16; in_image_info.width = in_video_info.aligned_width / 8; in_image_info.height = in_video_info.height; in_image_info.row_pitch = in_video_info.strides[0]; out_image_info.format.image_channel_order = CL_RGBA; out_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; //CL_UNORM_INT16; out_image_info.width = out_video_info.width / 8; out_image_info.height = out_video_info.aligned_height * 4; out_image_info.row_pitch = out_video_info.strides[0]; #if ENABLE_IMAGE_2D_INPUT SmartPtr image_in = convert_to_climage (context, input, in_image_info); #else SmartPtr buffer_in = convert_to_clbuffer (context, input); #endif uint32_t input_aligned_width = in_video_info.strides[0] / (2 * 8); // ushort8 SmartPtr image_out = convert_to_climage (context, output, out_image_info); uint32_t out_aligned_height = out_video_info.aligned_height; _blc_config.color_bits = in_video_info.color_bits; SmartPtr gamma_table_buffer = new CLBuffer( context, sizeof(float) * (XCAM_GAMMA_TABLE_SIZE + 1), CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_gamma_table); _stats_cl_buffer = _3a_stats_context->get_buffer (); XCAM_FAIL_RETURN ( WARNING, _stats_cl_buffer.ptr () && _stats_cl_buffer->is_valid (), XCAM_RETURN_ERROR_PARAM, "CLBayerBasic handler get 3a stats buffer failed"); XCAM_FAIL_RETURN ( WARNING, image_out->is_valid (), XCAM_RETURN_ERROR_MEM, "cl image handler(%s) out memory not available", XCAM_STR(get_name ())); //set args; #if ENABLE_IMAGE_2D_INPUT args.push_back (new CLMemArgument (image_in)); #else args.push_back (new CLMemArgument (buffer_in)); #endif args.push_back (new CLArgumentT (input_aligned_width)); args.push_back (new CLMemArgument (image_out)); args.push_back (new CLArgumentT (out_aligned_height)); args.push_back (new CLArgumentT (_blc_config)); args.push_back (new CLArgumentT (_wb_config)); args.push_back (new CLMemArgument (gamma_table_buffer)); args.push_back (new CLMemArgument (_stats_cl_buffer)); work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.local[0] = 16; work_size.local[1] = 2; work_size.global[0] = XCAM_ALIGN_UP(out_video_info.width, GROUP_CELL_X_SIZE) / GROUP_CELL_X_SIZE * work_size.local[0]; work_size.global[1] = XCAM_ALIGN_UP(out_video_info.aligned_height, GROUP_CELL_Y_SIZE) / GROUP_CELL_Y_SIZE * work_size.local[1]; //printf ("work_size:g(%d, %d), l(%d, %d)\n", work_size.global[0], work_size.global[1], work_size.local[0], work_size.local[1]); XCAM_ASSERT (_bayer_kernel.ptr ()); XCamReturn ret = _bayer_kernel->set_arguments (args, work_size); XCAM_FAIL_RETURN ( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "bayer basic kernel set arguments failed."); return XCAM_RETURN_NO_ERROR; } XCamReturn CLBayerBasicImageHandler::execute_done (SmartPtr &output) { XCAM_FAIL_RETURN ( ERROR, _3a_stats_thread->queue_stats (output, _stats_cl_buffer), XCAM_RETURN_ERROR_UNKNOWN, "cl bayer basic handler(%s) process 3a stats failed", XCAM_STR (get_name ())); _stats_cl_buffer.release (); if (_is_first_buf) { _is_first_buf = false; return XCAM_RETURN_BYPASS; } SmartPtr done_buf = _3a_stats_thread->pop_buf (); XCAM_FAIL_RETURN ( WARNING, done_buf.ptr (), XCAM_RETURN_ERROR_MEM, "cl bayer handler(%s) failed to get done buffer", get_name ()); output = done_buf; return XCAM_RETURN_NO_ERROR; } XCamReturn CLBayerBasicImageHandler::post_stats (const SmartPtr &stats) { if (_stats_callback.ptr ()) return _stats_callback->x3a_stats_ready (stats); return XCAM_RETURN_NO_ERROR; } SmartPtr create_cl_bayer_basic_image_handler (const SmartPtr &context, bool enable_gamma, uint32_t stats_bits) { SmartPtr bayer_planar_handler; SmartPtr basic_kernel; char build_options[1024]; bayer_planar_handler = new CLBayerBasicImageHandler (context, "cl_handler_bayer_basic"); bayer_planar_handler->set_stats_bits (stats_bits); basic_kernel = new CLBayerBasicImageKernel (context); XCAM_ASSERT (basic_kernel.ptr ()); xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DENABLE_GAMMA=%d " " -DENABLE_IMAGE_2D_INPUT=%d " " -DSTATS_BITS=%d ", (enable_gamma ? 1 : 0), ENABLE_IMAGE_2D_INPUT, stats_bits); XCAM_FAIL_RETURN ( ERROR, basic_kernel->build_kernel (kernel_bayer_basic_info, build_options) == XCAM_RETURN_NO_ERROR, NULL, "build bayer-basic kernel(%s) failed", kernel_bayer_basic_info.kernel_name); XCAM_ASSERT (basic_kernel->is_valid ()); bayer_planar_handler->set_bayer_kernel (basic_kernel); return bayer_planar_handler; } };