#include "precomp.hpp"

#ifdef HAVE_CLAMDBLAS

#include "opencv2/ocl/cl_runtime/cl_runtime.hpp"
#include "opencv2/ocl/cl_runtime/clamdblas_runtime.hpp"

#if defined(_WIN32)
    static void* WinGetProcAddress(const char* name)
    {
        static HMODULE opencl_module = NULL;
        if (!opencl_module)
        {
            opencl_module = GetModuleHandleA("clAmdBlas.dll");
            if (!opencl_module)
            {
                opencl_module = LoadLibraryA("clAmdBlas.dll");
                if (!opencl_module)
                    return NULL;
            }
        }
        return (void*)GetProcAddress(opencl_module, name);
    }
    #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name)
#endif // _WIN32

#if defined(__linux__)
    #include <dlfcn.h>
    #include <stdio.h>

    static void* GetProcAddress (const char* name)
    {
        static void* h = NULL;
        if (!h)
        {
            h = dlopen("libclAmdBlas.so", RTLD_LAZY | RTLD_GLOBAL);
            if (!h)
                return NULL;
        }

        return dlsym(h, name);
    }
    #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name)
#endif

#ifndef CV_CL_GET_PROC_ADDRESS
#define CV_CL_GET_PROC_ADDRESS(name) NULL
#endif

@CL_FN_ENUMS@
@CL_FN_NAMES@

static void* openclamdblas_check_fn(int ID)
{
    void* func = CV_CL_GET_PROC_ADDRESS(openclamdblas_fn_names[ID]);
    if (!func)
    {
        std::ostringstream msg;
        msg << "OpenCL AMD BLAS function is not available: [" << openclamdblas_fn_names[ID] << "]";
        CV_Error(CV_StsBadFunc, msg.str());
    }
    extern void* openclamdblas_fn_ptrs[];
    *(void**)(openclamdblas_fn_ptrs[ID]) = func;
    return func;
}

namespace {
@CL_FN_SWITCH@
}

@CL_FN_DEFINITIONS@

@CL_FN_PTRS@

#endif
