Repository: opencv/opencv
File: modules/dnn/src/layers/gridsample_layer.cpp (C++)

Code before:
                int y1 = (int)floorf(y);
                float tx = x - x1, ty = y - y1;

                float wx[4], wy[4];
                for (int i = 0; i < 4; ++i) {
                    wx[i] = cubicWeight((i - 1) - tx, alpha);
                    wy[i] = cubicWeight((i - 1) - ty, alpha);
                }
                float sumwx = wx[0]+wx[1]+wx[2]+wx[3];
                float sumwy = wy[0]+wy[1]+wy[2]+wy[3];
                if (sumwx != 0.f) { for (int i = 0; i < 4; ++i) wx[i] /= sumwx; }
                if (sumwy != 0.f) { for (int i = 0; i < 4; ++i) wy[i] /= sumwy; }

                float acc = 0.f;
                for (int j = 0; j < 4; ++j) {
                    float row = 0.f;
                    for (int i = 0; i < 4; ++i) {
                        row += fetch(y1 + (j - 1), x1 + (i - 1)) * wx[i];
                    }
                    acc += row * wy[j];
                }
                return acc;
            }
        };

        cv::parallel_for_(cv::Range(0, N * C * Hout * Wout), [&](const cv::Range& r) {
            for (int idx = r.start; idx < r.end; ++idx) {
                int t = idx;
                int w = t % Wout; t /= Wout;
                int h = t % Hout; t /= Hout;
                int c = t % C;    t /= C;
                int n = t;

                float nx = Gptr[n*gNStride + h*gHStride + w*gWStride + 0];
                float ny = Gptr[n*gNStride + h*gHStride + w*gWStride + 1];
                float x, y; normToPix(nx, ny, W, H, align_corners, x, y);

                Yptr[n*yNStride + c*yCStride + h*yHStride + w] = sampleAt(n, c, x, y);
            }
        });

        CV_Assert(!outputs.empty());
        int outType  = outputs[0].type();
        int outDepth = CV_MAT_DEPTH(outType);
        if (outDepth == CV_32F) {
            Ytmp.copyTo(outputs[0]);
        } else {
            Ytmp.convertTo(outputs[0], outType);
        }
    }
};

Review comment (suggestion):
let's:

1. put a loop inside parallel_for to handle a range of rows:

```
int nstripes = Hout*C*N;
parallel_for_(Range(0, nstripes), [&](const Range& range) {
    for (int row = range.start; row < range.end; row++) {
         int n = row/(Hout*C);
         int c = (row - n*Hout*C)/Hout;
         int y = row % Hout;
         if (type == CV_8U && interpolation == NN) {
         for (int x = 0; x < Wout; x++) {
            ...
         } } else if (type == CV_8U && interpolation == LINEAR) {
            for (int x = 0; x < Wout; x++) {
            }
        } ...
});
```

2. instead of a single loop over x, have a multiple loops that should be put into a template function, depending on the input data type, interpolation method etc.

3. support different data types, at least, 8U, FP16, BF16, FP32.

in total, you will have `4 {8U, FP16, BF16, FP32} * 3 {nearest neighbor, bilinear, bicubic} * 1 {2D} == 12` branches.

Code after:
                Yptr[yRowBase + w] = saturate_cast<T>(outv);
            }
        }
    });
}

template<typename T>
static inline void gridSampleDispatch(
        const T* Xptr,
        const float* Gptr,
        T* Yptr,
        int N, int C, int H, int W,
        int Hout, int Wout,
        bool align_corners,
        int mode, int padding)
{
    if (mode == M_NEAREST) {
        if (padding == P_ZEROS) gridSampleComputeRows<T, M_NEAREST, P_ZEROS>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
        else if (padding == P_BORDER) gridSampleComputeRows<T, M_NEAREST, P_BORDER>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
        else gridSampleComputeRows<T, M_NEAREST, P_REFLECTION>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
    } else if (mode == M_BILINEAR) {
        if (padding == P_ZEROS) gridSampleComputeRows<T, M_BILINEAR, P_ZEROS>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
        else if (padding == P_BORDER) gridSampleComputeRows<T, M_BILINEAR, P_BORDER>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
        else gridSampleComputeRows<T, M_BILINEAR, P_REFLECTION>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
    } else {
        if (padding == P_ZEROS) gridSampleComputeRows<T, M_BICUBIC, P_ZEROS>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
        else if (padding == P_BORDER) gridSampleComputeRows<T, M_BICUBIC, P_BORDER>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
        else gridSampleComputeRows<T, M_BICUBIC, P_REFLECTION>(Xptr, Gptr, Yptr, N, C, H, W, Hout, Wout, align_corners);
    }
}

class GridSampleLayerImpl CV_FINAL : public GridSampleLayer
{
public:
    int mode = M_BILINEAR;
    int padding = P_ZEROS;
    bool align_corners = false;

    GridSampleLayerImpl(const LayerParams& params) {
        setParamsFrom(params);
        String m = params.get<String>("mode", "bilinear");
        String p = params.get<String>("padding_mode", "zeros");
        align_corners = params.get<bool>("align_corners", false);

        if (m == "nearest") mode = M_NEAREST;
        else if (m == "bicubic") mode = M_BICUBIC;
        else mode = M_BILINEAR;

        if (p == "border") padding = P_BORDER;
        else if (p == "reflection") padding = P_REFLECTION;
        else padding = P_ZEROS;