• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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