示例#1
0
void dt_opencl_init(dt_opencl_t *cl, const int argc, char *argv[])
{
  dt_pthread_mutex_init(&cl->lock, NULL);
  cl->inited = 0;
  cl->enabled = 0;
  cl->dlocl = NULL;
  int exclude_opencl = 0;

  // user selectable parameter defines minimum requirement on GPU memory
  // default is 768MB
  // values below 200 will be (re)set to 200
  const int opencl_memory_requirement = max(200, dt_conf_get_int("opencl_memory_requirement"));
  dt_conf_set_int("opencl_memory_requirement", opencl_memory_requirement);


  for(int k=0; k<argc; k++) if(!strcmp(argv[k], "--disable-opencl"))
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] do not try to find and use an opencl runtime library due to explicit user request\n");
      exclude_opencl = 1;
    }

  if(exclude_opencl) goto finally;


  // look for explicit definition of opencl_runtime library in preferences
  const char *library = dt_conf_get_string("opencl_library");
  dt_print(DT_DEBUG_OPENCL, "[opencl_init] trying to load opencl library: '%s'\n", library && strlen(library) != 0 ? library : "<system default>");

  // dynamically load opencl runtime
  if(!dt_dlopencl_init(library, &cl->dlocl))
  {
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] no working opencl library found. Continue with opencl disabled\n");
    goto finally;
  }
  else
  {
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] opencl library '%s' found on your system and loaded\n", cl->dlocl->library);
  }

  cl_int err;
  cl_platform_id all_platforms[DT_OPENCL_MAX_PLATFORMS];
  cl_uint all_num_devices[DT_OPENCL_MAX_PLATFORMS];
  cl_uint num_platforms = DT_OPENCL_MAX_PLATFORMS;
  err = (cl->dlocl->symbols->dt_clGetPlatformIDs) (DT_OPENCL_MAX_PLATFORMS, all_platforms, &num_platforms);
  if(err != CL_SUCCESS)
  {
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not get platforms: %d\n", err);
    goto finally;
  }

  if(num_platforms == 0)
  {
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] no opencl platform available\n");
    goto finally;
  }
  dt_print(DT_DEBUG_OPENCL, "[opencl_init] found %d platform%s\n", num_platforms, num_platforms > 1 ? "s" : "");

  for(int n=0; n < num_platforms; n++)
  {
    cl_platform_id platform = all_platforms[n];
    // get the number of GPU devices available to the platforms
    // the other common option is CL_DEVICE_TYPE_GPU/CPU (but the latter doesn't work with the nvidia drivers)
    err = (cl->dlocl->symbols->dt_clGetDeviceIDs)(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &(all_num_devices[n]));
    if(err != CL_SUCCESS)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not get device id size: %d\n", err);
    }
  }

  cl_uint num_devices = 0;
  for(int n=0; n < num_platforms; n++) num_devices += all_num_devices[n];

  // create the device list
  cl->dev = (dt_opencl_device_t *)malloc(sizeof(dt_opencl_device_t)*num_devices);
  cl_device_id *devices = (cl_device_id *)malloc(sizeof(cl_device_id)*num_devices);

  cl_device_id *devs = devices;
  for(int n=0; n < num_platforms; n++)
  {
    cl_platform_id platform = all_platforms[n];
    err = (cl->dlocl->symbols->dt_clGetDeviceIDs)(platform, CL_DEVICE_TYPE_ALL, all_num_devices[n], devs, NULL);
    if(err != CL_SUCCESS)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not get devices list: %d\n", err);
    }
    devs += all_num_devices[n];
  }

  dt_print(DT_DEBUG_OPENCL, "[opencl_init] found %d device%s\n", num_devices, num_devices > 1 ? "s" : "");
  if(num_devices == 0) goto finally;

  int dev = 0;
  for(int k=0; k<num_devices; k++)
  {
    memset(cl->dev[dev].program_used, 0x0, sizeof(int)*DT_OPENCL_MAX_PROGRAMS);
    memset(cl->dev[dev].kernel_used,  0x0, sizeof(int)*DT_OPENCL_MAX_KERNELS);
    cl->dev[dev].eventlist = NULL;
    cl->dev[dev].eventtags = NULL;
    cl->dev[dev].numevents = 0;
    cl->dev[dev].eventsconsolidated = 0;
    cl->dev[dev].maxevents = 0;
    cl->dev[dev].lostevents = 0;
    cl->dev[dev].summary=CL_COMPLETE;
    cl->dev[dev].used_global_mem = 0;
    cl->dev[dev].nvidia_sm_20 = 0;
    cl_device_id devid = cl->dev[dev].devid = devices[k];

    char infostr[1024];
    char vendor[256];
    size_t infoint;
    size_t infointtab[1024];
    cl_device_type type;
    cl_bool image_support = 0;

    // test GPU memory and image support:
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_VENDOR, sizeof(vendor), &vendor, NULL);
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_NAME, sizeof(infostr), &infostr, NULL);
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_TYPE, sizeof(cl_device_type), &type,  NULL);
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL);
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &(cl->dev[dev].max_image_height), NULL);
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE2D_MAX_WIDTH,  sizeof(size_t), &(cl->dev[dev].max_image_width),  NULL);
    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_MEM_ALLOC_SIZE,  sizeof(cl_ulong), &(cl->dev[dev].max_mem_alloc),  NULL);

    if(!strncasecmp(vendor, "NVIDIA", 6))
    {
      // very lame attemt to detect support for atomic float add in global memory.
      // we need compute model sm_20, but let's try for all nvidia devices :(
      cl->dev[dev].nvidia_sm_20 = dt_nvidia_gpu_supports_sm_20(infostr);
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] device %d `%s' %s sm_20 support.\n", k, infostr, cl->dev[dev].nvidia_sm_20 ? "has" : "doesn't have");
    }

    if(type == CL_DEVICE_TYPE_CPU)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] discarding CPU device %d `%s' as it will not deliver any performance gain.\n", k, infostr);
      continue;
    }

    if(!image_support)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] discarding device %d `%s' due to missing image support.\n", k, infostr);
      continue;
    }

    (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &(cl->dev[dev].max_global_mem), NULL);
    if(cl->dev[dev].max_global_mem < opencl_memory_requirement*1024*1024)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] discarding device %d `%s' due to insufficient global memory (%luMB).\n", k, infostr, cl->dev[dev].max_global_mem/1024/1024);
      continue;
    }

    dt_print(DT_DEBUG_OPENCL, "[opencl_init] device %d `%s' supports image sizes of %zd x %zd\n", k, infostr, cl->dev[dev].max_image_width, cl->dev[dev].max_image_height);
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] device %d `%s' allows GPU memory allocations of up to %luMB\n", k, infostr, cl->dev[dev].max_mem_alloc/1024/1024);

    if(darktable.unmuted & DT_DEBUG_OPENCL)
    {
      printf("[opencl_init] device %d: %s \n", k, infostr);
      printf("     GLOBAL_MEM_SIZE:          %.0fMB\n", (double)cl->dev[dev].max_global_mem/1024.0/1024.0);
      (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(infoint), &infoint, NULL);
      printf("     MAX_WORK_GROUP_SIZE:      %zd\n", infoint);
      (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(infoint), &infoint, NULL);
      printf("     MAX_WORK_ITEM_DIMENSIONS: %zd\n", infoint);
      printf("     MAX_WORK_ITEM_SIZES:      [ ");
      (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(infointtab), infointtab, NULL);
      for (int i=0; i<infoint; i++) printf("%zd ", infointtab[i]);
      printf("]\n");
    }
    dt_pthread_mutex_init(&cl->dev[dev].lock, NULL);

    cl->dev[dev].context = (cl->dlocl->symbols->dt_clCreateContext)(0, 1, &devid, NULL, NULL, &err);
    if(err != CL_SUCCESS)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not create context for device %d: %d\n", k, err);
      goto finally;
    }
    // create a command queue for first device the context reported
    cl->dev[dev].cmd_queue = (cl->dlocl->symbols->dt_clCreateCommandQueue)(cl->dev[dev].context, devid, (darktable.unmuted & DT_DEBUG_PERF) ? CL_QUEUE_PROFILING_ENABLE : 0, &err);
    if(err != CL_SUCCESS)
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not create command queue for device %d: %d\n", k, err);
      goto finally;
    }

    char dtcache[DT_MAX_PATH_LEN];
    char cachedir[DT_MAX_PATH_LEN];
    char devname[1024];
    double tstart, tend, tdiff;
    dt_loc_get_user_cache_dir(dtcache, DT_MAX_PATH_LEN);

    int len = strlen(infostr);
    int j=0;
    // remove non-alphanumeric chars from device name
    for (int i=0; i < len; i++) if (isalnum(infostr[i])) devname[j++]=infostr[i];
    devname[j] = 0;
    snprintf(cachedir, DT_MAX_PATH_LEN, "%s/cached_kernels_for_%s", dtcache, devname);
    if (mkdir(cachedir, 0700) && (errno != EEXIST))
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] failed to create directory `%s'!\n", cachedir);
      goto finally;
    }

    char dtpath[DT_MAX_PATH_LEN];
    char filename[DT_MAX_PATH_LEN];
    char programname[DT_MAX_PATH_LEN];
    char binname[DT_MAX_PATH_LEN];
    dt_loc_get_datadir(dtpath, DT_MAX_PATH_LEN);
    snprintf(filename, DT_MAX_PATH_LEN, "%s/kernels/programs.conf", dtpath);

    // now load all darktable cl kernels.
    // TODO: compile as a job?
    tstart = dt_get_wtime();
    FILE *f = fopen(filename, "rb");
    if(f)
    {

      while(!feof(f))
      {
        int rd = fscanf(f, "%[^\n]\n", programname);
        if(rd != 1) continue;
        // remove comments:
        for(int pos=0; pos<strlen(programname); pos++)
          if(programname[pos] == '#')
          {
            programname[pos] = '\0';
            for(int l=pos-1; l>=0; l--)
            {
              if (programname[l] == ' ')
                programname[l] = '\0';
              else
                break;
            }
            break;
          }
        if(programname[0] == '\0') continue;
        snprintf(filename, DT_MAX_PATH_LEN, "%s/kernels/%s", dtpath, programname);
        snprintf(binname, DT_MAX_PATH_LEN, "%s/%s.bin", cachedir, programname);
        dt_print(DT_DEBUG_OPENCL, "[opencl_init] compiling program `%s' ..\n", programname);
        int loaded_cached;
        char md5sum[33];
        const int prog = dt_opencl_load_program(dev, filename, binname, cachedir, md5sum, &loaded_cached);
        if(dt_opencl_build_program(dev, prog, binname, cachedir, md5sum, loaded_cached) != CL_SUCCESS)
        {
          dt_print(DT_DEBUG_OPENCL, "[opencl_init] failed to compile program `%s'!\n", programname);
          goto finally;
        }

      }

      fclose(f);
      tend = dt_get_wtime();
      tdiff = tend - tstart;
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] kernel loading time: %2.4lf \n", tdiff);
    }
    else
    {
      dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not open `%s'!\n", filename);
      goto finally;
    }
    ++dev;
  }
  free(devices);
  if(dev > 0)
  {
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] successfully initialized.\n");
    cl->num_devs = dev;
    cl->inited = 1;
    cl->enabled = dt_conf_get_bool("opencl");
  }
  else
  {
    dt_print(DT_DEBUG_OPENCL, "[opencl_init] no suitable devices found.\n");
  }

finally:
  dt_print(DT_DEBUG_OPENCL, "[opencl_init] FINALLY: opencl is %sAVAILABLE on this system.\n", cl->inited ? "" : "NOT ");
  dt_print(DT_DEBUG_OPENCL, "[opencl_init] initial status of opencl enabled flag is %s.\n", cl->enabled ? "ON" : "OFF");
  if(cl->inited)
  {
    dt_capabilities_add("opencl");
    cl->bilateral = dt_bilateral_init_cl_global();
    cl->gaussian = dt_gaussian_init_cl_global();
  }
  return;
}
示例#2
0
/** Initializes a new pwstorage context. */
const dt_pwstorage_t *dt_pwstorage_new()
{
/* add password storage capabilities */
#ifdef HAVE_LIBSECRET
  dt_capabilities_add("libsecret");
#endif
#ifdef HAVE_KWALLET
  dt_capabilities_add("kwallet");
#endif

  dt_pwstorage_t *pwstorage = g_malloc(sizeof(dt_pwstorage_t));
  dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] Creating new context %p\n", pwstorage);

  if(pwstorage == NULL) return NULL;

  gchar *_backend_str = dt_conf_get_string("plugins/pwstorage/pwstorage_backend");
  gint _backend = PW_STORAGE_BACKEND_NONE;

  if(strcmp(_backend_str, "auto") == 0)
  {
    const gchar *desktop = getenv("XDG_CURRENT_DESKTOP");
    if(g_strcmp0(desktop, "KDE") == 0)
      _backend = PW_STORAGE_BACKEND_KWALLET;
    else if(g_strcmp0(desktop, "GNOME") == 0)
      _backend = PW_STORAGE_BACKEND_LIBSECRET;
    else if(g_strcmp0(desktop, "Unity") == 0)
      _backend = PW_STORAGE_BACKEND_LIBSECRET;
    else if(g_strcmp0(desktop, "XFCE") == 0)
      _backend = PW_STORAGE_BACKEND_LIBSECRET;

    dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] autodetected storage backend.\n");
  }
  else if(strcmp(_backend_str, "none") == 0)
    _backend = PW_STORAGE_BACKEND_NONE;
#ifdef HAVE_LIBSECRET
  else if(strcmp(_backend_str, "libsecret") == 0)
    _backend = PW_STORAGE_BACKEND_LIBSECRET;
#endif
#ifdef HAVE_KWALLET
  else if(strcmp(_backend_str, "kwallet") == 0)
    _backend = PW_STORAGE_BACKEND_KWALLET;
#endif
  else if(strcmp(_backend_str, "gnome keyring") == 0)
  {
    fprintf(stderr, "[pwstorage_new] GNOME Keyring backend is no longer supported.\n");
    dt_control_log(_("GNOME Keyring backend is no longer supported. configure a different one"));
    _backend = PW_STORAGE_BACKEND_NONE;
  }

  g_free(_backend_str);

  switch(_backend)
  {
    default:
      dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] unknown storage backend. Using none.\n");
    case PW_STORAGE_BACKEND_NONE:
      pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_NONE;
      pwstorage->backend_context = NULL;
      dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] no storage backend. not storing username/password. "
                                   "please change in preferences, core tab.\n");
      break;
    case PW_STORAGE_BACKEND_LIBSECRET:
#ifdef HAVE_LIBSECRET
      dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] using libsecret backend for username/password storage");
      pwstorage->backend_context = (void *)dt_pwstorage_libsecret_new();
      if(pwstorage->backend_context == NULL)
      {
        dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] error starting libsecret. using no storage backend.\n");
        pwstorage->backend_context = NULL;
        pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_NONE;
      }
      else
      {
        pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_LIBSECRET;
      }
      break;
#else
      dt_print(DT_DEBUG_PWSTORAGE,
               "[pwstorage_new] libsecret backend not available. using no storage backend.\n");
      pwstorage->backend_context = NULL;
      pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_NONE;
#endif
    case PW_STORAGE_BACKEND_KWALLET:
#ifdef HAVE_KWALLET
      dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] using kwallet backend for username/password storage");
      pwstorage->backend_context = (void *)dt_pwstorage_kwallet_new();
      if(pwstorage->backend_context == NULL)
      {
        dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_new] error starting kwallet. using no storage backend.\n");
        pwstorage->backend_context = NULL;
        pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_NONE;
      }
      else
      {
        pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_KWALLET;
      }
      dt_print(DT_DEBUG_PWSTORAGE, "  done.\n");
      break;
#else
      dt_print(DT_DEBUG_PWSTORAGE,
               "[pwstorage_new] kwallet backend not available. using no storage backend.\n");
      pwstorage->backend_context = NULL;
      pwstorage->pw_storage_backend = PW_STORAGE_BACKEND_NONE;
#endif
  }

  switch(pwstorage->pw_storage_backend)
  {
    case PW_STORAGE_BACKEND_NONE:
      dt_conf_set_string("plugins/pwstorage/pwstorage_backend", "none");
      break;
    case PW_STORAGE_BACKEND_LIBSECRET:
      dt_conf_set_string("plugins/pwstorage/pwstorage_backend", "libsecret");
      break;
    case PW_STORAGE_BACKEND_KWALLET:
      dt_conf_set_string("plugins/pwstorage/pwstorage_backend", "kwallet");
      break;
  }

  return pwstorage;
}