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

Code before:
    const float maxv = align_corners ? float(limit - 1) : float(limit) - 0.5f;
    const float m = maxv - minv;
    const float two_m = 2.f * m;

    float t = fmodf(x - minv, two_m);
    if (t < 0) t += two_m;
    if (t > m) t = two_m - t;
    return t + minv;
}

static inline float cubicWeight(float t, float alpha) {
    t = std::fabs(t);
    const float t2 = t * t;
    const float t3 = t2 * t;
    if (t <= 1.f) {
        return (alpha + 2.f) * t3 - (alpha + 3.f) * t2 + 1.f;
    } else if (t < 2.f) {
        return alpha * t3 - 5.f * alpha * t2 + 8.f * alpha * t - 4.f * alpha;
    } else {
        return 0.f;
    }
}

static inline void normToPix(float nx, float ny, int W, int H, bool align_corners, float& x, float& y) {
    if (align_corners) {
        x = (nx + 1.f) * 0.5f * (W - 1);
        y = (ny + 1.f) * 0.5f * (H - 1);
    } else {
        x = ((nx + 1.f) * W - 1.f) * 0.5f;
        y = ((ny + 1.f) * H - 1.f) * 0.5f;
    }
}

enum Mode { M_NEAREST=0, M_BILINEAR=1, M_BICUBIC=2 };
enum Pad  { P_ZEROS=0,  P_BORDER=1,  P_REFLECTION=2 };

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;

Review comment (suggestion):
Make normToPix branchless to facilitate auto vectorization:

```
static inline void normToPix(float nx, float ny, int W, int H, bool align_corners, float& x, float& y) {
      float delta = float(align_corners);
      x = ((nx + 1.f)*(W - delta) + (delta - 1.f))*0.5f;
      y = ((ny + 1.f)*(H - delta) + (delta - 1.f))*0.5f;
}
```

basically, you can precompute constant xscale, xdelta, yscale, ydelta, so that the code above is equivalent to

```
static inline void normToPix(float nx, float ny, float xscale, float yscale, float xdelta, float ydelta, float& x, float& y) {
      x = nx*xscale + xdelta;
      y = ny*yscale + ydelta;
}
```

compiler will _unlikely_ do this job for you, because it knows about machine arithmetic and rounding errors, so it will value accuracy over speed. You need to do this optimization manually.

Code after:
    const float maxv = align_corners ? float(limit - 1) : float(limit) - 0.5f;
    const float m = maxv - minv;
    const float two_m = 2.f * m;

    float t = fmodf(x - minv, two_m);
    if (t < 0) t += two_m;
    if (t > m) t = two_m - t;
    return t + minv;
}

static inline void getCubicCoeffs(float x, float A, float* coeffs )
{
    coeffs[0] = ((A*(x + 1.0f) - 5.0f*A)*(x + 1.0f) + 8.0f*A)*(x + 1.0f) - 4.0f*A;
    coeffs[1] = ((A + 2.0f)*x - (A + 3.0f))*x*x + 1.0f;
    coeffs[2] = ((A + 2.0f)*(1.0f - x) - (A + 3.0f))*(1.0f - x)*(1.0f - x) + 1.0f;
    coeffs[3] = 1.0f - coeffs[0] - coeffs[1] - coeffs[2];
}

static inline void computeNormToPixParams(int W, int H, bool align_corners,
                                           float& xscale, float& yscale,
                                           float& xdelta, float& ydelta)
{
    const float delta = align_corners ? 1.f : 0.f;
    xscale = 0.5f * (W - delta);
    yscale = 0.5f * (H - delta);
    xdelta = 0.5f * (W - delta) + 0.5f * (delta - 1.f);
    ydelta = 0.5f * (H - delta) + 0.5f * (delta - 1.f);
}

static inline void normToPix(float nx, float ny,
                             float xscale, float yscale,
                             float xdelta, float ydelta,
                             float& x, float& y)
{
    x = nx * xscale + xdelta;
    y = ny * yscale + ydelta;
}

enum Mode { M_NEAREST=0, M_BILINEAR=1, M_BICUBIC=2 };
enum Pad  { P_ZEROS=0,  P_BORDER=1,  P_REFLECTION=2 };

template<typename T, int MODE, int PAD>
static inline void gridSampleComputeRows(
        const T* Xptr,
        const float* Gptr,
        T* Yptr,
        int N, int C, int H, int W,
        int Hout, int Wout,
        bool align_corners)
{
    size_t xNStride = (size_t)C * H * W;