| 30 | |
| 31 | template<typename T> |
| 32 | void transform(Param<T> out, CParam<T> in, CParam<float> tf, const bool inverse, |
| 33 | const bool perspective, const af::interpType method, int order) { |
| 34 | auto transform = common::getKernel( |
| 35 | "arrayfire::cuda::transform", {{transform_cuh_src}}, |
| 36 | TemplateArgs(TemplateTypename<T>(), TemplateArg(inverse), |
| 37 | TemplateArg(order))); |
| 38 | |
| 39 | const unsigned int nImg2 = in.dims[2]; |
| 40 | const unsigned int nImg3 = in.dims[3]; |
| 41 | const unsigned int nTfs2 = tf.dims[2]; |
| 42 | const unsigned int nTfs3 = tf.dims[3]; |
| 43 | const unsigned int tf_len = (perspective) ? 9 : 6; |
| 44 | |
| 45 | // Copy transform to constant memory. |
| 46 | auto constPtr = transform.getDevPtr("c_tmat"); |
| 47 | transform.copyToReadOnly(constPtr, reinterpret_cast<CUdeviceptr>(tf.ptr), |
| 48 | nTfs2 * nTfs3 * tf_len * sizeof(float)); |
| 49 | |
| 50 | dim3 threads(TX, TY, 1); |
| 51 | dim3 blocks(divup(out.dims[0], threads.x), divup(out.dims[1], threads.y)); |
| 52 | |
| 53 | const int blocksXPerImage = blocks.x; |
| 54 | const int blocksYPerImage = blocks.y; |
| 55 | |
| 56 | // Takes care of all types of batching |
| 57 | // One-to-one batching is only done on blocks.x |
| 58 | // TODO If dim2 is not one-to-one batched, then divide blocks.x by factor |
| 59 | int batchImg2 = 1; |
| 60 | if (nImg2 != nTfs2) batchImg2 = std::min(nImg2, TI); |
| 61 | |
| 62 | blocks.x *= (nImg2 / batchImg2); |
| 63 | blocks.y *= nImg3; |
| 64 | |
| 65 | // Use blocks.z for transforms |
| 66 | blocks.z *= std::max((nTfs2 / nImg2), 1u) * std::max((nTfs3 / nImg3), 1u); |
| 67 | |
| 68 | EnqueueArgs qArgs(blocks, threads, getActiveStream()); |
| 69 | |
| 70 | transform(qArgs, out, in, nImg2, nImg3, nTfs2, nTfs3, batchImg2, |
| 71 | blocksXPerImage, blocksYPerImage, perspective, method); |
| 72 | |
| 73 | POST_LAUNCH_CHECK(); |
| 74 | } |
| 75 | |
| 76 | } // namespace kernel |
| 77 | } // namespace cuda |
no test coverage detected