<commit_before>#include <string>
#include <boost/asio/ip/tcp.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qi/messaging/net/networkasio.hpp>
#include <qi/messaging/net/option.hpp>

#if BOOST_OS_WINDOWS
# include <Winsock2.h> // needed by mstcpip.h
# include <Mstcpip.h> // for tcp_keepalive struct
#elif BOOST_OS_ANDROID
# include <linux/in.h> // for  IPPROTO_TCP
#endif

qiLogCategory(qi::net::logCategory());

#if BOOST_OS_WINDOWS
static void setSocketNativeOptionsWindows(
  boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle, int timeoutInSeconds)
{
  /* http://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
  On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.
  On Windows Server 2003, Windows XP, and Windows 2000, the default setting for number of keep-alive probes is 5.
  The number of keep-alive probes is controllable through the TcpMaxDataRetransmissions and PPTPTcpMaxDataRetransmissions registry settings.
  The number of keep-alive probes is set to the larger of the two registry key values.
  If this number is 0, then keep-alive probes will not be sent.
  If this number is above 255, then it is adjusted to 255.
  */
  tcp_keepalive params;
  params.onoff = 1;
  params.keepalivetime = 30000; // entry is in milliseconds
  // set interval to target timeout divided by probe count
  params.keepaliveinterval = timeoutInSeconds * 1000 / 10;
  DWORD bytesReturned;
  if (WSAIoctl(socketNativeHandle, SIO_KEEPALIVE_VALS, &params, sizeof(params),
    0, 0, &bytesReturned, 0, 0) != 0)
  {
    qiLogWarning() << "Failed to set socket keepalive with code " << WSAGetLastError();
  }
}
#elif BOOST_OS_LINUX
  /// Precondition: timeoutInSeconds >= 0
static void setSocketNativeOptionsLinux(
  boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle, int timeoutInSeconds)
{
  int optval = 1;
  if (setsockopt(socketNativeHandle, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
  {
    qiLogWarning() << "Failed to set so_keepalive: " << strerror(errno);
    return;
  }
  // Keepalive mechanism is overriden by TCP data retransmission mechanism.
  // Retransmission cannot be parameterized on a per-socket level.

  /* SOL_TCP level options: unit is seconds for times
  TCP_KEEPCNT: overrides tcp_keepalive_probes 9
    mark dead when that many probes are lost
  TCP_KEEPIDLE: overrides tcp_keepalive_time 7200
    only enable keepalive if that delay ever occurr between data sent
  TCP_KEEPINTVL: overrides  tcp_keepalive_intvl 75
    interval between probes
  */
  optval = timeoutInSeconds / 10;
  static const unsigned int optlen = sizeof(optval);
  if (setsockopt(socketNativeHandle, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPINTVL: " << strerror(errno);
  optval = 30;
  if (setsockopt(socketNativeHandle, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPIDLE : " << strerror(errno);
  optval = 10;
  if (setsockopt(socketNativeHandle, SOL_TCP, TCP_KEEPCNT, &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPCNT  : " << strerror(errno);
 qiLogDebug() << "enabling TCP_USER_TIMEOUT";
 // this is messy: defined in linux/tcp.h only after kernel 2.6.37,
 // which conflicts with netinet/tcp.h
 // We do not want to rely on compile-time flag to enable/disable this,
 // so just try it.
 static bool tcpUserTimeoutWarning = false;
 static const int QI_TCP_USER_TIMEOUT = 18;
 // TCP_USER_TIMEOUT: maximum time in ms data can remain unaknowledged
 optval = timeoutInSeconds * 1000;
 if (setsockopt(socketNativeHandle, SOL_TCP, QI_TCP_USER_TIMEOUT, &optval, optlen) < 0
   && !tcpUserTimeoutWarning)
 {
    qiLogVerbose() << "(Expected on old kernels) Failed to set TCP_USER_TIMEOUT  : " << strerror(errno);
    tcpUserTimeoutWarning = true;
 }
}
#elif BOOST_OS_MACOS
static void setSocketNativeOptionsMacOs(
  boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle)
{
  int optval = 1;
  if (setsockopt(socketNativeHandle, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
  {
    qiLogWarning() << "Failed to set so_keepalive: " << strerror(errno);
    return;
  }
  // MacOs only have TCP_KEEPALIVE wich is linux's TCP_KEEPIDLE.
  // So the best we can do is lower that, which will reduce delay from
  // hours to tens of minutes.
  optval = 30;
  static unsigned int optlen = sizeof(optval);
  if (setsockopt(socketNativeHandle, IPPROTO_TCP, TCP_KEEPALIVE , &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPALIVE : " << strerror(errno);
}
#endif

namespace qi {

  /// Use the environment variable QI_TCP_PING_TIMEOUT, if set.
  /// Use the passed default timeout otherwise.
  /// Returns 0 if QI_TCP_PING_TIMEOUT is set but its value is invalid.
  boost::optional<Seconds> getTcpPingTimeout(Seconds defaultTimeout)
  {
    static const char* envTimeout = getenv("QI_TCP_PING_TIMEOUT");
    auto timeout = defaultTimeout;
    if (envTimeout)
      timeout = Seconds{strtol(envTimeout, 0, 0)};
    if (timeout.count()) return timeout;
    else                 return {};
  }

  size_t getMaxPayloadFromEnv(size_t defaultValue)
  {
    std::string l = os::getenv("QI_MAX_MESSAGE_PAYLOAD");
    return l.empty() ? defaultValue : boost::lexical_cast<size_t>(l);
  }

  boost::optional<qi::int64_t> getSocketTimeWarnThresholdFromEnv()
  {
    static const auto thresholdEnvVariable = os::getenv("QIMESSAGING_SOCKET_DISPATCH_TIME_WARN_THRESHOLD");
    using Opt = boost::optional<qi::int64_t>;
    static Opt warnThreshold = thresholdEnvVariable.empty()
       ? Opt{}
       : Opt{strtol(thresholdEnvVariable.c_str(), 0, 0)};
    return warnThreshold;
  }
} // namespace qi

namespace qi { namespace net {

  void NetworkAsio::setSocketNativeOptions(
    boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle, int timeoutInSeconds)
  {
  #if BOOST_OS_WINDOWS
    setSocketNativeOptionsWindows(socketNativeHandle, timeoutInSeconds);
  #elif BOOST_OS_LINUX
    setSocketNativeOptionsLinux(socketNativeHandle, timeoutInSeconds);
  #elif BOOST_OS_MACOS
    setSocketNativeOptionsMacOs(socketNativeHandle);
  #else
  # error "Unsupported platform"
  #endif
  }

}} // namespace qi::net
<commit_msg>socket: Sets socket options for Android in the same way as Linux.<commit_after>#include <string>
#include <boost/asio/ip/tcp.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qi/messaging/net/networkasio.hpp>
#include <qi/messaging/net/option.hpp>

#if BOOST_OS_WINDOWS
# include <Winsock2.h> // needed by mstcpip.h
# include <Mstcpip.h> // for tcp_keepalive struct
#elif BOOST_OS_ANDROID
# include <linux/in.h> // for  IPPROTO_TCP
#endif

qiLogCategory(qi::net::logCategory());

#if BOOST_OS_WINDOWS
static void setSocketNativeOptionsWindows(
  boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle, int timeoutInSeconds)
{
  /* http://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
  On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.
  On Windows Server 2003, Windows XP, and Windows 2000, the default setting for number of keep-alive probes is 5.
  The number of keep-alive probes is controllable through the TcpMaxDataRetransmissions and PPTPTcpMaxDataRetransmissions registry settings.
  The number of keep-alive probes is set to the larger of the two registry key values.
  If this number is 0, then keep-alive probes will not be sent.
  If this number is above 255, then it is adjusted to 255.
  */
  tcp_keepalive params;
  params.onoff = 1;
  params.keepalivetime = 30000; // entry is in milliseconds
  // set interval to target timeout divided by probe count
  params.keepaliveinterval = timeoutInSeconds * 1000 / 10;
  DWORD bytesReturned;
  if (WSAIoctl(socketNativeHandle, SIO_KEEPALIVE_VALS, &params, sizeof(params),
    0, 0, &bytesReturned, 0, 0) != 0)
  {
    qiLogWarning() << "Failed to set socket keepalive with code " << WSAGetLastError();
  }
}
#elif BOOST_OS_LINUX || BOOST_OS_ANDROID
  /// Precondition: timeoutInSeconds >= 0
static void setSocketNativeOptionsLinuxAndroid(
  boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle, int timeoutInSeconds)
{
  int optval = 1;
  if (setsockopt(socketNativeHandle, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
  {
    qiLogWarning() << "Failed to set so_keepalive: " << strerror(errno);
    return;
  }
  // Keepalive mechanism is overriden by TCP data retransmission mechanism.
  // Retransmission cannot be parameterized on a per-socket level.

  /* SOL_TCP level options: unit is seconds for times
  TCP_KEEPCNT: overrides tcp_keepalive_probes 9
    mark dead when that many probes are lost
  TCP_KEEPIDLE: overrides tcp_keepalive_time 7200
    only enable keepalive if that delay ever occurr between data sent
  TCP_KEEPINTVL: overrides  tcp_keepalive_intvl 75
    interval between probes
  */
  optval = timeoutInSeconds / 10;
  static const unsigned int optlen = sizeof(optval);
  if (setsockopt(socketNativeHandle, SOL_TCP, TCP_KEEPINTVL, &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPINTVL: " << strerror(errno);
  optval = 30;
  if (setsockopt(socketNativeHandle, SOL_TCP, TCP_KEEPIDLE, &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPIDLE : " << strerror(errno);
  optval = 10;
  if (setsockopt(socketNativeHandle, SOL_TCP, TCP_KEEPCNT, &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPCNT  : " << strerror(errno);
 qiLogDebug() << "enabling TCP_USER_TIMEOUT";
 // this is messy: defined in linux/tcp.h only after kernel 2.6.37,
 // which conflicts with netinet/tcp.h
 // We do not want to rely on compile-time flag to enable/disable this,
 // so just try it.
 static bool tcpUserTimeoutWarning = false;
 static const int QI_TCP_USER_TIMEOUT = 18;
 // TCP_USER_TIMEOUT: maximum time in ms data can remain unaknowledged
 optval = timeoutInSeconds * 1000;
 if (setsockopt(socketNativeHandle, SOL_TCP, QI_TCP_USER_TIMEOUT, &optval, optlen) < 0
   && !tcpUserTimeoutWarning)
 {
    qiLogVerbose() << "(Expected on old kernels) Failed to set TCP_USER_TIMEOUT  : " << strerror(errno);
    tcpUserTimeoutWarning = true;
 }
}
#elif BOOST_OS_MACOS
static void setSocketNativeOptionsMacOs(
  boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle)
{
  int optval = 1;
  if (setsockopt(socketNativeHandle, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
  {
    qiLogWarning() << "Failed to set so_keepalive: " << strerror(errno);
    return;
  }
  // MacOs only have TCP_KEEPALIVE wich is linux's TCP_KEEPIDLE.
  // So the best we can do is lower that, which will reduce delay from
  // hours to tens of minutes.
  optval = 30;
  static unsigned int optlen = sizeof(optval);
  if (setsockopt(socketNativeHandle, IPPROTO_TCP, TCP_KEEPALIVE , &optval, optlen) < 0)
    qiLogWarning() << "Failed to set TCP_KEEPALIVE : " << strerror(errno);
}
#endif

namespace qi {

  /// Use the environment variable QI_TCP_PING_TIMEOUT, if set.
  /// Use the passed default timeout otherwise.
  /// Returns 0 if QI_TCP_PING_TIMEOUT is set but its value is invalid.
  boost::optional<Seconds> getTcpPingTimeout(Seconds defaultTimeout)
  {
    static const char* envTimeout = getenv("QI_TCP_PING_TIMEOUT");
    auto timeout = defaultTimeout;
    if (envTimeout)
      timeout = Seconds{strtol(envTimeout, 0, 0)};
    if (timeout.count()) return timeout;
    else                 return {};
  }

  size_t getMaxPayloadFromEnv(size_t defaultValue)
  {
    std::string l = os::getenv("QI_MAX_MESSAGE_PAYLOAD");
    return l.empty() ? defaultValue : boost::lexical_cast<size_t>(l);
  }

  boost::optional<qi::int64_t> getSocketTimeWarnThresholdFromEnv()
  {
    static const auto thresholdEnvVariable = os::getenv("QIMESSAGING_SOCKET_DISPATCH_TIME_WARN_THRESHOLD");
    using Opt = boost::optional<qi::int64_t>;
    static Opt warnThreshold = thresholdEnvVariable.empty()
       ? Opt{}
       : Opt{strtol(thresholdEnvVariable.c_str(), 0, 0)};
    return warnThreshold;
  }
} // namespace qi

namespace qi { namespace net {

  void NetworkAsio::setSocketNativeOptions(
    boost::asio::ip::tcp::socket::native_handle_type socketNativeHandle, int timeoutInSeconds)
  {
  #if BOOST_OS_WINDOWS
    setSocketNativeOptionsWindows(socketNativeHandle, timeoutInSeconds);
  #elif BOOST_OS_LINUX || BOOST_OS_ANDROID
    setSocketNativeOptionsLinuxAndroid(socketNativeHandle, timeoutInSeconds);
  #elif BOOST_OS_MACOS
    setSocketNativeOptionsMacOs(socketNativeHandle);
  #else
  # error "Unsupported platform"
  #endif
  }

}} // namespace qi::net
<|endoftext|>


<commit_before>#include <Source/Misc/utils.h>
#include "SolverFCBIILU2.h"
#include "solver_fcbiilu2.h"

namespace INMOST {

    SolverFCBIILU2::SolverFCBIILU2() {
        solver_data = NULL;
        matrix_data = NULL;
    }

    SolverInterface *SolverFCBIILU2::Copy(const SolverInterface *other) {
        if (other == NULL) {
            throw INMOST::SolverCopyNullException;
        }
        const SolverFCBIILU2 *fcother;
        try {
            fcother = dynamic_cast<const SolverFCBIILU2 *>(other);
        } catch (...) {
            throw INMOST::SolverCopyException;
        }
        SolverCopyDataFcbiilu2(&solver_data, fcother->solver_data, communicator);
        if (fcother->matrix_data != NULL) {
            MatrixCopyDataFcbiilu2(&matrix_data, fcother->matrix_data);
            SolverSetMatrixFcbiilu2(solver_data, matrix_data, false, false);
        }
        return this;
    }

    void SolverFCBIILU2::Assign(const SolverInterface *other) {
        if (other == NULL) {
            throw INMOST::SolverAssignNullException;
        }
        const SolverFCBIILU2 *fcother;
        try {
            fcother = dynamic_cast<const SolverFCBIILU2 *>(other);
        } catch (...) {
            throw INMOST::SolverAssignException;
        }
        SolverAssignDataFcbiilu2(solver_data, fcother->solver_data);
        if (fcother->matrix_data != NULL) {
            if (matrix_data != NULL) {
                MatrixAssignDataFcbiilu2(matrix_data, fcother->matrix_data);
            } else {
                MatrixCopyDataFcbiilu2(&matrix_data, fcother->matrix_data);
            }
            SolverSetMatrixFcbiilu2(solver_data, matrix_data, false, false);
        }
    }

    void SolverFCBIILU2::Setup(int *argc, char ***argv, SolverParameters &p) {
        SolverInitDataFcbiilu2(&solver_data, communicator, p.solverPrefix.c_str());
        solver_data->kovl = 0;    // number of overlap layers: kovl=0,1,2,...
        solver_data->tau = 3e-3;  // the ILU2 precision (for the submatrix factorization); tau=3e-3
        solver_data->eps = 1e-5;  // the residual precision: ||r|| < eps * ||b||; eps=1e-6
        solver_data->nit = 999;   // number of iterations permitted; nit=999
        solver_data->msglev = 2;  // messages level; msglev=0 for silent; msglev=1 to output solution statistics
        if (p.internalFile != "") {
            SolverInitializeFcbiilu2(solver_data, argc, argv, p.internalFile.c_str());
        } else {
            for (parameters_iterator_t parameter = p.parameters.begin(); parameter < p.parameters.end(); parameter++) {
                this->SetParameter((*parameter).first, (*parameter).second);
            }
        }
    }

    void SolverFCBIILU2::SetMatrix(Sparse::Matrix &A, bool ModifiedPattern, bool OldPreconditioner) {
        bool modified_pattern = ModifiedPattern;
        //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver;
        if (matrix_data == NULL) {
            MatrixInitDataFcbiilu2(&matrix_data, A.GetCommunicator(), A.GetName().c_str());
            modified_pattern = true;
        }
        if (modified_pattern) {
            global_size = local_size = A.Size();

            MatrixDestroyDataFcbiilu2(&matrix_data);
            MatrixInitDataFcbiilu2(&matrix_data, A.GetCommunicator(), A.GetName().c_str());
            INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 1;
            int nproc, myid;
#if defined(USE_MPI)
            MPI_Comm_size(A.GetCommunicator(), &nproc);
            MPI_Comm_rank(A.GetCommunicator(), &myid);
#else
            nproc = 1;
            myid = 0;
#endif
            int *ibl = (int *) malloc(sizeof(int) * (nproc + 1));
            ibl[0] = 0;
            int n = A.Size();
#if defined(USE_MPI)
            INMOST_DATA_ENUM_TYPE mbeg, mend;
            A.GetInterval(mbeg, mend);
            n = mend - mbeg;
            int block_end = mend;
            MPI_Allgather(&block_end, 1, MPI_INT, &ibl[1], 1, MPI_INT, A.GetCommunicator());
#else
            ibl[1] = n;
#endif
            int *ia = (int *) malloc(sizeof(int) * (n + 1));
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size();
            int *ja = (int *) malloc(sizeof(int) * nnz);
            double *values = (double *) malloc(sizeof(double) * nnz);
            ia[0] = shift;
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) {
                for (Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) {
                    ja[k] = jt->first + 1;
                    values[k] = jt->second;
                    //std::cout<<"# q="<<q<<" k="<<k<<" ja="<<ja[k]<<" a="<<values[k]<<std::endl;//db!
                    k++;
                }
                shift += it->Size();
                ia[q++] = shift;
            }
            MatrixFillFcbiilu2(matrix_data, n, nproc, ibl, ia, ja, values);
        } else {
            INMOST_DATA_ENUM_TYPE nnz = 0, k = 0;
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size();
            double *values = (double *) malloc(sizeof(double) * nnz);
            k = 0;
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++)
                for (Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++)
                    values[k++] = jt->second;
            MatrixFillValuesFcbiilu2(matrix_data, values);
        }
        MatrixFinalizeFcbiilu2(matrix_data);
        SolverSetMatrixFcbiilu2(solver_data, matrix_data, modified_pattern, OldPreconditioner);
        time_prec = solver_data->dstat[7];
    }

    bool SolverFCBIILU2::Solve(INMOST::Sparse::Vector &RHS, INMOST::Sparse::Vector &SOL) {
        INMOST_DATA_ENUM_TYPE vbeg, vend;
        RHS.GetInterval(vbeg, vend);

        vector_fcbiilu2 *rhs_data = NULL;
        VectorInitDataFcbiilu2(&rhs_data, RHS.GetCommunicator(), RHS.GetName().c_str());
        VectorPreallocateFcbiilu2(rhs_data, local_size);

        vector_fcbiilu2 *solution_data = NULL;
        VectorInitDataFcbiilu2(&solution_data, SOL.GetCommunicator(), SOL.GetName().c_str());
        VectorPreallocateFcbiilu2(solution_data, local_size);
        VectorFillFcbiilu2(rhs_data, &RHS[vbeg]);
        VectorFinalizeFcbiilu2(rhs_data);

        VectorFillFcbiilu2(solution_data, &SOL[vbeg]);
        VectorFinalizeFcbiilu2(solution_data);
        bool result = SolverSolveFcbiilu2(solver_data, rhs_data, solution_data);
        if (result) VectorLoadFcbiilu2(solution_data, &SOL[vbeg]);
        iter_time = solver_data->dstat[9];
        return result;
    }

    bool SolverFCBIILU2::Clear() {
        if (matrix_data != NULL) {
            MatrixDestroyDataFcbiilu2(&matrix_data);
        }
        SolverDestroyDataFcbiilu2(&solver_data);
        return true;
    }

    bool SolverFCBIILU2::isMatrixSet() {
        return matrix_data != NULL;
    }

    std::string SolverFCBIILU2::GetParameter(std::string name) const {
        if (name == "time_prec") return INMOST::to_string(time_prec);
        if (name == "time_iter") return INMOST::to_string(iter_time);
        if (name == "time_total") return INMOST::to_string(time_prec + iter_time);
        if (name == "prec_density") return INMOST::to_string(solver_data->dstat[0]);
        if (name == "pivot_mod") return INMOST::to_string(solver_data->istat[0]);
        std::cout << "Parameter " << name << " is unknown" << std::endl;
        return "";
    }

    void SolverFCBIILU2::SetParameter(std::string name, std::string value) {
        const char *val = value.c_str();
        if (name == "kovl") solver_data->kovl = atoi(val);
        else if (name == "tau") solver_data->tau = atof(val);
        else if (name == "eps") solver_data->eps = atof(val);
        else if (name == "nit") solver_data->nit = atoi(val);
        else if (name == "msglev") solver_data->msglev = atoi(val);
        else std::cout << "Parameter " << name << " is unknown" << std::endl;
    }

    const INMOST_DATA_ENUM_TYPE SolverFCBIILU2::Iterations() const {
        return static_cast<INMOST_DATA_ENUM_TYPE>(solver_data->ITER);
    }

    const INMOST_DATA_REAL_TYPE SolverFCBIILU2::Residual() const {
        return solver_data->RESID;
    }

    const std::string SolverFCBIILU2::ReturnReason() const {
        return "Unspecified for FCBIILU2";
    }

    const std::string SolverFCBIILU2::SolverName() const {
        return "fcbiilu2";
    }

    void SolverFCBIILU2::Finalize() {
        SolverFinalizeFcbiilu2();
    }

    SolverFCBIILU2::~SolverFCBIILU2() {
        this->Clear();
    }

}<commit_msg>k3 interface bug fixed<commit_after>#include <Source/Misc/utils.h>
#include "SolverFCBIILU2.h"
#include "solver_fcbiilu2.h"

namespace INMOST {

    SolverFCBIILU2::SolverFCBIILU2() {
        solver_data = NULL;
        matrix_data = NULL;
    }

    SolverInterface *SolverFCBIILU2::Copy(const SolverInterface *other) {
        if (other == NULL) {
            throw INMOST::SolverCopyNullException;
        }
        const SolverFCBIILU2 *fcother;
        try {
            fcother = dynamic_cast<const SolverFCBIILU2 *>(other);
        } catch (...) {
            throw INMOST::SolverCopyException;
        }
        SolverCopyDataFcbiilu2(&solver_data, fcother->solver_data, communicator);
        if (fcother->matrix_data != NULL) {
            MatrixCopyDataFcbiilu2(&matrix_data, fcother->matrix_data);
            SolverSetMatrixFcbiilu2(solver_data, matrix_data, false, false);
        }
        return this;
    }

    void SolverFCBIILU2::Assign(const SolverInterface *other) {
        if (other == NULL) {
            throw INMOST::SolverAssignNullException;
        }
        const SolverFCBIILU2 *fcother;
        try {
            fcother = dynamic_cast<const SolverFCBIILU2 *>(other);
        } catch (...) {
            throw INMOST::SolverAssignException;
        }
        SolverAssignDataFcbiilu2(solver_data, fcother->solver_data);
        if (fcother->matrix_data != NULL) {
            if (matrix_data != NULL) {
                MatrixAssignDataFcbiilu2(matrix_data, fcother->matrix_data);
            } else {
                MatrixCopyDataFcbiilu2(&matrix_data, fcother->matrix_data);
            }
            SolverSetMatrixFcbiilu2(solver_data, matrix_data, false, false);
        }
    }

    void SolverFCBIILU2::Setup(int *argc, char ***argv, SolverParameters &p) {
        SolverInitDataFcbiilu2(&solver_data, communicator, p.solverPrefix.c_str());
        solver_data->kovl = 0;    // number of overlap layers: kovl=0,1,2,...
        solver_data->tau = 3e-3;  // the ILU2 precision (for the submatrix factorization); tau=3e-3
        solver_data->eps = 1e-5;  // the residual precision: ||r|| < eps * ||b||; eps=1e-6
        solver_data->nit = 999;   // number of iterations permitted; nit=999
        solver_data->msglev = 2;  // messages level; msglev=0 for silent; msglev=1 to output solution statistics
        SolverInitializeFcbiilu2(solver_data, argc, argv, p.internalFile.c_str());
        for (parameters_iterator_t parameter = p.parameters.begin(); parameter < p.parameters.end(); parameter++) {
            this->SetParameter((*parameter).first, (*parameter).second);
        }
    }

    void SolverFCBIILU2::SetMatrix(Sparse::Matrix &A, bool ModifiedPattern, bool OldPreconditioner) {
        bool modified_pattern = ModifiedPattern;
        //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver;
        if (matrix_data == NULL) {
            MatrixInitDataFcbiilu2(&matrix_data, A.GetCommunicator(), A.GetName().c_str());
            modified_pattern = true;
        }
        if (modified_pattern) {
            global_size = local_size = A.Size();

            MatrixDestroyDataFcbiilu2(&matrix_data);
            MatrixInitDataFcbiilu2(&matrix_data, A.GetCommunicator(), A.GetName().c_str());
            INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 1;
            int nproc, myid;
#if defined(USE_MPI)
            MPI_Comm_size(A.GetCommunicator(), &nproc);
            MPI_Comm_rank(A.GetCommunicator(), &myid);
#else
            nproc = 1;
            myid = 0;
#endif
            int *ibl = (int *) malloc(sizeof(int) * (nproc + 1));
            ibl[0] = 0;
            int n = A.Size();
#if defined(USE_MPI)
            INMOST_DATA_ENUM_TYPE mbeg, mend;
            A.GetInterval(mbeg, mend);
            n = mend - mbeg;
            int block_end = mend;
            MPI_Allgather(&block_end, 1, MPI_INT, &ibl[1], 1, MPI_INT, A.GetCommunicator());
#else
            ibl[1] = n;
#endif
            int *ia = (int *) malloc(sizeof(int) * (n + 1));
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size();
            int *ja = (int *) malloc(sizeof(int) * nnz);
            double *values = (double *) malloc(sizeof(double) * nnz);
            ia[0] = shift;
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) {
                for (Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) {
                    ja[k] = jt->first + 1;
                    values[k] = jt->second;
                    //std::cout<<"# q="<<q<<" k="<<k<<" ja="<<ja[k]<<" a="<<values[k]<<std::endl;//db!
                    k++;
                }
                shift += it->Size();
                ia[q++] = shift;
            }
            MatrixFillFcbiilu2(matrix_data, n, nproc, ibl, ia, ja, values);
        } else {
            INMOST_DATA_ENUM_TYPE nnz = 0, k = 0;
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size();
            double *values = (double *) malloc(sizeof(double) * nnz);
            k = 0;
            for (Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++)
                for (Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++)
                    values[k++] = jt->second;
            MatrixFillValuesFcbiilu2(matrix_data, values);
        }
        MatrixFinalizeFcbiilu2(matrix_data);
        SolverSetMatrixFcbiilu2(solver_data, matrix_data, modified_pattern, OldPreconditioner);
        time_prec = solver_data->dstat[7];
    }

    bool SolverFCBIILU2::Solve(INMOST::Sparse::Vector &RHS, INMOST::Sparse::Vector &SOL) {
        INMOST_DATA_ENUM_TYPE vbeg, vend;
        RHS.GetInterval(vbeg, vend);

        vector_fcbiilu2 *rhs_data = NULL;
        VectorInitDataFcbiilu2(&rhs_data, RHS.GetCommunicator(), RHS.GetName().c_str());
        VectorPreallocateFcbiilu2(rhs_data, local_size);

        vector_fcbiilu2 *solution_data = NULL;
        VectorInitDataFcbiilu2(&solution_data, SOL.GetCommunicator(), SOL.GetName().c_str());
        VectorPreallocateFcbiilu2(solution_data, local_size);
        VectorFillFcbiilu2(rhs_data, &RHS[vbeg]);
        VectorFinalizeFcbiilu2(rhs_data);

        VectorFillFcbiilu2(solution_data, &SOL[vbeg]);
        VectorFinalizeFcbiilu2(solution_data);
        bool result = SolverSolveFcbiilu2(solver_data, rhs_data, solution_data);
        if (result) VectorLoadFcbiilu2(solution_data, &SOL[vbeg]);
        iter_time = solver_data->dstat[9];
        return result;
    }

    bool SolverFCBIILU2::Clear() {
        if (matrix_data != NULL) {
            MatrixDestroyDataFcbiilu2(&matrix_data);
        }
        SolverDestroyDataFcbiilu2(&solver_data);
        return true;
    }

    bool SolverFCBIILU2::isMatrixSet() {
        return matrix_data != NULL;
    }

    std::string SolverFCBIILU2::GetParameter(std::string name) const {
        if (name == "time_prec") return INMOST::to_string(time_prec);
        if (name == "time_iter") return INMOST::to_string(iter_time);
        if (name == "time_total") return INMOST::to_string(time_prec + iter_time);
        if (name == "prec_density") return INMOST::to_string(solver_data->dstat[0]);
        if (name == "pivot_mod") return INMOST::to_string(solver_data->istat[0]);
        std::cout << "Parameter " << name << " is unknown" << std::endl;
        return "";
    }

    void SolverFCBIILU2::SetParameter(std::string name, std::string value) {
        const char *val = value.c_str();
        if (name == "kovl") solver_data->kovl = atoi(val);
        else if (name == "tau") solver_data->tau = atof(val);
        else if (name == "eps") solver_data->eps = atof(val);
        else if (name == "nit") solver_data->nit = atoi(val);
        else if (name == "msglev") solver_data->msglev = atoi(val);
        else std::cout << "Parameter " << name << " is unknown" << std::endl;
    }

    const INMOST_DATA_ENUM_TYPE SolverFCBIILU2::Iterations() const {
        return static_cast<INMOST_DATA_ENUM_TYPE>(solver_data->ITER);
    }

    const INMOST_DATA_REAL_TYPE SolverFCBIILU2::Residual() const {
        return solver_data->RESID;
    }

    const std::string SolverFCBIILU2::ReturnReason() const {
        return "Unspecified for FCBIILU2";
    }

    const std::string SolverFCBIILU2::SolverName() const {
        return "fcbiilu2";
    }

    void SolverFCBIILU2::Finalize() {
        SolverFinalizeFcbiilu2();
    }

    SolverFCBIILU2::~SolverFCBIILU2() {
        this->Clear();
    }

}<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/fir/memdiags_fir.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 memdiags_fir.C
/// @brief Subroutines for memdiags/prd FIR
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>

#include <generic/memory/lib/utils/scom.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/fir/fir.H>
#include <lib/fir/memdiags_fir.H>
#include <lib/mc/port.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

namespace mss
{

namespace unmask
{

///
/// @brief Unmask and setup actions for memdiags related FIR
/// @param[in] i_target the fapi2::Target MCBIST
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template<>
fapi2::ReturnCode after_memdiags( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    fapi2::ReturnCode l_rc;
    fapi2::buffer<uint64_t> dsm0_buffer;
    uint64_t rd_tag_delay = 0;
    uint64_t wr_done_delay = 0;
    uint64_t mnfg_flag = 0;
    fapi2::ATTR_CHIP_EC_FEATURE_HW414700_Type l_checkstop_flag;

    for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        fir::reg<MCA_FIR> l_ecc64_fir_reg(p, l_rc);
        FAPI_TRY(l_rc, "unable to create fir::reg for %d", MCA_FIR);

        fir::reg<MCA_MBACALFIRQ> l_cal_fir_reg(p, l_rc);
        FAPI_TRY(l_rc, "unable to create fir::reg for %d", MCA_MBACALFIRQ);

        // Read out the wr_done and rd_tag delays and find min
        // and set the RCD Protect Time to this value
        FAPI_TRY (mss::read_dsm0q_register(p, dsm0_buffer) );
        mss::get_wrdone_delay(dsm0_buffer, wr_done_delay);
        mss::get_rdtag_delay(dsm0_buffer, rd_tag_delay);
        const auto rcd_protect_time = std::min(wr_done_delay, rd_tag_delay);
        FAPI_TRY (mss::change_rcd_protect_time(p, rcd_protect_time) );

        l_ecc64_fir_reg.checkstop<MCA_FIR_MAINLINE_AUE>()
        .recoverable_error<MCA_FIR_MAINLINE_UE>()
        .checkstop<MCA_FIR_MAINLINE_IAUE>()
        .recoverable_error<MCA_FIR_MAINLINE_IUE>()
        .checkstop<MCA_FIR_MAINTENANCE_AUE>()
        .checkstop<MCA_FIR_MAINTENANCE_IAUE>();

        // If ATTR_CHIP_EC_FEATURE_HW414700 is enabled set checkstops
        auto l_chip_target = mss::find_target<fapi2::TARGET_TYPE_PROC_CHIP>(i_target);
        FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_HW414700, l_chip_target, l_checkstop_flag) );

        if (l_checkstop_flag)
        {
            l_ecc64_fir_reg.checkstop<MCA_FIR_MAINLINE_UE>()
            .checkstop<MCA_FIR_MAINLINE_RCD>();
        }

        // If MNFG FLAG Threshhold is enabled skip IUE unflagging
        FAPI_TRY (mss::mnfg_flags(mnfg_flag) );

        if (mnfg_flag != fapi2::ENUM_ATTR_MNFG_FLAGS_MNFG_THRESHOLDS)
        {
            l_ecc64_fir_reg.recoverable_error<MCA_FIR_MAINTENANCE_IUE>();
        }

        l_cal_fir_reg.recoverable_error<MCA_MBACALFIRQ_PORT_FAIL>();

        FAPI_TRY(l_ecc64_fir_reg.write(), "unable to write fir::reg %d", MCA_FIR);
        FAPI_TRY(l_cal_fir_reg.write(), "unable to write fir::reg %d", MCA_MBACALFIRQ);

        // Note: We also want to include the following setup RCD recovery and port fail
        FAPI_TRY( mss::change_port_fail_disable(p, mss::LOW) );
        FAPI_TRY( mss::change_rcd_recovery_disable(p, mss::LOW) );
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Unmask and setup actions for scrub related FIR
/// @param[in] i_target the fapi2::Target MCBIST
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template<>
fapi2::ReturnCode after_background_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        fapi2::ReturnCode l_rc;
        fir::reg<MCA_FIR> l_ecc64_fir_reg(p, l_rc);
        FAPI_TRY(l_rc, "unable to create fir::reg for %d", MCA_FIR);

        l_ecc64_fir_reg.recoverable_error<MCA_FIR_MAINLINE_MPE_RANK_0_TO_7,
                                          MCA_FIR_MAINLINE_MPE_RANK_0_TO_7_LEN>()
                                          .recoverable_error<MCA_FIR_MAINLINE_NCE>()
                                          .recoverable_error<MCA_FIR_MAINLINE_TCE>()
                                          .recoverable_error<MCA_FIR_MAINLINE_IMPE>()
                                          .recoverable_error<MCA_FIR_MAINTENANCE_IMPE>();

        FAPI_TRY(l_ecc64_fir_reg.write(), "unable to write fir::reg %d", MCA_FIR);
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

}
}
<commit_msg>Update HPW Level for MSS API library<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/fir/memdiags_fir.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 memdiags_fir.C
/// @brief Subroutines for memdiags/prd FIR
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <p9_mc_scom_addresses.H>
#include <p9_mc_scom_addresses_fld.H>

#include <generic/memory/lib/utils/scom.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/fir/fir.H>
#include <lib/fir/memdiags_fir.H>
#include <lib/mc/port.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;

namespace mss
{

namespace unmask
{

///
/// @brief Unmask and setup actions for memdiags related FIR
/// @param[in] i_target the fapi2::Target MCBIST
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template<>
fapi2::ReturnCode after_memdiags( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    fapi2::ReturnCode l_rc;
    fapi2::buffer<uint64_t> dsm0_buffer;
    uint64_t rd_tag_delay = 0;
    uint64_t wr_done_delay = 0;
    uint64_t mnfg_flag = 0;
    fapi2::ATTR_CHIP_EC_FEATURE_HW414700_Type l_checkstop_flag;

    for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        fir::reg<MCA_FIR> l_ecc64_fir_reg(p, l_rc);
        FAPI_TRY(l_rc, "unable to create fir::reg for %d", MCA_FIR);

        fir::reg<MCA_MBACALFIRQ> l_cal_fir_reg(p, l_rc);
        FAPI_TRY(l_rc, "unable to create fir::reg for %d", MCA_MBACALFIRQ);

        // Read out the wr_done and rd_tag delays and find min
        // and set the RCD Protect Time to this value
        FAPI_TRY (mss::read_dsm0q_register(p, dsm0_buffer) );
        mss::get_wrdone_delay(dsm0_buffer, wr_done_delay);
        mss::get_rdtag_delay(dsm0_buffer, rd_tag_delay);
        const auto rcd_protect_time = std::min(wr_done_delay, rd_tag_delay);
        FAPI_TRY (mss::change_rcd_protect_time(p, rcd_protect_time) );

        l_ecc64_fir_reg.checkstop<MCA_FIR_MAINLINE_AUE>()
        .recoverable_error<MCA_FIR_MAINLINE_UE>()
        .checkstop<MCA_FIR_MAINLINE_IAUE>()
        .recoverable_error<MCA_FIR_MAINLINE_IUE>()
        .checkstop<MCA_FIR_MAINTENANCE_AUE>()
        .checkstop<MCA_FIR_MAINTENANCE_IAUE>();

        // If ATTR_CHIP_EC_FEATURE_HW414700 is enabled set checkstops
        auto l_chip_target = mss::find_target<fapi2::TARGET_TYPE_PROC_CHIP>(i_target);
        FAPI_TRY( FAPI_ATTR_GET(fapi2::ATTR_CHIP_EC_FEATURE_HW414700, l_chip_target, l_checkstop_flag) );

        if (l_checkstop_flag)
        {
            l_ecc64_fir_reg.checkstop<MCA_FIR_MAINLINE_UE>()
            .checkstop<MCA_FIR_MAINLINE_RCD>();
        }

        // If MNFG FLAG Threshhold is enabled skip IUE unflagging
        FAPI_TRY (mss::mnfg_flags(mnfg_flag) );

        if (mnfg_flag != fapi2::ENUM_ATTR_MNFG_FLAGS_MNFG_THRESHOLDS)
        {
            l_ecc64_fir_reg.recoverable_error<MCA_FIR_MAINTENANCE_IUE>();
        }

        l_cal_fir_reg.recoverable_error<MCA_MBACALFIRQ_PORT_FAIL>();

        FAPI_TRY(l_ecc64_fir_reg.write(), "unable to write fir::reg %d", MCA_FIR);
        FAPI_TRY(l_cal_fir_reg.write(), "unable to write fir::reg %d", MCA_MBACALFIRQ);

        // Note: We also want to include the following setup RCD recovery and port fail
        FAPI_TRY( mss::change_port_fail_disable(p, mss::LOW) );
        FAPI_TRY( mss::change_rcd_recovery_disable(p, mss::LOW) );
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Unmask and setup actions for scrub related FIR
/// @param[in] i_target the fapi2::Target MCBIST
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template<>
fapi2::ReturnCode after_background_scrub( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    for (const auto& p : mss::find_targets<TARGET_TYPE_MCA>(i_target))
    {
        fapi2::ReturnCode l_rc;
        fir::reg<MCA_FIR> l_ecc64_fir_reg(p, l_rc);
        FAPI_TRY(l_rc, "unable to create fir::reg for %d", MCA_FIR);

        l_ecc64_fir_reg.recoverable_error<MCA_FIR_MAINLINE_MPE_RANK_0_TO_7,
                                          MCA_FIR_MAINLINE_MPE_RANK_0_TO_7_LEN>()
                                          .recoverable_error<MCA_FIR_MAINLINE_NCE>()
                                          .recoverable_error<MCA_FIR_MAINLINE_TCE>()
                                          .recoverable_error<MCA_FIR_MAINLINE_IMPE>()
                                          .recoverable_error<MCA_FIR_MAINTENANCE_IMPE>();

        FAPI_TRY(l_ecc64_fir_reg.write(), "unable to write fir::reg %d", MCA_FIR);
    }

    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    return fapi2::current_err;
}

}
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/generic/memory/lib/spd/lrdimm/ddr4/lrdimm_raw_cards.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 raw_cards.C
/// @brief LRDIMM raw card data structure
/// Contains RCW settings per raw card rev
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

// std lib
#include <vector>

// fapi2
#include <fapi2.H>

// mss lib
#include <generic/memory/lib/spd/lrdimm/ddr4/lrdimm_raw_cards.H>

namespace mss
{

///
/// @brief raw card B0 settings
///
// TODO RTC:160116 Fill in valid RCD data for LRDIMM
rcw_settings lrdimm_rc_b0( 0x00, // RC00
                           0x00); // RC01

rcw_settings lrdimm_rc_default( 0x00, // RC00
                                0x00); // RC01

namespace lrdimm
{

// TODO - RTC:160121 Catch all for adding raw card data for DIMMs
const std::vector< std::pair< uint8_t , rcw_settings> > RAW_CARDS =
{
    // I expect this to grow as Warren M. expects us to have
    // settings for every raw card that JEDEC puts out.  Openpower
    // can't break due to a missing raw card...
    {raw_card_rev::B0, lrdimm_rc_b0},
};

}// lrdimm
}// mss
<commit_msg>Adds new LRDIMM raw cards settings<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/generic/memory/lib/spd/lrdimm/ddr4/lrdimm_raw_cards.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] 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 raw_cards.C
/// @brief LRDIMM raw card data structure
/// Contains RCW settings per raw card rev
///
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

// std lib
#include <vector>

// fapi2
#include <fapi2.H>

// mss lib
#include <generic/memory/lib/spd/lrdimm/ddr4/lrdimm_raw_cards.H>

namespace mss
{

// raw card settings
// fill in valid RCD data for LRDIMM
rcw_settings lrdimm_rc_a0( 0x00,  // RC00
                           0x00); // RC01
rcw_settings lrdimm_rc_b0( 0x00,
                           0x00);
rcw_settings lrdimm_rc_b1( 0x00,
                           0x00);
rcw_settings lrdimm_rc_b2( 0x00,
                           0x00);
rcw_settings lrdimm_rc_d2( 0x00,
                           0x00);
rcw_settings lrdimm_rc_default( 0x00, // RC00
                                0x00); // RC01

namespace lrdimm
{

// Catch all for adding raw card data for DIMMs
const std::vector< std::pair< uint8_t , rcw_settings> > RAW_CARDS =
{
    // I expect this to grow as Warren M. expects us to have
    // settings for every raw card that JEDEC puts out.  Openpower
    // can't break due to a missing raw card...
    {raw_card_rev::A0, lrdimm_rc_a0},
    {raw_card_rev::B0, lrdimm_rc_b0},
    {raw_card_rev::B1, lrdimm_rc_b1},
    {raw_card_rev::B2, lrdimm_rc_b2},
    {raw_card_rev::D2, lrdimm_rc_d2},
};

}// lrdimm
}// mss
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mlistindexfloatingview.h"
#include "mlistindexfloatingview_p.h"
#include "mlistview_p.h"

#include <mlistindex.h>

#include <MApplicationPage>
#include <MCancelEvent>
#include <MPannableViewport>
#include <MSeparator>
#include "mlistindextooltip.h"

#include <QGraphicsLinearLayout>
#include <QGraphicsSceneMouseEvent>
#include <QTapAndHoldGesture>

MListIndexFloatingViewPrivate::MListIndexFloatingViewPrivate()
    : MWidgetViewPrivate(),
    controller(NULL),
    container(NULL),
    list(NULL),
    tooltipWidget(NULL),
    tooltipVerticalOffset(0),
    contentHeight(0),
    fastScrollPosition()
{
}

MListIndexFloatingViewPrivate::~MListIndexFloatingViewPrivate()
{
}

void MListIndexFloatingViewPrivate::init()
{
    Q_Q(MListIndexFloatingView);
    q->connect(&scrollToDelayQueue, SIGNAL(timeout()), q, SLOT(_q_scrollListToCurrentIndex()));
}

void MListIndexFloatingViewPrivate::initLayout()
{
    attachToContainer();
    configureController();
}

void MListIndexFloatingViewPrivate::configureController()
{
    controller->show();
    controller->setOpacity(1.0);
}

void MListIndexFloatingViewPrivate::connectToList()
{
    Q_Q(MListIndexFloatingView);

    if (list)
        q->disconnect(list, SIGNAL(parentChanged()), q, SLOT(_q_listParentChanged()));

    if (q->model()->list())
        q->connect(q->model()->list(), SIGNAL(parentChanged()), q, SLOT(_q_listParentChanged()));

    list = q->model()->list();
}

void MListIndexFloatingViewPrivate::updateLayout()
{
    Q_Q(MListIndexFloatingView);

    if(container) {
        controller->resize(controller->preferredWidth(), containerRect.height() - q->model()->offset().y());
        controller->setPos(containerRect.x() + containerRect.width() - controller->preferredWidth(), containerRect.y() + q->model()->offset().y());
        updateContentHeight();
    }
}

void MListIndexFloatingViewPrivate::updateContentHeight()
{
    Q_Q(MListIndexFloatingView);
    contentHeight = (controller->size().height() - (q->style()->marginTop() + q->style()->marginBottom()));
}

void MListIndexFloatingViewPrivate::attachToContainer()
{
    Q_Q(MListIndexFloatingView);

    if (container)
        container->disconnect(container, SIGNAL(exposedContentRectChanged()), q, SLOT(_q_exposedContentRectChanged()));

    if (q->model()->list()) {
        container = MListViewPrivateNamespace::findParentWidgetOfType<MApplicationPage>(q->model()->list());

        if (container) {
            controller->setParentItem(container);

            container->connect(container, SIGNAL(exposedContentRectChanged()), q, SLOT(_q_recalculateListIndexRegion()));
            _q_recalculateListIndexRegion();
        }
    }
}

MListIndexTooltip *MListIndexFloatingViewPrivate::tooltip()
{
    Q_Q(MListIndexFloatingView);

    if (!tooltipWidget) {
        tooltipWidget = new MListIndexTooltip(controller);
        tooltipWidget->setIndexCount(q->style()->floatingIndexCount());
        // should be hidden by default;
        tooltipWidget->hide();

        q->connect(tooltipWidget, SIGNAL(geometryChanged()), q, SLOT(_q_recalculateTooltipOffsets()));
        _q_recalculateTooltipOffsets();
    }

    return tooltipWidget;
}

void MListIndexFloatingViewPrivate::updateTooltipPosition(int y)
{
    Q_Q(MListIndexFloatingView);

    if (tooltip()) {
        qreal top = 0;
        qreal tooltipHeight = tooltip()->size().height();

        if (y > tooltipHeight / 2 && y < tooltipVerticalOffset)
            top = y - tooltipHeight / 2;
        else if (y >= tooltipVerticalOffset)
            top = controller->size().height() - tooltipHeight;

        tooltip()->setPos(-tooltip()->size().width() - q->style()->floatingIndexOffset(), top);
    }
}

void MListIndexFloatingViewPrivate::updateTooltipData()
{
    Q_Q(MListIndexFloatingView);

    int shortcutCount = q->model()->shortcutIndexes().count();
    int shortcutIndex = q->model()->shortcutIndexes().indexOf(currentScrollToIndex);

    int floatingIndexCount = qMin(q->style()->floatingIndexCount(), shortcutCount);
    int startIndex = qMax(shortcutIndex - floatingIndexCount + 2, 0);
    int endIndex = qMin(startIndex + floatingIndexCount - 1, shortcutCount - 1);
    startIndex = qMin(startIndex, shortcutCount - floatingIndexCount);

    for (int i = startIndex; i <= endIndex; i++) {
        tooltip()->setIndexText(i - startIndex, q->model()->shortcutLabels().at(i));
    }
    tooltip()->setIndexSelected(shortcutIndex - startIndex);
}

void MListIndexFloatingViewPrivate::scrollToGroupHeader(int y)
{
    Q_Q(MListIndexFloatingView);

    qreal offset = (qreal)y / contentHeight;
    int shortcutCount = q->model()->shortcutIndexes().count();
    int shortcutIndex = shortcutCount * offset;

    if (shortcutIndex < shortcutCount && shortcutIndex >= 0) {
        QModelIndex scrollToIndex = q->model()->shortcutIndexes().at(shortcutIndex);
        if (scrollToIndex.isValid()) {
            if (scrollToIndex != currentScrollToIndex) {
                int snapDirection = -1;
                if (q->model()->shortcutIndexes().indexOf(currentScrollToIndex) < shortcutIndex)
                    snapDirection = 1;

                currentScrollToIndex = scrollToIndex;
                queueListScrollTo();
                updateTooltipData();

                tooltip()->snap(q->style()->floatingSnapDistance() * snapDirection);
            }
        }
    }
}

void MListIndexFloatingViewPrivate::queueListScrollTo()
{
    if (!scrollToDelayQueue.isActive())
        scrollToDelayQueue.start(50);
}

void MListIndexFloatingViewPrivate::_q_scrollListToCurrentIndex()
{
    Q_Q(MListIndexFloatingView);
    q->model()->list()->scrollTo(currentScrollToIndex, MList::PositionAtTopHint);
    scrollToDelayQueue.stop();
}

void MListIndexFloatingViewPrivate::_q_recalculateListIndexRegion()
{
    containerRect = container->exposedContentRect();
    updateLayout();
}

void MListIndexFloatingViewPrivate::_q_recalculateTooltipOffsets()
{
    tooltipVerticalOffset = controller->size().height() - tooltip()->size().height() / 2;
}

void MListIndexFloatingViewPrivate::_q_listParentChanged()
{
    initLayout();
}

void MListIndexFloatingViewPrivate::beginFastScrolling(const QPointF &pos)
{
    Q_Q(MListIndexFloatingView);

    if (q->model()->shortcutIndexes().isEmpty())
        return;

    updateFastScrolling(pos);
    fastScrollPosition = pos;

    tooltip()->show();
}

void MListIndexFloatingViewPrivate::updateFastScrolling(const QPointF &offset)
{
    fastScrollPosition += offset;
    int y = controller->mapFromScene(fastScrollPosition).y();
    scrollToGroupHeader(y);
    updateTooltipPosition(y);
}

void MListIndexFloatingViewPrivate::endFastScrolling()
{
    tooltip()->hide();
    fastScrollPosition = QPointF(0,0);
}

MListIndexFloatingView::MListIndexFloatingView(MListIndex *controller)
    : MWidgetView(*(new MListIndexFloatingViewPrivate),  controller)
{
    Q_D(MListIndexFloatingView);
    d->controller = controller;
    d->init();
}

MListIndexFloatingView::~MListIndexFloatingView()
{
}

void MListIndexFloatingView::setupModel()
{
    MWidgetView::setupModel();

    QList<const char*> modifications;
    modifications << MListIndexModel::List;
    modifications << MListIndexModel::ShortcutLabels;
    modifications << MListIndexModel::ShortcutIndexes;
    updateData(modifications);
}

void MListIndexFloatingView::updateData(const QList<const char *> &modifications)
{
    Q_D(MListIndexFloatingView);

    MWidgetView::updateData(modifications);

    const char *member;
    for (int i = 0; i < modifications.count(); i++) {
        member = modifications[i];
        if (member == MListIndexModel::List) {
            if (model()->list()) {
                d->initLayout();
                d->connectToList();
            }
        } else if (member == MListIndexModel::ShortcutIndexes) {
            d->tooltip()->setIndexCount(qMin(style()->floatingIndexCount(), model()->shortcutIndexes().count()));
        }
    }
}

void MListIndexFloatingView::applyStyle()
{
    Q_D(MListIndexFloatingView);

    MWidgetView::applyStyle();
    d->tooltip()->setStyleName(style()->floatingStyleName());
    d->updateContentHeight();
}

void MListIndexFloatingView::drawBackground(QPainter *painter, const QStyleOptionGraphicsItem *option) const
{
    Q_UNUSED(painter);
    Q_UNUSED(option);
}

void MListIndexFloatingView::tapAndHoldGestureEvent(QGestureEvent *event, QTapAndHoldGesture *gesture)
{
    Q_D(MListIndexFloatingView);

    if (d->tooltip()->isVisible()) {
        event->accept(gesture);
        return;
    }

    MWidgetView::tapAndHoldGestureEvent(event, gesture);
}

void MListIndexFloatingView::panGestureEvent(QGestureEvent *event, QPanGesture *gesture)
{
    Q_D(MListIndexFloatingView);
    if (gesture->state() == Qt::GestureStarted)
        d->beginFastScrolling(event->mapToGraphicsScene(gesture->hotSpot()));
    else if (gesture->state() == Qt::GestureFinished || gesture->state() == Qt::GestureCanceled)
        d->endFastScrolling();
    else if (gesture->state() == Qt::GestureUpdated)
        d->updateFastScrolling(gesture->delta());

    event->accept(gesture);
}

#include "moc_mlistindexfloatingview.cpp"

M_REGISTER_VIEW_NEW(MListIndexFloatingView, MListIndex)
<commit_msg>Fixes: NB#232754 - Floating fast scroll shows previous value when changing sort method<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "mlistindexfloatingview.h"
#include "mlistindexfloatingview_p.h"
#include "mlistview_p.h"

#include <mlistindex.h>

#include <MApplicationPage>
#include <MCancelEvent>
#include <MPannableViewport>
#include <MSeparator>
#include "mlistindextooltip.h"

#include <QGraphicsLinearLayout>
#include <QGraphicsSceneMouseEvent>
#include <QTapAndHoldGesture>

MListIndexFloatingViewPrivate::MListIndexFloatingViewPrivate()
    : MWidgetViewPrivate(),
    controller(NULL),
    container(NULL),
    list(NULL),
    tooltipWidget(NULL),
    tooltipVerticalOffset(0),
    contentHeight(0),
    fastScrollPosition()
{
}

MListIndexFloatingViewPrivate::~MListIndexFloatingViewPrivate()
{
}

void MListIndexFloatingViewPrivate::init()
{
    Q_Q(MListIndexFloatingView);
    q->connect(&scrollToDelayQueue, SIGNAL(timeout()), q, SLOT(_q_scrollListToCurrentIndex()));
}

void MListIndexFloatingViewPrivate::initLayout()
{
    attachToContainer();
    configureController();
}

void MListIndexFloatingViewPrivate::configureController()
{
    controller->show();
    controller->setOpacity(1.0);
}

void MListIndexFloatingViewPrivate::connectToList()
{
    Q_Q(MListIndexFloatingView);

    if (list)
        q->disconnect(list, SIGNAL(parentChanged()), q, SLOT(_q_listParentChanged()));

    if (q->model()->list())
        q->connect(q->model()->list(), SIGNAL(parentChanged()), q, SLOT(_q_listParentChanged()));

    list = q->model()->list();
}

void MListIndexFloatingViewPrivate::updateLayout()
{
    Q_Q(MListIndexFloatingView);

    if(container) {
        controller->resize(controller->preferredWidth(), containerRect.height() - q->model()->offset().y());
        controller->setPos(containerRect.x() + containerRect.width() - controller->preferredWidth(), containerRect.y() + q->model()->offset().y());
        updateContentHeight();
    }
}

void MListIndexFloatingViewPrivate::updateContentHeight()
{
    Q_Q(MListIndexFloatingView);
    contentHeight = (controller->size().height() - (q->style()->marginTop() + q->style()->marginBottom()));
}

void MListIndexFloatingViewPrivate::attachToContainer()
{
    Q_Q(MListIndexFloatingView);

    if (container)
        container->disconnect(container, SIGNAL(exposedContentRectChanged()), q, SLOT(_q_exposedContentRectChanged()));

    if (q->model()->list()) {
        container = MListViewPrivateNamespace::findParentWidgetOfType<MApplicationPage>(q->model()->list());

        if (container) {
            controller->setParentItem(container);

            container->connect(container, SIGNAL(exposedContentRectChanged()), q, SLOT(_q_recalculateListIndexRegion()));
            _q_recalculateListIndexRegion();
        }
    }
}

MListIndexTooltip *MListIndexFloatingViewPrivate::tooltip()
{
    Q_Q(MListIndexFloatingView);

    if (!tooltipWidget) {
        tooltipWidget = new MListIndexTooltip(controller);
        tooltipWidget->setIndexCount(q->style()->floatingIndexCount());
        // should be hidden by default;
        tooltipWidget->hide();

        q->connect(tooltipWidget, SIGNAL(geometryChanged()), q, SLOT(_q_recalculateTooltipOffsets()));
        _q_recalculateTooltipOffsets();
    }

    return tooltipWidget;
}

void MListIndexFloatingViewPrivate::updateTooltipPosition(int y)
{
    Q_Q(MListIndexFloatingView);

    if (tooltip()) {
        qreal top = 0;
        qreal tooltipHeight = tooltip()->size().height();

        if (y > tooltipHeight / 2 && y < tooltipVerticalOffset)
            top = y - tooltipHeight / 2;
        else if (y >= tooltipVerticalOffset)
            top = controller->size().height() - tooltipHeight;

        tooltip()->setPos(-tooltip()->size().width() - q->style()->floatingIndexOffset(), top);
    }
}

void MListIndexFloatingViewPrivate::updateTooltipData()
{
    Q_Q(MListIndexFloatingView);

    int shortcutCount = q->model()->shortcutIndexes().count();
    int shortcutIndex = q->model()->shortcutIndexes().indexOf(currentScrollToIndex);

    int floatingIndexCount = qMin(q->style()->floatingIndexCount(), shortcutCount);
    int startIndex = qMax(shortcutIndex - floatingIndexCount + 2, 0);
    int endIndex = qMin(startIndex + floatingIndexCount - 1, shortcutCount - 1);
    startIndex = qMin(startIndex, shortcutCount - floatingIndexCount);

    for (int i = startIndex; i <= endIndex; i++) {
        tooltip()->setIndexText(i - startIndex, q->model()->shortcutLabels().at(i));
    }
    tooltip()->setIndexSelected(shortcutIndex - startIndex);
}

void MListIndexFloatingViewPrivate::scrollToGroupHeader(int y)
{
    Q_Q(MListIndexFloatingView);

    qreal offset = (qreal)y / contentHeight;
    int shortcutCount = q->model()->shortcutIndexes().count();
    int shortcutIndex = shortcutCount * offset;

    if (shortcutIndex < shortcutCount && shortcutIndex >= 0) {
        QModelIndex scrollToIndex = q->model()->shortcutIndexes().at(shortcutIndex);
        if (scrollToIndex.isValid()) {
            if (scrollToIndex != currentScrollToIndex) {
                int snapDirection = -1;
                if (q->model()->shortcutIndexes().indexOf(currentScrollToIndex) < shortcutIndex)
                    snapDirection = 1;

                currentScrollToIndex = scrollToIndex;
                queueListScrollTo();
                updateTooltipData();

                tooltip()->snap(q->style()->floatingSnapDistance() * snapDirection);
            }
        }
    }
}

void MListIndexFloatingViewPrivate::queueListScrollTo()
{
    if (!scrollToDelayQueue.isActive())
        scrollToDelayQueue.start(50);
}

void MListIndexFloatingViewPrivate::_q_scrollListToCurrentIndex()
{
    Q_Q(MListIndexFloatingView);
    q->model()->list()->scrollTo(currentScrollToIndex, MList::PositionAtTopHint);
    scrollToDelayQueue.stop();
}

void MListIndexFloatingViewPrivate::_q_recalculateListIndexRegion()
{
    containerRect = container->exposedContentRect();
    updateLayout();
}

void MListIndexFloatingViewPrivate::_q_recalculateTooltipOffsets()
{
    tooltipVerticalOffset = controller->size().height() - tooltip()->size().height() / 2;
}

void MListIndexFloatingViewPrivate::_q_listParentChanged()
{
    initLayout();
}

void MListIndexFloatingViewPrivate::beginFastScrolling(const QPointF &pos)
{
    Q_Q(MListIndexFloatingView);

    if (q->model()->shortcutIndexes().isEmpty())
        return;

    updateFastScrolling(pos);
    fastScrollPosition = pos;

    tooltip()->show();
}

void MListIndexFloatingViewPrivate::updateFastScrolling(const QPointF &offset)
{
    fastScrollPosition += offset;
    int y = controller->mapFromScene(fastScrollPosition).y();
    scrollToGroupHeader(y);
    updateTooltipPosition(y);
}

void MListIndexFloatingViewPrivate::endFastScrolling()
{
    tooltip()->hide();
    fastScrollPosition = QPointF(0,0);
}

MListIndexFloatingView::MListIndexFloatingView(MListIndex *controller)
    : MWidgetView(*(new MListIndexFloatingViewPrivate),  controller)
{
    Q_D(MListIndexFloatingView);
    d->controller = controller;
    d->init();
}

MListIndexFloatingView::~MListIndexFloatingView()
{
}

void MListIndexFloatingView::setupModel()
{
    MWidgetView::setupModel();

    QList<const char*> modifications;
    modifications << MListIndexModel::List;
    modifications << MListIndexModel::ShortcutLabels;
    modifications << MListIndexModel::ShortcutIndexes;
    updateData(modifications);
}

void MListIndexFloatingView::updateData(const QList<const char *> &modifications)
{
    Q_D(MListIndexFloatingView);

    MWidgetView::updateData(modifications);

    const char *member;
    for (int i = 0; i < modifications.count(); i++) {
        member = modifications[i];
        if (member == MListIndexModel::List) {
            if (model()->list()) {
                d->initLayout();
                d->connectToList();
            }
        } else if (member == MListIndexModel::ShortcutIndexes) {
            d->tooltip()->setIndexCount(qMin(style()->floatingIndexCount(), model()->shortcutIndexes().count()));
        } else if (member == MListIndexModel::ShortcutLabels) {
            d->updateTooltipData();
        }
    }
}

void MListIndexFloatingView::applyStyle()
{
    Q_D(MListIndexFloatingView);

    MWidgetView::applyStyle();
    d->tooltip()->setStyleName(style()->floatingStyleName());
    d->updateContentHeight();
}

void MListIndexFloatingView::drawBackground(QPainter *painter, const QStyleOptionGraphicsItem *option) const
{
    Q_UNUSED(painter);
    Q_UNUSED(option);
}

void MListIndexFloatingView::tapAndHoldGestureEvent(QGestureEvent *event, QTapAndHoldGesture *gesture)
{
    Q_D(MListIndexFloatingView);

    if (d->tooltip()->isVisible()) {
        event->accept(gesture);
        return;
    }

    MWidgetView::tapAndHoldGestureEvent(event, gesture);
}

void MListIndexFloatingView::panGestureEvent(QGestureEvent *event, QPanGesture *gesture)
{
    Q_D(MListIndexFloatingView);
    if (gesture->state() == Qt::GestureStarted)
        d->beginFastScrolling(event->mapToGraphicsScene(gesture->hotSpot()));
    else if (gesture->state() == Qt::GestureFinished || gesture->state() == Qt::GestureCanceled)
        d->endFastScrolling();
    else if (gesture->state() == Qt::GestureUpdated)
        d->updateFastScrolling(gesture->delta());

    event->accept(gesture);
}

#include "moc_mlistindexfloatingview.cpp"

M_REGISTER_VIEW_NEW(MListIndexFloatingView, MListIndex)
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * 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.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
//
//////////////////////////////////////////////////////////////////////////////

#include <stdafx.h>

#include <cursespp/Screen.h>
#include <cursespp/Colors.h>
#include <cursespp/MessageQueue.h>
#include <cursespp/Message.h>
#include <cursespp/Text.h>

#include "Checkbox.h"

using namespace cursespp;

#define UNCHECKED std::string("□")
#define CHECKED std::string("✓")

Checkbox::Checkbox()
: Window()
, checked(false)
, focused(false) {
    this->SetFrameVisible(false);
}

Checkbox::~Checkbox() {
}

void Checkbox::Show() {
    Window::Show();
    this->Redraw();
}

void Checkbox::SetText(const std::string& value) {
    if (value != this->buffer) {
        this->buffer = value;
        this->Redraw();
    }
}

void Checkbox::SetChecked(bool checked) {
    if (checked != this->checked) {
        this->checked = checked;
        this->Redraw();
        this->CheckChanged(this, checked);
    }
}

void Checkbox::Focus() {
    this->focused = true;
    this->Redraw();
}

void Checkbox::Blur() {
    this->focused = false;
    this->Redraw();
}

void Checkbox::Redraw() {
    WINDOW* c = this->GetContent();
    werase(c);

    int len = (int) u8len(this->buffer);
    int cx = this->GetContentWidth();

    std::string symbol = (this->checked ? CHECKED : UNCHECKED);
    std::string ellipsized = symbol + " " + this->buffer;
    text::Ellipsize(ellipsized, cx);

    int64 attrs = this->focused ? BOX_COLOR_RED_ON_BLACK : -1LL;

    if (attrs != -1) {
        wattron(c, COLOR_PAIR(attrs));
    }

    wprintw(c, ellipsized.c_str());

    if (attrs != -1) {
        wattroff(c, COLOR_PAIR(attrs));
    }

    this->Repaint();
}

bool Checkbox::KeyPress(const std::string& key) {
    if (key == " ") {
        this->SetChecked(!this->checked);
        return true;
    }
    return false;
}
<commit_msg>Checkbox now also actuates with enter/return as well.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * 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.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.
//
//////////////////////////////////////////////////////////////////////////////

#include <stdafx.h>

#include <cursespp/Screen.h>
#include <cursespp/Colors.h>
#include <cursespp/MessageQueue.h>
#include <cursespp/Message.h>
#include <cursespp/Text.h>

#include "Checkbox.h"

using namespace cursespp;

#define UNCHECKED std::string("□")
#define CHECKED std::string("✓")

Checkbox::Checkbox()
: Window()
, checked(false)
, focused(false) {
    this->SetFrameVisible(false);
}

Checkbox::~Checkbox() {
}

void Checkbox::Show() {
    Window::Show();
    this->Redraw();
}

void Checkbox::SetText(const std::string& value) {
    if (value != this->buffer) {
        this->buffer = value;
        this->Redraw();
    }
}

void Checkbox::SetChecked(bool checked) {
    if (checked != this->checked) {
        this->checked = checked;
        this->Redraw();
        this->CheckChanged(this, checked);
    }
}

void Checkbox::Focus() {
    this->focused = true;
    this->Redraw();
}

void Checkbox::Blur() {
    this->focused = false;
    this->Redraw();
}

void Checkbox::Redraw() {
    WINDOW* c = this->GetContent();
    werase(c);

    int len = (int) u8len(this->buffer);
    int cx = this->GetContentWidth();

    std::string symbol = (this->checked ? CHECKED : UNCHECKED);
    std::string ellipsized = symbol + " " + this->buffer;
    text::Ellipsize(ellipsized, cx);

    int64 attrs = this->focused ? BOX_COLOR_RED_ON_BLACK : -1LL;

    if (attrs != -1) {
        wattron(c, COLOR_PAIR(attrs));
    }

    wprintw(c, ellipsized.c_str());

    if (attrs != -1) {
        wattroff(c, COLOR_PAIR(attrs));
    }

    this->Repaint();
}

bool Checkbox::KeyPress(const std::string& key) {
    if (key == " " || key == "^M") {
        this->SetChecked(!this->checked);
        return true;
    }
    return false;
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2016 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/ui/vulkan/vulkan_device.h"

#include <gflags/gflags.h>

#include <cinttypes>
#include <mutex>
#include <string>

#include "third_party/renderdoc/renderdoc_app.h"

#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/profiling.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_immediate_drawer.h"
#include "xenia/ui/vulkan/vulkan_instance.h"
#include "xenia/ui/vulkan/vulkan_util.h"
#include "xenia/ui/window.h"

namespace xe {
namespace ui {
namespace vulkan {

VulkanDevice::VulkanDevice(VulkanInstance* instance) : instance_(instance) {
  if (FLAGS_vulkan_validation) {
    /*DeclareRequiredLayer("VK_LAYER_GOOGLE_unique_objects",
                         Version::Make(0, 0, 0), true);*/
    DeclareRequiredLayer("VK_LAYER_LUNARG_threading", Version::Make(0, 0, 0),
                         true);
    /*DeclareRequiredLayer("VK_LAYER_LUNARG_mem_tracker", Version::Make(0, 0,
       0),
                         true);*/
    DeclareRequiredLayer("VK_LAYER_LUNARG_object_tracker",
                         Version::Make(0, 0, 0), true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_draw_state", Version::Make(0, 0, 0),
                         true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_param_checker",
                         Version::Make(0, 0, 0), true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_swapchain", Version::Make(0, 0, 0),
                         true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_device_limits",
                         Version::Make(0, 0, 0), true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_image", Version::Make(0, 0, 0), true);
  }
}

VulkanDevice::~VulkanDevice() {
  if (handle) {
    vkDestroyDevice(handle, nullptr);
    handle = nullptr;
  }
}

bool VulkanDevice::Initialize(DeviceInfo device_info) {
  // Gather list of enabled layer names.
  auto layers_result = CheckRequirements(required_layers_, device_info.layers);
  auto& enabled_layers = layers_result.second;

  // Gather list of enabled extension names.
  auto extensions_result =
      CheckRequirements(required_extensions_, device_info.extensions);
  auto& enabled_extensions = extensions_result.second;

  // We wait until both extensions and layers are checked before failing out so
  // that the user gets a complete list of what they have/don't.
  if (!extensions_result.first || !layers_result.first) {
    FatalVulkanError(
        "Layer and extension verification failed; aborting initialization");
    return false;
  }

  // Query supported features so we can make sure we have what we need.
  VkPhysicalDeviceFeatures supported_features;
  vkGetPhysicalDeviceFeatures(device_info.handle, &supported_features);
  VkPhysicalDeviceFeatures enabled_features = {0};
  bool any_features_missing = false;
#define ENABLE_AND_EXPECT(name)                                  \
  if (!supported_features.name) {                                \
    any_features_missing = true;                                 \
    FatalVulkanError("Vulkan device is missing feature " #name); \
  } else {                                                       \
    enabled_features.name = VK_TRUE;                             \
  }
  ENABLE_AND_EXPECT(geometryShader);
  ENABLE_AND_EXPECT(depthClamp);
  ENABLE_AND_EXPECT(alphaToOne);
  ENABLE_AND_EXPECT(multiViewport);
  // TODO(benvanik): add other features.
  if (any_features_missing) {
    XELOGE(
        "One or more required device features are missing; aborting "
        "initialization");
    return false;
  }

  // Pick a queue.
  // Any queue we use must support both graphics and presentation.
  // TODO(benvanik): use multiple queues (DMA-only, compute-only, etc).
  if (device_info.queue_family_properties.empty()) {
    FatalVulkanError("No queue families available");
    return false;
  }
  uint32_t ideal_queue_family_index = UINT_MAX;
  uint32_t queue_count = 1;
  for (size_t i = 0; i < device_info.queue_family_properties.size(); ++i) {
    auto queue_flags = device_info.queue_family_properties[i].queueFlags;
    if (!device_info.queue_family_supports_present[i]) {
      // Can't present from this queue, so ignore it.
      continue;
    }
    if (queue_flags & VK_QUEUE_GRAPHICS_BIT) {
      // Can do graphics and present - good!
      ideal_queue_family_index = static_cast<uint32_t>(i);
      // Grab all the queues we can.
      queue_count = device_info.queue_family_properties[i].queueCount;
      break;
    }
  }
  if (ideal_queue_family_index == UINT_MAX) {
    FatalVulkanError(
        "No queue families available that can both do graphics and present");
    return false;
  }

  // Some tools *cough* renderdoc *cough* can't handle multiple queues.
  if (FLAGS_vulkan_primary_queue_only) {
    queue_count = 1;
  }

  VkDeviceQueueCreateInfo queue_info;
  queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  queue_info.pNext = nullptr;
  queue_info.flags = 0;
  queue_info.queueFamilyIndex = ideal_queue_family_index;
  queue_info.queueCount = queue_count;
  std::vector<float> queue_priorities(queue_count);
  // Prioritize the primary queue.
  queue_priorities[0] = 1.0f;
  queue_info.pQueuePriorities = queue_priorities.data();

  VkDeviceCreateInfo create_info;
  create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  create_info.pNext = nullptr;
  create_info.flags = 0;
  create_info.queueCreateInfoCount = 1;
  create_info.pQueueCreateInfos = &queue_info;
  create_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
  create_info.ppEnabledLayerNames = enabled_layers.data();
  create_info.enabledExtensionCount =
      static_cast<uint32_t>(enabled_extensions.size());
  create_info.ppEnabledExtensionNames = enabled_extensions.data();
  create_info.pEnabledFeatures = &enabled_features;

  auto err = vkCreateDevice(device_info.handle, &create_info, nullptr, &handle);
  switch (err) {
    case VK_SUCCESS:
      // Ok!
      break;
    case VK_ERROR_INITIALIZATION_FAILED:
      FatalVulkanError("Device initialization failed; generic");
      return false;
    case VK_ERROR_EXTENSION_NOT_PRESENT:
      FatalVulkanError(
          "Device initialization failed; requested extension not present");
      return false;
    case VK_ERROR_LAYER_NOT_PRESENT:
      FatalVulkanError(
          "Device initialization failed; requested layer not present");
      return false;
    default:
      FatalVulkanError(std::string("Device initialization failed; unknown: ") +
                       to_string(err));
      return false;
  }

  device_info_ = std::move(device_info);
  queue_family_index_ = ideal_queue_family_index;

  // Get the primary queue used for most submissions/etc.
  vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_);

  // Get all additional queues, if we got any.
  for (uint32_t i = 0; i < queue_count - 1; ++i) {
    VkQueue queue;
    vkGetDeviceQueue(handle, queue_family_index_, i, &queue);
    free_queues_.push_back(queue);
  }

  XELOGVK("Device initialized successfully!");
  return true;
}

VkQueue VulkanDevice::AcquireQueue() {
  std::lock_guard<std::mutex> lock(queue_mutex_);
  if (free_queues_.empty()) {
    return nullptr;
  }
  auto queue = free_queues_.back();
  free_queues_.pop_back();
  return queue;
}

void VulkanDevice::ReleaseQueue(VkQueue queue) {
  std::lock_guard<std::mutex> lock(queue_mutex_);
  free_queues_.push_back(queue);
}

bool VulkanDevice::is_renderdoc_attached() const {
  return instance_->is_renderdoc_attached();
}

void VulkanDevice::BeginRenderDocFrameCapture() {
  auto api = reinterpret_cast<RENDERDOC_API_1_0_1*>(instance_->renderdoc_api());
  if (!api) {
    return;
  }
  assert_true(api->IsFrameCapturing() == 0);

  api->StartFrameCapture(nullptr, nullptr);
}

void VulkanDevice::EndRenderDocFrameCapture() {
  auto api = reinterpret_cast<RENDERDOC_API_1_0_1*>(instance_->renderdoc_api());
  if (!api) {
    return;
  }
  assert_true(api->IsFrameCapturing() == 1);

  api->EndFrameCapture(nullptr, nullptr);
}

VkDeviceMemory VulkanDevice::AllocateMemory(
    const VkMemoryRequirements& requirements, VkFlags required_properties) {
  // Search memory types to find one matching our requirements and our
  // properties.
  uint32_t type_index = UINT_MAX;
  for (uint32_t i = 0; i < device_info_.memory_properties.memoryTypeCount;
       ++i) {
    const auto& memory_type = device_info_.memory_properties.memoryTypes[i];
    if (((requirements.memoryTypeBits >> i) & 1) == 1) {
      // Type is available for use; check for a match on properties.
      if ((memory_type.propertyFlags & required_properties) ==
          required_properties) {
        type_index = i;
        break;
      }
    }
  }
  if (type_index == UINT_MAX) {
    XELOGE("Unable to find a matching memory type");
    return nullptr;
  }

  // Allocate the memory.
  VkMemoryAllocateInfo memory_info;
  memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  memory_info.pNext = nullptr;
  memory_info.allocationSize = requirements.size;
  memory_info.memoryTypeIndex = type_index;
  VkDeviceMemory memory = nullptr;
  auto err = vkAllocateMemory(handle, &memory_info, nullptr, &memory);
  CheckResult(err, "vkAllocateMemory");
  return memory;
}

}  // namespace vulkan
}  // namespace ui
}  // namespace xe
<commit_msg>VK: Enable independentBlend feature<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2016 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/ui/vulkan/vulkan_device.h"

#include <gflags/gflags.h>

#include <cinttypes>
#include <mutex>
#include <string>

#include "third_party/renderdoc/renderdoc_app.h"

#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/profiling.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_immediate_drawer.h"
#include "xenia/ui/vulkan/vulkan_instance.h"
#include "xenia/ui/vulkan/vulkan_util.h"
#include "xenia/ui/window.h"

namespace xe {
namespace ui {
namespace vulkan {

VulkanDevice::VulkanDevice(VulkanInstance* instance) : instance_(instance) {
  if (FLAGS_vulkan_validation) {
    /*DeclareRequiredLayer("VK_LAYER_GOOGLE_unique_objects",
                         Version::Make(0, 0, 0), true);*/
    DeclareRequiredLayer("VK_LAYER_LUNARG_threading", Version::Make(0, 0, 0),
                         true);
    /*DeclareRequiredLayer("VK_LAYER_LUNARG_mem_tracker", Version::Make(0, 0,
       0),
                         true);*/
    DeclareRequiredLayer("VK_LAYER_LUNARG_object_tracker",
                         Version::Make(0, 0, 0), true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_draw_state", Version::Make(0, 0, 0),
                         true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_param_checker",
                         Version::Make(0, 0, 0), true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_swapchain", Version::Make(0, 0, 0),
                         true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_device_limits",
                         Version::Make(0, 0, 0), true);
    DeclareRequiredLayer("VK_LAYER_LUNARG_image", Version::Make(0, 0, 0), true);
  }
}

VulkanDevice::~VulkanDevice() {
  if (handle) {
    vkDestroyDevice(handle, nullptr);
    handle = nullptr;
  }
}

bool VulkanDevice::Initialize(DeviceInfo device_info) {
  // Gather list of enabled layer names.
  auto layers_result = CheckRequirements(required_layers_, device_info.layers);
  auto& enabled_layers = layers_result.second;

  // Gather list of enabled extension names.
  auto extensions_result =
      CheckRequirements(required_extensions_, device_info.extensions);
  auto& enabled_extensions = extensions_result.second;

  // We wait until both extensions and layers are checked before failing out so
  // that the user gets a complete list of what they have/don't.
  if (!extensions_result.first || !layers_result.first) {
    FatalVulkanError(
        "Layer and extension verification failed; aborting initialization");
    return false;
  }

  // Query supported features so we can make sure we have what we need.
  VkPhysicalDeviceFeatures supported_features;
  vkGetPhysicalDeviceFeatures(device_info.handle, &supported_features);
  VkPhysicalDeviceFeatures enabled_features = {0};
  bool any_features_missing = false;
#define ENABLE_AND_EXPECT(name)                                  \
  if (!supported_features.name) {                                \
    any_features_missing = true;                                 \
    FatalVulkanError("Vulkan device is missing feature " #name); \
  } else {                                                       \
    enabled_features.name = VK_TRUE;                             \
  }
  ENABLE_AND_EXPECT(geometryShader);
  ENABLE_AND_EXPECT(depthClamp);
  ENABLE_AND_EXPECT(alphaToOne);
  ENABLE_AND_EXPECT(multiViewport);
  ENABLE_AND_EXPECT(independentBlend);
  // TODO(benvanik): add other features.
  if (any_features_missing) {
    XELOGE(
        "One or more required device features are missing; aborting "
        "initialization");
    return false;
  }

  // Pick a queue.
  // Any queue we use must support both graphics and presentation.
  // TODO(benvanik): use multiple queues (DMA-only, compute-only, etc).
  if (device_info.queue_family_properties.empty()) {
    FatalVulkanError("No queue families available");
    return false;
  }
  uint32_t ideal_queue_family_index = UINT_MAX;
  uint32_t queue_count = 1;
  for (size_t i = 0; i < device_info.queue_family_properties.size(); ++i) {
    auto queue_flags = device_info.queue_family_properties[i].queueFlags;
    if (!device_info.queue_family_supports_present[i]) {
      // Can't present from this queue, so ignore it.
      continue;
    }
    if (queue_flags & VK_QUEUE_GRAPHICS_BIT) {
      // Can do graphics and present - good!
      ideal_queue_family_index = static_cast<uint32_t>(i);
      // Grab all the queues we can.
      queue_count = device_info.queue_family_properties[i].queueCount;
      break;
    }
  }
  if (ideal_queue_family_index == UINT_MAX) {
    FatalVulkanError(
        "No queue families available that can both do graphics and present");
    return false;
  }

  // Some tools *cough* renderdoc *cough* can't handle multiple queues.
  if (FLAGS_vulkan_primary_queue_only) {
    queue_count = 1;
  }

  VkDeviceQueueCreateInfo queue_info;
  queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  queue_info.pNext = nullptr;
  queue_info.flags = 0;
  queue_info.queueFamilyIndex = ideal_queue_family_index;
  queue_info.queueCount = queue_count;
  std::vector<float> queue_priorities(queue_count);
  // Prioritize the primary queue.
  queue_priorities[0] = 1.0f;
  queue_info.pQueuePriorities = queue_priorities.data();

  VkDeviceCreateInfo create_info;
  create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  create_info.pNext = nullptr;
  create_info.flags = 0;
  create_info.queueCreateInfoCount = 1;
  create_info.pQueueCreateInfos = &queue_info;
  create_info.enabledLayerCount = static_cast<uint32_t>(enabled_layers.size());
  create_info.ppEnabledLayerNames = enabled_layers.data();
  create_info.enabledExtensionCount =
      static_cast<uint32_t>(enabled_extensions.size());
  create_info.ppEnabledExtensionNames = enabled_extensions.data();
  create_info.pEnabledFeatures = &enabled_features;

  auto err = vkCreateDevice(device_info.handle, &create_info, nullptr, &handle);
  switch (err) {
    case VK_SUCCESS:
      // Ok!
      break;
    case VK_ERROR_INITIALIZATION_FAILED:
      FatalVulkanError("Device initialization failed; generic");
      return false;
    case VK_ERROR_EXTENSION_NOT_PRESENT:
      FatalVulkanError(
          "Device initialization failed; requested extension not present");
      return false;
    case VK_ERROR_LAYER_NOT_PRESENT:
      FatalVulkanError(
          "Device initialization failed; requested layer not present");
      return false;
    default:
      FatalVulkanError(std::string("Device initialization failed; unknown: ") +
                       to_string(err));
      return false;
  }

  device_info_ = std::move(device_info);
  queue_family_index_ = ideal_queue_family_index;

  // Get the primary queue used for most submissions/etc.
  vkGetDeviceQueue(handle, queue_family_index_, 0, &primary_queue_);

  // Get all additional queues, if we got any.
  for (uint32_t i = 0; i < queue_count - 1; ++i) {
    VkQueue queue;
    vkGetDeviceQueue(handle, queue_family_index_, i, &queue);
    free_queues_.push_back(queue);
  }

  XELOGVK("Device initialized successfully!");
  return true;
}

VkQueue VulkanDevice::AcquireQueue() {
  std::lock_guard<std::mutex> lock(queue_mutex_);
  if (free_queues_.empty()) {
    return nullptr;
  }
  auto queue = free_queues_.back();
  free_queues_.pop_back();
  return queue;
}

void VulkanDevice::ReleaseQueue(VkQueue queue) {
  std::lock_guard<std::mutex> lock(queue_mutex_);
  free_queues_.push_back(queue);
}

bool VulkanDevice::is_renderdoc_attached() const {
  return instance_->is_renderdoc_attached();
}

void VulkanDevice::BeginRenderDocFrameCapture() {
  auto api = reinterpret_cast<RENDERDOC_API_1_0_1*>(instance_->renderdoc_api());
  if (!api) {
    return;
  }
  assert_true(api->IsFrameCapturing() == 0);

  api->StartFrameCapture(nullptr, nullptr);
}

void VulkanDevice::EndRenderDocFrameCapture() {
  auto api = reinterpret_cast<RENDERDOC_API_1_0_1*>(instance_->renderdoc_api());
  if (!api) {
    return;
  }
  assert_true(api->IsFrameCapturing() == 1);

  api->EndFrameCapture(nullptr, nullptr);
}

VkDeviceMemory VulkanDevice::AllocateMemory(
    const VkMemoryRequirements& requirements, VkFlags required_properties) {
  // Search memory types to find one matching our requirements and our
  // properties.
  uint32_t type_index = UINT_MAX;
  for (uint32_t i = 0; i < device_info_.memory_properties.memoryTypeCount;
       ++i) {
    const auto& memory_type = device_info_.memory_properties.memoryTypes[i];
    if (((requirements.memoryTypeBits >> i) & 1) == 1) {
      // Type is available for use; check for a match on properties.
      if ((memory_type.propertyFlags & required_properties) ==
          required_properties) {
        type_index = i;
        break;
      }
    }
  }
  if (type_index == UINT_MAX) {
    XELOGE("Unable to find a matching memory type");
    return nullptr;
  }

  // Allocate the memory.
  VkMemoryAllocateInfo memory_info;
  memory_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  memory_info.pNext = nullptr;
  memory_info.allocationSize = requirements.size;
  memory_info.memoryTypeIndex = type_index;
  VkDeviceMemory memory = nullptr;
  auto err = vkAllocateMemory(handle, &memory_info, nullptr, &memory);
  CheckResult(err, "vkAllocateMemory");
  return memory;
}

}  // namespace vulkan
}  // namespace ui
}  // namespace xe
<|endoftext|>