/* Query one device specified by type, create a context and command
 * queue, as well as retrieve device information
 */
cl_int mwSetupCL(CLInfo* ci, const CLRequest* clr)
{
    cl_int err;

    err = mwGetCLInfo(ci, clr);
    if (err != CL_SUCCESS)
    {
        mw_printf("Failed to get information about device\n");
        return err;
    }

    err = mwGetDevInfo(&ci->di, ci->dev);
    if (err != CL_SUCCESS)
    {
        mw_printf("Failed to get device info\n");
        return err;
    }

    if (mwIsFirstRun())
    {
        if (clr->verbose)
        {
            mwPrintDevInfo(&ci->di);
        }
        else
        {
            mwPrintDevInfoShort(&ci->di);
        }
    }

    return mwCreateCtxQueue(ci, CL_FALSE, clr->enableProfiling);
}
static int separationInit(int debugBOINC)
{
    int rc;
    MWInitType initType = MW_PLAIN;

  #if DISABLE_DENORMALS
    mwDisableDenormalsSSE();
  #endif

    mwFixFPUPrecision();

    if (debugBOINC)
        initType |= MW_DEBUG;

    if (SEPARATION_OPENCL)
        initType |= MW_OPENCL;

    rc = mwBoincInit(initType);
    if (rc)
        return rc;

    if (BOINC_APPLICATION && mwIsFirstRun())
    {
        /* Print the version, but only once for the workunit */
        printVersion(TRUE, FALSE);
    }

  #if (SEPARATION_OPENCL) && defined(_WIN32)
    /* We need to increase timer resolution to prevent big slowdown on windows when CPU is loaded. */
    mwSetTimerMinResolution();
  #endif /* defined(_WIN32) */

    return 0;
}
int main(int argc, const char* argv[])
{
    NBodyFlags nbf;
    int rc = 0;
    const char** argvCopy = mwFixArgv(argc, argv);

    nbSpecialSetup();

    if (nbReadParameters(argc, argvCopy ? argvCopy : argv, &nbf))
    {
        if (BOINC_APPLICATION)
        {
            mwBoincInit(MW_PLAIN);
            nbReadParameters(argc, argvCopy ? argvCopy : argv, &nbf);
            nbPrintVersion(TRUE, FALSE);
        }

        mw_finish(EXIT_FAILURE);
    }

    if (nbInit(&nbf))
    {
        exit(EXIT_FAILURE);
    }

    if (BOINC_APPLICATION && mwIsFirstRun())
    {
        nbPrintVersion(TRUE, FALSE);
    }

    nbSetDefaultFlags(&nbf);
    if (nbSetNumThreads(nbf.numThreads))
    {
        mw_finish(EXIT_FAILURE);
    }

    if (nbf.verifyOnly)
    {
        rc = nbVerifyFile(&nbf);
    }
    else if (nbf.matchHistogram)
    {
        double emd;

        emd = nbMatchHistogramFiles(nbf.histogramFileName, nbf.matchHistogram);
        mw_printf("%.15f\n", emd);
        rc = isnan(emd);
    }
    else
    {
        rc = nbMain(&nbf);
        rc = nbStatusToRC(rc);

        if (!nbf.noCleanCheckpoint)
        {
            mw_report("Removing checkpoint file '%s'\n", nbf.checkpointFileName);
            mw_remove(nbf.checkpointFileName);
        }
    }

    fflush(stderr);
    fflush(stdout); /* Odd things happen with the OpenCL one where stdout starts disappearing */


    freeNBodyFlags(&nbf);

    if (BOINC_APPLICATION)
    {
        mw_finish(rc);
    }

    return rc;
}
static cl_int mwGetCLInfo(CLInfo* ci, const CLRequest* clr)
{
    cl_int err = CL_SUCCESS;
    cl_uint nPlatform = 0;
    cl_uint nDev = 0;
    cl_platform_id* ids;
    cl_device_id* devs;
    cl_uint platformChoice;

    ids = mwGetAllPlatformIDs(&nPlatform);
    if (!ids)
        return MW_CL_ERROR;

    if (mwIsFirstRun())
    {
        mwPrintPlatforms(ids, nPlatform);
    }

    /* We have this set by default to UINT_MAX, so if it's in a
     * legitimate range, it was specified */
    if (clr->platform < nPlatform)
    {
        platformChoice = clr->platform;
    }
    else if (strcmp(clr->preferredPlatformVendor, "")) /* Didn't specify platform by index, try picking one by name */
    {
        platformChoice = choosePlatform(clr->preferredPlatformVendor, ids, nPlatform);
    }
    else
    {
        platformChoice = 0;
    }

    if (platformChoice >= nPlatform)
    {
        mw_printf("Didn't find preferred platform\n");
        platformChoice = 0;
    }

    mw_printf("Using device %u on platform %u\n", clr->devNum, platformChoice);

    ci->plat = ids[platformChoice];
    devs = mwGetAllDevices(ci->plat, &nDev);
    if (!devs)
    {
        mw_printf("Error getting devices\n");
        free(ids);
        return MW_CL_ERROR;
    }

    err = mwSelectDevice(ci, devs, clr, nDev);
    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Failed to select a device");
        err = -1;
    }

    free(ids);
    free(devs);

    return err;
}