plugins_manager.cpp 12.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions

   Copyright (C) 2014, 2015 CNRS
   Copyright (C) 2013, 2014 Inria

   This file is part of ALTA.

   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0.  If a copy of the MPL was not distributed with this
   file, You can obtain one at http://mozilla.org/MPL/2.0/.  */

12
#include "plugins_manager.h"
13 14
#include "rational_function.h"
#include "vertical_segment.h"
15

pacanows's avatar
pacanows committed
16
#ifdef _WIN32
17
    #include <windows.h>
18 19 20
#else
    #include <dlfcn.h>
#endif
21
#include <stdio.h>
22
#include <list>
23

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
//! Add dynamic library extension (.so or .dll) to a dynamic object as well as
//! prepending 'lib' depending on the plateform.
std::string library_name(const std::string name) 
{
	std::string filename;

	const int n = name.length();
#if defined( _WIN32)
	if(name.substr(n-4, n) != std::string("dll")) {
		filename.append(name);
		filename.append(".dll");
	}
#elif defined(__APPLE__)
	if(name.substr(n-5, n) != std::string("dylib")) {
		filename.append("lib");
		filename.append(name);
		filename.append(".dylib");
	}
#else
	if(name.substr(n-2, n) != std::string("so")) {
		filename.append("lib");
		filename.append(name);
		filename.append(".so");
	}
#endif
	else {
		filename.append(name);
	}

	return filename;
}

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
void get_library_dirs(std::list<std::string>& dirs)
{
	dirs.push_back("");

#ifndef _WIN32
	std::string obj_str ;
	const char *env_str = getenv("ALTA_LIB") ;

	if(env_str == NULL) {
		obj_str = "" ;
	} else {
		obj_str = std::string(env_str)+":" ;
	}

	while(true)	{
		int lb = obj_str.find_first_not_of(":",0) ;
		int le = obj_str.find_first_of(":",lb) ;

		if(lb < le)	{
			dirs.push_back(obj_str.substr(lb,le-lb)) ;
			obj_str = obj_str.substr(le+1,obj_str.size()) ;
		} else {
			break ;
		}
	}
#endif
}

84 85 86 87 88
//! \brief Open a dynamic library file (.so or .dll) and extract the associated
//! provide function. The template argument is used to cast the library to a
//! specific type.
template<typename T> T open_library(const std::string& filename, const char* function)
{
89 90 91 92 93 94 95 96 97
	std::list<std::string> basename;
	get_library_dirs(basename);

	std::list<std::string>::iterator iter;
	for(iter = basename.begin(); iter != basename.end(); ++iter)
	{
	std::string libname = *iter;
	libname.append(library_name(filename));

98

pacanows's avatar
pacanows committed
99
#ifdef _WIN32
100
    HINSTANCE handle = LoadLibraryA(libname.c_str());
101 102 103 104 105 106 107
    if(handle != NULL)
    {
        T res = (T)GetProcAddress(handle, function);

        if(res == NULL)
        {
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << filename << std::endl;
108
            continue;
109 110 111 112 113 114 115 116
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return res;
    }
    else
    {
117
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
118
        std::cerr << "          cause: \"" << GetLastError() << "\"" << std::endl;
119
        continue;
120
    }
121
#else
122
    void* handle = dlopen(libname.c_str(), RTLD_GLOBAL | RTLD_LAZY);
123

124
	 if(handle != NULL)
125 126 127
	 {
		 void (*res)();
		 *(void **)(&res) = dlsym(handle, function);
128 129 130

        if(dlerror() != NULL)
        {
131
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << libname << std::endl;
132
            continue;
133 134
        }
#ifdef DEBUG_CORE
135
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << libname << "\"" << std::endl;
136 137 138 139 140
#endif
        return (T)res;
    }
    else
    {
141
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
142
		  std::cerr << "          cause: \"" << dlerror() << "\"" << std::endl;
143
        continue;
144 145
    }
#endif
146 147
	}
return NULL;
148 149
}

150 151 152 153 154 155 156 157
//! \brief load a function from the ALTA input file.
function* plugins_manager::get_function(const std::string& filename)
{
	std::ifstream file;
	file.open(filename.c_str()) ;
	if(!file.is_open())
	{
		std::cerr << "<<ERROR>> unable to open file \"" << filename << "\"" << std::endl ;
158
		return NULL;
159 160
	}

161 162 163
	// Set the precision of the input
	file.precision(10);

164 165
	// Parameters of the function object
	int nX, nY;
166
	params::input param_in   = params::UNKNOWN_INPUT;
167
	params::output param_out = params::UNKNOWN_OUTPUT;
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
	arguments args;

	// Test for the first line of the file. Should be a ALTA FUNC HEADER
	std::string line ;
	std::getline(file, line) ;
	if(line != "#ALTA FUNC HEADER")
	{
		std::cerr << "<<ERROR>> this is not a function file" << std::endl;
	}

	// Parse the header for the function command line and the dimension
	// of the function
	while(line != "#ALTA HEADER END")
	{
		std::getline(file, line) ;
		std::stringstream linestream(line) ;

		linestream.ignore(1) ;

		std::string comment ;
		linestream >> comment ;

		if(comment == std::string("DIM"))
		{
			linestream >> nX >> nY ;
193 194 195 196 197 198 199 200 201 202 203 204 205
		}
		else if(comment == std::string("PARAM_IN"))
		{
			std::string name;
			linestream >> name;
			std::cout << "<<DEBUG>> parsed input parametrization: " << name << std::endl;
			param_in = params::parse_input(name);
		}
		else if(comment == std::string("PARAM_OUT"))
		{
			std::string name;
			linestream >> name;
			param_out = params::parse_output(name);
206 207
		}
		else if(comment == std::string("CMD"))
208
      {
209 210 211 212 213 214 215 216
			args = arguments::create_arguments(line.substr(4, std::string::npos));
		}
	}

	// Create the function from the command line
	function* f = get_function(args);
	f->setDimX(nX);
	f->setDimY(nY);
Laurent Belcour's avatar
Laurent Belcour committed
217 218 219 220
    if(f->input_parametrization() == params::UNKNOWN_INPUT)
    {
        f->setParametrization(param_in);
    }
221
	f->setParametrization(param_out);
222 223

	// Load the function part from the file object
224
    f->load(file);
225 226 227 228

	return f;
}

229 230 231
//! Get an instance of the function selected based on the name <em>n</em>.
//! Return NULL if no one exist.
function* plugins_manager::get_function(const arguments& args)
232
{
233
    if(!args.is_defined("func"))
234 235 236 237 238 239 240
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
        return new rational_function();
    }

241 242
    // The function to be returned.
    function* func = NULL;
Laurent Belcour's avatar
Laurent Belcour committed
243

244
    if(args.is_vec("func"))
245
    {
246 247 248 249 250 251 252 253
        std::vector<std::string> args_vec = args.get_vec("func");

        // Treating the case []
        if(args_vec.size() == 0)
        {
            return NULL;
        }

254
        //! create a <em>compound</em> class to store multiple
255
        //! functions in it.
PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
256
        compound_function* compound = new compound_function();
257

PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
258 259 260 261 262 263 264 265 266 267 268 269
        //! For each args_vec element, create a function object and add
        //! it to the compound one.
        for(unsigned int i=0; i<args_vec.size(); ++i)
        {
          std::string n("--func ");
          n.append(args_vec[i]);
  #ifdef DEBUG
          std::cout << "<<DEBUG>> load function with args: " << n << std::endl;
  #endif
          arguments temp_args = arguments::create_arguments(n);
          function* f = get_function(temp_args);
          if(dynamic_cast<nonlinear_function*>(f) == NULL)
270
          {
PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
271 272 273 274 275
              std::cerr << "<<ERROR>> only non-linear function care compatible with a compound" << std::endl;
          }
          else
          {
              compound->push_back(dynamic_cast<nonlinear_function*>(f), temp_args);
276
          }
PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
277
        }
278

279 280
		  //! return the compound class
		  func = compound;
281 282 283
    }
    else
    {
284
        const std::string filename = args["func"];
285 286 287 288 289
        FunctionPrototype myFunction = open_library<FunctionPrototype>(filename, "provide_function");
        if(myFunction != NULL)
        {
#ifdef DEBUG
            std::cout << "<<DEBUG>> using function provider in file \"" << filename << "\"" << std::endl;
290
#endif
291
            func =  myFunction();
292 293 294 295 296 297
        }
        else
        {
            std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
            return new rational_function() ;
        }
298 299
    }

300 301 302
    // Treat the case of the Fresnel
    if(args.is_defined("fresnel"))
    {
PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
303 304 305 306 307 308 309 310 311 312
      // Cast into a non linear function, only those are permitted to use
      // a Fresnel term.
      nonlinear_function* nl_func = dynamic_cast<nonlinear_function*>(func);
      if(nl_func == NULL)
      {
       std::cerr << "<<ERROR>> only non-linear function are permitted to use Fresnel" << std::endl;
       return func;
      }

      std::cout << "<<DEBUG>> multiplying by a Fresnel term" << std::endl;
313

PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
      std::string n("--func ");
      if(args.is_vec("fresnel"))
      {
       std::string temp = args["fresnel"];
       n.append(temp.substr(1, temp.size()-2));
      }
      else
      {
       std::string fname = args["fresnel"];
       if(fname.empty()) // Nothing to do except print error, no plugin defined
       {
      	 std::cerr << "<<ERROR>> Fresnel plugin not defined" << std::endl;
      	 std::cerr << "<<ERROR>> using --fresnel alone is not permitted" << std::endl;
      	 return func;
       }
       else // Case where the fresnel parameters is only the plugin filename
       {
      	 n.append(fname);
       }
      }

      nonlinear_function* func_fres = dynamic_cast<nonlinear_function*>(get_function(arguments::create_arguments(n)));
      if(func_fres != NULL)
      {
      return new product_function(nl_func, func_fres);
      }
      else
      {
       std::cerr << "<<ERROR>> the right part of the product is not a nonlinear function. Will use only the left part." << std::endl;
       return func;
      }
345
	 }
PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
346 347

   
348
/*
349 350 351 352 353 354 355
	 // Correction of the data by 1/cosine(theta_L)
	 if(args.is_defined("data-correct-cosine"))
	 {
		 nonlinear_function* cosine = new cosine_function();
		 func = new product_function(cosine, dynamic_cast<nonlinear_function*>(func));
	 }
	 // End of correction
356
*/
PACANOWSKI Romain's avatar
PACANOWSKI Romain committed
357 358


359
    return func;
360
}
361
ptr<data> plugins_manager::get_data(const std::string& n)
362
{
363 364
    if(n.empty())
    {
365
#ifdef DEBUG
366
        std::cout << "<<DEBUG>> no data plugin specified, returning a vertial_segment loader" << std::endl;
367
#endif
368 369 370
        return new vertical_segment();
    }

371
	 DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
372 373
    if(myData != NULL)
    {
374
#ifdef DEBUG
375 376 377 378 379 380 381 382 383
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myData();
    }
    else
    {
        std::cerr << "<<ERROR>> no data provider found in file \"" << n << "\"" << std::endl;
        return new vertical_segment() ;
    }
384
}
385
ptr<fitter> plugins_manager::get_fitter(const std::string& n)
386
{
Laurent Belcour's avatar
Laurent Belcour committed
387 388 389 390 391
    if(n.empty())
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
392
        return NULL;
Laurent Belcour's avatar
Laurent Belcour committed
393 394
    }

395
    FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
Laurent Belcour's avatar
Laurent Belcour committed
396 397 398 399 400
    if(myFitter != NULL)
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
401
        return myFitter();
Laurent Belcour's avatar
Laurent Belcour committed
402 403 404
    }
    else
    {
405
        std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
406
        return NULL ;
Laurent Belcour's avatar
Laurent Belcour committed
407
    }
408
}
409

410
void plugins_manager::check_compatibility(ptr<data>& d, const ptr<function>& f,
411
                                          const arguments& args)
Laurent Belcour's avatar
Laurent Belcour committed
412
{
413 414
	if(d->input_parametrization() == params::UNKNOWN_INPUT &&
		f->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
415
	{
416
		std::cout << "<<WARNING>> both function and data objects have no parametrization" << std::endl;
Laurent Belcour's avatar
Laurent Belcour committed
417 418 419
	}
	else
	{
420 421 422 423 424 425 426 427 428 429
		if(d->input_parametrization() == params::UNKNOWN_INPUT)
		{
			std::cout << "<<WARNING>> unknown parametrization for data" << std::endl;
		}

		if(f->input_parametrization() == params::UNKNOWN_INPUT)
		{
			std::cout << "<<DEBUG>> function will take the parametrization of the data" << std::endl;
			f->setParametrization(d->input_parametrization());
		}
430
		else if(d->input_parametrization() != f->input_parametrization() && args.is_defined("change-param"))
431
		{
432
			std::cout << "<<INFO>> has to change the parametrization of the input data " << params::get_name(d->input_parametrization()) << std::endl;
433
            std::cout << "<<INFO>> to " << params::get_name(f->input_parametrization()) << std::endl;
434 435
			ptr<data_params> dd = new data_params(d, f->input_parametrization());
			d = dynamic_pointer_cast<data>(dd) ;
436 437 438 439 440
		}
		else
		{
			std::cout << "<<DEBUG>> no change was made to the parametrization" << std::endl;
		}
Laurent Belcour's avatar
Laurent Belcour committed
441 442 443 444
	}

	if(f->dimY() != d->dimY())
	{
Laurent Belcour's avatar
Laurent Belcour committed
445
        f->setDimY(d->dimY());
Laurent Belcour's avatar
Laurent Belcour committed
446 447 448 449 450 451 452 453 454 455 456
	}

	/*
	// Check is the data has to be clusterized
	if(args.is_defined("cluster-dim"))
	{
	clustering* cluster = new clustering(d, args);
	d = cluster;
	}
	*/
}
457

458 459 460
// \todo implement the Darwin (MACOS) version.
#ifdef WIN32
#include <windows.h>
461
size_t plugins_manager::get_system_memory()
462 463 464 465 466 467
{
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);
	return status.ullTotalPhys;
}
468 469 470 471 472
#elif __APPLE__
size_t plugins_manager::get_system_memory()
{
	return 0;
}
473 474
#else
#include <unistd.h>
475
size_t plugins_manager::get_system_memory()
476 477 478 479 480 481
{
	long pages = sysconf(_SC_PHYS_PAGES);
	long page_size = sysconf(_SC_PAGE_SIZE);
	return pages * page_size;
}
#endif