<commit_before>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "../general/okina.hpp"

#include <bitset>
#include <cassert>

namespace mfem
{

// *****************************************************************************
// * Tests if ptr is a known address
// *****************************************************************************
static bool Known(const mm::ledger &maps, const void *ptr)
{
   const mm::memory_map::const_iterator found = maps.memories.find(ptr);
   const bool known = found != maps.memories.end();
   if (known) { return true; }
   return false;
}

// *****************************************************************************
bool mm::Known(const void *ptr)
{
   return mfem::Known(maps,ptr);
}

// *****************************************************************************
// * Looks if ptr is an alias of one memory
// *****************************************************************************
static const void* IsAlias(const mm::ledger &maps, const void *ptr)
{
   MFEM_ASSERT(!Known(maps, ptr), "Ptr is an already known address!");
   for (mm::memory_map::const_iterator mem = maps.memories.begin();
        mem != maps.memories.end(); mem++)
   {
      const void *b_ptr = mem->first;
      if (b_ptr > ptr) { continue; }
      const void *end = static_cast<const char*>(b_ptr) + mem->second.bytes;
      if (ptr < end) { return b_ptr; }
   }
   return nullptr;
}

// *****************************************************************************
static const void* InsertAlias(mm::ledger &maps,
                               const void *base,
                               const void *ptr)
{
   mm::memory &mem = maps.memories.at(base);
   const long offset = static_cast<const char*>(ptr) -
      static_cast<const char*> (base);
   const mm::alias *alias = new mm::alias{&mem, offset};
   maps.aliases.emplace(ptr, alias);
#ifdef MFEM_DEBUG_MM
   {
      mem.aliases.sort();
      for (const mm::alias *a : mem.aliases)
      {
         if (a->mem == &mem )
         {
            if (a->offset == offset){
               mfem_error("a->offset == offset");
            }
         }
      }
   }
#endif
   mem.aliases.push_back(alias);
   return ptr;
}

// *****************************************************************************
// * Tests if ptr is an alias address
// *****************************************************************************
static bool Alias(mm::ledger &maps, const void *ptr)
{
   const mm::alias_map::const_iterator found = maps.aliases.find(ptr);
   const bool alias = found != maps.aliases.end();
   if (alias) { return true; }
   const void *base = IsAlias(maps, ptr);
   if (!base) { return false; }
   InsertAlias(maps, base, ptr);
   return true;
}

// *****************************************************************************
bool mm::Alias(const void *ptr)
{
   return mfem::Alias(maps,ptr);
}

// *****************************************************************************
static void DumpMode(void)
{
   static bool env_ini = false;
   static bool env_dbg = false;
   if (!env_ini) { env_dbg = getenv("DBG"); env_ini = true; }
   if (!env_dbg) { return; }
   static std::bitset<8+1> mode;
   std::bitset<8+1> cfg;
   cfg.set(config::UsingMM()?8:0);
   cfg.set(config::DeviceHasBeenEnabled()?7:0);
   cfg.set(config::DeviceEnabled()?6:0);
   cfg.set(config::DeviceDisabled()?5:0);
   cfg.set(config::UsingHost()?4:0);
   cfg.set(config::UsingDevice()?3:0);
   cfg.set(config::UsingCuda()?2:0);
   cfg.set(config::UsingOcca()?1:0);
   cfg>>=1;
   if (cfg==mode) { return; }
   mode=cfg;
   printf("\033[1K\r[0x%lx] %sMM %sHasBeenEnabled %sEnabled %sDisabled "
          "%sHOST %sDEVICE %sCUDA %sOCCA\033[m", mode.to_ulong(),
          config::UsingMM()?"\033[32m":"\033[31m",
          config::DeviceHasBeenEnabled()?"\033[32m":"\033[31m",
          config::DeviceEnabled()?"\033[32m":"\033[31m",
          config::DeviceDisabled()?"\033[32m":"\033[31m",
          config::UsingHost()?"\033[32m":"\033[31m",
          config::UsingDevice()?"\033[32m":"\033[31m",
          config::UsingCuda()?"\033[32m":"\033[31m",
          config::UsingOcca()?"\033[32m":"\033[31m");
}

// *****************************************************************************
// * Adds an address
// *****************************************************************************
void* mm::Insert(void *ptr, const size_t bytes)
{
   if (!config::UsingMM()) { return ptr; }
   const bool known = Known(ptr);
   if (known)
   {
      mfem_error("Trying to add an already present address!");
   }
   DumpMode();
   // ex1p comes with (bytes==0)
   maps.memories.emplace(ptr, memory(ptr, bytes));
   return ptr;
}

// *****************************************************************************
// * Remove the address from the map, as well as all the address' aliases
// *****************************************************************************
void *mm::Erase(void *ptr)
{
   if (!config::UsingMM()) { return ptr; }
   const bool known = Known(ptr);
   if (!known) { mfem_error("Trying to erase an unknown pointer!"); }
   memory &mem = maps.memories.at(ptr);
   for (const alias* const alias : mem.aliases)
   {
      maps.aliases.erase(alias);
   }
   mem.aliases.clear();
   maps.memories.erase(ptr);
   return ptr;
}

// *****************************************************************************
static inline bool MmDeviceIniFilter(void)
{
   if (!config::UsingMM()) { return true; }
   if (config::DeviceDisabled()) { return true; }
   if (!config::DeviceHasBeenEnabled()) { return true; }
   if (config::UsingOcca()) { mfem_error("config::UsingOcca()"); }
   return false;
}

// *****************************************************************************
// * Turn a known address to the right host or device one
// * Alloc, Push or Pull it if required
// *****************************************************************************
static void *PtrKnown(mm::ledger &maps, void *ptr)
{
   mm::memory &base = maps.memories.at(ptr);
   const bool host = base.host;
   const bool device = !host;
   const size_t bytes = base.bytes;
   const bool gpu = config::UsingDevice();
   if (host && !gpu) { return ptr; }
   if (bytes==0) { mfem_error("PtrKnown bytes==0"); }
   if (!base.d_ptr) { cuMemAlloc(&base.d_ptr, bytes); }
   if (!base.d_ptr) { mfem_error("PtrKnown !base->d_ptr"); }
   if (device &&  gpu) { return base.d_ptr; }
   if (!ptr) { mfem_error("PtrKnown !ptr"); }
   if (device && !gpu) // Pull
   {
      mfem::cuMemcpyDtoH(ptr, base.d_ptr, bytes);
      base.host = true;
      return ptr;
   }
   // Push
   if (!(host && gpu)) { mfem_error("PtrKnown !(host && gpu)"); }
   cuMemcpyHtoD(base.d_ptr, ptr, bytes);
   base.host = false;
   return base.d_ptr;
}

// *****************************************************************************
// * Turn an alias to the right host or device one
// * Alloc, Push or Pull it if required
// *****************************************************************************
static void *PtrAlias(mm::ledger &maps, void *ptr)
{
   const bool gpu = config::UsingDevice();
   const mm::alias *alias = maps.aliases.at(ptr);
   assert(alias->offset >0);
   const mm::memory *base = alias->mem;
   assert(base);
   const bool host = base->host;
   const bool device = !base->host;
   const size_t bytes = base->bytes;
   if (host && !gpu) { return ptr; }
   if (bytes==0) { mfem_error("PtrAlias bytes==0"); }
   if (!base->d_ptr) { cuMemAlloc(&(alias->mem->d_ptr), bytes); }
   if (!base->d_ptr) { mfem_error("PtrAlias !base->d_ptr"); }
   void *a_ptr = static_cast<char*>(base->d_ptr) + alias->offset;
   if (device && gpu) { return a_ptr; }
   if (!base->h_ptr) { mfem_error("PtrAlias !base->h_ptr"); }
   if (device && !gpu) // Pull
   {
      mfem::cuMemcpyDtoH(base->h_ptr, base->d_ptr, bytes);
      alias->mem->host = true;
      return ptr;
   }
   // Push
   if (!(host && gpu)) { mfem_error("PtrAlias !(host && gpu)"); }
   mfem::cuMemcpyHtoD(base->d_ptr, base->h_ptr, bytes);
   alias->mem->host = false;
   return a_ptr;
}

// *****************************************************************************
// * Turn an address to the right host or device one
// * If the pointer is NULL the companion pointer
// * will be too.
// *****************************************************************************
void *mm::Ptr(void *ptr)
{
   if (MmDeviceIniFilter()) { return ptr; }
   if (Known(ptr)) { return PtrKnown(maps, ptr); }
   if (Alias(ptr)) { return PtrAlias(maps, ptr); }
   if (ptr==NULL)
   {
     return NULL;
   }
   else
   {
     mfem_error("Trying to use unknown pointer on the DEVICE!");
   }
   return ptr;
}

// *****************************************************************************
const void *mm::Ptr(const void *ptr)
{
   return static_cast<const void*>(Ptr(const_cast<void*>(ptr)));
}

// *****************************************************************************
static void PushKnown(mm::ledger &maps, const void *ptr, const size_t bytes)
{
   mm::memory &base = maps.memories.at(ptr);
   if (!base.d_ptr) { cuMemAlloc(&base.d_ptr, base.bytes); }
   mfem::cuMemcpyHtoD(base.d_ptr, ptr, bytes == 0 ? base.bytes : bytes);
}

// *****************************************************************************
static void PushAlias(const mm::ledger &maps, const void *ptr,
                      const size_t bytes)
{
   const mm::alias *alias = maps.aliases.at(ptr);
   void *dst = static_cast<char*>(alias->mem->d_ptr) + alias->offset;
   mfem::cuMemcpyHtoD(dst, ptr, bytes);
}

// *****************************************************************************
void mm::Push(const void *ptr, const size_t bytes)
{
   if (bytes==0) { mfem_error("Push bytes==0"); }
   if (MmDeviceIniFilter()) { return; }
   if (Known(ptr)) { return PushKnown(maps, ptr, bytes); }
   if (Alias(ptr)) { return PushAlias(maps, ptr, bytes); }
   if (config::UsingDevice()) { mfem_error("Unknown pointer to push to!"); }
}

// *****************************************************************************
static void PullKnown(const mm::ledger &maps, const void *ptr,
                      const size_t bytes)
{
   const mm::memory &base = maps.memories.at(ptr);
   const bool host = base.host;
   if (host) { return; }
   assert(base.h_ptr);
   assert(base.d_ptr);
   mfem::cuMemcpyDtoH(base.h_ptr, base.d_ptr, bytes == 0 ? base.bytes : bytes);
}

// *****************************************************************************
static void PullAlias(const mm::ledger &maps, const void *ptr,
                      const size_t bytes)
{
   const mm::alias *alias = maps.aliases.at(ptr);
   const bool host = alias->mem->host;
   if (host) { return; }
   if (!ptr) { mfem_error("PullAlias !ptr"); }
   if (!alias->mem->d_ptr) { mfem_error("PullAlias !alias->mem->d_ptr"); }
   mfem::cuMemcpyDtoH(const_cast<void*>(ptr),
                      static_cast<char*>(alias->mem->d_ptr) + alias->offset,
                      bytes);
}

// *****************************************************************************
void mm::Pull(const void *ptr, const size_t bytes)
{
   if (MmDeviceIniFilter()) { return; }
   if (Known(ptr)) { return PullKnown(maps, ptr, bytes); }
   if (Alias(ptr)) { return PullAlias(maps, ptr, bytes); }
   if (config::UsingDevice()) { mfem_error("Unknown pointer to pull from!"); }
}

// *****************************************************************************
// * Data will be pushed/pulled before the copy happens on the H or the D
// *****************************************************************************
void* mm::memcpy(void *dst, const void *src, const size_t bytes,
                 const bool async)
{
   void *d_dst = mm::ptr(dst);
   const void *d_src = mm::ptr(src);
   const bool host = config::UsingHost();
   if (bytes == 0) return dst;
   if (host) { return std::memcpy(dst, src, bytes); }
   if (!async)
   {
      return mfem::cuMemcpyDtoD(d_dst, const_cast<void*>(d_src), bytes);
   }
   return mfem::cuMemcpyDtoDAsync(d_dst, const_cast<void*>(d_src),
                                  bytes, config::Stream());
}

// *****************************************************************************
static OccaMemory occaMemory(mm::ledger &maps, const void *ptr)
{
   OccaDevice occaDevice = config::GetOccaDevice();
   if (!config::UsingMM())
   {
      OccaMemory o_ptr = occaWrapMemory(occaDevice, const_cast<void*>(ptr), 0);
      return o_ptr;
   }
   const bool known = mm::known(ptr);
   if (!known) { mfem_error("occaMemory: Unknown address!"); }
   mm::memory &base = maps.memories.at(ptr);
   const size_t bytes = base.bytes;
   const bool gpu = config::UsingDevice();
   if (!config::UsingOcca()) { mfem_error("Using OCCA without support!"); }
   if (!base.d_ptr)
   {
      base.host = false; // This address is no more on the host
      if (gpu)
      {
         cuMemAlloc(&base.d_ptr, bytes);
         void *stream = config::Stream();
         cuMemcpyHtoDAsync(base.d_ptr, base.h_ptr, bytes, stream);
      }
      else
      {
         base.o_ptr = occaDeviceMalloc(occaDevice, bytes);
         base.d_ptr = occaMemoryPtr(base.o_ptr);
         occaCopyFrom(base.o_ptr, base.h_ptr);
      }
   }
   if (gpu)
   {
      return occaWrapMemory(occaDevice, base.d_ptr, bytes);
   }
   return base.o_ptr;
}

// *****************************************************************************
void RegisterCheck(void *ptr)
{
  if(ptr != NULL){
    if(!mm::known(ptr))
      {
        assert(0 && "Pointer is not registered!");
        mfem_error("Trying use an unregistered pointer!");
      }
  }
}

// *****************************************************************************
OccaMemory mm::Memory(const void *ptr) { return occaMemory(maps, ptr); }

} // namespace mfem
<commit_msg>add guard in case mm is not being used<commit_after>// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.

#include "../general/okina.hpp"

#include <bitset>
#include <cassert>

namespace mfem
{

// *****************************************************************************
// * Tests if ptr is a known address
// *****************************************************************************
static bool Known(const mm::ledger &maps, const void *ptr)
{
   const mm::memory_map::const_iterator found = maps.memories.find(ptr);
   const bool known = found != maps.memories.end();
   if (known) { return true; }
   return false;
}

// *****************************************************************************
bool mm::Known(const void *ptr)
{
   return mfem::Known(maps,ptr);
}

// *****************************************************************************
// * Looks if ptr is an alias of one memory
// *****************************************************************************
static const void* IsAlias(const mm::ledger &maps, const void *ptr)
{
   MFEM_ASSERT(!Known(maps, ptr), "Ptr is an already known address!");
   for (mm::memory_map::const_iterator mem = maps.memories.begin();
        mem != maps.memories.end(); mem++)
   {
      const void *b_ptr = mem->first;
      if (b_ptr > ptr) { continue; }
      const void *end = static_cast<const char*>(b_ptr) + mem->second.bytes;
      if (ptr < end) { return b_ptr; }
   }
   return nullptr;
}

// *****************************************************************************
static const void* InsertAlias(mm::ledger &maps,
                               const void *base,
                               const void *ptr)
{
   mm::memory &mem = maps.memories.at(base);
   const long offset = static_cast<const char*>(ptr) -
      static_cast<const char*> (base);
   const mm::alias *alias = new mm::alias{&mem, offset};
   maps.aliases.emplace(ptr, alias);
#ifdef MFEM_DEBUG_MM
   {
      mem.aliases.sort();
      for (const mm::alias *a : mem.aliases)
      {
         if (a->mem == &mem )
         {
            if (a->offset == offset){
               mfem_error("a->offset == offset");
            }
         }
      }
   }
#endif
   mem.aliases.push_back(alias);
   return ptr;
}

// *****************************************************************************
// * Tests if ptr is an alias address
// *****************************************************************************
static bool Alias(mm::ledger &maps, const void *ptr)
{
   const mm::alias_map::const_iterator found = maps.aliases.find(ptr);
   const bool alias = found != maps.aliases.end();
   if (alias) { return true; }
   const void *base = IsAlias(maps, ptr);
   if (!base) { return false; }
   InsertAlias(maps, base, ptr);
   return true;
}

// *****************************************************************************
bool mm::Alias(const void *ptr)
{
   return mfem::Alias(maps,ptr);
}

// *****************************************************************************
static void DumpMode(void)
{
   static bool env_ini = false;
   static bool env_dbg = false;
   if (!env_ini) { env_dbg = getenv("DBG"); env_ini = true; }
   if (!env_dbg) { return; }
   static std::bitset<8+1> mode;
   std::bitset<8+1> cfg;
   cfg.set(config::UsingMM()?8:0);
   cfg.set(config::DeviceHasBeenEnabled()?7:0);
   cfg.set(config::DeviceEnabled()?6:0);
   cfg.set(config::DeviceDisabled()?5:0);
   cfg.set(config::UsingHost()?4:0);
   cfg.set(config::UsingDevice()?3:0);
   cfg.set(config::UsingCuda()?2:0);
   cfg.set(config::UsingOcca()?1:0);
   cfg>>=1;
   if (cfg==mode) { return; }
   mode=cfg;
   printf("\033[1K\r[0x%lx] %sMM %sHasBeenEnabled %sEnabled %sDisabled "
          "%sHOST %sDEVICE %sCUDA %sOCCA\033[m", mode.to_ulong(),
          config::UsingMM()?"\033[32m":"\033[31m",
          config::DeviceHasBeenEnabled()?"\033[32m":"\033[31m",
          config::DeviceEnabled()?"\033[32m":"\033[31m",
          config::DeviceDisabled()?"\033[32m":"\033[31m",
          config::UsingHost()?"\033[32m":"\033[31m",
          config::UsingDevice()?"\033[32m":"\033[31m",
          config::UsingCuda()?"\033[32m":"\033[31m",
          config::UsingOcca()?"\033[32m":"\033[31m");
}

// *****************************************************************************
// * Adds an address
// *****************************************************************************
void* mm::Insert(void *ptr, const size_t bytes)
{
   if (!config::UsingMM()) { return ptr; }
   const bool known = Known(ptr);
   if (known)
   {
      mfem_error("Trying to add an already present address!");
   }
   DumpMode();
   // ex1p comes with (bytes==0)
   maps.memories.emplace(ptr, memory(ptr, bytes));
   return ptr;
}

// *****************************************************************************
// * Remove the address from the map, as well as all the address' aliases
// *****************************************************************************
void *mm::Erase(void *ptr)
{
   if (!config::UsingMM()) { return ptr; }
   const bool known = Known(ptr);
   if (!known) { mfem_error("Trying to erase an unknown pointer!"); }
   memory &mem = maps.memories.at(ptr);
   for (const alias* const alias : mem.aliases)
   {
      maps.aliases.erase(alias);
   }
   mem.aliases.clear();
   maps.memories.erase(ptr);
   return ptr;
}

// *****************************************************************************
static inline bool MmDeviceIniFilter(void)
{
   if (!config::UsingMM()) { return true; }
   if (config::DeviceDisabled()) { return true; }
   if (!config::DeviceHasBeenEnabled()) { return true; }
   if (config::UsingOcca()) { mfem_error("config::UsingOcca()"); }
   return false;
}

// *****************************************************************************
// * Turn a known address to the right host or device one
// * Alloc, Push or Pull it if required
// *****************************************************************************
static void *PtrKnown(mm::ledger &maps, void *ptr)
{
   mm::memory &base = maps.memories.at(ptr);
   const bool host = base.host;
   const bool device = !host;
   const size_t bytes = base.bytes;
   const bool gpu = config::UsingDevice();
   if (host && !gpu) { return ptr; }
   if (bytes==0) { mfem_error("PtrKnown bytes==0"); }
   if (!base.d_ptr) { cuMemAlloc(&base.d_ptr, bytes); }
   if (!base.d_ptr) { mfem_error("PtrKnown !base->d_ptr"); }
   if (device &&  gpu) { return base.d_ptr; }
   if (!ptr) { mfem_error("PtrKnown !ptr"); }
   if (device && !gpu) // Pull
   {
      mfem::cuMemcpyDtoH(ptr, base.d_ptr, bytes);
      base.host = true;
      return ptr;
   }
   // Push
   if (!(host && gpu)) { mfem_error("PtrKnown !(host && gpu)"); }
   cuMemcpyHtoD(base.d_ptr, ptr, bytes);
   base.host = false;
   return base.d_ptr;
}

// *****************************************************************************
// * Turn an alias to the right host or device one
// * Alloc, Push or Pull it if required
// *****************************************************************************
static void *PtrAlias(mm::ledger &maps, void *ptr)
{
   const bool gpu = config::UsingDevice();
   const mm::alias *alias = maps.aliases.at(ptr);
   assert(alias->offset >0);
   const mm::memory *base = alias->mem;
   assert(base);
   const bool host = base->host;
   const bool device = !base->host;
   const size_t bytes = base->bytes;
   if (host && !gpu) { return ptr; }
   if (bytes==0) { mfem_error("PtrAlias bytes==0"); }
   if (!base->d_ptr) { cuMemAlloc(&(alias->mem->d_ptr), bytes); }
   if (!base->d_ptr) { mfem_error("PtrAlias !base->d_ptr"); }
   void *a_ptr = static_cast<char*>(base->d_ptr) + alias->offset;
   if (device && gpu) { return a_ptr; }
   if (!base->h_ptr) { mfem_error("PtrAlias !base->h_ptr"); }
   if (device && !gpu) // Pull
   {
      mfem::cuMemcpyDtoH(base->h_ptr, base->d_ptr, bytes);
      alias->mem->host = true;
      return ptr;
   }
   // Push
   if (!(host && gpu)) { mfem_error("PtrAlias !(host && gpu)"); }
   mfem::cuMemcpyHtoD(base->d_ptr, base->h_ptr, bytes);
   alias->mem->host = false;
   return a_ptr;
}

// *****************************************************************************
// * Turn an address to the right host or device one
// * If the pointer is NULL the companion pointer
// * will be too.
// *****************************************************************************
void *mm::Ptr(void *ptr)
{
   if (MmDeviceIniFilter()) { return ptr; }
   if (Known(ptr)) { return PtrKnown(maps, ptr); }
   if (Alias(ptr)) { return PtrAlias(maps, ptr); }
   if (ptr==NULL)
   {
     return NULL;
   }
   else
   {
     mfem_error("Trying to use unknown pointer on the DEVICE!");
   }
   return ptr;
}

// *****************************************************************************
const void *mm::Ptr(const void *ptr)
{
   return static_cast<const void*>(Ptr(const_cast<void*>(ptr)));
}

// *****************************************************************************
static void PushKnown(mm::ledger &maps, const void *ptr, const size_t bytes)
{
   mm::memory &base = maps.memories.at(ptr);
   if (!base.d_ptr) { cuMemAlloc(&base.d_ptr, base.bytes); }
   mfem::cuMemcpyHtoD(base.d_ptr, ptr, bytes == 0 ? base.bytes : bytes);
}

// *****************************************************************************
static void PushAlias(const mm::ledger &maps, const void *ptr,
                      const size_t bytes)
{
   const mm::alias *alias = maps.aliases.at(ptr);
   void *dst = static_cast<char*>(alias->mem->d_ptr) + alias->offset;
   mfem::cuMemcpyHtoD(dst, ptr, bytes);
}

// *****************************************************************************
void mm::Push(const void *ptr, const size_t bytes)
{
   if (bytes==0) { mfem_error("Push bytes==0"); }
   if (MmDeviceIniFilter()) { return; }
   if (Known(ptr)) { return PushKnown(maps, ptr, bytes); }
   if (Alias(ptr)) { return PushAlias(maps, ptr, bytes); }
   if (config::UsingDevice()) { mfem_error("Unknown pointer to push to!"); }
}

// *****************************************************************************
static void PullKnown(const mm::ledger &maps, const void *ptr,
                      const size_t bytes)
{
   const mm::memory &base = maps.memories.at(ptr);
   const bool host = base.host;
   if (host) { return; }
   assert(base.h_ptr);
   assert(base.d_ptr);
   mfem::cuMemcpyDtoH(base.h_ptr, base.d_ptr, bytes == 0 ? base.bytes : bytes);
}

// *****************************************************************************
static void PullAlias(const mm::ledger &maps, const void *ptr,
                      const size_t bytes)
{
   const mm::alias *alias = maps.aliases.at(ptr);
   const bool host = alias->mem->host;
   if (host) { return; }
   if (!ptr) { mfem_error("PullAlias !ptr"); }
   if (!alias->mem->d_ptr) { mfem_error("PullAlias !alias->mem->d_ptr"); }
   mfem::cuMemcpyDtoH(const_cast<void*>(ptr),
                      static_cast<char*>(alias->mem->d_ptr) + alias->offset,
                      bytes);
}

// *****************************************************************************
void mm::Pull(const void *ptr, const size_t bytes)
{
   if (MmDeviceIniFilter()) { return; }
   if (Known(ptr)) { return PullKnown(maps, ptr, bytes); }
   if (Alias(ptr)) { return PullAlias(maps, ptr, bytes); }
   if (config::UsingDevice()) { mfem_error("Unknown pointer to pull from!"); }
}

// *****************************************************************************
// * Data will be pushed/pulled before the copy happens on the H or the D
// *****************************************************************************
void* mm::memcpy(void *dst, const void *src, const size_t bytes,
                 const bool async)
{
   void *d_dst = mm::ptr(dst);
   const void *d_src = mm::ptr(src);
   const bool host = config::UsingHost();
   if (bytes == 0) return dst;
   if (host) { return std::memcpy(dst, src, bytes); }
   if (!async)
   {
      return mfem::cuMemcpyDtoD(d_dst, const_cast<void*>(d_src), bytes);
   }
   return mfem::cuMemcpyDtoDAsync(d_dst, const_cast<void*>(d_src),
                                  bytes, config::Stream());
}

// *****************************************************************************
static OccaMemory occaMemory(mm::ledger &maps, const void *ptr)
{
   OccaDevice occaDevice = config::GetOccaDevice();
   if (!config::UsingMM())
   {
      OccaMemory o_ptr = occaWrapMemory(occaDevice, const_cast<void*>(ptr), 0);
      return o_ptr;
   }
   const bool known = mm::known(ptr);
   if (!known) { mfem_error("occaMemory: Unknown address!"); }
   mm::memory &base = maps.memories.at(ptr);
   const size_t bytes = base.bytes;
   const bool gpu = config::UsingDevice();
   if (!config::UsingOcca()) { mfem_error("Using OCCA without support!"); }
   if (!base.d_ptr)
   {
      base.host = false; // This address is no more on the host
      if (gpu)
      {
         cuMemAlloc(&base.d_ptr, bytes);
         void *stream = config::Stream();
         cuMemcpyHtoDAsync(base.d_ptr, base.h_ptr, bytes, stream);
      }
      else
      {
         base.o_ptr = occaDeviceMalloc(occaDevice, bytes);
         base.d_ptr = occaMemoryPtr(base.o_ptr);
         occaCopyFrom(base.o_ptr, base.h_ptr);
      }
   }
   if (gpu)
   {
      return occaWrapMemory(occaDevice, base.d_ptr, bytes);
   }
   return base.o_ptr;
}

// *****************************************************************************
void RegisterCheck(void *ptr)
{
  if(ptr != NULL && config::UsingMM()){
    if(!mm::known(ptr))
      {
        assert(0 && "Pointer is not registered!");
        mfem_error("Trying use an unregistered pointer!");
      }
  }
}

// *****************************************************************************
OccaMemory mm::Memory(const void *ptr) { return occaMemory(maps, ptr); }

} // namespace mfem
<|endoftext|>


<commit_before>/*
 * smallargs.hpp
 *
 *  Created on: 2 Dec 2016
 *      Author: Fabian Meyer
 *
 * LICENSE
 * =======
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Fabian Meyer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef INCLUDE_SMALLARGS_HPP_
#define INCLUDE_SMALLARGS_HPP_

#include <cassert>
#include <string>
#include <stdexcept>
#include <sstream>
#include <vector>

extern "C" {
#include "smallargs.h"
}

namespace sarg
{
    typedef sarg_opt_type optType;
    typedef sarg_opt opt;
    typedef sarg_result result;
    typedef sarg_opt_cb optCallback;

    class Error : public std::exception
    {
    private:
        int errVal_;
        std::string errMsg_;

    public:
        Error(const int errVal) throw()
        : errVal_(errVal), errMsg_()
        {
            std::stringstream ss;
            ss << errVal_ << ": " << sarg_strerror(errVal);
            errMsg_ = ss.str();
        }

        ~Error() throw()
        {

        }

        const char* what() const throw()
        {
            return errMsg_.c_str();
        }

        int errval()
        {
            return errVal_;
        }
    };

    class Root
    {
    private:
        std::string name_;
        sarg_root root_;
        std::vector<opt> opts_;
        bool init_;

    public:
        Root(const std::string& name)
        :name_(name), init_(false)
        {}

        Root(const Root& root)
        :name_(root.name_), init_(false)
        {
            //TODO
            _SARG_UNUSED(root);
            assert(false);
        }

        ~Root()
        {
            unsigned int i;

            sarg_destroy(&root_);

            for(i = 0; i < opts_.size(); ++i)
                _sarg_opt_destroy(&opts_[i]);
        }

        Root &add(const std::string &shortName,
                const std::string &longName,
                const std::string &help,
                const optType type,
                const optCallback cb)
        {
            if(init_)
                throw std::logic_error("root was already initialized");

            int ret;
            opts_.resize(opts_.size() + 1);
            ret = _sarg_opt_init(&opts_.back(),
                    shortName.c_str(),
                    longName.c_str(),
                    help.c_str(),
                    type,
                    cb);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            return *this;
        }

        void init()
        {
            int ret;
            opt nullOpt = {NULL, NULL, NULL, INT, NULL};
            opts_.push_back(nullOpt);

            ret = sarg_init(&root_, &opts_[0], name_.c_str());
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            init_ = true;
        }

        const result& operator[](const std::string &key)
        {
            int ret;
            result *res;

            ret = sarg_get(&root_, key.c_str(), &res);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            return *res;
        }

        void parse(const char **argv, const int argc)
        {
            int ret;

            ret = sarg_parse(&root_, argv, argc);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);
        }

#ifndef SARG_NO_PRINT
        std::string getHelp()
        {
            std::string result;
            char *text;
            int ret;

            ret = sarg_help_text(&root_, &text);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            result = std::string(text);
            free(text);

            return result;
        }

        void printHelp()
        {
            int ret;

            ret = sarg_help_print(&root_);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);
        }
#endif

#ifndef SARG_NO_FILE
        void fromFile(const std::string &filename)
        {
            int ret;

            ret = sarg_parse_file(&root_, filename.c_str());
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);
        }
#endif
    };
}

#endif
<commit_msg>Fix NULL string issue<commit_after>/*
 * smallargs.hpp
 *
 *  Created on: 2 Dec 2016
 *      Author: Fabian Meyer
 *
 * LICENSE
 * =======
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Fabian Meyer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef INCLUDE_SMALLARGS_HPP_
#define INCLUDE_SMALLARGS_HPP_

#include <cassert>
#include <string>
#include <stdexcept>
#include <sstream>
#include <vector>

extern "C" {
#include "smallargs.h"
}

namespace sarg
{
    typedef sarg_opt_type optType;
    typedef sarg_opt opt;
    typedef sarg_result result;
    typedef sarg_opt_cb optCallback;

    class Error : public std::exception
    {
    private:
        int errVal_;
        std::string errMsg_;

    public:
        Error(const int errVal) throw()
        : errVal_(errVal), errMsg_()
        {
            std::stringstream ss;
            ss << errVal_ << ": " << sarg_strerror(errVal);
            errMsg_ = ss.str();
        }

        ~Error() throw()
        {

        }

        const char* what() const throw()
        {
            return errMsg_.c_str();
        }

        int errval()
        {
            return errVal_;
        }
    };

    class Root
    {
    private:
        std::string name_;
        sarg_root root_;
        std::vector<opt> opts_;
        bool init_;

    public:
        Root(const std::string& name)
        :name_(name), init_(false)
        {}

        Root(const Root& root)
        :name_(root.name_), init_(false)
        {
            //TODO
            _SARG_UNUSED(root);
            assert(false);
        }

        ~Root()
        {
            unsigned int i;

            sarg_destroy(&root_);

            for(i = 0; i < opts_.size(); ++i)
                _sarg_opt_destroy(&opts_[i]);
        }

        Root &add(const char *shortName,
                const char *longName,
                const char *help,
                const optType type,
                const optCallback cb)
        {
            if(init_)
                throw std::logic_error("root was already initialized");

            int ret;
            opts_.resize(opts_.size() + 1);
            ret = _sarg_opt_init(&opts_.back(),
                    shortName,
                    longName,
                    help,
                    type,
                    cb);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            return *this;
        }

        void init()
        {
            int ret;
            opt nullOpt = {NULL, NULL, NULL, INT, NULL};
            opts_.push_back(nullOpt);

            ret = sarg_init(&root_, &opts_[0], name_.c_str());
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            init_ = true;
        }

        const result& operator[](const std::string &key)
        {
            int ret;
            result *res;

            ret = sarg_get(&root_, key.c_str(), &res);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            return *res;
        }

        void parse(const char **argv, const int argc)
        {
            int ret;

            ret = sarg_parse(&root_, argv, argc);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);
        }

#ifndef SARG_NO_PRINT
        std::string getHelp()
        {
            std::string result;
            char *text;
            int ret;

            ret = sarg_help_text(&root_, &text);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);

            result = std::string(text);
            free(text);

            return result;
        }

        void printHelp()
        {
            int ret;

            ret = sarg_help_print(&root_);
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);
        }
#endif

#ifndef SARG_NO_FILE
        void fromFile(const std::string &filename)
        {
            int ret;

            ret = sarg_parse_file(&root_, filename.c_str());
            if(ret != SARG_ERR_SUCCESS)
                throw Error(ret);
        }
#endif
    };
}

#endif
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/* $Id$ */
/** @file    AliFMDPreprocessor.cxx
    @author  Hans Hjersing Dalsgaard <canute@nbi.dk>
    @date    Mon Mar 27 12:39:09 2006
    @brief   Shuttle "preprocessor" for the FMD
*/
//___________________________________________________________________
//
// The class processes data points from DCS (via Amanada), and DAQ DA
// files (via FXS) to make calibration data for the FMD.
//
// Data points:
//    *  Nothing yet.
//
// DAQ FXS file:
//    * pedestals - a (ASCII) Comma Separated Values files with the
//                  fields
//                       rcu	 DDL number
//                       board   FEC board number
//                       chip    ALTRO chip number on FEC
//                       channel ALTRO channel number
//                       strip   VA1 strip number
//                       sample  Sample number
//                       ped     Mean of ADC spectra
//                       noise   Spread of ADC spectra
//                       mu      Mean of Gaussian fit to ADC spectra
//                       sigma   Variance of Gaussian fit to ADC spectra
//                       chi2    Chi^2 per degrees of freedom of fit
//    * Gains     - a (ASCII) Comma Separated Values files with the
//                  fields
//                       rcu	 DDL number
//                       board   FEC board number
//                       chip    ALTRO chip number on FEC
//                       channel ALTRO channel number
//                       strip   VA1 strip number
//                       gain    Slope of gain
//                       error   Error on gain
//                       chi2    Chi^2 per degrees of freedom of fit
//
// See also
//
//   http://aliceinfo.cern.ch/Offline/Activities/Shuttle.html
//
// Latest changes by Christian Holm Christensen
//

// #include <iostream>

#include <fstream>
#include "AliFMDPreprocessor.h"
#include "AliFMDCalibPedestal.h"
#include "AliFMDCalibGain.h"
#include "AliFMDCalibStripRange.h"
#include "AliFMDCalibSampleRate.h"
#include "AliFMDParameters.h"
#include "AliCDBMetaData.h"
#include "AliCDBManager.h"
// #include "AliDCSValue.h"
#include "AliLog.h"
#include <TTimeStamp.h>
// #include <TFile.h>
#include <TObjString.h>
#include <TString.h>
#include <TNamed.h>

ClassImp(AliFMDPreprocessor)
#if 0 // Do not remove - here to make Emacs happy
;
#endif

//____________________________________________________
Bool_t AliFMDPreprocessor::GetAndCheckFileSources(TList*&     list,
						  Int_t       system,
						  const char* id)
{
  // Convinience function
  // Parameters:
  //   list     On return, list of files.
  //   system   Alice system (DAQ, DCS, ...)
  //   id       File id
  // Return:
  //   kTRUE on success.
  list = GetFileSources(system, id);
  if (!list) {
    TString sys;
    switch (system) {
    case kDAQ: sys = "DAQ";     break;
    case kDCS: sys = "DCS";     break;
    default:   sys = "unknown"; break;
    }
    Log(Form("Failed to get file sources for %s/%s", sys.Data(), system));
    return kFALSE;
  }
  return kTRUE;
}

//____________________________________________________
AliCDBEntry*
AliFMDPreprocessor::GetFromCDB(const char* second, const char* third)
{
  return GetFromOCDB(second, third);
}

//____________________________________________________
UInt_t AliFMDPreprocessor::Process(TMap* /* dcsAliasMap */)
{
  // Main member function.
  // Parameters:
  //    dcsAliassMap   Map of DCS data point aliases.
  // Return
  //    0 on success, >0 otherwise
  Bool_t resultPed   = kTRUE;
  Bool_t resultGain  = kTRUE;
  Bool_t resultRange = kTRUE;
  Bool_t resultRate  = kTRUE;
  Bool_t resultZero  = kTRUE;

  // Do we need this ?
  // if(!dcsAliasMap) return 1;
  //
  // Invoking the cdb manager and the FMD parameters class
  // AliCDBManager* cdb   = AliCDBManager::Instance();
  // cdb->SetDefaultStorage("local://$ALICE_ROOT");
  // cdb->SetRun(0);
  AliFMDParameters* pars = AliFMDParameters::Instance();
  pars->Init(this, false, AliFMDParameters::kAltroMap);

  // This is if the SOR contains Fee parameters, and we run a DA to
  // extract these parameters.   The same code could work if we get
  // the information from DCS via the FXS
  TList* files = 0;
  AliFMDCalibSampleRate*      calibRate  = 0;
  AliFMDCalibStripRange*      calibRange = 0;
  AliFMDCalibZeroSuppression* calibZero  = 0;
  // Disabled for now.
#if 0
  if (GetAndCheckFileSources(files, kDAQ,"info"))
    GetInfoCalibration(files, calibRate, calibRange, calibZero);
  resultRate  = (!calibRate  ? kFALSE : kTRUE);
  resultRange = (!calibRange ? kFALSE : kTRUE);
  resultZero  = (!calibZero  ? kFALSE : kTRUE);
#endif

  // Gt the run type
  TString runType(GetRunType());

  //Creating calibration objects
  AliFMDCalibPedestal* calibPed  = 0;
  AliFMDCalibGain*     calibGain = 0;
  if (runType.Contains("PEDESTAL", TString::kIgnoreCase)) {
    if (GetAndCheckFileSources(files, kDAQ, "pedestals")) {
      if(files->GetSize())
	calibPed = GetPedestalCalibration(files);
    }
    resultPed = (calibPed ? kTRUE : kFALSE);
  }
  if (runType.Contains("PULSER", TString::kIgnoreCase)) {
    if (GetAndCheckFileSources(files, kDAQ, "gains")) {
      if(files->GetSize())
	calibGain = GetGainCalibration(files);
    }
    resultGain = (calibGain ? kTRUE : kFALSE);
  }

  //Storing Calibration objects
  AliCDBMetaData metaData;
  metaData.SetBeamPeriod(0);
  metaData.SetResponsible("Hans H. Dalsgaard");
  metaData.SetComment("Preprocessor stores pedestals and gains for the FMD.");

  if(calibPed)  {
    resultPed  = Store("Calib","Pedestal", calibPed, &metaData, 0, kTRUE);
    delete calibPed;
  }
  if(calibGain) {
    resultGain = Store("Calib","PulseGain", calibGain, &metaData, 0, kTRUE);
    delete calibGain;
  }
  if(calibRange) {
    resultRange = Store("Calib","StripRange", calibRange, &metaData, 0, kTRUE);
    delete calibRange;
  }
  if(calibRate) {
    resultRate = Store("Calib","SampleRate", calibRate, &metaData, 0, kTRUE);
    delete calibRate;
  }
  if(calibZero) {
    resultZero = Store("Calib","ZeroSuppression", calibZero,&metaData,0,kTRUE);
    delete calibZero;
  }

#if 0
  // Disabled until we implement GetInfoCalibration properly
  Bool_t success = (resultPed && resultGain  && resultRange &&
		    resultRate  && resultZero);
#endif
  Bool_t success = resultPed && resultGain;
  Log(Form("FMD preprocessor was %s", (success ? "successful" : "failed")));
  return (success ? 0 : 1);
}

//____________________________________________________________________
Bool_t
AliFMDPreprocessor::GetInfoCalibration(TList* files,
				       AliFMDCalibSampleRate*&      s,
				       AliFMDCalibStripRange*&      r,
				       AliFMDCalibZeroSuppression*& z)
{
  // Get info calibrations.
  // Parameters:
  //     files List of files.
  //     s     On return, newly allocated object
  //     r     On return, newly allocated object
  //     z     On return, newly allocated object
  // Return:
  //     kTRUE on success
  if (!files) return kTRUE; // Should really be false
  if (files->GetEntries() <= 0) return kTRUE;

  s = new AliFMDCalibSampleRate();
  r = new AliFMDCalibStripRange();
  z = new AliFMDCalibZeroSuppression();

  // AliFMDParameters*    pars     = AliFMDParameters::Instance();
  TIter                iter(files);
  TObjString*          fileSource;

  while((fileSource = dynamic_cast<TObjString*>(iter.Next()))) {
    const Char_t* filename = GetFile(kDAQ, "info", fileSource->GetName());
    std::ifstream in(filename);
    if(!in) {
      Log(Form("File %s not found!", filename));
      continue;
    }
  }
  return kTRUE;
}

//____________________________________________________________________
AliFMDCalibPedestal*
AliFMDPreprocessor::GetPedestalCalibration(TList* pedFiles)
{
  // Read DAQ DA produced CSV files of pedestals, and return a
  // calibration object.
  // Parameters:
  //   pedFiles     List of pedestal files
  // Return
  //   A pointer to a newly allocated AliFMDCalibPedestal object, or
  //   null in case of errors.
  if(!pedFiles) return 0;

  AliFMDCalibPedestal* calibPed = new AliFMDCalibPedestal();
  AliFMDParameters*    pars     = AliFMDParameters::Instance();
  TIter                iter(pedFiles);
  TObjString*          fileSource;

  while((fileSource = dynamic_cast<TObjString*>(iter.Next()))) {
    const Char_t* filename = GetFile(kDAQ, "pedestals", fileSource->GetName());
    std::ifstream in(filename);
    if(!in) {
      Log(Form("File %s not found!", filename));
      continue;
    }

    // Get header (how long is it ?)
    TString header;
    header.ReadLine(in);
    header.ToLower();
    if(!header.Contains("pedestal")) {
      Log("File header is not from pedestal!");
      continue;
    }
    Log("File contains data from pedestals");

    // Read columns line
    int lineno = 2;
    header.ReadLine(in);

    // Loop until EOF
    while(in.peek()!=EOF) {
      if(in.bad()) {
	Log(Form("Bad read at line %d in %s", lineno, filename));
	break;
      }
      UInt_t ddl=2, board, chip, channel, strip, sample, tb;
      Float_t ped, noise, mu, sigma, chi2ndf;
      Char_t c[11];

      in >> ddl      >> c[0]
	 >> board    >> c[1]
	 >> chip     >> c[2]
	 >> channel  >> c[3]
	 >> strip    >> c[4]
	 >> sample   >> c[5]
	 >> tb       >> c[6]
	 >> ped      >> c[7]
	 >> noise    >> c[8]
	 >> mu       >> c[9]
	 >> sigma    >> c[10]
	 >> chi2ndf;
      lineno++;

      // Ignore trailing garbage
      if (strip > 127) continue;

      //Setting DDL to comply with the FMD in DAQ
      UInt_t FmdDDLBase = 3072;
      ddl = ddl - FmdDDLBase;
      //Setting the pedestals via the hardware address
      UShort_t det, sec, str;
      Char_t ring;

      pars->Hardware2Detector(ddl,board,chip,channel,det,ring,sec,str);
      strip += str;

      calibPed->Set(det,ring,sec,strip,ped,noise);

    }
  }
  return calibPed;
}

//____________________________________________________________________
AliFMDCalibGain*
AliFMDPreprocessor::GetGainCalibration(TList* gainFiles)
{
  // Read DAQ DA produced CSV files of pedestals, and return a
  // calibration object.
  // Parameters:
  //   pedFiles     List of pedestal files
  // Return
  //   A pointer to a newly allocated AliFMDCalibPedestal object, or
  //   null in case of errors.
  if(!gainFiles) return 0;

  AliFMDCalibGain*  calibGain  = new AliFMDCalibGain();
  AliFMDParameters* pars       = AliFMDParameters::Instance();
  TIter             iter(gainFiles);
  TObjString*       fileSource;
  while((fileSource = dynamic_cast<TObjString *>(iter.Next()))) {
    const Char_t* filename = GetFile(kDAQ, "gains", fileSource->GetName());
    std::ifstream in(filename);
    if(!in) {
      Log(Form("File %s not found!", filename));
      continue;
    }

    //Get header (how long is it ?)
    TString header;
    header.ReadLine(in);
    header.ToLower();
    if(!header.Contains("gain")) {
      Log("File header is not from gain!");
      continue;
    }
    Log("File contains data from pulse gain");

    // Read column headers
    header.ReadLine(in);

    int lineno  = 2;
    // Read until EOF
    while(in.peek()!=EOF) {
      if(in.bad()) {
	Log(Form("Bad read at line %d in %s", lineno, filename));
	break;
      }
      UInt_t ddl=2, board, chip, channel, strip;
      Float_t gain,error,  chi2ndf;
      Char_t c[7];

      in >> ddl      >> c[0]
	 >> board    >> c[1]
	 >> chip     >> c[2]
	 >> channel  >> c[3]
	 >> strip    >> c[4]
	 >> gain     >> c[5]
	 >> error    >> c[6]
	 >> chi2ndf;
      lineno++;
      // Ignore trailing garbage
      if(strip > 127) continue;

      //Setting DDL to comply with the FMD in DAQ
      UInt_t FmdDDLBase = 3072;
      ddl = ddl - FmdDDLBase;
      //Setting the pedestals via the hardware address
      UShort_t det, sec, str;
      Char_t ring;
      pars->Hardware2Detector(ddl,board,chip,channel,det,ring,sec,str);

      strip += str;
      calibGain->Set(det,ring,sec,strip,gain);
    }
  }
  return calibGain;
}

//____________________________________________________________________
//
// EOF
//
<commit_msg>Changed the constructor to include calls to AddRunType(...). This change was required by the shuttle team at CERN.<commit_after>/**************************************************************************
 * Copyright(c) 2004, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/* $Id$ */
/** @file    AliFMDPreprocessor.cxx
    @author  Hans Hjersing Dalsgaard <canute@nbi.dk>
    @date    Mon Mar 27 12:39:09 2006
    @brief   Shuttle "preprocessor" for the FMD
*/
//___________________________________________________________________
//
// The class processes data points from DCS (via Amanada), and DAQ DA
// files (via FXS) to make calibration data for the FMD.
//
// Data points:
//    *  Nothing yet.
//
// DAQ FXS file:
//    * pedestals - a (ASCII) Comma Separated Values files with the
//                  fields
//                       rcu	 DDL number
//                       board   FEC board number
//                       chip    ALTRO chip number on FEC
//                       channel ALTRO channel number
//                       strip   VA1 strip number
//                       sample  Sample number
//                       ped     Mean of ADC spectra
//                       noise   Spread of ADC spectra
//                       mu      Mean of Gaussian fit to ADC spectra
//                       sigma   Variance of Gaussian fit to ADC spectra
//                       chi2    Chi^2 per degrees of freedom of fit
//    * Gains     - a (ASCII) Comma Separated Values files with the
//                  fields
//                       rcu	 DDL number
//                       board   FEC board number
//                       chip    ALTRO chip number on FEC
//                       channel ALTRO channel number
//                       strip   VA1 strip number
//                       gain    Slope of gain
//                       error   Error on gain
//                       chi2    Chi^2 per degrees of freedom of fit
//
// See also
//
//   http://aliceinfo.cern.ch/Offline/Activities/Shuttle.html
//
// Latest changes by Christian Holm Christensen
//

// #include <iostream>

#include <fstream>
#include "AliFMDPreprocessor.h"
#include "AliFMDCalibPedestal.h"
#include "AliFMDCalibGain.h"
#include "AliFMDCalibStripRange.h"
#include "AliFMDCalibSampleRate.h"
#include "AliFMDParameters.h"
#include "AliCDBMetaData.h"
#include "AliCDBManager.h"
// #include "AliDCSValue.h"
#include "AliLog.h"
#include <TTimeStamp.h>
// #include <TFile.h>
#include <TObjString.h>
#include <TString.h>
#include <TNamed.h>

ClassImp(AliFMDPreprocessor)
#if 0 // Do not remove - here to make Emacs happy
;
#endif

//____________________________________________________
AliFMDPreprocessor::AliFMDPreprocessor(AliShuttleInterface* shuttle)
  : AliPreprocessor("FMD", shuttle)
{
  AddRunType("PHYSICS");
  AddRunType("STANDALONE");
  AddRunType("PEDESTAL");
  AddRunType("GAIN");
}

//____________________________________________________
Bool_t AliFMDPreprocessor::GetAndCheckFileSources(TList*&     list,
						  Int_t       system,
						  const char* id)
{
  // Convinience function
  // Parameters:
  //   list     On return, list of files.
  //   system   Alice system (DAQ, DCS, ...)
  //   id       File id
  // Return:
  //   kTRUE on success.
  list = GetFileSources(system, id);
  if (!list) {
    TString sys;
    switch (system) {
    case kDAQ: sys = "DAQ";     break;
    case kDCS: sys = "DCS";     break;
    default:   sys = "unknown"; break;
    }
    Log(Form("Failed to get file sources for %s/%s", sys.Data(), system));
    return kFALSE;
  }
  return kTRUE;
}

//____________________________________________________
AliCDBEntry*
AliFMDPreprocessor::GetFromCDB(const char* second, const char* third)
{
  return GetFromOCDB(second, third);
}

//____________________________________________________
UInt_t AliFMDPreprocessor::Process(TMap* /* dcsAliasMap */)
{
  // Main member function.
  // Parameters:
  //    dcsAliassMap   Map of DCS data point aliases.
  // Return
  //    0 on success, >0 otherwise
  Bool_t resultPed   = kTRUE;
  Bool_t resultGain  = kTRUE;
  Bool_t resultRange = kTRUE;
  Bool_t resultRate  = kTRUE;
  Bool_t resultZero  = kTRUE;

  // Do we need this ?
  // if(!dcsAliasMap) return 1;
  //
  // Invoking the cdb manager and the FMD parameters class
  // AliCDBManager* cdb   = AliCDBManager::Instance();
  // cdb->SetDefaultStorage("local://$ALICE_ROOT");
  // cdb->SetRun(0);
  AliFMDParameters* pars = AliFMDParameters::Instance();
  pars->Init(this, false, AliFMDParameters::kAltroMap);

  // This is if the SOR contains Fee parameters, and we run a DA to
  // extract these parameters.   The same code could work if we get
  // the information from DCS via the FXS
  TList* files = 0;
  AliFMDCalibSampleRate*      calibRate  = 0;
  AliFMDCalibStripRange*      calibRange = 0;
  AliFMDCalibZeroSuppression* calibZero  = 0;
  // Disabled for now.
#if 0
  if (GetAndCheckFileSources(files, kDAQ,"info"))
    GetInfoCalibration(files, calibRate, calibRange, calibZero);
  resultRate  = (!calibRate  ? kFALSE : kTRUE);
  resultRange = (!calibRange ? kFALSE : kTRUE);
  resultZero  = (!calibZero  ? kFALSE : kTRUE);
#endif

  // Gt the run type
  TString runType(GetRunType());

  //Creating calibration objects
  AliFMDCalibPedestal* calibPed  = 0;
  AliFMDCalibGain*     calibGain = 0;
  if (runType.Contains("PEDESTAL", TString::kIgnoreCase)) {
    if (GetAndCheckFileSources(files, kDAQ, "pedestals")) {
      if(files->GetSize())
	calibPed = GetPedestalCalibration(files);
    }
    resultPed = (calibPed ? kTRUE : kFALSE);
  }
  if (runType.Contains("GAIN", TString::kIgnoreCase)) {
    if (GetAndCheckFileSources(files, kDAQ, "gains")) {
      if(files->GetSize())
	calibGain = GetGainCalibration(files);
    }
    resultGain = (calibGain ? kTRUE : kFALSE);
  }

  //Storing Calibration objects
  AliCDBMetaData metaData;
  metaData.SetBeamPeriod(0);
  metaData.SetResponsible("Hans H. Dalsgaard");
  metaData.SetComment("Preprocessor stores pedestals and gains for the FMD.");

  if(calibPed)  {
    resultPed  = Store("Calib","Pedestal", calibPed, &metaData, 0, kTRUE);
    delete calibPed;
  }
  if(calibGain) {
    resultGain = Store("Calib","PulseGain", calibGain, &metaData, 0, kTRUE);
    delete calibGain;
  }
  if(calibRange) {
    resultRange = Store("Calib","StripRange", calibRange, &metaData, 0, kTRUE);
    delete calibRange;
  }
  if(calibRate) {
    resultRate = Store("Calib","SampleRate", calibRate, &metaData, 0, kTRUE);
    delete calibRate;
  }
  if(calibZero) {
    resultZero = Store("Calib","ZeroSuppression", calibZero,&metaData,0,kTRUE);
    delete calibZero;
  }

#if 0
  // Disabled until we implement GetInfoCalibration properly
  Bool_t success = (resultPed && resultGain  && resultRange &&
		    resultRate  && resultZero);
#endif
  Bool_t success = resultPed && resultGain;
  Log(Form("FMD preprocessor was %s", (success ? "successful" : "failed")));
  return (success ? 0 : 1);
}

//____________________________________________________________________
Bool_t
AliFMDPreprocessor::GetInfoCalibration(TList* files,
				       AliFMDCalibSampleRate*&      s,
				       AliFMDCalibStripRange*&      r,
				       AliFMDCalibZeroSuppression*& z)
{
  // Get info calibrations.
  // Parameters:
  //     files List of files.
  //     s     On return, newly allocated object
  //     r     On return, newly allocated object
  //     z     On return, newly allocated object
  // Return:
  //     kTRUE on success
  if (!files) return kTRUE; // Should really be false
  if (files->GetEntries() <= 0) return kTRUE;

  s = new AliFMDCalibSampleRate();
  r = new AliFMDCalibStripRange();
  z = new AliFMDCalibZeroSuppression();

  // AliFMDParameters*    pars     = AliFMDParameters::Instance();
  TIter                iter(files);
  TObjString*          fileSource;

  while((fileSource = dynamic_cast<TObjString*>(iter.Next()))) {
    const Char_t* filename = GetFile(kDAQ, "info", fileSource->GetName());
    std::ifstream in(filename);
    if(!in) {
      Log(Form("File %s not found!", filename));
      continue;
    }
  }
  return kTRUE;
}

//____________________________________________________________________
AliFMDCalibPedestal*
AliFMDPreprocessor::GetPedestalCalibration(TList* pedFiles)
{
  // Read DAQ DA produced CSV files of pedestals, and return a
  // calibration object.
  // Parameters:
  //   pedFiles     List of pedestal files
  // Return
  //   A pointer to a newly allocated AliFMDCalibPedestal object, or
  //   null in case of errors.
  if(!pedFiles) return 0;

  AliFMDCalibPedestal* calibPed = new AliFMDCalibPedestal();
  AliFMDParameters*    pars     = AliFMDParameters::Instance();
  TIter                iter(pedFiles);
  TObjString*          fileSource;

  while((fileSource = dynamic_cast<TObjString*>(iter.Next()))) {
    const Char_t* filename = GetFile(kDAQ, "pedestals", fileSource->GetName());
    std::ifstream in(filename);
    if(!in) {
      Log(Form("File %s not found!", filename));
      continue;
    }

    // Get header (how long is it ?)
    TString header;
    header.ReadLine(in);
    header.ToLower();
    if(!header.Contains("pedestal")) {
      Log("File header is not from pedestal!");
      continue;
    }
    Log("File contains data from pedestals");

    // Read columns line
    int lineno = 2;
    header.ReadLine(in);

    // Loop until EOF
    while(in.peek()!=EOF) {
      if(in.bad()) {
	Log(Form("Bad read at line %d in %s", lineno, filename));
	break;
      }
      UInt_t ddl=2, board, chip, channel, strip, sample, tb;
      Float_t ped, noise, mu, sigma, chi2ndf;
      Char_t c[11];

      in >> ddl      >> c[0]
	 >> board    >> c[1]
	 >> chip     >> c[2]
	 >> channel  >> c[3]
	 >> strip    >> c[4]
	 >> sample   >> c[5]
	 >> tb       >> c[6]
	 >> ped      >> c[7]
	 >> noise    >> c[8]
	 >> mu       >> c[9]
	 >> sigma    >> c[10]
	 >> chi2ndf;
      lineno++;

      // Ignore trailing garbage
      if (strip > 127) continue;

      //Setting DDL to comply with the FMD in DAQ
      UInt_t FmdDDLBase = 3072;
      ddl = ddl - FmdDDLBase;
      //Setting the pedestals via the hardware address
      UShort_t det, sec, str;
      Char_t ring;

      pars->Hardware2Detector(ddl,board,chip,channel,det,ring,sec,str);
      strip += str;

      calibPed->Set(det,ring,sec,strip,ped,noise);

    }
  }
  return calibPed;
}

//____________________________________________________________________
AliFMDCalibGain*
AliFMDPreprocessor::GetGainCalibration(TList* gainFiles)
{
  // Read DAQ DA produced CSV files of pedestals, and return a
  // calibration object.
  // Parameters:
  //   pedFiles     List of pedestal files
  // Return
  //   A pointer to a newly allocated AliFMDCalibPedestal object, or
  //   null in case of errors.
  if(!gainFiles) return 0;

  AliFMDCalibGain*  calibGain  = new AliFMDCalibGain();
  AliFMDParameters* pars       = AliFMDParameters::Instance();
  TIter             iter(gainFiles);
  TObjString*       fileSource;
  while((fileSource = dynamic_cast<TObjString *>(iter.Next()))) {
    const Char_t* filename = GetFile(kDAQ, "gains", fileSource->GetName());
    std::ifstream in(filename);
    if(!in) {
      Log(Form("File %s not found!", filename));
      continue;
    }

    //Get header (how long is it ?)
    TString header;
    header.ReadLine(in);
    header.ToLower();
    if(!header.Contains("gain")) {
      Log("File header is not from gain!");
      continue;
    }
    Log("File contains data from pulse gain");

    // Read column headers
    header.ReadLine(in);

    int lineno  = 2;
    // Read until EOF
    while(in.peek()!=EOF) {
      if(in.bad()) {
	Log(Form("Bad read at line %d in %s", lineno, filename));
	break;
      }
      UInt_t ddl=2, board, chip, channel, strip;
      Float_t gain,error,  chi2ndf;
      Char_t c[7];

      in >> ddl      >> c[0]
	 >> board    >> c[1]
	 >> chip     >> c[2]
	 >> channel  >> c[3]
	 >> strip    >> c[4]
	 >> gain     >> c[5]
	 >> error    >> c[6]
	 >> chi2ndf;
      lineno++;
      // Ignore trailing garbage
      if(strip > 127) continue;

      //Setting DDL to comply with the FMD in DAQ
      UInt_t FmdDDLBase = 3072;
      ddl = ddl - FmdDDLBase;
      //Setting the pedestals via the hardware address
      UShort_t det, sec, str;
      Char_t ring;
      pars->Hardware2Detector(ddl,board,chip,channel,det,ring,sec,str);

      strip += str;
      calibGain->Set(det,ring,sec,strip,gain);
    }
  }
  return calibGain;
}

//____________________________________________________________________
//
// EOF
//
<|endoftext|>


<commit_before>/* * This file is part of meego-keyboard *
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * Contact: Nokia Corporation (directui@nokia.com)
 *
 * 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 "bm_painting.h"
#include "paintrunner.h"
#include "loggingwindow.h"
#include "mimkeyarea.h"
#include "keyboarddata.h"
#include "utils.h"

// this test could not be compiled for Windows
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <MApplication>
#include <MTheme>
#include <MSceneWindow>
#include <MScene>
#include <MSceneManager>

#include <QDir>

namespace {
    int gArgc = 2;
    char *gArgv[2] = { (char *) "bm_painting",
                       (char *) "-software" };
    const char *const MImUserDirectory = ".meego-im";
}

void Bm_Painting::initTestCase()
{
    disableQtPlugins();

    QDir dir;
    dir.mkpath(QString("%1/%2").arg(QDir::homePath()).arg(MImUserDirectory));
}

void Bm_Painting::cleanupTestCase()
{
}

void Bm_Painting::init()
{
    keyboard = 0;
    subject = 0;
}

void Bm_Painting::cleanup()
{
    delete subject;
    subject = 0;
    delete keyboard;
    keyboard = 0;

    delete sceneWindow;
    sceneWindow = 0;
    delete window;
    window = 0;
    delete widget;
    widget = 0;
    delete app;
    app = 0;
}

void Bm_Painting::benchmarkPaint_data()
{
    QDir dir("/usr/share/meegotouch/virtual-keyboard/layouts/");
    QStringList filters;
    QFileInfoList files;
    QFileInfo info;
    QStringList resultFilenames;
    QString fileNameTemplate(QString("%1/%2/%3-%4").arg(QDir::homePath())
                                                   .arg(MImUserDirectory)
                                                   .arg(QCoreApplication::applicationPid()));

    QTest::addColumn<QString>("filename");
    QTest::addColumn<bool>("hardwareRendering");
    QTest::addColumn<bool>("compositing");
    QTest::addColumn<QString>("resultFilename");

    resultFilenames << fileNameTemplate.arg("sw_opaque.csv")
                    << fileNameTemplate.arg("hw_opaque.csv")
                    << fileNameTemplate.arg("sw_composite.csv")
                    << fileNameTemplate.arg("hw_composite.csv");

    filters << "en_gb.xml";
    files = dir.entryInfoList(filters);

    int x = 0;
    for (int composite = 0; composite <= 1; ++composite) {
        for (int hw = 0; hw <= 1; ++hw) {
            for (int n = files.count() - 1; n >= 0; --n) {
                info = files.at(n);
                QString caseName = QString("file=%1 composite=%2 hw=%3 results=%4").arg(info.fileName()).arg(composite).arg(hw).arg(resultFilenames.at(x));
                QTest::newRow(caseName.toLatin1().constData()) << info.fileName() << bool(hw) << bool(composite) << resultFilenames.at(x);
                ++x;
            }
        }
    }
}

void Bm_Painting::benchmarkPaint()
{
    QFETCH(QString, filename);
    QFETCH(bool, hardwareRendering);
    QFETCH(bool, compositing);
    QFETCH(QString, resultFilename);

    gArgc = hardwareRendering ? 1 : 2;

    app = new MApplication(gArgc, gArgv);

    widget = new QWidget;
    if (compositing) {
        widget->setAttribute(Qt::WA_TranslucentBackground);
    }
    Qt::WindowFlags windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
    widget->setWindowFlags(windowFlags);
    widget->show();

    window = new LoggingWindow(widget);
    window->setTranslucentBackground(!MApplication::softwareRendering());
    if (MApplication::softwareRendering())
        window->viewport()->setAutoFillBackground(false);
    sceneWindow = createMSceneWindow(window);
    window->show();
    QTest::qWaitForWindowShown(window);

    QSize sceneSize = window->visibleSceneSize(M::Landscape);
    int w = sceneSize.width();
    int h = sceneSize.height();
    window->setSceneRect(0, 0, w, h);

    widget->resize(sceneSize);
    keyboard = new KeyboardData;
    QVERIFY(keyboard->loadNokiaKeyboard(filename));
    subject = new MImKeyArea(keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection));

    subject->resize(defaultLayoutSize());

    PaintRunner runner;
    window->scene()->addItem(&runner);
    runner.update();

    subject->setParentItem(&runner);

    MImKey *key0 = dynamic_cast<MImKey *>(keyAt(0, 0));
    MImKey *key1 = dynamic_cast<MImKey *>(keyAt(1, 3));
    MImKey *key2 = dynamic_cast<MImKey *>(keyAt(2, 6));

    QVERIFY(key0);
    QVERIFY(key1);

    const QPoint point0 = key0->buttonBoundingRect().center().toPoint();
    const QPoint point1 = key1->buttonBoundingRect().center().toPoint();
    const QPoint point2 = key2->buttonBoundingRect().center().toPoint();

    QTouchEvent::TouchPoint press0(MImAbstractKeyArea::createTouchPoint(0, Qt::TouchPointPressed,
                                                                        subject->mapToScene(point0),
                                                                        QPointF()));
    QTouchEvent::TouchPoint release0(MImAbstractKeyArea::createTouchPoint(0, Qt::TouchPointReleased,
                                                                          subject->mapToScene(point0),
                                                                          QPointF()));

    QTouchEvent::TouchPoint press1(MImAbstractKeyArea::createTouchPoint(1, Qt::TouchPointPressed,
                                                                        subject->mapToScene(point1),
                                                                        QPointF()));
    QTouchEvent::TouchPoint release1(MImAbstractKeyArea::createTouchPoint(1, Qt::TouchPointReleased,
                                                                          subject->mapToScene(point1),
                                                                          QPointF()));

    QTouchEvent::TouchPoint press2(MImAbstractKeyArea::createTouchPoint(2, Qt::TouchPointPressed,
                                                                        subject->mapToScene(point2),
                                                                        QPointF()));
    QTouchEvent::TouchPoint release2(MImAbstractKeyArea::createTouchPoint(2, Qt::TouchPointReleased,
                                                                          subject->mapToScene(point2),
                                                                          QPointF()));

    QList< QList<QTouchEvent::TouchPoint> > plannedEvents;
    QList<QTouchEvent::TouchPoint> eventList;

    plannedEvents << eventList;

    eventList << press0;
    plannedEvents << eventList;
    eventList.clear();

    eventList << release0;
    plannedEvents << eventList;
    eventList.clear();

    eventList << press0 << press1;
    plannedEvents << eventList;
    eventList.clear();

    eventList << release0 << release1;
    plannedEvents << eventList;
    eventList.clear();

    eventList << press0 << press1 << press2;
    plannedEvents << eventList;
    eventList.clear();

    eventList << release0 << release1 << release2;
    plannedEvents << eventList;
    eventList.clear();

    window->loggingEnabled = true;
    foreach (eventList, plannedEvents) {
        foreach (const QTouchEvent::TouchPoint &event, eventList) {
            if (event.state() == Qt::TouchPointPressed) {
                qDebug() << "press " << event.scenePos();
                subject->touchPointPressed(event);
            } else if (event.state() == Qt::TouchPointReleased) {
                qDebug() << "release " << event.scenePos();
                subject->touchPointReleased(event);
            }
        }
        qDebug() << "***";
        window->logMark();
        QTest::qWait(1000);
    }
    window->loggingEnabled = false;

    window->writeResults(resultFilename);

    subject->setParentItem(0);
}

QSize Bm_Painting::defaultLayoutSize()
{
    // Take visible scene size as layout size, but reduce keyboard's paddings first from its width.
    // The height value is ignored since MImAbstractKeyAreas determine their own height.
    return window->visibleSceneSize()
            - QSize(subject->style()->paddingLeft() + subject->style()->paddingRight(), 0);
}

MImAbstractKey *Bm_Painting::keyAt(unsigned int row, unsigned int column) const
{
    // If this fails there is something wrong with the test.
    Q_ASSERT(subject
             && (row < static_cast<unsigned int>(subject->rowCount()))
             && (column < static_cast<unsigned int>(subject->sectionModel()->columnsAt(row))));

    MImAbstractKey *key = 0;

    MImKeyArea *buttonArea = dynamic_cast<MImKeyArea *>(subject);
    if (buttonArea) {
        key = buttonArea->rowList[row].keys[column];
    }

    return key;
}

QTEST_APPLESS_MAIN(Bm_Painting);
<commit_msg>Changes: bm_painting uses environment variables to select test case<commit_after>/* * This file is part of meego-keyboard *
 *
 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 * Contact: Nokia Corporation (directui@nokia.com)
 *
 * 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 "bm_painting.h"
#include "paintrunner.h"
#include "loggingwindow.h"
#include "mimkeyarea.h"
#include "keyboarddata.h"
#include "utils.h"

// this test could not be compiled for Windows
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <MApplication>
#include <MTheme>
#include <MSceneWindow>
#include <MScene>
#include <MSceneManager>

#include <QDir>
#include <QtGlobal>

namespace {
    int gArgc = 2;
    char *gArgv[2] = { (char *) "bm_painting",
                       (char *) "-software" };
    const char *const MImUserDirectory = ".meego-im";
    const int DefaultDelay = 1000; // milliseconds
}

void Bm_Painting::initTestCase()
{
    disableQtPlugins();

    QDir dir;
    dir.mkpath(QString("%1/%2").arg(QDir::homePath()).arg(MImUserDirectory));
}

void Bm_Painting::cleanupTestCase()
{
}

void Bm_Painting::init()
{
    keyboard = 0;
    subject = 0;
}

void Bm_Painting::cleanup()
{
    delete subject;
    subject = 0;
    delete keyboard;
    keyboard = 0;

    delete sceneWindow;
    sceneWindow = 0;
    delete window;
    window = 0;
    delete widget;
    widget = 0;
    delete app;
    app = 0;
}

/*
 * COMPOSITE variable defines whether main window should be
 * composited or not. Possible values (case sensitive):
 *     * <unset> - perform tests for both opaque and tranclucent windows
 *     * true - perform tests for tranclucent (composited) window
 *     * any other - perform tests for opaque window
 * HARDWARE variable defines whether hardware acceleration should be used or
 * not. Possible values:
 *     * <unset> - perform tests with and without hardware acceleration
 *     * true - perform tests with hardware acceleration
 *     * any other - perform tests without hardware acceleration
 * DELAY defines duration of one step in test case. Default value is 750
 * milliseconds.
 */
void Bm_Painting::benchmarkPaint_data()
{
    QDir dir("/usr/share/meegotouch/virtual-keyboard/layouts/");
    QStringList filters;
    QFileInfoList files;
    QFileInfo info;
    QString resultFilenames[2][2];
    QString fileNameTemplate(QString("%1/%2/%3-%4").arg(QDir::homePath())
                                                   .arg(MImUserDirectory)
                                                   .arg(QCoreApplication::applicationPid()));
    int hwMin = 0;
    int hwMax = 1;
    int compositeMin = 0;
    int compositeMax = 1;
    int delay = DefaultDelay;
    QString env;

    env = qgetenv("COMPOSITE");
    if (!env.isEmpty()) {
        compositeMin = compositeMax = ((env == "true") ? 1 : 0);
    }

    env = qgetenv("HARDWARE");
    if (!env.isEmpty()) {
        hwMin = hwMax = ((env == "true") ? 1 : 0);
    }

    env = qgetenv("DELAY");
    if (!env.isEmpty()) {
        delay = env.toInt();
    }

    QTest::addColumn<QString>("filename");
    QTest::addColumn<bool>("hardwareRendering");
    QTest::addColumn<bool>("compositing");
    QTest::addColumn<QString>("resultFilename");
    QTest::addColumn<int>("delay");

    resultFilenames[0][0] = fileNameTemplate.arg("sw_opaque.csv");
    resultFilenames[1][0] = fileNameTemplate.arg("hw_opaque.csv");
    resultFilenames[0][1] = fileNameTemplate.arg("sw_composite.csv");
    resultFilenames[1][1] = fileNameTemplate.arg("hw_composite.csv");

    filters << "en_gb.xml";
    files = dir.entryInfoList(filters);

    for (int composite = compositeMin; composite <= compositeMax; ++composite) {
        for (int hw = hwMin; hw <= hwMax; ++hw) {
            for (int n = files.count() - 1; n >= 0; --n) {
                info = files.at(n);
                QString caseName = QString("file=%1 composite=%2 hw=%3 results=%4").arg(info.fileName()).arg(composite).arg(hw).
                    arg(resultFilenames[hw][composite]);
                QTest::newRow(caseName.toLatin1().constData()) << info.fileName()
                                                               << bool(hw)
                                                               << bool(composite)
                                                               << resultFilenames[hw][composite]
                                                               << delay;
            }
        }
    }
}

void Bm_Painting::benchmarkPaint()
{
    QFETCH(QString, filename);
    QFETCH(bool, hardwareRendering);
    QFETCH(bool, compositing);
    QFETCH(QString, resultFilename);
    QFETCH(int, delay);

    gArgc = hardwareRendering ? 1 : 2;

    app = new MApplication(gArgc, gArgv);

    widget = new QWidget;
    if (compositing) {
        widget->setAttribute(Qt::WA_TranslucentBackground);
    }
    Qt::WindowFlags windowFlags = Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint;
    widget->setWindowFlags(windowFlags);
    widget->show();

    window = new LoggingWindow(widget);
    window->setTranslucentBackground(!MApplication::softwareRendering());
    if (MApplication::softwareRendering())
        window->viewport()->setAutoFillBackground(false);
    sceneWindow = createMSceneWindow(window);
    window->show();
    QTest::qWaitForWindowShown(window);

    QSize sceneSize = window->visibleSceneSize(M::Landscape);
    int w = sceneSize.width();
    int h = sceneSize.height();
    window->setSceneRect(0, 0, w, h);

    widget->resize(sceneSize);
    keyboard = new KeyboardData;
    QVERIFY(keyboard->loadNokiaKeyboard(filename));
    subject = new MImKeyArea(keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection));

    subject->resize(defaultLayoutSize());

    PaintRunner runner;
    window->scene()->addItem(&runner);
    runner.update();

    subject->setParentItem(&runner);

    MImKey *key0 = dynamic_cast<MImKey *>(keyAt(0, 0));
    MImKey *key1 = dynamic_cast<MImKey *>(keyAt(1, 3));
    MImKey *key2 = dynamic_cast<MImKey *>(keyAt(2, 6));

    QVERIFY(key0);
    QVERIFY(key1);

    const QPoint point0 = key0->buttonBoundingRect().center().toPoint();
    const QPoint point1 = key1->buttonBoundingRect().center().toPoint();
    const QPoint point2 = key2->buttonBoundingRect().center().toPoint();

    QTouchEvent::TouchPoint press0(MImAbstractKeyArea::createTouchPoint(0, Qt::TouchPointPressed,
                                                                        subject->mapToScene(point0),
                                                                        QPointF()));
    QTouchEvent::TouchPoint release0(MImAbstractKeyArea::createTouchPoint(0, Qt::TouchPointReleased,
                                                                          subject->mapToScene(point0),
                                                                          QPointF()));

    QTouchEvent::TouchPoint press1(MImAbstractKeyArea::createTouchPoint(1, Qt::TouchPointPressed,
                                                                        subject->mapToScene(point1),
                                                                        QPointF()));
    QTouchEvent::TouchPoint release1(MImAbstractKeyArea::createTouchPoint(1, Qt::TouchPointReleased,
                                                                          subject->mapToScene(point1),
                                                                          QPointF()));

    QTouchEvent::TouchPoint press2(MImAbstractKeyArea::createTouchPoint(2, Qt::TouchPointPressed,
                                                                        subject->mapToScene(point2),
                                                                        QPointF()));
    QTouchEvent::TouchPoint release2(MImAbstractKeyArea::createTouchPoint(2, Qt::TouchPointReleased,
                                                                          subject->mapToScene(point2),
                                                                          QPointF()));

    QList< QList<QTouchEvent::TouchPoint> > plannedEvents;
    QList<QTouchEvent::TouchPoint> eventList;

    plannedEvents << eventList;

    eventList << press0;
    plannedEvents << eventList;
    eventList.clear();

    eventList << release0;
    plannedEvents << eventList;
    eventList.clear();

    eventList << press0 << press1;
    plannedEvents << eventList;
    eventList.clear();

    eventList << release0 << release1;
    plannedEvents << eventList;
    eventList.clear();

    eventList << press0 << press1 << press2;
    plannedEvents << eventList;
    eventList.clear();

    eventList << release0 << release1 << release2;
    plannedEvents << eventList;
    eventList.clear();

    window->loggingEnabled = true;
    foreach (eventList, plannedEvents) {
        foreach (const QTouchEvent::TouchPoint &event, eventList) {
            if (event.state() == Qt::TouchPointPressed) {
                qDebug() << "press " << event.scenePos();
                subject->touchPointPressed(event);
            } else if (event.state() == Qt::TouchPointReleased) {
                qDebug() << "release " << event.scenePos();
                subject->touchPointReleased(event);
            }
        }
        qDebug() << "***";
        window->logMark();
        QTest::qWait(delay);
    }
    window->loggingEnabled = false;

    window->writeResults(resultFilename);

    subject->setParentItem(0);
}

QSize Bm_Painting::defaultLayoutSize()
{
    // Take visible scene size as layout size, but reduce keyboard's paddings first from its width.
    // The height value is ignored since MImAbstractKeyAreas determine their own height.
    return window->visibleSceneSize()
            - QSize(subject->style()->paddingLeft() + subject->style()->paddingRight(), 0);
}

MImAbstractKey *Bm_Painting::keyAt(unsigned int row, unsigned int column) const
{
    // If this fails there is something wrong with the test.
    Q_ASSERT(subject
             && (row < static_cast<unsigned int>(subject->rowCount()))
             && (column < static_cast<unsigned int>(subject->sectionModel()->columnsAt(row))));

    MImAbstractKey *key = 0;

    MImKeyArea *buttonArea = dynamic_cast<MImKeyArea *>(subject);
    if (buttonArea) {
        key = buttonArea->rowList[row].keys[column];
    }

    return key;
}

QTEST_APPLESS_MAIN(Bm_Painting);
<|endoftext|>


<commit_before><commit_msg>TODO-593: bug fix<commit_after><|endoftext|>


<commit_before>// This file is part of gltfpack; see gltfpack.h for version/license details
#include "gltfpack.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

struct BasisSettings
{
	int etc1s_l;
	int etc1s_q;
	int uastc_l;
	float uastc_q;
};

static const char* kMimeTypes[][2] = {
    {"image/jpeg", ".jpg"},
    {"image/jpeg", ".jpeg"},
    {"image/png", ".png"},
};

static const BasisSettings kBasisSettings[10] = {
    {0, 1, 0, 1.5f},
    {0, 6, 0, 1.f},
    {1, 20, 1, 1.0f},
    {1, 50, 1, 0.75f},
    {1, 90, 1, 0.5f},
    {1, 128, 1, 0.4f},
    {1, 160, 1, 0.34f},
    {1, 192, 1, 0.29f}, // default
    {1, 224, 2, 0.26f},
    {1, 255, 2, 0.f},
};

void analyzeImages(cgltf_data* data, std::vector<ImageInfo>& images)
{
	for (size_t i = 0; i < data->materials_count; ++i)
	{
		const cgltf_material& material = data->materials[i];

		if (material.has_pbr_metallic_roughness)
		{
			const cgltf_pbr_metallic_roughness& pbr = material.pbr_metallic_roughness;

			if (pbr.base_color_texture.texture && pbr.base_color_texture.texture->image)
				images[pbr.base_color_texture.texture->image - data->images].srgb = true;
		}

		if (material.has_pbr_specular_glossiness)
		{
			const cgltf_pbr_specular_glossiness& pbr = material.pbr_specular_glossiness;

			if (pbr.diffuse_texture.texture && pbr.diffuse_texture.texture->image)
				images[pbr.diffuse_texture.texture->image - data->images].srgb = true;
		}

		if (material.emissive_texture.texture && material.emissive_texture.texture->image)
			images[material.emissive_texture.texture->image - data->images].srgb = true;

		if (material.normal_texture.texture && material.normal_texture.texture->image)
			images[material.normal_texture.texture->image - data->images].normal_map = true;
	}
}

const char* inferMimeType(const char* path)
{
	const char* ext = strrchr(path, '.');
	if (!ext)
		return "";

	std::string extl = ext;
	for (size_t i = 0; i < extl.length(); ++i)
		extl[i] = char(tolower(extl[i]));

	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (extl == kMimeTypes[i][1])
			return kMimeTypes[i][0];

	return "";
}

static const char* mimeExtension(const char* mime_type)
{
	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (strcmp(kMimeTypes[i][0], mime_type) == 0)
			return kMimeTypes[i][1];

	return ".raw";
}

#ifdef __EMSCRIPTEN__
EM_JS(int, execute, (const char* cmd, bool ignore_stdout, bool ignore_stderr), {
	var cp = require('child_process');
	var stdio = [ 'ignore', ignore_stdout ? 'ignore' : 'inherit', ignore_stderr ? 'ignore' : 'inherit' ];
	var ret = cp.spawnSync(UTF8ToString(cmd), [], {shell:true, stdio:stdio });
	return ret.status == null ? 256 : ret.status;
});

EM_JS(const char*, readenv, (const char* name), {
	var val = process.env[UTF8ToString(name)];
	if (!val)
		return 0;
	var ret = _malloc(lengthBytesUTF8(val) + 1);
	stringToUTF8(val, ret, lengthBytesUTF8(val) + 1);
	return ret;
});
#else
static int execute(const char* cmd_, bool ignore_stdout, bool ignore_stderr)
{
#ifdef _WIN32
	std::string ignore = "nul";
#else
	std::string ignore = "/dev/null";
#endif

	std::string cmd = cmd_;

	if (ignore_stdout)
		(cmd += " >") += ignore;
	if (ignore_stderr)
		(cmd += " 2>") += ignore;

	return system(cmd.c_str());
}

static const char* readenv(const char* name)
{
	return getenv(name);
}
#endif

bool checkBasis(bool verbose)
{
	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	cmd += " -version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool uastc, bool verbose)
{
	(void)scale;

	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".basis");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	const BasisSettings& bs = kBasisSettings[std::max(0, std::min(9, quality - 1))];

	cmd += " -mipmap";

	if (normal_map)
	{
		cmd += " -normal_map";
		// for optimal quality we should specify seperate_rg_to_color_alpha but this requires renderer awareness
	}
	else if (!srgb)
	{
		cmd += " -linear";
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " -uastc_level %d -uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " -uastc";
		cmd += settings;
		cmd += " -uastc_rdo_d 1024";
	}
	else
	{
		char settings[128];
		sprintf(settings, " -comp_level %d -q %d", bs.etc1s_l, bs.etc1s_q);

		cmd += settings;
	}

	cmd += " -file ";
	cmd += temp_input.path;
	cmd += " -output_file ";
	cmd += temp_output.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}

bool checkKtx(bool verbose)
{
	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	cmd += " --version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool uastc, bool verbose)
{
	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".ktx2");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	const BasisSettings& bs = kBasisSettings[std::max(0, std::min(9, quality - 1))];

	cmd += " --t2";
	cmd += " --2d";
	cmd += " --genmipmap";
	cmd += " --nowarn";

	if (scale < 1)
	{
		char sl[128];
		sprintf(sl, "%g", scale);

		cmd += " --scale ";
		cmd += sl;
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " %d --uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " --uastc";
		cmd += settings;
		cmd += " --uastc_rdo_d 1024";
		cmd += " --zcmp 9";
	}
	else
	{
		char settings[128];
		sprintf(settings, " --clevel %d --qlevel %d", bs.etc1s_l, bs.etc1s_q);

		cmd += " --bcmp";
		cmd += settings;

		// for optimal quality we should specify separate_rg_to_color_alpha but this requires renderer awareness
		if (normal_map)
			cmd += " --normal_map";
	}

	if (srgb)
		cmd += " --srgb";
	else
		cmd += " --linear";

	cmd += " -- ";
	cmd += temp_output.path;
	cmd += " ";
	cmd += temp_input.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ false, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}
<commit_msg>gltfpack: Fix Windows build<commit_after>// This file is part of gltfpack; see gltfpack.h for version/license details
#include "gltfpack.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

struct BasisSettings
{
	int etc1s_l;
	int etc1s_q;
	int uastc_l;
	float uastc_q;
};

static const char* kMimeTypes[][2] = {
    {"image/jpeg", ".jpg"},
    {"image/jpeg", ".jpeg"},
    {"image/png", ".png"},
};

static const BasisSettings kBasisSettings[10] = {
    {0, 1, 0, 1.5f},
    {0, 6, 0, 1.f},
    {1, 20, 1, 1.0f},
    {1, 50, 1, 0.75f},
    {1, 90, 1, 0.5f},
    {1, 128, 1, 0.4f},
    {1, 160, 1, 0.34f},
    {1, 192, 1, 0.29f}, // default
    {1, 224, 2, 0.26f},
    {1, 255, 2, 0.f},
};

void analyzeImages(cgltf_data* data, std::vector<ImageInfo>& images)
{
	for (size_t i = 0; i < data->materials_count; ++i)
	{
		const cgltf_material& material = data->materials[i];

		if (material.has_pbr_metallic_roughness)
		{
			const cgltf_pbr_metallic_roughness& pbr = material.pbr_metallic_roughness;

			if (pbr.base_color_texture.texture && pbr.base_color_texture.texture->image)
				images[pbr.base_color_texture.texture->image - data->images].srgb = true;
		}

		if (material.has_pbr_specular_glossiness)
		{
			const cgltf_pbr_specular_glossiness& pbr = material.pbr_specular_glossiness;

			if (pbr.diffuse_texture.texture && pbr.diffuse_texture.texture->image)
				images[pbr.diffuse_texture.texture->image - data->images].srgb = true;
		}

		if (material.emissive_texture.texture && material.emissive_texture.texture->image)
			images[material.emissive_texture.texture->image - data->images].srgb = true;

		if (material.normal_texture.texture && material.normal_texture.texture->image)
			images[material.normal_texture.texture->image - data->images].normal_map = true;
	}
}

const char* inferMimeType(const char* path)
{
	const char* ext = strrchr(path, '.');
	if (!ext)
		return "";

	std::string extl = ext;
	for (size_t i = 0; i < extl.length(); ++i)
		extl[i] = char(tolower(extl[i]));

	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (extl == kMimeTypes[i][1])
			return kMimeTypes[i][0];

	return "";
}

static const char* mimeExtension(const char* mime_type)
{
	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (strcmp(kMimeTypes[i][0], mime_type) == 0)
			return kMimeTypes[i][1];

	return ".raw";
}

#ifdef __EMSCRIPTEN__
EM_JS(int, execute, (const char* cmd, bool ignore_stdout, bool ignore_stderr), {
	var cp = require('child_process');
	var stdio = [ 'ignore', ignore_stdout ? 'ignore' : 'inherit', ignore_stderr ? 'ignore' : 'inherit' ];
	var ret = cp.spawnSync(UTF8ToString(cmd), [], {shell:true, stdio:stdio });
	return ret.status == null ? 256 : ret.status;
});

EM_JS(const char*, readenv, (const char* name), {
	var val = process.env[UTF8ToString(name)];
	if (!val)
		return 0;
	var ret = _malloc(lengthBytesUTF8(val) + 1);
	stringToUTF8(val, ret, lengthBytesUTF8(val) + 1);
	return ret;
});
#else
static int execute(const char* cmd_, bool ignore_stdout, bool ignore_stderr)
{
#ifdef _WIN32
	std::string ignore = "nul";
#else
	std::string ignore = "/dev/null";
#endif

	std::string cmd = cmd_;

	if (ignore_stdout)
		(cmd += " >") += ignore;
	if (ignore_stderr)
		(cmd += " 2>") += ignore;

	return system(cmd.c_str());
}

static const char* readenv(const char* name)
{
	return getenv(name);
}
#endif

bool checkBasis(bool verbose)
{
	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	cmd += " -version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool uastc, bool verbose)
{
	(void)scale;

	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".basis");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];

	cmd += " -mipmap";

	if (normal_map)
	{
		cmd += " -normal_map";
		// for optimal quality we should specify seperate_rg_to_color_alpha but this requires renderer awareness
	}
	else if (!srgb)
	{
		cmd += " -linear";
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " -uastc_level %d -uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " -uastc";
		cmd += settings;
		cmd += " -uastc_rdo_d 1024";
	}
	else
	{
		char settings[128];
		sprintf(settings, " -comp_level %d -q %d", bs.etc1s_l, bs.etc1s_q);

		cmd += settings;
	}

	cmd += " -file ";
	cmd += temp_input.path;
	cmd += " -output_file ";
	cmd += temp_output.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}

bool checkKtx(bool verbose)
{
	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	cmd += " --version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool uastc, bool verbose)
{
	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".ktx2");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];

	cmd += " --t2";
	cmd += " --2d";
	cmd += " --genmipmap";
	cmd += " --nowarn";

	if (scale < 1)
	{
		char sl[128];
		sprintf(sl, "%g", scale);

		cmd += " --scale ";
		cmd += sl;
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " %d --uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " --uastc";
		cmd += settings;
		cmd += " --uastc_rdo_d 1024";
		cmd += " --zcmp 9";
	}
	else
	{
		char settings[128];
		sprintf(settings, " --clevel %d --qlevel %d", bs.etc1s_l, bs.etc1s_q);

		cmd += " --bcmp";
		cmd += settings;

		// for optimal quality we should specify separate_rg_to_color_alpha but this requires renderer awareness
		if (normal_map)
			cmd += " --normal_map";
	}

	if (srgb)
		cmd += " --srgb";
	else
		cmd += " --linear";

	cmd += " -- ";
	cmd += temp_output.path;
	cmd += " ";
	cmd += temp_input.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ false, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}
<|endoftext|>