-
Laurent Belcour authored
to specify a configuration in arguments. This allow to specify configuration at the creation of the plugin object.
Laurent Belcour authoredto specify a configuration in arguments. This allow to specify configuration at the creation of the plugin object.
plugins_manager.cpp 15.38 KiB
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions
Copyright (C) 2014, 2015 CNRS
Copyright (C) 2013, 2014, 2015 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/. */
#include "plugins_manager.h"
#include "rational_function.h"
#include "vertical_segment.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <list>
//#define DEBUG
//! 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;
}
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
}
//! \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)
{
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));
#ifdef _WIN32
HINSTANCE handle = LoadLibraryA(libname.c_str());
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;
continue;
}
#ifdef DEBUG_CORE
std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
return res;
}
else
{
std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
std::cerr << " cause: \"" << GetLastError() << "\"" << std::endl;
continue;
}
#else
void* handle = dlopen(libname.c_str(), RTLD_GLOBAL | RTLD_LAZY);
if(handle != NULL)
{
void (*res)();
*(void **)(&res) = dlsym(handle, function);
if(dlerror() != NULL)
{
std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << libname << std::endl;
continue;
}
#ifdef DEBUG_CORE
std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << libname << "\"" << std::endl;
#endif
return (T)res;
}
else
{
std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
std::cerr << " cause: \"" << dlerror() << "\"" << std::endl;
continue;
}
#endif
}
return NULL;
}
//! \brief load a function from the ALTA input file.
function* plugins_manager::load_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 ;
return NULL;
}
// Set the precision of the input
file.precision(10);
// Parameters of the function object
int nX, nY;
params::input param_in = params::UNKNOWN_INPUT;
params::output param_out = params::UNKNOWN_OUTPUT;
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;
//RP: Returning NULL immediately now
return NULL;
}
// 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 ;
}
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);
}
else if(comment == std::string("CMD"))
{
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);
if(f->input_parametrization() == params::UNKNOWN_INPUT)
{
f->setParametrization(param_in);
}
f->setParametrization(param_out);
// Load the function part from the file object
if( f->load(file) )
{
return f;
}
std::cout << "<<ERROR>> COULD NOT LOAD THE BRDF from File " << filename << std::endl;
return NULL;
}
//! Get an instance of the function selected based on the name <em>n</em>.
//! Return NULL if none exists.
function* plugins_manager::get_function(const arguments& args)
{
#ifdef DEBUG
std::cout << __FILE__ << " " << __LINE__ << std::endl;
std::cout << " INitial args = " << args << std::endl;
#endif
if(!args.is_defined("func"))
{
#ifdef DEBUG
std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
return new rational_function();
}
// The function to be returned.
function* func = NULL;
if(args.is_vec("func")) //Checking if the argument prodived with --func is of the form --func [ arg1, arg2, arg3]
{
#ifdef DEBUG
std::cout << __FILE__ << " " << __LINE__ << " ARGUMENTS of --func are forming a VECTOR " << std::endl;
#endif
std::vector<std::string> args_vec = args.get_vec("func");
// Treating the case []
if(args_vec.size() == 0)
{
return NULL;
}
//! create a <em>compound</em> class to store multiple
//! functions in it.
compound_function* compound = new compound_function();
//! 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 << __FILE__ << " " << __LINE__ << std::endl
<< " at i=" << i << " n=" << n << std::endl;
std::cout << "<<DEBUG>> load function with args: " << n << std::endl;
#endif
arguments temp_args = arguments::create_arguments(n);
//Recursive call
function* f = get_function(temp_args);
if(dynamic_cast<nonlinear_function*>(f) == NULL)
{
std::cerr << "<<ERROR>> only non-linear functions are compatible with a compound" << std::endl;
}
else
{
compound->push_back(dynamic_cast<nonlinear_function*>(f), temp_args);
}
}
//! return the compound class
func = compound;
#ifdef DEBUG
std::cout << __FILE__ << " " << __LINE__ << " WE HAVE A COMPOUND " << std::endl;
#endif
}
else //Here we check if the argument provided with --func is file describing a function
{
const std::string filename = args["func"];
FunctionPrototype myFunction = open_library<FunctionPrototype>(filename, "provide_function");
if(myFunction != NULL)
{
#ifdef DEBUG
std::cout << "<<DEBUG>> using function provider in file \"" << filename << "\"" << std::endl;
#endif
func = myFunction();
}
else
{
std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
return new rational_function() ;
}
}
// Treat the case of the Fresnel
if(args.is_defined("fresnel"))
{
#ifdef DEBUG
std::cout << __FILE__ << " " << __LINE__ << std::endl;
std::cout << " INSIDE fresnel args = " << args << std::endl;
#endif
// 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;
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);
}
}
#ifdef DEBUG
std::cout << __FILE__ << " " << __LINE__ << std::endl;
std::cout << " n = " << n << std::endl;
#endif
nonlinear_function* func_fres = dynamic_cast<nonlinear_function*>(get_function(arguments::create_arguments(n)));
if(func_fres != NULL)
{
bool const fresnel_is_fixed = (args.is_defined("fixed-fresnel")) ? (true) : (false);
bool const lobe_is_fixed = (args.is_defined("fixed-lobe")) ? (true) : (false);
if( fresnel_is_fixed )
{
std::cout << "<<DEBUG>> The Fresnel term is fixed" << std::endl;
}
if( lobe_is_fixed )
{
std::cout << "<<DEBUG>> The lobe is fixed" << std::endl;
}
return new product_function(nl_func, func_fres, lobe_is_fixed, fresnel_is_fixed);
}
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;
}
}
/*
// 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
*/
return func;
}
ptr<function> plugins_manager::get_function(const std::string& n)
{
if(n.empty())
{
#ifdef DEBUG
std::cout << "<<DEBUG>> no function plugin specified, returning nothing" << std::endl;
#endif
return NULL;
}
FunctionPrototype myFunc = open_library<FunctionPrototype>(n, "provide_function");
if(myFunc != NULL)
{
#ifdef DEBUG
std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
return myFunc();
}
else
{
std::cerr << "<<ERROR>> no function provider found in file \"" << n << "\"" << std::endl;
return NULL;
}
}
ptr<data> plugins_manager::get_data(const std::string& n, const arguments& args)
{
if(n.empty())
{
#ifdef DEBUG
std::cout << "<<DEBUG>> no data plugin specified, returning a vertical_segment loader" << std::endl;
#endif
return new vertical_segment();
}
DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
if(myData != NULL)
{
#ifdef DEBUG
std::cout << "<<DEBUG>> using data provider in file \"" << n << "\"" << std::endl;
#endif
return myData(args);
}
else
{
std::cerr << "<<ERROR>> no data provider found in file \"" << n << "\"" << std::endl;
return new vertical_segment() ;
}
}
ptr<fitter> plugins_manager::get_fitter(const std::string& n)
{
if(n.empty())
{
#ifdef DEBUG
std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
return NULL;
}
FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
if(myFitter != NULL)
{
#ifdef DEBUG
std::cout << "<<DEBUG>> using fitter provider in file \"" << n << "\"" << std::endl;
#endif
return myFitter();
}
else
{
std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
return NULL ;
}
}
void plugins_manager::check_compatibility( ptr<data>& d,
const ptr<function>& f,
const arguments& args)
{
if(d->input_parametrization() == params::UNKNOWN_INPUT &&
f->input_parametrization() == params::UNKNOWN_INPUT)
{
std::cout << "<<WARNING>> both function and data objects have no parametrization" << std::endl;
}
else
{
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());
}
else if(d->input_parametrization() != f->input_parametrization() && args.is_defined("change-param"))
{
std::cout << "<<INFO>> has to change the parametrization of the input data " << params::get_name(d->input_parametrization()) << std::endl;
std::cout << "<<INFO>> to " << params::get_name(f->input_parametrization()) << std::endl;
ptr<data_params> dd = new data_params(d, f->input_parametrization());
d = dynamic_pointer_cast<data>(dd) ;
}
else
{
std::cout << "<<DEBUG>> no change was made to the parametrization" << std::endl;
}
}
if(f->dimY() != d->dimY())
{
f->setDimY(d->dimY());
}
/*
// Check is the data has to be clusterized
if(args.is_defined("cluster-dim"))
{
clustering* cluster = new clustering(d, args);
d = cluster;
}
*/
}
// \todo implement the Darwin (MACOS) version.
// \todo : Why not move these functions to common.h ?
#ifdef _WIN32
#include <windows.h>
size_t plugins_manager::get_system_memory()
{
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullTotalPhys;
}
#elif defined(__APPLE__)
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>
size_t plugins_manager::get_system_memory()
{
int mib[2];
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
int64_t size = 0;
size_t len = sizeof( size );
if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
return (size_t)size;
return 0L;
}
#else
#include <unistd.h>
size_t plugins_manager::get_system_memory()
{
long pages = sysconf(_SC_PHYS_PAGES);
long page_size = sysconf(_SC_PAGE_SIZE);
return pages * page_size;
}
#endif