1 /* 2 * cl_image_processor.cpp - CL image processor 3 * 4 * Copyright (c) 2015 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 #include "cl_image_processor.h" 21 #include "cl_context.h" 22 #include "cl_device.h" 23 #include "cl_image_handler.h" 24 #include "cl_demo_handler.h" 25 #include "xcam_thread.h" 26 27 namespace XCam { 28 29 class CLHandlerThread 30 : public Thread 31 { 32 public: 33 CLHandlerThread (CLImageProcessor *processor) 34 : Thread ("CLHandlerThread") 35 , _processor (processor) 36 {} 37 ~CLHandlerThread () {} 38 39 virtual bool loop (); 40 41 private: 42 CLImageProcessor *_processor; 43 }; 44 45 bool CLHandlerThread::loop () 46 { 47 XCAM_ASSERT (_processor); 48 XCamReturn ret = _processor->process_cl_buffer_queue (); 49 if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) 50 return false; 51 return true; 52 } 53 54 class CLBufferNotifyThread 55 : public Thread 56 { 57 public: 58 CLBufferNotifyThread (CLImageProcessor *processor) 59 : Thread ("CLBufNtfThrd") 60 , _processor (processor) 61 {} 62 ~CLBufferNotifyThread () {} 63 64 virtual bool loop (); 65 66 private: 67 CLImageProcessor *_processor; 68 }; 69 70 bool CLBufferNotifyThread::loop () 71 { 72 XCAM_ASSERT (_processor); 73 XCamReturn ret = _processor->process_done_buffer (); 74 if (ret < XCAM_RETURN_NO_ERROR) 75 return false; 76 return true; 77 } 78 CLImageProcessor::CLImageProcessor (const char* name) 79 : ImageProcessor (name ? name : "CLImageProcessor") 80 , _seq_num (0) 81 , _keep_attached_buffer (false) 82 { 83 _context = CLDevice::instance ()->get_context (); 84 XCAM_ASSERT (_context.ptr()); 85 86 _handler_thread = new CLHandlerThread (this); 87 XCAM_ASSERT (_handler_thread.ptr ()); 88 89 _done_buf_thread = new CLBufferNotifyThread (this); 90 XCAM_ASSERT (_done_buf_thread.ptr ()); 91 92 XCAM_LOG_DEBUG ("CLImageProcessor constructed"); 93 XCAM_OBJ_PROFILING_INIT; 94 } 95 96 CLImageProcessor::~CLImageProcessor () 97 { 98 XCAM_LOG_DEBUG ("CLImageProcessor destructed"); 99 } 100 101 void 102 CLImageProcessor::keep_attached_buf(bool flag) 103 { 104 _keep_attached_buffer = flag; 105 } 106 107 bool 108 CLImageProcessor::add_handler (SmartPtr<CLImageHandler> &handler) 109 { 110 XCAM_ASSERT (handler.ptr ()); 111 _handlers.push_back (handler); 112 return true; 113 } 114 115 CLImageProcessor::ImageHandlerList::iterator 116 CLImageProcessor::handlers_begin () 117 { 118 return _handlers.begin (); 119 } 120 121 CLImageProcessor::ImageHandlerList::iterator 122 CLImageProcessor::handlers_end () 123 { 124 return _handlers.end (); 125 } 126 127 SmartPtr<CLContext> 128 CLImageProcessor::get_cl_context () 129 { 130 return _context; 131 } 132 133 bool 134 CLImageProcessor::can_process_result (SmartPtr<X3aResult> &result) 135 { 136 XCAM_UNUSED (result); 137 return false; 138 } 139 140 XCamReturn 141 CLImageProcessor::apply_3a_results (X3aResultList &results) 142 { 143 XCAM_UNUSED (results); 144 return XCAM_RETURN_NO_ERROR; 145 } 146 147 XCamReturn 148 CLImageProcessor::apply_3a_result (SmartPtr<X3aResult> &result) 149 { 150 XCAM_UNUSED (result); 151 return XCAM_RETURN_NO_ERROR; 152 } 153 154 XCamReturn 155 CLImageProcessor::process_buffer (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) 156 { 157 XCamReturn ret = XCAM_RETURN_NO_ERROR; 158 XCAM_ASSERT (input.ptr ()); 159 160 // Always set to NULL, output buf should be handled in CLBufferNotifyThread 161 output = NULL; 162 163 STREAM_LOCK; 164 165 if (_handlers.empty()) { 166 ret = create_handlers (); 167 } 168 169 XCAM_FAIL_RETURN ( 170 WARNING, 171 !_handlers.empty () && ret == XCAM_RETURN_NO_ERROR, 172 XCAM_RETURN_ERROR_CL, 173 "CL image processor create handlers failed"); 174 175 SmartPtr<PriorityBuffer> p_buf = new PriorityBuffer; 176 p_buf->set_seq_num (_seq_num++); 177 p_buf->data = input; 178 p_buf->handler = *(_handlers.begin ()); 179 180 XCAM_FAIL_RETURN ( 181 WARNING, 182 _process_buffer_queue.push_priority_buf (p_buf), 183 XCAM_RETURN_ERROR_UNKNOWN, 184 "CLImageProcessor push priority buffer failed"); 185 186 return XCAM_RETURN_BYPASS; 187 } 188 189 XCamReturn 190 CLImageProcessor::process_done_buffer () 191 { 192 SmartPtr<VideoBuffer> done_buf = _done_buffer_queue.pop (-1); 193 if (!done_buf.ptr ()) 194 return XCAM_RETURN_ERROR_THREAD; 195 196 //notify buffer done, only in this thread 197 notify_process_buffer_done (done_buf); 198 return XCAM_RETURN_NO_ERROR; 199 } 200 201 uint32_t 202 CLImageProcessor::check_ready_buffers () 203 { 204 uint32_t ready_count = 0; 205 bool is_ready_or_disabled = false; 206 UnsafePriorityBufferList::iterator i = _not_ready_buffers.begin (); 207 208 while (i != _not_ready_buffers.end()) { 209 SmartPtr<PriorityBuffer> buf = *i; 210 XCAM_ASSERT (buf.ptr () && buf->handler.ptr ()); 211 { 212 is_ready_or_disabled = (!buf->handler->is_handler_enabled () || buf->handler->is_ready ()); 213 } 214 if (is_ready_or_disabled) { 215 ready_count ++; 216 _process_buffer_queue.push_priority_buf (buf); 217 _not_ready_buffers.erase (i++); 218 } else 219 ++i; 220 } 221 return ready_count; 222 } 223 224 XCamReturn 225 CLImageProcessor::process_cl_buffer_queue () 226 { 227 XCamReturn ret = XCAM_RETURN_NO_ERROR; 228 SmartPtr<PriorityBuffer> p_buf; 229 const int32_t timeout = 5000; // 5ms 230 uint32_t ready_count = 0; 231 232 { 233 STREAM_LOCK; // make sure handler APIs are protected 234 check_ready_buffers (); 235 } 236 237 p_buf = _process_buffer_queue.pop (timeout); 238 239 if (!p_buf.ptr ()) { 240 //XCAM_LOG_DEBUG ("cl buffer queue stopped"); 241 return XCAM_RETURN_BYPASS; 242 } 243 244 SmartPtr<VideoBuffer> data = p_buf->data; 245 SmartPtr<CLImageHandler> handler = p_buf->handler; 246 SmartPtr <VideoBuffer> out_data; 247 248 XCAM_ASSERT (data.ptr () && handler.ptr ()); 249 250 XCAM_LOG_DEBUG ("buf:%d, rank:%d\n", p_buf->seq_num, p_buf->rank); 251 252 { 253 STREAM_LOCK; 254 if (handler->is_handler_enabled () && !handler->is_ready ()) { 255 _not_ready_buffers.push_back (p_buf); 256 return XCAM_RETURN_NO_ERROR; 257 } 258 259 ready_count = check_ready_buffers (); 260 if (ready_count) { 261 _process_buffer_queue.push_priority_buf (p_buf); 262 return XCAM_RETURN_BYPASS; 263 } 264 265 ret = handler->execute (data, out_data); 266 XCAM_FAIL_RETURN ( 267 WARNING, 268 (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), 269 ret, 270 "CLImageProcessor execute image handler failed"); 271 XCAM_ASSERT (out_data.ptr ()); 272 if (ret == XCAM_RETURN_BYPASS) 273 return ret; 274 275 // for loop in handler, find next handler 276 ImageHandlerList::iterator i_handler = _handlers.begin (); 277 while (i_handler != _handlers.end ()) 278 { 279 if (handler.ptr () == (*i_handler).ptr ()) { 280 ++i_handler; 281 break; 282 } 283 ++i_handler; 284 } 285 286 //skip all disabled handlers 287 while (i_handler != _handlers.end () && !(*i_handler)->is_handler_enabled ()) 288 ++i_handler; 289 290 if (i_handler != _handlers.end ()) 291 p_buf->handler = *i_handler; 292 else 293 p_buf->handler = NULL; 294 } 295 296 // buffer processed by all handlers, done 297 if (!p_buf->handler.ptr ()) { 298 if (!_keep_attached_buffer && out_data.ptr ()) 299 out_data->clear_attached_buffers (); 300 301 XCAM_OBJ_PROFILING_START; 302 CLDevice::instance()->get_context ()->finish (); 303 XCAM_OBJ_PROFILING_END (get_name (), XCAM_OBJ_DUR_FRAME_NUM); 304 305 // buffer done, push back 306 _done_buffer_queue.push (out_data); 307 return XCAM_RETURN_NO_ERROR; 308 } 309 310 p_buf->data = out_data; 311 p_buf->down_rank (); 312 313 XCAM_FAIL_RETURN ( 314 WARNING, 315 _process_buffer_queue.push_priority_buf (p_buf), 316 XCAM_RETURN_ERROR_UNKNOWN, 317 "CLImageProcessor push priority buffer failed"); 318 319 return ret; 320 } 321 322 XCamReturn 323 CLImageProcessor::emit_start () 324 { 325 _done_buffer_queue.resume_pop (); 326 _process_buffer_queue.resume_pop (); 327 328 if (!_done_buf_thread->start ()) 329 return XCAM_RETURN_ERROR_THREAD; 330 331 if (!_handler_thread->start ()) 332 return XCAM_RETURN_ERROR_THREAD; 333 334 return XCAM_RETURN_NO_ERROR; 335 } 336 337 void 338 CLImageProcessor::emit_stop () 339 { 340 _process_buffer_queue.pause_pop(); 341 _done_buffer_queue.pause_pop (); 342 343 344 for (ImageHandlerList::iterator i_handler = _handlers.begin (); 345 i_handler != _handlers.end (); ++i_handler) { 346 (*i_handler)->emit_stop (); 347 } 348 349 _handler_thread->stop (); 350 _done_buf_thread->stop (); 351 _not_ready_buffers.clear (); 352 _process_buffer_queue.clear (); 353 _done_buffer_queue.clear (); 354 } 355 356 XCamReturn 357 CLImageProcessor::create_handlers () 358 { 359 SmartPtr<CLImageHandler> demo_handler; 360 demo_handler = create_cl_demo_image_handler (_context); 361 // demo_handler = create_cl_binary_demo_image_handler (_context); 362 XCAM_FAIL_RETURN ( 363 WARNING, 364 demo_handler.ptr (), 365 XCAM_RETURN_ERROR_CL, 366 "CLImageProcessor create demo handler failed"); 367 add_handler (demo_handler); 368 369 return XCAM_RETURN_NO_ERROR; 370 } 371 372 }; 373