<commit_before>/*
-------------------------------------------------------------------------
   This file is part of BayesOpt, an efficient C++ library for
   Bayesian optimization.

   Copyright (C) 2011-2015 Ruben Martinez-Cantin <rmcantin@unizar.es>

   BayesOpt is free software: you can redistribute it and/or modify it
   under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOpt 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 Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with BayesOpt.  If not, see <http://www.gnu.org/licenses/>.
------------------------------------------------------------------------
*/

#include <ctime>
#include "bayesopt/bayesoptbase.hpp"
#include "bayesopt/parameters.hpp"

#include "log.hpp"
#include "posteriormodel.hpp"
#include "specialtypes.hpp"
#include "bopt_state.hpp"

namespace bayesopt
{
  BayesOptBase::BayesOptBase(size_t dim, Parameters parameters):
    mParameters(parameters), mDims(dim)
  {
    // Random seed
    if (mParameters.random_seed < 0) mParameters.random_seed = std::time(0);
    mEngine.seed(mParameters.random_seed);

    // Setting verbose stuff (files, levels, etc.)
    int verbose = mParameters.verbose_level;
    if (verbose>=3)
      {
	FILE* log_fd = fopen( mParameters.log_filename.c_str() , "w" );
	Output2FILE::Stream() = log_fd;
	verbose -= 3;
      }

    switch(verbose)
      {
      case 0: FILELog::ReportingLevel() = logWARNING; break;
      case 1: FILELog::ReportingLevel() = logINFO; break;
      case 2: FILELog::ReportingLevel() = logDEBUG4; break;
      default:
	FILELog::ReportingLevel() = logERROR; break;
      }
  }

  BayesOptBase::~BayesOptBase()
  { } // Default destructor

  // OPTIMIZATION INTERFACE
  void BayesOptBase::optimize(vectord &bestPoint)
  {
    assert(mDims == bestPoint.size());

    // Restore state from file
    if(mParameters.load_save_flag == 1 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        bool load_succeed = state.loadFromFile(mParameters.load_filename,
					       mParameters);
        if(load_succeed)
	  {
            restoreOptimization(state);
            FILE_LOG(logINFO) << "State succesfully restored from file \""
			      << mParameters.load_filename << "\"";
	  }
        else
	  {
	    // If load not succeed, print info message and then
	    // initialize a new optimization
            FILE_LOG(logINFO) << "File \"" << mParameters.load_filename
			      << "\" does not exist,"
			      << " starting a new optimization";
            initializeOptimization();
	  }
      }
    else
      {
	// Initialize a new state
        initializeOptimization();
      }

    for (size_t ii = mCurrentIter; ii < mParameters.n_iterations; ++ii)
      {
        stepOptimization();
      }

    bestPoint = getFinalResult();
  } // optimize

  void BayesOptBase::stepOptimization()
  {
    // Find what is the next point.
    vectord xNext = nextPoint();
    double yNext = evaluateSampleInternal(xNext);

    // If we are stuck in the same point for several iterations, try a random jump!
    if (mParameters.force_jump)
      {
        if (std::pow(mYPrev - yNext,2) < mParameters.noise)
          {
            mCounterStuck++;
            FILE_LOG(logDEBUG) << "Stuck for "<< mCounterStuck << " steps";
          }
        else
          {
            mCounterStuck = 0;
          }
        mYPrev = yNext;

        if (mCounterStuck > mParameters.force_jump)
          {
            FILE_LOG(logINFO) << "Forced random query!";
            xNext = samplePoint();
            yNext = evaluateSampleInternal(xNext);
            mCounterStuck = 0;
          }
      }

    mModel->addSample(xNext,yNext);

    // Update surrogate model
    bool retrain = ((mParameters.n_iter_relearn > 0) &&
		    ((mCurrentIter + 1) % mParameters.n_iter_relearn == 0));

    if (retrain)  // Full update
      {
        mModel->updateHyperParameters();
        mModel->fitSurrogateModel();
      }
    else          // Incremental update
      {
        mModel->updateSurrogateModel();
      }

    plotStepData(mCurrentIter,xNext,yNext);
    mModel->updateCriteria(xNext);
    mCurrentIter++;

    // Save state if required
    if(mParameters.load_save_flag == 2 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        saveOptimization(state);
        state.saveToFile(mParameters.save_filename);
      }
  }

  void BayesOptBase::initializeOptimization()
  {
    // Posterior surrogate model
    mModel.reset(PosteriorModel::create(mDims,mParameters,mEngine));

    // Configure iteration parameters
    if (mParameters.n_init_samples <= 0)
      {
        mParameters.n_init_samples =
          static_cast<size_t>(ceil(0.1*mParameters.n_iterations));
      }

    size_t nSamples = mParameters.n_init_samples;

    // Generate xPoints for initial sampling
    matrixd xPoints(nSamples,mDims);
    vectord yPoints(nSamples,0);

    // Save generated xPoints before its evaluation
    generateInitialPoints(xPoints);
    saveInitialSamples(xPoints);

    // Save on each evaluation for safety reasons
    for(size_t i=0; i<yPoints.size(); i++)
      {
        yPoints[i] = evaluateSample(row(xPoints,i));
	//We clear the vector in the first iteration
        saveResponse(yPoints[i], i==0);
      }

    // Put samples into model
    mModel->setSamples(xPoints,yPoints);

    if(mParameters.verbose_level > 0)
      {
        mModel->plotDataset(logDEBUG);
      }

    mModel->updateHyperParameters();
    mModel->fitSurrogateModel();
    mCurrentIter = 0;

    mCounterStuck = 0;
    mYPrev = 0.0;
  }

  vectord BayesOptBase::getFinalResult()
  {
    return remapPoint(getPointAtMinimum());
  }

  // SAVE-RESTORE INTERFACE
  void BayesOptBase::saveOptimization(BOptState &state)
  {
    // BayesOptBase members
    state.mCurrentIter = mCurrentIter;
    state.mCounterStuck = mCounterStuck;
    state.mYPrev = mYPrev;

    state.mParameters = mParameters;

    // Samples
    state.mX = mModel->getData()->mX;
    state.mY = mModel->getData()->mY;
  }

  void BayesOptBase::restoreOptimization(BOptState state)
  {
    // Restore parameters
    mParameters = state.mParameters;

    // Posterior surrogate model
    mModel.reset(PosteriorModel::create(mDims, mParameters, mEngine));

    // Load samples, putting mX vecOfvec into a matrixd
    matrixd xPoints(state.mX.size(),state.mX[0].size());
    vectord yPoints(state.mX.size(),0);
    for(size_t i=0; i<state.mX.size(); i++)
      {
        row(xPoints, i) = state.mX[i];
        if(i < state.mY.size())
	  {
            yPoints[i] = state.mY[i];
	  }
	else
	  {
	    // Generate remaining initial samples saving in each evaluation
	    yPoints[i] = evaluateSample(row(xPoints,i));
	    saveResponse(yPoints[i], false);
	  }
      }

    // Set loaded and generated samples
    mModel->setSamples(xPoints,yPoints);

    if(mParameters.verbose_level > 0)
    {
        mModel->plotDataset(logDEBUG);
    }

    // Calculate the posterior model
    mModel->updateHyperParameters();
    mModel->fitSurrogateModel();

    mCurrentIter = state.mCurrentIter;
    mCounterStuck = state.mCounterStuck;
    mYPrev = state.mYPrev;

    // Check if optimization has already finished
    if(mCurrentIter >= mParameters.n_iterations)
      {
        FILE_LOG(logINFO) << "Optimization has already finished, delete \""
			  << mParameters.load_filename
			  << "\" or give more n_iterations in parameters.";
      }
  }

  // GETTERS AND SETTERS
  // Potential inline functions. Moved here to simplify API and header
  // structure.
  ProbabilityDistribution* BayesOptBase::getPrediction(const vectord& query)
  { return mModel->getPrediction(query); };

  const Dataset* BayesOptBase::getData()
  { return mModel->getData(); };

  Parameters* BayesOptBase::getParameters()
  {return &mParameters;};

  double BayesOptBase::getValueAtMinimum()
  { return mModel->getValueAtMinimum(); };

  double BayesOptBase::evaluateCriteria(const vectord& query)
  {
    if (checkReachability(query)) return mModel->evaluateCriteria(query);
    else return 0.0;
  }

  size_t BayesOptBase::getCurrentIter()
  {return mCurrentIter;};

  // PROTECTED
  vectord BayesOptBase::getPointAtMinimum()
  { return mModel->getPointAtMinimum(); };

  double BayesOptBase::evaluateSampleInternal( const vectord &query )
  {
    const double yNext = evaluateSample(remapPoint(query));
    if (yNext == HUGE_VAL)
      {
	throw std::runtime_error("Function evaluation out of range");
      }
    return yNext;
  };

  void BayesOptBase::plotStepData(size_t iteration, const vectord& xNext,
				     double yNext)
  {
    if(mParameters.verbose_level >0)
      {
	FILE_LOG(logINFO) << "Iteration: " << iteration+1 << " of "
			  << mParameters.n_iterations << " | Total samples: "
			  << iteration+1+mParameters.n_init_samples ;
	FILE_LOG(logINFO) << "Query: "         << remapPoint(xNext); ;
	FILE_LOG(logINFO) << "Query outcome: " << yNext ;
	FILE_LOG(logINFO) << "Best query: "    << getFinalResult();
	FILE_LOG(logINFO) << "Best outcome: "  << getValueAtMinimum();
      }
  } //plotStepData

  void BayesOptBase::saveInitialSamples(matrixd xPoints)
  {
    // Save state if required
    if(mParameters.load_save_flag == 2 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        saveOptimization(state);

        // Overwrite the state with initial samples so far
        state.mX.clear();
        for(size_t i=0; i<xPoints.size1(); i++)
	  {
            state.mX.push_back(row(xPoints,i));
	  }
        state.saveToFile(mParameters.save_filename);
      }
  }

  void BayesOptBase::saveResponse(double yPoint, bool clear)
  {
    // Save state if required
    if(mParameters.load_save_flag == 2 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        saveOptimization(state);
	if (clear)
	  {
	    state.mY.clear();
	  }
	utils::append(state.mY,yPoint);
        state.saveToFile(mParameters.save_filename);
      }
  }

  // PRIVATE MEMBERS
  vectord BayesOptBase::nextPoint()
  {
    //Epsilon-Greedy exploration (see Bull 2011)
    if ((mParameters.epsilon > 0.0) && (mParameters.epsilon < 1.0))
      {
	randFloat drawSample(mEngine,realUniformDist(0,1));
	double result = drawSample();
	FILE_LOG(logINFO) << "Trying random jump with prob:" << result;
	if (mParameters.epsilon > result)
	  {
	    FILE_LOG(logINFO) << "Epsilon-greedy random query!";
	    return samplePoint();
	  }
      }

    vectord Xnext(mDims);

    // GP-Hedge and related algorithms
    if (mModel->criteriaRequiresComparison())
      {
	bool changed = true;

	mModel->setFirstCriterium();
	while (changed)
	  {
	    findOptimal(Xnext);
	    changed = mModel->setNextCriterium(Xnext);
	  }
	std::string name = mModel->getBestCriteria(Xnext);
	FILE_LOG(logINFO) << name << " was selected.";
      }
    else  // Standard "Bayesian optimization"
      {
	FILE_LOG(logDEBUG) << "------ Optimizing criteria ------";
	findOptimal(Xnext);
      }
    return Xnext;
  }

} //namespace bayesopt

<commit_msg>Fixed bug in initial values not being rescaled properly<commit_after>/*
-------------------------------------------------------------------------
   This file is part of BayesOpt, an efficient C++ library for
   Bayesian optimization.

   Copyright (C) 2011-2015 Ruben Martinez-Cantin <rmcantin@unizar.es>

   BayesOpt is free software: you can redistribute it and/or modify it
   under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOpt 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 Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with BayesOpt.  If not, see <http://www.gnu.org/licenses/>.
------------------------------------------------------------------------
*/

#include <ctime>
#include "bayesopt/bayesoptbase.hpp"
#include "bayesopt/parameters.hpp"

#include "log.hpp"
#include "posteriormodel.hpp"
#include "specialtypes.hpp"
#include "bopt_state.hpp"

namespace bayesopt
{
  BayesOptBase::BayesOptBase(size_t dim, Parameters parameters):
    mParameters(parameters), mDims(dim)
  {
    // Random seed
    if (mParameters.random_seed < 0) mParameters.random_seed = std::time(0);
    mEngine.seed(mParameters.random_seed);

    // Setting verbose stuff (files, levels, etc.)
    int verbose = mParameters.verbose_level;
    if (verbose>=3)
      {
	FILE* log_fd = fopen( mParameters.log_filename.c_str() , "w" );
	Output2FILE::Stream() = log_fd;
	verbose -= 3;
      }

    switch(verbose)
      {
      case 0: FILELog::ReportingLevel() = logWARNING; break;
      case 1: FILELog::ReportingLevel() = logINFO; break;
      case 2: FILELog::ReportingLevel() = logDEBUG4; break;
      default:
	FILELog::ReportingLevel() = logERROR; break;
      }
  }

  BayesOptBase::~BayesOptBase()
  { } // Default destructor

  // OPTIMIZATION INTERFACE
  void BayesOptBase::optimize(vectord &bestPoint)
  {
    assert(mDims == bestPoint.size());

    // Restore state from file
    if(mParameters.load_save_flag == 1 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        bool load_succeed = state.loadFromFile(mParameters.load_filename,
					       mParameters);
        if(load_succeed)
	  {
            restoreOptimization(state);
            FILE_LOG(logINFO) << "State succesfully restored from file \""
			      << mParameters.load_filename << "\"";
	  }
        else
	  {
	    // If load not succeed, print info message and then
	    // initialize a new optimization
            FILE_LOG(logINFO) << "File \"" << mParameters.load_filename
			      << "\" does not exist,"
			      << " starting a new optimization";
            initializeOptimization();
	  }
      }
    else
      {
	// Initialize a new state
        initializeOptimization();
      }

    for (size_t ii = mCurrentIter; ii < mParameters.n_iterations; ++ii)
      {
        stepOptimization();
      }

    bestPoint = getFinalResult();
  } // optimize

  void BayesOptBase::stepOptimization()
  {
    // Find what is the next point.
    vectord xNext = nextPoint();
    double yNext = evaluateSampleInternal(xNext);

    // If we are stuck in the same point for several iterations, try a random jump!
    if (mParameters.force_jump)
      {
        if (std::pow(mYPrev - yNext,2) < mParameters.noise)
          {
            mCounterStuck++;
            FILE_LOG(logDEBUG) << "Stuck for "<< mCounterStuck << " steps";
          }
        else
          {
            mCounterStuck = 0;
          }
        mYPrev = yNext;

        if (mCounterStuck > mParameters.force_jump)
          {
            FILE_LOG(logINFO) << "Forced random query!";
            xNext = samplePoint();
            yNext = evaluateSampleInternal(xNext);
            mCounterStuck = 0;
          }
      }

    mModel->addSample(xNext,yNext);

    // Update surrogate model
    bool retrain = ((mParameters.n_iter_relearn > 0) &&
		    ((mCurrentIter + 1) % mParameters.n_iter_relearn == 0));

    if (retrain)  // Full update
      {
        mModel->updateHyperParameters();
        mModel->fitSurrogateModel();
      }
    else          // Incremental update
      {
        mModel->updateSurrogateModel();
      }

    plotStepData(mCurrentIter,xNext,yNext);
    mModel->updateCriteria(xNext);
    mCurrentIter++;

    // Save state if required
    if(mParameters.load_save_flag == 2 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        saveOptimization(state);
        state.saveToFile(mParameters.save_filename);
      }
  }

  void BayesOptBase::initializeOptimization()
  {
    // Posterior surrogate model
    mModel.reset(PosteriorModel::create(mDims,mParameters,mEngine));

    // Configure iteration parameters
    if (mParameters.n_init_samples <= 0)
      {
        mParameters.n_init_samples =
          static_cast<size_t>(ceil(0.1*mParameters.n_iterations));
      }

    size_t nSamples = mParameters.n_init_samples;

    // Generate xPoints for initial sampling
    matrixd xPoints(nSamples,mDims);
    vectord yPoints(nSamples,0);

    // Save generated xPoints before its evaluation
    generateInitialPoints(xPoints);
    saveInitialSamples(xPoints);

    // Save on each evaluation for safety reasons
    for(size_t i=0; i<yPoints.size(); i++)
      {
        yPoints[i] = evaluateSampleInternal(row(xPoints,i));
	//We clear the vector in the first iteration
        saveResponse(yPoints[i], i==0);
      }

    // Put samples into model
    mModel->setSamples(xPoints,yPoints);

    if(mParameters.verbose_level > 0)
      {
        mModel->plotDataset(logDEBUG);
      }

    mModel->updateHyperParameters();
    mModel->fitSurrogateModel();
    mCurrentIter = 0;

    mCounterStuck = 0;
    mYPrev = 0.0;
  }

  vectord BayesOptBase::getFinalResult()
  {
    return remapPoint(getPointAtMinimum());
  }

  // SAVE-RESTORE INTERFACE
  void BayesOptBase::saveOptimization(BOptState &state)
  {
    // BayesOptBase members
    state.mCurrentIter = mCurrentIter;
    state.mCounterStuck = mCounterStuck;
    state.mYPrev = mYPrev;

    state.mParameters = mParameters;

    // Samples
    state.mX = mModel->getData()->mX;
    state.mY = mModel->getData()->mY;
  }

  void BayesOptBase::restoreOptimization(BOptState state)
  {
    // Restore parameters
    mParameters = state.mParameters;

    // Posterior surrogate model
    mModel.reset(PosteriorModel::create(mDims, mParameters, mEngine));

    // Load samples, putting mX vecOfvec into a matrixd
    matrixd xPoints(state.mX.size(),state.mX[0].size());
    vectord yPoints(state.mX.size(),0);
    for(size_t i=0; i<state.mX.size(); i++)
      {
        row(xPoints, i) = state.mX[i];
        if(i < state.mY.size())
	  {
            yPoints[i] = state.mY[i];
	  }
	else
	  {
	    // Generate remaining initial samples saving in each evaluation
	    yPoints[i] = evaluateSampleInternal(row(xPoints,i));
	    saveResponse(yPoints[i], false);
	  }
      }

    // Set loaded and generated samples
    mModel->setSamples(xPoints,yPoints);

    if(mParameters.verbose_level > 0)
    {
        mModel->plotDataset(logDEBUG);
    }

    // Calculate the posterior model
    mModel->updateHyperParameters();
    mModel->fitSurrogateModel();

    mCurrentIter = state.mCurrentIter;
    mCounterStuck = state.mCounterStuck;
    mYPrev = state.mYPrev;

    // Check if optimization has already finished
    if(mCurrentIter >= mParameters.n_iterations)
      {
        FILE_LOG(logINFO) << "Optimization has already finished, delete \""
			  << mParameters.load_filename
			  << "\" or give more n_iterations in parameters.";
      }
  }

  // GETTERS AND SETTERS
  // Potential inline functions. Moved here to simplify API and header
  // structure.
  ProbabilityDistribution* BayesOptBase::getPrediction(const vectord& query)
  { return mModel->getPrediction(query); };

  const Dataset* BayesOptBase::getData()
  { return mModel->getData(); };

  Parameters* BayesOptBase::getParameters()
  {return &mParameters;};

  double BayesOptBase::getValueAtMinimum()
  { return mModel->getValueAtMinimum(); };

  double BayesOptBase::evaluateCriteria(const vectord& query)
  {
    if (checkReachability(query)) return mModel->evaluateCriteria(query);
    else return 0.0;
  }

  size_t BayesOptBase::getCurrentIter()
  {return mCurrentIter;};

  // PROTECTED
  vectord BayesOptBase::getPointAtMinimum()
  { return mModel->getPointAtMinimum(); };

  double BayesOptBase::evaluateSampleInternal( const vectord &query )
  {
    const double yNext = evaluateSample(remapPoint(query));
    if (yNext == HUGE_VAL)
      {
	throw std::runtime_error("Function evaluation out of range");
      }
    return yNext;
  };

  void BayesOptBase::plotStepData(size_t iteration, const vectord& xNext,
				     double yNext)
  {
    if(mParameters.verbose_level >0)
      {
	FILE_LOG(logINFO) << "Iteration: " << iteration+1 << " of "
			  << mParameters.n_iterations << " | Total samples: "
			  << iteration+1+mParameters.n_init_samples ;
	FILE_LOG(logINFO) << "Query: "         << remapPoint(xNext); ;
	FILE_LOG(logINFO) << "Query outcome: " << yNext ;
	FILE_LOG(logINFO) << "Best query: "    << getFinalResult();
	FILE_LOG(logINFO) << "Best outcome: "  << getValueAtMinimum();
      }
  } //plotStepData

  void BayesOptBase::saveInitialSamples(matrixd xPoints)
  {
    // Save state if required
    if(mParameters.load_save_flag == 2 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        saveOptimization(state);

        // Overwrite the state with initial samples so far
        state.mX.clear();
        for(size_t i=0; i<xPoints.size1(); i++)
	  {
            state.mX.push_back(row(xPoints,i));
	  }
        state.saveToFile(mParameters.save_filename);
      }
  }

  void BayesOptBase::saveResponse(double yPoint, bool clear)
  {
    // Save state if required
    if(mParameters.load_save_flag == 2 || mParameters.load_save_flag == 3)
      {
        BOptState state;
        saveOptimization(state);
	if (clear)
	  {
	    state.mY.clear();
	  }
	utils::append(state.mY,yPoint);
        state.saveToFile(mParameters.save_filename);
      }
  }

  // PRIVATE MEMBERS
  vectord BayesOptBase::nextPoint()
  {
    //Epsilon-Greedy exploration (see Bull 2011)
    if ((mParameters.epsilon > 0.0) && (mParameters.epsilon < 1.0))
      {
	randFloat drawSample(mEngine,realUniformDist(0,1));
	double result = drawSample();
	FILE_LOG(logINFO) << "Trying random jump with prob:" << result;
	if (mParameters.epsilon > result)
	  {
	    FILE_LOG(logINFO) << "Epsilon-greedy random query!";
	    return samplePoint();
	  }
      }

    vectord Xnext(mDims);

    // GP-Hedge and related algorithms
    if (mModel->criteriaRequiresComparison())
      {
	bool changed = true;

	mModel->setFirstCriterium();
	while (changed)
	  {
	    findOptimal(Xnext);
	    changed = mModel->setNextCriterium(Xnext);
	  }
	std::string name = mModel->getBestCriteria(Xnext);
	FILE_LOG(logINFO) << name << " was selected.";
      }
    else  // Standard "Bayesian optimization"
      {
	FILE_LOG(logDEBUG) << "------ Optimizing criteria ------";
	findOptimal(Xnext);
      }
    return Xnext;
  }

} //namespace bayesopt

<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep07/call_mss_eff_config.C $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file call_mss_eff_config.C
 *  Contains the wrapper for mss_eff_config istep
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#include    <stdint.h>
#include    <map>

#include    <trace/interface.H>
#include    <initservice/taskargs.H>
#include    <errl/errlentry.H>

#include    <isteps/hwpisteperror.H>
#include    <errl/errludtarget.H>

#include    <initservice/isteps_trace.H>

//  targeting support
#include    <targeting/common/commontargeting.H>
#include    <targeting/common/utilFilter.H>

#include    <config.h>
#include    <fapi2.H>
#include    <fapi2/plat_hwp_invoker.H>

// HWP
#include    <p9_mss_eff_config.H>
#include    <p9_mss_eff_config_thermal.H>
#include    <p9_mss_eff_grouping.H>

namespace   ISTEP_07
{

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;

errlHndl_t call_mss_eff_grouping(IStepError & io_istepErr)
{
    errlHndl_t l_err = NULL;

    TARGETING::TargetHandleList l_procsList;
    getAllChips(l_procsList, TYPE_PROC);

    for (const auto & l_cpu_target : l_procsList)
    {
        //  print call to hwp and write HUID of the target(s)
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "p9_mss_eff_grouping HWP cpu target HUID %.8X",
            TARGETING::get_huid(l_cpu_target));

        // cast OUR type of target to a FAPI type of target.
        const fapi2::Target <fapi2::TARGET_TYPE_PROC_CHIP> l_fapi_cpu_target
            (l_cpu_target);

        FAPI_INVOKE_HWP(l_err, p9_mss_eff_grouping, l_fapi_cpu_target);

        //  process return code.
        if ( l_err )
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "ERROR 0x%.8X:  p9_mss_eff_grouping HWP on target %.8x",
                l_err->reasonCode(), TARGETING::get_huid(l_cpu_target));

            // capture the target data in the elog
            ErrlUserDetailsTarget(l_cpu_target).addToLog(l_err);
            io_istepErr.addErrorDetails(l_err);
            errlCommit(l_err, HWPF_COMP_ID);
        }
        else
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "SUCCESS :  p9_mss_eff_grouping HWP on target %.8x",
                TARGETING::get_huid(l_cpu_target));
        }
    }   // end processor list processing

    return l_err;
}

errlHndl_t call_mss_eff_mb_interleave()
{
    errlHndl_t l_err = NULL;
/* TOOD RTC: 144076 --- cumulus only ---
    TARGETING::TargetHandleList l_membufTargetList;
    getAllChips(l_membufTargetList, TYPE_MEMBUF);

    for (const auto & l_membuf_target : l_membufTargetList)
    {
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                "=====  Running mss_eff_mb_interleave HWP on HUID %.8X",
                TARGETING::get_huid(l_membuf_target));
        fapi::Target l_membuf_fapi_target(fapi::TARGET_TYPE_MEMBUF_CHIP,
                    (const_cast<TARGETING::Target*>(l_membuf_target)) );
        FAPI_INVOKE_HWP(l_err, mss_eff_mb_interleave, l_membuf_fapi_target);
        if (l_err)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "ERROR 0x%.8X: mss_eff_mb_interleave HWP returns error",
                      l_err->reasonCode());
            ErrlUserDetailsTarget(l_membuf_target).addToLog(l_err);
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "Successfully ran mss_eff_mb_interleave HWP on HUID %.8X",
                      TARGETING::get_huid(l_membuf_target));
        }
    }
*/
    return l_err;
}

//
//  Wrapper function to call mss_eff_config
//
void*    call_mss_eff_config( void *io_pArgs )
{
    IStepError l_StepError;
    errlHndl_t l_err = NULL;

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config entry" );

    TARGETING::Target* l_sys = NULL;
    targetService().getTopLevelTarget(l_sys);
    assert( l_sys != NULL );

    // The attribute ATTR_MEM_MIRROR_PLACEMENT_POLICY should already be
    // correctly set by default for all platforms except for sapphire.
    // Don't allow mirroring on sapphire yet @todo-RTC:108314
    //
    //ATTR_PAYLOAD_IN_MIRROR_MEM_type l_mirrored =
    //    l_sys->getAttr<ATTR_PAYLOAD_IN_MIRROR_MEM>();
    //
    //if(l_mirrored && is_sapphire_load())
    //{
    //    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "Mirroring is enabled");

    //    uint8_t l_mmPolicy =
    //        fapi::ENUM_ATTR_MEM_MIRROR_PLACEMENT_POLICY_FLIPPED;
    //    l_sys->
    //        setAttr<TARGETING::ATTR_MEM_MIRROR_PLACEMENT_POLICY>(l_mmPolicy);
    //}

    // Get all functional MCS chiplets
    TARGETING::TargetHandleList l_mcsTargetList;
    getAllChiplets(l_mcsTargetList, TYPE_MCS);

    // Iterate over all MCS, calling mss_eff_config and mss_eff_config_thermal
    for (const auto & l_mcs_target : l_mcsTargetList)
    {
        // Get the TARGETING::Target pointer and its HUID
        uint32_t l_huid = TARGETING::get_huid(l_mcs_target);

        // Create a FAPI target representing the MCS
        const fapi2::Target <fapi2::TARGET_TYPE_MCS> l_fapi_mcs_target
            (l_mcs_target);

        // Call the mss_eff_config HWP
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "p9_mss_eff_config HWP. MCS HUID %.8X", l_huid);
        FAPI_INVOKE_HWP(l_err, p9_mss_eff_config, l_fapi_mcs_target);

        if (l_err)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                "ERROR 0x%.8X:  p9_mss_eff_config HWP ", l_err->reasonCode());

            // Ensure istep error created and has same plid as this error
            ErrlUserDetailsTarget(l_mcs_target).addToLog(l_err);
            l_StepError.addErrorDetails(l_err);
            errlCommit(l_err, HWPF_COMP_ID);
            continue;
        }

        TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
            "SUCCESS :  p9_mss_eff_config HWP");
    } // end membuf loop

    std::map<ATTR_VDDR_ID_type,TARGETING::TargetHandleList> l_domainIdGroups;
    TARGETING::TargetHandleList l_mcbistTargetList;
    getAllChiplets(l_mcsTargetList, TYPE_MCBIST);

    // Iterate over all MCBIST, calling mss_eff_config_thermal
    for (const auto & l_mcbist_target : l_mcbistTargetList)
    {
        TARGETING::TargetHandleList l_mcsChildren;
        getChildChiplets(l_mcsChildren,l_mcbist_target, TARGETING::TYPE_MCS);

        ATTR_VDDR_ID_type l_vddr_id = l_mcbist_target->getAttr<ATTR_VDDR_ID>();
        if(l_domainIdGroups.find(l_vddr_id) == l_domainIdGroups.end())
        {
            std::pair<ATTR_VDDR_ID_type, TARGETING::TargetHandleList> tuple(l_vddr_id, l_mcsChildren);
            l_domainIdGroups.insert(tuple);
        }
        else
        {
            l_domainIdGroups[l_vddr_id].insert(l_domainIdGroups[l_vddr_id].end(), l_mcsChildren.begin(), l_mcsChildren.end());
        }
    }

    for (auto & l_tuple : l_domainIdGroups)
    {
        std::vector<fapi2::Target<fapi2::TARGET_TYPE_MCS>> l_fapi_mcs_targs;
        for(const auto & l_mcs_target : l_tuple.second)
        {
            // Create a FAPI target representing the MCS
            const fapi2::Target <fapi2::TARGET_TYPE_MCS> l_fapi_mcs_target
            (l_mcs_target);
            l_fapi_mcs_targs.push_back(l_fapi_mcs_target);
        }
        // Call the mss_eff_config_thermal HWP
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                   "p9_mss_eff_config_thermal HWP. ");
        FAPI_INVOKE_HWP(l_err, p9_mss_eff_config_thermal,l_fapi_mcs_targs);

        if (l_err)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                        "ERROR 0x%.8X:  p9_mss_eff_config_thermal HWP ",
                        l_err->reasonCode());

            // Ensure istep error created and has same plid as this error
            l_StepError.addErrorDetails(l_err);
            errlCommit(l_err, HWPF_COMP_ID);
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                        "SUCCESS : p9_mss_eff_config_thermal HWP");
        }
    }

    if (l_StepError.isNull())
    {
        // Stack the memory on each chip
        l_err = call_mss_eff_grouping(l_StepError);

        // TODO RTC: 144076
        //if(!l_err) //Cumulus only
        //{
        //    l_err = call_mss_eff_mb_interleave();
        //}

        if (l_err)
        {
            // Ensure istep error created and has same plid as this error
            l_StepError.addErrorDetails( l_err );
            errlCommit( l_err, HWPF_COMP_ID );
        }
    }

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config exit" );
    return l_StepError.getErrorHandle();
}
};   // end namespace
<commit_msg>Fix bugs to allow p9_mss_eff_config_thermal to be executed<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep07/call_mss_eff_config.C $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file call_mss_eff_config.C
 *  Contains the wrapper for mss_eff_config istep
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#include    <stdint.h>
#include    <map>

#include    <trace/interface.H>
#include    <initservice/taskargs.H>
#include    <errl/errlentry.H>

#include    <isteps/hwpisteperror.H>
#include    <errl/errludtarget.H>

#include    <initservice/isteps_trace.H>

//  targeting support
#include    <targeting/common/commontargeting.H>
#include    <targeting/common/utilFilter.H>

#include    <config.h>
#include    <fapi2.H>
#include    <fapi2/plat_hwp_invoker.H>

// HWP
#include    <p9_mss_eff_config.H>
#include    <p9_mss_eff_config_thermal.H>
#include    <p9_mss_eff_grouping.H>

namespace   ISTEP_07
{

using   namespace   ISTEP;
using   namespace   ISTEP_ERROR;
using   namespace   ERRORLOG;
using   namespace   TARGETING;

errlHndl_t call_mss_eff_grouping(IStepError & io_istepErr)
{
    errlHndl_t l_err = NULL;

    TARGETING::TargetHandleList l_procsList;
    getAllChips(l_procsList, TYPE_PROC);

    for (const auto & l_cpu_target : l_procsList)
    {
        //  print call to hwp and write HUID of the target(s)
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "p9_mss_eff_grouping HWP cpu target HUID %.8X",
            TARGETING::get_huid(l_cpu_target));

        // cast OUR type of target to a FAPI type of target.
        const fapi2::Target <fapi2::TARGET_TYPE_PROC_CHIP> l_fapi_cpu_target
            (l_cpu_target);

        FAPI_INVOKE_HWP(l_err, p9_mss_eff_grouping, l_fapi_cpu_target);

        //  process return code.
        if ( l_err )
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "ERROR 0x%.8X:  p9_mss_eff_grouping HWP on target %.8x",
                l_err->reasonCode(), TARGETING::get_huid(l_cpu_target));

            // capture the target data in the elog
            ErrlUserDetailsTarget(l_cpu_target).addToLog(l_err);
            io_istepErr.addErrorDetails(l_err);
            errlCommit(l_err, HWPF_COMP_ID);
        }
        else
        {
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "SUCCESS :  p9_mss_eff_grouping HWP on target %.8x",
                TARGETING::get_huid(l_cpu_target));
        }
    }   // end processor list processing

    return l_err;
}

errlHndl_t call_mss_eff_mb_interleave()
{
    errlHndl_t l_err = NULL;
/* TOOD RTC: 144076 --- cumulus only ---
    TARGETING::TargetHandleList l_membufTargetList;
    getAllChips(l_membufTargetList, TYPE_MEMBUF);

    for (const auto & l_membuf_target : l_membufTargetList)
    {
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                "=====  Running mss_eff_mb_interleave HWP on HUID %.8X",
                TARGETING::get_huid(l_membuf_target));
        fapi::Target l_membuf_fapi_target(fapi::TARGET_TYPE_MEMBUF_CHIP,
                    (const_cast<TARGETING::Target*>(l_membuf_target)) );
        FAPI_INVOKE_HWP(l_err, mss_eff_mb_interleave, l_membuf_fapi_target);
        if (l_err)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "ERROR 0x%.8X: mss_eff_mb_interleave HWP returns error",
                      l_err->reasonCode());
            ErrlUserDetailsTarget(l_membuf_target).addToLog(l_err);
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "Successfully ran mss_eff_mb_interleave HWP on HUID %.8X",
                      TARGETING::get_huid(l_membuf_target));
        }
    }
*/
    return l_err;
}

//
//  Wrapper function to call mss_eff_config
//
void*    call_mss_eff_config( void *io_pArgs )
{
    IStepError l_StepError;
    errlHndl_t l_err = NULL;

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config entry" );

    TARGETING::Target* l_sys = NULL;
    targetService().getTopLevelTarget(l_sys);
    assert( l_sys != NULL );

    // The attribute ATTR_MEM_MIRROR_PLACEMENT_POLICY should already be
    // correctly set by default for all platforms except for sapphire.
    // Don't allow mirroring on sapphire yet @todo-RTC:108314
    //
    //ATTR_PAYLOAD_IN_MIRROR_MEM_type l_mirrored =
    //    l_sys->getAttr<ATTR_PAYLOAD_IN_MIRROR_MEM>();
    //
    //if(l_mirrored && is_sapphire_load())
    //{
    //    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "Mirroring is enabled");

    //    uint8_t l_mmPolicy =
    //        fapi::ENUM_ATTR_MEM_MIRROR_PLACEMENT_POLICY_FLIPPED;
    //    l_sys->
    //        setAttr<TARGETING::ATTR_MEM_MIRROR_PLACEMENT_POLICY>(l_mmPolicy);
    //}

    // Get all functional MCS chiplets
    TARGETING::TargetHandleList l_mcsTargetList;
    getAllChiplets(l_mcsTargetList, TYPE_MCS);

    // Iterate over all MCS, calling mss_eff_config and mss_eff_config_thermal
    for (const auto & l_mcs_target : l_mcsTargetList)
    {
        // Get the TARGETING::Target pointer and its HUID
        uint32_t l_huid = TARGETING::get_huid(l_mcs_target);

        // Create a FAPI target representing the MCS
        const fapi2::Target <fapi2::TARGET_TYPE_MCS> l_fapi_mcs_target
            (l_mcs_target);

        // Call the mss_eff_config HWP
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "p9_mss_eff_config HWP. MCS HUID %.8X", l_huid);
        FAPI_INVOKE_HWP(l_err, p9_mss_eff_config, l_fapi_mcs_target);

        if (l_err)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                "ERROR 0x%.8X:  p9_mss_eff_config HWP ", l_err->reasonCode());

            // Ensure istep error created and has same plid as this error
            ErrlUserDetailsTarget(l_mcs_target).addToLog(l_err);
            l_StepError.addErrorDetails(l_err);
            errlCommit(l_err, HWPF_COMP_ID);
            continue;
        }

        TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
            "SUCCESS :  p9_mss_eff_config HWP");
    } // end membuf loop

    std::map<ATTR_VDDR_ID_type,TARGETING::TargetHandleList> l_domainIdGroups;
    TARGETING::TargetHandleList l_mcbistTargetList;
    getAllChiplets(l_mcbistTargetList, TYPE_MCBIST);

    // Iterate over all MCBIST, calling mss_eff_config_thermal
    for (const auto & l_mcbist_target : l_mcbistTargetList)
    {
        TARGETING::TargetHandleList l_mcsChildren;
        getChildChiplets(l_mcsChildren,l_mcbist_target, TARGETING::TYPE_MCS);

        ATTR_VDDR_ID_type l_vddr_id = l_mcbist_target->getAttr<ATTR_VDDR_ID>();
        if(l_domainIdGroups.find(l_vddr_id) == l_domainIdGroups.end())
        {
            std::pair<ATTR_VDDR_ID_type, TARGETING::TargetHandleList> tuple(l_vddr_id, l_mcsChildren);
            l_domainIdGroups.insert(tuple);
        }
        else
        {
            l_domainIdGroups[l_vddr_id].insert(l_domainIdGroups[l_vddr_id].end(), l_mcsChildren.begin(), l_mcsChildren.end());
        }
    }

    for (auto & l_tuple : l_domainIdGroups)
    {
        std::vector<fapi2::Target<fapi2::TARGET_TYPE_MCS>> l_fapi_mcs_targs;
        for(const auto & l_mcs_target : l_tuple.second)
        {
            // Create a FAPI target representing the MCS
            const fapi2::Target <fapi2::TARGET_TYPE_MCS> l_fapi_mcs_target
            (l_mcs_target);
            l_fapi_mcs_targs.push_back(l_fapi_mcs_target);
        }
        // Call the mss_eff_config_thermal HWP
        TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                   "p9_mss_eff_config_thermal HWP. ");
        FAPI_INVOKE_HWP(l_err, p9_mss_eff_config_thermal,l_fapi_mcs_targs);

        if (l_err)
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                        "ERROR 0x%.8X:  p9_mss_eff_config_thermal HWP ",
                        l_err->reasonCode());

            // Ensure istep error created and has same plid as this error
            l_StepError.addErrorDetails(l_err);
            errlCommit(l_err, HWPF_COMP_ID);
        }
        else
        {
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                        "SUCCESS : p9_mss_eff_config_thermal HWP");
        }
    }

    if (l_StepError.isNull())
    {
        // Stack the memory on each chip
        l_err = call_mss_eff_grouping(l_StepError);

        // TODO RTC: 144076
        //if(!l_err) //Cumulus only
        //{
        //    l_err = call_mss_eff_mb_interleave();
        //}

        if (l_err)
        {
            // Ensure istep error created and has same plid as this error
            l_StepError.addErrorDetails( l_err );
            errlCommit( l_err, HWPF_COMP_ID );
        }
    }

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace, "call_mss_eff_config exit" );
    return l_StepError.getErrorHandle();
}
};   // end namespace
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep08/call_host_setup_sbe.C $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file call_host_setup_sbe.C
 *
 *  Support file for IStep: slave_sbe
 *   Slave SBE
 *
 *  HWP_IGNORE_VERSION_CHECK
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#include <stdint.h>
#include <trace/interface.H>
#include <initservice/taskargs.H>
#include <errl/errlentry.H>
#include <initservice/isteps_trace.H>
#include <initservice/initserviceif.H>
#include <initservice/initsvcreasoncodes.H>
#include <sys/time.h>
#include <devicefw/userif.H>
#include <i2c/i2cif.H>

//  targeting support
#include <targeting/common/commontargeting.H>
#include <targeting/common/utilFilter.H>
#include <targeting/namedtarget.H>
#include <targeting/attrsync.H>

#include <fapi2/target.H>
#include <fapi2/plat_hwp_invoker.H>

#include <errl/errlmanager.H>

#include <isteps/hwpisteperror.H>

#include <errl/errludtarget.H>

#include <p9_set_fsi_gp_shadow.H>

using namespace ISTEP;
using namespace ISTEP_ERROR;
using namespace ERRORLOG;
using namespace TARGETING;

namespace ISTEP_08
{

//******************************************************************************
// call_host_setup_sbe()
//******************************************************************************
void* call_host_setup_sbe(void *io_pArgs)
{
    errlHndl_t l_errl = NULL;
    IStepError  l_stepError;
    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_host_setup_sbe entry" );

    //
    //  get a list of all the procs in the system
    //
    TARGETING::TargetHandleList l_cpuTargetList;
    getAllChips(l_cpuTargetList, TYPE_PROC);

    //
    //  identify master processor target
    //
    TARGETING::Target* l_pMasterProcTarget = NULL;
    TARGETING::targetService().masterProcChipTargetHandle(l_pMasterProcTarget);

    for (const auto & l_procChip: l_cpuTargetList)
    {
        // call only on non-master processor chips
        if (l_procChip != l_pMasterProcTarget)
        {
            const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>
                l_fapi2_proc_target (l_procChip);

            //call p9_set_fsi_gp_shadow on non-master processors
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                    "Running p9_set_fsi_gp_shadow HWP on processor target %.8X",
                    TARGETING::get_huid(l_procChip) );

            FAPI_INVOKE_HWP(l_errl,p9_set_fsi_gp_shadow, l_fapi2_proc_target);
            if(l_errl)
            {
                l_stepError.addErrorDetails(l_errl);
                TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                         "ERROR : call p9_set_fsi_gp_shadow, PLID=0x%x",
                         l_errl->plid() );
                errlCommit(l_errl, HWPF_COMP_ID);
            }
        }

    } // end of cycling through all processor chips

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "call_host_setup_sbe exit" );
    return l_stepError.getErrorHandle();
}
};
<commit_msg>Temp workaround to setup slave sbe scratch registers<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/isteps/istep08/call_host_setup_sbe.C $                */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 *  @file call_host_setup_sbe.C
 *
 *  Support file for IStep: slave_sbe
 *   Slave SBE
 *
 *  HWP_IGNORE_VERSION_CHECK
 */

/******************************************************************************/
// Includes
/******************************************************************************/
#include <stdint.h>
#include <trace/interface.H>
#include <initservice/taskargs.H>
#include <errl/errlentry.H>
#include <initservice/isteps_trace.H>
#include <initservice/initserviceif.H>
#include <initservice/initsvcreasoncodes.H>
#include <sys/time.h>
#include <devicefw/userif.H>
#include <i2c/i2cif.H>

//  targeting support
#include <targeting/common/commontargeting.H>
#include <targeting/common/utilFilter.H>
#include <targeting/namedtarget.H>
#include <targeting/attrsync.H>

#include <fapi2/target.H>
#include <fapi2/plat_hwp_invoker.H>

#include <errl/errlmanager.H>

#include <isteps/hwpisteperror.H>

#include <errl/errludtarget.H>

#include <p9_set_fsi_gp_shadow.H>

using namespace ISTEP;
using namespace ISTEP_ERROR;
using namespace ERRORLOG;
using namespace TARGETING;

namespace ISTEP_08
{

//******************************************************************************
// call_host_setup_sbe()
//******************************************************************************
void* call_host_setup_sbe(void *io_pArgs)
{
    errlHndl_t l_errl = NULL;
    IStepError  l_stepError;
    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
               "call_host_setup_sbe entry" );

    //
    //  get a list of all the procs in the system
    //
    TARGETING::TargetHandleList l_cpuTargetList;
    getAllChips(l_cpuTargetList, TYPE_PROC);

    //
    //  identify master processor target
    //
    TARGETING::Target* l_pMasterProcTarget = NULL;
    TARGETING::targetService().masterProcChipTargetHandle(l_pMasterProcTarget);

    for (const auto & l_procChip: l_cpuTargetList)
    {
        // call only on non-master processor chips
        if (l_procChip != l_pMasterProcTarget)
        {
            const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>
                l_fapi2_proc_target (l_procChip);

            //call p9_set_fsi_gp_shadow on non-master processors
            TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                    "Running p9_set_fsi_gp_shadow HWP on processor target %.8X",
                    TARGETING::get_huid(l_procChip) );

            FAPI_INVOKE_HWP(l_errl,p9_set_fsi_gp_shadow, l_fapi2_proc_target);
            if(l_errl)
            {
                l_stepError.addErrorDetails(l_errl);
                TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
                         "ERROR : call p9_set_fsi_gp_shadow, PLID=0x%x",
                         l_errl->plid() );
                errlCommit(l_errl, HWPF_COMP_ID);
            }

            // TODO-RTC:152203 BEGIN
            // Configure slave sbe to be in slave SBE, continuous IPL mode
            // All this code gets deleted once host_slave_sbe_config.C is in
            TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                      "WORKAROUND:RTC:152203 - Setup slave sbe scratch "
                      "registers for proc 0x%.8X",
                      TARGETING::get_huid(l_procChip));

            // Bits 7-15 are address portion
            const uint32_t CFAM_ADDRESS_MASK = 0x1FF;

            // Bits 0-6 are engine offset
            const uint32_t CFAM_ENGINE_OFFSET = 0xFE00;

            uint64_t l_addr = 0x283A;
            l_addr = ((l_addr & CFAM_ADDRESS_MASK) << 2) |
              (l_addr & CFAM_ENGINE_OFFSET);
            uint32_t l_data = 0x10000000;
            size_t l_size = sizeof(uint32_t);
            l_errl = deviceWrite(l_procChip,
                                &l_data,
                                l_size,
                                DEVICE_FSI_ADDRESS(l_addr));
            if (l_errl)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          ERR_MRK"WORKAROUND:RTC:152203 - FAIL to setup "
                          "slave sbe scratch  registers for proc 0x%.8X "
                          "scratch 0x3A",
                          TARGETING::get_huid(l_procChip));
                delete l_errl;
                l_errl = NULL;
            }

            l_addr = 0x283D;
            l_addr = ((l_addr & CFAM_ADDRESS_MASK) << 2) |
              (l_addr & CFAM_ENGINE_OFFSET);
            l_data = 0x00000080;
            l_errl = deviceWrite(l_procChip,
                                 &l_data,
                                 l_size,
                                 DEVICE_FSI_ADDRESS(l_addr));
            if (l_errl)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          ERR_MRK"WORKAROUND:RTC:152203 - FAIL to setup "
                          "slave sbe scratch registers for proc 0x%.8X "
                          "scratch 0x3D",
                          TARGETING::get_huid(l_procChip));
                delete l_errl;
                l_errl = NULL;
            }
            l_addr = 0x283F;
            l_addr = ((l_addr & CFAM_ADDRESS_MASK) << 2) |
              (l_addr & CFAM_ENGINE_OFFSET);
            l_data = 0x24000000;
            l_errl = deviceWrite(l_procChip,
                                 &l_data,
                                 l_size,
                                 DEVICE_FSI_ADDRESS(l_addr));
            if (l_errl)
            {
                TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace,
                          ERR_MRK"WORKAROUND:RTC:152203 - FAIL to setup "
                          "slave sbe scratch "
                          "registers for proc 0x%.8X scratch 0x3F",
                          TARGETING::get_huid(l_procChip));
                delete l_errl;
                l_errl = NULL;
            }
            // TODO-RTC:152203 END
        }

    } // end of cycling through all processor chips

    TRACFCOMP( ISTEPS_TRACE::g_trac_isteps_trace,
            "call_host_setup_sbe exit" );
    return l_stepError.getErrorHandle();
}
};
<|endoftext|>


<commit_before>//===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the X86 target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "jit"
#include "X86JITInfo.h"
#include "X86Relocations.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/Config/alloca.h"
using namespace llvm;

void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
  unsigned char *OldByte = (unsigned char *)Old;
  *OldByte++ = 0xE9;                // Emit JMP opcode.
  unsigned *OldWord = (unsigned *)OldByte;
  unsigned NewAddr = (intptr_t)New;
  unsigned OldAddr = (intptr_t)OldWord;
  *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
}

#ifdef _MSC_VER
#pragma optimize("y", off)
#endif

/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;

// Provide a wrapper for X86CompilationCallback2 that saves non-traditional
// callee saved registers, for the fastcc calling convention.
extern "C" void X86CompilationCallback(void);

#if defined(__i386__) || defined(i386)
#ifndef _MSC_VER
asm(
   ".text\n"
   ".align 8\n"
   ".globl X86CompilationCallback\n"
"X86CompilationCallback:\n"
   "pushl   %ebp\n"
   "movl    %esp, %ebp\n"    // Standard prologue
   "pushl   %eax\n"
   "pushl   %edx\n"          // save EAX/EDX
   "call X86CompilationCallback2\n"
   "popl    %edx\n"
   "popl    %eax\n"
   "popl    %ebp\n"
   "ret\n");
#else
// FIXME: implement this for VC++
#endif

#else
// Not an i386 host
void X86CompilationCallback() {
  assert(0 && "This is not a X86, you can't execute this!");
  abort();
}
#endif

/// X86CompilationCallback - This is the target-specific function invoked by the
/// function stub when we did not know the real target of a call.  This function
/// must locate the start of the stub or call site and pass it into the JIT
/// compiler function.
extern "C" void X86CompilationCallback2() {
#ifdef _MSC_VER
  // FIXME: This needs to go up one more level!
  unsigned *StackPtr, RetAddr;
  __asm mov StackPtr, ebp;
  __asm mov eax, DWORD PTR [ebp + 4];
  __asm mov RetAddr, eax;
#else
  unsigned *StackPtr = (unsigned*)__builtin_frame_address(1);
  unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1);

  // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has
  // been performed.  Having a variable sized alloca disables frame pointer
  // elimination currently, even if it's dead.  This is a gross hack.
  alloca(10+(RetAddr >> 31));

#endif
  assert(StackPtr[1] == RetAddr &&
         "Could not find return address on the stack!");

  // It's a stub if there is an interrupt marker after the call.
  bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD;

  // The call instruction should have pushed the return value onto the stack...
  RetAddr -= 4;  // Backtrack to the reference itself...

#if 0
  DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr
                  << " ESP=" << (void*)StackPtr
                  << ": Resolving call to function: "
                  << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
#endif

  // Sanity check to make sure this really is a call instruction.
  assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!");

  unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr);

  // Rewrite the call target... so that we don't end up here every time we
  // execute the call.
  *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4;

  if (isStub) {
    // If this is a stub, rewrite the call into an unconditional branch
    // instruction so that two return addresses are not pushed onto the stack
    // when the requested function finally gets called.  This also makes the
    // 0xCD byte (interrupt) dead, so the marker doesn't effect anything.
    ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9;
  }

  // Change the return address to reexecute the call instruction...
  StackPtr[1] -= 5;
}

#ifdef _MSC_VER
#pragma optimize( "", on )
#endif

TargetJITInfo::LazyResolverFn
X86JITInfo::getLazyResolverFunction(JITCompilerFn F) {
  JITCompilerFunction = F;
  return X86CompilationCallback;
}

void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
  if (Fn != X86CompilationCallback) {
    MCE.startFunctionStub(5);
    MCE.emitByte(0xE9);
    MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4);
    return MCE.finishFunctionStub(0);
  }

  MCE.startFunctionStub(6);
  MCE.emitByte(0xE8);   // Call with 32 bit pc-rel destination...

  MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4);

  MCE.emitByte(0xCD);   // Interrupt - Just a marker identifying the stub!
  return MCE.finishFunctionStub(0);
}

/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void X86JITInfo::relocate(void *Function, MachineRelocation *MR,
                          unsigned NumRelocs) {
  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
    void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
    intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
    switch ((X86::RelocationType)MR->getRelocationType()) {
    case X86::reloc_pcrel_word:
      // PC relative relocation, add the relocated value to the value already in
      // memory, after we adjust it for where the PC is.
      ResultPtr = ResultPtr-(intptr_t)RelocPos-4;
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    case X86::reloc_absolute_word:
      // Absolute relocation, just add the relocated value to the value already
      // in memory.
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    }
  }
}
<commit_msg>Fix tail call support in VC++ builds<commit_after>//===-- X86JITInfo.cpp - Implement the JIT interfaces for the X86 target --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the X86 target.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "jit"
#include "X86JITInfo.h"
#include "X86Relocations.h"
#include "llvm/CodeGen/MachineCodeEmitter.h"
#include "llvm/Config/alloca.h"
using namespace llvm;

void X86JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
  unsigned char *OldByte = (unsigned char *)Old;
  *OldByte++ = 0xE9;                // Emit JMP opcode.
  unsigned *OldWord = (unsigned *)OldByte;
  unsigned NewAddr = (intptr_t)New;
  unsigned OldAddr = (intptr_t)OldWord;
  *OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
}

/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;

// Provide a wrapper for X86CompilationCallback2 that saves non-traditional
// callee saved registers, for the fastcc calling convention.
extern "C" {
#if defined(__i386__) || defined(i386) || defined(_M_IX86)
#ifndef _MSC_VER
  void X86CompilationCallback(void);
  asm(
    ".text\n"
    ".align 8\n"
    ".globl X86CompilationCallback\n"
  "X86CompilationCallback:\n"
    "pushl   %ebp\n"
    "movl    %esp, %ebp\n"    // Standard prologue
    "pushl   %eax\n"
    "pushl   %edx\n"          // save EAX/EDX
    "call X86CompilationCallback2\n"
    "popl    %edx\n"
    "popl    %eax\n"
    "popl    %ebp\n"
    "ret\n");
#else
  extern "C" void *_AddressOfReturnAddress(void);
  #pragma intrinsic(_AddressOfReturnAddress)

  void X86CompilationCallback2(void);

  _declspec(naked) void X86CompilationCallback(void) {
    __asm {
      push  eax
      push  edx
      call  X86CompilationCallback2
      pop   edx
      pop   eax
      ret
    }
  }
#endif

#else
  // Not an i386 host
  void X86CompilationCallback() {
    assert(0 && "This is not a X86, you can't execute this!");
    abort();
  }
#endif
}

/// X86CompilationCallback - This is the target-specific function invoked by the
/// function stub when we did not know the real target of a call.  This function
/// must locate the start of the stub or call site and pass it into the JIT
/// compiler function.
extern "C" void X86CompilationCallback2() {
#ifdef _MSC_VER
  assert(sizeof(size_t) == 4); // FIXME: handle Win64
  unsigned *RetAddrLoc = (unsigned *)_AddressOfReturnAddress();
  RetAddrLoc += 3;  // skip over ret addr, edx, eax
  unsigned RetAddr = *RetAddrLoc;
#else
  unsigned *StackPtr = (unsigned*)__builtin_frame_address(1);
  unsigned RetAddr = (unsigned)(intptr_t)__builtin_return_address(1);
  unsigned *RetAddrLoc = &StackPtr[1];

  // NOTE: __builtin_frame_address doesn't work if frame pointer elimination has
  // been performed.  Having a variable sized alloca disables frame pointer
  // elimination currently, even if it's dead.  This is a gross hack.
  alloca(10+(RetAddr >> 31));

#endif
  assert(*RetAddrLoc == RetAddr &&
         "Could not find return address on the stack!");

  // It's a stub if there is an interrupt marker after the call.
  bool isStub = ((unsigned char*)(intptr_t)RetAddr)[0] == 0xCD;

  // The call instruction should have pushed the return value onto the stack...
  RetAddr -= 4;  // Backtrack to the reference itself...

#if 0
  DEBUG(std::cerr << "In callback! Addr=" << (void*)RetAddr
                  << " ESP=" << (void*)StackPtr
                  << ": Resolving call to function: "
                  << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n");
#endif

  // Sanity check to make sure this really is a call instruction.
  assert(((unsigned char*)(intptr_t)RetAddr)[-1] == 0xE8 &&"Not a call instr!");

  unsigned NewVal = (intptr_t)JITCompilerFunction((void*)(intptr_t)RetAddr);

  // Rewrite the call target... so that we don't end up here every time we
  // execute the call.
  *(unsigned*)(intptr_t)RetAddr = NewVal-RetAddr-4;

  if (isStub) {
    // If this is a stub, rewrite the call into an unconditional branch
    // instruction so that two return addresses are not pushed onto the stack
    // when the requested function finally gets called.  This also makes the
    // 0xCD byte (interrupt) dead, so the marker doesn't effect anything.
    ((unsigned char*)(intptr_t)RetAddr)[-1] = 0xE9;
  }

  // Change the return address to reexecute the call instruction...
  *RetAddrLoc -= 5;
}

TargetJITInfo::LazyResolverFn
X86JITInfo::getLazyResolverFunction(JITCompilerFn F) {
  JITCompilerFunction = F;
  return X86CompilationCallback;
}

void *X86JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
  if (Fn != X86CompilationCallback) {
    MCE.startFunctionStub(5);
    MCE.emitByte(0xE9);
    MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4);
    return MCE.finishFunctionStub(0);
  }

  MCE.startFunctionStub(6);
  MCE.emitByte(0xE8);   // Call with 32 bit pc-rel destination...

  MCE.emitWord((intptr_t)Fn-MCE.getCurrentPCValue()-4);

  MCE.emitByte(0xCD);   // Interrupt - Just a marker identifying the stub!
  return MCE.finishFunctionStub(0);
}

/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void X86JITInfo::relocate(void *Function, MachineRelocation *MR,
                          unsigned NumRelocs) {
  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
    void *RelocPos = (char*)Function + MR->getMachineCodeOffset();
    intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
    switch ((X86::RelocationType)MR->getRelocationType()) {
    case X86::reloc_pcrel_word:
      // PC relative relocation, add the relocated value to the value already in
      // memory, after we adjust it for where the PC is.
      ResultPtr = ResultPtr-(intptr_t)RelocPos-4;
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    case X86::reloc_absolute_word:
      // Absolute relocation, just add the relocated value to the value already
      // in memory.
      *((intptr_t*)RelocPos) += ResultPtr;
      break;
    }
  }
}
<|endoftext|>


<commit_before>/* ************************************************************************** */
/*                                                                            */
/*                                                                            */
/*    VertexArray.hpp                                oooooo       oooooo      */
/*                                                 oooooooooo   oooooooooo    */
/*                                                         o%%%%%o            */
/*                                                         %:::::%            */
/*                                                        %:::::::%           */
/*    This file is part of the                             %:::::%            */
/*    Lums library.                                         %%%%%             */
/*                                                                            */
/* ************************************************************************** */

#ifndef LUMS_VERTEX_ARRAY_HPP
#define LUMS_VERTEX_ARRAY_HPP

#include <type_traits>
#include <Lums/GL.hpp>

namespace lm
{
	enum class Vertex
	{
		Color,
		Texture
	};

	namespace internal
	{
		template <Vertex Base, Vertex...>
		struct _VertexOfType
		{
			enum { value = false };
		};

		template <Vertex Base, Vertex Head, Vertex... Queue>
		struct _VertexOfType<Base, Head, Queue...>
		{
			enum { value = (Base == Head) ? true : _VertexOfType<Base, Queue...>::value };
		};

		template <Vertex...>
		struct _VertexLen
		{
			enum { value = 2 };
		};

		template <Vertex Head, Vertex... Queue>
		struct _VertexLen<Head, Queue...>
		{

		};

		template <Vertex... Queue>
		struct _VertexLen<Vertex::Color, Queue...>
		{
			enum { value = 3 + _VertexLen<Queue...>::value };
		};

		template <Vertex... Queue>
		struct _VertexLen<Vertex::Texture, Queue...>
		{
			enum { value = 2 + _VertexLen<Queue...>::value };
		};

		template <size_t N, Vertex Base, Vertex...>
		struct _VertexOffsetHelper
		{
            enum { value = 0 };
		};

		template <size_t N, Vertex Base, Vertex Head, Vertex... Queue>
		struct _VertexOffsetHelper<N, Base, Head, Queue...>
		{
			enum { value = (Base == Head) ? N : _VertexOffsetHelper<N + (_VertexLen<Head>::value - 2), Base, Queue...>::value };
		};

		template <Vertex Base, Vertex Head, Vertex... Queue>
		struct _VertexOffset
		{
			enum { value = _VertexOffsetHelper<2, Base, Head, Queue...>::value };
		};

		template <Vertex Head, Vertex... Opt>
		struct _VertexPush
		{
			template <Vertex V = Head, typename... T>
			static typename std::enable_if<V == Vertex::Color>::type
			apply(float* buffer, float r, float g, float b, T... Args)
			{
				buffer[0] = r;
				buffer[1] = g;
				buffer[2] = b;
				forward<sizeof...(Opt)>(buffer + 3, Args...);
			}

			template <Vertex V = Head, typename... T>
			static typename std::enable_if<V == Vertex::Texture>::type
			apply(float* buffer, float x, float y, T... Args)
			{
				buffer[0] = x;
				buffer[1] = y;
				forward<sizeof...(Opt)>(buffer + 2, Args...);
			}

			template <int N, typename... T>
			static typename std::enable_if<N != 0>::type
			forward(float *buffer, T... Args)
			{
				_VertexPush<Opt...>::apply(buffer, Args...);
			}

			template <int N, typename... T>
			static typename std::enable_if<N == 0>::type
			forward(float* buffer)
			{

			}
		};
	}

	template <size_t N, Vertex... Options>
	class VertexArray
	{
	public:
		VertexArray()
		: _count(0)
        , _vertices(0)
		{

		}

		void
		clear()
		{
			_count = 0;
            _vertices = 0;
		}

		template <typename ...T>
		void
		push(float x, float y, T ...Args)
		{
			_buffer[_count] = x;
			_buffer[_count + 1] = y;
			forward<sizeof...(Options)>(_buffer + _count + 2, Args...);
			_count += internal::_VertexLen<Options...>::value;
            _vertices++;
		}

		template <int Len, typename ...T>
		typename std::enable_if<Len != 0>::type
		forward(float* buffer, T... Args)
		{
			internal::_VertexPush<Options...>::apply(buffer, Args...);
		}

		template <int Len, typename ...T>
		typename std::enable_if<Len == 0>::type
		forward(float* buffer)
		{

		}

		void
		draw(GLenum mode) const
		{
			glEnableClientState(GL_VERTEX_ARRAY);
            glVertexPointer(2, GL_FLOAT, internal::_VertexLen<Options...>::value * sizeof(float), _buffer);
			enableColor<Options...>();
			enableTexture<Options...>();
            glDrawArrays(mode, 0, _vertices);
			disableTexture<Options...>();
			disableColor<Options...>();
			glDisableClientState(GL_VERTEX_ARRAY);
		}

	protected:
		float 	_buffer[N * internal::_VertexLen<Options...>::value];
		size_t	_count;
        size_t  _vertices;

	private:
		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == true>::type
		enableColor() const
		{
			glEnableClientState(GL_COLOR_ARRAY);
            glColorPointer(
                3,
                GL_FLOAT,
                internal::_VertexLen<Options...>::value * sizeof(float),
                _buffer + internal::_VertexOffset<Vertex::Color, Options...>::value
            );
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == false>::type
		enableColor() const
		{

		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == true>::type
		enableTexture() const
		{
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glEnable(GL_TEXTURE_2D);
            glTexCoordPointer(
                2,
                GL_FLOAT,
                internal::_VertexLen<Options...>::value * sizeof(float),
                _buffer + internal::_VertexOffset<Vertex::Texture, Options...>::value
            );
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == false>::type
		enableTexture() const
		{
			glDisable(GL_TEXTURE_2D);
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == true>::type
		disableColor() const
		{
			glDisableClientState(GL_COLOR_ARRAY);
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == false>::type
		disableColor() const
		{

		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == true>::type
		disableTexture() const
		{
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == false>::type
		disableTexture() const
		{

		}
	};

	template <size_t N>
	using VertexArrayc = VertexArray<N, Vertex::Color>;

	template <size_t N>
	using VertexArrayt = VertexArray<N, Vertex::Texture>;

	template <size_t N>
	using VertexArrayct = VertexArray<N, Vertex::Color, Vertex::Texture>;
}

#endif
<commit_msg>2.9 prev<commit_after>/* ************************************************************************** */
/*                                                                            */
/*                                                                            */
/*    VertexArray.hpp                                oooooo       oooooo      */
/*                                                 oooooooooo   oooooooooo    */
/*                                                         o%%%%%o            */
/*                                                         %:::::%            */
/*                                                        %:::::::%           */
/*    This file is part of the                             %:::::%            */
/*    Lums library.                                         %%%%%             */
/*                                                                            */
/* ************************************************************************** */

#ifndef LUMS_VERTEX_ARRAY_HPP
#define LUMS_VERTEX_ARRAY_HPP

#include <type_traits>
#include <Lums/GL.hpp>
#include <Lums/Image.hpp>

namespace lm
{
	enum class Vertex
	{
		Color,
		Texture
	};

	namespace internal
	{
		template <Vertex Base, Vertex...>
		struct _VertexOfType
		{
			enum { value = false };
		};

		template <Vertex Base, Vertex Head, Vertex... Queue>
		struct _VertexOfType<Base, Head, Queue...>
		{
			enum { value = (Base == Head) ? true : _VertexOfType<Base, Queue...>::value };
		};

		template <Vertex...>
		struct _VertexLen
		{
			enum { value = 2 };
		};

		template <Vertex Head, Vertex... Queue>
		struct _VertexLen<Head, Queue...>
		{

		};

		template <Vertex... Queue>
		struct _VertexLen<Vertex::Color, Queue...>
		{
			enum { value = 3 + _VertexLen<Queue...>::value };
		};

		template <Vertex... Queue>
		struct _VertexLen<Vertex::Texture, Queue...>
		{
			enum { value = 2 + _VertexLen<Queue...>::value };
		};

		template <size_t N, Vertex Base, Vertex...>
		struct _VertexOffsetHelper
		{
            enum { value = 0 };
		};

		template <size_t N, Vertex Base, Vertex Head, Vertex... Queue>
		struct _VertexOffsetHelper<N, Base, Head, Queue...>
		{
			enum { value = (Base == Head) ? N : _VertexOffsetHelper<N + (_VertexLen<Head>::value - 2), Base, Queue...>::value };
		};

		template <Vertex Base, Vertex Head, Vertex... Queue>
		struct _VertexOffset
		{
			enum { value = _VertexOffsetHelper<2, Base, Head, Queue...>::value };
		};

		template <Vertex Head, Vertex... Opt>
		struct _VertexPush
		{
			template <Vertex V = Head, typename... T>
			static typename std::enable_if<V == Vertex::Color>::type
			apply(float* buffer, float r, float g, float b, T... Args)
			{
				buffer[0] = r;
				buffer[1] = g;
				buffer[2] = b;
				forward<sizeof...(Opt)>(buffer + 3, Args...);
			}

			template <Vertex V = Head, typename... T>
			static typename std::enable_if<V == Vertex::Texture>::type
			apply(float* buffer, float x, float y, T... Args)
			{
				buffer[0] = x;
				buffer[1] = y;
				forward<sizeof...(Opt)>(buffer + 2, Args...);
			}

			template <int N, typename... T>
			static typename std::enable_if<N != 0>::type
			forward(float *buffer, T... Args)
			{
				_VertexPush<Opt...>::apply(buffer, Args...);
			}

			template <int N, typename... T>
			static typename std::enable_if<N == 0>::type
			forward(float* buffer)
			{

			}
		};
	}

	template <size_t N, Vertex... Options>
	class VertexArray
	{
	public:
		VertexArray()
		: _count(0)
        , _vertices(0)
		{

		}

		void
		clear()
		{
			_count = 0;
            _vertices = 0;
		}

		template <typename ...T>
		void
		push(float x, float y, T ...Args)
		{
			_buffer[_count] = x;
			_buffer[_count + 1] = y;
			forward<sizeof...(Options)>(_buffer + _count + 2, Args...);
			_count += internal::_VertexLen<Options...>::value;
            _vertices++;
		}

		template <int Len, typename ...T>
		typename std::enable_if<Len != 0>::type
		forward(float* buffer, T... Args)
		{
			internal::_VertexPush<Options...>::apply(buffer, Args...);
		}

		template <int Len, typename ...T>
		typename std::enable_if<Len == 0>::type
		forward(float* buffer)
		{

		}

		void
		draw(GLenum mode) const
		{
			glEnableClientState(GL_VERTEX_ARRAY);
            glVertexPointer(2, GL_FLOAT, internal::_VertexLen<Options...>::value * sizeof(float), _buffer);
			enableColor<Options...>();
			enableTexture<Options...>();
            glDrawArrays(mode, 0, _vertices);
			disableTexture<Options...>();
			disableColor<Options...>();
			glDisableClientState(GL_VERTEX_ARRAY);
		}

	protected:
		float 	_buffer[N * internal::_VertexLen<Options...>::value];
		size_t	_count;
        size_t  _vertices;

	private:
		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == true>::type
		enableColor() const
		{
			glEnableClientState(GL_COLOR_ARRAY);
            glColorPointer(
                3,
                GL_FLOAT,
                internal::_VertexLen<Options...>::value * sizeof(float),
                _buffer + internal::_VertexOffset<Vertex::Color, Options...>::value
            );
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == false>::type
		enableColor() const
		{

		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == true>::type
		enableTexture() const
		{
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(
                2,
                GL_FLOAT,
                internal::_VertexLen<Options...>::value * sizeof(float),
                _buffer + internal::_VertexOffset<Vertex::Texture, Options...>::value
            );
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == false>::type
		enableTexture() const
		{
			lm::Image::none().bind();
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == true>::type
		disableColor() const
		{
			glDisableClientState(GL_COLOR_ARRAY);
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Color, V...>::value == false>::type
		disableColor() const
		{

		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == true>::type
		disableTexture() const
		{
			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		}

		template <Vertex... V>
		typename std::enable_if<internal::_VertexOfType<Vertex::Texture, V...>::value == false>::type
		disableTexture() const
		{

		}
	};

	template <size_t N>
	using VertexArrayc = VertexArray<N, Vertex::Color>;

	template <size_t N>
	using VertexArrayt = VertexArray<N, Vertex::Texture>;

	template <size_t N>
	using VertexArrayct = VertexArray<N, Vertex::Color, Vertex::Texture>;
}

#endif
<|endoftext|>


<commit_before>/*
 * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/utils.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef RENDER_UTILS_HPP_
#define RENDER_UTILS_HPP_

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

namespace eos {
	namespace render {

/**
 * Transforms a point from clip space ([-1, 1] x [-1, 1]) to
 * image (screen) coordinates, i.e. the window transform.
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 * No z-division is performed.
 * Note: It should rather be called from NDC to screen space?
 *
 * Exactly conforming to the OpenGL viewport transform, except that
 * we flip y at the end.
 * Qt: Origin top-left. OpenGL: bottom-left. OCV: top-left.
 *
 * @param[in] clip_coordinates A point in clip coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to screen space.
 */
inline cv::Vec2f clip_to_screen_space(const cv::Vec2f& clip_coordinates, int screen_width, int screen_height)
{
	// Window transform:
	const float x_ss = (clip_coordinates[0] + 1.0f) * (screen_width / 2.0f);
	const float y_ss = screen_height - (clip_coordinates[1] + 1.0f) * (screen_height / 2.0f); // also flip y; Qt: Origin top-left. OpenGL: bottom-left.
	return cv::Vec2f(x_ss, y_ss);
	/* Note: What we do here is equivalent to
	   x_w = (x *  vW/2) + vW/2;
	   However, Shirley says we should do:
	   x_w = (x *  vW/2) + (vW-1)/2;
	   (analogous for y)
	   Todo: Check the consequences.
	*/
};

/**
 * Transforms a point from image (screen) coordinates to
 * clip space ([-1, 1] x [-1, 1]).
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 *
 * @param[in] screen_coordinates A point in screen coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to clip space.
 */
inline cv::Vec2f screen_to_clip_space(const cv::Vec2f& screen_coordinates, int screen_width, int screen_height)
{
	const float x_cs = screen_coordinates[0] / (screen_width / 2.0f) - 1.0f;
	float y_cs = screen_coordinates[1] / (screen_height / 2.0f) - 1.0f;
	y_cs *= -1.0f;
	return cv::Vec2f(x_cs, y_cs);
};

// TODO: Should go to detail:: namespace, or texturing/utils or whatever.
unsigned int get_max_possible_mipmaps_num(unsigned int width, unsigned int height)
{
	unsigned int mipmapsNum = 1;
	unsigned int size = std::max(width, height);

	if (size == 1)
		return 1;

	do {
		size >>= 1;
		mipmapsNum++;
	} while (size != 1);

	return mipmapsNum;
};

inline bool is_power_of_two(int x)
{
	return !(x & (x - 1));
};

class Texture
{
public:
	// Todo: This whole class needs a major overhaul and documentation.

	// throws: ocv exc,  runtime_ex
	void create_mipmapped_texture(cv::Mat image, unsigned int mipmapsNum = 0) {

		this->mipmaps_num = (mipmapsNum == 0 ? get_max_possible_mipmaps_num(image.cols, image.rows) : mipmapsNum);
		/*if (mipmapsNum == 0)
		{
		uchar mmn = render::utils::MatrixUtils::getMaxPossibleMipmapsNum(image.cols, image.rows);
		this->mipmapsNum = mmn;
		} else
		{
		this->mipmapsNum = mipmapsNum;
		}*/

		if (this->mipmaps_num > 1)
		{
			if (!is_power_of_two(image.cols) || !is_power_of_two(image.rows))
			{
				throw std::runtime_error("Error: Couldn't generate mipmaps, width or height not power of two.");
			}
		}
		image.convertTo(image, CV_8UC4);	// Most often, the input img is CV_8UC3. Img is BGR. Add an alpha channel
		cv::cvtColor(image, image, CV_BGR2BGRA);

		int currWidth = image.cols;
		int currHeight = image.rows;
		for (int i = 0; i < this->mipmaps_num; i++)
		{
			if (i == 0) {
				mipmaps.push_back(image);
			}
			else {
				cv::Mat currMipMap(currHeight, currWidth, CV_8UC4);
				cv::resize(mipmaps[i - 1], currMipMap, currMipMap.size());
				mipmaps.push_back(currMipMap);
			}

			if (currWidth > 1)
				currWidth >>= 1;
			if (currHeight > 1)
				currHeight >>= 1;
		}
		this->widthLog = (uchar)(std::log(mipmaps[0].cols) / CV_LOG2 + 0.0001f); // std::epsilon or something? or why 0.0001f here?
		this->heightLog = (uchar)(std::log(mipmaps[0].rows) / CV_LOG2 + 0.0001f); // Changed std::logf to std::log because it doesnt compile in linux (gcc 4.8). CHECK THAT
	};

	std::vector<cv::Mat> mipmaps;	// make Texture a friend class of renderer, then move this to private?
	unsigned char widthLog, heightLog; // log2 of width and height of the base mip-level

private:
	//std::string filename;
	unsigned int mipmaps_num;
};
	} /* namespace render */
} /* namespace eos */

#endif /* RENDER_UTILS_HPP_ */
<commit_msg>Added a function to draw the texture coordinate triangles<commit_after>/*
 * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/utils.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef RENDER_UTILS_HPP_
#define RENDER_UTILS_HPP_

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

namespace eos {
	namespace render {

/**
 * Transforms a point from clip space ([-1, 1] x [-1, 1]) to
 * image (screen) coordinates, i.e. the window transform.
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 * No z-division is performed.
 * Note: It should rather be called from NDC to screen space?
 *
 * Exactly conforming to the OpenGL viewport transform, except that
 * we flip y at the end.
 * Qt: Origin top-left. OpenGL: bottom-left. OCV: top-left.
 *
 * @param[in] clip_coordinates A point in clip coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to screen space.
 */
inline cv::Vec2f clip_to_screen_space(const cv::Vec2f& clip_coordinates, int screen_width, int screen_height)
{
	// Window transform:
	const float x_ss = (clip_coordinates[0] + 1.0f) * (screen_width / 2.0f);
	const float y_ss = screen_height - (clip_coordinates[1] + 1.0f) * (screen_height / 2.0f); // also flip y; Qt: Origin top-left. OpenGL: bottom-left.
	return cv::Vec2f(x_ss, y_ss);
	/* Note: What we do here is equivalent to
	   x_w = (x *  vW/2) + vW/2;
	   However, Shirley says we should do:
	   x_w = (x *  vW/2) + (vW-1)/2;
	   (analogous for y)
	   Todo: Check the consequences.
	*/
};

/**
 * Transforms a point from image (screen) coordinates to
 * clip space ([-1, 1] x [-1, 1]).
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 *
 * @param[in] screen_coordinates A point in screen coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to clip space.
 */
inline cv::Vec2f screen_to_clip_space(const cv::Vec2f& screen_coordinates, int screen_width, int screen_height)
{
	const float x_cs = screen_coordinates[0] / (screen_width / 2.0f) - 1.0f;
	float y_cs = screen_coordinates[1] / (screen_height / 2.0f) - 1.0f;
	y_cs *= -1.0f;
	return cv::Vec2f(x_cs, y_cs);
};

/**
 * Draws the texture coordinates (uv-coords) of the given mesh
 * into an image by looping over the triangles and drawing each
 * triangle's texcoords.
 *
 * @param[in] mesh A mesh with texture coordinates.
 * @param[in] image An optional image to draw onto.
 * @return An image with the texture coordinate triangles drawn in it, 512x512 if no image is given.
 */
cv::Mat draw_texcoords(Mesh mesh, cv::Mat image = cv::Mat())
{
	using cv::Point2f;
	using cv::Scalar;
	if (image.empty())
	{
		image = cv::Mat(512, 512, CV_8UC4, Scalar(0.0f, 0.0f, 0.0f, 255.0f));
	}

	for (const auto& triIdx : mesh.tvi) {
		cv::line(image, Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
		cv::line(image, Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
		cv::line(image, Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
	}
	return image;
};

// TODO: Should go to detail:: namespace, or texturing/utils or whatever.
unsigned int get_max_possible_mipmaps_num(unsigned int width, unsigned int height)
{
	unsigned int mipmapsNum = 1;
	unsigned int size = std::max(width, height);

	if (size == 1)
		return 1;

	do {
		size >>= 1;
		mipmapsNum++;
	} while (size != 1);

	return mipmapsNum;
};

inline bool is_power_of_two(int x)
{
	return !(x & (x - 1));
};

class Texture
{
public:
	// Todo: This whole class needs a major overhaul and documentation.

	// throws: ocv exc,  runtime_ex
	void create_mipmapped_texture(cv::Mat image, unsigned int mipmapsNum = 0) {

		this->mipmaps_num = (mipmapsNum == 0 ? get_max_possible_mipmaps_num(image.cols, image.rows) : mipmapsNum);
		/*if (mipmapsNum == 0)
		{
		uchar mmn = render::utils::MatrixUtils::getMaxPossibleMipmapsNum(image.cols, image.rows);
		this->mipmapsNum = mmn;
		} else
		{
		this->mipmapsNum = mipmapsNum;
		}*/

		if (this->mipmaps_num > 1)
		{
			if (!is_power_of_two(image.cols) || !is_power_of_two(image.rows))
			{
				throw std::runtime_error("Error: Couldn't generate mipmaps, width or height not power of two.");
			}
		}
		image.convertTo(image, CV_8UC4);	// Most often, the input img is CV_8UC3. Img is BGR. Add an alpha channel
		cv::cvtColor(image, image, CV_BGR2BGRA);

		int currWidth = image.cols;
		int currHeight = image.rows;
		for (int i = 0; i < this->mipmaps_num; i++)
		{
			if (i == 0) {
				mipmaps.push_back(image);
			}
			else {
				cv::Mat currMipMap(currHeight, currWidth, CV_8UC4);
				cv::resize(mipmaps[i - 1], currMipMap, currMipMap.size());
				mipmaps.push_back(currMipMap);
			}

			if (currWidth > 1)
				currWidth >>= 1;
			if (currHeight > 1)
				currHeight >>= 1;
		}
		this->widthLog = (uchar)(std::log(mipmaps[0].cols) / CV_LOG2 + 0.0001f); // std::epsilon or something? or why 0.0001f here?
		this->heightLog = (uchar)(std::log(mipmaps[0].rows) / CV_LOG2 + 0.0001f); // Changed std::logf to std::log because it doesnt compile in linux (gcc 4.8). CHECK THAT
	};

	std::vector<cv::Mat> mipmaps;	// make Texture a friend class of renderer, then move this to private?
	unsigned char widthLog, heightLog; // log2 of width and height of the base mip-level

private:
	//std::string filename;
	unsigned int mipmaps_num;
};
	} /* namespace render */
} /* namespace eos */

#endif /* RENDER_UTILS_HPP_ */
<|endoftext|>


<commit_before>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this list of
    conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice, this list
    of conditions and the following disclaimer in the documentation and/or other materials
    provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY Joe Hermaszewski "AS IS" AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Joe Hermaszewski OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of Joe Hermaszewski.
*/

#pragma once

#include <config.h>
#include <cstdint>

typedef uint8_t 	u8;
typedef uint16_t 	u16;
typedef uint32_t 	u32;
typedef uint64_t 	u64;

typedef int8_t		s8;
typedef int16_t 	s16;
typedef int32_t 	s32;
typedef int64_t 	s64;
<commit_msg>including config.hpp instead of config.h<commit_after>/*
    Copyright 2011 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this list of
    conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice, this list
    of conditions and the following disclaimer in the documentation and/or other materials
    provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY Joe Hermaszewski "AS IS" AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Joe Hermaszewski OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of Joe Hermaszewski.
*/

#pragma once

#include <joemath/config.hpp>
#include <cstdint>

typedef uint8_t 	u8;
typedef uint16_t 	u16;
typedef uint32_t 	u32;
typedef uint64_t 	u64;

typedef int8_t		s8;
typedef int16_t 	s16;
typedef int32_t 	s32;
typedef int64_t 	s64;
<|endoftext|>