1/*
2 * cl_bayer_basic_handler.cpp - CL bayer basic handler
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
21#include "cl_utils.h"
22#include "cl_bayer_basic_handler.h"
23#include "xcam_thread.h"
24
25#define GROUP_CELL_X_SIZE 64
26#define GROUP_CELL_Y_SIZE 4
27
28#define STATS_3A_CELL_X_SIZE 8
29#define STATS_3A_CELL_Y_SIZE GROUP_CELL_Y_SIZE
30
31#define STANDARD_3A_STATS_SIZE 8
32
33#define ENABLE_IMAGE_2D_INPUT 0
34
35namespace XCam {
36
37static const XCamKernelInfo kernel_bayer_basic_info = {
38    "kernel_bayer_basic",
39#include "kernel_bayer_basic.clx"
40    , 0,
41};
42
43struct BayerPostData {
44    SmartPtr<VideoBuffer> image_buffer;
45    SmartPtr<CLBuffer>    stats_cl_buf;
46};
47
48class CLBayer3AStatsThread
49    : public Thread
50{
51public:
52    CLBayer3AStatsThread (CLBayerBasicImageHandler *handler)
53        : Thread ("CLBayer3AStatsThread")
54        , _handler (handler)
55    {}
56    ~CLBayer3AStatsThread () {}
57
58    virtual bool emit_stop ();
59    bool queue_stats (SmartPtr<VideoBuffer> &buf, SmartPtr<CLBuffer> &stats);
60    SmartPtr<VideoBuffer> pop_buf ();
61protected:
62    virtual bool loop ();
63    virtual void stopped ();
64
65private:
66    CLBayerBasicImageHandler     *_handler;
67    SafeList<BayerPostData>      _stats_process_list;
68    SafeList<VideoBuffer>        _buffer_done_list;
69};
70
71bool
72CLBayer3AStatsThread::emit_stop ()
73{
74    _stats_process_list.pause_pop ();
75    _buffer_done_list.pause_pop ();
76
77    _stats_process_list.wakeup ();
78    _buffer_done_list.wakeup ();
79
80    return Thread::emit_stop ();
81}
82
83bool
84CLBayer3AStatsThread::queue_stats (SmartPtr<VideoBuffer> &buf, SmartPtr<CLBuffer> &stats)
85{
86    XCAM_FAIL_RETURN (
87        WARNING,
88        buf.ptr () && stats.ptr (),
89        false,
90        "cl bayer 3a-stats thread has error buffer/stats to queue");
91
92    SmartPtr<BayerPostData> data = new BayerPostData;
93    XCAM_ASSERT (data.ptr ());
94    data->image_buffer = buf;
95    data->stats_cl_buf = stats;
96
97    return _stats_process_list.push (data);
98}
99
100SmartPtr<VideoBuffer>
101CLBayer3AStatsThread::pop_buf ()
102{
103    return _buffer_done_list.pop ();
104}
105
106void
107CLBayer3AStatsThread::stopped ()
108{
109    _stats_process_list.clear ();
110    _buffer_done_list.clear ();
111}
112
113bool
114CLBayer3AStatsThread::loop ()
115{
116    XCamReturn ret = XCAM_RETURN_NO_ERROR;
117    SmartPtr<BayerPostData> data;
118    data = _stats_process_list.pop ();
119    if (!data.ptr ()) {
120        XCAM_LOG_INFO ("cl bayer 3a-stats thread is going to stop, processing data empty");
121        return false;
122    }
123
124    XCAM_ASSERT (data->image_buffer.ptr ());
125    XCAM_ASSERT (data->stats_cl_buf.ptr ());
126    XCAM_ASSERT (_handler);
127
128    ret = _handler->process_stats_buffer (data->image_buffer, data->stats_cl_buf);
129    XCAM_FAIL_RETURN (
130        WARNING,
131        ret == XCAM_RETURN_NO_ERROR,
132        false,
133        "cl bayer 3a-stats thread has error buffer on kernel post processing");
134
135    XCAM_FAIL_RETURN (
136        ERROR,
137        _buffer_done_list.push (data->image_buffer),
138        false,
139        "cl bayer 3a-stats thread failed to queue done-buffers");
140    return true;
141}
142
143CLBayerBasicImageKernel::CLBayerBasicImageKernel (const SmartPtr<CLContext> &context)
144    : CLImageKernel (context, "kernel_bayer_basic")
145{
146}
147
148XCamReturn
149CLBayerBasicImageHandler::process_stats_buffer (SmartPtr<VideoBuffer> &buffer, SmartPtr<CLBuffer> &cl_stats)
150{
151    SmartPtr<X3aStats> stats_3a;
152    SmartPtr<CLContext> context = get_context ();
153
154    XCAM_OBJ_PROFILING_START;
155
156    context->finish ();
157    stats_3a = _3a_stats_context->copy_stats_out (cl_stats);
158    if (!stats_3a.ptr ()) {
159        XCAM_LOG_DEBUG ("copy 3a stats failed, maybe handler stopped");
160        return XCAM_RETURN_ERROR_CL;
161    }
162
163    stats_3a->set_timestamp (buffer->get_timestamp ());
164    buffer->attach_buffer (stats_3a);
165
166    if (cl_stats.ptr ())
167        _3a_stats_context->release_buffer (cl_stats);
168
169    XCAM_OBJ_PROFILING_END ("3a_stats_cpu_copy(async)", XCAM_OBJ_DUR_FRAME_NUM);
170
171    return post_stats (stats_3a);
172}
173
174CLBayerBasicImageHandler::CLBayerBasicImageHandler (
175    const SmartPtr<CLContext> &context, const char *name)
176    : CLImageHandler (context, name)
177    , _is_first_buf (true)
178{
179    _blc_config.level_gr = XCAM_CL_BLC_DEFAULT_LEVEL;
180    _blc_config.level_r = XCAM_CL_BLC_DEFAULT_LEVEL;
181    _blc_config.level_b = XCAM_CL_BLC_DEFAULT_LEVEL;
182    _blc_config.level_gb = XCAM_CL_BLC_DEFAULT_LEVEL;
183    _blc_config.color_bits = 10;
184
185    _wb_config.r_gain = 1.0;
186    _wb_config.gr_gain = 1.0;
187    _wb_config.gb_gain = 1.0;
188    _wb_config.b_gain = 1.0;
189
190    for(int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++)
191        _gamma_table[i] = (float)i / 256.0f;
192    _gamma_table[XCAM_GAMMA_TABLE_SIZE] = 0.9999f;
193
194    _3a_stats_context = new CL3AStatsCalculatorContext (context);
195    XCAM_ASSERT (_3a_stats_context.ptr ());
196    _3a_stats_thread = new CLBayer3AStatsThread (this);
197    XCAM_ASSERT (_3a_stats_thread.ptr ());
198
199    XCAM_OBJ_PROFILING_INIT;
200}
201
202CLBayerBasicImageHandler::~CLBayerBasicImageHandler ()
203{
204    _3a_stats_thread->stop ();
205    _3a_stats_context->clean_up_data ();
206}
207
208void
209CLBayerBasicImageHandler::set_stats_bits (uint32_t stats_bits)
210{
211    XCAM_ASSERT (_3a_stats_context.ptr ());
212    _3a_stats_context->set_bit_depth (stats_bits);
213}
214
215bool
216CLBayerBasicImageHandler::set_bayer_kernel (SmartPtr<CLBayerBasicImageKernel> &kernel)
217{
218    SmartPtr<CLImageKernel> image_kernel = kernel;
219    add_kernel (image_kernel);
220    _bayer_kernel = kernel;
221    return true;
222}
223
224bool
225CLBayerBasicImageHandler::set_blc_config (const XCam3aResultBlackLevel &blc)
226{
227    _blc_config.level_r = (float)blc.r_level;
228    _blc_config.level_gr = (float)blc.gr_level;
229    _blc_config.level_gb = (float)blc.gb_level;
230    _blc_config.level_b = (float)blc.b_level;
231    //_blc_config.color_bits = 0;
232    return true;
233}
234
235bool
236CLBayerBasicImageHandler::set_wb_config (const XCam3aResultWhiteBalance &wb)
237{
238    _wb_config.r_gain = (float)wb.r_gain;
239    _wb_config.gr_gain = (float)wb.gr_gain;
240    _wb_config.gb_gain = (float)wb.gb_gain;
241    _wb_config.b_gain = (float)wb.b_gain;
242    return true;
243}
244
245bool
246CLBayerBasicImageHandler::set_gamma_table (const XCam3aResultGammaTable &gamma)
247{
248    for(int i = 0; i < XCAM_GAMMA_TABLE_SIZE; i++)
249        _gamma_table[i] = (float)gamma.table[i] / 256.0f;
250
251    return true;
252}
253
254void
255CLBayerBasicImageHandler::emit_stop ()
256{
257    _3a_stats_context->pre_stop ();
258    _3a_stats_thread->emit_stop ();
259}
260
261XCamReturn
262CLBayerBasicImageHandler::prepare_buffer_pool_video_info (
263    const VideoBufferInfo &input,
264    VideoBufferInfo &output)
265{
266    uint32_t format = XCAM_PIX_FMT_SGRBG16_planar;
267    bool format_inited = output.init (format, input.width / 2 , input.height / 2);
268
269    XCAM_FAIL_RETURN (
270        WARNING,
271        format_inited,
272        XCAM_RETURN_ERROR_PARAM,
273        "CL image handler(%s) output format(%s) unsupported",
274        get_name (), xcam_fourcc_to_string (format));
275
276    return XCAM_RETURN_NO_ERROR;
277}
278
279XCamReturn
280CLBayerBasicImageHandler::prepare_parameters (
281    SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
282{
283    SmartPtr<CLContext> context = get_context ();
284    const VideoBufferInfo & in_video_info = input->get_video_info ();
285    const VideoBufferInfo & out_video_info = output->get_video_info ();
286    CLImageDesc in_image_info;
287    CLImageDesc out_image_info;
288    CLArgList args;
289    CLWorkSize work_size;
290
291    XCAM_ASSERT (_bayer_kernel.ptr ());
292
293    if (!_3a_stats_context->is_ready () &&
294            !_3a_stats_context->allocate_data (
295                in_video_info,
296                STANDARD_3A_STATS_SIZE / STATS_3A_CELL_X_SIZE,
297                STANDARD_3A_STATS_SIZE / STATS_3A_CELL_Y_SIZE)) {
298        XCAM_LOG_WARNING ("CL3AStatsCalculatorContext allocate data failed");
299        return XCAM_RETURN_ERROR_MEM;
300    }
301
302    if (_is_first_buf) {
303        XCAM_FAIL_RETURN (
304            WARNING, _3a_stats_thread->start (), XCAM_RETURN_ERROR_THREAD,
305            "cl bayer basic handler start 3a stats thread failed");
306    }
307
308    in_image_info.format.image_channel_order = CL_RGBA;
309    in_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; //CL_UNORM_INT16;
310    in_image_info.width = in_video_info.aligned_width / 8;
311    in_image_info.height = in_video_info.height;
312    in_image_info.row_pitch = in_video_info.strides[0];
313
314    out_image_info.format.image_channel_order = CL_RGBA;
315    out_image_info.format.image_channel_data_type = CL_UNSIGNED_INT32; //CL_UNORM_INT16;
316    out_image_info.width = out_video_info.width  / 8;
317    out_image_info.height = out_video_info.aligned_height * 4;
318    out_image_info.row_pitch = out_video_info.strides[0];
319
320#if ENABLE_IMAGE_2D_INPUT
321    SmartPtr<CLImage> image_in = convert_to_climage (context, input, in_image_info);
322#else
323    SmartPtr<CLBuffer> buffer_in = convert_to_clbuffer (context, input);
324#endif
325    uint32_t input_aligned_width = in_video_info.strides[0] / (2 * 8); // ushort8
326    SmartPtr<CLImage> image_out = convert_to_climage (context, output, out_image_info);
327
328    uint32_t out_aligned_height = out_video_info.aligned_height;
329    _blc_config.color_bits = in_video_info.color_bits;
330
331    SmartPtr<CLBuffer> gamma_table_buffer = new CLBuffer(
332        context, sizeof(float) * (XCAM_GAMMA_TABLE_SIZE + 1),
333        CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, &_gamma_table);
334
335    _stats_cl_buffer = _3a_stats_context->get_buffer ();
336    XCAM_FAIL_RETURN (
337        WARNING,
338        _stats_cl_buffer.ptr () && _stats_cl_buffer->is_valid (),
339        XCAM_RETURN_ERROR_PARAM,
340        "CLBayerBasic handler get 3a stats buffer failed");
341
342    XCAM_FAIL_RETURN (
343        WARNING,
344        image_out->is_valid (),
345        XCAM_RETURN_ERROR_MEM,
346        "cl image handler(%s) out memory not available", XCAM_STR(get_name ()));
347
348    //set args;
349#if ENABLE_IMAGE_2D_INPUT
350    args.push_back (new CLMemArgument (image_in));
351#else
352    args.push_back (new CLMemArgument (buffer_in));
353#endif
354    args.push_back (new CLArgumentT<uint32_t> (input_aligned_width));
355    args.push_back (new CLMemArgument (image_out));
356    args.push_back (new CLArgumentT<uint32_t> (out_aligned_height));
357    args.push_back (new CLArgumentT<CLBLCConfig> (_blc_config));
358    args.push_back (new CLArgumentT<CLWBConfig> (_wb_config));
359    args.push_back (new CLMemArgument (gamma_table_buffer));
360    args.push_back (new CLMemArgument (_stats_cl_buffer));
361
362    work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
363    work_size.local[0] = 16;
364    work_size.local[1] = 2;
365    work_size.global[0] = XCAM_ALIGN_UP(out_video_info.width, GROUP_CELL_X_SIZE) / GROUP_CELL_X_SIZE * work_size.local[0];
366    work_size.global[1] = XCAM_ALIGN_UP(out_video_info.aligned_height, GROUP_CELL_Y_SIZE) / GROUP_CELL_Y_SIZE * work_size.local[1];
367
368    //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]);
369    XCAM_ASSERT (_bayer_kernel.ptr ());
370    XCamReturn ret = _bayer_kernel->set_arguments (args, work_size);
371    XCAM_FAIL_RETURN (
372        WARNING, ret == XCAM_RETURN_NO_ERROR, ret,
373        "bayer basic kernel set arguments failed.");
374
375    return XCAM_RETURN_NO_ERROR;
376}
377
378XCamReturn
379CLBayerBasicImageHandler::execute_done (SmartPtr<VideoBuffer> &output)
380{
381    XCAM_FAIL_RETURN (
382        ERROR, _3a_stats_thread->queue_stats (output, _stats_cl_buffer), XCAM_RETURN_ERROR_UNKNOWN,
383        "cl bayer basic handler(%s) process 3a stats failed", XCAM_STR (get_name ()));
384
385    _stats_cl_buffer.release ();
386
387    if (_is_first_buf) {
388        _is_first_buf = false;
389        return XCAM_RETURN_BYPASS;
390    }
391
392    SmartPtr<VideoBuffer> done_buf = _3a_stats_thread->pop_buf ();
393    XCAM_FAIL_RETURN (
394        WARNING,
395        done_buf.ptr (),
396        XCAM_RETURN_ERROR_MEM,
397        "cl bayer handler(%s) failed to get done buffer", get_name ());
398    output = done_buf;
399
400    return XCAM_RETURN_NO_ERROR;
401}
402
403
404XCamReturn
405CLBayerBasicImageHandler::post_stats (const SmartPtr<X3aStats> &stats)
406{
407    if (_stats_callback.ptr ())
408        return _stats_callback->x3a_stats_ready (stats);
409
410    return XCAM_RETURN_NO_ERROR;
411}
412
413
414SmartPtr<CLImageHandler>
415create_cl_bayer_basic_image_handler (const SmartPtr<CLContext> &context, bool enable_gamma, uint32_t stats_bits)
416{
417    SmartPtr<CLBayerBasicImageHandler> bayer_planar_handler;
418    SmartPtr<CLBayerBasicImageKernel> basic_kernel;
419    char build_options[1024];
420
421    bayer_planar_handler = new CLBayerBasicImageHandler (context, "cl_handler_bayer_basic");
422    bayer_planar_handler->set_stats_bits (stats_bits);
423    basic_kernel = new CLBayerBasicImageKernel (context);
424    XCAM_ASSERT (basic_kernel.ptr ());
425
426    xcam_mem_clear (build_options);
427    snprintf (build_options, sizeof (build_options),
428              " -DENABLE_GAMMA=%d "
429              " -DENABLE_IMAGE_2D_INPUT=%d "
430              " -DSTATS_BITS=%d ",
431              (enable_gamma ? 1 : 0),
432              ENABLE_IMAGE_2D_INPUT,
433              stats_bits);
434    XCAM_FAIL_RETURN (
435        ERROR, basic_kernel->build_kernel (kernel_bayer_basic_info, build_options) == XCAM_RETURN_NO_ERROR, NULL,
436        "build bayer-basic kernel(%s) failed", kernel_bayer_basic_info.kernel_name);
437
438    XCAM_ASSERT (basic_kernel->is_valid ());
439    bayer_planar_handler->set_bayer_kernel (basic_kernel);
440
441    return bayer_planar_handler;
442}
443
444};
445