| 293 | |
| 294 | template<typename T, typename aT> |
| 295 | void convolve2(Param<T> out, CParam<T> signal, CParam<aT> filter, int conv_dim, |
| 296 | bool expand) { |
| 297 | int fLen = |
| 298 | filter.dims[0] * filter.dims[1] * filter.dims[2] * filter.dims[3]; |
| 299 | |
| 300 | if (fLen > kernel::MAX_SCONV_FILTER_LEN) { |
| 301 | // TODO call upon fft |
| 302 | char errMessage[256]; |
| 303 | snprintf(errMessage, sizeof(errMessage), |
| 304 | "\nCUDA convolution supports max kernel size of %d\n", |
| 305 | kernel::MAX_SCONV_FILTER_LEN); |
| 306 | CUDA_NOT_SUPPORTED(errMessage); |
| 307 | } |
| 308 | |
| 309 | auto convolve2_separable = common::getKernel( |
| 310 | "arrayfire::cuda::convolve2_separable", {{convolve_separable_cuh_src}}, |
| 311 | TemplateArgs(TemplateTypename<T>(), TemplateTypename<aT>(), |
| 312 | TemplateArg(conv_dim), TemplateArg(expand), |
| 313 | TemplateArg(fLen)), |
| 314 | {{DefineValue(MAX_SCONV_FILTER_LEN), DefineValue(SCONV_THREADS_X), |
| 315 | DefineValue(SCONV_THREADS_Y)}}); |
| 316 | |
| 317 | dim3 threads(SCONV_THREADS_X, SCONV_THREADS_Y); |
| 318 | |
| 319 | int blk_x = divup(out.dims[0], threads.x); |
| 320 | int blk_y = divup(out.dims[1], threads.y); |
| 321 | |
| 322 | dim3 blocks(blk_x * signal.dims[2], blk_y * signal.dims[3]); |
| 323 | |
| 324 | // FIXME: case where filter array is strided |
| 325 | auto constMemPtr = convolve2_separable.getDevPtr(sconv_c_name); |
| 326 | convolve2_separable.copyToReadOnly( |
| 327 | constMemPtr, reinterpret_cast<CUdeviceptr>(filter.ptr), |
| 328 | fLen * sizeof(aT)); |
| 329 | |
| 330 | EnqueueArgs qArgs(blocks, threads, getActiveStream()); |
| 331 | convolve2_separable(qArgs, out, signal, blk_x, blk_y); |
| 332 | POST_LAUNCH_CHECK(); |
| 333 | } |
| 334 | |
| 335 | } // namespace kernel |
| 336 | } // namespace cuda |
no test coverage detected