/******************************************************************************
 * $Id$
 *
 * Project:  OpenCL Image Reprojector
 * Purpose:  Implementation of the GDALWarpKernel reprojector in OpenCL.
 * Author:   Seth Price, seth@pricepages.org
 *
 ******************************************************************************
 * Copyright (c) 2010, Seth Price <seth@pricepages.org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/

#if defined(HAVE_OPENCL)

/* The following relates to the profiling calls to
   clSetCommandQueueProperty() which are not available by default
   with some OpenCL implementation (i.e. ATI) */

#if defined(DEBUG_OPENCL) && DEBUG_OPENCL == 1
#define CL_USE_DEPRECATED_OPENCL_1_0_APIS
#endif

#define CL_TARGET_OPENCL_VERSION 100

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/opencl.h>
#endif

#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
extern "C" {
#endif

typedef enum {
    OCL_Bilinear=10,
    OCL_Cubic=11,
    OCL_CubicSpline=12,
    OCL_Lanczos=13
} OCLResampAlg;

typedef enum
{
    VENDOR_OTHER,
    VENDOR_AMD,
    VENDOR_INTEL
} OCLVendor;

struct oclWarper {
    cl_command_queue queue;
    cl_context context;
    cl_device_id dev;
    cl_kernel kern1;
    cl_kernel kern4;

    int srcWidth;
    int srcHeight;
    int dstWidth;
    int dstHeight;

    int useUnifiedSrcDensity;
    int useUnifiedSrcValid;
    int useDstDensity;
    int useDstValid;

    int numBands;
    int numImages;
    OCLResampAlg resampAlg;

    cl_channel_type imageFormat;
    cl_mem *realWorkCL;
    union {
        void **v;
        char **c;
        unsigned char **uc;
        short **s;
        unsigned short **us;
        float **f;
    } realWork;

    cl_mem *imagWorkCL;
    union {
        void **v;
        char **c;
        unsigned char **uc;
        short **s;
        unsigned short **us;
        float **f;
    } imagWork;

    cl_mem *dstRealWorkCL;
    union {
        void **v;
        char **c;
        unsigned char **uc;
        short **s;
        unsigned short **us;
        float **f;
    } dstRealWork;

    cl_mem *dstImagWorkCL;
    union {
        void **v;
        char **c;
        unsigned char **uc;
        short **s;
        unsigned short **us;
        float **f;
    } dstImagWork;

    unsigned int imgChSize1;
    cl_channel_order imgChOrder1;
    unsigned int imgChSize4;
    cl_channel_order imgChOrder4;
    char    useVec;

    cl_mem useBandSrcValidCL;
    char *useBandSrcValid;

    cl_mem nBandSrcValidCL;
    float *nBandSrcValid;

    cl_mem xyWorkCL;
    float *xyWork;

    int xyWidth;
    int xyHeight;
    int coordMult;

    unsigned int xyChSize;
    cl_channel_order xyChOrder;

    cl_mem fDstNoDataRealCL;
    float *fDstNoDataReal;

    OCLVendor eCLVendor;
};

struct oclWarper* GDALWarpKernelOpenCL_createEnv(int srcWidth, int srcHeight,
                                                 int dstWidth, int dstHeight,
                                                 cl_channel_type imageFormat,
                                                 int numBands, int coordMult,
                                                 int useImag, int useBandSrcValid,
                                                 float *fDstDensity,
                                                 double *dfDstNoDataReal,
                                                 OCLResampAlg resampAlg, cl_int *envErr);

cl_int GDALWarpKernelOpenCL_setSrcValid(struct oclWarper *warper,
                                        int *bandSrcValid, int bandNum);

cl_int GDALWarpKernelOpenCL_setSrcImg(struct oclWarper *warper, void *imgData,
                                      int bandNum);

cl_int GDALWarpKernelOpenCL_setDstImg(struct oclWarper *warper, void *imgData,
                                      int bandNum);

cl_int GDALWarpKernelOpenCL_setCoordRow(struct oclWarper *warper,
                                        double *rowSrcX, double *rowSrcY,
                                        double srcXOff, double srcYOff,
                                        int *success, int rowNum);

cl_int GDALWarpKernelOpenCL_runResamp(struct oclWarper *warper,
                                      float *unifiedSrcDensity,
                                      unsigned int *unifiedSrcValid,
                                      float *dstDensity,
                                      unsigned int *dstValid,
                                      double dfXScale, double dfYScale,
                                      double dfXFilter, double dfYFilter,
                                      int nXRadius, int nYRadius,
                                      int nFiltInitX, int nFiltInitY);

cl_int GDALWarpKernelOpenCL_getRow(struct oclWarper *warper,
                                   void **rowReal, void **rowImag,
                                   int rowNum, int bandNum);

cl_int GDALWarpKernelOpenCL_deleteEnv(struct oclWarper *warper);

#ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
}
#endif

#endif /* defined(HAVE_OPENCL) */
