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; }
/** 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; }