Add arbkernel type (user defined - as an example pointing to Sobel3x3)
[processor-sdk/gst-plugin-dsp66.git] / src / kernels / oclconv / oclconv.cpp
1 /******************************************************************************
2  * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/
3  *   All rights reserved.
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions are met:
7  *       * Redistributions of source code must retain the above copyright
8  *         notice, this list of conditions and the following disclaimer.
9  *       * Redistributions in binary form must reproduce the above copyright
10  *         notice, this list of conditions and the following disclaimer in the
11  *         documentation and/or other materials provided with the distribution.
12  *       * Neither the name of Texas Instruments Incorporated nor the
13  *         names of its contributors may be used to endorse or promote products
14  *         derived from this software without specific prior written permission.
15  *
16  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  *   THE POSSIBILITY OF SUCH DAMAGE.
27  *****************************************************************************/
28 #define __CL_ENABLE_EXCEPTIONS
29 #include <CL/cl.hpp>
30 #include <iostream>
31 #include <fstream>
32 #include <cstdlib>
33 #include "ocl_util.h"
34 #include "conv.dsp_h"
36 //#define VERBOSE
37 using namespace cl;
38 using namespace std;
40 /*----------------------------------------------------------------------------------------------------------------------*/
41 static int oclconv_imgproc(char *kernelName, unsigned char *data_in, unsigned char *data_out, int width, int height, int sstride, int dstride)
42 {
43    cl_int err     = CL_SUCCESS;
44    int  bufsize   = sstride * height * sizeof(unsigned char);
45 #ifdef VERBOSE
46    ofstream logfile;
47    logfile.open ("/home/root/oclconv_log.txt", ios::out | ios::app); 
48    logfile << "Entered oclconv_test, width=" << width << " height=" << height << " dstride=" << dstride << " sstride=" << sstride << '\n';
49    logfile.close();
50 #endif
52    try 
53    {
54      Context context(CL_DEVICE_TYPE_ACCELERATOR);
55      std::vector<Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
56      devices.resize(1); // resize to 1 since we are only running on 1 DSP
58      Buffer bufA   (context, CL_MEM_READ_ONLY,  bufsize);
59      Buffer bufDst (context, CL_MEM_WRITE_ONLY, bufsize);
61      Program::Binaries binary(1, make_pair(conv_dsp_bin,sizeof(conv_dsp_bin)));
62      Program           program = Program(context, devices, binary);
63      program.build(devices);
64      Kernel kernel(program, kernelName);
65      kernel.setArg(0, bufA);
66      kernel.setArg(1, bufDst);
67      kernel.setArg(2, width);
68      kernel.setArg(3, height);
69      kernel.setArg(4, dstride);
70      kernel.setArg(5, sstride);
72      Event ev1,ev2,ev3,ev4;
74      CommandQueue Q(context, devices[0], CL_QUEUE_PROFILING_ENABLE);
76      Q.enqueueWriteBuffer(bufA, CL_FALSE, 0, bufsize, data_in, NULL, &ev1);
77      Q.enqueueTask (kernel, NULL, &ev3);
78      Q.enqueueReadBuffer (bufDst, CL_TRUE, 0, bufsize, data_out, NULL, &ev4);
79    }
80    catch (Error err) 
81    { cerr << "ERROR: " << err.what() << "(" << err.err() << ")" << endl; return -1; }
82 #ifdef VERBOSE
83    logfile.open ("/home/root/oclconv_log.txt", ios::out | ios::app); 
84    logfile << "Success!" << endl; 
85    logfile.close();
86 #endif
87    return 0;
88 }
89 /*----------------------------------------------------------------------------------------------------------------------*/
90 static bool          canny_first_call = true;
91 static Context       canny_ctx(CL_DEVICE_TYPE_ACCELERATOR);
92 static CommandQueue *canny_Q;
93 static Buffer       *canny_gradX, *canny_gradY, *canny_mag, *canny_scratch, *canny_numItems;
94 static Kernel       *canny_K;
95 static Buffer       *canny_input, *canny_output;
97 /******************************************************************************
98  * Canny Edge Detection - called on ARM, but algorithm dispatched to 1 DSP
99  *
100  * Note: Assumes arguments are invariant from call 1 to call N. If this is 
101  *   not the case, then move buffer creation back to the every frame section
102  *   rather than being cached in frame 0.
103  *
104  * Note: Also assumes total size is not overly large as it allocates temp 
105  *       buffers in MSMC
106  *****************************************************************************/
107 static int ocl_canny(unsigned char *data_in, unsigned char *data_out, unsigned short height, unsigned short width)
109     int numelem = (int)height*(int)width;
110     try 
111     {
112         Event canny_ev, canny_ev1, canny_ev2;
113         /*---------------------------------------------------------------------
114         * Cache as much OpenCL plumbing on the first call, so the cost is not 
115         * repeatedfor every frame.
116         *--------------------------------------------------------------------*/
117         if (canny_first_call)
118         {
119             canny_first_call = false;
121             std::vector<Device> devices = canny_ctx.getInfo<CL_CONTEXT_DEVICES>();
122             devices.resize(1); // resize to 1 since we are only running on 1 DSP
123             canny_Q = new CommandQueue(canny_ctx, devices[0]);
125             canny_input   = new Buffer(canny_ctx, CL_MEM_READ_ONLY, numelem);
126             canny_output  = new Buffer(canny_ctx, CL_MEM_WRITE_ONLY, numelem);
127             canny_gradX   = new Buffer(canny_ctx, CL_MEM_WRITE_ONLY, numelem*sizeof(short));
128             canny_gradY   = new Buffer(canny_ctx, CL_MEM_WRITE_ONLY, numelem*sizeof(short));
129             canny_mag     = new Buffer(canny_ctx, CL_MEM_WRITE_ONLY, numelem*sizeof(short));
130             canny_scratch = new Buffer(canny_ctx, CL_MEM_WRITE_ONLY, numelem);
131             canny_numItems= new Buffer(canny_ctx, CL_MEM_WRITE_ONLY, sizeof(int));
133             /*---------------------------------------------------------------------
134             * Compile the Kernel Source for the devices
135             *--------------------------------------------------------------------*/
136             Program::Binaries binary(1, make_pair(conv_dsp_bin, sizeof(conv_dsp_bin)));
137             Program program(canny_ctx, devices, binary);
138             program.build(devices);
139             canny_K = new Kernel(program, "canny_tiocl");
141             canny_K->setArg(0, *canny_input);
142             canny_K->setArg(1, *canny_gradX);
143             canny_K->setArg(2, *canny_gradY);
144             canny_K->setArg(3, *canny_mag);
145             canny_K->setArg(4, *canny_output);
146             canny_K->setArg(5, *canny_scratch);
147             canny_K->setArg(6, *canny_numItems);
148             canny_K->setArg(7, width);
149             canny_K->setArg(8, height);
150         }
152        canny_Q->enqueueWriteBuffer(*canny_input, CL_FALSE, 0, numelem, data_in, NULL, &canny_ev1);
153        canny_Q->enqueueTask(*canny_K, 0, &canny_ev);
154        canny_Q->enqueueReadBuffer (*canny_output, CL_TRUE, 0, numelem, data_out, NULL, &canny_ev2);
155     }
156     catch (cl::Error err)
157     {
158        cerr << "ERROR: " << err.what() << "(" << err.err() << ")" << endl;
159        return (-1);
160     }
161     return 0;
163 /*----------------------------------------------------------------------------------------------------------------------*/
165 #ifdef __cplusplus
166 extern "C" {
167 #endif
168 int oclconv_kernel(int kernel_type, int filter_size, char *arbkernel,
169                    unsigned char *data_in, unsigned char *data_out, 
170                    int width, int height, int dstride, int sstride)
172   int retval = -1;
173   switch(kernel_type)
174   {
175     case 0: /* Median */
176       if(filter_size == 5) { 
177         retval = oclconv_imgproc("Median2x2", data_in, data_out, width, height, sstride, dstride);
178       } else if(filter_size == 9) { 
179         retval = oclconv_imgproc("Median3x3", data_in, data_out, width, height, sstride, dstride);
180       }
181       break;
182     case 1: /* Sobel */
183       if(filter_size == 9) { 
184         retval = oclconv_imgproc("Sobel3x3", data_in, data_out, width, height, sstride, dstride);
185       }
186       break;
187     case 2: /* conv */
188       if(filter_size == 25) { 
189         retval = oclconv_imgproc("Conv5x5", data_in, data_out, width, height, sstride, dstride);
190         return 0;
191       }
192       break;
193     case 3: /* vlib canny */
194       /* filter size is ignored */
195       retval = ocl_canny (data_in, data_out, width, height); /* input and output stride assumed to be == width */
196       break;
197     case 4: /* user defined kernel */
198       retval = oclconv_imgproc (arbkernel, data_in, data_out, width, height, sstride, dstride);
199       break;
200     default:
201       break;
202   }
203   return retval;
205 #ifdef __cplusplus
207 #endif