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@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:
CLHandlerThread(CLImageProcessor * processor)33 CLHandlerThread (CLImageProcessor *processor)
34 : Thread ("CLHandlerThread")
35 , _processor (processor)
36 {}
~CLHandlerThread()37 ~CLHandlerThread () {}
38
39 virtual bool loop ();
40
41 private:
42 CLImageProcessor *_processor;
43 };
44
loop()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:
CLBufferNotifyThread(CLImageProcessor * processor)58 CLBufferNotifyThread (CLImageProcessor *processor)
59 : Thread ("CLBufNtfThrd")
60 , _processor (processor)
61 {}
~CLBufferNotifyThread()62 ~CLBufferNotifyThread () {}
63
64 virtual bool loop ();
65
66 private:
67 CLImageProcessor *_processor;
68 };
69
loop()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 }
CLImageProcessor(const char * name)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
~CLImageProcessor()96 CLImageProcessor::~CLImageProcessor ()
97 {
98 XCAM_LOG_DEBUG ("CLImageProcessor destructed");
99 }
100
101 void
keep_attached_buf(bool flag)102 CLImageProcessor::keep_attached_buf(bool flag)
103 {
104 _keep_attached_buffer = flag;
105 }
106
107 bool
add_handler(SmartPtr<CLImageHandler> & handler)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
handlers_begin()116 CLImageProcessor::handlers_begin ()
117 {
118 return _handlers.begin ();
119 }
120
121 CLImageProcessor::ImageHandlerList::iterator
handlers_end()122 CLImageProcessor::handlers_end ()
123 {
124 return _handlers.end ();
125 }
126
127 SmartPtr<CLContext>
get_cl_context()128 CLImageProcessor::get_cl_context ()
129 {
130 return _context;
131 }
132
133 bool
can_process_result(SmartPtr<X3aResult> & result)134 CLImageProcessor::can_process_result (SmartPtr<X3aResult> &result)
135 {
136 XCAM_UNUSED (result);
137 return false;
138 }
139
140 XCamReturn
apply_3a_results(X3aResultList & results)141 CLImageProcessor::apply_3a_results (X3aResultList &results)
142 {
143 XCAM_UNUSED (results);
144 return XCAM_RETURN_NO_ERROR;
145 }
146
147 XCamReturn
apply_3a_result(SmartPtr<X3aResult> & result)148 CLImageProcessor::apply_3a_result (SmartPtr<X3aResult> &result)
149 {
150 XCAM_UNUSED (result);
151 return XCAM_RETURN_NO_ERROR;
152 }
153
154 XCamReturn
process_buffer(SmartPtr<VideoBuffer> & input,SmartPtr<VideoBuffer> & output)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
process_done_buffer()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
check_ready_buffers()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
process_cl_buffer_queue()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
emit_start()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
emit_stop()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
create_handlers()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