<commit_before>#ifndef _CCTAG_POINT_HPP_
#define	_CCTAG_POINT_HPP_

#include <cctag/progBase/exceptions.hpp>

#include <boost/numeric/conversion/cast.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/functional/hash.hpp>

namespace cctag {

/**
 * @brief A Homogeneous 2D point [x, y, w].
 */
template<class T>
class Point2dH : public boost::numeric::ublas::bounded_vector<T, 3>
{
public:
	typedef boost::numeric::ublas::bounded_vector<T, 3> Container;
	typedef Container Parent;
	typedef Point2dH<T> This;

	template<class V>
	Point2dH( const Point2dH<V>& p )
		: Parent( 3 )
	{
		using boost::numeric_cast;
		this->setX( numeric_cast<T>( p.x() ) );
		this->setY( numeric_cast<T>( p.y() ) );
		this->setW( numeric_cast<T>( p.w() ) );
	}

	Point2dH()
		: Parent( 3 )
	{
		this->setX( 0 );
		this->setY( 0 );
		this->setW( 1 );
	}

	Point2dH( const This& p )
		: Parent( 3 )
	{
		this->setX( p.x() );
		this->setY( p.y() );
		this->setW( p.w() );
	}

	Point2dH( const T px, const T py )
		: Parent( 3 )
	{
		this->setX( px );
		this->setY( py );
		this->setW( 1 );
	}

	Point2dH( const Container& p )
		: Parent( 3 )
	{
		this->setX( p(0) );
		this->setY( p(1) );
		this->setW( p(2) );
	}

	virtual ~Point2dH() {}

//	virtual cv::Point_<T> cvPoint() const
//	{
//		cv::Point_<T> p;
//		p.x = x() / w();
//		p.y = y() / w();
//		return p;
//	}

	inline This& toNonHomogen()
	{
		if( w() == 0 )
		{
			BOOST_THROW_EXCEPTION( exception::Bug()
				<< exception::dev() + "Normalization of an infinite point !" );
		}
		x() /= w();
		y() /= w();
		this->setW( 1.0 );
		return *this;
	}

	template<class P>
	This& operator=( const P& p )
	{
		using boost::numeric_cast;
		this->setX( numeric_cast<T>( p.x() ) );
		this->setY( numeric_cast<T>( p.y() ) );
		this->setW( numeric_cast<T>( p.w() ) );
		return *this;
	}

	bool operator==( const This& p ) const
	{
		return
			x() == p.x() &&
			y() == p.y() &&
			w() == p.w();
	}

	virtual boost::numeric::ublas::bounded_vector<T, 2> getNormalizedBoundedVec2d() const
	{
		boost::numeric::ublas::bounded_vector<T, 2> v( 2 );
		if( w() == 0 )
		{
			v( 0 ) = x();
			v( 1 ) = y();
			return v;
		}
		v( 0 ) = x() / w();
		v( 1 ) = y() / w();
		return v;
	}

	inline T  x() const { return (*this)( 0 ); }
	inline T& x()       { return (*this)( 0 ); }

	inline T  y() const { return (*this)( 1 ); }
	inline T& y()       { return (*this)( 1 ); }

	inline T  w() const { return (*this)( 2 ); }
	inline T& w()       { return (*this)( 2 ); }

	inline T    getX() const { return x(); }
	inline T    getY() const { return y(); }
	inline T    getW() const { return w(); }
	inline void setX( const T px ) { x() = px; }
	inline void setY( const T py ) { y() = py; }
	inline void setW( const T pw ) { w() = pw; }

	inline const Container& getContainer() const { return *this; }
	inline Container& getContainer() { return *this; }
};

/**
 * @brief A 2D normalized point [x, y, 1].
 */
template<class T>
class Point2dN : public Point2dH<T>
{
	typedef Point2dH<T> Parent;
	typedef typename Parent::Container Container;
	typedef Point2dN<T> This;

public:
	Point2dN()
		: Parent()
	{}

	Point2dN( const Container& p )
		: Parent(p)
	{
		Parent::toNonHomogen();
	}

	Point2dN( const This& p )
		: Parent( p.x(), p.y() )
	{}

	Point2dN( const T px, const T py )
		: Parent( px, py )
	{}

	virtual ~Point2dN()
	{}

//	cv::Point_<T> cvPoint() const
//	{
//		cv::Point_<T> p;
//		p.x = Parent::x();
//		p.y = Parent::y();
//		return p;
//	}

        T norm() const
        {
          return sqrt(this->x()*this->x()+this->y()*this->y());
        }

	template<typename TT>
	This& operator=( const Point2dN<TT>& p )
	{
		using boost::numeric_cast;
		this->setX( numeric_cast<T>( p.x() ) );
		this->setY( numeric_cast<T>( p.y() ) );
		this->setW( (T)1 );
		return *this;
	}
	This& operator=( const Point2dH<T>& p )
	{
		if( p.w() == 0 )
		{
			this->setX( p.x() );
			this->setY( p.y() );
			this->setW( (T)1 );
			return *this;
		}
		this->setX( p.x() / p.w() );
		this->setY( p.y() / p.w() );
		this->setW( (T)1 );
		return *this;
	}
};

/**
 * @brief A 2D normalized point [x, y, 1] + its gradient bounded_vector<T,2>
 */
template<class T>
class DirectedPoint2d : public Point2dN<T>
{
	typedef Point2dN<T> Parent;
	typedef DirectedPoint2d<T> This;

public:
	DirectedPoint2d()
		: Parent()
	{
          _grad.clear();
        }

        DirectedPoint2d( const This& p )
		: Parent(p.x(), p.y())
	{
          _grad(0) = p.dX();
          _grad(1) = p.dY();
        }

	DirectedPoint2d( const Parent& p, const T dX, const T dY)
		: Parent( p.x(), p.y() )
	{
          _grad(0) = dX;
          _grad(1) = dY;
        }

	DirectedPoint2d( const T px, const T py, const T dX, const T dY)
		: Parent( px, py )
	{
          _grad(0) = dX;
          _grad(1) = dY;
        }

        inline T  dX() const { return _grad(0); }
        inline T  dY() const {return  _grad(1); }

        inline void  setDX(T dX ) { _grad(0) = dX; }
        inline void  setDY(T dY ) { _grad(1) = dY; }

        const boost::numeric::ublas::bounded_vector<T,2> & gradient() const
        {
          return _grad;
        }

	virtual ~DirectedPoint2d()
	{}

private:
        boost::numeric::ublas::bounded_vector<T,2> _grad;
};

struct UnHomogenizer
{
	template<class T>
	void operator()( T& p ) { p.toNonHomogen(); }
};

template<class T>
struct Point3d : public boost::numeric::ublas::bounded_vector<T, 3>
{
	Point3d( const boost::numeric::ublas::bounded_vector<T, 3> & p )
		: boost::numeric::ublas::bounded_vector<T, 3>( p )
	{
	}

	Point3d()
		: boost::numeric::ublas::bounded_vector<T, 3>( 3 )
	{
		this->setX( 0 );
		this->setY( 0 );
		this->setZ( 0 );
	}

	Point3d( const T px, const T py, const T pz )
		: boost::numeric::ublas::bounded_vector<T, 3>( 3 )
	{
		this->setX( px );
		this->setY( py );
		this->setZ( pz );
	}

	inline T  x() const { return (*this)( 0 ); }
	inline T& x()       { return (*this)( 0 ); }

	inline T  y() const { return (*this)( 1 ); }
	inline T& y()       { return (*this)( 1 ); }

	inline T  z() const { return (*this)( 2 ); }
	inline T& z()       { return (*this)( 2 ); }

	inline void setX( const T px ) { x() = px; }
	inline void setY( const T py ) { y() = py; }
	inline void setZ( const T pz ) { z() = pz; }

	inline void setNormalized( const T x, const T y, const T z, const T w )
	{
		if( w == 0 )
		{
			this->setX( 0 );
			this->setY( 0 );
			this->setZ( 0 );
			return;
		}
		this->setX( x / w );
		this->setY( y / w );
		this->setZ( z / w );
	}

	inline void setNormalized( const boost::numeric::ublas::bounded_vector<T, 4>& p )
	{
		if( p[3] == 0 )
		{
			this->setX( 0 );
			this->setY( 0 );
			this->setZ( 0 );
			return;
		}
		this->setX( p[0]/p[3] );
		this->setY( p[1]/p[3] );
		this->setZ( p[2]/p[3] );
	}
};

template<class T>
inline size_t hash_value( const Point2dH<T> & v )
{
	size_t h = 0xdeadbeef;
	boost::hash_combine( h, v.x() );
	boost::hash_combine( h, v.y() );
	boost::hash_combine( h, v.w() );
	return h;
}

}

#endif

<commit_msg>Format code.<commit_after>#ifndef _CCTAG_POINT_HPP_
#define	_CCTAG_POINT_HPP_

#include <cctag/progBase/exceptions.hpp>

#include <boost/numeric/conversion/cast.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/functional/hash.hpp>

namespace cctag {

/**
 * @brief A Homogeneous 2D point [x, y, w].
 */
template<class T>
class Point2dH : public boost::numeric::ublas::bounded_vector<T, 3>
{
public:
	typedef boost::numeric::ublas::bounded_vector<T, 3> Container;
	typedef Container Parent;
	typedef Point2dH<T> This;

	template<class V>
	Point2dH( const Point2dH<V>& p )
		: Parent( 3 )
	{
		using boost::numeric_cast;
		this->setX( numeric_cast<T>( p.x() ) );
		this->setY( numeric_cast<T>( p.y() ) );
		this->setW( numeric_cast<T>( p.w() ) );
	}

	Point2dH()
		: Parent( 3 )
	{
		this->setX( 0 );
		this->setY( 0 );
		this->setW( 1 );
	}

	Point2dH( const This& p )
		: Parent( 3 )
	{
		this->setX( p.x() );
		this->setY( p.y() );
		this->setW( p.w() );
	}

	Point2dH( const T px, const T py )
		: Parent( 3 )
	{
		this->setX( px );
		this->setY( py );
		this->setW( 1 );
	}

	Point2dH( const Container& p )
		: Parent( 3 )
	{
		this->setX( p(0) );
		this->setY( p(1) );
		this->setW( p(2) );
	}

	virtual ~Point2dH() {}

//	virtual cv::Point_<T> cvPoint() const
//	{
//		cv::Point_<T> p;
//		p.x = x() / w();
//		p.y = y() / w();
//		return p;
//	}

	inline This& toNonHomogen()
	{
		if( w() == 0 )
		{
			BOOST_THROW_EXCEPTION( exception::Bug()
				<< exception::dev() + "Normalization of an infinite point !" );
		}
		x() /= w();
		y() /= w();
		this->setW( 1.0 );
		return *this;
	}

	template<class P>
	This& operator=( const P& p )
	{
		using boost::numeric_cast;
		this->setX( numeric_cast<T>( p.x() ) );
		this->setY( numeric_cast<T>( p.y() ) );
		this->setW( numeric_cast<T>( p.w() ) );
		return *this;
	}

	bool operator==( const This& p ) const
	{
		return
			x() == p.x() &&
			y() == p.y() &&
			w() == p.w();
	}

	virtual boost::numeric::ublas::bounded_vector<T, 2> getNormalizedBoundedVec2d() const
	{
		boost::numeric::ublas::bounded_vector<T, 2> v( 2 );
		if( w() == 0 )
		{
			v( 0 ) = x();
			v( 1 ) = y();
			return v;
		}
		v( 0 ) = x() / w();
		v( 1 ) = y() / w();
		return v;
	}

	inline T  x() const { return (*this)( 0 ); }
	inline T& x()       { return (*this)( 0 ); }

	inline T  y() const { return (*this)( 1 ); }
	inline T& y()       { return (*this)( 1 ); }

	inline T  w() const { return (*this)( 2 ); }
	inline T& w()       { return (*this)( 2 ); }

	inline T    getX() const { return x(); }
	inline T    getY() const { return y(); }
	inline T    getW() const { return w(); }
	inline void setX( const T px ) { x() = px; }
	inline void setY( const T py ) { y() = py; }
	inline void setW( const T pw ) { w() = pw; }

	inline const Container& getContainer() const { return *this; }
	inline Container& getContainer() { return *this; }
};

/**
 * @brief A 2D normalized point [x, y, 1].
 */
template<class T>
class Point2dN : public Point2dH<T>
{
	typedef Point2dH<T> Parent;
	typedef typename Parent::Container Container;
	typedef Point2dN<T> This;

public:
	Point2dN()
		: Parent()
	{}

	Point2dN( const Container& p )
		: Parent(p)
	{
		Parent::toNonHomogen();
	}

	Point2dN( const This& p )
		: Parent( p.x(), p.y() )
	{}

	Point2dN( const T px, const T py )
		: Parent( px, py )
	{}

	virtual ~Point2dN()
	{}

//	cv::Point_<T> cvPoint() const
//	{
//		cv::Point_<T> p;
//		p.x = Parent::x();
//		p.y = Parent::y();
//		return p;
//	}

        T norm() const
        {
          return sqrt(this->x()*this->x()+this->y()*this->y());
        }

	template<typename TT>
	This& operator=( const Point2dN<TT>& p )
	{
		using boost::numeric_cast;
		this->setX( numeric_cast<T>( p.x() ) );
		this->setY( numeric_cast<T>( p.y() ) );
		this->setW( (T)1 );
		return *this;
	}
	This& operator=( const Point2dH<T>& p )
	{
		if( p.w() == 0 )
		{
			this->setX( p.x() );
			this->setY( p.y() );
			this->setW( (T)1 );
			return *this;
		}
		this->setX( p.x() / p.w() );
		this->setY( p.y() / p.w() );
		this->setW( (T)1 );
		return *this;
	}
};

/**
 * @brief A 2D normalized point [x, y, 1] + its gradient bounded_vector<T,2>
 */
template<class T>
class DirectedPoint2d : public Point2dN<T>
{
	typedef Point2dN<T> Parent;
	typedef DirectedPoint2d<T> This;

public:
	DirectedPoint2d()
		: Parent()
	{
          _grad.clear();
        }

        DirectedPoint2d( const This& p )
		: Parent(p.x(), p.y())
	{
          _grad(0) = p.dX();
          _grad(1) = p.dY();
        }

	DirectedPoint2d( const Parent& p, const T dX, const T dY)
		: Parent( p.x(), p.y() )
	{
          _grad(0) = dX;
          _grad(1) = dY;
        }

	DirectedPoint2d( const T px, const T py, const T dX, const T dY)
		: Parent( px, py )
	{
          _grad(0) = dX;
          _grad(1) = dY;
        }

        inline T  dX() const { return _grad(0); }
        inline T  dY() const { return _grad(1); }

        inline void  setDX(T dX ) { _grad(0) = dX; }
        inline void  setDY(T dY ) { _grad(1) = dY; }

        const boost::numeric::ublas::bounded_vector<T,2> & gradient() const
        {
          return _grad;
        }

	virtual ~DirectedPoint2d()
	{}

private:
        boost::numeric::ublas::bounded_vector<T,2> _grad;
};

struct UnHomogenizer
{
	template<class T>
	void operator()( T& p ) { p.toNonHomogen(); }
};

template<class T>
struct Point3d : public boost::numeric::ublas::bounded_vector<T, 3>
{
	Point3d( const boost::numeric::ublas::bounded_vector<T, 3> & p )
		: boost::numeric::ublas::bounded_vector<T, 3>( p )
	{
	}

	Point3d()
		: boost::numeric::ublas::bounded_vector<T, 3>( 3 )
	{
		this->setX( 0 );
		this->setY( 0 );
		this->setZ( 0 );
	}

	Point3d( const T px, const T py, const T pz )
		: boost::numeric::ublas::bounded_vector<T, 3>( 3 )
	{
		this->setX( px );
		this->setY( py );
		this->setZ( pz );
	}

	inline T  x() const { return (*this)( 0 ); }
	inline T& x()       { return (*this)( 0 ); }

	inline T  y() const { return (*this)( 1 ); }
	inline T& y()       { return (*this)( 1 ); }

	inline T  z() const { return (*this)( 2 ); }
	inline T& z()       { return (*this)( 2 ); }

	inline void setX( const T px ) { x() = px; }
	inline void setY( const T py ) { y() = py; }
	inline void setZ( const T pz ) { z() = pz; }

	inline void setNormalized( const T x, const T y, const T z, const T w )
	{
		if( w == 0 )
		{
			this->setX( 0 );
			this->setY( 0 );
			this->setZ( 0 );
			return;
		}
		this->setX( x / w );
		this->setY( y / w );
		this->setZ( z / w );
	}

	inline void setNormalized( const boost::numeric::ublas::bounded_vector<T, 4>& p )
	{
		if( p[3] == 0 )
		{
			this->setX( 0 );
			this->setY( 0 );
			this->setZ( 0 );
			return;
		}
		this->setX( p[0]/p[3] );
		this->setY( p[1]/p[3] );
		this->setZ( p[2]/p[3] );
	}
};

template<class T>
inline size_t hash_value( const Point2dH<T> & v )
{
	size_t h = 0xdeadbeef;
	boost::hash_combine( h, v.x() );
	boost::hash_combine( h, v.y() );
	boost::hash_combine( h, v.w() );
	return h;
}

}

#endif

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013-2015 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "engineuwsgi.h"

#include <Cutelyst/application.h>

#include <QCoreApplication>
#include <QSocketNotifier>
#include <QPluginLoader>
#include <QFileInfo>
#include <QDir>

#define CUTELYST_MODIFIER1 0

using namespace Cutelyst;

extern "C" struct uwsgi_cutelyst {
    char *app;
    int reload;
} options;

static QList<uWSGI *> *coreEngines = 0;

void cuteOutput(QtMsgType, const QMessageLogContext &, const QString &);
void uwsgi_cutelyst_loop(void);
#ifdef UWSGI_GO_CHEAP_CODE
static void fsmon_reload(struct uwsgi_fsmon *fs);
#endif

/**
 * This function is called as soon as
 * the plugin is loaded
 */
extern "C" void uwsgi_cutelyst_on_load()
{
    uwsgi_register_loop( (char *) "CutelystQtLoop", uwsgi_cutelyst_loop);

    // Get the uwsgi options
    QVariantHash opts;
    for (int i = 0; i < uwsgi.exported_opts_cnt; i++) {
        const QString &key = QString::fromLatin1(uwsgi.exported_opts[i]->key);
        if (uwsgi.exported_opts[i]->value == NULL) {
            opts.insertMulti(key, QVariant());
        } else {
            opts.insertMulti(key, QString::fromLatin1(uwsgi.exported_opts[i]->value));
        }
    }

    // if the path is relative build a path
    // relative to the current working directory
    QDir cwd(uwsgi.cwd);

    // Set the configuration env
    QVariantHash::ConstIterator it = opts.constFind(QLatin1String("ini"));
    if (it != opts.constEnd()) {
        QString config = cwd.absoluteFilePath(it.value().toString());
        qputenv("CUTELYST_CONFIG", config.toUtf8());
        if (!qEnvironmentVariableIsSet("QT_LOGGING_CONF")) {
            qputenv("QT_LOGGING_CONF", config.toUtf8());
        }
    }

    QCoreApplication *app = new QCoreApplication(uwsgi.argc, uwsgi.argv);
    app->setProperty("UWSGI_OPTS", opts);

    if (qEnvironmentVariableIsEmpty("CUTELYST_NO_UWSGI_LOG")) {
        qInstallMessageHandler(cuteOutput);
    }
}

extern "C" int uwsgi_cutelyst_init()
{
    uwsgi_log("Initializing Cutelyst plugin\n");

    // if the path is relative build a path
    // relative to the current working directory
    QDir cwd(uwsgi.cwd);

    QString path(options.app);
    if (path.isEmpty()) {
        uwsgi_log("Cutelyst application name or path was not set\n");
        exit(1);
    }

    path = cwd.absoluteFilePath(path);
#ifdef UWSGI_GO_CHEAP_CODE
    if (options.reload) {
        // Register application auto reload
        char *file = qstrdup(path.toUtf8().constData());
        uwsgi_register_fsmon(file, fsmon_reload, NULL);
    }
#endif // UWSGI_GO_CHEAP_CODE

    uwsgi.loop = (char *) "CutelystQtLoop";

    coreEngines = new QList<uWSGI *>();

    return 0;
}

extern "C" void uwsgi_cutelyst_post_fork()
{
    Q_FOREACH (uWSGI *engine, *coreEngines) {
        engine->setWorkerId(uwsgi.mywid - 1);
        if (engine->thread() != qApp->thread()) {
            engine->thread()->start();
        } else {
            Q_EMIT engine->postFork();
        }
    }
}

extern "C" int uwsgi_cutelyst_request(struct wsgi_request *wsgi_req)
{
    // empty request ?
    if (!wsgi_req->uh->pktsize) {
        qCDebug(CUTELYST_UWSGI) << "Empty request. skip.";
        return -1;
    }

    // get uwsgi variables
    if (uwsgi_parse_vars(wsgi_req)) {
        qCDebug(CUTELYST_UWSGI) << "Invalid request. skip.";
        return -1;
    }

    coreEngines->at(wsgi_req->async_id)->processRequest(wsgi_req);

    return UWSGI_OK;
}

#ifdef UWSGI_GO_CHEAP_CODE // Actually we only need uwsgi 2.0.1
static void fsmon_reload(struct uwsgi_fsmon *fs)
{
    qCDebug(CUTELYST_UWSGI) << "Reloading application due to file change";
    QFileInfo fileInfo(fs->path);
    int count = 0;
    // Ugly hack to wait for 2 seconds for the file to be filled
    while (fileInfo.size() == 0 && count < 10) {
        ++count;
        qCDebug(CUTELYST_UWSGI) << "Sleeping as the application file is empty" << count;
        usleep(200 * 1000);
        fileInfo.refresh();
    }

    uwsgi_reload(uwsgi.argv);
}
#endif // UWSGI_GO_CHEAP_CODE

/**
 * This function is called when the child process is exiting
 */
extern "C" void uwsgi_cutelyst_atexit()
{
    qCDebug(CUTELYST_UWSGI) << "Child process finishing:" << QCoreApplication::applicationPid();

    Q_FOREACH (uWSGI *engine, *coreEngines) {
        engine->stop();
    }
    qDeleteAll(*coreEngines);

    delete coreEngines;

    qCDebug(CUTELYST_UWSGI) << "Child process finished:" << QCoreApplication::applicationPid();
}

extern "C" void uwsgi_cutelyst_init_apps()
{
    const QString &applicationName = QCoreApplication::applicationName();

    qCDebug(CUTELYST_UWSGI) << "Cutelyst loading application:" << options.app;

    // if the path is relative build a path
    // relative to the current working directory
    QDir cwd(uwsgi.cwd);
    QString path = cwd.absoluteFilePath(options.app);

    QPluginLoader *loader = new QPluginLoader(path);
    if (!loader->load()) {
        qCCritical(CUTELYST_UWSGI) << "Could not load application:" << loader->errorString();
        exit(1);
    }

    QObject *instance = loader->instance();
    if (!instance) {
        qCCritical(CUTELYST_UWSGI) << "Could not get a QObject instance: %s\n" << loader->errorString();
        exit(1);
    }

    Application *app = qobject_cast<Application *>(instance);
    if (!app) {
        qCCritical(CUTELYST_UWSGI) << "Could not cast Cutelyst::Application from instance: %s\n" << loader->errorString();
        exit(1);
    }

    // Sets the application name with the name from our library
    if (QCoreApplication::applicationName() == applicationName) {
        QCoreApplication::setApplicationName(app->metaObject()->className());
    }
    qCDebug(CUTELYST_UWSGI) << "Loaded application:" << QCoreApplication::applicationName();

    QVariantHash opts = qApp->property("UWSGI_OPTS").toHash();

    uWSGI *mainEngine = new uWSGI(opts, app);
    if (!mainEngine->initApplication(app, false)) {
        qCCritical(CUTELYST_UWSGI) << "Failed to init application.";
        exit(1);
    }

    uWSGI *engine = mainEngine;
    for (int i = 0; i < uwsgi.cores; ++i) {
        // Create the wsgi_request structure
        struct wsgi_request *wsgi_req = new wsgi_request;
        memset(wsgi_req, 0, sizeof(struct wsgi_request));
        wsgi_req->async_id = i;

        // Create the desired threads
        // i > 0 the main thread counts as one thread
        if (uwsgi.threads > 1) {
            QThread *thread = new QThread(qApp);

            // reuse the main engine
            if (i != 0) {
                // The engine can't have a parent otherwise
                // we can't move it
                engine = new uWSGI(opts, app);
            }

            // the request must be added before moving threads
            engine->addUnusedRequest(wsgi_req);

            // Move to the new thread
            engine->setThread(thread);

            if (i != 0) {
                // Post fork might fail when on threaded mode
                QObject::connect(engine, &uWSGI::engineDisabled,
                                 mainEngine, &uWSGI::reuseEngineRequests, Qt::QueuedConnection);
            }

        } else {
            engine->addUnusedRequest(wsgi_req);
        }
        engine->setWorkerCore(i);

        if (!coreEngines->contains(engine)) {
            coreEngines->append(engine);
        }
    }

    // register a new app under a specific "mountpoint"
    uwsgi_add_app(1, CUTELYST_MODIFIER1, (char *) "", 0, NULL, NULL);

    delete loader;

    if (uwsgi.lazy_apps) {
        // Make sure we start listening on lazy mode
        uwsgi_cutelyst_post_fork();
    }
}

void uwsgi_cutelyst_watch_signal(int signalFD)
{
    QSocketNotifier *socketNotifier = new QSocketNotifier(signalFD, QSocketNotifier::Read);
    QObject::connect(socketNotifier, &QSocketNotifier::activated,
                     [=](int fd) {
        socketNotifier->setEnabled(false);
        uwsgi_receive_signal(fd, (char *) "worker", uwsgi.mywid);
        socketNotifier->setEnabled(true);
    });
}

void uwsgi_cutelyst_loop()
{
    // ensure SIGPIPE is ignored
    signal(SIGPIPE, SIG_IGN);

    // FIX for some reason this is not being set by UWSGI
    uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;

    // monitor signals
    if (uwsgi.signal_socket > -1) {
        uwsgi_cutelyst_watch_signal(uwsgi.signal_socket);
        uwsgi_cutelyst_watch_signal(uwsgi.my_signal_socket);
    }

    // start the qt event loop
    qApp->exec();
}

void cuteOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    switch (type) {
    case QtDebugMsg:
        uwsgi_log("%s[debug] %s\n", context.category, localMsg.constData());
        break;
    case QtWarningMsg:
        uwsgi_log("%s[warn]  %s\n", context.category, localMsg.constData());
        break;
    case QtCriticalMsg:
        uwsgi_log("%s[crit]  %s\n", context.category, localMsg.constData());
        break;
    case QtFatalMsg:
        uwsgi_log("%s[fatal] %s\n", context.category, localMsg.constData());
        abort();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
    case QtInfoMsg:
        fprintf(stderr, "%s[info]  %s\n", context.category, localMsg.constData());
        break;
#endif
    }
}

struct uwsgi_option uwsgi_cutelyst_options[] = {

{const_cast<char *>("cutelyst-app"), required_argument, 0, const_cast<char *>("loads the Cutelyst Application"), uwsgi_opt_set_str, &options.app, 0},
{const_cast<char *>("cutelyst-reload"), no_argument, 0, const_cast<char *>("auto reloads the application when app file changes"), uwsgi_opt_true, &options.reload, 0},
{0, 0, 0, 0, 0, 0, 0},

};

struct uwsgi_plugin cutelyst_plugin = {
    "cutelyst", // name
    0, // alias
    0, // modifier1
    0, // data
    uwsgi_cutelyst_on_load, // on_load
    uwsgi_cutelyst_init, // init
    0, // post_init
    uwsgi_cutelyst_post_fork, // post_fork
    uwsgi_cutelyst_options, // options
    0, // enable threads
    0, // init thread
    uwsgi_cutelyst_request, // request
    0, // after request
    0, // pre init apps
    uwsgi_cutelyst_init_apps, // init apps
    0, // post init apps
    0, // (*fixup) (void);
    0, //void (*master_fixup) (int);
    0, // master_cycle) (void);
    0, //int (*mount_app) (char *, char *);
    0, //int (*manage_udp) (char *, int, char *, int);
    0, //void (*suspend) (struct wsgi_request *);
    0, //void (*resume) (struct wsgi_request *);

    0, //void (*harakiri) (int);

    0, //void (*hijack_worker) (void);
    0, //void (*spooler_init) (void);
    uwsgi_cutelyst_atexit, // atexit
};
<commit_msg>Fix loading on i386<commit_after>/*
 * Copyright (C) 2013-2015 Daniel Nicoletti <dantti12@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB. If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "engineuwsgi.h"

#include <Cutelyst/application.h>

#include <QCoreApplication>
#include <QSocketNotifier>
#include <QPluginLoader>
#include <QFileInfo>
#include <QDir>

#define CUTELYST_MODIFIER1 0

using namespace Cutelyst;

struct uwsgi_cutelyst {
    char *app;
    int reload;
} options;

static QList<uWSGI *> *coreEngines = 0;

void cuteOutput(QtMsgType, const QMessageLogContext &, const QString &);
void uwsgi_cutelyst_loop(void);
#ifdef UWSGI_GO_CHEAP_CODE
static void fsmon_reload(struct uwsgi_fsmon *fs);
#endif

/**
 * This function is called as soon as
 * the plugin is loaded
 */
void uwsgi_cutelyst_on_load()
{
    uwsgi_register_loop( (char *) "CutelystQtLoop", uwsgi_cutelyst_loop);

    // Get the uwsgi options
    QVariantHash opts;
    for (int i = 0; i < uwsgi.exported_opts_cnt; i++) {
        const QString &key = QString::fromLatin1(uwsgi.exported_opts[i]->key);
        if (uwsgi.exported_opts[i]->value == NULL) {
            opts.insertMulti(key, QVariant());
        } else {
            opts.insertMulti(key, QString::fromLatin1(uwsgi.exported_opts[i]->value));
        }
    }

    // if the path is relative build a path
    // relative to the current working directory
    QDir cwd(uwsgi.cwd);

    // Set the configuration env
    QVariantHash::ConstIterator it = opts.constFind(QLatin1String("ini"));
    if (it != opts.constEnd()) {
        QString config = cwd.absoluteFilePath(it.value().toString());
        qputenv("CUTELYST_CONFIG", config.toUtf8());
        if (!qEnvironmentVariableIsSet("QT_LOGGING_CONF")) {
            qputenv("QT_LOGGING_CONF", config.toUtf8());
        }
    }

    QCoreApplication *app = new QCoreApplication(uwsgi.argc, uwsgi.argv);
    app->setProperty("UWSGI_OPTS", opts);

    if (qEnvironmentVariableIsEmpty("CUTELYST_NO_UWSGI_LOG")) {
        qInstallMessageHandler(cuteOutput);
    }
}

int uwsgi_cutelyst_init()
{
    uwsgi_log("Initializing Cutelyst plugin\n");

    // if the path is relative build a path
    // relative to the current working directory
    QDir cwd(uwsgi.cwd);

    QString path(options.app);
    if (path.isEmpty()) {
        uwsgi_log("Cutelyst application name or path was not set\n");
        exit(1);
    }

    path = cwd.absoluteFilePath(path);
#ifdef UWSGI_GO_CHEAP_CODE
    if (options.reload) {
        // Register application auto reload
        char *file = qstrdup(path.toUtf8().constData());
        uwsgi_register_fsmon(file, fsmon_reload, NULL);
    }
#endif // UWSGI_GO_CHEAP_CODE

    uwsgi.loop = (char *) "CutelystQtLoop";

    coreEngines = new QList<uWSGI *>();

    return 0;
}

void uwsgi_cutelyst_post_fork()
{
    Q_FOREACH (uWSGI *engine, *coreEngines) {
        engine->setWorkerId(uwsgi.mywid - 1);
        if (engine->thread() != qApp->thread()) {
            engine->thread()->start();
        } else {
            Q_EMIT engine->postFork();
        }
    }
}

int uwsgi_cutelyst_request(struct wsgi_request *wsgi_req)
{
    // empty request ?
    if (!wsgi_req->uh->pktsize) {
        qCDebug(CUTELYST_UWSGI) << "Empty request. skip.";
        return -1;
    }

    // get uwsgi variables
    if (uwsgi_parse_vars(wsgi_req)) {
        qCDebug(CUTELYST_UWSGI) << "Invalid request. skip.";
        return -1;
    }

    coreEngines->at(wsgi_req->async_id)->processRequest(wsgi_req);

    return UWSGI_OK;
}

#ifdef UWSGI_GO_CHEAP_CODE // Actually we only need uwsgi 2.0.1
static void fsmon_reload(struct uwsgi_fsmon *fs)
{
    qCDebug(CUTELYST_UWSGI) << "Reloading application due to file change";
    QFileInfo fileInfo(fs->path);
    int count = 0;
    // Ugly hack to wait for 2 seconds for the file to be filled
    while (fileInfo.size() == 0 && count < 10) {
        ++count;
        qCDebug(CUTELYST_UWSGI) << "Sleeping as the application file is empty" << count;
        usleep(200 * 1000);
        fileInfo.refresh();
    }

    uwsgi_reload(uwsgi.argv);
}
#endif // UWSGI_GO_CHEAP_CODE

/**
 * This function is called when the child process is exiting
 */
void uwsgi_cutelyst_atexit()
{
    qCDebug(CUTELYST_UWSGI) << "Child process finishing:" << QCoreApplication::applicationPid();

    Q_FOREACH (uWSGI *engine, *coreEngines) {
        engine->stop();
    }
    qDeleteAll(*coreEngines);

    delete coreEngines;

    qCDebug(CUTELYST_UWSGI) << "Child process finished:" << QCoreApplication::applicationPid();
}

void uwsgi_cutelyst_init_apps()
{
    const QString &applicationName = QCoreApplication::applicationName();

    qCDebug(CUTELYST_UWSGI) << "Cutelyst loading application:" << options.app;

    // if the path is relative build a path
    // relative to the current working directory
    QDir cwd(uwsgi.cwd);
    QString path = cwd.absoluteFilePath(options.app);

    QPluginLoader *loader = new QPluginLoader(path);
    if (!loader->load()) {
        qCCritical(CUTELYST_UWSGI) << "Could not load application:" << loader->errorString();
        exit(1);
    }

    QObject *instance = loader->instance();
    if (!instance) {
        qCCritical(CUTELYST_UWSGI) << "Could not get a QObject instance: %s\n" << loader->errorString();
        exit(1);
    }

    Application *app = qobject_cast<Application *>(instance);
    if (!app) {
        qCCritical(CUTELYST_UWSGI) << "Could not cast Cutelyst::Application from instance: %s\n" << loader->errorString();
        exit(1);
    }

    // Sets the application name with the name from our library
    if (QCoreApplication::applicationName() == applicationName) {
        QCoreApplication::setApplicationName(app->metaObject()->className());
    }
    qCDebug(CUTELYST_UWSGI) << "Loaded application:" << QCoreApplication::applicationName();

    QVariantHash opts = qApp->property("UWSGI_OPTS").toHash();

    uWSGI *mainEngine = new uWSGI(opts, app);
    if (!mainEngine->initApplication(app, false)) {
        qCCritical(CUTELYST_UWSGI) << "Failed to init application.";
        exit(1);
    }

    uWSGI *engine = mainEngine;
    for (int i = 0; i < uwsgi.cores; ++i) {
        // Create the wsgi_request structure
        struct wsgi_request *wsgi_req = new wsgi_request;
        memset(wsgi_req, 0, sizeof(struct wsgi_request));
        wsgi_req->async_id = i;

        // Create the desired threads
        // i > 0 the main thread counts as one thread
        if (uwsgi.threads > 1) {
            QThread *thread = new QThread(qApp);

            // reuse the main engine
            if (i != 0) {
                // The engine can't have a parent otherwise
                // we can't move it
                engine = new uWSGI(opts, app);
            }

            // the request must be added before moving threads
            engine->addUnusedRequest(wsgi_req);

            // Move to the new thread
            engine->setThread(thread);

            if (i != 0) {
                // Post fork might fail when on threaded mode
                QObject::connect(engine, &uWSGI::engineDisabled,
                                 mainEngine, &uWSGI::reuseEngineRequests, Qt::QueuedConnection);
            }

        } else {
            engine->addUnusedRequest(wsgi_req);
        }
        engine->setWorkerCore(i);

        if (!coreEngines->contains(engine)) {
            coreEngines->append(engine);
        }
    }

    // register a new app under a specific "mountpoint"
    uwsgi_add_app(1, CUTELYST_MODIFIER1, (char *) "", 0, NULL, NULL);

    delete loader;

    if (uwsgi.lazy_apps) {
        // Make sure we start listening on lazy mode
        uwsgi_cutelyst_post_fork();
    }
}

void uwsgi_cutelyst_watch_signal(int signalFD)
{
    QSocketNotifier *socketNotifier = new QSocketNotifier(signalFD, QSocketNotifier::Read);
    QObject::connect(socketNotifier, &QSocketNotifier::activated,
                     [=](int fd) {
        socketNotifier->setEnabled(false);
        uwsgi_receive_signal(fd, (char *) "worker", uwsgi.mywid);
        socketNotifier->setEnabled(true);
    });
}

void uwsgi_cutelyst_loop()
{
    // ensure SIGPIPE is ignored
    signal(SIGPIPE, SIG_IGN);

    // FIX for some reason this is not being set by UWSGI
    uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;

    // monitor signals
    if (uwsgi.signal_socket > -1) {
        uwsgi_cutelyst_watch_signal(uwsgi.signal_socket);
        uwsgi_cutelyst_watch_signal(uwsgi.my_signal_socket);
    }

    // start the qt event loop
    qApp->exec();
}

void cuteOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    switch (type) {
    case QtDebugMsg:
        uwsgi_log("%s[debug] %s\n", context.category, localMsg.constData());
        break;
    case QtWarningMsg:
        uwsgi_log("%s[warn]  %s\n", context.category, localMsg.constData());
        break;
    case QtCriticalMsg:
        uwsgi_log("%s[crit]  %s\n", context.category, localMsg.constData());
        break;
    case QtFatalMsg:
        uwsgi_log("%s[fatal] %s\n", context.category, localMsg.constData());
        abort();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
    case QtInfoMsg:
        fprintf(stderr, "%s[info]  %s\n", context.category, localMsg.constData());
        break;
#endif
    }
}

struct uwsgi_option uwsgi_cutelyst_options[] = {

{const_cast<char *>("cutelyst-app"), required_argument, 0, const_cast<char *>("loads the Cutelyst Application"), uwsgi_opt_set_str, &options.app, 0},
{const_cast<char *>("cutelyst-reload"), no_argument, 0, const_cast<char *>("auto reloads the application when app file changes"), uwsgi_opt_true, &options.reload, 0},
{0, 0, 0, 0, 0, 0, 0},

};

struct uwsgi_plugin cutelyst_plugin = {
    "cutelyst", // name
    0, // alias
    0, // modifier1
    0, // data
    uwsgi_cutelyst_on_load, // on_load
    uwsgi_cutelyst_init, // init
    0, // post_init
    uwsgi_cutelyst_post_fork, // post_fork
    uwsgi_cutelyst_options, // options
    0, // enable threads
    0, // init thread
    uwsgi_cutelyst_request, // request
    0, // after request
    0, // pre init apps
    uwsgi_cutelyst_init_apps, // init apps
    0, // post init apps
    0, // (*fixup) (void);
    0, //void (*master_fixup) (int);
    0, // master_cycle) (void);
    0, //int (*mount_app) (char *, char *);
    0, //int (*manage_udp) (char *, int, char *, int);
    0, //void (*suspend) (struct wsgi_request *);
    0, //void (*resume) (struct wsgi_request *);

    0, //void (*harakiri) (int);

    0, //void (*hijack_worker) (void);
    0, //void (*spooler_init) (void);
    uwsgi_cutelyst_atexit, // atexit
};
<|endoftext|>


<commit_before>
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE libstorage

#include <boost/test/unit_test.hpp>
#include <iostream>

#include "storage/Devices/Md.h"
#include "storage/Devices/Encryption.h"

#include "storage/Filesystems/BlkFilesystem.h"
#include "storage/Filesystems/MountPoint.h"
#include "storage/Devices/LvmVg.h"
#include "storage/Devices/LvmPv.h"

#include "testsuite/CompoundAction/Fixture.h"

#define BLOCK_SIZE	1024L
#define kiB             1L
#define MiB		(1024L*kiB)
#define GiB		(1024L*MiB)
#define TiB		(1024L*GiB)

using std::cout;
using std::endl;

namespace storage
{
    namespace test
    {
	struct MdFixture: public CompoundActionFixture
	{
	    MdFixture()
	    {
                create_disks();
            }

	    void create_disks()
	    {
		Environment environment(true, ProbeMode::NONE, TargetMode::IMAGE);
		storage = shared_ptr<Storage>(new Storage(environment));
		staging = storage->get_staging();

                for ( int i=0; i < 5; ++i )
                {
                    string device_name = "/dev/sd";
                    device_name += 'a' + i;

                    // cout << "Creating disk " << device_name << endl;
                    Disk * disk = Disk::create( staging, device_name, Region( 0, 512*GiB, BLOCK_SIZE ) );
                    disks.push_back( disk );
                }

		copy_staging_to_probed();
	    }

            Md * create_raid( const string & raid_name, MdLevel md_level )
            {
                Md * raid = Md::create( staging, raid_name );
                raid->set_md_level( md_level );

                for ( unsigned i=0; i < raid->minimal_number_of_devices() && i < disk_count(); ++i )
                    raid->add_device( disks[i] );

                return raid;
            }

            unsigned disk_count() const { return disks.size(); }

	    vector<Disk *> disks;
	};
    }
}

using namespace storage;

BOOST_FIXTURE_TEST_SUITE( md_raid_sentence, test::MdFixture )

BOOST_AUTO_TEST_CASE( test_create )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID6 );

    // Encryption * encryption = raid->create_encryption( "cr_raid0" );
    BlkFilesystem * ext4 = raid->create_blk_filesystem( FsType::EXT4 );
    ext4->create_mount_point( "/data" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected =
        "Create RAID6 /dev/md0 (1023.75 GiB) for /data with ext4\n"
        "from /dev/sda (512.00 GiB), /dev/sdb (512.00 GiB), /dev/sdc (512.00 GiB), /dev/sdd (512.00 GiB)";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>More test cases for MD-RAID<commit_after>
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE libstorage

#include <boost/test/unit_test.hpp>
#include <iostream>

#include "storage/Devices/Md.h"
#include "storage/Devices/Encryption.h"

#include "storage/Filesystems/BlkFilesystem.h"
#include "storage/Filesystems/MountPoint.h"
#include "storage/Devices/LvmVg.h"
#include "storage/Devices/LvmPv.h"

#include "testsuite/CompoundAction/Fixture.h"

#define BLOCK_SIZE	1024L
#define kiB             1L
#define MiB		(1024L*kiB)
#define GiB		(1024L*MiB)
#define TiB		(1024L*GiB)

using std::cout;
using std::endl;

namespace storage
{
    namespace test
    {
	struct MdFixture: public CompoundActionFixture
	{
	    MdFixture()
	    {
                create_disks();
            }

	    void create_disks()
	    {
		Environment environment(true, ProbeMode::NONE, TargetMode::IMAGE);
		storage = shared_ptr<Storage>(new Storage(environment));
		staging = storage->get_staging();

                for ( int i=0; i < 5; ++i )
                {
                    string device_name = "/dev/sd";
                    device_name += 'a' + i;

                    // cout << "Creating disk " << device_name << endl;
                    Disk * disk = Disk::create( staging, device_name, Region( 0, 512*GiB, BLOCK_SIZE ) );
                    disks.push_back( disk );
                }

		copy_staging_to_probed();
	    }

            Md * create_raid( const string & raid_name, MdLevel md_level )
            {
                Md * raid = Md::create( staging, raid_name );
                raid->set_md_level( md_level );

                for ( unsigned i=0; i < raid->minimal_number_of_devices() && i < disk_count(); ++i )
                    raid->add_device( disks[i] );

                return raid;
            }

            unsigned disk_count() const { return disks.size(); }

	    vector<Disk *> disks;
	};
    }
}

using namespace storage;

BOOST_FIXTURE_TEST_SUITE( md_raid_sentence, test::MdFixture )

BOOST_AUTO_TEST_CASE( test_create_format_mount )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID6 );

    BlkFilesystem * fs = raid->create_blk_filesystem( FsType::EXT4 );
    fs->create_mount_point( "/data" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected =
        "Create RAID6 /dev/md0 (1023.75 GiB) for /data with ext4\n"
        "from /dev/sda (512.00 GiB), /dev/sdb (512.00 GiB), /dev/sdc (512.00 GiB), /dev/sdd (512.00 GiB)";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_create_encrypt_format_mount )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID1 );

    Encryption * encryption = raid->create_encryption( "cr_raid0" );
    BlkFilesystem * fs = encryption->create_blk_filesystem( FsType::XFS );
    fs->create_mount_point( "/secret" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected =
        "Create encrypted RAID1 /dev/md0 (511.87 GiB) for /secret with xfs\n"
        "from /dev/sda (512.00 GiB), /dev/sdb (512.00 GiB)";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_create_encrypt_format_no_mount )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID1 );

    Encryption * encryption = raid->create_encryption( "cr_raid0" );
    encryption->create_blk_filesystem( FsType::XFS );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected =
        "Create encrypted RAID1 /dev/md0 (511.87 GiB) with xfs\n"
        "from /dev/sda (512.00 GiB), /dev/sdb (512.00 GiB)";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_just_create )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID1 );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected =
        "Create RAID1 /dev/md0 (511.87 GiB) from /dev/sda (512.00 GiB), /dev/sdb (512.00 GiB)";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_format_mount )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID6 );
    copy_staging_to_probed();

    BlkFilesystem * fs = raid->create_blk_filesystem( FsType::EXT4 );
    fs->create_mount_point( "/data" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected = "Format RAID6 /dev/md0 (1023.75 GiB) for /data with ext4";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_encrypt_format_mount )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID5 );
    copy_staging_to_probed();

    Encryption * encryption = raid->create_encryption( "cr_raid0" );
    BlkFilesystem * fs = encryption->create_blk_filesystem( FsType::XFS );

    fs->create_mount_point( "/data" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected = "Encrypt RAID5 /dev/md0 (1023.75 GiB) for /data with xfs";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_just_mount )
{
    Md * raid = create_raid( "/dev/md0", MdLevel::RAID5 );
    BlkFilesystem * fs = raid->create_blk_filesystem( FsType::EXT4 );
    copy_staging_to_probed();

    fs->create_mount_point( "/data" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected = "Mount RAID5 /dev/md0 (1023.75 GiB) at /data";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_CASE( test_create_encrypted_swap )
{
    Md * raid = create_raid( "/dev/md1", MdLevel::RAID1 );

    Encryption * encryption = raid->create_encryption( "cr_raid1" );
    BlkFilesystem * fs = encryption->create_blk_filesystem( FsType::SWAP );
    fs->create_mount_point( "swap" );

    const Actiongraph	 * actiongraph     = storage->calculate_actiongraph();
    const CompoundAction * compound_action = find_compound_action_by_target( actiongraph, raid );

    BOOST_REQUIRE( compound_action ) ;

    string expected =
        "Create encrypted RAID1 /dev/md1 (511.87 GiB) for swap\n"
        "from /dev/sda (512.00 GiB), /dev/sdb (512.00 GiB)";

    BOOST_CHECK_EQUAL( compound_action->sentence(), expected );

#if 0
    cout << "\nEXPECTED:\n\n" << expected << "\n" << endl;
    cout << "\nACTUAL:\n\n"   << compound_action->sentence() << "\n" << endl;
#endif
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//
// Copyright (c) 2015 Advanced Micro Devices, Inc. All rights reserved.
//
#pragma once

#include "device/pal/palkernel.hpp"
#include "amd_hsa_loader.hpp"

#if defined(WITH_LIGHTNING_COMPILER)
#include "llvm/Support/AMDGPUMetadata.h"

typedef llvm::AMDGPU::HSAMD::Metadata CodeObjectMD;
#endif  // defined(WITH_LIGHTNING_COMPILER)

namespace amd {
namespace option {
class Options;
}  // option
namespace hsa {
namespace loader {
class Loader;
class Executable;
class Context;
}  // loader
}  // hsa
}  // amd

//! \namespace pal PAL Device Implementation
namespace pal {

/*! \addtogroup pal PAL Device Implementation
 *  @{
 */

using namespace amd::hsa::loader;
class HSAILProgram;

class Segment : public amd::HeapObject {
 public:
  Segment();
  ~Segment();

  //! Allocates a segment
  bool alloc(HSAILProgram& prog, amdgpu_hsa_elf_segment_t segment, size_t size, size_t align,
             bool zero);

  //! Copies data from host to the segment
  void copy(size_t offset, const void* src, size_t size);

  //! Segment freeze
  bool freeze(bool destroySysmem);

  //! Returns address for GPU access in the segment
  uint64_t gpuAddress(size_t offset) const { return gpuAccess_->vmAddress() + offset; }

  //! Returns address for CPU access in the segment
  void* cpuAddress(size_t offset) const
    { return ((cpuAccess_ != nullptr) ? cpuAccess_->data() : cpuMem_) + offset; }

  void DestroyCpuAccess();

 private:
  Memory* gpuAccess_;   //!< GPU memory for segment access
  Memory* cpuAccess_;   //!< CPU memory for segment (backing store)
  address cpuMem_;      //!< CPU memory for segment without GPU direct access (backing store)
};

class PALHSALoaderContext final : public Context {
 public:
  PALHSALoaderContext(HSAILProgram* program) : program_(program) {}

  virtual ~PALHSALoaderContext() {}

  hsa_isa_t IsaFromName(const char* name) override;

  bool IsaSupportedByAgent(hsa_agent_t agent, hsa_isa_t isa) override;

  void* SegmentAlloc(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, size_t size, size_t align,
                     bool zero) override;

  bool SegmentCopy(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* dst, size_t offset,
                   const void* src, size_t size) override;

  void SegmentFree(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                   size_t size = 0) override;

  void* SegmentAddress(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                       size_t offset) override;

  void* SegmentHostAddress(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                           size_t offset) override;

  bool SegmentFreeze(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                     size_t size) override;

  bool ImageExtensionSupported() override { return false; }

  hsa_status_t ImageCreate(hsa_agent_t agent, hsa_access_permission_t image_permission,
                           const hsa_ext_image_descriptor_t* image_descriptor,
                           const void* image_data, hsa_ext_image_t* image_handle) override {
    // not supported
    assert(false);
    return HSA_STATUS_ERROR;
  }

  hsa_status_t ImageDestroy(hsa_agent_t agent, hsa_ext_image_t image_handle) override {
    // not supported
    assert(false);
    return HSA_STATUS_ERROR;
  }

  hsa_status_t SamplerCreate(hsa_agent_t agent,
                             const hsa_ext_sampler_descriptor_t* sampler_descriptor,
                             hsa_ext_sampler_t* sampler_handle) override;

  //! All samplers are owned by HSAILProgram and are deleted in its destructor.
  hsa_status_t SamplerDestroy(hsa_agent_t agent, hsa_ext_sampler_t sampler_handle) override;

 private:
  PALHSALoaderContext(const PALHSALoaderContext& c);
  PALHSALoaderContext& operator=(const PALHSALoaderContext& c);

  pal::HSAILProgram* program_;
};

//! \class HSAIL program
class HSAILProgram : public device::Program {
  friend class ClBinary;

 public:
  //! Default constructor
  HSAILProgram(Device& device);
  HSAILProgram(NullDevice& device);
  //! Default destructor
  virtual ~HSAILProgram();

  //! Returns the aclBinary associated with the progrm
  aclBinary* binaryElf() const { return static_cast<aclBinary*>(binaryElf_); }

  void addGlobalStore(Memory* mem) { globalStores_.push_back(mem); }

  void setCodeObjects(Segment* seg, Memory* codeGpu, address codeCpu) {
    codeSegGpu_ = codeGpu;
    codeSegment_ = seg;
  }

  const std::vector<Memory*>& globalStores() const { return globalStores_; }

  //! Return a typecasted GPU device
  pal::Device& dev() { return const_cast<pal::Device&>(static_cast<const pal::Device&>(device())); }

  //! Returns GPU kernel table
  const Memory* kernelTable() const { return kernels_; }

  //! Adds all kernels to the mem handle lists
  void fillResListWithKernels(VirtualGPU& gpu) const;

  //! Returns the maximum number of scratch regs used in the program
  uint maxScratchRegs() const { return maxScratchRegs_; }

  //! Add internal static sampler
  void addSampler(Sampler* sampler) { staticSamplers_.push_back(sampler); }

  //! Returns TRUE if the program just compiled
  bool isNull() const { return isNull_; }

  //! Returns TRUE if the program used internally by runtime
  bool isInternal() const { return internal_; }

  //! Returns TRUE if the program contains static samplers
  bool isStaticSampler() const { return (staticSamplers_.size() != 0); }

  //! Returns code segement on GPU
  const Memory& codeSegGpu() const { return *codeSegGpu_; }

  //! Returns CPU address for a kernel
  uint64_t findHostKernelAddress(uint64_t devAddr) const {
    return loader_->FindHostAddress(devAddr);
  }

 protected:
  //! pre-compile setup for GPU
  virtual bool initBuild(amd::option::Options* options);

  //! post-compile setup for GPU
  virtual bool finiBuild(bool isBuildGood);

  /*! \brief Compiles GPU CL program to LLVM binary (compiler frontend)
  *
  *  \return True if we successefully compiled a GPU program
  */
  virtual bool compileImpl(const std::string& sourceCode,  //!< the program's source code
                           const std::vector<const std::string*>& headers,
                           const char** headerIncludeNames,
                           amd::option::Options* options  //!< compile options's object
                           );

  /* \brief Returns the next stage to compile from, based on sections in binary,
  *  also returns completeStages in a vector, which contains at least ACL_TYPE_DEFAULT,
  *  sets needOptionsCheck to true if options check is needed to decide whether or not to recompile
  */
  aclType getCompilationStagesFromBinary(std::vector<aclType>& completeStages,
                                         bool& needOptionsCheck);

  /* \brief Returns the next stage to compile from, based on sections and options in binary
  */
  aclType getNextCompilationStageFromBinary(amd::option::Options* options);

  bool saveBinaryAndSetType(type_t type);

  virtual bool linkImpl(amd::option::Options* options);

  //! Link the device programs.
  virtual bool linkImpl(const std::vector<device::Program*>& inputPrograms,
                        amd::option::Options* options, bool createLibrary);

  virtual bool createBinary(amd::option::Options* options);

  virtual const aclTargetInfo& info(const char* str = "");

  virtual bool isElf(const char* bin) const {
    return amd::isElfMagic(bin);
  }

  //! Destroys CPU allocations in the code segment
  void DestroySegmentCpuAccess() const { codeSegment_->DestroyCpuAccess(); }

 private:
  //! Disable default copy constructor
  HSAILProgram(const HSAILProgram&);

  //! Disable operator=
  HSAILProgram& operator=(const HSAILProgram&);

 protected:
  //! Allocate kernel table
  bool allocKernelTable();

  std::string openCLSource_;           //!< Original OpenCL source
  std::string HSAILProgram_;           //!< FSAIL program after compilation
  std::string llvmBinary_;             //!< LLVM IR binary code
  aclBinary* binaryElf_;               //!< Binary for the new compiler library
  void* rawBinary_;                    //!< Pointer to the raw binary
  aclBinaryOptions binOpts_;           //!< Binary options to create aclBinary
  std::vector<Memory*> globalStores_;  //!< Global memory for the program
  Memory* kernels_;                    //!< Table with kernel object pointers
  Memory* codeSegGpu_;                 //!< GPU memory with code objects
  Segment*  codeSegment_;              //!< Pointer to the code segment for this program
  uint
      maxScratchRegs_;  //!< Maximum number of scratch regs used in the program by individual kernel
  std::list<Sampler*> staticSamplers_;  //!< List od internal static samplers
  union {
    struct {
      uint32_t isNull_ : 1;    //!< Null program no memory allocations
      uint32_t internal_ : 1;  //!< Internal blit program
    };
    uint32_t flags_;  //!< Program flags
  };
  amd::hsa::loader::Loader* loader_;          //!< Loader object
  amd::hsa::loader::Executable* executable_;  //!< Executable for HSA Loader
  PALHSALoaderContext loaderContext_;         //!< Context for HSA Loader
};

#if defined(WITH_LIGHTNING_COMPILER)
//! \class Lightning Compiler Program
class LightningProgram : public HSAILProgram {
 public:
  LightningProgram(NullDevice& device) : HSAILProgram(device), metadata_(nullptr) {}

  LightningProgram(Device& device) : HSAILProgram(device), metadata_(nullptr) {}

  const CodeObjectMD* metadata() const { return metadata_; }

 private:
  virtual ~LightningProgram();

  /* \brief Returns the next stage to compile from, based on sections in binary,
  *  also returns completeStages in a vector, which contains at least ACL_TYPE_DEFAULT,
  *  sets needOptionsCheck to true if options check is needed to decide whether or not to recompile
  */
  aclType getCompilationStagesFromBinary(std::vector<aclType>& completeStages,
                                         bool& needOptionsCheck);

  /* \brief Returns the next stage to compile from, based on sections and options in binary
  */
  aclType getNextCompilationStageFromBinary(amd::option::Options* options);

 protected:
  virtual bool compileImpl(const std::string& sourceCode,  //!< the program's source code
                           const std::vector<const std::string*>& headers,
                           const char** headerIncludeNames,
                           amd::option::Options* options  //!< compile options's object
                           ) override;

  virtual bool linkImpl(amd::option::Options* options) override;

  //! Link the device programs.
  virtual bool linkImpl(const std::vector<device::Program*>& inputPrograms,
                        amd::option::Options* options, bool createLibrary) override;

  bool setKernels(amd::option::Options* options, void* binary, size_t size);

  virtual bool createBinary(amd::option::Options* options) override;

  //! Return a new transient compiler instance.
  static std::unique_ptr<amd::opencl_driver::Compiler> newCompilerInstance();

 private:
  CodeObjectMD* metadata_;  //!< Runtime metadata
};
#endif  // defined(WITH_LIGHTNING_COMPILER)

/*@}*/} // namespace pal
<commit_msg>P4 to Git Change 1604422 by gandryey@gera-ocl-lc on 2018/09/11 16:51:04<commit_after>//
// Copyright (c) 2015 Advanced Micro Devices, Inc. All rights reserved.
//
#pragma once

#include "device/pal/palkernel.hpp"
#include "amd_hsa_loader.hpp"

#if defined(WITH_LIGHTNING_COMPILER)
#include "llvm/Support/AMDGPUMetadata.h"

typedef llvm::AMDGPU::HSAMD::Metadata CodeObjectMD;
#endif  // defined(WITH_LIGHTNING_COMPILER)

namespace amd {
namespace option {
class Options;
}  // option
namespace hsa {
namespace loader {
class Loader;
class Executable;
class Context;
}  // loader
}  // hsa
}  // amd

//! \namespace pal PAL Device Implementation
namespace pal {

/*! \addtogroup pal PAL Device Implementation
 *  @{
 */

using namespace amd::hsa::loader;
class HSAILProgram;

class Segment : public amd::HeapObject {
 public:
  Segment();
  ~Segment();

  //! Allocates a segment
  bool alloc(HSAILProgram& prog, amdgpu_hsa_elf_segment_t segment, size_t size, size_t align,
             bool zero);

  //! Copies data from host to the segment
  void copy(size_t offset, const void* src, size_t size);

  //! Segment freeze
  bool freeze(bool destroySysmem);

  //! Returns address for GPU access in the segment
  uint64_t gpuAddress(size_t offset) const { return gpuAccess_->vmAddress() + offset; }

  //! Returns address for CPU access in the segment
  void* cpuAddress(size_t offset) const
    { return ((cpuAccess_ != nullptr) ? cpuAccess_->data() : cpuMem_) + offset; }

  void DestroyCpuAccess();

 private:
  Memory* gpuAccess_;   //!< GPU memory for segment access
  Memory* cpuAccess_;   //!< CPU memory for segment (backing store)
  address cpuMem_;      //!< CPU memory for segment without GPU direct access (backing store)
};

class PALHSALoaderContext final : public Context {
 public:
  PALHSALoaderContext(HSAILProgram* program) : program_(program) {}

  virtual ~PALHSALoaderContext() {}

  hsa_isa_t IsaFromName(const char* name) override;

  bool IsaSupportedByAgent(hsa_agent_t agent, hsa_isa_t isa) override;

  void* SegmentAlloc(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, size_t size, size_t align,
                     bool zero) override;

  bool SegmentCopy(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* dst, size_t offset,
                   const void* src, size_t size) override;

  void SegmentFree(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                   size_t size = 0) override;

  void* SegmentAddress(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                       size_t offset) override;

  void* SegmentHostAddress(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                           size_t offset) override;

  bool SegmentFreeze(amdgpu_hsa_elf_segment_t segment, hsa_agent_t agent, void* seg,
                     size_t size) override;

  bool ImageExtensionSupported() override { return false; }

  hsa_status_t ImageCreate(hsa_agent_t agent, hsa_access_permission_t image_permission,
                           const hsa_ext_image_descriptor_t* image_descriptor,
                           const void* image_data, hsa_ext_image_t* image_handle) override {
    // not supported
    assert(false);
    return HSA_STATUS_ERROR;
  }

  hsa_status_t ImageDestroy(hsa_agent_t agent, hsa_ext_image_t image_handle) override {
    // not supported
    assert(false);
    return HSA_STATUS_ERROR;
  }

  hsa_status_t SamplerCreate(hsa_agent_t agent,
                             const hsa_ext_sampler_descriptor_t* sampler_descriptor,
                             hsa_ext_sampler_t* sampler_handle) override;

  //! All samplers are owned by HSAILProgram and are deleted in its destructor.
  hsa_status_t SamplerDestroy(hsa_agent_t agent, hsa_ext_sampler_t sampler_handle) override;

 private:
  PALHSALoaderContext(const PALHSALoaderContext& c);
  PALHSALoaderContext& operator=(const PALHSALoaderContext& c);

  pal::HSAILProgram* program_;
};

//! \class HSAIL program
class HSAILProgram : public device::Program {
  friend class ClBinary;

 public:
  //! Default constructor
  HSAILProgram(Device& device);
  HSAILProgram(NullDevice& device);
  //! Default destructor
  virtual ~HSAILProgram();

  //! Returns the aclBinary associated with the progrm
  aclBinary* binaryElf() const { return static_cast<aclBinary*>(binaryElf_); }

  void addGlobalStore(Memory* mem) { globalStores_.push_back(mem); }

  void setCodeObjects(Segment* seg, Memory* codeGpu, address codeCpu) {
    codeSegGpu_ = codeGpu;
    codeSegment_ = seg;
  }

  const std::vector<Memory*>& globalStores() const { return globalStores_; }

  //! Return a typecasted GPU device
  pal::Device& dev() { return const_cast<pal::Device&>(static_cast<const pal::Device&>(device())); }

  //! Returns GPU kernel table
  const Memory* kernelTable() const { return kernels_; }

  //! Adds all kernels to the mem handle lists
  void fillResListWithKernels(VirtualGPU& gpu) const;

  //! Returns the maximum number of scratch regs used in the program
  uint maxScratchRegs() const { return maxScratchRegs_; }

  //! Add internal static sampler
  void addSampler(Sampler* sampler) { staticSamplers_.push_back(sampler); }

  //! Returns TRUE if the program just compiled
  bool isNull() const { return isNull_; }

  //! Returns TRUE if the program used internally by runtime
  bool isInternal() const { return internal_; }

  //! Returns TRUE if the program contains static samplers
  bool isStaticSampler() const { return (staticSamplers_.size() != 0); }

  //! Returns code segement on GPU
  const Memory& codeSegGpu() const { return *codeSegGpu_; }

  //! Returns CPU address for a kernel
  uint64_t findHostKernelAddress(uint64_t devAddr) const {
    return loader_->FindHostAddress(devAddr);
  }

 protected:
  //! pre-compile setup for GPU
  virtual bool initBuild(amd::option::Options* options);

  //! post-compile setup for GPU
  virtual bool finiBuild(bool isBuildGood);

  /*! \brief Compiles GPU CL program to LLVM binary (compiler frontend)
  *
  *  \return True if we successefully compiled a GPU program
  */
  virtual bool compileImpl(const std::string& sourceCode,  //!< the program's source code
                           const std::vector<const std::string*>& headers,
                           const char** headerIncludeNames,
                           amd::option::Options* options  //!< compile options's object
                           );

  /* \brief Returns the next stage to compile from, based on sections in binary,
  *  also returns completeStages in a vector, which contains at least ACL_TYPE_DEFAULT,
  *  sets needOptionsCheck to true if options check is needed to decide whether or not to recompile
  */
  aclType getCompilationStagesFromBinary(std::vector<aclType>& completeStages,
                                         bool& needOptionsCheck);

  /* \brief Returns the next stage to compile from, based on sections and options in binary
  */
  aclType getNextCompilationStageFromBinary(amd::option::Options* options);

  bool saveBinaryAndSetType(type_t type);

  virtual bool linkImpl(amd::option::Options* options);

  //! Link the device programs.
  virtual bool linkImpl(const std::vector<device::Program*>& inputPrograms,
                        amd::option::Options* options, bool createLibrary);

  virtual bool createBinary(amd::option::Options* options);

  virtual const aclTargetInfo& info(const char* str = "");

  virtual bool isElf(const char* bin) const {
    return amd::isElfMagic(bin);
  }

  //! Destroys CPU allocations in the code segment
  void DestroySegmentCpuAccess() const
    { if (!isNull()) { codeSegment_->DestroyCpuAccess(); } }

 private:
  //! Disable default copy constructor
  HSAILProgram(const HSAILProgram&);

  //! Disable operator=
  HSAILProgram& operator=(const HSAILProgram&);

 protected:
  //! Allocate kernel table
  bool allocKernelTable();

  std::string openCLSource_;           //!< Original OpenCL source
  std::string HSAILProgram_;           //!< FSAIL program after compilation
  std::string llvmBinary_;             //!< LLVM IR binary code
  aclBinary* binaryElf_;               //!< Binary for the new compiler library
  void* rawBinary_;                    //!< Pointer to the raw binary
  aclBinaryOptions binOpts_;           //!< Binary options to create aclBinary
  std::vector<Memory*> globalStores_;  //!< Global memory for the program
  Memory* kernels_;                    //!< Table with kernel object pointers
  Memory* codeSegGpu_;                 //!< GPU memory with code objects
  Segment*  codeSegment_;              //!< Pointer to the code segment for this program
  uint
      maxScratchRegs_;  //!< Maximum number of scratch regs used in the program by individual kernel
  std::list<Sampler*> staticSamplers_;  //!< List od internal static samplers
  union {
    struct {
      uint32_t isNull_ : 1;    //!< Null program no memory allocations
      uint32_t internal_ : 1;  //!< Internal blit program
    };
    uint32_t flags_;  //!< Program flags
  };
  amd::hsa::loader::Loader* loader_;          //!< Loader object
  amd::hsa::loader::Executable* executable_;  //!< Executable for HSA Loader
  PALHSALoaderContext loaderContext_;         //!< Context for HSA Loader
};

#if defined(WITH_LIGHTNING_COMPILER)
//! \class Lightning Compiler Program
class LightningProgram : public HSAILProgram {
 public:
  LightningProgram(NullDevice& device) : HSAILProgram(device), metadata_(nullptr) {}

  LightningProgram(Device& device) : HSAILProgram(device), metadata_(nullptr) {}

  const CodeObjectMD* metadata() const { return metadata_; }

 private:
  virtual ~LightningProgram();

  /* \brief Returns the next stage to compile from, based on sections in binary,
  *  also returns completeStages in a vector, which contains at least ACL_TYPE_DEFAULT,
  *  sets needOptionsCheck to true if options check is needed to decide whether or not to recompile
  */
  aclType getCompilationStagesFromBinary(std::vector<aclType>& completeStages,
                                         bool& needOptionsCheck);

  /* \brief Returns the next stage to compile from, based on sections and options in binary
  */
  aclType getNextCompilationStageFromBinary(amd::option::Options* options);

 protected:
  virtual bool compileImpl(const std::string& sourceCode,  //!< the program's source code
                           const std::vector<const std::string*>& headers,
                           const char** headerIncludeNames,
                           amd::option::Options* options  //!< compile options's object
                           ) override;

  virtual bool linkImpl(amd::option::Options* options) override;

  //! Link the device programs.
  virtual bool linkImpl(const std::vector<device::Program*>& inputPrograms,
                        amd::option::Options* options, bool createLibrary) override;

  bool setKernels(amd::option::Options* options, void* binary, size_t size);

  virtual bool createBinary(amd::option::Options* options) override;

  //! Return a new transient compiler instance.
  static std::unique_ptr<amd::opencl_driver::Compiler> newCompilerInstance();

 private:
  CodeObjectMD* metadata_;  //!< Runtime metadata
};
#endif  // defined(WITH_LIGHTNING_COMPILER)

/*@}*/} // namespace pal
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "bvh4.h"
#include "bvh4_builder_hair_new.h"
#include "builders_new/primrefgen.h"

#include "geometry/bezier1v.h"
#include "geometry/bezier1i.h"

#include "common/profile.h"

namespace embree
{
  namespace isa
  {
    static const size_t MAX_BRANCHING_FACTOR = 16;  //!< maximal supported BVH branching factor
    static const size_t MIN_LARGE_LEAF_LEVELS = 8;  //!< create balanced tree of we are that many levels before the maximal tree depth

    template<typename Primitive>
    BVH4BuilderHairNew<Primitive>::BVH4BuilderHairNew (BVH4* bvh, Scene* scene, size_t mode)
      : scene(scene), maxDepth(BVH4::maxBuildDepthLeaf), minLeafSize(1), maxLeafSize(BVH4::maxLeafBlocks), bvh(bvh) {}

    template<typename Primitive>
    BVH4::NodeRef BVH4BuilderHairNew<Primitive>::createLeaf(size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc)
    {
      /*if (g_verbose >= 2) {
        static atomic_t N = 0;
        size_t n = atomic_add(&N,pinfo.size());
        if (n>1024) { std::cout << "." << std::flush; N = 0; }
        }*/

      size_t items = pinfo.size();
      size_t start = pinfo.begin;
      Primitive* accel = (Primitive*) alloc->alloc1.malloc(items*sizeof(Primitive));
      BVH4::NodeRef node = bvh->encodeLeaf((char*)accel,items);
      for (size_t i=0; i<items; i++) {
        accel[i].fill(prims.data(),start,pinfo.end,bvh->scene,false);
      }
      return node;
    }

    template<typename Primitive>
    BVH4::NodeRef BVH4BuilderHairNew<Primitive>::createLargeLeaf(size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc)
    {
      //if (current.depth > maxDepth)
      //  THROW_RUNTIME_ERROR("depth limit reached");

      /* create leaf for few primitives */
      if (pinfo.size() <= maxLeafSize)
        return createLeaf(depth,pinfo,alloc);

      /* fill all children by always splitting the largest one */
      //ReductionTy values[MAX_BRANCHING_FACTOR];
      //PrimInfo* pchildren[MAX_BRANCHING_FACTOR];
      PrimInfo children[BVH4::N]; //MAX_BRANCHING_FACTOR];
      size_t numChildren = 1;
      children[0] = pinfo;
      //pchildren[0] = &children[0];

      do {

        /* find best child with largest bounding box area */
        int bestChild = -1;
        int bestSize = 0;
        for (size_t i=0; i<numChildren; i++)
        {
          /* ignore leaves as they cannot get split */
          if (children[i].size() <= maxLeafSize)
            continue;

          /* remember child with largest size */
          if (children[i].size() > bestSize) {
            bestSize = children[i].size();
            bestChild = i;
          }
        }
        if (bestChild == -1) break;

        /*! split best child into left and right child */
        __aligned(64) PrimInfo left, right;
        alignedHeuristic.splitFallback(children[bestChild],left,right);

        /* add new children left and right */
        //left.init(pinfo.depth+1);
        //right.init(pinfo.depth+1);
        children[bestChild] = children[numChildren-1];
        children[numChildren-1] = left;
        children[numChildren+0] = right;
        //pchildren[numChildren] = &children[numChildren];
        numChildren++;

      } while (numChildren < BVH4::N); // branchingFactor);

      /* create node */
      //auto node = createNode(pinfo,pchildren,numChildren,alloc);
      //BVH4::Node* node = bvh->allocNode(alloc);
      BVH4::Node* node = (BVH4::Node*) alloc->alloc0.malloc(sizeof(BVH4::Node),16); node->clear();
      for (size_t i=0; i<numChildren; i++) {
        node->set(i,children[i].geomBounds);
        node->set(i,createLargeLeaf(depth+1,children[i],alloc));
      }
      return BVH4::encodeNode(node);

      /* recurse into each child */
      //for (size_t i=0; i<numChildren; i++)
      //values[i] = createLargeLeaf(children[i],alloc);

      /* perform reduction */
      //return updateNode(node,values,numChildren);
    }

    template<typename Primitive>
    bool BVH4BuilderHairNew<Primitive>::split(const PrimInfo& pinfo, PrimInfo& linfo, PrimInfo& rinfo)
    {
      /* variable to track the SAH of the best splitting approach */
      float bestSAH = inf;
      const float leafSAH = BVH4::intCost*float(pinfo.size())*halfArea(pinfo.geomBounds);

      /* perform standard binning in aligned space */
      float alignedObjectSAH = inf;
      HeuristicArrayBinningSAH<BezierPrim>::Split alignedObjectSplit;
      //if (pinfo.size() > 100) {
        alignedObjectSplit = alignedHeuristic.find(pinfo,0);
        alignedObjectSAH = BVH4::travCostAligned*halfArea(pinfo.geomBounds) + BVH4::intCost*alignedObjectSplit.splitSAH();
        bestSAH = min(alignedObjectSAH,bestSAH);
        //}

      /* perform standard binning in unaligned space */
      UnalignedHeuristicArrayBinningSAH<BezierPrim>::Split unalignedObjectSplit;
      LinearSpace3fa uspace;
      float unalignedObjectSAH = inf;
      //if (alignedObjectSAH > 0.7f*leafSAH) {
      //if (pinfo.size() <= 100) {
        uspace = unalignedHeuristic.computeAlignedSpace(pinfo);
        const PrimInfo       sinfo = unalignedHeuristic.computePrimInfo(pinfo,uspace);
        unalignedObjectSplit = unalignedHeuristic.find(sinfo,0,uspace);
        unalignedObjectSAH = BVH4::travCostUnaligned*halfArea(pinfo.geomBounds) + BVH4::intCost*unalignedObjectSplit.splitSAH();
        bestSAH = min(unalignedObjectSAH,bestSAH);
        //}

      /* perform best split */
      if (bestSAH == float(inf)) {
        alignedHeuristic.splitFallback(pinfo,linfo,rinfo);
        return true;
      }
      else if (bestSAH == alignedObjectSAH) {
        alignedHeuristic.split(alignedObjectSplit,pinfo,linfo,rinfo);
        return true;
      }
      else if (bestSAH == unalignedObjectSAH) {
        unalignedHeuristic.split(unalignedObjectSplit,uspace,pinfo,linfo,rinfo);
        return false;
      }
      else {
        THROW_RUNTIME_ERROR("bvh4hair_builder: internal error"); // FIXME: remove
        return true;
      }
    }

    template<typename Primitive>
    BVH4::NodeRef BVH4BuilderHairNew<Primitive>::recurse(size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc)
    {
      if (alloc == NULL)
        //alloc = createAlloc();
        alloc = bvh->alloc2.threadLocal2();

      //ReductionTy values[MAX_BRANCHING_FACTOR];
      //PrimInfo children[MAX_BRANCHING_FACTOR];
      PrimInfo children[BVH4::N];
      //__aligned(64) PrimInfo children[MAX_BRANCHING_FACTOR];

      /* create leaf node */
      if (depth+MIN_LARGE_LEAF_LEVELS >= maxDepth || pinfo.size() <= minLeafSize) {
        alignedHeuristic.deterministic_order(pinfo);
        return createLargeLeaf(depth,pinfo,alloc);
      }

      /* fill all children by always splitting the one with the largest surface area */
      size_t numChildren = 1;
      children[0] = pinfo;
      //pchildren[0] = &children[0];
      bool aligned = true;

      do {

        /* find best child with largest bounding box area */
        int bestChild = -1;
        float bestArea = neg_inf;
        for (size_t i=0; i<numChildren; i++)
        {
          /* ignore leaves as they cannot get split */
          if (children[i].size() <= minLeafSize)
            continue;

          /* remember child with largest area */
          if (area(children[i].geomBounds) > bestArea) {
            bestArea = area(children[i].geomBounds);
            bestChild = i;
          }
        }
        if (bestChild == -1) break;

        /*! split best child into left and right child */
        PrimInfo left, right;
        aligned &= split(children[bestChild],left,right);

        /* add new children left and right */
        //left.init(current.depth+1);
        //right.init(current.depth+1);
        children[bestChild] = children[numChildren-1];
        children[numChildren-1] = left;
        children[numChildren+0] = right;
        //pchildren[numChildren] = &children[numChildren];
        numChildren++;

      } while (numChildren < BVH4::N); //branchingFactor);
      assert(numChildren > 1);

      /* create node */
      //auto node = createNode(current,pchildren,numChildren,alloc);

      /* create aligned node */
      if (aligned)
      {
        //BVH4::Node* node = bvh->allocNode(alloc);
        BVH4::Node* node = (BVH4::Node*) alloc->alloc0.malloc(sizeof(BVH4::Node),16); node->clear();

        for (size_t i=0; i<numChildren; i++)
          node->set(i,children[i].geomBounds);

        /* spawn tasks or ... */
        if (pinfo.size() > 4096)
        {
          SPAWN_BEGIN;
          for (size_t i=0; i<numChildren; i++)
            SPAWN(([&,i] { node->child(i) = recurse(depth+1,children[i],NULL); }));
          SPAWN_END;
        }
        /* ... continue sequential */
        else {
          for (size_t i=0; i<numChildren; i++)
            node->child(i) = recurse(depth+1,children[i],alloc);
        }
        return BVH4::encodeNode(node);
      }

      /* create unaligned node */
      else
      {
        //BVH4::UnalignedNode* node = bvh->allocUnalignedNode(alloc);
        BVH4::UnalignedNode* node = (BVH4::UnalignedNode*) alloc->alloc0.malloc(sizeof(BVH4::UnalignedNode),16); node->clear();
        for (size_t i=0; i<numChildren; i++)
        {
          const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]);
          const PrimInfo       sinfo = unalignedHeuristic.computePrimInfo(children[i],space);
          node->set(i,NAABBox3fa(space,sinfo.geomBounds));
        }

        /* spawn tasks or ... */
        if (pinfo.size() > 4096)
        {
          SPAWN_BEGIN;
          for (size_t i=0; i<numChildren; i++)
            SPAWN(([&,i] { node->child(i) = recurse(depth+1,children[i],NULL); }));
          SPAWN_END;
        }
        /* ... continue sequential */
        else {
          for (size_t i=0; i<numChildren; i++)
            node->child(i) = recurse(depth+1,children[i],alloc);
        }
        return BVH4::encodeNode(node);
      }
    }

    template<typename Primitive>
    void BVH4BuilderHairNew<Primitive>::build(size_t threadIndex, size_t threadCount)
    {
      /* fast path for empty BVH */
      const size_t numPrimitives = scene->getNumPrimitives<BezierCurves,1>();
      if (numPrimitives == 0) {
        prims.resize(0,true);
        bvh->set(BVH4::emptyNode,empty,0);
        return;
      }

      double t0 = 0.0;
      if (g_verbose >= 2) {
        std::cout << "building BVH4<" + bvh->primTy.name + "> using " << TOSTRING(isa) << "::BVH4BuilderHairNew ..." << std::flush;
        t0 = getSeconds();
      }

      //profile(1,5,numPrimitives,[&] (ProfileTimer& timer) {

          /* create primref array */
          bvh->alloc2.init(numPrimitives*sizeof(Primitive));
          prims.resize(numPrimitives);
          new (  &alignedHeuristic)          HeuristicArrayBinningSAH<BezierPrim>(prims.data());
          new (&unalignedHeuristic) UnalignedHeuristicArrayBinningSAH<BezierPrim>(prims.data());

          const PrimInfo pinfo = createBezierRefArray<1>(scene,prims);
          const BVH4::NodeRef root = recurse(1,pinfo,NULL);
          bvh->set(root,pinfo.geomBounds,pinfo.size());

          // timer("BVH4BuilderHairNew");
          //});

      /* clear temporary data for static geometry */
      const bool staticGeom = scene->isStatic();
      if (staticGeom) prims.resize(0,true);
      bvh->alloc2.cleanup();

      if (g_verbose >= 2) {
        double t1 = getSeconds();
        std::cout << " [DONE]" << std::endl;
        std::cout << "  dt = " << 1000.0f*(t1-t0) << "ms, perf = " << 1E-6*double(numPrimitives)/(t1-t0) << " Mprim/s" << std::endl;
        bvh->printStatistics();
      }
    }

    /*! entry functions for the builder */
    Builder* BVH4Bezier1vBuilder_OBB_New (void* bvh, Scene* scene, size_t mode) { return new BVH4BuilderHairNew<Bezier1v>((BVH4*)bvh,scene,mode); }
    Builder* BVH4Bezier1iBuilder_OBB_New (void* bvh, Scene* scene, size_t mode) { return new BVH4BuilderHairNew<Bezier1i>((BVH4*)bvh,scene,mode); }
  }
}
<commit_msg>cleanups<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "bvh4.h"
#include "bvh4_builder_hair_new.h"
#include "builders_new/primrefgen.h"

#include "geometry/bezier1v.h"
#include "geometry/bezier1i.h"

#include "common/profile.h"

namespace embree
{
  namespace isa
  {
    static const size_t MAX_BRANCHING_FACTOR = 16;  //!< maximal supported BVH branching factor
    static const size_t MIN_LARGE_LEAF_LEVELS = 8;  //!< create balanced tree of we are that many levels before the maximal tree depth

    template<typename Primitive>
    BVH4BuilderHairNew<Primitive>::BVH4BuilderHairNew (BVH4* bvh, Scene* scene, size_t mode)
      : scene(scene), maxDepth(BVH4::maxBuildDepthLeaf), minLeafSize(1), maxLeafSize(BVH4::maxLeafBlocks), bvh(bvh) {}

    template<typename Primitive>
    BVH4::NodeRef BVH4BuilderHairNew<Primitive>::createLeaf(size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc)
    {
      /*if (g_verbose >= 2) {
        static atomic_t N = 0;
        size_t n = atomic_add(&N,pinfo.size());
        if (n>1024) { std::cout << "." << std::flush; N = 0; }
        }*/

      size_t items = pinfo.size();
      size_t start = pinfo.begin;
      Primitive* accel = (Primitive*) alloc->alloc1.malloc(items*sizeof(Primitive));
      BVH4::NodeRef node = bvh->encodeLeaf((char*)accel,items);
      for (size_t i=0; i<items; i++) {
        accel[i].fill(prims.data(),start,pinfo.end,bvh->scene,false);
      }
      return node;
    }

    template<typename Primitive>
    BVH4::NodeRef BVH4BuilderHairNew<Primitive>::createLargeLeaf(size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc)
    {
      //if (current.depth > maxDepth)
      //  THROW_RUNTIME_ERROR("depth limit reached");

      /* create leaf for few primitives */
      if (pinfo.size() <= maxLeafSize)
        return createLeaf(depth,pinfo,alloc);

      /* fill all children by always splitting the largest one */
      //ReductionTy values[MAX_BRANCHING_FACTOR];
      //PrimInfo* pchildren[MAX_BRANCHING_FACTOR];
      PrimInfo children[BVH4::N]; //MAX_BRANCHING_FACTOR];
      size_t numChildren = 1;
      children[0] = pinfo;
      //pchildren[0] = &children[0];

      do {

        /* find best child with largest bounding box area */
        int bestChild = -1;
        int bestSize = 0;
        for (size_t i=0; i<numChildren; i++)
        {
          /* ignore leaves as they cannot get split */
          if (children[i].size() <= maxLeafSize)
            continue;

          /* remember child with largest size */
          if (children[i].size() > bestSize) {
            bestSize = children[i].size();
            bestChild = i;
          }
        }
        if (bestChild == -1) break;

        /*! split best child into left and right child */
        __aligned(64) PrimInfo left, right;
        alignedHeuristic.splitFallback(children[bestChild],left,right);

        /* add new children left and right */
        //left.init(pinfo.depth+1);
        //right.init(pinfo.depth+1);
        children[bestChild] = children[numChildren-1];
        children[numChildren-1] = left;
        children[numChildren+0] = right;
        //pchildren[numChildren] = &children[numChildren];
        numChildren++;

      } while (numChildren < BVH4::N); // branchingFactor);

      /* create node */
      //auto node = createNode(pinfo,pchildren,numChildren,alloc);
      //BVH4::Node* node = bvh->allocNode(alloc);
      BVH4::Node* node = (BVH4::Node*) alloc->alloc0.malloc(sizeof(BVH4::Node),16); node->clear();
      for (size_t i=0; i<numChildren; i++) {
        node->set(i,children[i].geomBounds);
        node->set(i,createLargeLeaf(depth+1,children[i],alloc));
      }
      return BVH4::encodeNode(node);

      /* recurse into each child */
      //for (size_t i=0; i<numChildren; i++)
      //values[i] = createLargeLeaf(children[i],alloc);

      /* perform reduction */
      //return updateNode(node,values,numChildren);
    }

    template<typename Primitive>
    bool BVH4BuilderHairNew<Primitive>::split(const PrimInfo& pinfo, PrimInfo& linfo, PrimInfo& rinfo)
    {
      /* variable to track the SAH of the best splitting approach */
      float bestSAH = inf;
      const float leafSAH = BVH4::intCost*float(pinfo.size())*halfArea(pinfo.geomBounds);

      /* perform standard binning in aligned space */
      float alignedObjectSAH = inf;
      HeuristicArrayBinningSAH<BezierPrim>::Split alignedObjectSplit;
      //if (pinfo.size() > 100) {
        alignedObjectSplit = alignedHeuristic.find(pinfo,0);
        alignedObjectSAH = BVH4::travCostAligned*halfArea(pinfo.geomBounds) + BVH4::intCost*alignedObjectSplit.splitSAH();
        bestSAH = min(alignedObjectSAH,bestSAH);
        //}

      /* perform standard binning in unaligned space */
      UnalignedHeuristicArrayBinningSAH<BezierPrim>::Split unalignedObjectSplit;
      LinearSpace3fa uspace;
      float unalignedObjectSAH = inf;
      //if (alignedObjectSAH > 0.7f*leafSAH) {
      //if (pinfo.size() <= 100) {
        uspace = unalignedHeuristic.computeAlignedSpace(pinfo);
        const PrimInfo       sinfo = unalignedHeuristic.computePrimInfo(pinfo,uspace);
        unalignedObjectSplit = unalignedHeuristic.find(sinfo,0,uspace);
        unalignedObjectSAH = BVH4::travCostUnaligned*halfArea(pinfo.geomBounds) + BVH4::intCost*unalignedObjectSplit.splitSAH();
        bestSAH = min(unalignedObjectSAH,bestSAH);
        //}

      /* perform aligned split if this is best */
      if (bestSAH == alignedObjectSAH) {
        alignedHeuristic.split(alignedObjectSplit,pinfo,linfo,rinfo);
        return true;
      }
      /* perform unaligned split if this is best */
      else if (bestSAH == unalignedObjectSAH) {
        unalignedHeuristic.split(unalignedObjectSplit,uspace,pinfo,linfo,rinfo);
        return false;
      }
      /* otherwise perform fallback split */
      else {
        alignedHeuristic.deterministic_order(pinfo);
        alignedHeuristic.splitFallback(pinfo,linfo,rinfo);
        return true;
      }
    }

    template<typename Primitive>
    BVH4::NodeRef BVH4BuilderHairNew<Primitive>::recurse(size_t depth, const PrimInfo& pinfo, FastAllocator::ThreadLocal2* alloc)
    {
      if (alloc == NULL)
        alloc = bvh->alloc2.threadLocal2();

      //ReductionTy values[MAX_BRANCHING_FACTOR];
      PrimInfo children[BVH4::N];

      /* create leaf node */
      if (depth+MIN_LARGE_LEAF_LEVELS >= maxDepth || pinfo.size() <= minLeafSize) {
        alignedHeuristic.deterministic_order(pinfo);
        return createLargeLeaf(depth,pinfo,alloc);
      }

      /* fill all children by always splitting the one with the largest surface area */
      size_t numChildren = 1;
      children[0] = pinfo;
      bool aligned = true;

      do {

        /* find best child with largest bounding box area */
        int bestChild = -1;
        float bestArea = neg_inf;
        for (size_t i=0; i<numChildren; i++)
        {
          /* ignore leaves as they cannot get split */
          if (children[i].size() <= minLeafSize)
            continue;

          /* remember child with largest area */
          if (area(children[i].geomBounds) > bestArea) {
            bestArea = area(children[i].geomBounds);
            bestChild = i;
          }
        }
        if (bestChild == -1) break;

        /*! split best child into left and right child */
        PrimInfo left, right;
        aligned &= split(children[bestChild],left,right);

        /* add new children left and right */
        children[bestChild] = children[numChildren-1];
        children[numChildren-1] = left;
        children[numChildren+0] = right;
        numChildren++;

      } while (numChildren < BVH4::N);
      assert(numChildren > 1);

      /* create aligned node */
      if (aligned)
      {
        BVH4::Node* node = (BVH4::Node*) alloc->alloc0.malloc(sizeof(BVH4::Node),16); node->clear();

        for (size_t i=0; i<numChildren; i++)
          node->set(i,children[i].geomBounds);

        /* spawn tasks or ... */
        if (pinfo.size() > 4096)
        {
          SPAWN_BEGIN;
          for (size_t i=0; i<numChildren; i++)
            SPAWN(([&,i] { node->child(i) = recurse(depth+1,children[i],NULL); }));
          SPAWN_END;
        }
        /* ... continue sequential */
        else {
          for (size_t i=0; i<numChildren; i++)
            node->child(i) = recurse(depth+1,children[i],alloc);
        }
        return BVH4::encodeNode(node);
      }

      /* create unaligned node */
      else
      {
        BVH4::UnalignedNode* node = (BVH4::UnalignedNode*) alloc->alloc0.malloc(sizeof(BVH4::UnalignedNode),16); node->clear();
        for (size_t i=0; i<numChildren; i++)
        {
          const LinearSpace3fa space = unalignedHeuristic.computeAlignedSpace(children[i]);
          const PrimInfo       sinfo = unalignedHeuristic.computePrimInfo(children[i],space);
          node->set(i,NAABBox3fa(space,sinfo.geomBounds));
        }

        /* spawn tasks or ... */
        if (pinfo.size() > 4096)
        {
          SPAWN_BEGIN;
          for (size_t i=0; i<numChildren; i++)
            SPAWN(([&,i] { node->child(i) = recurse(depth+1,children[i],NULL); }));
          SPAWN_END;
        }
        /* ... continue sequential */
        else {
          for (size_t i=0; i<numChildren; i++)
            node->child(i) = recurse(depth+1,children[i],alloc);
        }
        return BVH4::encodeNode(node);
      }
    }

    template<typename Primitive>
    void BVH4BuilderHairNew<Primitive>::build(size_t threadIndex, size_t threadCount)
    {
      /* fast path for empty BVH */
      const size_t numPrimitives = scene->getNumPrimitives<BezierCurves,1>();
      if (numPrimitives == 0) {
        prims.resize(0,true);
        bvh->set(BVH4::emptyNode,empty,0);
        return;
      }

      double t0 = 0.0;
      if (g_verbose >= 2) {
        std::cout << "building BVH4<" + bvh->primTy.name + "> using " << TOSTRING(isa) << "::BVH4BuilderHairNew ..." << std::flush;
        t0 = getSeconds();
      }

      //profile(1,5,numPrimitives,[&] (ProfileTimer& timer) {

          /* create primref array */
          bvh->alloc2.init(numPrimitives*sizeof(Primitive));
          prims.resize(numPrimitives);
          new (  &alignedHeuristic)          HeuristicArrayBinningSAH<BezierPrim>(prims.data());
          new (&unalignedHeuristic) UnalignedHeuristicArrayBinningSAH<BezierPrim>(prims.data());

          const PrimInfo pinfo = createBezierRefArray<1>(scene,prims);
          const BVH4::NodeRef root = recurse(1,pinfo,NULL);
          bvh->set(root,pinfo.geomBounds,pinfo.size());

          // timer("BVH4BuilderHairNew");
          //});

      /* clear temporary data for static geometry */
      const bool staticGeom = scene->isStatic();
      if (staticGeom) prims.resize(0,true);
      bvh->alloc2.cleanup();

      if (g_verbose >= 2) {
        double t1 = getSeconds();
        std::cout << " [DONE]" << std::endl;
        std::cout << "  dt = " << 1000.0f*(t1-t0) << "ms, perf = " << 1E-6*double(numPrimitives)/(t1-t0) << " Mprim/s" << std::endl;
        bvh->printStatistics();
      }
    }

    /*! entry functions for the builder */
    Builder* BVH4Bezier1vBuilder_OBB_New (void* bvh, Scene* scene, size_t mode) { return new BVH4BuilderHairNew<Bezier1v>((BVH4*)bvh,scene,mode); }
    Builder* BVH4Bezier1iBuilder_OBB_New (void* bvh, Scene* scene, size_t mode) { return new BVH4BuilderHairNew<Bezier1i>((BVH4*)bvh,scene,mode); }
  }
}
<|endoftext|>